public override async Task ExecuteAsync(InstanceDetailsViewModel model)
        {
            if (LicenseChecks)
            {
                var licenseCheckResult = serviceControlInstaller.CheckLicenseIsValid();
                if (!licenseCheckResult.Valid)
                {
                    windowManager.ShowMessage("LICENSE ERROR", $"Upgrade could not continue due to an issue with the current license. {licenseCheckResult.Message}.  Contact [email protected]", hideCancel: true);
                    return;
                }
            }

            var instance = InstanceFinder.FindInstanceByName <ServiceControlAuditInstance>(model.Name);

            instance.Service.Refresh();

            var upgradeInfo    = UpgradeControl.GetUpgradeInfoForTargetVersion(serviceControlInstaller.ZipInfo.Version, instance.Version);
            var upgradeOptions = new ServiceControlUpgradeOptions {
                UpgradeInfo = upgradeInfo
            };

            if (instance.Service.Status != ServiceControllerStatus.Stopped &&
                !windowManager.ShowYesNoDialog($"STOP INSTANCE AND UPGRADE TO {serviceControlInstaller.ZipInfo.Version}",
                                               $"{model.Name} needs to be stopped in order to upgrade to version {serviceControlInstaller.ZipInfo.Version}.",
                                               "Do you want to proceed?",
                                               "Yes, I want to proceed", "No"))
            {
                return;
            }

            await UpgradeAuditInstance(model, instance, upgradeOptions);

            eventAggregator.PublishOnUIThread(new RefreshInstances());
        }
Example #2
0
        Result ValidateUpgradeVersion(ServiceControlInstance instance)
        {
            var upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(serviceControlInstaller.ZipInfo.Version, instance.Version);

            if (instance.Version < upgradeInfo.CurrentMinimumVersion)
            {
                return(Result.Failed($"An interim upgrade to version {upgradeInfo.RecommendedUpgradeVersion} is required before upgrading to version {serviceControlInstaller.ZipInfo.Version}. Download available at https://github.com/Particular/ServiceControl/releases/tag/{upgradeInfo.RecommendedUpgradeVersion}"));
            }

            return(Result.Success);
        }
Example #3
0
        public Result Split(ServiceControlInstance instance, Options options, Func <PathInfo, bool> pathToProceed)
        {
            var result = ValidateLicense();

            if (!result.Succeeded)
            {
                return(result);
            }

            result = ValidateUpgradeVersion(instance);
            if (!result.Succeeded)
            {
                return(result);
            }

            result = ValidateUpgradeAction(instance);
            if (!result.Succeeded)
            {
                return(result);
            }


            log.Info("Gathering details for new audit instance...");
            var newAuditInstance = CreateSplitOutAuditInstance(instance);

            options.ApplyTo(newAuditInstance);

            result = ValidateServiceAccount(options, newAuditInstance);
            if (!result.Succeeded)
            {
                return(result);
            }

            log.Info($"Upgrading existing instance {instance.Name}...");
            var serviceControlUpgradeOptions = new ServiceControlUpgradeOptions
            {
                UpgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(serviceControlInstaller.ZipInfo.Version, instance.Version),
                RemoteUrl   = newAuditInstance.Url
            };

            if (!serviceControlInstaller.Upgrade(instance, serviceControlUpgradeOptions))
            {
                return(Result.Failed($"Unable to upgrade existing instance {instance.Name}"));
            }

            log.Info($"Creating new audit instance {newAuditInstance.Name}...");
            if (!auditInstaller.Add(newAuditInstance, pathToProceed))
            {
                return(Result.Failed("Unable to create new audit instance"));
            }

            return(Result.Success);
        }
        void PerformUpgrade(ServiceControlInstance instance, UnattendServiceControlInstaller installer)
        {
            var options = new ServiceControlUpgradeOptions
            {
                SkipQueueCreation = SkipQueueCreation
            };

            options.UpgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(installer.ZipInfo.Version, instance.Version);

            if (!installer.Upgrade(instance, options))
            {
                ThrowTerminatingError(new ErrorRecord(new Exception($"Upgrade of {instance.Name} failed"), "UpgradeFailure", ErrorCategory.InvalidResult, null));
            }
        }
        public void ValidateVersion2UpgradeData()
        {
            var tooOldVersion = new Version(1, 41, 0);

            var minimumVersion = new Version(1, 41, 3);

            var recommendedVersion = new Version(1, 48, 0);

            var version2 = new Version(2, 0, 0);

            //Test current is too old
            var upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(version2, tooOldVersion);

            Assert.AreEqual(minimumVersion, upgradeInfo.CurrentMinimumVersion, "CurrentMinimumVersion mismatch");
            Assert.AreEqual(version2, upgradeInfo.TargetMinimumVersion, "TargetMinimumVersion mismatch");
            Assert.AreEqual(recommendedVersion, upgradeInfo.RecommendedUpgradeVersion, "RecommendedUpgradeVersion mismatch");
        }
        public void TestGetUpgradeInfoForTargetVersion()
        {
            var upgrade1Info = new UpgradeInfo(new Version(2, 0, 0), new Version(1, 41, 3))
            {
                RecommendedUpgradeVersion = new Version(1, 48, 0)
            };

            var upgrade2Info = new UpgradeInfo(new Version(3, 0, 0), new Version(2, 1, 3))
            {
                RecommendedUpgradeVersion = new Version(2, 1, 3)
            };

            UpgradeControl.details = new[]
            {
                upgrade1Info,
                upgrade2Info
            };

            var target = new Version(3, 1, 1);

            var defaultUpgradeInfo = new UpgradeInfo(target, new Version(0, 0));

            // User is 0.1 and trying to update to 3.1.1. Expect require update to 1.41.3 or higher. (upgrade1Info)
            var upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(target, new Version(0, 1, 0));

            Assert.AreSame(upgrade1Info, upgradeInfo, "Incorrect UpgradeInfro, expected upgrade1Info");

            // User is 1.42 and trying to update to 3.1.1. Expect require update to 2.1.3 or higher (upgrade2info)
            upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(target, new Version(1, 42, 0));
            Assert.AreSame(upgrade2Info, upgradeInfo, "Incorrect UpgradeInfro, expected upgrade2Info (below 2)");

            // User is 2.1.0 and trying to upgrade to 3.1.1. Expect require update to 2.1.3 or higher (upgrade2info)
            upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(target, new Version(2, 1, 0));
            Assert.AreSame(upgrade2Info, upgradeInfo, "Incorrect UpgradeInfro, expected upgrade2Info (above 2)");

            // User is 2.2 and trying to upgrade to 3.1.1. Expect default.
            upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(target, new Version(2, 2, 0));
            Assert.AreEqual(defaultUpgradeInfo, upgradeInfo, "Incorrect UpgradeInfro, expected defaultUpgradeInfo");

            Assert.AreEqual(defaultUpgradeInfo.TargetMinimumVersion, upgradeInfo.TargetMinimumVersion, $"TargetMinimumVersion mismatch {target}");
            Assert.AreEqual(defaultUpgradeInfo.CurrentMinimumVersion, upgradeInfo.CurrentMinimumVersion, $"CurrentMinimumVersion mismatch {target}");
            Assert.AreEqual(defaultUpgradeInfo.RecommendedUpgradeVersion, upgradeInfo.RecommendedUpgradeVersion, $"RecommendedUpgradeVersion mismatch {target}");
        }
