From bb40f0b887f4eac806b8e1233bf50401137bb6bc Mon Sep 17 00:00:00 2001 From: Alexander Trofimov Date: Wed, 22 Apr 2015 22:05:13 +0300 Subject: [PATCH] wsp-10329 Adding hyper-v replica to HyperV Provider. WebPortal Part 3. --- .../VirtualizationServerController2012.cs | 5 +- .../esVirtualizationServer2012.asmx.cs | 2 +- .../Replication/ReplicationDetailInfo.cs | 1 + .../Code/Helpers/VirtualMachines2012Helper.cs | 26 ++ .../App_LocalResources/VdcHome.ascx.resx | 3 + .../VpsDetailsReplications.ascx.resx | 69 ++++ .../VPS2012/UserControls/ServerTabs.ascx.cs | 4 +- .../WebsitePanel/VPS2012/VdcHome.ascx | 5 + .../WebsitePanel/VPS2012/VdcHome.ascx.cs | 29 +- .../VPS2012/VpsDetailsReplications.ascx | 166 +++++++-- .../VPS2012/VpsDetailsReplications.ascx.cs | 118 ++++++- .../VpsDetailsReplications.ascx.designer.cs | 326 +++++++++++++++++- 12 files changed, 692 insertions(+), 62 deletions(-) diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Virtualization2012/VirtualizationServerController2012.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Virtualization2012/VirtualizationServerController2012.cs index df25e2bf..a4352b0e 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Virtualization2012/VirtualizationServerController2012.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Virtualization2012/VirtualizationServerController2012.cs @@ -3825,7 +3825,7 @@ namespace WebsitePanel.EnterpriseServer { VirtualMachine vm = GetVirtualMachineByItemId(itemId); VirtualizationServer2012 vs = GetVirtualizationProxy(vm.ServiceId); - vs.DisableVmReplication(vm.VirtualMachineId, null); + vs.DisableVmReplication(vm.VirtualMachineId); CleanUpReplicaServer(vm); @@ -3887,10 +3887,9 @@ namespace WebsitePanel.EnterpriseServer // Clean up replica server var replicaVm = replicaServer.GetVirtualMachines().FirstOrDefault(m => m.Name == originalVm.Name); - if (replicaVm != null) { - replicaServer.DisableVmReplication(replicaVm.VirtualMachineId, null); + replicaServer.DisableVmReplication(replicaVm.VirtualMachineId); replicaServer.ShutDownVirtualMachine(replicaVm.VirtualMachineId, true, "ReplicaDelete"); replicaServer.DeleteVirtualMachine(replicaVm.VirtualMachineId); } diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esVirtualizationServer2012.asmx.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esVirtualizationServer2012.asmx.cs index cf1b1f40..0f5a3104 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esVirtualizationServer2012.asmx.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esVirtualizationServer2012.asmx.cs @@ -532,7 +532,7 @@ namespace WebsitePanel.EnterpriseServer [WebMethod] public ResultObject ResumeReplication(int itemId) { - return VirtualizationServerController2012.PauseReplication(itemId); + return VirtualizationServerController2012.ResumeReplication(itemId); } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Virtualization/Replication/ReplicationDetailInfo.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Virtualization/Replication/ReplicationDetailInfo.cs index 77fe5aa6..df941862 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Virtualization/Replication/ReplicationDetailInfo.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Virtualization/Replication/ReplicationDetailInfo.cs @@ -17,6 +17,7 @@ namespace WebsitePanel.Providers.Virtualization public TimeSpan AverageLatency { get; set; } public int Errors { get; set; } public int SuccessfulReplications { get; set; } + public int MissedReplicationCount { get; set; } public string PendingSize { get; set; } public DateTime LastSynhronizedAt { get; set; } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/Code/Helpers/VirtualMachines2012Helper.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/Code/Helpers/VirtualMachines2012Helper.cs index 0ad705fd..009b046c 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/Code/Helpers/VirtualMachines2012Helper.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/Code/Helpers/VirtualMachines2012Helper.cs @@ -30,6 +30,7 @@ using WebsitePanel.Providers.Virtualization; using System.Web; using System; +using System.Collections.Specialized; namespace WebsitePanel.Portal { @@ -125,5 +126,30 @@ namespace WebsitePanel.Portal return privateAddresses.Count; } #endregion + + public static StringDictionary ConvertArrayToDictionary(string[] settings) + { + StringDictionary r = new StringDictionary(); + foreach (string setting in settings) + { + int idx = setting.IndexOf('='); + r.Add(setting.Substring(0, idx), setting.Substring(idx + 1)); + } + return r; + } + + public static bool IsReplicationEnabled(int packageId) + { + var vmsMeta = (new VirtualMachines2012Helper()).GetVirtualMachines(packageId, null, null, null, 1, 0); + if (vmsMeta.Length == 0) return false; + + var packageVm = ES.Services.VPS2012.GetVirtualMachineItem(vmsMeta[0].ItemID); + if (packageVm == null) return false; + + var serviceSettings = ConvertArrayToDictionary(ES.Services.Servers.GetServiceSettings(packageVm.ServiceId)); + if (serviceSettings == null) return false; + + return serviceSettings["ReplicaMode"] == ReplicaMode.ReplicationEnabled.ToString(); + } } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VdcHome.ascx.resx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VdcHome.ascx.resx index 8b86f534..2991155c 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VdcHome.ascx.resx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VdcHome.ascx.resx @@ -186,4 +186,7 @@ Fast Create VM + + Replication status + \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VpsDetailsReplications.ascx.resx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VpsDetailsReplications.ascx.resx index beba1420..8a978a97 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VpsDetailsReplications.ascx.resx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/App_LocalResources/VpsDetailsReplications.ascx.resx @@ -123,12 +123,27 @@ ShowProgressDialog('Updating VM replication...'); + + ShowProgressDialog('Pausing VM replication...'); + + + ShowProgressDialog('Resuming VM replication...'); + Replication + + Close + Details + + Pause + + + Resume + Update @@ -147,15 +162,54 @@ 5 minutes + + Average latency: + + + Average size: + SSL ceritficate: + + Replication details + + + Replication Health: + + + Replication Mode: + + + Current Primary Server: + + + Current Replica Server: + + + Replication State: + + + Errors encountered: + Replication Frequency + + From time: + + + Health: + Last synchronized at: + + Last synchronized at: + + + Maximum size: + Primary Server: @@ -168,6 +222,15 @@ Replica Server: + + Size of data yet to be replicated: + + + Successful replication cycles: + + + To time: + Choose Replication VHDs: @@ -177,12 +240,18 @@ Maintain only the latest recovery point + + Pending replication: + Replication Configuration Health + + Statistic for past + SSL certificate is required diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/UserControls/ServerTabs.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/UserControls/ServerTabs.ascx.cs index ebdf4a57..aef33468 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/UserControls/ServerTabs.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/UserControls/ServerTabs.ascx.cs @@ -133,7 +133,7 @@ namespace WebsitePanel.Portal.VPS2012.UserControls if ((vm.ExternalNetworkEnabled || vm.PrivateNetworkEnabled) && !createError) tabsList.Add(CreateTab("vps_network", "Tab.Network")); - if (!createError) + if (VirtualMachines2012Helper.IsReplicationEnabled(PanelSecurity.PackageId) && !createError) tabsList.Add(CreateTab("vps_replication", "Tab.Replication")); //tabsList.Add(CreateTab("vps_permissions", "Tab.Permissions")); @@ -161,7 +161,7 @@ namespace WebsitePanel.Portal.VPS2012.UserControls if(createError && idx == 0) messageBox.ShowErrorMessage("VPS_PROVISION_ERROR"); } - + private void BindTask(VirtualMachine vm) { task = ES.Services.Tasks.GetTaskWithLogRecords(vm.CurrentTaskId, DateTime.MinValue); diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx index 8e1fbfce..7bde89d3 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx @@ -73,6 +73,11 @@ <%# Eval("UserName") %> + + + + + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx.cs index b1adc433..e54442d9 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VdcHome.ascx.cs @@ -27,11 +27,10 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using System; -using System.Collections.Generic; -using System.Web; -using System.Web.UI; +using System.Linq; using System.Web.UI.WebControls; using WebsitePanel.EnterpriseServer; +using WebsitePanel.Providers.Virtualization; namespace WebsitePanel.Portal.VPS2012 { @@ -52,15 +51,19 @@ namespace WebsitePanel.Portal.VPS2012 gvServers.Columns[3].Visible = !isUserSelected; gvServers.Columns[4].Visible = !isUserSelected; + // replication + gvServers.Columns[5].Visible = VirtualMachines2012Helper.IsReplicationEnabled(PanelSecurity.PackageId); + // check package quotas bool manageAllowed = VirtualMachines2012Helper.IsVirtualMachineManagementAllowed(PanelSecurity.PackageId); btnCreate.Visible = manageAllowed; btnImport.Visible = (PanelSecurity.EffectiveUser.Role == UserRole.Administrator); - gvServers.Columns[5].Visible = manageAllowed; // delete column + gvServers.Columns[6].Visible = manageAllowed; // delete column // admin operations column - gvServers.Columns[6].Visible = (PanelSecurity.EffectiveUser.Role == UserRole.Administrator); + gvServers.Columns[7].Visible = (PanelSecurity.EffectiveUser.Role == UserRole.Administrator); + } public string GetServerEditUrl(string itemID) @@ -79,6 +82,22 @@ namespace WebsitePanel.Portal.VPS2012 return PortalUtils.GetUserHomePageUrl(userId); } + private VirtualMachine[] _machines; + public string GetReplicationStatus(int itemID) + { + if (_machines == null) + { + var packageVm = ES.Services.VPS2012.GetVirtualMachineItem(itemID); + _machines = ES.Services.VPS2012.GetVirtualMachinesByServiceId(packageVm.ServiceId); + } + + var vmItem = ES.Services.VPS2012.GetVirtualMachineItem(itemID); + if (vmItem == null) return ""; + + var vm = _machines.FirstOrDefault(v => v.VirtualMachineId == vmItem.VirtualMachineId); + return vm != null ? vm.ReplicationState.ToString() : ""; + } + protected void odsServersPaged_Selected(object sender, ObjectDataSourceStatusEventArgs e) { if (e.Exception != null) diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx index bb2bc8fe..e1f1657c 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx @@ -53,15 +53,20 @@ - - + TargetControlID="ReplicationDetailsPanel" meta:ResourceKey="secReplicationDetails" Text="Health"> + + + meta:resourcekey="btnDetailInfo" Text="Details" Style="margin-left: 20px"> + +
- +
@@ -209,8 +214,7 @@ @@ -221,31 +225,145 @@
- - + + + + + + + + + + + + + + + + + + +
- - - * -
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ +
- - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+
+ + + + + + + + + + + + + +
+ + + +
+ + + +
+
+
- - - +  
\ No newline at end of file + BackgroundCssClass="modalBackground" DropShadow="false" CancelControlID="btnCancel" /> \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.cs index 1e145062..9004a56a 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.cs @@ -40,6 +40,8 @@ namespace WebsitePanel.Portal.VPS2012 { public partial class VpsDetailsReplications : WebsitePanelModuleBase { + private const string DateFormat = "MM/dd/yyyy h:mm:ss tt"; + protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) @@ -74,27 +76,31 @@ namespace WebsitePanel.Portal.VPS2012 var packageVm = ES.Services.VPS2012.GetVirtualMachineItem(PanelRequest.ItemID); var vm = ES.Services.VPS2012.GetVirtualMachineExtendedInfo(packageVm.ServiceId, packageVm.VirtualMachineId); - var serviceSettings = ConvertArrayToDictionary(ES.Services.Servers.GetServiceSettings(packageVm.ServiceId)); + var serviceSettings = VirtualMachines2012Helper.ConvertArrayToDictionary(ES.Services.Servers.GetServiceSettings(packageVm.ServiceId)); //var replicaMode = Enum.Parse(typeof(ReplicaMode), serviceSettings["ReplicaMode"]); var computerName = serviceSettings["ServerName"]; var vmReplica = ES.Services.VPS2012.GetReplication(PanelRequest.ItemID); var vmReplicaInfo = ES.Services.VPS2012.GetReplicationInfo(PanelRequest.ItemID); - + // Enable checkpoint chbEnable.Checked = ReplicaTable.Visible = vmReplica != null; - // General labels if (vmReplicaInfo != null) { + // General labels labPrimaryServer.Text = vmReplicaInfo.PrimaryServerName; labReplicaServer.Text = vmReplicaInfo.ReplicaServerName; - labLastSynchronized.Text = vmReplicaInfo.LastSynhronizedAt.ToShortTimeString(); + labLastSynchronized.Text = vmReplicaInfo.LastSynhronizedAt.ToString(DateFormat); + + // Details + labHealth.Text = vmReplicaInfo.Health.ToString(); } else { labPrimaryServer.Text = labReplicaServer.Text = labLastSynchronized.Text = na; + labHealth.Text = ""; } // Certificates list @@ -126,7 +132,7 @@ namespace WebsitePanel.Portal.VPS2012 labVHDs.Text = ""; foreach (var disk in vm.Disks) { - if (string.Equals(vmReplica.VhdToReplicate, disk.Path, StringComparison.OrdinalIgnoreCase)) + if (vmReplica.VhdToReplicate.Any(p=>string.Equals(p, disk.Path, StringComparison.OrdinalIgnoreCase))) labVHDs.Text += disk.Path + "
"; } trVHDEditable.Visible = false; @@ -163,9 +169,24 @@ namespace WebsitePanel.Portal.VPS2012 txtRecoveryPointsVSS.Text = vmReplica.VSSSnapshotFrequencyHour.ToString(); } } + + BindDetailsPopup(vmReplicaInfo); } + // Details secReplicationDetails.Visible = ReplicationDetailsPanel.Visible = vmReplica != null; + + // Pause buttons + if (vm.ReplicationState == ReplicationState.Suspended) + { + btnResume.Visible = true; + btnPause.Visible = false; + } + else + { + btnResume.Visible = false; + btnPause.Visible = true; + } } catch (Exception ex) { @@ -173,6 +194,33 @@ namespace WebsitePanel.Portal.VPS2012 } } + private void BindDetailsPopup(ReplicationDetailInfo vmReplicaInfo) + { + labDetailsState.Text = vmReplicaInfo.State.ToString(); + labDetailsMode.Text = vmReplicaInfo.Mode.ToString(); + labDetailsPrimary.Text = vmReplicaInfo.PrimaryServerName; + labDetailsReplica.Text = vmReplicaInfo.ReplicaServerName; + labDetailsHealth.Text = vmReplicaInfo.Health.ToString(); + labDetailsHealthDetails.Text = vmReplicaInfo.HealthDetails; + + // statistic + StatisticCollapsiblePanel.Text += ToReadableString(vmReplicaInfo.ToTime - vmReplicaInfo.FromTime); + labFromTime.Text = vmReplicaInfo.FromTime.ToString(DateFormat); + labToTime.Text = vmReplicaInfo.ToTime.ToString(DateFormat); + labAverageSize.Text = vmReplicaInfo.AverageSize; + labMaximumSize.Text = vmReplicaInfo.MaximumSize; + labAverageLatency.Text = vmReplicaInfo.AverageLatency.ToString("c"); + labErrorsEncountered.Text = vmReplicaInfo.Errors.ToString(); + labSuccessfulReplicationCycles.Text = string.Format("{0} out of {1} ({2}%)", + vmReplicaInfo.SuccessfulReplications, + vmReplicaInfo.SuccessfulReplications + vmReplicaInfo.MissedReplicationCount, + Convert.ToInt32(100*vmReplicaInfo.SuccessfulReplications/vmReplicaInfo.MissedReplicationCount)); + + // pending replication + labSizeData.Text = vmReplicaInfo.PendingSize; + labLastSyncro.Text = vmReplicaInfo.LastSynhronizedAt.ToString(DateFormat); + } + protected void btnUpdate_Click(object sender, EventArgs e) { if (!Page.IsValid) @@ -191,8 +239,7 @@ namespace WebsitePanel.Portal.VPS2012 vmReplica.VhdToReplicate = chlVHDs.Items.Cast() .Where(li => li.Selected) .Select(li => li.Value) - .ToList() - .FirstOrDefault(); + .ToArray(); vmReplica.Thumbprint = ddlCeritficateDiv.Visible ? ddlCeritficate.SelectedValue : txtCeritficate.Text; vmReplica.ReplicaFrequency = (ReplicaFrequency) Convert.ToInt32(ddlFrequency.SelectedValue); @@ -206,11 +253,11 @@ namespace WebsitePanel.Portal.VPS2012 if (res.IsSuccess) Bind(); else - messageBox.ShowMessage(res, "VPS_ERROR_SET_VM_REPLICATION", "VPS"); + messageBox.ShowMessage(res, "VPS_SET_REPLICA_SERVER_ERROR", "VPS"); } catch (Exception ex) { - messageBox.ShowErrorMessage("VPS_ERROR_SET_VM_REPLICATION", ex); + messageBox.ShowErrorMessage("VPS_SET_REPLICA_SERVER_ERROR", ex); } } @@ -223,23 +270,60 @@ namespace WebsitePanel.Portal.VPS2012 if (res.IsSuccess) Bind(); else - messageBox.ShowMessage(res, "VPS_ERROR_DISABLE_VM_REPLICATION", "VPS"); + messageBox.ShowMessage(res, "VPS_DISABLE_REPLICATION_ERROR", "VPS"); } catch (Exception ex) { - messageBox.ShowErrorMessage("VPS_ERROR_DISABLE_VM_REPLICATION", ex); + messageBox.ShowErrorMessage("VPS_DISABLE_REPLICATION_ERROR", ex); + } + } + + protected void btnPause_Click(object sender, EventArgs e) + { + try + { + ResultObject res = ES.Services.VPS2012.PauseReplication(PanelRequest.ItemID); + + if (res.IsSuccess) + Bind(); + else + messageBox.ShowMessage(res, "VPS_PAUSE_REPLICATION_ERROR", "VPS"); + } + catch (Exception ex) + { + messageBox.ShowErrorMessage("VPS_PAUSE_REPLICATION_ERROR", ex); } } - private StringDictionary ConvertArrayToDictionary(string[] settings) + protected void btnResume_Click(object sender, EventArgs e) { - StringDictionary r = new StringDictionary(); - foreach (string setting in settings) + try { - int idx = setting.IndexOf('='); - r.Add(setting.Substring(0, idx), setting.Substring(idx + 1)); + ResultObject res = ES.Services.VPS2012.ResumeReplication(PanelRequest.ItemID); + + if (res.IsSuccess) + Bind(); + else + messageBox.ShowMessage(res, "VPS_RESUME_REPLICATION_ERROR", "VPS"); } - return r; + catch (Exception ex) + { + messageBox.ShowErrorMessage("VPS_RESUME_REPLICATION_ERROR", ex); + } + } + + public string ToReadableString(TimeSpan span) + { + string formatted = string.Format("{0}{1}{2}", + span.Duration().Days > 0 ? string.Format("{0:0} Day{1}, ", span.Days, span.Days == 1 ? String.Empty : "s") : string.Empty, + span.Duration().Hours > 0 ? string.Format("{0:0} Hour{1}, ", span.Hours, span.Hours == 1 ? String.Empty : "s") : string.Empty, + span.Duration().Minutes > 0 ? string.Format("{0:0} Minute{1}, ", span.Minutes, span.Minutes == 1 ? String.Empty : "s") : string.Empty); + + if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2); + + if (string.IsNullOrEmpty(formatted)) formatted = "0 Minutes"; + + return formatted; } } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.designer.cs index a1720283..d13ead44 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.designer.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/VPS2012/VpsDetailsReplications.ascx.designer.cs @@ -102,6 +102,24 @@ namespace WebsitePanel.Portal.VPS2012 { /// protected global::System.Web.UI.WebControls.Panel ReplicationDetailsPanel; + /// + /// locHealth control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locHealth; + + /// + /// labHealth control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labHealth; + /// /// btnDetailInfo control. /// @@ -111,6 +129,24 @@ namespace WebsitePanel.Portal.VPS2012 { /// protected global::System.Web.UI.WebControls.Button btnDetailInfo; + /// + /// btnPause control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button btnPause; + + /// + /// btnResume control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button btnResume; + /// /// secReplication control. /// @@ -427,49 +463,319 @@ namespace WebsitePanel.Portal.VPS2012 { protected global::System.Web.UI.WebControls.Panel DetailsPanel; /// - /// locRenameSnapshot control. + /// locDetails control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.Localize locRenameSnapshot; + protected global::System.Web.UI.WebControls.Localize locDetails; /// - /// txtSnapshotName control. + /// locDetailsState control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.TextBox txtSnapshotName; + protected global::System.Web.UI.WebControls.Localize locDetailsState; /// - /// SnapshotNameValidator control. + /// labDetailsState control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator SnapshotNameValidator; + protected global::System.Web.UI.WebControls.Label labDetailsState; /// - /// btnRenameSnapshot control. + /// locDetailsMode control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.Button btnRenameSnapshot; + protected global::System.Web.UI.WebControls.Localize locDetailsMode; /// - /// btnCancelRename control. + /// labDetailsMode control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.Button btnCancelRename; + protected global::System.Web.UI.WebControls.Label labDetailsMode; + + /// + /// locDetailsPrimary control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locDetailsPrimary; + + /// + /// labDetailsPrimary control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labDetailsPrimary; + + /// + /// locDetailsReplica control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locDetailsReplica; + + /// + /// labDetailsReplica control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labDetailsReplica; + + /// + /// locDetailsHealth control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locDetailsHealth; + + /// + /// labDetailsHealth control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labDetailsHealth; + + /// + /// labDetailsHealthDetails control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labDetailsHealthDetails; + + /// + /// StatisticCollapsiblePanel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::WebsitePanel.Portal.CollapsiblePanel StatisticCollapsiblePanel; + + /// + /// StatisticPanel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel StatisticPanel; + + /// + /// locFromTime control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locFromTime; + + /// + /// labFromTime control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labFromTime; + + /// + /// locToTime control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locToTime; + + /// + /// labToTime control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labToTime; + + /// + /// locAverageSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locAverageSize; + + /// + /// labAverageSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labAverageSize; + + /// + /// locMaximumSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locMaximumSize; + + /// + /// labMaximumSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labMaximumSize; + + /// + /// locAverageLatency control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locAverageLatency; + + /// + /// labAverageLatency control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labAverageLatency; + + /// + /// locErrorsEncountered control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locErrorsEncountered; + + /// + /// labErrorsEncountered control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labErrorsEncountered; + + /// + /// locSuccessfulReplicationCycles control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locSuccessfulReplicationCycles; + + /// + /// labSuccessfulReplicationCycles control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labSuccessfulReplicationCycles; + + /// + /// PendingReplicationCollapsiblePanel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::WebsitePanel.Portal.CollapsiblePanel PendingReplicationCollapsiblePanel; + + /// + /// PendingReplicationPanel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel PendingReplicationPanel; + + /// + /// locSizeData control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locSizeData; + + /// + /// labSizeData control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labSizeData; + + /// + /// locLastSyncro control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locLastSyncro; + + /// + /// labLastSyncro control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label labLastSyncro; + + /// + /// btnCancel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button btnCancel; /// /// DetailModal control.