diff --git a/XenAdmin/Commands/RotatePoolSecretCommand.cs b/XenAdmin/Commands/RotatePoolSecretCommand.cs new file mode 100644 index 000000000..3c8d29435 --- /dev/null +++ b/XenAdmin/Commands/RotatePoolSecretCommand.cs @@ -0,0 +1,99 @@ +/* Copyright (c) Citrix Systems, Inc. + * All rights reserved. + * + * 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. + */ + + +using System.Linq; +using XenAdmin.Actions; +using XenAdmin.Core; +using XenAdmin.Dialogs; +using XenAPI; + + +namespace XenAdmin.Commands +{ + class RotatePoolSecretCommand : Command + { + protected override void ExecuteCore(SelectedItemCollection selection) + { + var connection = selection.GetConnectionOfFirstItem(); + + if (connection != null && !connection.Session.IsLocalSuperuser && !Registry.DontSudo && + connection.Session.Roles.All(r => r.name_label != Role.MR_ROLE_POOL_ADMIN)) + { + var currentRoles = connection.Session.Roles; + currentRoles.Sort(); + + var msg = string.Format(Messages.ROTATE_POOL_SECRET_RBAC_RESTRICTION, currentRoles[0].FriendlyName(), + Role.FriendlyName(Role.MR_ROLE_POOL_ADMIN)); + + using (var dlg = new ErrorDialog(msg)) + dlg.ShowDialog(Parent); + + return; + } + + new DelegatedAsyncAction(connection, Messages.ROTATE_POOL_SECRET_TITLE, + Messages.ROTATE_POOL_SECRET_TITLE, Messages.COMPLETED, + Pool.rotate_secret, "pool.rotate_secret").RunAsync(); + } + + protected override bool CanExecuteCore(SelectedItemCollection selection) + { + if (selection.Any(i => !(i.XenObject is Host) && !(i.XenObject is Pool))) + return false; + + var conn = selection.GetConnectionOfAllItems(); + if (conn == null || !Helpers.StockholmOrGreater(conn) || conn.Cache.Hosts.Any(Host.RestrictPoolSecretRotation)) + return false; + + var pool = Helpers.GetPoolOfOne(conn); + return pool != null && !pool.ha_enabled && !pool.RollingUpgrade(); + } + + protected override string GetCantExecuteReasonCore(IXenObject item) + { + var pool = item == null ? null : Helpers.GetPoolOfOne(item.Connection); + + if (pool != null) + { + if (pool.ha_enabled) + return Messages.ROTATE_POOL_SECRET_HA; + + if (pool.RollingUpgrade()) + return Messages.ROTATE_POOL_SECRET_RPU; + } + + return base.GetCantExecuteReasonCore(item); + } + + public override string MenuText => Messages.ROTATE_POOL_SECRET_MENU; + } +} diff --git a/XenAdmin/MainWindow.Designer.cs b/XenAdmin/MainWindow.Designer.cs index 63e6184ed..f33d8e115 100644 --- a/XenAdmin/MainWindow.Designer.cs +++ b/XenAdmin/MainWindow.Designer.cs @@ -180,6 +180,7 @@ namespace XenAdmin this.backupToolStripMenuItem = new XenAdmin.Commands.CommandToolStripMenuItem(); this.restoreFromBackupToolStripMenuItem = new XenAdmin.Commands.CommandToolStripMenuItem(); this.toolStripSeparator23 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripMenuItemInstallCertificate = new XenAdmin.Commands.CommandToolStripMenuItem(); this.maintenanceModeToolStripMenuItem1 = new XenAdmin.Commands.CommandToolStripMenuItem(); this.controlDomainMemoryToolStripMenuItem = new XenAdmin.Commands.CommandToolStripMenuItem(); this.RemoveCrashdumpsToolStripMenuItem = new XenAdmin.Commands.CommandToolStripMenuItem(); @@ -277,12 +278,12 @@ namespace XenAdmin this.securityGroupsToolStripMenuItem = new XenAdmin.Commands.CommandToolStripMenuItem(); this.MenuPanel = new System.Windows.Forms.Panel(); this.StatusStrip = new System.Windows.Forms.StatusStrip(); - this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.statusProgressBar = new System.Windows.Forms.ToolStripProgressBar(); - this.toolStripMenuItemInstallCertificate = new XenAdmin.Commands.CommandToolStripMenuItem(); + this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.statusLabelAlerts = new System.Windows.Forms.ToolStripStatusLabel(); this.statusLabelUpdates = new System.Windows.Forms.ToolStripStatusLabel(); this.statusLabelErrors = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripMenuItemRotateSecret = new XenAdmin.Commands.CommandToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); this.splitContainer1.Panel1.SuspendLayout(); this.splitContainer1.Panel2.SuspendLayout(); @@ -927,6 +928,7 @@ namespace XenAdmin this.conversionToolStripMenuItem, this.toolStripSeparator9, this.changePoolPasswordToolStripMenuItem, + this.toolStripMenuItemRotateSecret, this.toolStripMenuItem1, this.deleteToolStripMenuItem, this.toolStripSeparator26, @@ -1234,6 +1236,12 @@ namespace XenAdmin this.toolStripSeparator23.Name = "toolStripSeparator23"; resources.ApplyResources(this.toolStripSeparator23, "toolStripSeparator23"); // + // toolStripMenuItemInstallCertificate + // + this.toolStripMenuItemInstallCertificate.Command = new XenAdmin.Commands.InstallCertificateCommand(); + this.toolStripMenuItemInstallCertificate.Name = "toolStripMenuItemInstallCertificate"; + resources.ApplyResources(this.toolStripMenuItemInstallCertificate, "toolStripMenuItemInstallCertificate"); + // // maintenanceModeToolStripMenuItem1 // this.maintenanceModeToolStripMenuItem1.Command = new XenAdmin.Commands.HostMaintenanceModeCommand(); @@ -1890,14 +1898,6 @@ namespace XenAdmin this.StatusStrip.Name = "StatusStrip"; this.StatusStrip.ShowItemToolTips = true; // - // statusLabel - // - this.statusLabel.AutoToolTip = true; - resources.ApplyResources(this.statusLabel, "statusLabel"); - this.statusLabel.Name = "statusLabel"; - this.statusLabel.Overflow = System.Windows.Forms.ToolStripItemOverflow.Never; - this.statusLabel.Spring = true; - // // statusProgressBar // resources.ApplyResources(this.statusProgressBar, "statusProgressBar"); @@ -1905,11 +1905,13 @@ namespace XenAdmin this.statusProgressBar.Name = "statusProgressBar"; this.statusProgressBar.Overflow = System.Windows.Forms.ToolStripItemOverflow.Never; // - // toolStripMenuItemInstallCertificate + // statusLabel // - this.toolStripMenuItemInstallCertificate.Command = new XenAdmin.Commands.InstallCertificateCommand(); - this.toolStripMenuItemInstallCertificate.Name = "toolStripMenuItemInstallCertificate"; - resources.ApplyResources(this.toolStripMenuItemInstallCertificate, "toolStripMenuItemInstallCertificate"); + this.statusLabel.AutoToolTip = true; + resources.ApplyResources(this.statusLabel, "statusLabel"); + this.statusLabel.Name = "statusLabel"; + this.statusLabel.Overflow = System.Windows.Forms.ToolStripItemOverflow.Never; + this.statusLabel.Spring = true; // // statusLabelAlerts // @@ -1947,6 +1949,12 @@ namespace XenAdmin this.statusLabelErrors.VisitedLinkColor = System.Drawing.SystemColors.ControlDarkDark; this.statusLabelErrors.Click += new System.EventHandler(this.statusLabelErrors_Click); // + // toolStripMenuItemRotateSecret + // + this.toolStripMenuItemRotateSecret.Name = "toolStripMenuItemRotateSecret"; + this.toolStripMenuItemRotateSecret.Command = new XenAdmin.Commands.RotatePoolSecretCommand(); + resources.ApplyResources(this.toolStripMenuItemRotateSecret, "toolStripMenuItemRotateSecret"); + // // MainWindow // resources.ApplyResources(this, "$this"); @@ -2222,6 +2230,7 @@ namespace XenAdmin private System.Windows.Forms.ToolStripStatusLabel statusLabelAlerts; private System.Windows.Forms.ToolStripStatusLabel statusLabelUpdates; private System.Windows.Forms.ToolStripStatusLabel statusLabelErrors; + private XenAdmin.Commands.CommandToolStripMenuItem toolStripMenuItemRotateSecret; } } diff --git a/XenAdmin/MainWindow.cs b/XenAdmin/MainWindow.cs index 0a6cca3c7..3144fd776 100755 --- a/XenAdmin/MainWindow.cs +++ b/XenAdmin/MainWindow.cs @@ -1657,18 +1657,11 @@ namespace XenAdmin sendCtrlAltDelToolStripMenuItem.Enabled = (TheTabControl.SelectedTab == TabPageConsole) && vm && ((VM)SelectionManager.Selection.First).power_state == vm_power_state.Running; IXenConnection conn = SelectionManager.Selection.GetConnectionOfAllItems(); - if (SelectionManager.Selection.Count > 0 && (Helpers.GetMaster(conn) != null) && (Helpers.FalconOrGreater(conn))) - { - assignSnapshotScheduleToolStripMenuItem.Available = true; - VMSnapshotScheduleToolStripMenuItem.Available = true; - - } - else /* hide VMSS */ - { - assignSnapshotScheduleToolStripMenuItem.Available = false; - VMSnapshotScheduleToolStripMenuItem.Available = false; - } + bool vmssOn = conn != null && Helpers.FalconOrGreater(conn); + assignSnapshotScheduleToolStripMenuItem.Available = vmssOn; + VMSnapshotScheduleToolStripMenuItem.Available = vmssOn; + templatesToolStripMenuItem1.Checked = Properties.Settings.Default.DefaultTemplatesVisible; customTemplatesToolStripMenuItem.Checked = Properties.Settings.Default.UserTemplatesVisible; localStorageToolStripMenuItem.Checked = Properties.Settings.Default.LocalSRsVisible; @@ -1677,6 +1670,9 @@ namespace XenAdmin conversionToolStripMenuItem.Available = conn != null && conn.Cache.VMs.Any(v => v.IsConversionVM()); installToolsToolStripMenuItem.Available = SelectionManager.Selection.Any(v => !Helpers.StockholmOrGreater(v.Connection)); toolStripMenuItemInstallCertificate.Available = Helpers.StockholmOrGreater(conn); + toolStripMenuItemRotateSecret.Available = SelectionManager.Selection.Any(s => + s.Connection != null && Helpers.StockholmOrGreater(s.Connection) && + !s.Connection.Cache.Hosts.Any(Host.RestrictPoolSecretRotation)); } private void xenSourceOnTheWebToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/XenAdmin/MainWindow.resx b/XenAdmin/MainWindow.resx index ab388ef2d..c7f81b4e8 100644 --- a/XenAdmin/MainWindow.resx +++ b/XenAdmin/MainWindow.resx @@ -1822,13 +1822,13 @@ 163, 5 - 146, 22 + 145, 22 Show &Toolbar - 147, 26 + 146, 26 ToolBarContextMenu @@ -2040,6 +2040,12 @@ Change Server Pass&word... + + 277, 22 + + + Rotate &Pool Secret + 274, 6 @@ -2245,13 +2251,13 @@ Remove Crash Dump &Files - 180, 22 + 161, 22 &Change... - 180, 22 + 161, 22 &Forget Password @@ -2299,130 +2305,130 @@ &Server - 243, 22 + 242, 22 &New VM... - 243, 22 + 242, 22 &Start/Shut down - 243, 22 + 242, 22 Res&ume on Server - 243, 22 + 242, 22 M&igrate to Server - 243, 22 + 242, 22 Start &on Server - 240, 6 + 239, 6 - 243, 22 + 242, 22 Assign to Snaps&hot Schedule... - 243, 22 + 242, 22 Assign to &vApp - 240, 6 + 239, 6 - 243, 22 + 242, 22 &Copy VM - 243, 22 + 242, 22 &Move VM - 243, 22 + 242, 22 Ta&ke a Snapshot - 243, 22 + 242, 22 Convert to &Template - 243, 22 + 242, 22 &Export... - 243, 22 + 242, 22 D&isable Changed Block Tracking - 243, 22 + 242, 22 - 243, 22 + 242, 22 - 240, 6 + 239, 6 - 243, 22 + 242, 22 Inst&all [Citrix VM Tools] - 243, 22 + 242, 22 Send Ctrl+&Alt+Del - 240, 6 + 239, 6 - 243, 22 + 242, 22 &Delete VM - 240, 6 + 239, 6 - 243, 22 + 242, 22 PluginItemsPlaceHolder - 243, 22 + 242, 22 P&roperties @@ -2815,7 +2821,7 @@ None - 498, 22 + 529, 22 MiddleLeft @@ -3411,6 +3417,12 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + toolStripMenuItemInstallCertificate + + + XenAdmin.Commands.CommandToolStripMenuItem, XenCenterMain, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + maintenanceModeToolStripMenuItem1 @@ -3975,23 +3987,17 @@ XenAdmin.Commands.CommandToolStripMenuItem, XenCenterMain, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - - statusLabel - - - System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - statusProgressBar System.Windows.Forms.ToolStripProgressBar, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItemInstallCertificate + + statusLabel - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 statusLabelAlerts @@ -4011,6 +4017,12 @@ System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + toolStripMenuItemRotateSecret + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + MainWindow diff --git a/XenAdmin/XenAdmin.csproj b/XenAdmin/XenAdmin.csproj index 87e386946..2544fc43b 100755 --- a/XenAdmin/XenAdmin.csproj +++ b/XenAdmin/XenAdmin.csproj @@ -117,6 +117,7 @@ Component + diff --git a/XenModel/Messages.Designer.cs b/XenModel/Messages.Designer.cs index 6f46761e0..acc221a0a 100755 --- a/XenModel/Messages.Designer.cs +++ b/XenModel/Messages.Designer.cs @@ -32809,6 +32809,53 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to You cannot rotate the pool secret when HA is on.. + /// + public static string ROTATE_POOL_SECRET_HA { + get { + return ResourceManager.GetString("ROTATE_POOL_SECRET_HA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rotate &Pool Secret. + /// + public static string ROTATE_POOL_SECRET_MENU { + get { + return ResourceManager.GetString("ROTATE_POOL_SECRET_MENU", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A {0} user does not have sufficient permissions to rotate the pool secret. Please login using an account with one of the following roles: + /// + ///{1}. + /// + public static string ROTATE_POOL_SECRET_RBAC_RESTRICTION { + get { + return ResourceManager.GetString("ROTATE_POOL_SECRET_RBAC_RESTRICTION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You cannot rotate the pool secret when a Rolling Pool Upgrade is in progress.. + /// + public static string ROTATE_POOL_SECRET_RPU { + get { + return ResourceManager.GetString("ROTATE_POOL_SECRET_RPU", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rotating pool secret. + /// + public static string ROTATE_POOL_SECRET_TITLE { + get { + return ResourceManager.GetString("ROTATE_POOL_SECRET_TITLE", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} could be skipped.. /// diff --git a/XenModel/Messages.resx b/XenModel/Messages.resx index 2c6d9c2ab..374631e1e 100755 --- a/XenModel/Messages.resx +++ b/XenModel/Messages.resx @@ -11385,6 +11385,23 @@ The master must be upgraded first, so if you skip the master, the rolling pool u The rolling pool upgrade process was completed with warnings. + + You cannot rotate the pool secret when HA is on. + + + Rotate &Pool Secret + + + A {0} user does not have sufficient permissions to rotate the pool secret. Please login using an account with one of the following roles: + +{1} + + + You cannot rotate the pool secret when a Rolling Pool Upgrade is in progress. + + + Rotating pool secret + {0} could be skipped. diff --git a/XenModel/XenAPI-Extensions/Host.cs b/XenModel/XenAPI-Extensions/Host.cs index 5876abc9c..699e3059c 100644 --- a/XenModel/XenAPI-Extensions/Host.cs +++ b/XenModel/XenAPI-Extensions/Host.cs @@ -308,6 +308,11 @@ namespace XenAPI return !BoolKey(h.license_params, "enable_xha"); } + public static bool RestrictPoolSecretRotation(Host h) + { + return BoolKeyPreferTrue(h.license_params, "restrict_pool_secret_rotation"); + } + public static bool RestrictAlerts(Host h) { return BoolKeyPreferTrue(h.license_params, "restrict_email_alerting"); diff --git a/XenModel/XenAPI/FriendlyErrorNames.Designer.cs b/XenModel/XenAPI/FriendlyErrorNames.Designer.cs index 4cba3458a..24ab353fe 100755 --- a/XenModel/XenAPI/FriendlyErrorNames.Designer.cs +++ b/XenModel/XenAPI/FriendlyErrorNames.Designer.cs @@ -1348,7 +1348,7 @@ namespace XenAPI { } /// - /// Looks up a localized string similar to The master says the server is not known to it. Perhaps the server was deleted from the master's database?. + /// Looks up a localized string similar to The master says the server is not known to it. Is the server in the master's database and pointing to the correct master? Are all servers using the same pool secret?. /// public static string HOST_UNKNOWN_TO_MASTER { get { diff --git a/XenModel/XenAPI/FriendlyErrorNames.resx b/XenModel/XenAPI/FriendlyErrorNames.resx index 2297030ec..fba563e72 100755 --- a/XenModel/XenAPI/FriendlyErrorNames.resx +++ b/XenModel/XenAPI/FriendlyErrorNames.resx @@ -553,7 +553,7 @@ The server is still booting. - The master says the server is not known to it. Perhaps the server was deleted from the master's database? + The master says the server is not known to it. Is the server in the master's database and pointing to the correct master? Are all servers using the same pool secret? The specified VBD device is not recognized: please use a non-negative integer diff --git a/XenModel/XenAPI/JsonRpcClient.cs b/XenModel/XenAPI/JsonRpcClient.cs index fe0d31f7a..8a4ff85ba 100755 --- a/XenModel/XenAPI/JsonRpcClient.cs +++ b/XenModel/XenAPI/JsonRpcClient.cs @@ -1838,6 +1838,20 @@ namespace XenAPI return Rpc>("Async.pool.remove_from_guest_agent_config", new JArray(session, _pool ?? "", _key ?? ""), serializer); } + public void pool_rotate_secret(string session) + { + var converters = new List {}; + var serializer = CreateSerializer(converters); + Rpc("pool.rotate_secret", new JArray(session), serializer); + } + + public XenRef async_pool_rotate_secret(string session) + { + var converters = new List {new XenRefConverter()}; + var serializer = CreateSerializer(converters); + return Rpc>("Async.pool.rotate_secret", new JArray(session), serializer); + } + public List> pool_get_all(string session) { var converters = new List {new XenRefListConverter()}; diff --git a/XenModel/XenAPI/Pool.cs b/XenModel/XenAPI/Pool.cs index 8bd35615a..930b54563 100644 --- a/XenModel/XenAPI/Pool.cs +++ b/XenModel/XenAPI/Pool.cs @@ -2714,6 +2714,32 @@ namespace XenAPI return XenRef.Create(session.XmlRpcProxy.async_pool_remove_from_guest_agent_config(session.opaque_ref, _pool ?? "", _key ?? "").parse()); } + /// + /// + /// First published in Unreleased. + /// + /// The session + public static void rotate_secret(Session session) + { + if (session.JsonRpcClient != null) + session.JsonRpcClient.pool_rotate_secret(session.opaque_ref); + else + session.XmlRpcProxy.pool_rotate_secret(session.opaque_ref).parse(); + } + + /// + /// + /// First published in Unreleased. + /// + /// The session + public static XenRef async_rotate_secret(Session session) + { + if (session.JsonRpcClient != null) + return session.JsonRpcClient.async_pool_rotate_secret(session.opaque_ref); + else + return XenRef.Create(session.XmlRpcProxy.async_pool_rotate_secret(session.opaque_ref).parse()); + } + /// /// Return a list of all the pools known to the system. /// First published in XenServer 4.0. diff --git a/XenModel/XenAPI/Proxy.cs b/XenModel/XenAPI/Proxy.cs index 713810331..214f67ccd 100755 --- a/XenModel/XenAPI/Proxy.cs +++ b/XenModel/XenAPI/Proxy.cs @@ -1070,6 +1070,14 @@ namespace XenAPI Response async_pool_remove_from_guest_agent_config(string session, string _pool, string _key); + [XmlRpcMethod("pool.rotate_secret")] + Response + pool_rotate_secret(string session); + + [XmlRpcMethod("Async.pool.rotate_secret")] + Response + async_pool_rotate_secret(string session); + [XmlRpcMethod("pool.get_all")] Response pool_get_all(string session);