Example #7
0
        public override async Task ExecuteAsync(InstanceDetailsViewModel model)
        {
            if (LicenseChecks)
            {
                var licenseCheckResult = serviceControlInstaller.CheckLicenseIsValid();
                if (!licenseCheckResult.Valid)
                {
                    windowManager.ShowMessage("LICENSE ERROR", $"Upgrade could not continue due to an issue with the current license. {licenseCheckResult.Message}.  Contact [email protected]", hideCancel: true);
                    return;
                }
            }

            var instance = InstanceFinder.FindInstanceByName <ServiceControlInstance>(model.Name);

            instance.Service.Refresh();

            var upgradeInfo    = UpgradeControl.GetUpgradeInfoForTargetVersion(serviceControlInstaller.ZipInfo.Version, instance.Version);
            var upgradeOptions = new ServiceControlUpgradeOptions {
                UpgradeInfo = upgradeInfo
            };


            var upgradeAction      = instance.GetRequiredUpgradeAction(serviceControlInstaller.ZipInfo.Version);
            var shouldInstallAudit = upgradeAction == RequiredUpgradeAction.SplitOutAudit;

            AddNewAuditInstanceViewModel auditViewModel = null;

            if (instance.Version < upgradeInfo.CurrentMinimumVersion)
            {
                windowManager.ShowMessage("VERSION UPGRADE INCOMPATIBLE",
                                          "<Section xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\" TextAlignment=\"Left\" LineHeight=\"Auto\" IsHyphenationEnabled=\"False\" xml:lang=\"en-us\">\r\n" +
                                          $"<Paragraph>You must upgrade to version {upgradeInfo.RecommendedUpgradeVersion} before upgrading to version {serviceControlInstaller.ZipInfo.Version}:</Paragraph>\r\n" +
                                          "<List MarkerStyle=\"Decimal\" Margin=\"0,0,0,0\" Padding=\"0,0,0,0\">\r\n" +
                                          $"<ListItem Margin=\"48,0,0,0\"><Paragraph>Uninstall version {serviceControlInstaller.ZipInfo.Version}.</Paragraph></ListItem>\r\n" +
                                          $"<ListItem Margin=\"48,0,0,0\"><Paragraph>Download and install version {upgradeInfo.RecommendedUpgradeVersion} from https://github.com/Particular/ServiceControl/releases/tag/{upgradeInfo.RecommendedUpgradeVersion}</Paragraph></ListItem>" +
                                          $"<ListItem Margin=\"48,0,0,0\"><Paragraph>Upgrade this instance to version {upgradeInfo.RecommendedUpgradeVersion}.</Paragraph></ListItem>\r\n" +
                                          "<ListItem Margin=\"48,0,0,0\"><Paragraph>Download and install the latest version from https://particular.net/start-servicecontrol-download</Paragraph></ListItem>\r\n" +
                                          "<ListItem Margin=\"48,0,0,0\"><Paragraph>Upgrade this instance to the latest version of ServiceControl.</Paragraph></ListItem>\r\n" +
                                          "</List>\r\n" +
                                          "</Section>",
                                          hideCancel: true);

                return;
            }

            if (instance.IsErrorQueueDisabled())
            {
                windowManager.ShowMessage("UPGRADE INCOMPATIBLE",
                                          "You cannot upgrade the instance of ServiceControl with error ingestion disabled. Please contact support.",
                                          hideCancel: true);

                return;
            }

            if (!instance.AppConfig.AppSettingExists(ServiceControlSettings.ForwardErrorMessages.Name))
            {
                var result = windowManager.ShowYesNoCancelDialog("UPGRADE QUESTION - DISABLE ERROR FORWARDING", "Error messages can be forwarded to a secondary error queue known as the Error Forwarding Queue. This queue exists to allow external tools to receive error messages. If you do not have a tool processing messages from the Error Forwarding Queue this setting should be disabled.", "So what do you want to do ?", "Do NOT forward", "Yes I want to forward");
                if (!result.HasValue)
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }

                upgradeOptions.OverrideEnableErrorForwarding = !result.Value;
            }

            //Grab old setting if it exists
            if (!instance.AppConfig.AppSettingExists(ServiceControlSettings.AuditRetentionPeriod.Name))
            {
                if (instance.AppConfig.AppSettingExists(ServiceControlSettings.HoursToKeepMessagesBeforeExpiring.Name))
                {
                    var i = instance.AppConfig.Read(ServiceControlSettings.HoursToKeepMessagesBeforeExpiring.Name, -1);
                    if (i != -1)
                    {
                        upgradeOptions.AuditRetentionPeriod = TimeSpan.FromHours(i);
                    }
                }

                // No setting to migrate so display dialog
                if (!upgradeOptions.AuditRetentionPeriod.HasValue)
                {
                    var viewModel = new SliderDialogViewModel("INPUT REQUIRED - DATABASE RETENTION",
                                                              "Service Control periodically purges audit messages from the database.",
                                                              "AUDIT RETENTION PERIOD",
                                                              "Please specify the age at which these records should be removed",
                                                              TimeSpanUnits.Hours,
                                                              SettingConstants.AuditRetentionPeriodMinInHours,
                                                              SettingConstants.AuditRetentionPeriodMaxInHours,
                                                              1,
                                                              24,
                                                              SettingConstants.AuditRetentionPeriodDefaultInHoursForUI);

                    if (windowManager.ShowSliderDialog(viewModel))
                    {
                        upgradeOptions.AuditRetentionPeriod = viewModel.Period;
                    }
                    else
                    {
                        //Dialog was cancelled
                        eventAggregator.PublishOnUIThread(new RefreshInstances());
                        return;
                    }
                }
            }

            if (!instance.AppConfig.AppSettingExists(ServiceControlSettings.ErrorRetentionPeriod.Name))
            {
                var viewModel = new SliderDialogViewModel("INPUT REQUIRED - DATABASE RETENTION",
                                                          "Service Control periodically purges resolved and archived error messages from the database.",
                                                          "ERROR RETENTION PERIOD",
                                                          "Please specify the age at which these records should be removed",
                                                          TimeSpanUnits.Days,
                                                          SettingConstants.ErrorRetentionPeriodMinInDays,
                                                          SettingConstants.ErrorRetentionPeriodMaxInDays,
                                                          1,
                                                          1,
                                                          SettingConstants.ErrorRetentionPeriodDefaultInDaysForUI);

                if (windowManager.ShowSliderDialog(viewModel))
                {
                    upgradeOptions.ErrorRetentionPeriod = viewModel.Period;
                }
                else
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }
            }

            if (!instance.AppConfig.AppSettingExists(ServiceControlSettings.DatabaseMaintenancePort.Name))
            {
                var viewModel = new TextBoxDialogViewModel("INPUT REQUIRED - MAINTENANCE PORT",
                                                           "When Service Control is set to maintenance mode it requires a prereserved port on which it exposes the RavenDB database.",
                                                           "MAINTENANCE PORT",
                                                           "Please specify an open port that will be used as the maintenance port",
                                                           new PortValidator());

                if (windowManager.ShowTextBoxDialog(viewModel))
                {
                    upgradeOptions.MaintenancePort = int.Parse(viewModel.Value);
                }
                else
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }
            }

            if (shouldInstallAudit)
            {
                auditViewModel = auditUpgradeViewModelFactory(instance.Name);
                auditViewModel.ServiceControlAudit.SetupServiceAccount(instance);

                if (windowManager.ShowInnerDialog(auditViewModel) != true)
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }
            }

            if (instance.Service.Status != ServiceControllerStatus.Stopped &&
                !windowManager.ShowYesNoDialog($"STOP INSTANCE AND UPGRADE TO {serviceControlInstaller.ZipInfo.Version}",
                                               $"{model.Name} needs to be stopped in order to upgrade to version {serviceControlInstaller.ZipInfo.Version}.",
                                               "Do you want to proceed?",
                                               "Yes, I want to proceed", "No"))
            {
                return;
            }

            if (shouldInstallAudit)
            {
                var auditInstalled = await InstallServiceControlAudit(model, auditViewModel, instance);

                if (!auditInstalled)
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }

                var auditInstance = InstanceFinder.FindInstanceByName <ServiceControlAuditInstance>(auditViewModel.ServiceControlAudit.InstanceName);
                upgradeOptions.RemoteUrl = auditInstance.BrowsableUrl;
            }

            await UpgradeServiceControlInstance(model, instance, upgradeOptions);

            eventAggregator.PublishOnUIThread(new RefreshInstances());
        }
        static void UpgradeInstances(Session session, ServiceControlZipInfo zipInfo, MSILogger logger, UnattendServiceControlInstaller unattendedInstaller)
        {
            var options = new ServiceControlUpgradeOptions();

            var upgradeInstancesPropertyValue = session["UPGRADEINSTANCES"];

            if (string.IsNullOrWhiteSpace(upgradeInstancesPropertyValue))
            {
                return;
            }

            upgradeInstancesPropertyValue = upgradeInstancesPropertyValue.Trim();

            var forwardErrorMessagesPropertyValue = session["FORWARDERRORMESSAGES"];

            try
            {
                options.OverrideEnableErrorForwarding = bool.Parse(forwardErrorMessagesPropertyValue);
            }
            catch
            {
                options.OverrideEnableErrorForwarding = null;
            }

            var auditRetentionPeriodPropertyValue = session["AUDITRETENTIONPERIOD"];

            try
            {
                options.AuditRetentionPeriod = TimeSpan.Parse(auditRetentionPeriodPropertyValue);
            }
            catch
            {
                options.AuditRetentionPeriod = null;
            }

            var errorRetentionPeriodPropertyValue = session["ERRORRETENTIONPERIOD"];

            try
            {
                options.ErrorRetentionPeriod = TimeSpan.Parse(errorRetentionPeriodPropertyValue);
            }
            catch
            {
                options.ErrorRetentionPeriod = null;
            }

            var confirmDatabaseHasBeenBackedUpValue = session["CONFIRMDATABASEHASBEENBACKEDUP"];

            try
            {
                options.ConfirmDatabaseHasBeenBackedUp = bool.Parse(confirmDatabaseHasBeenBackedUpValue);
            }
            catch
            {
                options.ConfirmDatabaseHasBeenBackedUp = false;
            }

            var allowLargeDatabaseUpgradeValue = session["ALLOWLARGEDATABASEUPGRADE"];

            try
            {
                options.AllowLargeDatabaseUpdate = bool.Parse(allowLargeDatabaseUpgradeValue);
            }
            catch
            {
                options.ConfirmDatabaseHasBeenBackedUp = false;
            }

            //determine what to upgrade
            var instancesToUpgrade = new List <ServiceControlInstance>();

            if (upgradeInstancesPropertyValue.Equals("*", StringComparison.OrdinalIgnoreCase) || upgradeInstancesPropertyValue.Equals("ALL", StringComparison.OrdinalIgnoreCase))
            {
                instancesToUpgrade.AddRange(InstanceFinder.ServiceControlInstances());
            }
            else
            {
                var candidates = upgradeInstancesPropertyValue.Replace(" ", String.Empty).Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                instancesToUpgrade.AddRange(InstanceFinder.ServiceControlInstances().Where(instance => candidates.Contains(instance.Name, StringComparer.OrdinalIgnoreCase)));
            }

            // do upgrades
            foreach (var instance in instancesToUpgrade)
            {
                if (zipInfo.Version > instance.Version)
                {
                    var upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(zipInfo.Version, instance.Version);

                    options.UpgradeInfo = upgradeInfo;

                    if (!instance.AppConfig.AppSettingExists(SettingsList.ForwardErrorMessages.Name) & !options.OverrideEnableErrorForwarding.Value)
                    {
                        logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. FORWARDERRORMESSAGES MSI parameter was required because appsettings needed a value for '{SettingsList.ForwardErrorMessages.Name}'");
                        continue;
                    }

                    if (!options.AuditRetentionPeriod.HasValue)
                    {
                        if (!instance.AppConfig.AppSettingExists(SettingsList.AuditRetentionPeriod.Name))
                        {
                            //Try migration first
                            if (instance.AppConfig.AppSettingExists(SettingsList.HoursToKeepMessagesBeforeExpiring.Name))
                            {
                                var i = instance.AppConfig.Read(SettingsList.HoursToKeepMessagesBeforeExpiring.Name, -1);
                                if (i > 0)
                                {
                                    options.AuditRetentionPeriod = TimeSpan.FromHours(i);
                                }
                            }
                            else
                            {
                                logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. AUDITRETENTIONPERIOD MSI parameter was required because appsettings needed a value for '{SettingsList.AuditRetentionPeriod.Name}'");
                                continue;
                            }
                        }
                    }

                    if (!instance.AppConfig.AppSettingExists(SettingsList.ErrorRetentionPeriod.Name) & !options.ErrorRetentionPeriod.HasValue)
                    {
                        logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. ERRORRETENTIONPERIOD MSI parameter was required because appsettings needed a value for '{SettingsList.ErrorRetentionPeriod.Name}'");
                        continue;
                    }

                    if (upgradeInfo.DataBaseUpdate) //Database is being updated -> recommend DB backup
                    {
                        if (!options.ConfirmDatabaseHasBeenBackedUp)
                        {
                            logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. This upgrade requires a database update and the database should be backed up prior to updating. CONFIRMDATABASEHASBEENBACKEDUP MSI parameter was required to allow the database upgrade.'");
                            continue;
                        }

                        var dbSize = instance.GetDatabaseSizeInGb();
                        if (dbSize >= 100) // 100GB
                        {
                            logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. Upgrade requires a database update and the database being upgraded is {dbSize:N0} GB. " +
                                        "Migrating this much data could take a long time and ServiceControl will be stopped for that entire duration. It is recommended that you consider one of the other upgrade approaches instead. " +
                                        "ALLOWLARGEDATABASEUPGRADE MSI parameter can be used to allow an unattended database upgrade.'");
                            continue;
                        }
                    }

                    if (!unattendedInstaller.Upgrade(instance, options))
                    {
                        logger.Warn($"Failed to upgrade {instance.Name} to {zipInfo.Version}");
                    }
                }
            }
        }
