diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4a291b8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,17 @@ +We welcome your code contributions. Before submitting code via a GitHub pull +request, or by filing a bug in https://bugs.mysql.com you will need to have +signed the Oracle Contributor Agreement (see https://oca.opensource.oracle.com). + +Only pull requests from committers that can be verified as having signed the OCA +can be accepted. + +# Submitting a contribution + +1. Make sure you have a user account at bugs.mysql.com. You'll need to reference this + user account when you submit your OCA (Oracle Contributor Agreement). +2. Sign the Oracle OCA. You can find instructions for doing that at the OCA Page. + at https://oca.opensource.oracle.com +3. Validate your contribution by including tests that sufficiently cover the functionality. +4. Verify that the entire test suite passes with your code applied. +5. Submit your pull request via GitHub or uploading it using the contribution tab to a bug + record in https://bugs.mysql.com (using the 'contribution' tab. \ No newline at end of file diff --git a/Configurator/Core/Classes/ExtensionMethods.cs b/Configurator/Core/Classes/ExtensionMethods.cs index 65649cb..0163052 100644 --- a/Configurator/Core/Classes/ExtensionMethods.cs +++ b/Configurator/Core/Classes/ExtensionMethods.cs @@ -1102,6 +1102,207 @@ public static bool ServerSupportsCachingSha2Authentication(this Version serverVe return serverVersion >= new Version("8.0.4"); } + /// + /// Checks if the LTS versions are consecutive. + /// + /// The version to which the upgrade will be made to. + /// The version of the existing server instance. + /// The maturity of the version to which the upgrade will be made to. + /// The maturity of the version of the existing server instance. + /// true if the validation has been met; otherwise, false. + public static bool IsFromLtsToNextLts(this Version newVersion, Version oldVersion, ServerMaturity newVersionMaturity, ServerMaturity oldVersionMaturity) + { + if (newVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (oldVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (newVersionMaturity != ServerMaturity.LTS + || oldVersionMaturity != ServerMaturity.LTS) + { + return false; + } + + if ((oldVersion.Major == 8 + && oldVersion.Minor == 0 + && oldVersion.Build >=35 + && newVersion.Major == 8 + && newVersion.Minor == 4) + || (oldVersion.Major == 8 + && oldVersion.Minor == 4 + && newVersion.Major == 9 + && newVersion.Minor == 7)) + { + return true; + } + + return false; + } + + /// + /// Checks if an LTS version is being upgraded to an innovation release that comes before + /// the next LTS. + /// + /// The version to which the upgrade will be made to. + /// The version of the existing server instance. + /// The maturity of the version to which the upgrade will be made to. + /// The maturity of the version of the existing server instance. + /// true if the validation has been met; otherwise, false. + public static bool IsFromLtsToInnovationBeforeNextLts(this Version newVersion, Version oldVersion, ServerMaturity newVersionMaturity, ServerMaturity oldVersionMaturity) + { + if (newVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (oldVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (newVersionMaturity != ServerMaturity.Innovation + || oldVersionMaturity != ServerMaturity.LTS) + { + return false; + } + + if ((oldVersion.Major == 8 + && oldVersion.Minor == 0 + && oldVersion.Build >= 35 + && newVersion.Major == 8 + && newVersion.Minor < 4) + ||(oldVersion.Major == 8 + && oldVersion.Minor == 4 + && newVersion.Major == 9 + && newVersion.Minor < 7)) + { + return true; + } + + return false; + } + + /// + /// Checks if an innovation release is being upgaded to the next LTS. + /// + /// The version to which the upgrade will be made to. + /// The version of the existing server instance. + /// The maturity of the version to which the upgrade will be made to. + /// The maturity of the version of the existing server instance. + /// true if the validation has been met; otherwise, false. + public static bool IsFromInnovationToNextLts(this Version newVersion, Version oldVersion, ServerMaturity newVersionMaturity, ServerMaturity oldVersionMaturity) + { + if (newVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (oldVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (newVersionMaturity != ServerMaturity.LTS + || oldVersionMaturity != ServerMaturity.Innovation) + { + return false; + } + + if ((oldVersion.Major == 8 + && oldVersion.Minor <= 3 + && newVersion.Major == 8 + && newVersion.Minor == 4) + || (((oldVersion.Major == 8 + && oldVersion.Minor > 4) + || (oldVersion.Major == 9 + && oldVersion.Minor < 7)) + && newVersion.Major == 9 + && newVersion.Minor == 7)) + { + return true; + } + + return false; + } + + /// + /// Checks if both versions are within the same innovation release series. + /// + /// The version to which the upgrade will be made to. + /// The version of the existing server instance. + /// The maturity of the version to which the upgrade will be made to. + /// The maturity of the version of the existing server instance. + /// true if the validation has been met; otherwise, false. + public static bool IsWithinSameInnovationSeries(this Version newVersion, Version oldVersion, ServerMaturity newVersionMaturity, ServerMaturity oldVersionMaturity) + { + if (newVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (oldVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (newVersionMaturity != ServerMaturity.Innovation + || oldVersionMaturity != ServerMaturity.Innovation) + { + return false; + } + + if (oldVersion.Major == newVersion.Major + && ((oldVersion.Major == 8 + && oldVersion.Minor < 4) + || (oldVersion.Major == 9 + && oldVersion.Minor < 7))) + { + return true; + } + + return false; + } + + /// + /// Checks if both versions are within the same LTS. + /// + /// The version to which the upgrade will be made to. + /// The version of the existing server instance. + /// The maturity of the version to which the upgrade will be made to. + /// The maturity of the version of the existing server instance. + /// true if the validation has been met; otherwise, false. + public static bool IsWithinSameLts(this Version newVersion, Version oldVersion, ServerMaturity newVersionMaturity, ServerMaturity oldVersionMaturity) + { + if (newVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (oldVersion == null) + { + throw new ArgumentNullException(nameof(oldVersion)); + } + + if (newVersionMaturity != ServerMaturity.LTS + || oldVersionMaturity != ServerMaturity.LTS) + { + return false; + } + + if (oldVersion.Major == newVersion.Major + && oldVersion.Minor == newVersion.Minor) + { + return true; + } + + return false; + } + /// /// Validates if the specified server version supports an in-place upgrade based on the rules outlined by the new versioning scheme. /// @@ -1143,44 +1344,16 @@ public static UpgradeViability ServerSupportsInPlaceUpgrades(this Version newVer return UpgradeViability.Unsupported; } else if ( - // If 8.0.X to 8.Y Innovation. X>=35, Y=1 - (oldVersionMaturity == ServerMaturity.Older - && oldVersion >= new Version(8, 0, 35) - && newVersionMaturiy == ServerMaturity.Innovation - && newVersion.Major == 8 - && newVersion.Minor == 1) - // If 8.0.X to 8.4 LTS. X>=35 - || (oldVersionMaturity == ServerMaturity.Older - && oldVersion >= new Version(8, 0, 35) - && newVersionMaturiy == ServerMaturity.LTS - && newVersion.Major == 8 - && newVersion.Minor == 4) - // Upgrade from innovation to next innovation. 8.X.0 to 8.Y.0 innovation. Y = X + 1 - // E.g. 8.2.0 to 8.3.0 - || (oldVersionMaturity == ServerMaturity.Innovation - && newVersionMaturiy == ServerMaturity.Innovation - && oldVersion.Major == newVersion.Major - && oldVersion.Minor + 1 == newVersion.Minor - && oldVersion.Build == 0 - && newVersion.Build == 0) - // Upgrade from last innovation release to next LTS. E.g. 8.3.0 Innovation to 8.4.0 LTS - || (oldVersionMaturity == ServerMaturity.Innovation - && newVersionMaturiy == ServerMaturity.LTS - && oldVersion.Minor + 1 == newVersion.Minor - && newVersion.Build == 0) - // Upgrade within same LTS. E.g 8.4.X LTS to 8.4.Y LTS - || (oldVersionMaturity == ServerMaturity.LTS - && newVersionMaturiy == ServerMaturity.LTS - && oldVersion.Major == newVersion.Major - && oldVersion.Minor == newVersion.Minor) - // Upgrade from one LTS to the next innovation release. E.g. 8.4.X LTS to 9.0.0 Innovation - || (oldVersionMaturity == ServerMaturity.LTS - && newVersionMaturiy == ServerMaturity.Innovation - && newVersion == new Version(oldVersion.Major + 1, 0, 0)) - // Upgrade from one LTS to the next LTS. E.g. 8.4.X LTS to 9.7.Y LTS - || (oldVersionMaturity == ServerMaturity.LTS - && newVersionMaturiy == ServerMaturity.LTS - && oldVersion.Major + 1 == newVersion.Major)) + // Within an LTS. E.g 8.4.X LTS to 8.4.Y LTS. + IsWithinSameLts(newVersion, oldVersion, newVersionMaturiy, oldVersionMaturity) + // From an LTS to the next LTS series. + || IsFromLtsToNextLts(newVersion, oldVersion, newVersionMaturiy, oldVersionMaturity) + // From an LTS to an innovation release before the next LTS series. + || IsFromLtsToInnovationBeforeNextLts(newVersion, oldVersion, newVersionMaturiy, oldVersionMaturity) + // From an innovation series to the next LTS series. + || IsFromInnovationToNextLts(newVersion, oldVersion, newVersionMaturiy, oldVersionMaturity) + // From within an innovation series. + || IsWithinSameInnovationSeries(newVersion, oldVersion, newVersionMaturiy, oldVersionMaturity)) { return UpgradeViability.Supported; } diff --git a/Configurator/Core/Classes/MySqlUpgradeHistoryManager.cs b/Configurator/Core/Classes/MySqlUpgradeHistoryManager.cs new file mode 100644 index 0000000..50bc0c4 --- /dev/null +++ b/Configurator/Core/Classes/MySqlUpgradeHistoryManager.cs @@ -0,0 +1,135 @@ +/* Copyright (c) 2024, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, as + published by the Free Software Foundation. + + This program is designed to work with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, as + designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have either included with + the program or referenced in the documentation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +using MySql.Configurator.Core.Classes.Logging; +using MySql.Configurator.Core.Common; +using MySql.Configurator.Core.Enums; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Web.Script.Serialization; + +namespace MySql.Configurator.Core.Classes +{ + /// + /// Handles the reading the mysql_upgrade_history server json file. + /// + public static class MySqlUpgradeHistoryManager + { + #region Constants + + /// + /// The name of the ugprade history file. + /// + public const string UPGRADE_HISTORY_FILE_NAME = "mysql_upgrade_history"; + + #endregion + + /// + /// Loads the specified upgrade history file. + /// + /// The directory path where the MySQL upgrade history file is located. + /// A tuple containing the version for the latest entry as well as a flag indicating + /// if the version is appended with a metadata string. + public static (Version, bool) GetUpgradeHistoryLatestVersion(string mysqlUpgradeHistoryFilePath) + { + if (string.IsNullOrEmpty(mysqlUpgradeHistoryFilePath)) + { + throw new ArgumentNullException(nameof(mysqlUpgradeHistoryFilePath)); + } + + var filePath = Path.Combine(mysqlUpgradeHistoryFilePath, "Data", UPGRADE_HISTORY_FILE_NAME); + if (!File.Exists(filePath)) + { + Logger.LogException(new FileNotFoundException(filePath)); + return (null, false); + } + + try + { + MySqlUpgradeHistory upgradeHistory; + using (StreamReader reader = new StreamReader(filePath)) + { + var jsonString = reader.ReadToEnd(); + var serializer = new JavaScriptSerializer(); + upgradeHistory = serializer.Deserialize(jsonString); + } + + if (upgradeHistory.Upgrade_History.Count == 0) + { + throw new ConfiguratorException(ConfiguratorError.UpgradeHistoryElementsNotFound); + } + + var latestEntry = upgradeHistory.Upgrade_History.OrderByDescending(o => DateTime.Parse(o.Date)).First(); + var versionItems = latestEntry.Version.Split('-'); + var version = new Version(versionItems[0]); + return (version, versionItems.Length > 1); + } + catch (Exception ex) + { + Logger.LogException(ex); + return (null, false); + } + } + } + + /// + /// The upgrade history of a MySQL Server instance. + /// Represents the root element of the mysql_upgrade_history server file. + /// + public class MySqlUpgradeHistory + { + /// + /// Gets or sets the file format version number. + /// + public string File_Format { get; set; } + /// + /// Gets or sets a list containing the upgrade history. + /// + public List Upgrade_History { get; set; } + } + + /// + /// Contains historical upgrade details for a MySQL Server instance. + /// + public class UpgradeHistory + { + /// + /// Gets or sets a value indicating the date of the upgrade. + /// + public string Date { get; set; } + /// + /// Gets or sets a value indicating the version number of the server instance. + /// + public string Version { get; set; } + /// + /// Gets or sets a value indicating the maturity (LTS or innovation) of the server instance.. + /// + public string Maturity { get; set; } + /// + /// Gets or sets a value indicating if the data directory was initialized. + /// + public bool Initialize { get; set; } + } +} diff --git a/Configurator/Core/Classes/Utilities.cs b/Configurator/Core/Classes/Utilities.cs index fb0d55e..5ea89fc 100644 --- a/Configurator/Core/Classes/Utilities.cs +++ b/Configurator/Core/Classes/Utilities.cs @@ -1106,9 +1106,7 @@ public static DataTable GetSchemaInformation(string connectionString, SchemaInfo /// public static ServerMaturity GetServerMaturity(Version version) { - if (version.Major < 8 - || (version.Major == 8 - && version.Minor == 0)) + if (version.Major < 8) { return ServerMaturity.Older; } diff --git a/Configurator/Core/Common/GeneralSettings.cs b/Configurator/Core/Common/GeneralSettings.cs index f9409bb..8f797ed 100644 --- a/Configurator/Core/Common/GeneralSettings.cs +++ b/Configurator/Core/Common/GeneralSettings.cs @@ -22,6 +22,7 @@ You should have received a copy of the GNU General Public License 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ using MySql.Configurator.Core.Classes.Logging; +using MySql.Configurator.Core.Enums; using MySql.Configurator.Properties; using System; using System.IO; @@ -52,6 +53,11 @@ public class GeneralSettings /// public string IniDirectory { get; set; } + /// + /// Gets or sets the server installation type selected during a Server's configuration + /// + public ServerInstallationType ServerInstallationType { get; set; } + #endregion } diff --git a/Configurator/Core/Controllers/BaseServerSettings.cs b/Configurator/Core/Controllers/BaseServerSettings.cs index fb595c8..c32be29 100644 --- a/Configurator/Core/Controllers/BaseServerSettings.cs +++ b/Configurator/Core/Controllers/BaseServerSettings.cs @@ -30,7 +30,10 @@ You should have received a copy of the GNU General Public License using MySql.Configurator.Core.Classes.Forms; using MySql.Configurator.Core.Classes.Logging; using MySql.Configurator.Core.Common; +using MySql.Configurator.Core.Dialogs; +using MySql.Configurator.Core.Enums; using MySql.Configurator.Core.IniFile; +using MySql.Configurator.Dialogs; using MySql.Configurator.Properties; using static MySql.Configurator.Core.Classes.Forms.InfoDialog; @@ -136,7 +139,9 @@ public bool GeneralPropertiesChanged } [XmlIgnore] - public string FullConfigFilePath => Path.Combine(IniDirectory, ConfigFile); + public string FullConfigFilePath => !string.IsNullOrEmpty(IniDirectory) + ? Path.Combine(IniDirectory, ConfigFile) + : null; public string IniDirectory { get; set; } @@ -248,11 +253,16 @@ public void FindConfigFile() var foundConfigFile = false; string[] configFileNames = new string[2] { DEFAULT_CONFIG_FILE_NAME, ALTERNATE_CONFIG_FILE_NAME }; - string[] possibleConfigFileLocations = new string[2] { DataDirectory, InstallDirectory }; + string[] possibleConfigFileLocations = new string[3] { DataDirectory, InstallDirectory, IniDirectory }; foreach (var configFileName in configFileNames) { foreach (var directory in possibleConfigFileLocations) { + if (string.IsNullOrEmpty(directory)) + { + continue; + } + if (!File.Exists(Path.Combine(directory, configFileName))) { continue; @@ -261,6 +271,7 @@ public void FindConfigFile() ConfigFile = configFileName; IniDirectory = directory; foundConfigFile = true; + break; } if (foundConfigFile) @@ -304,20 +315,39 @@ public virtual void LoadGeneralSettings() if (!string.IsNullOrEmpty(_generalSettings.IniDirectory)) { var iniFilePath = Path.Combine(_generalSettings.IniDirectory, BaseServerSettings.DEFAULT_CONFIG_FILE_NAME); - if (File.Exists(iniFilePath)) + var alternateIniFilePath = Path.Combine(_generalSettings.IniDirectory, BaseServerSettings.ALTERNATE_CONFIG_FILE_NAME); + var iniFileExists = File.Exists(iniFilePath); + var alternateIniFileExists = File.Exists(alternateIniFilePath); + if (!iniFileExists + && !alternateIniFileExists) { - // Load and parse ini file to get the data dir path. - var iniFile = new IniFileEngine(iniFilePath).Load(); - var dataDirectory = iniFile.FindValue("mysqld", "datadir", false); - if (!string.IsNullOrEmpty(dataDirectory) - && Directory.Exists(dataDirectory)) + using (var configurationFileDialog = new ConfigurationFileDialog()) { - var parentDirectory = Directory.GetParent(dataDirectory); - DataDirectory = parentDirectory != null - ? parentDirectory.FullName - : dataDirectory; + if (configurationFileDialog.ShowDialog() == DialogResult.OK) + { + _generalSettings.IniDirectory = configurationFileDialog.ConfigurationFilePath; + } + else + { + throw new ConfiguratorException(ConfiguratorError.ConfigurationFileNotFound, _generalSettings.IniDirectory); + } } } + + // Load and parse ini file to get the data dir path. + var path = iniFileExists + ? iniFilePath + : alternateIniFilePath; + var iniFile = new IniFileEngine(path).Load(); + var dataDirectory = iniFile.FindValue("mysqld", "datadir", false); + if (!string.IsNullOrEmpty(dataDirectory) + && Directory.Exists(dataDirectory)) + { + var parentDirectory = Directory.GetParent(dataDirectory); + DataDirectory = parentDirectory != null + ? parentDirectory.FullName + : dataDirectory; + } } this.SetPropertyValuesFrom(_generalSettings); diff --git a/Configurator/Core/Controllers/ExtendedServerSettings.cs b/Configurator/Core/Controllers/ExtendedServerSettings.cs deleted file mode 100644 index 988d2d7..0000000 --- a/Configurator/Core/Controllers/ExtendedServerSettings.cs +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2023, 2024, Oracle and/or its affiliates. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License, version 2.0, as - published by the Free Software Foundation. - - This program is designed to work with certain software (including - but not limited to OpenSSL) that is licensed under separate terms, as - designated in a particular file or component or in included license - documentation. The authors of MySQL hereby grant you an additional - permission to link the program and your derivative works with the - separately licensed software that they have either included with - the program or referenced in the documentation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License, version 2.0, for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -using System; -using System.IO; -using System.Linq; -using System.Xml.Serialization; -using MySql.Configurator.Core.Classes; -using MySql.Configurator.Core.Classes.Logging; -using MySql.Configurator.Core.Enums; - -namespace MySql.Configurator.Core.Controllers -{ - /// - /// Represents Server configuration values not stored in the Server's configuration file. - /// - [Serializable] - public class ExtendedServerSettings - { - #region Properties - - /// - /// Gets or sets a value indicating whether the Server is configured as a Service. - /// - public bool ConfigureAsService { get; set; } - - /// - /// Gets or sets a value indicating if the Enterprise Firewall is enabled. - /// - public bool EnterpriseFirewallEnabled { get; set; } - - /// - /// Gets or sets a value indicating whether an upgrade to system tables is pending to be performed. - /// - public bool PendingSystemTablesUpgrade { get; set; } - - #endregion Properties - - /// - /// Deserializes the class. - /// - /// The location where the serialized file is located. - public static ExtendedServerSettings Deserialize(string filePath) - { - ExtendedServerSettings extendedSettings = null; - try - { - var serializer = new XmlSerializer(typeof(ExtendedServerSettings)); - using (var stream = new FileStream(filePath, FileMode.Open)) - { - extendedSettings = (ExtendedServerSettings)serializer.Deserialize(stream); - } - } - catch (Exception ex) - { - Logger.LogException(ex); - } - - return extendedSettings; - } - - /// - /// Serializes the class. - /// - /// The location where the serialized file will be output. - /// true if the serialization was done successfully, false otherwise. - public bool Serialize(string filePath) - { - bool success = true; - try - { - var serializer = new XmlSerializer(typeof(ExtendedServerSettings)); - using (var myWriter = new StreamWriter(filePath, false)) - { - serializer.Serialize(myWriter, this); - myWriter.Close(); - } - } - catch (Exception ex) - { - success = false; - Logger.LogException(ex); - } - - return success; - } - } -} diff --git a/Configurator/Core/Controls/PasswordStrengthLabel.Designer.cs b/Configurator/Core/Controls/PasswordStrengthLabel.Designer.cs index 8cc3bba..05aa028 100644 --- a/Configurator/Core/Controls/PasswordStrengthLabel.Designer.cs +++ b/Configurator/Core/Controls/PasswordStrengthLabel.Designer.cs @@ -76,7 +76,7 @@ private void InitializeComponent() this.ValueLabel.Name = "ValueLabel"; this.ValueLabel.Size = new System.Drawing.Size(36, 13); this.ValueLabel.TabIndex = 30; - this.ValueLabel.Text = "Max"; + this.ValueLabel.Text = "Weak"; // // PasswordStrengthLabel // diff --git a/Configurator/Core/Enums/ConfiguratorError.cs b/Configurator/Core/Enums/ConfiguratorError.cs index 716a6a5..3515615 100644 --- a/Configurator/Core/Enums/ConfiguratorError.cs +++ b/Configurator/Core/Enums/ConfiguratorError.cs @@ -43,9 +43,9 @@ public enum ConfiguratorError : uint VersionNotFound = 1, /// - /// Version not found. + /// Version mismatch. /// - [Description("The version provided does not match with the one installed.")] + [Description("Version for the mysql.exe and mysql_configurator.exe do not match.")] VersionMismatch = 2, /// @@ -99,7 +99,28 @@ public enum ConfiguratorError : uint /// /// Invalid execution mode. /// - [Description("An invalid exeuction mode was provided.")] + [Description("An invalid execution mode was provided.")] InvalidExecutionMode = 11, + + /// + /// Upgrade history elements not found in the server's upgrade history file. + /// + [Description("No upgrade history elements found in the mysql_upgrade_history file.")] + UpgradeHistoryElementsNotFound = 12, + + /// + /// The mysqld.exe was not found in the same directory as mysql_configurator.exe. + /// + [Description("mysqld.exe not found at: '{0}'.")] + MysqldExeNotFound = 13, + + /// + /// The server configuration file was not found. + /// + [Description("Configuration file not found at: '{0}'")] + ConfigurationFileNotFound = 14, + + [Description("Failed to update the authentication plugin of the root user.")] + AuthenticationPluginUpdateFailed = 15 } } diff --git a/Configurator/Core/Enums/ExecutionMode.cs b/Configurator/Core/Enums/ExecutionMode.cs index 70444ce..b1ecb48 100644 --- a/Configurator/Core/Enums/ExecutionMode.cs +++ b/Configurator/Core/Enums/ExecutionMode.cs @@ -29,8 +29,8 @@ namespace MySql.Configurator.Core.Enums public enum ExecutionMode : uint { /// - /// Execution mode in which a server installation is configured, either as a new configuration, a - /// reconfiguration or an upgrade. + /// Execution mode in which a server installation is configured, either as a new configuration or a + /// reconfiguration. /// Configure = 0, /// @@ -42,5 +42,9 @@ public enum ExecutionMode : uint /// the Configurator is automatically closed and a warning is added to the log. /// RemoveNoShow = 2, + /// + /// Execution mode in which a server installation is upgraded. + /// + Upgrade = 3 } } diff --git a/Configurator/Core/Enums/ServerInstallationType.cs b/Configurator/Core/Enums/ServerInstallationType.cs index b412eea..0653799 100644 --- a/Configurator/Core/Enums/ServerInstallationType.cs +++ b/Configurator/Core/Enums/ServerInstallationType.cs @@ -25,6 +25,7 @@ namespace MySql.Configurator.Core.Enums { public enum ServerInstallationType { + None = 0, Dedicated = 1, Server = 2, Developer = 3, diff --git a/Configurator/Core/IniFile/Template/IniTemplate.cs b/Configurator/Core/IniFile/Template/IniTemplate.cs index cbf4cf2..b36dff2 100644 --- a/Configurator/Core/IniFile/Template/IniTemplate.cs +++ b/Configurator/Core/IniFile/Template/IniTemplate.cs @@ -63,7 +63,7 @@ public IniTemplate(Version serverVersion, ServerInstallationType iniServerType) SetDefaults(); InitializeDeprecatedServerVariables(); ServerVersion = serverVersion; - ServerType = iniServerType; + ServerInstallationType = iniServerType; } /// @@ -164,7 +164,7 @@ public List DeprecatedVariablesForVersion public string LogError { get; set; } public string LogOutput { get; set; } public string LongQueryTime { get; set; } - public uint LooseMySqlXPort { get; set; } + public uint MySqlXPort { get; set; } public LowerCaseTableNamesTypes LowerCaseTableNames { get; set; } public string MemoryName { get; set; } public double MyisamUsage { get; set; } @@ -180,7 +180,7 @@ public List DeprecatedVariablesForVersion public Version ServerVersion { get; } - public ServerInstallationType ServerType + public ServerInstallationType ServerInstallationType { get { @@ -470,7 +470,7 @@ public void ProcessTemplate(bool isReconfigure = false, bool writeTemplate = tru _formulaEngine.AssignFormulaVariable("bitedness", Win32.Is64BitOs ? "0" : "1"); _formulaEngine.AssignFormulaVariable("secure_file_priv", SecureFilePriv); _formulaEngine.AssignFormulaVariable("plugin_load", PluginLoad); - _formulaEngine.AssignFormulaVariable("loose_mysqlx_port", LooseMySqlXPort.ToString()); + _formulaEngine.AssignFormulaVariable("mysqlx_port", MySqlXPort.ToString()); _formulaEngine.AssignFormulaVariable("named_pipe_full_access_group", NamedPipeFullAccessGroup); // In this case we don't want the existing file to be replaced. @@ -1086,7 +1086,7 @@ private void SetDefaults() SkipInnodb = false; IsValid = false; OutputExists = false; - ServerType = ServerInstallationType.Developer; + ServerInstallationType = ServerInstallationType.Developer; LongQueryTime = "10"; NamedPipeFullAccessGroup = string.Empty; @@ -1118,7 +1118,9 @@ private void InitializeDeprecatedServerVariables() new DeprecatedServerVariable("innodbclusterport", ServerSeriesType.S57 | ServerSeriesType.S80), new DeprecatedServerVariable("innodbclustertypeselection", ServerSeriesType.S57 | ServerSeriesType.S80), new DeprecatedServerVariable("sync_master_info", new Version(8,0,26)), - new DeprecatedServerVariable("sync_relay_log_info=", new Version(8,0,34)) + new DeprecatedServerVariable("sync_relay_log_info=", new Version(8,0,34)), + new DeprecatedServerVariable("loose_mysqlx_port", ServerSeriesType.All), + new DeprecatedServerVariable("server_type", ServerSeriesType.All) }; } } diff --git a/Configurator/Core/Wizard/WizardPage.cs b/Configurator/Core/Wizard/WizardPage.cs index 4599e37..f70c873 100644 --- a/Configurator/Core/Wizard/WizardPage.cs +++ b/Configurator/Core/Wizard/WizardPage.cs @@ -27,6 +27,7 @@ You should have received a copy of the GNU General Public License using MySql.Configurator.Core.Classes; using MySql.Configurator.Core.Classes.Logging; using MySql.Configurator.Core.Interfaces; +using Action = System.Action; using Utilities = MySql.Configurator.Core.Classes.Utilities; namespace MySql.Configurator.Core.Wizard @@ -47,7 +48,6 @@ public WizardPage() InitializeComponent(); ErrorProperties = ErrorProviderProperties.Empty; ErrorLabel = null; - WorkDone = false; PageVisible = true; DisabledControlShowingTooltip = null; SkipUpdateButtons = false; @@ -82,6 +82,11 @@ public string Caption public virtual bool NextOk => Wizard.CanGoNext && !ValidationsErrorProvider.HasErrors(); + /// + /// Gets or sets a value indicating that the page is busy executing an operation. + /// + public bool OperationExecuting { get; set; } + public bool PageVisible { get; set; } public string SubCaption @@ -96,12 +101,6 @@ public string SubCaption public IWizard Wizard { get; set; } - /// - /// Property that can be used to signal that a panel has done all its work and there is no - /// need to ask the user if he agrees when closing the application. - /// - public bool WorkDone { get; set; } - /// /// Gets or sets to use with the . /// @@ -138,6 +137,7 @@ public string SubCaption public virtual void Activate() { Logger.LogInformation($"Beginning {Name}."); + OperationExecuting = false; } public virtual bool Back() @@ -145,6 +145,15 @@ public virtual bool Back() return true; } + /// + /// Executes prep work needed before a long running operation. + /// + public virtual void BeginLongRunningOperation() + { + Cursor = Cursors.WaitCursor; + OperationExecuting = true; + } + public virtual bool Cancel() { return true; @@ -155,10 +164,45 @@ public virtual void Deactivate() Logger.LogInformation($"Finished {Name}."); } + /// + /// Executes post work needed after a long running operation. + /// + public virtual void EndLongRunningOperation() + { + Cursor = Cursors.Default; + OperationExecuting = false; + } + public virtual void Execute() { } + /// + /// Executes a long running operation with optional pre and post actions. + /// + /// An action corresponding to the code that will be executed. + /// Flag to indicate if preparation tasks should be executed. + /// Flag to indicate if post tasks should be executed. + protected void ExecuteLongRunningOperation(Action longRunningOperation, bool executeBeforeTasks = true, bool executeAfterTasks = true) + { + try + { + if (executeBeforeTasks) + { + BeginLongRunningOperation(); + } + + longRunningOperation(); + } + finally + { + if (executeBeforeTasks) + { + EndLongRunningOperation(); + } + } + } + public virtual bool Finish() { return true; @@ -169,6 +213,18 @@ public virtual bool Next() return true; } + /// + /// Subscribes custom events relavant to this wizard page. + /// + public virtual void SubscribeEvents() + { + } + + /// Unsubscribes custom events relavant to this wizard page. + public virtual void UnsubscribeEvents() + { + } + public virtual void WizardShowing() { } diff --git a/Configurator/Dialogs/AboutScreenForm.Designer.cs b/Configurator/Dialogs/AboutScreenForm.Designer.cs index 54b3b2b..e0e826b 100644 --- a/Configurator/Dialogs/AboutScreenForm.Designer.cs +++ b/Configurator/Dialogs/AboutScreenForm.Designer.cs @@ -87,7 +87,7 @@ private void InitializeComponent() this.CopyrightLabel.Name = "CopyrightLabel"; this.CopyrightLabel.Size = new System.Drawing.Size(241, 13); this.CopyrightLabel.TabIndex = 1; - this.CopyrightLabel.Text = "Copyright (c) 2023, 2024, Oracle and/or its affiliates."; + this.CopyrightLabel.Text = "Copyright (c) 2023, 2025, Oracle and/or its affiliates."; this.CopyrightLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // RegisteredTrademarkLabel diff --git a/Configurator/Dialogs/ConfigurationFileDialog.Designer.cs b/Configurator/Dialogs/ConfigurationFileDialog.Designer.cs new file mode 100644 index 0000000..5b2f5a2 --- /dev/null +++ b/Configurator/Dialogs/ConfigurationFileDialog.Designer.cs @@ -0,0 +1,306 @@ +/* Copyright (c) 2024, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, as + published by the Free Software Foundation. + + This program is designed to work with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, as + designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have either included with + the program or referenced in the documentation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +namespace MySql.Configurator.Dialogs +{ + partial class ConfigurationFileDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.DialogCancelButton = new System.Windows.Forms.Button(); + this.OkButton = new System.Windows.Forms.Button(); + this.ConfigurationFileErrorPictureBox = new System.Windows.Forms.PictureBox(); + this.ConfigurationFileErrorLabel = new System.Windows.Forms.Label(); + this.ConfigurationFileRevertButton = new System.Windows.Forms.Button(); + this.ConfigurationFileBrowseButton = new System.Windows.Forms.Button(); + this.ConfigurationFilePathLabel = new System.Windows.Forms.Label(); + this.ConfigurationFileTextBox = new System.Windows.Forms.TextBox(); + this.ConfigurationFilePathDescriptionLabel = new System.Windows.Forms.Label(); + this.LogoPictureBox = new System.Windows.Forms.PictureBox(); + this.TitleLabel = new System.Windows.Forms.Label(); + this.ToolTip = new System.Windows.Forms.ToolTip(this.components); + this.ValidationsErrorProvider = new System.Windows.Forms.ErrorProvider(this.components); + this.ValidationsTimer = new System.Windows.Forms.Timer(this.components); + this.ContentAreaPanel.SuspendLayout(); + this.CommandAreaPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.ConfigurationFileErrorPictureBox)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.LogoPictureBox)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.ValidationsErrorProvider)).BeginInit(); + this.SuspendLayout(); + // + // FootnoteAreaPanel + // + this.FootnoteAreaPanel.Location = new System.Drawing.Point(0, 449); + this.FootnoteAreaPanel.Size = new System.Drawing.Size(951, 0); + // + // ContentAreaPanel + // + this.ContentAreaPanel.Controls.Add(this.LogoPictureBox); + this.ContentAreaPanel.Controls.Add(this.TitleLabel); + this.ContentAreaPanel.Controls.Add(this.ConfigurationFilePathDescriptionLabel); + this.ContentAreaPanel.Controls.Add(this.ConfigurationFileErrorPictureBox); + this.ContentAreaPanel.Controls.Add(this.ConfigurationFileErrorLabel); + this.ContentAreaPanel.Controls.Add(this.ConfigurationFileRevertButton); + this.ContentAreaPanel.Controls.Add(this.ConfigurationFileBrowseButton); + this.ContentAreaPanel.Controls.Add(this.ConfigurationFilePathLabel); + this.ContentAreaPanel.Controls.Add(this.ConfigurationFileTextBox); + this.ContentAreaPanel.Size = new System.Drawing.Size(505, 220); + // + // CommandAreaPanel + // + this.CommandAreaPanel.Controls.Add(this.OkButton); + this.CommandAreaPanel.Controls.Add(this.DialogCancelButton); + this.CommandAreaPanel.Location = new System.Drawing.Point(0, 175); + this.CommandAreaPanel.Size = new System.Drawing.Size(505, 45); + // + // DialogCancelButton + // + this.DialogCancelButton.AccessibleDescription = "A button to dismiss the dialog"; + this.DialogCancelButton.AccessibleName = "Cancel"; + this.DialogCancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.DialogCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.DialogCancelButton.Location = new System.Drawing.Point(418, 10); + this.DialogCancelButton.Name = "DialogCancelButton"; + this.DialogCancelButton.Size = new System.Drawing.Size(75, 23); + this.DialogCancelButton.TabIndex = 1; + this.DialogCancelButton.Text = "Cancel"; + this.DialogCancelButton.UseVisualStyleBackColor = true; + // + // OkButton + // + this.OkButton.AccessibleDescription = "A button to apply the changes done to the advanced install options"; + this.OkButton.AccessibleName = "OK"; + this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OkButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.OkButton.Enabled = false; + this.OkButton.Location = new System.Drawing.Point(337, 10); + this.OkButton.Name = "OkButton"; + this.OkButton.Size = new System.Drawing.Size(75, 23); + this.OkButton.TabIndex = 0; + this.OkButton.Text = "OK"; + this.OkButton.UseVisualStyleBackColor = true; + // + // ConfigurationFileErrorPictureBox + // + this.ConfigurationFileErrorPictureBox.AccessibleDescription = "A picture box displaying an error icon for an invalid configuration file path"; + this.ConfigurationFileErrorPictureBox.AccessibleName = "Configuration File Error Icon"; + this.ConfigurationFileErrorPictureBox.Image = global::MySql.Configurator.Properties.Resources.error_sign; + this.ConfigurationFileErrorPictureBox.Location = new System.Drawing.Point(15, 145); + this.ConfigurationFileErrorPictureBox.Name = "ConfigurationFileErrorPictureBox"; + this.ConfigurationFileErrorPictureBox.Size = new System.Drawing.Size(16, 16); + this.ConfigurationFileErrorPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; + this.ConfigurationFileErrorPictureBox.TabIndex = 57; + this.ConfigurationFileErrorPictureBox.TabStop = false; + this.ConfigurationFileErrorPictureBox.Visible = false; + // + // ConfigurationFileErrorLabel + // + this.ConfigurationFileErrorLabel.AccessibleDescription = "A label displaying a message about a warning or error in the configuration file p" + + "ath validation"; + this.ConfigurationFileErrorLabel.AccessibleName = "Configuration File Validation Text"; + this.ConfigurationFileErrorLabel.AutoSize = true; + this.ConfigurationFileErrorLabel.Location = new System.Drawing.Point(34, 146); + this.ConfigurationFileErrorLabel.Name = "ConfigurationFileErrorLabel"; + this.ConfigurationFileErrorLabel.Size = new System.Drawing.Size(0, 25); + this.ConfigurationFileErrorLabel.TabIndex = 4; + this.ConfigurationFileErrorLabel.Visible = false; + // + // ConfigurationFileRevertButton + // + this.ConfigurationFileRevertButton.AccessibleDescription = "A button to revert the value of the configuration file path"; + this.ConfigurationFileRevertButton.AccessibleName = "Configuration File Revert"; + this.ConfigurationFileRevertButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.ConfigurationFileRevertButton.BackgroundImage = global::MySql.Configurator.Properties.Resources.Revert; + this.ConfigurationFileRevertButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.ConfigurationFileRevertButton.FlatAppearance.BorderSize = 0; + this.ConfigurationFileRevertButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.ConfigurationFileRevertButton.Location = new System.Drawing.Point(460, 99); + this.ConfigurationFileRevertButton.Margin = new System.Windows.Forms.Padding(0); + this.ConfigurationFileRevertButton.Name = "ConfigurationFileRevertButton"; + this.ConfigurationFileRevertButton.Size = new System.Drawing.Size(29, 20); + this.ConfigurationFileRevertButton.TabIndex = 1; + this.ConfigurationFileRevertButton.UseVisualStyleBackColor = true; + this.ConfigurationFileRevertButton.Click += new System.EventHandler(this.ConfigurationFileRevertButton_Click); + // + // ConfigurationFileBrowseButton + // + this.ConfigurationFileBrowseButton.AccessibleDescription = "A button to open a dialog to browse through the file system and select the path t" + + "o the configuration file"; + this.ConfigurationFileBrowseButton.AccessibleName = "Configuration File Browse"; + this.ConfigurationFileBrowseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.ConfigurationFileBrowseButton.Location = new System.Drawing.Point(461, 116); + this.ConfigurationFileBrowseButton.Name = "ConfigurationFileBrowseButton"; + this.ConfigurationFileBrowseButton.Size = new System.Drawing.Size(29, 22); + this.ConfigurationFileBrowseButton.TabIndex = 3; + this.ConfigurationFileBrowseButton.Text = "..."; + this.ConfigurationFileBrowseButton.UseVisualStyleBackColor = true; + this.ConfigurationFileBrowseButton.Click += new System.EventHandler(this.ConfigurationFileBrowseButton_Click); + // + // ConfigurationFilePathLabel + // + this.ConfigurationFilePathLabel.AccessibleDescription = "A label displaying the text configuration file path"; + this.ConfigurationFilePathLabel.AccessibleName = "Configuration File Path Text"; + this.ConfigurationFilePathLabel.AutoSize = true; + this.ConfigurationFilePathLabel.Location = new System.Drawing.Point(12, 95); + this.ConfigurationFilePathLabel.Name = "ConfigurationFilePathLabel"; + this.ConfigurationFilePathLabel.Size = new System.Drawing.Size(195, 25); + this.ConfigurationFilePathLabel.TabIndex = 0; + this.ConfigurationFilePathLabel.Text = "Configuration File Path:"; + // + // ConfigurationFileTextBox + // + this.ConfigurationFileTextBox.AccessibleDescription = "A text box to set the full absolute path of the server configuration file"; + this.ConfigurationFileTextBox.AccessibleName = "Configuration File Path"; + this.ConfigurationFileTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ConfigurationFileTextBox.Location = new System.Drawing.Point(12, 115); + this.ConfigurationFileTextBox.Name = "ConfigurationFileTextBox"; + this.ConfigurationFileTextBox.Size = new System.Drawing.Size(443, 31); + this.ConfigurationFileTextBox.TabIndex = 2; + this.ConfigurationFileTextBox.TextChanged += new System.EventHandler(this.ConfigurationFileTextBox_TextChangedHandler); + this.ConfigurationFileTextBox.Validated += new System.EventHandler(this.ConfigurationFileTextBox_Validated); + // + // ConfigurationFilePathDescriptionLabel + // + this.ConfigurationFilePathDescriptionLabel.AccessibleDescription = "A label displaying a description about the need to provide the path to the server" + + " configuration file"; + this.ConfigurationFilePathDescriptionLabel.AccessibleName = "Configuration file path description"; + this.ConfigurationFilePathDescriptionLabel.Font = new System.Drawing.Font("Segoe UI", 9F); + this.ConfigurationFilePathDescriptionLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(102)))), ((int)(((byte)(102)))), ((int)(((byte)(102))))); + this.ConfigurationFilePathDescriptionLabel.Location = new System.Drawing.Point(90, 46); + this.ConfigurationFilePathDescriptionLabel.Name = "ConfigurationFilePathDescriptionLabel"; + this.ConfigurationFilePathDescriptionLabel.Size = new System.Drawing.Size(401, 44); + this.ConfigurationFilePathDescriptionLabel.TabIndex = 58; + this.ConfigurationFilePathDescriptionLabel.Text = "The server configuration file (my.ini or my.cnf) was not found. Please specify th" + + "e location of the file to continue."; + // + // LogoPictureBox + // + this.LogoPictureBox.AccessibleDescription = "A picture box displaying an icon related to the consumer application and the dial" + + "og\'s purpose"; + this.LogoPictureBox.AccessibleName = "Icon"; + this.LogoPictureBox.Image = global::MySql.Configurator.Properties.Resources.MainLogo; + this.LogoPictureBox.Location = new System.Drawing.Point(12, 15); + this.LogoPictureBox.Margin = new System.Windows.Forms.Padding(4, 6, 4, 6); + this.LogoPictureBox.Name = "LogoPictureBox"; + this.LogoPictureBox.Size = new System.Drawing.Size(66, 65); + this.LogoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.LogoPictureBox.TabIndex = 60; + this.LogoPictureBox.TabStop = false; + // + // TitleLabel + // + this.TitleLabel.AccessibleDescription = "A generic title label"; + this.TitleLabel.AccessibleName = "Title"; + this.TitleLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TitleLabel.AutoEllipsis = true; + this.TitleLabel.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.TitleLabel.ForeColor = System.Drawing.Color.Navy; + this.TitleLabel.Location = new System.Drawing.Point(91, 15); + this.TitleLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.TitleLabel.Name = "TitleLabel"; + this.TitleLabel.Size = new System.Drawing.Size(402, 31); + this.TitleLabel.TabIndex = 59; + this.TitleLabel.Text = "Server Configuration File Not Found"; + // + // ValidationsErrorProvider + // + this.ValidationsErrorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink; + this.ValidationsErrorProvider.ContainerControl = this; + // + // ValidationsTimer + // + this.ValidationsTimer.Interval = 800; + this.ValidationsTimer.Tick += new System.EventHandler(this.ValidationsTimer_Tick); + // + // ConfigurationFileDialog + // + this.AcceptButton = this.OkButton; + this.AccessibleDescription = "A modal dialog showing a textbox to select the path of the server configuraiton f" + + "ile"; + this.AccessibleName = "Configuration File Dialog"; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.CancelButton = this.DialogCancelButton; + this.ClientSize = new System.Drawing.Size(505, 220); + this.CommandAreaHeight = 45; + this.CommandAreaVisible = true; + this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FootnoteAreaHeight = 0; + this.Name = "ConfigurationFileDialog"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "MySQL Configurator"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ConfigurationFileDialog_FormClosing); + this.ContentAreaPanel.ResumeLayout(false); + this.ContentAreaPanel.PerformLayout(); + this.CommandAreaPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.ConfigurationFileErrorPictureBox)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.LogoPictureBox)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.ValidationsErrorProvider)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.Button DialogCancelButton; + private System.Windows.Forms.PictureBox ConfigurationFileErrorPictureBox; + private System.Windows.Forms.Label ConfigurationFileErrorLabel; + private System.Windows.Forms.Button ConfigurationFileRevertButton; + private System.Windows.Forms.Button ConfigurationFileBrowseButton; + private System.Windows.Forms.Label ConfigurationFilePathLabel; + private System.Windows.Forms.TextBox ConfigurationFileTextBox; + protected System.Windows.Forms.Button OkButton; + private System.Windows.Forms.Label ConfigurationFilePathDescriptionLabel; + private System.Windows.Forms.PictureBox LogoPictureBox; + private System.Windows.Forms.Label TitleLabel; + protected System.Windows.Forms.ToolTip ToolTip; + protected System.Windows.Forms.ErrorProvider ValidationsErrorProvider; + protected System.Windows.Forms.Timer ValidationsTimer; + } +} diff --git a/Configurator/Dialogs/ConfigurationFileDialog.cs b/Configurator/Dialogs/ConfigurationFileDialog.cs new file mode 100644 index 0000000..5cb83e8 --- /dev/null +++ b/Configurator/Dialogs/ConfigurationFileDialog.cs @@ -0,0 +1,202 @@ +/* Copyright (c) 2024, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, as + published by the Free Software Foundation. + + This program is designed to work with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, as + designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have either included with + the program or referenced in the documentation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using MySql.Configurator.Core.Classes; +using MySql.Configurator.Core.Forms; +using Utilities = MySql.Configurator.Core.Classes.Utilities; +using MySql.Configurator.Properties; +using MySql.Configurator.Core.Controllers; +using static System.Windows.Forms.VisualStyles.VisualStyleElement; + +namespace MySql.Configurator.Dialogs +{ + /// + /// Dialog that enables to provide an updated path for the server configuration file. + /// + public partial class ConfigurationFileDialog : AutoStyleableBaseDialog + { + /// + /// Initializes a new instance of the class. + /// + public ConfigurationFileDialog() + { + InitializeComponent(); + } + + #region Properties + + /// + /// The path containing the my.ini or my.cnf server configuration file. + /// + public string ConfigurationFilePath { get; private set; } + + #endregion Properties + + /// + /// Checks that the path in the Configuration File textbox is valid and contains a server + /// configuration file. + /// + protected void CheckDirectory() + { + var path = ConfigurationFileTextBox.Text.Trim(); + ConfigurationFileErrorLabel.Text = string.Empty; + ConfigurationFileErrorPictureBox.Visible = false; + if (string.IsNullOrEmpty(path)) + { + OkButton.Enabled = false; + return; + } + + var iniFilePath = Path.Combine(path, BaseServerSettings.DEFAULT_CONFIG_FILE_NAME); + var alternateIniFilePath = Path.Combine(path, BaseServerSettings.ALTERNATE_CONFIG_FILE_NAME); + if (path.IndexOfAny(Path.GetInvalidPathChars()) >= 0 || !Path.IsPathRooted(path)) + { + ConfigurationFileErrorLabel.Text = Resources.PathInvalidError; + ConfigurationFileErrorPictureBox.Visible = true; + } + + var errorMessage = Utilities.ValidateFilePath(path); + if (!string.IsNullOrEmpty(errorMessage)) + { + ConfigurationFileErrorLabel.Text = errorMessage; + ConfigurationFileErrorPictureBox.Visible = true; + } + + if (!File.Exists(iniFilePath) + && !File.Exists(alternateIniFilePath)) + { + ConfigurationFileErrorLabel.Text = Resources.ConfigurationFileNotFound; + ConfigurationFileErrorPictureBox.Visible = true; + } + + ConfigurationFileErrorLabel.Visible = !string.IsNullOrEmpty(ConfigurationFileErrorLabel.Text); + OkButton.Enabled = !ConfigurationFileErrorPictureBox.Visible; + } + + /// + /// Handles the OnLoad event. + /// + /// The instance containing the event data. + protected override void OnLoad(EventArgs e) + { + Utilities.NormalizeFont(this); + base.OnLoad(e); + } + + /// + /// Handles the FormClosing event. + /// + /// The source of the event. + /// The instance containing the event data. + private void ConfigurationFileDialog_FormClosing(object sender, FormClosingEventArgs e) + { + if (DialogResult == DialogResult.Cancel) + { + return; + } + + ConfigurationFilePath = ConfigurationFileTextBox.Text.Trim(); + } + + /// + /// Handles the Click event for the Browse button. + /// + /// The source of the event. + /// The instance containing the event data. + private void ConfigurationFileBrowseButton_Click(object sender, EventArgs e) + { + using (var folderBrowserDialog = new FolderBrowserDialog()) + { + folderBrowserDialog.SelectedPath = ConfigurationFileTextBox.Text; + if (folderBrowserDialog.ShowDialog() == DialogResult.Cancel) + { + return; + } + + ConfigurationFileTextBox.Text = folderBrowserDialog.SelectedPath; + } + + CheckDirectory(); + } + + /// + /// Handles the Click event for the Revert button. + /// + /// The source of the event. + /// The instance containing the event data. + private void ConfigurationFileRevertButton_Click(object sender, EventArgs e) + { + ConfigurationFileTextBox.Clear(); + CheckDirectory(); + } + + /// + /// Resets the validations timer. + /// + private void ResetValidationsTimer() + { + ValidationsTimer.Stop(); + ValidationsTimer.Start(); + } + + /// + /// Handles the TextValidated event. + /// + /// The source of the event. + /// The instance containing the event data. + /// This event method is meant to be used with the event. + private void ConfigurationFileTextBox_Validated(object sender, EventArgs e) + { + CheckDirectory(); + } + + /// + /// Handles the TextChanged event. + /// + /// The source of the event. + /// The instance containing the event data. + private void ConfigurationFileTextBox_TextChangedHandler(object sender, EventArgs e) + { + ResetValidationsTimer(); + } + + /// + /// Handles the Tick event. + /// + /// The source of the event. + /// The instance containing the event data. + private void ValidationsTimer_Tick(object sender, EventArgs e) + { + var focusedTextBox = this.GetChildControlsOfType().FirstOrDefault(control => control.Focused); + if (focusedTextBox != null) + { + ConfigurationFileTextBox_Validated(focusedTextBox, EventArgs.Empty); + } + } + } +} diff --git a/Configurator/Dialogs/ConfigurationFileDialog.resx b/Configurator/Dialogs/ConfigurationFileDialog.resx new file mode 100644 index 0000000..f351272 --- /dev/null +++ b/Configurator/Dialogs/ConfigurationFileDialog.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 25, 19 + + + 148, 19 + + + 407, 19 + + \ No newline at end of file diff --git a/Configurator/Dialogs/MainForm.cs b/Configurator/Dialogs/MainForm.cs index a537975..391ad7b 100644 --- a/Configurator/Dialogs/MainForm.cs +++ b/Configurator/Dialogs/MainForm.cs @@ -24,6 +24,7 @@ You should have received a copy of the GNU General Public License using System; using System.Configuration; using System.Drawing; +using System.IO; using System.Linq; using System.Windows.Forms; using MySql.Configurator.Core.Classes; @@ -122,6 +123,68 @@ private void SetWindowPosition() private void TryToLaunchWizard(bool launchedFromMainIcon) { + // Update execution mode if current configuration needs to be upgraded. + var controller = _package.Controller as ServerConfigurationController; + if (controller == null) + { + throw new ArgumentNullException(nameof(controller)); + } + + var upgradeHistoryFileExists = false; + Version existingServerVersion = new Version(); + if (_executionMode == ExecutionMode.Configure) + { + var path = Path.Combine(controller.DataDirectory, "Data", MySqlUpgradeHistoryManager.UPGRADE_HISTORY_FILE_NAME); + upgradeHistoryFileExists = File.Exists(path); + + // TODO: Enable upgrade history file regeneration when server bug is fixed. + /* + // If upgrade history file does not exist, stop and start server to regenerate it. + if (!upgradeHistoryFileExists + && controller.IsThereServerDataFiles + && _package.Version.Major >= 8 + && _package.Version.Minor >= 4) + { + var serverInstance = new LocalServerInstance(controller); + serverInstance.DataDir = controller.DataDirectory; + if (serverInstance.IsRunning) + { + serverInstance.StopInstance(); + } + + serverInstance.StartInstanceAsProcess("--upgrade=MINIMAL"); + upgradeHistoryFileExists = File.Exists(path); + } + */ + + if (controller.IsThereServerDataFiles + && upgradeHistoryFileExists) + { + (Version, bool) result = MySqlUpgradeHistoryManager.GetUpgradeHistoryLatestVersion(controller.DataDirectory); + existingServerVersion = result.Item1; + bool hasMetadata = result.Item2; + + // If the version is lower or if version is the same but we have metadata it means that this is + // an updated version of the current package and needs to be upgraded. + if (existingServerVersion != null + && (existingServerVersion < _package.Version) + || (existingServerVersion == _package.Version + && hasMetadata)) + { + var validUpgrade = _package.Version.ServerSupportsInPlaceUpgrades(existingServerVersion); + if (validUpgrade == UpgradeViability.Supported + && _package.Version.Major == existingServerVersion.Major + && _package.Version.Minor == existingServerVersion.Minor) + { + Logger.LogInformation(Resources.ExecutionModeSwitch); + _executionMode = ExecutionMode.Upgrade; + controller.IsSameDirectoryUpgrade = true; + } + } + } + } + + // Show wizard matching the selected execution mode. ConfigurationType configurationType; switch (_executionMode) { @@ -144,13 +207,25 @@ private void TryToLaunchWizard(bool launchedFromMainIcon) removeWizard.ShowWizard(_package, this); break; + case ExecutionMode.Upgrade: + configurationType = ConfigurationType.Upgrade; + configWizard = new ConfigWizard(); + Controls.Add(configWizard); + configWizard.WizardCanceled += WizardClosed; + configWizard.WizardClosed += WizardClosed; + configWizard.ShowWizard(_package, this, configurationType); + break; + default: throw new ConfiguratorException(ConfiguratorError.InvalidExecutionMode); } + // Update status bar. StatusStrip.Visible = true; - VersionLabel.Text = $"MySQL Server {_package.VersionString}"; var controllerConfigurationType = _package.Controller.ConfigurationType; + VersionLabel.Text = controllerConfigurationType != ConfigurationType.Upgrade + ? $"MySQL Server {_package.VersionString}" + : $"MySQL Server {(upgradeHistoryFileExists ? existingServerVersion.ToString() : "Unknown")} -> {_package.VersionString}"; var stringConfigurationType = string.Empty; switch (controllerConfigurationType) { @@ -165,7 +240,8 @@ private void TryToLaunchWizard(bool launchedFromMainIcon) ConfigurationTypeLabel.Text = stringConfigurationType; if (controllerConfigurationType == ConfigurationType.Reconfiguration - || controllerConfigurationType == ConfigurationType.Remove) + || controllerConfigurationType == ConfigurationType.Remove + || controllerConfigurationType == ConfigurationType.Upgrade) { var serverController = _package.Controller as ServerConfigurationController; DataDirectoryLabel.Text = $"Data Directory: {serverController.DataDirectory}"; @@ -218,11 +294,17 @@ public bool CanClose() var wizard = Controls.OfType().FirstOrDefault(); if (wizard == null) { - // This is unexpected, a Wizard should be already in the Controls collection, but if not found just let the form close. return true; } - return wizard.CanCancel; + if (wizard.CurrentPage.OperationExecuting) + { + var result = InfoDialog.ShowDialog(InfoDialogProperties.GetYesNoDialogProperties(InfoDialog.InfoType.Warning, Resources.MainFormOnGoingOperationTitle, Resources.MainFormOnGoingOperationDescription, Resources.MainFormOnGoingOperationDetail)); + return result.DialogResult == DialogResult.OK + || result.DialogResult == DialogResult.Yes; + } + + return true; } #region Event handling diff --git a/Configurator/MySQLConfigurator.csproj b/Configurator/MySQLConfigurator.csproj index 1c63c72..41c580e 100644 --- a/Configurator/MySQLConfigurator.csproj +++ b/Configurator/MySQLConfigurator.csproj @@ -2,6 +2,7 @@ Debug + 999.999.999 AnyCPU 9.0.30729 2.0 @@ -114,6 +115,7 @@ + @@ -141,6 +143,7 @@ + @@ -184,7 +187,6 @@ - @@ -383,6 +385,12 @@ AboutScreenForm.cs + + Form + + + ConfigurationFileDialog.cs + Form @@ -646,6 +654,9 @@ AboutScreenForm.cs + + ConfigurationFileDialog.cs + UpgradeFromServerPreGaWarningDialog.cs @@ -685,6 +696,7 @@ ConfigureErrorPage.cs + Designer RemoveErrorPage.cs @@ -884,4 +896,18 @@ --> + + + + <_Parameter1>$(Version) + + + + + + + + \ No newline at end of file diff --git a/Configurator/Program.cs b/Configurator/Program.cs index 25f80e4..b464ad1 100644 --- a/Configurator/Program.cs +++ b/Configurator/Program.cs @@ -64,10 +64,6 @@ public class Program #endregion - #region Properties - - #endregion - /// /// Customizes the looks of common dialogs. /// @@ -126,15 +122,7 @@ For ZIP installations this path is whichever location where the server files wer // Do not show form if running in removal mode and option --show-removal-warning was not provided. Package package = null; - try - { - package = ProductManager.LoadPackage(_version, _installDirPath); - } - catch (ConfiguratorException ex) - { - Logger.LogException(ex); - } - + package = ProductManager.LoadPackage(_version, _installDirPath); if (executionMode == ExecutionMode.RemoveNoShow) { var controller = package.Controller as ServerConfigurationController; @@ -237,29 +225,35 @@ private static ExecutionMode ProcessCommandLineArguments(string[] arguments) _installDirPath = installDirPath; #endif + if (string.IsNullOrEmpty(_installDirPath)) + { + throw new ArgumentNullException(_installDirPath); + } + // Validate install dir. var pathToMySqld = Path.Combine(_installDirPath, "bin\\mysqld.exe"); if (!Directory.Exists(_installDirPath) || !File.Exists(pathToMySqld)) { - _installDirPath = null; + throw new ConfiguratorException(ConfiguratorError.MysqldExeNotFound, _installDirPath); } // Set version. - FileVersionInfo versionInfo = null; - Version versionItem = null; - if (!string.IsNullOrEmpty(_installDirPath)) - { - versionInfo = FileVersionInfo.GetVersionInfo(pathToMySqld); - versionItem = new Version(versionInfo.FileVersion); - } - else + var versionInfo = FileVersionInfo.GetVersionInfo(pathToMySqld); + var mysqldExeVersion = new Version(versionInfo.FileVersion); + var assemblyVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); + var configuratorVersion = new Version(versionInfo.FileVersion); + if (mysqldExeVersion != configuratorVersion) { - versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); - versionItem = new Version(versionInfo.FileVersion); + throw new ConfiguratorException(ConfiguratorError.VersionMismatch); } - _version = $"{versionItem.Major}.{versionItem.Minor}.{versionItem.Build}"; + _version = $"{mysqldExeVersion.Major}.{mysqldExeVersion.Minor}.{mysqldExeVersion.Build}"; + } + catch (ConfiguratorException ex) + { + Logger.LogException(ex); + throw ex; } catch (Exception ex) { diff --git a/Configurator/Properties/AssemblyInfo.cs b/Configurator/Properties/AssemblyInfo.cs index 49b357e..1b56ae0 100644 --- a/Configurator/Properties/AssemblyInfo.cs +++ b/Configurator/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ You should have received a copy of the GNU General Public License [assembly: AssemblyTitle("The MySQL Configurator is designed to allow the configuration and/or upgrade of the MySQL Server product.")] [assembly: AssemblyCompany("Oracle Corporation")] [assembly: AssemblyProduct("MySQL Configurator")] -[assembly: AssemblyCopyright("Copyright (c) 2023, 2024, Oracle and/or its affiliates.")] +[assembly: AssemblyCopyright("Copyright (c) 2023, 2025, Oracle and/or its affiliates.")] [assembly: AssemblyTrademark("Oracle®, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates.")] // Setting ComVisible to false makes the types in this assembly not visible @@ -51,5 +51,3 @@ You should have received a copy of the GNU General Public License // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("8.4.0.0")] -[assembly: AssemblyFileVersion("8.4.0.0")] diff --git a/Configurator/Properties/Resources.Designer.cs b/Configurator/Properties/Resources.Designer.cs index 9163ce2..350d339 100644 --- a/Configurator/Properties/Resources.Designer.cs +++ b/Configurator/Properties/Resources.Designer.cs @@ -1,27 +1,4 @@ -/* Copyright (c) 2023, 2024, Oracle and/or its affiliates. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License, version 2.0, as - published by the Free Software Foundation. - - This program is designed to work with certain software (including - but not limited to OpenSSL) that is licensed under separate terms, as - designated in a particular file or component or in included license - documentation. The authors of MySQL hereby grant you an additional - permission to link the program and your derivative works with the - separately licensed software that they have either included with - the program or referenced in the documentation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License, version 2.0, for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -608,6 +585,15 @@ public static string ConfigStepTakingTooLong { } } + /// + /// Looks up a localized string similar to A my.ini or my.cnf configuration file was not found at the specified location.. + /// + public static string ConfigurationFileNotFound { + get { + return ResourceManager.GetString("ConfigurationFileNotFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to *WARNING*: A deprecated configuration setting is being used('{0}') and will be removed in a future release. Use any of the following keywords instead: {1}.. /// @@ -676,7 +662,7 @@ public static string ConfigureHasTimedOutTitle { /// /// Looks up a localized string similar to The configuration for {0} was successful. - ///Click Finish to continue.. + ///Click Next to continue.. /// public static string ConfigureSuccess { get { @@ -1038,6 +1024,15 @@ public static byte[] example_databases { } } + /// + /// Looks up a localized string similar to MySQL Server needs to be upgraded. Switching to 'upgrade' mode.. + /// + public static string ExecutionModeSwitch { + get { + return ResourceManager.GetString("ExecutionModeSwitch", resourceCulture); + } + } + /// /// Looks up a localized string similar to The data directory name will be renamed to ///"{0}" before the data is upgraded.. @@ -1338,6 +1333,33 @@ public static System.Drawing.Bitmap logo { } } + /// + /// Looks up a localized string similar to There is an ongoing operation and closing MySQL Configurator may result in a corrupt setup.. + /// + public static string MainFormOnGoingOperationDescription { + get { + return ResourceManager.GetString("MainFormOnGoingOperationDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Do you still want to close MySQL Configurator?. + /// + public static string MainFormOnGoingOperationDetail { + get { + return ResourceManager.GetString("MainFormOnGoingOperationDetail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An operation is currently running. + /// + public static string MainFormOnGoingOperationTitle { + get { + return ResourceManager.GetString("MainFormOnGoingOperationTitle", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -2712,6 +2734,25 @@ public static string ServerConfigCheckingAccessToLogs { } } + /// + /// Looks up a localized string similar to A my.ini or my.cnf server configuration file was not found in the location as the data directory. + ///Provide a path for the server configuration file.. + /// + public static string ServerConfigConfigurationFileNotFound { + get { + return ResourceManager.GetString("ServerConfigConfigurationFileNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified ini file could not be read. Provide a valid server configuration file or select a different file to continue.. + /// + public static string ServerConfigConfigurationFileNotValid { + get { + return ResourceManager.GetString("ServerConfigConfigurationFileNotValid", resourceCulture); + } + } + /// /// Looks up a localized string similar to Failed to convert inherited permissions to explicit permissions.. /// @@ -3181,6 +3222,24 @@ public static string ServerConfigFailedToRetrieveLocalPrincipals { } } + /// + /// Looks up a localized string similar to Failed to revert the authentication plugin change for the root user with message: {0}.. + /// + public static string ServerConfigFailedToRevertAuthenticationPluginChange { + get { + return ResourceManager.GetString("ServerConfigFailedToRevertAuthenticationPluginChange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to update the authentication plugin of the root user.. + /// + public static string ServerConfigFailedToUpdateRootUserAuthPlugin { + get { + return ResourceManager.GetString("ServerConfigFailedToUpdateRootUserAuthPlugin", resourceCulture); + } + } + /// /// Looks up a localized string similar to General settings file not found.. /// @@ -3307,6 +3366,16 @@ public static string ServerConfigInstanceRunning { } } + /// + /// Looks up a localized string similar to The 'root' user is configured to use the 'mysql_native_password' authentication plugin. + ///Proceeding with the upgrade will update the plugin to 'caching_sha2_password'.. + /// + public static string ServerConfigInvalidAuthenticationPlugin { + get { + return ResourceManager.GetString("ServerConfigInvalidAuthenticationPlugin", resourceCulture); + } + } + /// /// Looks up a localized string similar to One or more of the given security tokens is not valid. Please verify the list entered:. /// @@ -3559,6 +3628,15 @@ public static string ServerConfigRevertDataDirRenameError { } } + /// + /// Looks up a localized string similar to Reverted the authentication plugin change for the root user.. + /// + public static string ServerConfigRevertedAuthenticationPluginChange { + get { + return ResourceManager.GetString("ServerConfigRevertedAuthenticationPluginChange", resourceCulture); + } + } + /// /// Looks up a localized string similar to Reverted the data directory renaming.. /// @@ -3568,6 +3646,15 @@ public static string ServerConfigRevertedDataDirRename { } } + /// + /// Looks up a localized string similar to Reverting the authentication plugin change for the root user.... + /// + public static string ServerConfigRevertingAuthenticationPluginChanged { + get { + return ResourceManager.GetString("ServerConfigRevertingAuthenticationPluginChanged", resourceCulture); + } + } + /// /// Looks up a localized string similar to Reverting the data directory renaming.... /// @@ -3847,6 +3934,15 @@ public static string ServerConfigUnspecifiedError { } } + /// + /// Looks up a localized string similar to Updated authentication plugin of the root user.. + /// + public static string ServerConfigUpdatedRootUserAuthPlugin { + get { + return ResourceManager.GetString("ServerConfigUpdatedRootUserAuthPlugin", resourceCulture); + } + } + /// /// Looks up a localized string similar to Updating existing service.... /// @@ -3865,6 +3961,15 @@ public static string ServerConfigUpdatingExistingServiceWithNewName { } } + /// + /// Looks up a localized string similar to Updating the authentication plugin of the root user to: {0}.. + /// + public static string ServerConfigUpdatingRootUserAuthPlugin { + get { + return ResourceManager.GetString("ServerConfigUpdatingRootUserAuthPlugin", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unable to access the Active Directory of the domain. Confirm that. /// @@ -4252,6 +4357,15 @@ public static string ServerStopProcessStep { } } + /// + /// Looks up a localized string similar to Updating authentication plugin for the root user. + /// + public static string ServerUpdateAuthenticationPluginStep { + get { + return ResourceManager.GetString("ServerUpdateAuthenticationPluginStep", resourceCulture); + } + } + /// /// Looks up a localized string similar to Updating example databases. /// @@ -4433,20 +4547,11 @@ public static string SettingsFileReadError { } /// - /// Looks up a localized string similar to Setting up product configuration controller for new installation.. - /// - public static string SettingUpNewInstallation { - get { - return ResourceManager.GetString("SettingUpNewInstallation", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Setting up product configuration controller for reconfiguration.. + /// Looks up a localized string similar to Product configuration controller set to '{0}' configuration type.. /// - public static string SettingUpReconfiguration { + public static string SettingUpControllerMessage { get { - return ResourceManager.GetString("SettingUpReconfiguration", resourceCulture); + return ResourceManager.GetString("SettingUpControllerMessage", resourceCulture); } } diff --git a/Configurator/Properties/Resources.resx b/Configurator/Properties/Resources.resx index 5c16804..956b5ea 100644 --- a/Configurator/Properties/Resources.resx +++ b/Configurator/Properties/Resources.resx @@ -294,7 +294,7 @@ Click Finish to continue. The configuration for {0} was successful. -Click Finish to continue. +Click Next to continue. The removal for some products has failed or was cancelled by the user. @@ -919,11 +919,8 @@ Provide a more complex password for stronger security. Setting the instance as writable - - Setting up product configuration controller for new installation. - - - Setting up product configuration controller for reconfiguration. + + Product configuration controller set to '{0}' configuration type. Setting up product configuration controller for upgrade. @@ -1773,4 +1770,51 @@ the upgrade may result in an upgrade failure, proceed at your own risk. Invalid action provided. Running in configuration mode. + + MySQL Server needs to be upgraded. Switching to 'upgrade' mode. + + + A my.ini or my.cnf configuration file was not found at the specified location. + + + A my.ini or my.cnf server configuration file was not found in the location as the data directory. +Provide a path for the server configuration file. + + + The specified ini file could not be read. Provide a valid server configuration file or select a different file to continue. + + + Failed to update the authentication plugin of the root user. + + + The 'root' user is configured to use the 'mysql_native_password' authentication plugin. +Proceeding with the upgrade will update the plugin to 'caching_sha2_password'. + + + Updated authentication plugin of the root user. + + + Updating the authentication plugin of the root user to: {0}. + + + Updating authentication plugin for the root user + + + Failed to revert the authentication plugin change for the root user with message: {0}. + + + Reverted the authentication plugin change for the root user. + + + Reverting the authentication plugin change for the root user... + + + There is an ongoing operation and closing MySQL Configurator may result in a corrupt setup. + + + Do you still want to close MySQL Configurator? + + + An operation is currently running + \ No newline at end of file diff --git a/Configurator/Resources/my-template-8.x.ini b/Configurator/Resources/my-template-8.x.ini index 7afba2c..6f4b776 100644 --- a/Configurator/Resources/my-template-8.x.ini +++ b/Configurator/Resources/my-template-8.x.ini @@ -136,8 +136,6 @@ no-beep # you have installed the server correctly (see above) so it reads this # file. # -# [SERVER_TYPE]="server_type" -# server_type= [mysqld] # The next three options are mutually exclusive to SERVER_PORT below. diff --git a/Configurator/Wizards/Common/BaseConfigureRemoveApplyPage.cs b/Configurator/Wizards/Common/BaseConfigureRemoveApplyPage.cs index 36983b3..6566bef 100644 --- a/Configurator/Wizards/Common/BaseConfigureRemoveApplyPage.cs +++ b/Configurator/Wizards/Common/BaseConfigureRemoveApplyPage.cs @@ -39,7 +39,6 @@ public partial class BaseConfigureRemoveApplyPage : WizardPage #region Fields protected ProductConfigurationController CurrentController; - protected bool Executing; protected Stopwatch StopWatch; #endregion Fields @@ -48,7 +47,6 @@ public BaseConfigureRemoveApplyPage() { InitializeComponent(); StopWatch = new Stopwatch(); - Executing = false; } public BaseConfigureRemoveApplyPage(ProductConfigurationController controller) @@ -79,16 +77,9 @@ public override bool Finish() { string msg = string.Format(Resources.ConfirmFinishWithFailingConfig, CurrentController.Package.NameWithVersion); result = InfoDialog.ShowDialog(InfoDialogProperties.GetYesNoDialogProperties(InfoDialog.InfoType.Warning, Resources.AppName, msg)).DialogResult; - bool shouldClose = result == DialogResult.Yes; - if (shouldClose) - { - DetachEvents(); - } - - return shouldClose; + return result == DialogResult.Yes; } - DetachEvents(); if (!RebootWhenDoneCheckBox.Checked) { return base.Finish(); @@ -144,15 +135,11 @@ public override bool FinishOk { SetControlVisibleStatus(Wizard.FinishButton, !Wizard.ExecuteButton.Visible); SetControlVisibleStatus(Wizard.BackButton, Wizard.ExecuteButton.Visible); - return !Executing; + return !OperationExecuting; } } #endregion Properties - - protected virtual void DetachEvents() - { - } protected void RebootWhenDoneCheckBox_CheckedChanged_1(object sender, EventArgs e) { diff --git a/Configurator/Wizards/ConfigWizard/ConfigApplyPage.cs b/Configurator/Wizards/ConfigWizard/ConfigApplyPage.cs index be6fb1a..e73b071 100644 --- a/Configurator/Wizards/ConfigWizard/ConfigApplyPage.cs +++ b/Configurator/Wizards/ConfigWizard/ConfigApplyPage.cs @@ -35,6 +35,7 @@ You should have received a copy of the GNU General Public License using MySql.Configurator.Properties; using MySql.Configurator.Wizards.Common; using MySql.Configurator.Wizards.Server; +using Action = System.Action; namespace MySql.Configurator.Wizards.ConfigWizard { @@ -63,7 +64,7 @@ public override bool NextOk { get { Wizard.FinishButton.Visible = false; - return !Executing + return !OperationExecuting && !Wizard.ExecuteButton.Enabled; } } @@ -117,17 +118,10 @@ public override bool Next() { string msg = string.Format(Resources.ConfirmFinishWithFailingConfig, CurrentController.Package.NameWithVersion); result = InfoDialog.ShowDialog(InfoDialogProperties.GetYesNoDialogProperties(InfoDialog.InfoType.Warning, Resources.AppName, msg)).DialogResult; - bool shouldClose = result == DialogResult.Yes; - if (shouldClose) - { - DetachEvents(); - } - - return shouldClose; + return result == DialogResult.Yes; } Wizard.Log = LogContentsTextBox.Text; - DetachEvents(); if (!RebootWhenDoneCheckBox.Checked) { return base.Finish(); @@ -154,44 +148,66 @@ public override bool Next() public override void Execute() { - if (_callActivateOnExecute) + Action action; + action = delegate { - Activate(); - } + if (_callActivateOnExecute) + { + Activate(); + } - LogContentsTextBox.Clear(); - Executing = true; - Wizard.ExecuteButton.Enabled = false; - Wizard.CancelButton.Visible = true; - ConfigurationResultLabel.Text = string.Empty; - RetryButton.Visible = false; + LogContentsTextBox.Clear(); + Wizard.ExecuteButton.Enabled = false; + Wizard.CancelButton.Visible = true; + ConfigurationResultLabel.Text = string.Empty; + RetryButton.Visible = false; + + foreach (var configStepControl in ExecutionStepsTabPage.Controls.OfType()) + { + configStepControl.SetStatus(ConfigStepControl.OPEN); + } + + subCaptionLabel.Text = Resources.ConfigStepsAreExecuting; + if (Wizard is ConfigWizard configWizard) + { + CurrentController.ConfigurationType = configWizard.ConfigurationType; + } - foreach (var configStepControl in ExecutionStepsTabPage.Controls.OfType()) + CurrentController.Configure(); + }; + + ExecuteLongRunningOperation(action, false, false); + } + + /// + /// Subscribes custom events relavant to this wizard page. + /// + public override void SubscribeEvents() + { + base.SubscribeEvents(); + if (CurrentController == null) { - configStepControl.SetStatus(ConfigStepControl.OPEN); + throw new ArgumentNullException(nameof(CurrentController)); } - subCaptionLabel.Text = Resources.ConfigStepsAreExecuting; - DetachEvents(); + CurrentController.ConfigurationStarted += ConfigurationStarted; CurrentController.ConfigurationEnded += ConfigurationEnded; CurrentController.ConfigureTimedOut += ConfigureTimedOut; CurrentController.ConfigurationStatusChanged += controller_ConfigurationStatusChanged; - if (Wizard is ConfigWizard configWizard) - { - CurrentController.ConfigurationType = configWizard.ConfigurationType; - } - - UpdateButtons(); - - Wizard.BackButton.Visible = false; - Wizard.ExecuteButton.Enabled = false; - Wizard.CancelButton.Visible = true; - - CurrentController.Configure(); } - protected override void DetachEvents() + /// + /// Unsubscribes custom events relavant to this wizard page. + /// + public override void UnsubscribeEvents() { + base.UnsubscribeEvents(); + if (CurrentController == null) + { + throw new ArgumentNullException(nameof(CurrentController)); + } + + CurrentController.ConfigurationStarted -= ConfigurationStarted; CurrentController.ConfigurationEnded -= ConfigurationEnded; CurrentController.ConfigureTimedOut -= ConfigureTimedOut; CurrentController.ConfigurationStatusChanged -= controller_ConfigurationStatusChanged; @@ -199,67 +215,86 @@ protected override void DetachEvents() private void ConfigurationEnded(object sender, EventArgs e) { - Executing = false; - subCaptionLabel.Text = Resources.ConfigStepsFinished; - switch (CurrentController.CurrentState) + try { - case ConfigState.ConfigurationError: - _callActivateOnExecute = true; - ConfigurationResultLabel.Text = string.Format(Resources.ConfigureFailed, CurrentController.Package.NameWithVersion); - RetryButton.Visible = true; - Wizard.BackButton.Enabled = true; - Wizard.BackButton.Visible = true; - - // Update step descriptions. - var serverController = CurrentController as ServerConfigurationController; - if (serverController != null) - { - var revertedSteps = serverController.RevertedSteps; - if (revertedSteps == null) - { - break; - } - - foreach (var revertedStep in revertedSteps) + subCaptionLabel.Text = Resources.ConfigStepsFinished; + switch (CurrentController.CurrentState) + { + case ConfigState.ConfigurationError: + _callActivateOnExecute = true; + ConfigurationResultLabel.Text = string.Format(Resources.ConfigureFailed, CurrentController.Package.NameWithVersion); + RetryButton.Visible = true; + Wizard.BackButton.Enabled = true; + Wizard.BackButton.Visible = true; + + // Update step descriptions. + var serverController = CurrentController as ServerConfigurationController; + if (serverController != null) { - var control = ExecutionStepsTabPage.Controls.OfType().FirstOrDefault(configStepControl => configStepControl.Step.Description.Equals(revertedStep)); - if (control == null) + var revertedSteps = serverController.RevertedSteps; + if (revertedSteps == null) { - continue; + break; } - control.Label = $"{control.Step.Description} (REVERTED)"; - } - } + foreach (var revertedStep in revertedSteps) + { + var control = ExecutionStepsTabPage.Controls.OfType().FirstOrDefault(configStepControl => configStepControl.Step.Description.Equals(revertedStep)); + if (control == null) + { + continue; + } - break; + control.Label = $"{control.Step.Description} (REVERTED)"; + } + } - case ConfigState.ConfigurationCancelled: - _callActivateOnExecute = true; - ConfigurationResultLabel.Text = string.Format(Resources.ConfigureCancelled, CurrentController.Package.NameWithVersion); - RetryButton.Visible = true; - break; + break; + + case ConfigState.ConfigurationCancelled: + _callActivateOnExecute = true; + ConfigurationResultLabel.Text = string.Format(Resources.ConfigureCancelled, CurrentController.Package.NameWithVersion); + RetryButton.Visible = true; + break; + + default: + _callActivateOnExecute = false; + ConfigurationResultLabel.Text = string.Format(Resources.ConfigureSuccess, CurrentController.Package.NameWithVersion); + ShowConfigurationSummaryTab(); + Wizard.ExecuteButton.Visible = false; + Wizard.CancelButton.Visible = false; + Wizard.BackButton.Visible = false; + break; + } - default: - _callActivateOnExecute = false; - ConfigurationResultLabel.Text = string.Format(Resources.ConfigureSuccess, CurrentController.Package.NameWithVersion); - ShowConfigurationSummaryTab(); - Wizard.ExecuteButton.Visible = false; - Wizard.CancelButton.Visible = false; - Wizard.BackButton.Visible = false; - break; + if (CurrentController.ConfigurationType == ConfigurationType.Reconfiguration + && CurrentController.RebootRequired) + { + ExecutionTabControl.Height -= RebootWhenDonePanel.Height; + RebootWhenDonePanel.Visible = true; + RebootWhenDoneCheckBox.Checked = true; + } } - - if (CurrentController.ConfigurationType == ConfigurationType.Reconfiguration - && CurrentController.RebootRequired) + finally { - ExecutionTabControl.Height -= RebootWhenDonePanel.Height; - RebootWhenDonePanel.Visible = true; - RebootWhenDoneCheckBox.Checked = true; + EndLongRunningOperation(); + UpdateButtons(); + Wizard.FinishButton.Visible = false; } + } + /// + /// Event method triggered when the configuration operation starts. + /// + /// The sender object. + /// The evenet arugments. + private void ConfigurationStarted(object sender, EventArgs e) + { + BeginLongRunningOperation(); UpdateButtons(); - Wizard.FinishButton.Visible = false; + Wizard.BackButton.Visible = false; + Wizard.ExecuteButton.Enabled = false; + Wizard.CancelButton.Visible = true; } private void ConfigureTimedOut(object sender, EventArgs e) diff --git a/Configurator/Wizards/ConfigWizard/ConfigCompletePage.cs b/Configurator/Wizards/ConfigWizard/ConfigCompletePage.cs index 639945c..f58df06 100644 --- a/Configurator/Wizards/ConfigWizard/ConfigCompletePage.cs +++ b/Configurator/Wizards/ConfigWizard/ConfigCompletePage.cs @@ -62,7 +62,6 @@ public override bool BackOk public override void Activate() { base.Activate(); - WorkDone = true; // This is the last page, no need to ask for confirmation to close. if (!(Wizard is ConfigWizard configWizard)) { return; diff --git a/Configurator/Wizards/RemoveWizard/RemoveApplyPage.cs b/Configurator/Wizards/RemoveWizard/RemoveApplyPage.cs index 2a09414..30aea4d 100644 --- a/Configurator/Wizards/RemoveWizard/RemoveApplyPage.cs +++ b/Configurator/Wizards/RemoveWizard/RemoveApplyPage.cs @@ -38,6 +38,7 @@ You should have received a copy of the GNU General Public License using MySql.Configurator.Core.Product; using MySql.Configurator.Properties; using MySql.Configurator.Wizards.Common; +using Action = System.Action; namespace MySql.Configurator.Wizards.RemoveWizard { @@ -178,7 +179,7 @@ public override void Activate() public override bool Cancel() { if (PackageManager != null - && Executing) + && !OperationExecuting) { PackageManager.Cancel(); } @@ -192,30 +193,36 @@ public override bool Cancel() /// public override void Execute() { - subCaptionLabel.Visible = false; - Wizard.BackButton.Enabled = false; - Wizard.ExecuteButton.Enabled = false; - - // Reset failed steps. - foreach (var removeStepControl in RemoveStepsFlowLayoutPanel.Controls.OfType().Where(removeStepControl => removeStepControl.Controller.CurrentState == ConfigState.ConfigurationError)) + Action action; + action = delegate { - removeStepControl.Controller.ResetState(); - removeStepControl.Step.Status = ConfigurationStepStatus.NotStarted; - removeStepControl.SetStatus(ConfigStepControl.OPEN); - if (removeStepControl.SubSteps == null - || removeStepControl.SubSteps.Count == 0) - { - continue; - } + subCaptionLabel.Visible = false; + Wizard.BackButton.Enabled = false; + Wizard.ExecuteButton.Enabled = false; - foreach (var subStep in removeStepControl.SubSteps) + // Reset failed steps. + foreach (var removeStepControl in RemoveStepsFlowLayoutPanel.Controls.OfType().Where(removeStepControl => removeStepControl.Controller.CurrentState == ConfigState.ConfigurationError)) { - subStep.Step.Status = ConfigurationStepStatus.NotStarted; - subStep.SetStatus(ConfigStepControl.OPEN); + removeStepControl.Controller.ResetState(); + removeStepControl.Step.Status = ConfigurationStepStatus.NotStarted; + removeStepControl.SetStatus(ConfigStepControl.OPEN); + if (removeStepControl.SubSteps == null + || removeStepControl.SubSteps.Count == 0) + { + continue; + } + + foreach (var subStep in removeStepControl.SubSteps) + { + subStep.Step.Status = ConfigurationStepStatus.NotStarted; + subStep.SetStatus(ConfigStepControl.OPEN); + } } - } - UninstallNextProduct(); + UninstallNextProduct(); + }; + + ExecuteLongRunningOperation(action, false, false); } /// @@ -307,12 +314,39 @@ public virtual void QueueFinished(object sender, EventArgs e) } /// - /// Unsubscribes events from the handlers. + /// Subscribes custom events relavant to this wizard page. /// - protected override void DetachEvents() + public override void SubscribeEvents() { - if (_parentRemoveStepControl == null) + base.SubscribeEvents(); + if (_parentRemoveStepControl == null + || _parentRemoveStepControl.Controller == null) + { + // We don't raise an exception because for this page the _parentRemoveStepControl + // is determined until the operation is ongoing and the control assinged + // to _parentRemoveStepControl changes based on the product currently being removed. + return; + } + + _parentRemoveStepControl.Controller.ConfigurationStarted += ConfigurationStarted; + _parentRemoveStepControl.Controller.ConfigurationEnded += ConfigurationEnded; + _parentRemoveStepControl.Controller.ConfigureTimedOut += ConfigureTimedOut; + _parentRemoveStepControl.Controller.ConfigurationStatusChanged += controller_ConfigurationStatusChanged; + _parentRemoveStepControl.Controller.PackageUninstall += PackageUninstall; + } + + /// + /// Unsubscribes custom events relavant to this wizard page. + /// + public override void UnsubscribeEvents() + { + base.UnsubscribeEvents(); + if (_parentRemoveStepControl == null + || _parentRemoveStepControl.Controller == null) { + // We don't raise an exception because for this page the _parentRemoveStepControl + // is determined until the operation is ongoing and the control assinged + // to _parentRemoveStepControl changes based on the product currently being removed. return; } @@ -415,7 +449,6 @@ private void CollapseButton_Click(object sender, EventArgs e) /// The instance containing the event data. private void ConfigurationEnded(object sender, EventArgs e) { - Executing = false; _currentProgress = 100; SetProgress(100); @@ -450,6 +483,7 @@ private void ConfigurationStarted(object sender, EventArgs e) return; } + BeginLongRunningOperation(); _currentProgress = 0; var stepCount = _parentRemoveStepControl.SubSteps == null || _parentRemoveStepControl.SubSteps.Count == 0 @@ -806,55 +840,61 @@ private void StartStep(BaseStep step, string message) /// private void TerminateUninstallOperation() { - subCaptionLabel.Text = Resources.RemoveStepsFinished; - if (RemoveStepsFlowLayoutPanel.Controls.OfType().Any(control => - control.Controller.CurrentState == ConfigState.ConfigurationCancelled - || control.Controller.CurrentState == ConfigState.ConfigurationError)) + try { - ConfigurationResultLabel.Text = Resources.RemoveFailed; - RetryButton.Visible = true; - RebootWhenDonePanel.Visible = true; - RebootWhenDoneCheckBox.Visible = false; - RebootWhenDoneLabel.Visible = false; - Wizard.BackButton.Enabled = true; - Wizard.BackButton.Visible = true; - } - else - { - ConfigurationResultLabel.Text = RemoveStepsFlowLayoutPanel.Controls.OfType().Any(control => - control.HasFailedSubSteps(false) == true) - ? Resources.RemoveSuccessWithErrors - : Resources.RemoveSuccess; - RetryButton.Visible = false; - RebootWhenDonePanel.Visible = false; - Wizard.ExecuteButton.Visible = false; - Wizard.CancelButton.Visible = false; - Wizard.BackButton.Visible = false; - Wizard.FinishButton.Visible = true; - RemoveStepsFlowLayoutPanel.Height -= HEIGHT_REDUCED_WHEN_UNINSTALL_COMPLETE; - } - - if (UninstallInstallerPanel.Visible) - { - ExecutionTabControl.Height -= HEIGHT_REDUCED_WHEN_UNINSTALL_COMPLETE; - } - - if (RemoveStepsFlowLayoutPanel.Controls.OfType().Any(control => control.Controller.RebootRequired)) - { - RebootWhenDonePanel.Visible = true; - RebootWhenDoneCheckBox.Visible = true; - RebootWhenDoneLabel.Visible = true; - RebootWhenDoneCheckBox.Checked = true; - ToolTip.SetToolTip(RebootWhenDoneCheckBox, GetRebootWhenDoneCheckBoxToolTip()); + subCaptionLabel.Text = Resources.RemoveStepsFinished; + if (RemoveStepsFlowLayoutPanel.Controls.OfType().Any(control => + control.Controller.CurrentState == ConfigState.ConfigurationCancelled + || control.Controller.CurrentState == ConfigState.ConfigurationError)) + { + ConfigurationResultLabel.Text = Resources.RemoveFailed; + RetryButton.Visible = true; + RebootWhenDonePanel.Visible = true; + RebootWhenDoneCheckBox.Visible = false; + RebootWhenDoneLabel.Visible = false; + Wizard.BackButton.Enabled = true; + Wizard.BackButton.Visible = true; + } + else + { + ConfigurationResultLabel.Text = RemoveStepsFlowLayoutPanel.Controls.OfType().Any(control => + control.HasFailedSubSteps(false) == true) + ? Resources.RemoveSuccessWithErrors + : Resources.RemoveSuccess; + RetryButton.Visible = false; + RebootWhenDonePanel.Visible = false; + Wizard.ExecuteButton.Visible = false; + Wizard.CancelButton.Visible = false; + Wizard.BackButton.Visible = false; + Wizard.FinishButton.Visible = true; + RemoveStepsFlowLayoutPanel.Height -= HEIGHT_REDUCED_WHEN_UNINSTALL_COMPLETE; + } if (UninstallInstallerPanel.Visible) { ExecutionTabControl.Height -= HEIGHT_REDUCED_WHEN_UNINSTALL_COMPLETE; - RebootWhenDonePanel.Location = new Point(RebootWhenDonePanel.Location.X, ExecutionTabControl.Location.Y + ExecutionTabControl.Height + 5); } - } - Wizard.FinishButton.Enabled = FinishOk; + if (RemoveStepsFlowLayoutPanel.Controls.OfType().Any(control => control.Controller.RebootRequired)) + { + RebootWhenDonePanel.Visible = true; + RebootWhenDoneCheckBox.Visible = true; + RebootWhenDoneLabel.Visible = true; + RebootWhenDoneCheckBox.Checked = true; + ToolTip.SetToolTip(RebootWhenDoneCheckBox, GetRebootWhenDoneCheckBoxToolTip()); + + if (UninstallInstallerPanel.Visible) + { + ExecutionTabControl.Height -= HEIGHT_REDUCED_WHEN_UNINSTALL_COMPLETE; + RebootWhenDonePanel.Location = new Point(RebootWhenDonePanel.Location.X, ExecutionTabControl.Location.Y + ExecutionTabControl.Height + 5); + } + } + } + finally + { + EndLongRunningOperation(); + Wizard.FinishButton.Enabled = FinishOk; + } } /// @@ -863,7 +903,7 @@ private void TerminateUninstallOperation() /// private bool UninstallNextProduct() { - DetachEvents(); + UnsubscribeEvents(); var parentRemoveStepControl = RemoveStepsFlowLayoutPanel.Controls.OfType().FirstOrDefault(removeStepControl => removeStepControl.Step.Status == ConfigurationStepStatus.NotStarted && removeStepControl.Controller.CurrentState != ConfigState.ConfigurationError); @@ -874,12 +914,12 @@ private bool UninstallNextProduct() _parentRemoveStepControl = parentRemoveStepControl; CurrentController = _parentRemoveStepControl.Controller; - Executing = true; CurrentController.ConfigurationStarted += ConfigurationStarted; CurrentController.ConfigurationEnded += ConfigurationEnded; CurrentController.ConfigureTimedOut += ConfigureTimedOut; CurrentController.ConfigurationStatusChanged += controller_ConfigurationStatusChanged; CurrentController.PackageUninstall += PackageUninstall; + SubscribeEvents(); CurrentController.Remove(); return true; } diff --git a/Configurator/Wizards/RemoveWizard/RemoveProductsWizard.cs b/Configurator/Wizards/RemoveWizard/RemoveProductsWizard.cs index 5193e40..b5da66d 100644 --- a/Configurator/Wizards/RemoveWizard/RemoveProductsWizard.cs +++ b/Configurator/Wizards/RemoveWizard/RemoveProductsWizard.cs @@ -90,8 +90,6 @@ public void ShowWizard(Package package, MainForm parentMainForm) WizardSideBar.ShowConfigPanel(package.NameWithVersion); ClearPages(); package.Controller.ConfigurationType = ConfigurationType.Remove; - package.Controller.UpdateRemoveSteps(); - package.Controller.SetPages(); var serverController = package.Controller as ServerConfigurationController; if (serverController == null) { @@ -105,6 +103,8 @@ public void ShowWizard(Package package, MainForm parentMainForm) return; } + package.Controller.UpdateRemoveSteps(); + package.Controller.SetPages(); ProductsToRemove.Add(package); foreach (var page in package.Controller.Pages.Where(page => page.ValidForType(package.Controller.ConfigurationType))) { diff --git a/Configurator/Wizards/Server/MySqlServerSettings.cs b/Configurator/Wizards/Server/MySqlServerSettings.cs index f75eca0..00cfd13 100644 --- a/Configurator/Wizards/Server/MySqlServerSettings.cs +++ b/Configurator/Wizards/Server/MySqlServerSettings.cs @@ -64,6 +64,7 @@ public MySqlServerSettings(Package p) { NewServerUsers = new List(); Plugins = new PluginsList(p.Version); + ServerInstallationType = ServerInstallationType.Developer; } #region Properties @@ -217,7 +218,7 @@ public MySqlServerSettings(Package p) [ControllerSetting("Optimizes settings depending on the intended use of the server instance.", "server_type", "servertype")] [DefaultValue(ServerInstallationType.Developer)] - public ServerInstallationType ServerInstallType { get; set; } + public ServerInstallationType ServerInstallationType { get; set; } [ControllerSetting("The password of the Windows User Account used to run the Windows Service. Ignored if " + "as_windows_service is false or if windows_service_user is not present.", "windows_service_password,win_service_pwd", "sapass")] @@ -285,7 +286,7 @@ public void Save(IniTemplate template, bool skipExistingValues = false) throw new Exception(Resources.InvalidServerTemplate); } - template.ServerType = ServerInstallType; + template.ServerInstallationType = ServerInstallationType; template.EnableNetworking = EnableTcpIp; template.Port = Port; template.EnableNamedPipe = EnableNamedPipe; @@ -310,7 +311,7 @@ public void Save(IniTemplate template, bool skipExistingValues = false) template.LowerCaseTableNames = LowerCaseTableNames; template.SecureFilePriv = string.IsNullOrEmpty(SecureFilePrivFolder) ? string.Empty : $"\"{SecureFilePrivFolder.Replace('\\', '/')}\""; template.PluginLoad = string.IsNullOrEmpty(Plugins.ToString()) ? string.Empty : $"\"{Plugins}\""; - template.LooseMySqlXPort = MySqlXPort == 0 ? X_PROTOCOL_DEFAULT_PORT : MySqlXPort; + template.MySqlXPort = MySqlXPort == 0 ? X_PROTOCOL_DEFAULT_PORT : MySqlXPort; template.NamedPipeFullAccessGroup = NamedPipeFullAccessGroup; template.ProcessTemplate(false, true, skipExistingValues); SaveGeneralSettings(); @@ -383,7 +384,7 @@ public IniTemplate GetExistingIniFileTemplate() if (configFileExists.HasValue && configFileExists.Value) { - t = new IniTemplate(InstallDirectory, DataDirectory, FullConfigFilePath, Package.Version, ServerInstallType, null); + t = new IniTemplate(InstallDirectory, DataDirectory, FullConfigFilePath, Package.Version, ServerInstallationType, null); } else { @@ -438,7 +439,7 @@ private void LoadIniSettings() var iniFile = new IniFileEngine(fullIniPath).Load(); Logger.LogInformation("Server Settings - Load Ini Settings - IniTemplate Parsing"); - var t = new IniTemplate(Package.Version, ServerInstallType); + var t = new IniTemplate(Package.Version, ServerInstallationType); t.ParseConfigurationFile(fullIniPath); Logger.LogInformation("Server Settings - Load Ini Settings - getting settings from IniTemplate"); @@ -453,8 +454,14 @@ private void LoadIniSettings() NamedPipeFullAccessGroup = t.NamedPipeFullAccessGroup; Logger.LogInformation("Server Settings - Load Ini Settings - getting settings from IniFileEngine"); + + + // Attempt to read the server installation type from the ini file for old configurations. + // Value is ignored if the extended settings file already contains an entry for the server installation type. var serverType = iniFile.FindValue("mysql", "server_type", true); - ServerInstallType = serverType == 1 + if (serverType != 0) + { + ServerInstallationType = serverType == 1 ? ServerInstallationType.Dedicated : serverType == 2 ? ServerInstallationType.Server @@ -463,8 +470,9 @@ private void LoadIniSettings() : serverType == 4 ? ServerInstallationType.Manual : ServerInstallationType.Developer; - OpenFirewall = EnableTcpIp && IsRuleEnabled(Port.ToString()); + } + OpenFirewall = EnableTcpIp && IsRuleEnabled(Port.ToString()); ErrorLogFileName = iniFile.FindValue("mysqld", "log-error", false); EnableGeneralLog = iniFile.FindValue("mysqld", "general-log", false); GeneralQueryLogFileName = iniFile.FindValue("mysqld", "general_log_file", false); diff --git a/Configurator/Wizards/Server/MysqlSCM.cs b/Configurator/Wizards/Server/MysqlSCM.cs index a18d536..5a6799a 100644 --- a/Configurator/Wizards/Server/MysqlSCM.cs +++ b/Configurator/Wizards/Server/MysqlSCM.cs @@ -414,7 +414,7 @@ public static void Restart(string serviceName, CancellationToken cancellationTok public static bool ServiceExists(string serviceName) { var services = ServiceController.GetServices(); - var service = services.FirstOrDefault(s => s.ServiceName == serviceName); + var service = services.FirstOrDefault(s => s.ServiceName.Equals(serviceName, StringComparison.InvariantCultureIgnoreCase)); return service != null; } diff --git a/Configurator/Wizards/Server/ServerConfigBackupPage.Designer.cs b/Configurator/Wizards/Server/ServerConfigBackupPage.Designer.cs index 51b4a9e..a245182 100644 --- a/Configurator/Wizards/Server/ServerConfigBackupPage.Designer.cs +++ b/Configurator/Wizards/Server/ServerConfigBackupPage.Designer.cs @@ -56,13 +56,22 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServerConfigBackupPage)); this.UpgradeDatabaseFlowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel(); this.UpgradeExternalPanel = new System.Windows.Forms.Panel(); - this.SkipBackupRadioButton = new System.Windows.Forms.RadioButton(); - this.RunBackupRadioButton = new System.Windows.Forms.RadioButton(); this.BackupDatabaseLabel = new System.Windows.Forms.Label(); + this.RunBackupRadioButton = new System.Windows.Forms.RadioButton(); + this.CredentialsPanel = new System.Windows.Forms.Panel(); + this.ConnectDescriptionLabel = new System.Windows.Forms.Label(); + this.ResultLabel = new System.Windows.Forms.Label(); + this.RootUserLabel = new System.Windows.Forms.Label(); + this.PasswordTextBox = new System.Windows.Forms.TextBox(); + this.ConnectButton = new System.Windows.Forms.Button(); + this.UserLabel = new System.Windows.Forms.Label(); + this.RootPasswordLabel = new System.Windows.Forms.Label(); + this.SkipBackupRadioButton = new System.Windows.Forms.RadioButton(); this.ConnectionErrorProvider = new System.Windows.Forms.ErrorProvider(this.components); ((System.ComponentModel.ISupportInitialize)(this.ValidationsErrorProvider)).BeginInit(); this.UpgradeDatabaseFlowLayoutPanel.SuspendLayout(); this.UpgradeExternalPanel.SuspendLayout(); + this.CredentialsPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.ConnectionErrorProvider)).BeginInit(); this.SuspendLayout(); // @@ -84,12 +93,15 @@ private void InitializeComponent() // this.UpgradeDatabaseFlowLayoutPanel.AccessibleDescription = "A panel containing inner panels with options appearing depending on the upgrading" + " process handled by MySQL Server."; - this.UpgradeDatabaseFlowLayoutPanel.AccessibleName = "Upgrade Database Flow Panel"; + this.UpgradeDatabaseFlowLayoutPanel.AccessibleName = "Upgrade database flow layout"; this.UpgradeDatabaseFlowLayoutPanel.Controls.Add(this.UpgradeExternalPanel); + this.UpgradeDatabaseFlowLayoutPanel.Controls.Add(this.RunBackupRadioButton); + this.UpgradeDatabaseFlowLayoutPanel.Controls.Add(this.CredentialsPanel); + this.UpgradeDatabaseFlowLayoutPanel.Controls.Add(this.SkipBackupRadioButton); this.UpgradeDatabaseFlowLayoutPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; - this.UpgradeDatabaseFlowLayoutPanel.Location = new System.Drawing.Point(3, 58); + this.UpgradeDatabaseFlowLayoutPanel.Location = new System.Drawing.Point(27, 58); this.UpgradeDatabaseFlowLayoutPanel.Name = "UpgradeDatabaseFlowLayoutPanel"; - this.UpgradeDatabaseFlowLayoutPanel.Size = new System.Drawing.Size(563, 510); + this.UpgradeDatabaseFlowLayoutPanel.Size = new System.Drawing.Size(514, 510); this.UpgradeDatabaseFlowLayoutPanel.TabIndex = 1; // // UpgradeExternalPanel @@ -97,58 +109,166 @@ private void InitializeComponent() this.UpgradeExternalPanel.AccessibleDescription = "A panel containing controls for upgrading the system tables calling the external " + "mysql_upgrade cllient."; this.UpgradeExternalPanel.AccessibleName = "Upgrade External Group"; - this.UpgradeExternalPanel.Controls.Add(this.SkipBackupRadioButton); - this.UpgradeExternalPanel.Controls.Add(this.RunBackupRadioButton); this.UpgradeExternalPanel.Controls.Add(this.BackupDatabaseLabel); this.UpgradeExternalPanel.Location = new System.Drawing.Point(3, 3); this.UpgradeExternalPanel.Name = "UpgradeExternalPanel"; - this.UpgradeExternalPanel.Size = new System.Drawing.Size(560, 212); + this.UpgradeExternalPanel.Size = new System.Drawing.Size(511, 67); this.UpgradeExternalPanel.TabIndex = 6; // - // SkipBackupRadioButton + // BackupDatabaseLabel // - this.SkipBackupRadioButton.AccessibleDescription = "An option to replace a selected MySQL Server installation, meaning its data direc" + - "tory will be used for the installation being configured."; - this.SkipBackupRadioButton.AccessibleName = "Replace MySQL Server installation option"; - this.SkipBackupRadioButton.AutoSize = true; - this.SkipBackupRadioButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.SkipBackupRadioButton.Location = new System.Drawing.Point(26, 112); - this.SkipBackupRadioButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.SkipBackupRadioButton.Name = "SkipBackupRadioButton"; - this.SkipBackupRadioButton.Size = new System.Drawing.Size(360, 29); - this.SkipBackupRadioButton.TabIndex = 6; - this.SkipBackupRadioButton.Text = "No thanks, I have already run a backup"; - this.SkipBackupRadioButton.UseVisualStyleBackColor = true; + this.BackupDatabaseLabel.AccessibleDescription = "A label displaying instructions about backing up the database before running the " + + "upgrade process"; + this.BackupDatabaseLabel.AccessibleName = "Backup MySQL databases description"; + this.BackupDatabaseLabel.Font = new System.Drawing.Font("Segoe UI", 9F); + this.BackupDatabaseLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(102)))), ((int)(((byte)(102)))), ((int)(((byte)(102))))); + this.BackupDatabaseLabel.Location = new System.Drawing.Point(-1, 10); + this.BackupDatabaseLabel.Name = "BackupDatabaseLabel"; + this.BackupDatabaseLabel.Size = new System.Drawing.Size(520, 79); + this.BackupDatabaseLabel.TabIndex = 0; + this.BackupDatabaseLabel.Text = resources.GetString("BackupDatabaseLabel.Text"); // // RunBackupRadioButton // - this.RunBackupRadioButton.AccessibleDescription = "An option to replace a selected MySQL Server installation, meaning its data direc" + - "tory will be used for the installation being configured."; - this.RunBackupRadioButton.AccessibleName = "Replace MySQL Server installation option"; + this.RunBackupRadioButton.AccessibleDescription = "An option to specify that a backup"; + this.RunBackupRadioButton.AccessibleName = "Backup databses using mysqldump option"; this.RunBackupRadioButton.AutoSize = true; this.RunBackupRadioButton.Checked = true; this.RunBackupRadioButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.RunBackupRadioButton.Location = new System.Drawing.Point(26, 79); + this.RunBackupRadioButton.Location = new System.Drawing.Point(4, 78); this.RunBackupRadioButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.RunBackupRadioButton.Name = "RunBackupRadioButton"; this.RunBackupRadioButton.Size = new System.Drawing.Size(402, 29); - this.RunBackupRadioButton.TabIndex = 5; + this.RunBackupRadioButton.TabIndex = 1; this.RunBackupRadioButton.TabStop = true; this.RunBackupRadioButton.Text = "Run a mysqldump backup prior to upgrade"; this.RunBackupRadioButton.UseVisualStyleBackColor = true; + this.RunBackupRadioButton.CheckedChanged += new System.EventHandler(this.BackupDatabaseCheckBox_CheckedChanged); + this.RunBackupRadioButton.Validated += new System.EventHandler(this.ValidatedHandler); // - // BackupDatabaseLabel + // CredentialsPanel // - this.BackupDatabaseLabel.AccessibleDescription = "A label displaying instructions about backing up the database before running the " + - "upgrade process"; - this.BackupDatabaseLabel.AccessibleName = "Backup MySQL Database Description"; - this.BackupDatabaseLabel.Font = new System.Drawing.Font("Segoe UI", 9F); - this.BackupDatabaseLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(102)))), ((int)(((byte)(102)))), ((int)(((byte)(102))))); - this.BackupDatabaseLabel.Location = new System.Drawing.Point(21, 4); - this.BackupDatabaseLabel.Name = "BackupDatabaseLabel"; - this.BackupDatabaseLabel.Size = new System.Drawing.Size(520, 79); - this.BackupDatabaseLabel.TabIndex = 0; - this.BackupDatabaseLabel.Text = resources.GetString("BackupDatabaseLabel.Text"); + this.CredentialsPanel.AccessibleDescription = "A panel containing the controls to connect to the MySQL Server instance that is b" + + "eing upgraded."; + this.CredentialsPanel.AccessibleName = "Credentials"; + this.CredentialsPanel.Controls.Add(this.ConnectDescriptionLabel); + this.CredentialsPanel.Controls.Add(this.ResultLabel); + this.CredentialsPanel.Controls.Add(this.RootUserLabel); + this.CredentialsPanel.Controls.Add(this.PasswordTextBox); + this.CredentialsPanel.Controls.Add(this.ConnectButton); + this.CredentialsPanel.Controls.Add(this.UserLabel); + this.CredentialsPanel.Controls.Add(this.RootPasswordLabel); + this.CredentialsPanel.Location = new System.Drawing.Point(3, 115); + this.CredentialsPanel.Name = "CredentialsPanel"; + this.CredentialsPanel.Size = new System.Drawing.Size(511, 151); + this.CredentialsPanel.TabIndex = 9; + // + // ConnectDescriptionLabel + // + this.ConnectDescriptionLabel.AccessibleDescription = "A label displaying a description about the need to provide the credentials for th" + + "e root user."; + this.ConnectDescriptionLabel.AccessibleName = "Need for credentials description"; + this.ConnectDescriptionLabel.Font = new System.Drawing.Font("Segoe UI", 9F); + this.ConnectDescriptionLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(102)))), ((int)(((byte)(102)))), ((int)(((byte)(102))))); + this.ConnectDescriptionLabel.Location = new System.Drawing.Point(17, 3); + this.ConnectDescriptionLabel.Name = "ConnectDescriptionLabel"; + this.ConnectDescriptionLabel.Size = new System.Drawing.Size(494, 44); + this.ConnectDescriptionLabel.TabIndex = 9; + this.ConnectDescriptionLabel.Text = "To create the backup, a connection to the MySQL Server instance must be made. Ple" + + "ase provide the password for the root user and then click the Connect button:"; + // + // ResultLabel + // + this.ResultLabel.AccessibleDescription = "A label displaying the result of the root credentials check"; + this.ResultLabel.AccessibleName = "Root Credentials Check Result"; + this.ResultLabel.AutoSize = true; + this.ResultLabel.Location = new System.Drawing.Point(146, 116); + this.ResultLabel.Name = "ResultLabel"; + this.ResultLabel.Size = new System.Drawing.Size(0, 25); + this.ResultLabel.TabIndex = 7; + // + // RootUserLabel + // + this.RootUserLabel.AccessibleDescription = "A text with the word root"; + this.RootUserLabel.AccessibleName = "Root text"; + this.RootUserLabel.AutoSize = true; + this.RootUserLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.RootUserLabel.Location = new System.Drawing.Point(88, 48); + this.RootUserLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.RootUserLabel.Name = "RootUserLabel"; + this.RootUserLabel.Size = new System.Drawing.Size(46, 25); + this.RootUserLabel.TabIndex = 3; + this.RootUserLabel.Text = "root"; + // + // PasswordTextBox + // + this.PasswordTextBox.AccessibleDescription = "A field to input the password of the root user."; + this.PasswordTextBox.AccessibleName = "Root password"; + this.PasswordTextBox.Location = new System.Drawing.Point(90, 73); + this.PasswordTextBox.Name = "PasswordTextBox"; + this.PasswordTextBox.PasswordChar = '*'; + this.PasswordTextBox.Size = new System.Drawing.Size(126, 31); + this.PasswordTextBox.TabIndex = 5; + this.PasswordTextBox.TextChanged += new System.EventHandler(this.TextChangedHandler); + this.PasswordTextBox.Validated += new System.EventHandler(this.ValidatedHandler); + // + // ConnectButton + // + this.ConnectButton.AccessibleDescription = "A button to connect to the existing MySQL Server instance."; + this.ConnectButton.AccessibleName = "Connect"; + this.ConnectButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ConnectButton.Location = new System.Drawing.Point(20, 110); + this.ConnectButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.ConnectButton.Name = "ConnectButton"; + this.ConnectButton.Size = new System.Drawing.Size(97, 28); + this.ConnectButton.TabIndex = 6; + this.ConnectButton.Text = "Connect"; + this.ToolTip.SetToolTip(this.ConnectButton, "Tests the connection to the MySQL Server installation to upgrade."); + this.ConnectButton.UseVisualStyleBackColor = true; + this.ConnectButton.Click += new System.EventHandler(this.ConnectButton_Click); + // + // UserLabel + // + this.UserLabel.AccessibleDescription = "A text to specify the user that will connect to the MySQL Server instance."; + this.UserLabel.AccessibleName = "User text"; + this.UserLabel.AutoSize = true; + this.UserLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.UserLabel.Location = new System.Drawing.Point(18, 48); + this.UserLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.UserLabel.Name = "UserLabel"; + this.UserLabel.Size = new System.Drawing.Size(51, 25); + this.UserLabel.TabIndex = 2; + this.UserLabel.Text = "User:"; + // + // RootPasswordLabel + // + this.RootPasswordLabel.AccessibleDescription = "A text to ask for the password of the root user."; + this.RootPasswordLabel.AccessibleName = "Root password text"; + this.RootPasswordLabel.AutoSize = true; + this.RootPasswordLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.RootPasswordLabel.Location = new System.Drawing.Point(18, 77); + this.RootPasswordLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.RootPasswordLabel.Name = "RootPasswordLabel"; + this.RootPasswordLabel.Size = new System.Drawing.Size(91, 25); + this.RootPasswordLabel.TabIndex = 4; + this.RootPasswordLabel.Text = "Password:"; + // + // SkipBackupRadioButton + // + this.SkipBackupRadioButton.AccessibleDescription = "An option to replace a selected MySQL Server installation, meaning its data direc" + + "tory will be used for the installation being configured."; + this.SkipBackupRadioButton.AccessibleName = "Skip backup option"; + this.SkipBackupRadioButton.AutoSize = true; + this.SkipBackupRadioButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.SkipBackupRadioButton.Location = new System.Drawing.Point(4, 274); + this.SkipBackupRadioButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.SkipBackupRadioButton.Name = "SkipBackupRadioButton"; + this.SkipBackupRadioButton.Size = new System.Drawing.Size(370, 29); + this.SkipBackupRadioButton.TabIndex = 8; + this.SkipBackupRadioButton.Text = "No thanks, I have already run a backup"; + this.SkipBackupRadioButton.UseVisualStyleBackColor = true; + this.SkipBackupRadioButton.CheckedChanged += new System.EventHandler(this.BackupDatabaseCheckBox_CheckedChanged); + this.SkipBackupRadioButton.Validated += new System.EventHandler(this.ValidatedHandler); // // ConnectionErrorProvider // @@ -157,9 +277,8 @@ private void InitializeComponent() // // ServerConfigBackupPage // - this.AccessibleDescription = "A configuration wizard page to upgrade the database upon a server upgrade or recr" + - "eate an existing sandbox cluster"; - this.AccessibleName = "Check And Upgrade Database Page"; + this.AccessibleDescription = "A configuration wizard page to backup the existing databases"; + this.AccessibleName = "Backup Page"; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; this.Caption = "Backup Data"; this.Controls.Add(this.UpgradeDatabaseFlowLayoutPanel); @@ -172,8 +291,10 @@ private void InitializeComponent() this.Controls.SetChildIndex(this.captionLabel, 0); ((System.ComponentModel.ISupportInitialize)(this.ValidationsErrorProvider)).EndInit(); this.UpgradeDatabaseFlowLayoutPanel.ResumeLayout(false); + this.UpgradeDatabaseFlowLayoutPanel.PerformLayout(); this.UpgradeExternalPanel.ResumeLayout(false); - this.UpgradeExternalPanel.PerformLayout(); + this.CredentialsPanel.ResumeLayout(false); + this.CredentialsPanel.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.ConnectionErrorProvider)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -186,7 +307,15 @@ private void InitializeComponent() private System.Windows.Forms.Panel UpgradeExternalPanel; private System.Windows.Forms.Label BackupDatabaseLabel; private System.Windows.Forms.ErrorProvider ConnectionErrorProvider; - private System.Windows.Forms.RadioButton SkipBackupRadioButton; private System.Windows.Forms.RadioButton RunBackupRadioButton; + private System.Windows.Forms.Panel CredentialsPanel; + private System.Windows.Forms.Label UserLabel; + private System.Windows.Forms.Label RootPasswordLabel; + private System.Windows.Forms.RadioButton SkipBackupRadioButton; + private System.Windows.Forms.Button ConnectButton; + private System.Windows.Forms.TextBox PasswordTextBox; + private System.Windows.Forms.Label RootUserLabel; + private System.Windows.Forms.Label ResultLabel; + private System.Windows.Forms.Label ConnectDescriptionLabel; } } diff --git a/Configurator/Wizards/Server/ServerConfigBackupPage.cs b/Configurator/Wizards/Server/ServerConfigBackupPage.cs index d1ea970..ec4ed4d 100644 --- a/Configurator/Wizards/Server/ServerConfigBackupPage.cs +++ b/Configurator/Wizards/Server/ServerConfigBackupPage.cs @@ -22,7 +22,12 @@ You should have received a copy of the GNU General Public License 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ using System; +using MySql.Configurator.Core.Classes; +using MySql.Configurator.Core.Enums; +using System.Windows.Forms; using MySql.Configurator.Core.Wizard; +using MySql.Configurator.Properties; +using Action = System.Action; namespace MySql.Configurator.Wizards.Server { @@ -33,6 +38,11 @@ public partial class ServerConfigBackupPage : ConfigWizardPage { #region Fields + /// + /// The connection result obtained when pressing the Connect button. + /// + private ConnectionResultType _connectionResult; + /// /// The used to perform actions. /// @@ -48,6 +58,7 @@ public ServerConfigBackupPage(ServerConfigurationController controller) { BackupDatabase = true; InitializeComponent(); + _connectionResult = ConnectionResultType.None; _controller = controller; } @@ -58,6 +69,16 @@ public ServerConfigBackupPage(ServerConfigurationController controller) /// public bool BackupDatabase { get; private set; } + /// + /// Gets a value indicating if it is allowed to go to the next configuration page. + /// + public override bool NextOk => ((_controller.IsSameDirectoryUpgrade + && ((RunBackupRadioButton.Checked + && _connectionResult == ConnectionResultType.ConnectionSuccess) + || SkipBackupRadioButton.Checked)) + || !_controller.IsSameDirectoryUpgrade) + && base.NextOk; + #endregion Properties /// @@ -65,6 +86,7 @@ public ServerConfigBackupPage(ServerConfigurationController controller) /// public override void Activate() { + CredentialsPanel.Visible = !_controller.RootUserCredentialsSet; base.Activate(); } @@ -76,17 +98,96 @@ public override bool Next() { _controller.IsBackupDatabaseStepNeeded = RunBackupRadioButton.Checked; _controller.UpdateUpgradeConfigSteps(); + if (!_controller.RootUserCredentialsSet) + { + _controller.Settings.ExistingRootPassword = PasswordTextBox.Text; + } + return base.Next(); } /// /// Event delegate method fired when the checked property changes. /// - /// Sender object. - /// Event arguments. + /// The sender object. + /// The event arguments. private void BackupDatabaseCheckBox_CheckedChanged(object sender, EventArgs e) { BackupDatabase = RunBackupRadioButton.Checked; + ValidationsErrorProvider.Clear(); + ValidatedHandler(sender, e); + } + + /// + /// Event delegate method fired when the Connect button is clicked. + /// + /// The sender object. + /// The event arguments. + private void ConnectButton_Click(object sender, EventArgs e) + { + Action action; + action = delegate + { + ResultLabel.Text = Resources.StartingServerAndTestingConnection; + var providerProperties = new ErrorProviderProperties(Resources.StartingServerAndTestingConnection, Resources.Config_InProgressIcon, true); + ConnectionErrorProvider.SetProperties(ConnectButton, providerProperties); + _connectionResult = LocalServerInstance.CanConnect(_controller, out string errorMessage, PasswordTextBox.Text, true, true); + providerProperties.ErrorMessage = string.IsNullOrEmpty(errorMessage) + ? _connectionResult.GetDescription() + : errorMessage; + providerProperties.ErrorIcon = _connectionResult == ConnectionResultType.ConnectionSuccess + ? Resources.Config_DoneIcon + : Resources.Config_ErrorIcon; + ConnectionErrorProvider.SetProperties(ConnectButton, providerProperties); + ResultLabel.Text = providerProperties.ErrorMessage; + UpdateButtons(); + }; + + ExecuteLongRunningOperation(action); + } + + /// + /// Handles the TextChanged event. + /// + /// The source of the event. + /// The instance containing the event data. + protected override void TextChangedHandler(object sender, EventArgs e) + { + // Looks like we could get rid of this empty override, but it is necessary to avoid an error of: + // The method 'xxx' cannot be the method for an event because a class this class derives from already defines the method + base.TextChangedHandler(sender, e); + } + + /// + /// Handles the TextValidated event. + /// + /// The source of the event. + /// The instance containing the event data. + /// This event method is meant to be used with the event. + protected override void ValidatedHandler(object sender, EventArgs e) + { + // Looks like we could get rid of this empty override, but it is necessary to avoid an error of: + // The method 'xxx' cannot be the method for an event because a class this class derives from already defines the method + base.ValidatedHandler(sender, e); + } + + /// + /// Contains calls to methods that validate the given control's value. + /// + /// An error message or null / if everything is valid. + protected override string ValidateFields() + { + string errorMessage = base.ValidateFields(); + switch (ErrorProviderControl.Name) + { + case nameof(PasswordTextBox): + _connectionResult = ConnectionResultType.None; + ConnectionErrorProvider.Clear(); + ResultLabel.Text = string.Empty; + break; + } + + return errorMessage; } } } diff --git a/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.Designer.cs b/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.Designer.cs index 2b699bf..1a472e7 100644 --- a/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.Designer.cs +++ b/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.Designer.cs @@ -128,7 +128,6 @@ private void InitializeComponent() // DataDirectoryBrowserDialog // this.DataDirectoryBrowserDialog.Description = "Select the MySQL Server data directory"; - this.DataDirectoryBrowserDialog.RootFolder = System.Environment.SpecialFolder.CommonApplicationData; // // ServerConfigDataDirectoryPage // diff --git a/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.cs b/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.cs index 88469ab..1ac6de3 100644 --- a/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.cs +++ b/Configurator/Wizards/Server/ServerConfigDataDirectoryPage.cs @@ -131,7 +131,7 @@ private void DataDirectoryBrowseButton_Click(object sender, EventArgs e) private void DataDirectoryRevertButton_Click(object sender, EventArgs e) { - DataDirectoryTextBox.Text = _controller.Settings.DataDirectory; + DataDirectoryTextBox.Text = _controller.Settings.DefaultDataDirectory; } #endregion Event Handlers diff --git a/Configurator/Wizards/Server/ServerConfigLocalMachinePage.cs b/Configurator/Wizards/Server/ServerConfigLocalMachinePage.cs index 5756662..f625268 100644 --- a/Configurator/Wizards/Server/ServerConfigLocalMachinePage.cs +++ b/Configurator/Wizards/Server/ServerConfigLocalMachinePage.cs @@ -104,19 +104,19 @@ public override bool Next() switch (ConfigTypeComboBox.SelectedIndex) { case 0: - _settings.ServerInstallType = ServerInstallationType.Developer; + _settings.ServerInstallationType = ServerInstallationType.Developer; break; case 1: - _settings.ServerInstallType = ServerInstallationType.Server; + _settings.ServerInstallationType = ServerInstallationType.Server; break; case 2: - _settings.ServerInstallType = ServerInstallationType.Dedicated; + _settings.ServerInstallationType = ServerInstallationType.Dedicated; break; case 3: - _settings.ServerInstallType = ServerInstallationType.Manual; + _settings.ServerInstallationType = ServerInstallationType.Manual; break; } @@ -167,7 +167,7 @@ public override void WizardShowing() ConfigTypeComboBox.SelectedIndex = 0; if (_controller.ConfigurationType == ConfigurationType.Reconfiguration) { - switch(_settings.ServerInstallType) + switch(_settings.ServerInstallationType) { case ServerInstallationType.Dedicated: ConfigTypeComboBox.SelectedIndex = 2; diff --git a/Configurator/Wizards/Server/ServerConfigSecurityPage.cs b/Configurator/Wizards/Server/ServerConfigSecurityPage.cs index e68c063..cb364c5 100644 --- a/Configurator/Wizards/Server/ServerConfigSecurityPage.cs +++ b/Configurator/Wizards/Server/ServerConfigSecurityPage.cs @@ -131,7 +131,8 @@ public override void Activate() AddItemToListView(FullControlListView, _controller.Settings.ServiceAccountUsername, false, true); } - if (!_controller.Settings.ServiceAccountUsername.Equals(_currentServiceAccountUsername, StringComparison.InvariantCultureIgnoreCase)) + if (!string.IsNullOrEmpty(_controller.Settings.ServiceAccountUsername) + && !_controller.Settings.ServiceAccountUsername.Equals(_currentServiceAccountUsername, StringComparison.InvariantCultureIgnoreCase)) { FullControlListView.Items.RemoveByKey(_currentServiceAccountUsername); } @@ -173,7 +174,8 @@ public override bool Next() var fullControlDictionary = new Dictionary(); if (YesRadioButton.Checked) { - if (_controller.Settings.ConfigureAsService) + if (_controller.Settings.ConfigureAsService + && !string.IsNullOrEmpty(_controller.Settings.ServiceAccountUsername)) { var serviceAccountUsername = _controller.Settings.ServiceAccountUsername.StartsWith(".") ? _controller.Settings.ServiceAccountUsername.Replace(".", Environment.MachineName) diff --git a/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.Designer.cs b/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.Designer.cs index e72f089..333e865 100644 --- a/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.Designer.cs +++ b/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.Designer.cs @@ -91,6 +91,7 @@ private void InitializeComponent() this.DataDirectoryRenameWarningProvider = new System.Windows.Forms.ErrorProvider(this.components); this.VersionErrorProvider = new System.Windows.Forms.ErrorProvider(this.components); this.VersionWarningProvider = new System.Windows.Forms.ErrorProvider(this.components); + this.UserWarningProvider = new System.Windows.Forms.ErrorProvider(this.components); ((System.ComponentModel.ISupportInitialize)(this.ValidationsErrorProvider)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.ConnectionErrorProvider)).BeginInit(); this.InstallationTypeFlowLayoutPanel.SuspendLayout(); @@ -356,7 +357,7 @@ private void InitializeComponent() this.NameLabel.AccessibleName = "Selected MySQL server named pipe or shared memory label"; this.NameLabel.AutoSize = true; this.NameLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.NameLabel.Location = new System.Drawing.Point(408, 52); + this.NameLabel.Location = new System.Drawing.Point(422, 52); this.NameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.NameLabel.Name = "NameLabel"; this.NameLabel.Size = new System.Drawing.Size(63, 25); @@ -369,7 +370,7 @@ private void InitializeComponent() "rver instance."; this.PipeOrSharedMemoryNameTextBox.AccessibleName = "Pipe shared memory name"; this.PipeOrSharedMemoryNameTextBox.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.PipeOrSharedMemoryNameTextBox.Location = new System.Drawing.Point(479, 46); + this.PipeOrSharedMemoryNameTextBox.Location = new System.Drawing.Point(493, 46); this.PipeOrSharedMemoryNameTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.PipeOrSharedMemoryNameTextBox.Name = "PipeOrSharedMemoryNameTextBox"; this.PipeOrSharedMemoryNameTextBox.Size = new System.Drawing.Size(251, 31); @@ -384,7 +385,7 @@ private void InitializeComponent() this.PortLabel.AccessibleName = "Existing MySQL Server port number label"; this.PortLabel.AutoSize = true; this.PortLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.PortLabel.Location = new System.Drawing.Point(408, 52); + this.PortLabel.Location = new System.Drawing.Point(415, 52); this.PortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.PortLabel.Name = "PortLabel"; this.PortLabel.Size = new System.Drawing.Size(48, 25); @@ -487,7 +488,7 @@ private void InitializeComponent() this.ConnectButton.AccessibleDescription = "A button to connect to the existing MySQL Server instance."; this.ConnectButton.AccessibleName = "Connect"; this.ConnectButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ConnectButton.Location = new System.Drawing.Point(413, 97); + this.ConnectButton.Location = new System.Drawing.Point(445, 97); this.ConnectButton.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.ConnectButton.Name = "ConnectButton"; this.ConnectButton.Size = new System.Drawing.Size(111, 41); @@ -649,6 +650,11 @@ private void InitializeComponent() this.VersionWarningProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink; this.VersionWarningProvider.ContainerControl = this; // + // UserWarningProvider + // + this.UserWarningProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink; + this.UserWarningProvider.ContainerControl = this; + // // ServerConfigServerInstallationsPage // this.AccessibleDescription = "A configuration wizard page used to select the type of server installation"; @@ -678,6 +684,7 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.DataDirectoryRenameWarningProvider)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.VersionErrorProvider)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.VersionWarningProvider)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.UserWarningProvider)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -724,5 +731,6 @@ private void InitializeComponent() private System.Windows.Forms.ErrorProvider DataDirectoryRenameWarningProvider; private System.Windows.Forms.ErrorProvider VersionErrorProvider; private System.Windows.Forms.ErrorProvider VersionWarningProvider; + private System.Windows.Forms.ErrorProvider UserWarningProvider; } } diff --git a/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.cs b/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.cs index 34eb384..1562bf1 100644 --- a/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.cs +++ b/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.cs @@ -31,12 +31,14 @@ You should have received a copy of the GNU General Public License using MySql.Configurator.Core.Controllers; using MySql.Configurator.Core.Enums; using MySql.Configurator.Core.IniFile; +using MySql.Configurator.Core.IniFile.Template; using MySql.Configurator.Core.Package; using MySql.Configurator.Core.Product; using MySql.Configurator.Core.Wizard; using MySql.Configurator.Dialogs; using MySql.Configurator.Properties; using MySql.Data.MySqlClient; +using Action = System.Action; namespace MySql.Configurator.Wizards.Server { @@ -72,6 +74,11 @@ public partial class ServerConfigServerInstallationsPage : ConfigWizardPage /// private bool _rootPasswordOk; + /// + /// A flag indicating whether the controller needs to be recalculated. + /// + private bool _resetController; + #endregion Fields /// @@ -83,6 +90,7 @@ public ServerConfigServerInstallationsPage(ServerConfigurationController control InitializeComponent(); _controller = controller; _package = _controller.Package; + _resetController = true; _rootPasswordOk = false; _originalPagesVisibility = new Dictionary(); PortTextBox.Text = BaseServerSettings.DEFAULT_PORT.ToString(); @@ -129,43 +137,56 @@ public override void Activate() public override bool Next() { - if (ReplaceServerInstallationRadioButton.Checked) + if (!_resetController) { - var existingPackage = ProductManager.LoadPackage(_existingServerInstallationInstance.ServerVersion.ToString(), _existingServerInstallationInstance.BaseDir); - var oldController = (ServerConfigurationController) existingPackage.Controller; - oldController.LoadState(); - _controller.Settings.OldSettings = oldController.Settings; - _controller.ConfigurationType = ConfigurationType.Upgrade; - var dataDirectory = new DirectoryInfo(ExistingDataDirectoryTextBox.Text); - _controller.Settings.DataDirectory = dataDirectory.Parent.FullName; - _controller.Settings.ExistingRootPassword = RootPasswordTextBox.Text; - _controller.IsRemoveExistingServerInstallationStepNeeded = true; - _controller.IsDataDirectoryRenameNeeded = DataDirectoryRenameWarningProvider.HasErrors(); - _controller.ExistingServerInstallationInstance = _existingServerInstallationInstance; - - // Find if existing instance is configured as service. - var serviceNames = MySqlServiceControlManager.FindServiceNamesWithBaseDirectory(_existingServerInstallationInstance.BaseDir); - if (serviceNames.Length > 0) - { - _existingServerInstallationInstance.ServiceName = serviceNames[0]; - } - - _controller.IsServiceRenameNeeded = _existingServerInstallationInstance.IsServiceNameDefault( - _existingServerInstallationInstance.ServiceName, - _existingServerInstallationInstance.ServerVersion); - DetermineExistingServerPersistedVariablesToReset(); + return base.Next(); } - else + + Action action; + action = delegate { - _controller.Package = _package; - _controller.LoadState(); - _controller.ConfigurationType = ConfigurationType.New; - _controller.Settings.DataDirectory = NewDataDirectoryTextBox.Text; - _controller.ExistingServerInstallationInstance = null; - _controller.IsDataDirectoryRenameNeeded = false; - _controller.IsRemoveExistingServerInstallationStepNeeded = false; - _controller.PrepareForConfigure(); - } + if (ReplaceServerInstallationRadioButton.Checked) + { + var existingPackage = ProductManager.LoadPackage(_existingServerInstallationInstance.ServerVersion.ToString(), _existingServerInstallationInstance.BaseDir); + var oldController = (ServerConfigurationController)existingPackage.Controller; + oldController.LoadState(); + _controller.Settings.OldSettings = oldController.Settings; + _controller.ConfigurationType = ConfigurationType.Upgrade; + var dataDirectory = new DirectoryInfo(ExistingDataDirectoryTextBox.Text); + _controller.Settings.DataDirectory = dataDirectory.Parent.FullName; + _controller.Settings.ExistingRootPassword = RootPasswordTextBox.Text; + _controller.Settings.IniDirectory = new FileInfo(ExistingConfigFilePathTextBox.Text).DirectoryName; + _controller.IsRemoveExistingServerInstallationStepNeeded = true; + _controller.IsDataDirectoryRenameNeeded = DataDirectoryRenameWarningProvider.HasErrors(); + _controller.ExistingServerInstallationInstance = _existingServerInstallationInstance; + + // Find if existing instance is configured as service. + var serviceNames = MySqlServiceControlManager.FindServiceNamesWithBaseDirectory(_existingServerInstallationInstance.BaseDir); + if (serviceNames.Length > 0) + { + _existingServerInstallationInstance.ServiceName = serviceNames[0]; + } + + _controller.IsServiceRenameNeeded = _existingServerInstallationInstance.IsServiceNameDefault( + _existingServerInstallationInstance.ServiceName, + _existingServerInstallationInstance.ServerVersion); + DetermineExistingServerPersistedVariablesToReset(); + } + else + { + _controller.Package = _package; + _controller.LoadState(); + _controller.ConfigurationType = ConfigurationType.New; + _controller.Settings.DataDirectory = NewDataDirectoryTextBox.Text; + _controller.Settings.IniDirectory = _controller.Settings.DataDirectory; + _controller.ExistingServerInstallationInstance = null; + _controller.IsDataDirectoryRenameNeeded = false; + _controller.IsRemoveExistingServerInstallationStepNeeded = false; + _controller.PrepareForConfigure(); + } + }; + ExecuteLongRunningOperation(action); + _resetController = false; if (Wizard is ConfigWizard.ConfigWizard configWizard) { @@ -334,6 +355,7 @@ private void RefreshConfigurationPagesVisibility() private void ResetConnectionTest() { ConnectionErrorProvider.Clear(); + UserWarningProvider.Clear(); DataDirectoryRenameWarningProvider.Clear(); ValidationsErrorProvider.Clear(); VersionErrorProvider.Clear(); @@ -344,6 +366,7 @@ private void ResetConnectionTest() ExistingDataDirectoryTextBox.Text = string.Empty; ExistingConfigFilePathTextBox.Text = string.Empty; _existingServerInstallationInstance = null; + _resetController = true; _rootPasswordOk = false; ConnectButton.Enabled = ConnectEnabled; } @@ -363,6 +386,7 @@ private void UpdateExistingServerInstallationInstance() throw new ArgumentNullException(nameof(_existingServerInstallationInstance.Controller)); } + // Determine if the upgrade is supported. VersionTextBox.Text = _existingServerInstallationInstance.ServerVersion?.ToString(); string versionErrorMessage = null; var newVersion = _controller.Package.Version; @@ -371,7 +395,7 @@ private void UpdateExistingServerInstallationInstance() switch (upgradeViability) { case UpgradeViability.UnsupportedWithWarning: - versionErrorMessage = Resources.UpgradeNotSupportedWithWarningError; + versionErrorMessage = string.Format(Resources.UpgradeNotSupportedWithWarningError, oldVersion, newVersion); break; case UpgradeViability.Unsupported: if (oldVersion.Major < 8) @@ -416,6 +440,7 @@ private void UpdateExistingServerInstallationInstance() VersionWarningProvider.Clear(); } + // Populate server details. InstallDirectoryTextBox.Text = _existingServerInstallationInstance.BaseDir; ExistingDataDirectoryTextBox.Text = _existingServerInstallationInstance.DataDir; DataDirectoryRenameWarningProvider.SetProperties(ExistingDataDirectoryTextBox, new ErrorProviderProperties(_existingServerInstallationInstance.IsDataDirNameDefault(_controller.ServerVersion) @@ -424,7 +449,8 @@ private void UpdateExistingServerInstallationInstance() ValidationsErrorProvider.SetProperties(ExistingDataDirectoryTextBox, new ErrorProviderProperties(string.IsNullOrEmpty(_existingServerInstallationInstance.DataDir) ? Resources.ServerInstanceFailedToRetrieveDataDir : string.Empty)); - + + var configFileIsValid = false; if (!string.IsNullOrEmpty(_existingServerInstallationInstance.DataDir)) { string dataDirectory = null; @@ -436,11 +462,21 @@ private void UpdateExistingServerInstallationInstance() dataDirectory = new DirectoryInfo(_existingServerInstallationInstance.DataDir).Parent.FullName; var defaultConfigFile = Path.Combine(dataDirectory, BaseServerSettings.DEFAULT_CONFIG_FILE_NAME); var alternateConfigFile = Path.Combine(dataDirectory, BaseServerSettings.ALTERNATE_CONFIG_FILE_NAME); - ExistingConfigFilePathTextBox.Text = File.Exists(defaultConfigFile) + + var configFile = File.Exists(defaultConfigFile) ? defaultConfigFile : File.Exists(alternateConfigFile) ? alternateConfigFile : null; + configFileIsValid = configFile != null + ? ValidateExistingServerInstallationInstanceConfigurationFile(configFile) + : false; + if (!configFileIsValid) + { + ValidationsErrorProvider.SetProperties(ExistingConfigFileBrowseButton, new ErrorProviderProperties(Resources.ServerConfigConfigurationFileNotValid)); + } + + ExistingConfigFilePathTextBox.Text = configFile; } else { @@ -463,11 +499,45 @@ private void UpdateExistingServerInstallationInstance() _existingServerInstallationInstance.Controller.Settings.ConfigureAsService = true; } - // Load ini template and set data dir and error log paths. - var iniFile = new IniFileEngine(ExistingConfigFilePathTextBox.Text).Load(); - _existingServerInstallationInstance.Controller.Settings.DataDirectory = new DirectoryInfo(iniFile.FindValue("mysqld", "datadir", false)).Parent.FullName; - _existingServerInstallationInstance.Controller.Settings.ErrorLogFileName = iniFile.FindValue("mysqld", "log-error", false); + if (!string.IsNullOrEmpty(ExistingConfigFilePathTextBox.Text) + && configFileIsValid) + { + var iniFile = new IniFileEngine(ExistingConfigFilePathTextBox.Text).Load(); + _existingServerInstallationInstance.Controller.Settings.DataDirectory = new DirectoryInfo(iniFile.FindValue("mysqld", "datadir", false)).Parent.FullName; + _existingServerInstallationInstance.Controller.Settings.ErrorLogFileName = iniFile.FindValue("mysqld", "log-error", false); + } + else + { + ValidationsErrorProvider.SetProperties(ExistingConfigFileBrowseButton, new ErrorProviderProperties(Resources.ServerConfigConfigurationFileNotFound)); + } + } + } + + /// + /// Checks that the server configuration file can be successfully parsed. + /// + /// + /// true if the provided server configuration file is valid; otherwise, false. + private bool ValidateExistingServerInstallationInstanceConfigurationFile(string serverConfigurationFilePath) + { + if (string.IsNullOrEmpty(serverConfigurationFilePath)) + { + throw new ArgumentNullException(nameof(serverConfigurationFilePath)); + } + + if (!File.Exists(serverConfigurationFilePath)) + { + throw new FileNotFoundException(serverConfigurationFilePath); } + + var template = new IniTemplate(_existingServerInstallationInstance.BaseDir, + _existingServerInstallationInstance.DataDir, + serverConfigurationFilePath, + _existingServerInstallationInstance.Controller.ServerVersion, + _existingServerInstallationInstance.Controller.Settings.ServerInstallationType, + null); + + return template.IsValid; } #region Event Handlers @@ -586,12 +656,25 @@ private void ExistingConfigFileBrowseButton_Click(object sender, EventArgs e) if (ConfigFileDialog.ShowDialog() == DialogResult.OK) { - ExistingConfigFilePathTextBox.Text = ConfigFileDialog.FileName; + var valid = ValidateExistingServerInstallationInstanceConfigurationFile(ConfigFileDialog.FileName); + if (!valid) + { + ValidationsErrorProvider.SetProperties(ExistingConfigFileBrowseButton, new ErrorProviderProperties(Resources.ServerConfigConfigurationFileNotValid)); + } + else + { + ValidatedHandler(sender, e); + } + + ExistingConfigFilePathTextBox.Text = valid + ? ConfigFileDialog.FileName + : string.Empty; } } private void InstallationRadioButtonsCheckedChanged(object sender, EventArgs e) { + _resetController = true; ReplaceInstallationControlsPanel.Enabled = ReplaceServerInstallationRadioButton.Checked; ReplaceInstallationControlsPanel.Visible = ReplaceServerInstallationRadioButton.Checked; SideBySideInstallationControlsPanel.Enabled = SideBySideInstallationRadioButton.Checked; diff --git a/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.resx b/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.resx index a0c2bfc..da71520 100644 --- a/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.resx +++ b/Configurator/Wizards/Server/ServerConfigServerInstallationsPage.resx @@ -121,27 +121,33 @@ 17, 17 - 105, 17 + 140, 17 - 243, 17 + 338, 17 - 17, 108 + 1089, 17 + + + 119 - 289, 162 + 17, 65 - 727, 243 + 310, 65 - 1287, 365 + 506, 65 - 1319, 39 + 858, 17 - 624, 26 + 597, 17 + + + 884, 65 \ No newline at end of file diff --git a/Configurator/Wizards/Server/ServerConfigUserAccountsPage.cs b/Configurator/Wizards/Server/ServerConfigUserAccountsPage.cs index 1dcd6a9..27a52f3 100644 --- a/Configurator/Wizards/Server/ServerConfigUserAccountsPage.cs +++ b/Configurator/Wizards/Server/ServerConfigUserAccountsPage.cs @@ -31,6 +31,7 @@ You should have received a copy of the GNU General Public License using MySql.Configurator.Core.Enums; using MySql.Configurator.Core.Wizard; using MySql.Configurator.Properties; +using Action = System.Action; namespace MySql.Configurator.Wizards.Server { @@ -126,19 +127,24 @@ public override bool Next() private void PasswordCheckButton_Click(object sender, EventArgs e) { - Cursor = Cursors.WaitCursor; - _rootPasswordOk = false; - var providerProperties = new ErrorProviderProperties(Resources.ConnectionTestingText, Resources.Config_InProgressIcon, true); - ConnectionErrorProvider.SetProperties(PasswordCheckButton, providerProperties); - var connectionResult = LocalServerInstance.CanConnect(_controller, CurrentRootPasswordTextBox.Text, _controller.ConfigurationType == ConfigurationType.Reconfiguration); - _rootPasswordOk = connectionResult == ConnectionResultType.ConnectionSuccess; - providerProperties.ErrorIcon = _rootPasswordOk - ? Resources.Config_DoneIcon - : Resources.Config_ErrorIcon; - providerProperties.ErrorMessage = connectionResult.GetDescription(); - ConnectionErrorProvider.SetProperties(PasswordCheckButton, providerProperties); - Cursor = Cursors.Default; - UpdateButtons(); + Action action; + action = delegate + { + _rootPasswordOk = false; + var providerProperties = new ErrorProviderProperties(Resources.ConnectionTestingText, Resources.Config_InProgressIcon, true); + ConnectionErrorProvider.SetProperties(PasswordCheckButton, providerProperties); + var connectionResult = LocalServerInstance.CanConnect(_controller, CurrentRootPasswordTextBox.Text, _controller.ConfigurationType == ConfigurationType.Reconfiguration); + _rootPasswordOk = connectionResult == ConnectionResultType.ConnectionSuccess; + providerProperties.ErrorIcon = _rootPasswordOk + ? Resources.Config_DoneIcon + : Resources.Config_ErrorIcon; + providerProperties.ErrorMessage = connectionResult.GetDescription(); + ConnectionErrorProvider.SetProperties(PasswordCheckButton, providerProperties); + Cursor = Cursors.Default; + UpdateButtons(); + }; + + ExecuteLongRunningOperation(action); } private string CheckPasswords() diff --git a/Configurator/Wizards/Server/ServerConfigurationController.cs b/Configurator/Wizards/Server/ServerConfigurationController.cs index 260771d..e1af85a 100644 --- a/Configurator/Wizards/Server/ServerConfigurationController.cs +++ b/Configurator/Wizards/Server/ServerConfigurationController.cs @@ -288,8 +288,9 @@ public List FirewallRulesList { /// /// Gets a value indicating if there are configuration files that need to be deleted. /// - public bool IsDeleteConfigurationFileStepNeeded => File.Exists(Path.Combine(InstallDirectory, GeneralSettingsManager.CONFIGURATOR_SETTINGS_FILE_NAME)) - || File.Exists(Settings.FullConfigFilePath); + public bool IsDeleteConfigurationFileStepNeeded => (!string.IsNullOrEmpty(InstallDirectory) + && File.Exists(Path.Combine(InstallDirectory, GeneralSettingsManager.CONFIGURATOR_SETTINGS_FILE_NAME))) + || File.Exists(Settings.FullConfigFilePath); /// /// Gets a value indicating whether the removal step that deletes the data directory needs to run. @@ -301,14 +302,20 @@ public List FirewallRulesList { /// public bool IsDeleteServiceStepNeeded => MySqlServiceControlManager.ServiceExists(Settings?.ServiceName); + /// + /// Gets or sets a value indicating if the upgrade is reusing the existing installation and data directories. + /// + public bool IsSameDirectoryUpgrade { get; set; } + /// /// Gets a value indicating if there are steps that require to be executed for a server removal. /// - public bool IsRemovalExecutionNeeded => IsDeleteDataDirectoryStepNeeded - || IsDeleteConfigurationFileStepNeeded - || IsDeleteServiceStepNeeded - || IsRemoveFirewallRuleStepNeeded - || IsStopServerConfigurationStepNeeded; + public bool IsRemovalExecutionNeeded => IsDataDirectoryConfigured + && (IsDeleteDataDirectoryStepNeeded + || IsDeleteConfigurationFileStepNeeded + || IsDeleteServiceStepNeeded + || IsRemoveFirewallRuleStepNeeded + || IsStopServerConfigurationStepNeeded); /// /// Gets a value indicating whether the removal step that deletes the firewall rules needs to run. @@ -412,7 +419,8 @@ public bool IsStopServerConfigurationStepNeeded && ConfigurationType != ConfigurationType.New && (!Settings.ConfigureAsService || OldSettings.ServiceName != Settings.ServiceName)) - || Settings.ConfigureAsService; + || Settings.ConfigureAsService + && ConfigurationType != ConfigurationType.Upgrade; /// /// Gets a value indicating wheter the configuration step to update settings for the MySQL process needs to run. @@ -458,6 +466,11 @@ public bool IsStopServerConfigurationStepNeeded public RoleDefinitions RolesDefined { get; private set; } + /// + /// Gets a value indicating if the credentials of the root user have been provided and validated. + /// + public bool RootUserCredentialsSet => !string.IsNullOrEmpty(Settings.ExistingRootPassword); + /// /// Gets or sets the value of the password used for the root account. /// @@ -882,9 +895,7 @@ public override void SetPages() return; } - Logger.LogInformation(ConfigurationType == ConfigurationType.Reconfiguration - ? Resources.SettingUpReconfiguration - : Resources.SettingUpNewInstallation); + Logger.LogInformation(string.Format(Resources.SettingUpControllerMessage, ConfigurationType.GetDescription())); // New configuration pages. if (ConfigurationType == ConfigurationType.New) @@ -907,7 +918,12 @@ public override void SetPages() } // Upgrade pages. - Pages.Add(new ServerConfigBackupPage(this) { PageVisible = false }); + Pages.Add(new ServerConfigBackupPage(this) { PageVisible = ConfigurationType == ConfigurationType.Upgrade }); + if (ConfigurationType == ConfigurationType.Upgrade) + { + Pages.Add(new ServerConfigSecurityPage(this) { PageVisible = !ValidateServerFilesHaveRecommendedPermissions() }); + return; + } // New configuration and reconfiguration pages. Pages.Add(new ServerConfigLocalMachinePage(this)); @@ -968,8 +984,10 @@ public void UpdateUpgradeConfigSteps() _removeExistingServerInstallationStep.Execute = IsRemoveExistingServerInstallationStepNeeded; _resetPersistedVariablesStep.Execute = PersistedVariablesToReset?.Count > 0; _renameExistingDataDirectoryStep.Execute = IsDataDirectoryRenameNeeded; - _updateAccessPermissions.Execute = IsUpdateServerFilesPermissionsStepNeeded; _startAndUpgradeServerConfigStep.Execute = IsStartAndUpgradeConfigurationStepNeeded; + _stopServerConfigurationStep.Execute = IsSameDirectoryUpgrade; + _stopExistingServerInstanceStep.Execute = !IsSameDirectoryUpgrade; + _updateAccessPermissions.Execute = IsUpdateServerFilesPermissionsStepNeeded; ConfigurationSteps = StandAloneServerSteps; } @@ -1095,14 +1113,17 @@ private bool AddUserToSpecialUsersRegistryKey() /// private void BackupDatabase() { - if (ExistingServerInstallationInstance == null) + if (!IsSameDirectoryUpgrade) { - throw new Exception(Resources.ExistingServerInstanceNotSetError); - } + if (ExistingServerInstallationInstance == null) + { + throw new Exception(Resources.ExistingServerInstanceNotSetError); + } - if (!ExistingServerInstallationInstance.IsRunning) - { - throw new Exception(Resources.ExistingServerInstanceNotRunningError); + if (!ExistingServerInstallationInstance.IsRunning) + { + throw new Exception(Resources.ExistingServerInstanceNotRunningError); + } } var success = false; @@ -1123,7 +1144,9 @@ private void BackupDatabase() if (!string.IsNullOrEmpty(backupFile)) { ReportStatus(string.Format(Resources.ServerConfigBackupDatabaseDumpRunning, backupFile)); - var binDirectory = Path.Combine(ExistingServerInstallationInstance.BaseDir, BINARY_DIRECTORY_NAME); + var binDirectory = Path.Combine(IsSameDirectoryUpgrade + ? InstallDirectory + : ExistingServerInstallationInstance.BaseDir, BINARY_DIRECTORY_NAME); var user = GetUserAccountToConnectBeforeUpdatingRootUser(); var connectionOptions = string.Empty; bool sendingPasswordInCommandLine = false; @@ -1993,9 +2016,6 @@ private void LoadSelfContainedUpgradeSteps() _updateAccessPermissions, _updateWindowsServiceStep, _startAndUpgradeServerConfigStep, - //_prepareAuthenticationPluginChangeStep, - _stopServerConfigurationStep, - _startServerConfigurationStep, _updateSecurityStep, _updateStartMenuLinksStep, _removeExistingServerInstallationStep @@ -2055,8 +2075,8 @@ private IniTemplate LoadTemplate() string templateBase = "my-template{0}.ini"; var version = Package.Version; string templateFile = null; - if (version.Major >= 8 - && version.Minor > 0) + if ((version.Major >= 8 + && version.Minor > 0)) { templateFile = string.Format(templateBase, $"-{version.Major}.x"); } @@ -2071,7 +2091,7 @@ private IniTemplate LoadTemplate() Settings.IniDirectory, !string.IsNullOrEmpty(Settings.ConfigFile) ? Settings.ConfigFile : BaseServerSettings.DEFAULT_CONFIG_FILE_NAME, version, - Settings.ServerInstallType, + Settings.ServerInstallationType, _revertController); } @@ -2202,7 +2222,8 @@ private void RemoveFirewallRulesStep() ReportStatus(string.Format(Resources.RemovingFirewallRuleText, Settings.Port)); var removedXProtocolFirewallRule = true; - if (Settings.OpenFirewallForXProtocol) + if (Settings.OpenFirewallForXProtocol + && Settings.MySqlXPort != 0) { removedXProtocolFirewallRule = RemoveFirewallRule(Settings.MySqlXPort); } @@ -2518,7 +2539,14 @@ private void StopServerSafe(bool useOldSettings) CancellationToken.ThrowIfCancellationRequested(); var serverInstanceInfo = new LocalServerInstance(this, ReportStatus); serverInstanceInfo.UseOldSettings = useOldSettings; - if (ConfigurationType == ConfigurationType.Remove) + + // Set the data directory to allow the call to the ShutdownInstance method to correctly validate + // if the server is actually running before attempting to stop it. + // Other scenarios do not need this property to be set because the server is expected to be running + // allowing the DataDir property getter to query the database for that value. + if (ConfigurationType == ConfigurationType.Remove + || (ConfigurationType == ConfigurationType.Upgrade + && IsSameDirectoryUpgrade)) { serverInstanceInfo.DataDir = DataDirectory; } @@ -3066,7 +3094,8 @@ private void UpdateWindowsFirewall() if ((ConfigurationType == ConfigurationType.Reconfiguration || isDataDirectoryConfigured) && OldSettings != null - && OldSettings.OpenFirewall) + && OldSettings.OpenFirewallForXProtocol + && OldSettings.MySqlXPort != 0) { RemoveFirewallRule(OldSettings.Port); } @@ -3092,7 +3121,8 @@ private void UpdateWindowsFirewall() } CancellationToken.ThrowIfCancellationRequested(); - if (Settings.OpenFirewallForXProtocol) + if (Settings.OpenFirewallForXProtocol + && Settings.MySqlXPort != 0) { CreateFirewallRule(Settings.MySqlXPort); } diff --git a/Configurator/Wizards/Wizard.Designer.cs b/Configurator/Wizards/Wizard.Designer.cs index a77a5e0..5f9d7ec 100644 --- a/Configurator/Wizards/Wizard.Designer.cs +++ b/Configurator/Wizards/Wizard.Designer.cs @@ -43,6 +43,7 @@ protected override void Dispose(bool disposing) components.Dispose(); } + Pages.ForEach(p => p.UnsubscribeEvents()); base.Dispose(disposing); } diff --git a/Configurator/Wizards/Wizard.cs b/Configurator/Wizards/Wizard.cs index bacddf8..e908bd5 100644 --- a/Configurator/Wizards/Wizard.cs +++ b/Configurator/Wizards/Wizard.cs @@ -147,12 +147,14 @@ public void AddPage(WizardPage page) Controls.Add(page); page.Location = new System.Drawing.Point(220, 0); page.Wizard = this; + page.SubscribeEvents(); AddSideBarTabForPage(page); } public void ClearPages() { WizardSideBar.Tabs.Clear(); + Pages.ForEach(p => p.UnsubscribeEvents()); Pages.ForEach(p => p.Dispose()); Pages.Clear(); } diff --git a/Configurator/app.manifest b/Configurator/app.manifest index 0e1a299..a7de836 100644 --- a/Configurator/app.manifest +++ b/Configurator/app.manifest @@ -1,6 +1,6 @@  - + diff --git a/LICENSE b/LICENSE index dee23d1..f65f7a2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ Licensing Information User Manual -MySQL 8.4.0 Community +MySQL 8.4.5 Community __________________________________________________________________ Introduction @@ -8,18 +8,18 @@ Introduction This License Information User Manual contains Oracle's product license and other licensing information, including licensing information for third-party software which may be included in this distribution of - MySQL 8.4.0 Community. + MySQL 8.4.5 Community. - Last updated: March 2024 + Last updated: March 2025 Licensing Information - This release of MySQL 8.4.0 Community is brought to you by the MySQL + This release of MySQL 8.4.5 Community is brought to you by the MySQL team at Oracle. This software is released under version 2 of the GNU General Public License (GPLv2), as set forth below, with the following additional permissions: - This distribution of MySQL 8.4.0 Community is designed to work with + This distribution of MySQL 8.4.5 Community is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in the license documentation. Without limiting your rights @@ -36,7 +36,7 @@ Licensing Information reproduced below and can also be found along with its FAQ at http://oss.oracle.com/licenses/universal-foss-exception. - Copyright (c) 1997, 2024, Oracle and/or its affiliates. + Copyright (c) 1997, 2025, Oracle and/or its affiliates. Election of GPLv2 @@ -820,483 +820,6 @@ of parameters between 7-parameter geocentric transformation methods. ====================================================================== ====================================================================== -Expect.pm - -Expect.pm is licensed under the Perl license, which is essentially a dual -license. - -Oracle may use, redistribute and/or modify this code under the terms of -either: - - a) the GNU General Public License as published by the Free Software -Foundation; either version 1, or (at your option) any later version, or - - b) the "Artistic License" which comes with the Expect/pr code. - -Oracle elects to use the Artistic license for all versions of MySQL - -A copy of the GPLv2 and the Artistic License (Perl) 1.0 must be included with -any distribution: - -The GNU General Public License (GPL-2.0) -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is intended -to guarantee your freedom to share and change free software--to make sure the -software is free for all its users. This General Public License applies to -most of the Free Software Foundation's software and to any other program -whose authors commit to using it. (Some other Free Software Foundation -software is covered by the GNU Library General Public License instead.) You -can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom -to distribute copies of free software (and charge for this service if you -wish), that you receive source code or can get it if you want it, that you -can change the software or use pieces of it in new free programs; and that -you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to -deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you distribute -copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or -for a fee, you must give the recipients all the rights that you have. You -must make sure that they, too, receive or can get the source code. And you -must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) -offer you this license which gives you legal permission to copy, distribute -and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If the -software is modified by someone else and passed on, we want its recipients to -know that what they have is not the original, so that any problems introduced -by others will not reflect on the original authors' reputations. - -Finally, any free program is threatened constantly by software patents. We -wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must be -licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a notice -placed by the copyright holder saying it may be distributed under the terms -of this General Public License. The "Program", below, refers to any such -program or work, and a "work based on the Program" means either the Program -or any derivative work under copyright law: that is to say, a work containing -the Program or a portion of it, either verbatim or with modifications and/or -translated into another language. (Hereinafter, translation is included -without limitation in the term "modification".) Each licensee is addressed as -"you". - -Activities other than copying, distribution and modification are not covered -by this License; they are outside its scope. The act of running the Program -is not restricted, and the output from the Program is covered only if its -contents constitute a work based on the Program (independent of having been -made by running the Program). Whether that is true depends on what the -Program does. - -1. You may copy and distribute verbatim copies of the Program's source code -as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -License and to the absence of any warranty; and give any other recipients of -the Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and you may -at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, -thus forming a work based on the Program, and copy and distribute such -modifications or work under the terms of Section 1 above, provided that you -also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices stating -that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in whole -or in part contains or is derived from the Program or any part thereof, to be -licensed as a whole at no charge to all third parties under the terms of this -License. - - c) If the modified program normally reads commands interactively when -run, you must cause it, when started running for such interactive use in the -most ordinary way, to print or display an announcement including an -appropriate copyright notice and a notice that there is no warranty (or else, -saying that you provide a warranty) and that users may redistribute the -program under these conditions, and telling the user how to view a copy of -this License. (Exception: if the Program itself is interactive but does not -normally print such an announcement, your work based on the Program is not -required to print an announcement.) - -These requirements apply to the modified work as a whole. If identifiable -sections of that work are not derived from the Program, and can be reasonably -considered independent and separate works in themselves, then this License, -and its terms, do not apply to those sections when you distribute them as -separate works. But when you distribute the same sections as part of a whole -which is a work based on the Program, the distribution of the whole must be -on the terms of this License, whose permissions for other licensees extend to -the entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your -rights to work written entirely by you; rather, the intent is to exercise the -right to control the distribution of derivative or collective works based on -the Program. - -In addition, mere aggregation of another work not based on the Program with -the Program (or with a work based on the Program) on a volume of a storage or -distribution medium does not bring the other work under the scope of this -License. - -3. You may copy and distribute the Program (or a work based on it, under -Section 2) in object code or executable form under the terms of Sections 1 -and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable source -code, which must be distributed under the terms of Sections 1 and 2 above on -a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three years, to -give any third party, for a charge no more than your cost of physically -performing source distribution, a complete machine-readable copy of the -corresponding source code, to be distributed under the terms of Sections 1 -and 2 above on a medium customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer to -distribute corresponding source code. (This alternative is allowed only for -noncommercial distribution and only if you received the program in object -code or executable form with such an offer, in accord with Subsection b -above.) - -The source code for a work means the preferred form of the work for making -modifications to it. For an executable work, complete source code means all -the source code for all modules it contains, plus any associated interface -definition files, plus the scripts used to control compilation and -installation of the executable. However, as a special exception, the source -code distributed need not include anything that is normally distributed (in -either source or binary form) with the major components (compiler, kernel, -and so on) of the operating system on which the executable runs, unless that -component itself accompanies the executable. - -If distribution of executable or object code is made by offering access to -copy from a designated place, then offering equivalent access to copy the -source code from the same place counts as distribution of the source code, -even though third parties are not compelled to copy the source along with the -object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as -expressly provided under this License. Any attempt otherwise to copy, modify, -sublicense or distribute the Program is void, and will automatically -terminate your rights under this License. However, parties who have received -copies, or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - -5. You are not required to accept this License, since you have not signed it. -However, nothing else grants you permission to modify or distribute the -Program or its derivative works. These actions are prohibited by law if you -do not accept this License. Therefore, by modifying or distributing the -Program (or any work based on the Program), you indicate your acceptance of -this License to do so, and all its terms and conditions for copying, -distributing or modifying the Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the Program), -the recipient automatically receives a license from the original licensor to -copy, distribute or modify the Program subject to these terms and conditions. -You may not impose any further restrictions on the recipients' exercise of -the rights granted herein. You are not responsible for enforcing compliance -by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not excuse -you from the conditions of this License. If you cannot distribute so as to -satisfy simultaneously your obligations under this License and any other -pertinent obligations, then as a consequence you may not distribute the -Program at all. For example, if a patent license would not permit -royalty-free redistribution of the Program by all those who receive copies -directly or indirectly through you, then the only way you could satisfy both -it and this License would be to refrain entirely from distribution of the -Program. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply and -the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents -or other property right claims or to contest validity of any such claims; -this section has the sole purpose of protecting the integrity of the free -software distribution system, which is implemented by public license -practices. Many people have made generous contributions to the wide range of -software distributed through that system in reliance on consistent -application of that system; it is up to the author/donor to decide if he or -she is willing to distribute software through any other system and a licensee -cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be a -consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain -countries either by patents or by copyrighted interfaces, the original -copyright holder who places the Program under this License may add an -explicit geographical distribution limitation excluding those countries, so -that distribution is permitted only in or among countries not thus excluded. -In such case, this License incorporates the limitation as if written in the -body of this License. - -9. The Free Software Foundation may publish revised and/or new versions of -the General Public License from time to time. Such new versions will be -similar in spirit to the present version, but may differ in detail to address -new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any later -version", you have the option of following the terms and conditions either of -that version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of this License, -you may choose any version ever published by the Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs -whose distribution conditions are different, write to the author to ask for -permission. For software which is copyrighted by the Free Software -Foundation, write to the Free Software Foundation; we sometimes make -exceptions for this. Our decision will be guided by the two goals of -preserving the free status of all derivatives of our free software and of -promoting the sharing and reuse of software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR -THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE -STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE -PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND -PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, -YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO -LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR -THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible -use to the public, the best way to achieve this is to make it free software -which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach -them to the start of each source file to most effectively convey the -exclusion of warranty; and each file should have at least the "copyright" -line and a pointer to where the full notice is found. - - One line to give the program's name and a brief idea of what it does. - Copyright (C) - - This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2 of the License, or (at your option) any -later version. - - This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -details. - - You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., 59 -Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this when -it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author Gnomovision -comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free -software, and you are welcome to redistribute it under certain conditions; -type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may be -called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program -`Gnomovision' (which makes passes at compilers) written by James Hacker. - - signature of Ty Coon, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General Public -License instead of this License. - -________________________________________________________ - -The "Artistic License" - -Preamble - -The intent of this document is to state the conditions under which a -Package may be copied, such that the Copyright Holder maintains some -semblance of artistic control over the development of the package, -while giving the users of the package the right to use and distribute -the Package in a more-or-less customary fashion, plus the right to make -reasonable modifications. - -Definitions: - - "Package" refers to the collection of files distributed by the - Copyright Holder, and derivatives of that collection of files - created through textual modification. - - "Standard Version" refers to such a Package if it has not been - modified, or has been modified in accordance with the wishes - of the Copyright Holder as specified below. - - "Copyright Holder" is whoever is named in the copyright or - copyrights for the package. - - "You" is you, if you're thinking about copying or distributing - this Package. - - "Reasonable copying fee" is whatever you can justify on the - basis of media cost, duplication charges, time of people involved, - and so on. (You will not be required to justify it to the - Copyright Holder, but only to the computing community at large - as a market that must bear the fee.) - - "Freely Available" means that no fee is charged for the item - itself, though there may be fees involved in handling the item. - It also means that recipients of the item may redistribute it - under the same conditions they received it. - -1. You may make and give away verbatim copies of the source form of the -Standard Version of this Package without restriction, provided that you -duplicate all of the original copyright notices and associated disclaimers. - -2. You may apply bug fixes, portability fixes and other modifications -derived from the Public Domain or from the Copyright Holder. A Package -modified in such a way shall still be considered the Standard Version. - -3. You may otherwise modify your copy of this Package in any way, provided -that you insert a prominent notice in each changed file stating how and -when you changed that file, and provided that you do at least ONE of the -following: - - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet or - an equivalent medium, or placing the modifications on a major archive - site such as uunet.uu.net, or by allowing the Copyright Holder to include - your modifications in the Standard Version of the Package. - - b) use the modified Package only within your corporation or organization. - - c) rename any non-standard executables so the names do not conflict - with standard executables, which must also be provided, and provide - a separate manual page for each non-standard executable that clearly - documents how it differs from the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -4. You may distribute the programs of this Package in object code or -executable form, provided that you do at least ONE of the following: - - a) distribute a Standard Version of the executables and library files, - together with instructions (in the manual page or equivalent) on where - to get the Standard Version. - - b) accompany the distribution with the machine-readable source of - the Package with your modifications. - - c) give non-standard executables non-standard names, and clearly - document the differences in manual pages (or equivalent), together - with instructions on where to get the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -5. You may charge a reasonable copying fee for any distribution of this -Package. You may charge any fee you choose for support of this -Package. You may not charge a fee for this Package itself. However, -you may distribute this Package in aggregate with other (possibly -commercial) programs as part of a larger (possibly commercial) software -distribution provided that you do not advertise this Package as a -product of your own. You may embed this Package's interpreter within -an executable of yours (by linking); this shall be construed as a mere -form of aggregation, provided that the complete Standard Version of the -interpreter is so embedded. - -6. The scripts and library files supplied as input to or produced as -output from the programs of this Package do not automatically fall -under the copyright of this Package, but belong to whoever generated -them, and may be sold commercially, and may be aggregated with this -Package. If such scripts or library files are aggregated with this -Package via the so-called "undump" or "unexec" methods of producing a -binary executable image, then distribution of such an image shall -neither be construed as a distribution of this Package nor shall it -fall under the restrictions of Paragraphs 3 and 4, provided that you do -not represent such an executable image as a Standard Version of this -Package. - -7. C subroutines (or comparably compiled subroutines in other -languages) supplied by you and linked into this Package in order to -emulate subroutines and variables of the language defined by this -Package shall not be considered part of this Package, but are the -equivalent of input as in Paragraph 6, provided these subroutines do -not change the language in any way that would cause it to fail the -regression tests for the language. - -8. Aggregation of this Package with a commercial distribution is always -permitted provided that the use of this Package is embedded; that is, -when no overt attempt is made to make this Package's interfaces visible -to the end user of the commercial distribution. Such use shall not be -construed as a distribution of this Package. - -9. The name of the Copyright Holder may not be used to endorse or promote -products derived from this software without specific prior written -permission. - -10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - The End - - ====================================================================== - ====================================================================== - Facebook Fast Checksum Patch Facebook Fast Checksum Patch @@ -1519,6 +1042,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Google Protocol Buffers +You may be receiving a copy of abseil-cpp as part of this product in object code + form. +The terms of the Oracle license do NOT apply to abseil-cpp. +abseil-cpp is licensed under the Apache 2.0 license, separate from the Oracle pr +oduct. +If you do not wish to install this library, you may remove it, but the Oracle pr +ogram +might not operate properly or at all without it. + Copyright 2008 Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -2147,7 +1679,14 @@ SUCH DAMAGE. Kerberos5 -Kerberos5 +You may be receiving a copy of the kerberos documentation as part of this +product. The terms of the Oracle license do NOT apply to Kerberos documentation. + +Kerberos documentation is licensed under the CC-BY-SA 3.0 license, separate from + +the Oracle product. +If you do not wish to install this library, you may remove it, but +the Oracle program might not operate properly or at all without it. Copyright (C) 1985-2019 by the Massachusetts Institute of Technology. @@ -4435,6 +3974,35 @@ SOFTWARE. ====================================================================== ====================================================================== +xxHash + +Copyright (c) 2012-2021 Yann Collet +All rights reserved. +BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Some source files include the above license with different copyright years: +Copyright (C) 2012-2023 Yann Collet +Copyright (C) 2020-2024 Yann Collet + + ====================================================================== + ====================================================================== + zlib Oracle gratefully acknowledges the contributions of Jean-loup Gailly diff --git a/MySQLConfigurator.Test/MySQLConfigurator.Test.csproj b/MySQLConfigurator.Test/MySQLConfigurator.Test.csproj index 09bde43..2ca4f89 100644 --- a/MySQLConfigurator.Test/MySQLConfigurator.Test.csproj +++ b/MySQLConfigurator.Test/MySQLConfigurator.Test.csproj @@ -4,6 +4,7 @@ Debug + 999.999.999 AnyCPU {5304B25D-746B-465D-B866-48606D9B6F68} Library @@ -71,4 +72,18 @@ + + + + <_Parameter1>$(Version) + + + + + + + + \ No newline at end of file diff --git a/MySQLConfigurator.Test/Properties/AssemblyInfo.cs b/MySQLConfigurator.Test/Properties/AssemblyInfo.cs index 7b3eae0..803dc83 100644 --- a/MySQLConfigurator.Test/Properties/AssemblyInfo.cs +++ b/MySQLConfigurator.Test/Properties/AssemblyInfo.cs @@ -32,8 +32,4 @@ You should have received a copy of the GNU General Public License [assembly: ComVisible(false)] -[assembly: Guid("5304b25d-746b-465d-b866-48606d9b6f68")] - -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("8.4.0.0")] -[assembly: AssemblyFileVersion("8.4.0.0")] +[assembly: Guid("5304b25d-746b-465d-b866-48606d9b6f68")] \ No newline at end of file diff --git a/README.md b/README.md index 00e4ca8..71178a8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It performs the initial configuration, a reconfiguration, and also functions as ## Licensing -Please refer to the license files, available in this repository, and [Legal Notices in documentation](https://dev.mysql.com/doc/refman/8.1/en/preface.html) for further details. +Please refer to the license files, available in this repository, and [Legal Notices in documentation](https://dev.mysql.com/doc/refman/8.4/en/preface.html) for further details. ## Download and build @@ -49,3 +49,9 @@ This directory is expected to contain the bin, share, etc and other server direc For MSI installations this path is usually "C:\Program Files\MySQL\MySQL Server 8.4" or the custom path set during installation. For ZIP installations this path is whichever location where the server files were extracted to. + +### Report a bug + +To report a bug, access the [MySQL Bugs Tracking System](https://bugs.mysql.com/). Before reporting the bug please read the **Report a Bug** section for tips. If the bug hasn't been reported yet click the **Report a bug** tab and provide relevant details. The category corresponding to **MySQL Configurator** is **MySQL Sever: Install Configuration Tool**, this will ensure that the bug is routed to the appropriate team. + + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..8b94f40 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,30 @@ +# Reporting security vulnerabilities + +Oracle values the independent security research community and believes that +responsible disclosure of security vulnerabilities helps us ensure the security +and privacy of all our users. + +Please do NOT raise a GitHub Issue to report a security vulnerability. If you +believe you have found a security vulnerability, please submit a report to +secalert_us@oracle.com preferably with a proof of concept. Please review +some additional information on how to report security vulnerabilities to Oracle +(see https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html) +We encourage people who contact Oracle Security to use email encryption using +our encryption key (see https://www.oracle.com/security-alerts/encryptionkey.html) + +We ask that you do not use other channels or contact the project maintainers +directly. + +## Security updates, alerts and bulletins + +Security updates will be released on a regular cadence. Many of our projects +will typically release security fixes in conjunction with the Oracle Critical Patch +Update program. Additional information, including past advisories, is available on our +security alerts page at https://www.oracle.com/security-alerts/ + +# Security-related information + +We will provide security related information such as a threat model, considerations +for secure use, or any known security issues in our documentation. Please note +that labs and sample code are intended to demonstrate a concept and may not be +sufficiently hardened for production use. \ No newline at end of file diff --git a/common/MySql.Data.dll b/common/MySql.Data.dll index c018073..c5064bc 100644 Binary files a/common/MySql.Data.dll and b/common/MySql.Data.dll differ