Example #9
0
        protected override void ProcessRecord()
        {
            var logger = new PSLogger(Host);

            var zipFolder = Path.GetDirectoryName(MyInvocation.MyCommand.Module.Path);
            var installer = new UnattendServiceControlInstaller(logger, zipFolder);

            foreach (var name in Name)
            {
                var options = new ServiceControlUpgradeOptions
                {
                    AuditRetentionPeriod          = AuditRetentionPeriod,
                    ErrorRetentionPeriod          = ErrorRetentionPeriod,
                    OverrideEnableErrorForwarding = ForwardErrorMessages,
                    SkipQueueCreation             = SkipQueueCreation,
                    MaintenancePort = DatabaseMaintenancePort == 0 ? (int?)null : DatabaseMaintenancePort
                };
                var instance = InstanceFinder.FindServiceControlInstance(name);
                if (instance == null)
                {
                    WriteWarning($"No action taken. An instance called {name} was not found");
                    break;
                }

                options.UpgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(installer.ZipInfo.Version, instance.Version);

                options.OverrideEnableErrorForwarding = ForwardErrorMessages;

                // Migrate Value
                if (!options.AuditRetentionPeriod.HasValue)
                {
                    if (instance.AppConfig.AppSettingExists(SettingsList.HoursToKeepMessagesBeforeExpiring.Name))
                    {
                        var i = instance.AppConfig.Read(SettingsList.HoursToKeepMessagesBeforeExpiring.Name, -1);
                        if (i != -1)
                        {
                            options.AuditRetentionPeriod = TimeSpan.FromHours(i);
                        }
                    }
                }

                if (!options.OverrideEnableErrorForwarding.HasValue & !instance.AppConfig.AppSettingExists(SettingsList.ForwardErrorMessages.Name))
                {
                    ThrowTerminatingError(new ErrorRecord(new Exception($"Upgrade of {instance.Name} aborted. ForwardErrorMessages parameter must be set to true or false because the configuration file has no setting for ForwardErrorMessages. This setting is mandatory as of version 1.12"), "UpgradeFailure", ErrorCategory.InvalidArgument, null));
                }

                if (!options.MaintenancePort.HasValue & !instance.AppConfig.AppSettingExists(SettingsList.DatabaseMaintenancePort.Name))
                {
                    ThrowTerminatingError(new ErrorRecord(new Exception($"Upgrade of {instance.Name} aborted. DatabaseMaintenancePort parameter must be set to a value between 1 and 49151 because the configuration file has no setting for DatabaseMaintenancePort. This setting is mandatory as of version 2.0.0. If this is the only instance of ServiceControl, 33334 is the recommended value."), "UpgradeFailure", ErrorCategory.InvalidArgument, null));
                }

                if (!options.ErrorRetentionPeriod.HasValue & !instance.AppConfig.AppSettingExists(SettingsList.ErrorRetentionPeriod.Name))
                {
                    ThrowTerminatingError(new ErrorRecord(new Exception($"Upgrade of {instance.Name} aborted. ErrorRetentionPeriod parameter must be set to timespan because the configuration file has no setting for ErrorRetentionPeriod. This setting is mandatory as of version 1.13"), "UpgradeFailure", ErrorCategory.InvalidArgument, null));
                }

                if (!options.AuditRetentionPeriod.HasValue & !instance.AppConfig.AppSettingExists(SettingsList.AuditRetentionPeriod.Name))
                {
                    ThrowTerminatingError(new ErrorRecord(new Exception($"Upgrade of {instance.Name} aborted. AuditRetentionPeriod parameter must be set to timespan because the configuration file has no setting for AuditRetentionPeriod. This setting is mandatory as of version 1.13"), "UpgradeFailure", ErrorCategory.InvalidArgument, null));
                }

                if (!installer.Upgrade(instance, options))
                {
                    ThrowTerminatingError(new ErrorRecord(new Exception($"Upgrade of {instance.Name} failed"), "UpgradeFailure", ErrorCategory.InvalidResult, null));
                }
            }
        }
        static void UpgradeInstances(Session session, PlatformZipInfo zipInfo, MSILogger logger, UnattendServiceControlInstaller unattendedInstaller)
        {
            var options = new ServiceControlUpgradeOptions();

            var upgradeInstancesPropertyValue = session["UPGRADEINSTANCES"];

            if (string.IsNullOrWhiteSpace(upgradeInstancesPropertyValue))
            {
                return;
            }

            upgradeInstancesPropertyValue = upgradeInstancesPropertyValue.Trim();

            var forwardErrorMessagesPropertyValue = session["FORWARDERRORMESSAGES"];

            try
            {
                options.OverrideEnableErrorForwarding = bool.Parse(forwardErrorMessagesPropertyValue);
            }
            catch
            {
                options.OverrideEnableErrorForwarding = null;
            }

            var auditRetentionPeriodPropertyValue = session["AUDITRETENTIONPERIOD"];

            try
            {
                options.AuditRetentionPeriod = TimeSpan.Parse(auditRetentionPeriodPropertyValue);
            }
            catch
            {
                options.AuditRetentionPeriod = null;
            }

            var errorRetentionPeriodPropertyValue = session["ERRORRETENTIONPERIOD"];

            try
            {
                options.ErrorRetentionPeriod = TimeSpan.Parse(errorRetentionPeriodPropertyValue);
            }
            catch
            {
                options.ErrorRetentionPeriod = null;
            }

            //determine what to upgrade
            var instancesToUpgrade = new List <ServiceControlInstance>();

            if (upgradeInstancesPropertyValue.Equals("*", StringComparison.OrdinalIgnoreCase) || upgradeInstancesPropertyValue.Equals("ALL", StringComparison.OrdinalIgnoreCase))
            {
                instancesToUpgrade.AddRange(InstanceFinder.ServiceControlInstances());
            }
            else
            {
                var candidates = upgradeInstancesPropertyValue.Replace(" ", String.Empty).Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                instancesToUpgrade.AddRange(InstanceFinder.ServiceControlInstances().Where(instance => candidates.Contains(instance.Name, StringComparer.OrdinalIgnoreCase)));
            }

            // do upgrades
            foreach (var instance in instancesToUpgrade)
            {
                if (zipInfo.Version > instance.Version)
                {
                    var upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(zipInfo.Version, instance.Version);

                    options.UpgradeInfo = upgradeInfo;

                    if (!instance.AppConfig.AppSettingExists(ServiceControlSettings.ForwardErrorMessages.Name) & !options.OverrideEnableErrorForwarding.Value)
                    {
                        logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. FORWARDERRORMESSAGES MSI parameter was required because appsettings needed a value for '{ServiceControlSettings.ForwardErrorMessages.Name}'");
                        continue;
                    }

                    if (!options.AuditRetentionPeriod.HasValue)
                    {
                        if (!instance.AppConfig.AppSettingExists(ServiceControlSettings.AuditRetentionPeriod.Name))
                        {
                            //Try migration first
                            if (instance.AppConfig.AppSettingExists(ServiceControlSettings.HoursToKeepMessagesBeforeExpiring.Name))
                            {
                                var i = instance.AppConfig.Read(ServiceControlSettings.HoursToKeepMessagesBeforeExpiring.Name, -1);
                                if (i > 0)
                                {
                                    options.AuditRetentionPeriod = TimeSpan.FromHours(i);
                                }
                            }
                            else
                            {
                                logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. AUDITRETENTIONPERIOD MSI parameter was required because appsettings needed a value for '{ServiceControlSettings.AuditRetentionPeriod.Name}'");
                                continue;
                            }
                        }
                    }

                    if (!instance.AppConfig.AppSettingExists(ServiceControlSettings.ErrorRetentionPeriod.Name) & !options.ErrorRetentionPeriod.HasValue)
                    {
                        logger.Warn($"Unattend upgrade {instance.Name} to {zipInfo.Version} not attempted. ERRORRETENTIONPERIOD MSI parameter was required because appsettings needed a value for '{ServiceControlSettings.ErrorRetentionPeriod.Name}'");
                        continue;
                    }

                    if (!unattendedInstaller.Upgrade(instance, options))
                    {
                        logger.Warn($"Failed to upgrade {instance.Name} to {zipInfo.Version}");
                    }
                }
            }
        }
Example #11
0
        public override async Task ExecuteAsync(InstanceDetailsViewModel model)
        {
            if (LicenseChecks)
            {
                var licenseCheckResult = installer.CheckLicenseIsValid();
                if (!licenseCheckResult.Valid)
                {
                    windowManager.ShowMessage("LICENSE ERROR", $"Upgrade could not continue due to an issue with the current license. {licenseCheckResult.Message}.  Contact [email protected]", hideCancel: true);
                    return;
                }
            }

            var instance = InstanceFinder.FindServiceControlInstance(model.Name);

            instance.Service.Refresh();

            var upgradeInfo = UpgradeControl.GetUpgradeInfoForTargetVersion(installer.ZipInfo.Version, instance.Version);

            var upgradeOptions = new ServiceControlUpgradeOptions {
                UpgradeInfo = upgradeInfo
            };

            if (instance.Version < upgradeInfo.CurrentMinimumVersion)
            {
                windowManager.ShowMessage("VERSION UPGRADE INCOMPATIBLE",
                                          "<Section xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\" TextAlignment=\"Left\" LineHeight=\"Auto\" IsHyphenationEnabled=\"False\" xml:lang=\"en-us\">\r\n" +
                                          $"<Paragraph>You must upgrade to version {upgradeInfo.RecommendedUpgradeVersion} before upgrading to version {installer.ZipInfo.Version}:</Paragraph>\r\n" +
                                          "<List MarkerStyle=\"Decimal\" Margin=\"0,0,0,0\" Padding=\"0,0,0,0\">\r\n" +
                                          $"<ListItem Margin=\"48,0,0,0\"><Paragraph>Uninstall version {installer.ZipInfo.Version}.</Paragraph></ListItem>\r\n" +
                                          $"<ListItem Margin=\"48,0,0,0\"><Paragraph>Download and install version {upgradeInfo.RecommendedUpgradeVersion} from https://github.com/Particular/ServiceControl/releases/tag/{upgradeInfo.RecommendedUpgradeVersion}</Paragraph></ListItem>" +
                                          $"<ListItem Margin=\"48,0,0,0\"><Paragraph>Upgrade this instance to version {upgradeInfo.RecommendedUpgradeVersion}.</Paragraph></ListItem>\r\n" +
                                          "<ListItem Margin=\"48,0,0,0\"><Paragraph>Download and install the latest version from https://particular.net/start-servicecontrol-download</Paragraph></ListItem>\r\n" +
                                          "<ListItem Margin=\"48,0,0,0\"><Paragraph>Upgrade this instance to the latest version of ServiceControl.</Paragraph></ListItem>\r\n" +
                                          "</List>\r\n" +
                                          "</Section>",
                                          hideCancel: true);

                return;
            }

            if (!instance.AppConfig.AppSettingExists(SettingsList.ForwardErrorMessages.Name))
            {
                var result = windowManager.ShowYesNoCancelDialog("UPGRADE QUESTION - DISABLE ERROR FORWARDING", "Error messages can be forwarded to a secondary error queue known as the Error Forwarding Queue. This queue exists to allow external tools to receive error messages. If you do not have a tool processing messages from the Error Forwarding Queue this setting should be disabled.", "So what do you want to do ?", "Do NOT forward", "Yes I want to forward");
                if (!result.HasValue)
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }

                upgradeOptions.OverrideEnableErrorForwarding = !result.Value;
            }

            //Grab old setting if it exists
            if (!instance.AppConfig.AppSettingExists(SettingsList.AuditRetentionPeriod.Name))
            {
                if (instance.AppConfig.AppSettingExists(SettingsList.HoursToKeepMessagesBeforeExpiring.Name))
                {
                    var i = instance.AppConfig.Read(SettingsList.HoursToKeepMessagesBeforeExpiring.Name, -1);
                    if (i != -1)
                    {
                        upgradeOptions.AuditRetentionPeriod = TimeSpan.FromHours(i);
                    }
                }

                // No setting to migrate so display dialog
                if (!upgradeOptions.AuditRetentionPeriod.HasValue)
                {
                    var viewModel = new SliderDialogViewModel("INPUT REQUIRED - DATABASE RETENTION",
                                                              "Service Control periodically purges audit messages from the database.",
                                                              "AUDIT RETENTION PERIOD",
                                                              "Please specify the age at which these records should be removed",
                                                              TimeSpanUnits.Hours,
                                                              SettingConstants.AuditRetentionPeriodMinInHours,
                                                              SettingConstants.AuditRetentionPeriodMaxInHours,
                                                              1,
                                                              24,
                                                              SettingConstants.AuditRetentionPeriodDefaultInHoursForUI);

                    if (windowManager.ShowSliderDialog(viewModel))
                    {
                        upgradeOptions.AuditRetentionPeriod = viewModel.Period;
                    }
                    else
                    {
                        //Dialog was cancelled
                        eventAggregator.PublishOnUIThread(new RefreshInstances());
                        return;
                    }
                }
            }

            if (!instance.AppConfig.AppSettingExists(SettingsList.ErrorRetentionPeriod.Name))
            {
                var viewModel = new SliderDialogViewModel("INPUT REQUIRED - DATABASE RETENTION",
                                                          "Service Control periodically purges resolved and archived error messages from the database.",
                                                          "ERROR RETENTION PERIOD",
                                                          "Please specify the age at which these records should be removed",
                                                          TimeSpanUnits.Days,
                                                          SettingConstants.ErrorRetentionPeriodMinInDays,
                                                          SettingConstants.ErrorRetentionPeriodMaxInDays,
                                                          1,
                                                          1,
                                                          SettingConstants.ErrorRetentionPeriodDefaultInDaysForUI);

                if (windowManager.ShowSliderDialog(viewModel))
                {
                    upgradeOptions.ErrorRetentionPeriod = viewModel.Period;
                }
                else
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }
            }

            if (!instance.AppConfig.AppSettingExists(SettingsList.DatabaseMaintenancePort.Name))
            {
                var viewModel = new TextBoxDialogViewModel("INPUT REQUIRED - MAINTENANCE PORT",
                                                           "When Service Control is set to maintenance mode it requires a prereserved port on which it exposes the RavenDB database.",
                                                           "MAINTENANCE PORT",
                                                           "Please specify an open port that will be used as the maintenance port",
                                                           new MaintenancePortValidator());

                if (windowManager.ShowTextBoxDialog(viewModel))
                {
                    upgradeOptions.MaintenancePort = int.Parse(viewModel.Value);
                }
                else
                {
                    //Dialog was cancelled
                    eventAggregator.PublishOnUIThread(new RefreshInstances());
                    return;
                }
            }

            if (upgradeInfo.DataBaseUpdate) //Database is being updated -> recommend DB backup
            {
                if (!windowManager.ShowYesNoDialog($"STOP INSTANCE AND UPGRADE TO {installer.ZipInfo.Version}",
                                                   $"{model.Name} is going to be upgraded to version {installer.ZipInfo.Version} which uses a different storage format. Database migration will be conducted "
                                                   + " as part of the upgrade. It is recommended that you back up the database before upgrading. To read more about the back up process "
                                                   + " see https://docs.particular.net/servicecontrol/backup-sc-database.",
                                                   "Do you want to proceed?",
                                                   "Yes I backed up the database and I want to proceed", "No"))
                {
                    return;
                }

                var dbSize = instance.GetDatabaseSizeInGb();
                if (dbSize >= 100) // 100GB
                {
                    if (!windowManager.ShowYesNoDialog("MIGRATE LARGE DATABASE", $"The database being upgraded is {dbSize.ToString("N0")} GB. Migrating this much data could take a long "
                                                       + "time and ServiceControl will be stopped for that entire duration. It is recommended that you consider one of the other upgrade approaches instead.",
                                                       "Are you sure you want to migrate this database?", "Yes", "No"))
                    {
                        return;
                    }
                }
            }
            else
            {
                if (instance.Service.Status != ServiceControllerStatus.Stopped &&
                    !windowManager.ShowYesNoDialog($"STOP INSTANCE AND UPGRADE TO {installer.ZipInfo.Version}",
                                                   $"{model.Name} needs to be stopped in order to upgrade to version {installer.ZipInfo.Version}.",
                                                   "Do you want to proceed?",
                                                   "Yes I want to proceed", "No"))
                {
                    return;
                }
            }

            using (var progress = model.GetProgressObject($"UPGRADING {model.Name}"))
            {
                var reportCard   = new ReportCard();
                var restartAgain = model.IsRunning;

                var stopped = await model.StopService(progress);

                if (!stopped)
                {
                    eventAggregator.PublishOnUIThread(new RefreshInstances());

                    reportCard.Errors.Add("Failed to stop the service");
                    reportCard.SetStatus();
                    windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:");

                    return;
                }

                reportCard = await Task.Run(() => installer.Upgrade(instance, upgradeOptions, progress));

                if (reportCard.HasErrors || reportCard.HasWarnings)
                {
                    windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:", "There were some warnings while upgrading the instance:");
                }
                else
                {
                    if (restartAgain)
                    {
                        var serviceStarted = await model.StartService(progress);

                        if (!serviceStarted)
                        {
                            reportCard.Errors.Add("The Service failed to start. Please consult the service control logs for this instance");
                            windowManager.ShowActionReport(reportCard, "UPGRADE FAILURE", "Instance reported this error after upgrade:");
                        }
                    }
                }
            }

            eventAggregator.PublishOnUIThread(new RefreshInstances());
        }