wsp-10329 Adding hyper-v replica to HyperV Provider. WebPortal Part 3.

This commit is contained in:
Alexander Trofimov 2015-04-22 22:05:13 +03:00
parent 3a8e9e8355
commit bb40f0b887
12 changed files with 692 additions and 62 deletions

View file

@ -3825,7 +3825,7 @@ namespace WebsitePanel.EnterpriseServer
{ {
VirtualMachine vm = GetVirtualMachineByItemId(itemId); VirtualMachine vm = GetVirtualMachineByItemId(itemId);
VirtualizationServer2012 vs = GetVirtualizationProxy(vm.ServiceId); VirtualizationServer2012 vs = GetVirtualizationProxy(vm.ServiceId);
vs.DisableVmReplication(vm.VirtualMachineId, null); vs.DisableVmReplication(vm.VirtualMachineId);
CleanUpReplicaServer(vm); CleanUpReplicaServer(vm);
@ -3887,10 +3887,9 @@ namespace WebsitePanel.EnterpriseServer
// Clean up replica server // Clean up replica server
var replicaVm = replicaServer.GetVirtualMachines().FirstOrDefault(m => m.Name == originalVm.Name); var replicaVm = replicaServer.GetVirtualMachines().FirstOrDefault(m => m.Name == originalVm.Name);
if (replicaVm != null) if (replicaVm != null)
{ {
replicaServer.DisableVmReplication(replicaVm.VirtualMachineId, null); replicaServer.DisableVmReplication(replicaVm.VirtualMachineId);
replicaServer.ShutDownVirtualMachine(replicaVm.VirtualMachineId, true, "ReplicaDelete"); replicaServer.ShutDownVirtualMachine(replicaVm.VirtualMachineId, true, "ReplicaDelete");
replicaServer.DeleteVirtualMachine(replicaVm.VirtualMachineId); replicaServer.DeleteVirtualMachine(replicaVm.VirtualMachineId);
} }

View file

@ -532,7 +532,7 @@ namespace WebsitePanel.EnterpriseServer
[WebMethod] [WebMethod]
public ResultObject ResumeReplication(int itemId) public ResultObject ResumeReplication(int itemId)
{ {
return VirtualizationServerController2012.PauseReplication(itemId); return VirtualizationServerController2012.ResumeReplication(itemId);
} }

View file

@ -17,6 +17,7 @@ namespace WebsitePanel.Providers.Virtualization
public TimeSpan AverageLatency { get; set; } public TimeSpan AverageLatency { get; set; }
public int Errors { get; set; } public int Errors { get; set; }
public int SuccessfulReplications { get; set; } public int SuccessfulReplications { get; set; }
public int MissedReplicationCount { get; set; }
public string PendingSize { get; set; } public string PendingSize { get; set; }
public DateTime LastSynhronizedAt { get; set; } public DateTime LastSynhronizedAt { get; set; }
} }

View file

@ -30,6 +30,7 @@
using WebsitePanel.Providers.Virtualization; using WebsitePanel.Providers.Virtualization;
using System.Web; using System.Web;
using System; using System;
using System.Collections.Specialized;
namespace WebsitePanel.Portal namespace WebsitePanel.Portal
{ {
@ -125,5 +126,30 @@ namespace WebsitePanel.Portal
return privateAddresses.Count; return privateAddresses.Count;
} }
#endregion #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();
}
} }
} }

View file

@ -186,4 +186,7 @@
<data name="btnFastCreate.Text" xml:space="preserve"> <data name="btnFastCreate.Text" xml:space="preserve">
<value>Fast Create VM</value> <value>Fast Create VM</value>
</data> </data>
<data name="gvReplication.HeaderText" xml:space="preserve">
<value>Replication status</value>
</data>
</root> </root>

View file

@ -123,12 +123,27 @@
<data name="btnUpdate.OnClientClick" xml:space="preserve"> <data name="btnUpdate.OnClientClick" xml:space="preserve">
<value>ShowProgressDialog('Updating VM replication...');</value> <value>ShowProgressDialog('Updating VM replication...');</value>
</data> </data>
<data name="btnPause.OnClientClick" xml:space="preserve">
<value>ShowProgressDialog('Pausing VM replication...');</value>
</data>
<data name="btnResume.OnClientClick" xml:space="preserve">
<value>ShowProgressDialog('Resuming VM replication...');</value>
</data>
<data name="locTitle.Text" xml:space="preserve"> <data name="locTitle.Text" xml:space="preserve">
<value>Replication</value> <value>Replication</value>
</data> </data>
<data name="btnCancel.Text" xml:space="preserve">
<value>Close</value>
</data>
<data name="btnDetailInfo.Text" xml:space="preserve"> <data name="btnDetailInfo.Text" xml:space="preserve">
<value>Details</value> <value>Details</value>
</data> </data>
<data name="btnPause.Text" xml:space="preserve">
<value>Pause</value>
</data>
<data name="btnResume.Text" xml:space="preserve">
<value>Resume</value>
</data>
<data name="btnUpdate.Text" xml:space="preserve"> <data name="btnUpdate.Text" xml:space="preserve">
<value>Update</value> <value>Update</value>
</data> </data>
@ -147,15 +162,54 @@
<data name="ddlFrequency5minutes.Text" xml:space="preserve"> <data name="ddlFrequency5minutes.Text" xml:space="preserve">
<value>5 minutes</value> <value>5 minutes</value>
</data> </data>
<data name="locAverageLatency.Text" xml:space="preserve">
<value>Average latency:</value>
</data>
<data name="locAverageSize.Text" xml:space="preserve">
<value>Average size:</value>
</data>
<data name="locCeritficate.Text" xml:space="preserve"> <data name="locCeritficate.Text" xml:space="preserve">
<value>SSL ceritficate:</value> <value>SSL ceritficate:</value>
</data> </data>
<data name="locDetails.Text" xml:space="preserve">
<value>Replication details</value>
</data>
<data name="locDetailsHealth.Text" xml:space="preserve">
<value>Replication Health:</value>
</data>
<data name="locDetailsMode.Text" xml:space="preserve">
<value>Replication Mode:</value>
</data>
<data name="locDetailsPrimary.Text" xml:space="preserve">
<value>Current Primary Server:</value>
</data>
<data name="locDetailsReplica.Text" xml:space="preserve">
<value>Current Replica Server:</value>
</data>
<data name="locDetailsState.Text" xml:space="preserve">
<value>Replication State:</value>
</data>
<data name="locErrorsEncountered.Text" xml:space="preserve">
<value>Errors encountered:</value>
</data>
<data name="locFrequency.Text" xml:space="preserve"> <data name="locFrequency.Text" xml:space="preserve">
<value>Replication Frequency</value> <value>Replication Frequency</value>
</data> </data>
<data name="locFromTime.Text" xml:space="preserve">
<value>From time:</value>
</data>
<data name="locHealth.Text" xml:space="preserve">
<value>Health:</value>
</data>
<data name="locLastSynchronized.Text" xml:space="preserve"> <data name="locLastSynchronized.Text" xml:space="preserve">
<value>Last synchronized at:</value> <value>Last synchronized at:</value>
</data> </data>
<data name="locLastSyncro.Text" xml:space="preserve">
<value>Last synchronized at:</value>
</data>
<data name="locMaximumSize.Text" xml:space="preserve">
<value>Maximum size:</value>
</data>
<data name="locPrimaryServer.Text" xml:space="preserve"> <data name="locPrimaryServer.Text" xml:space="preserve">
<value>Primary Server:</value> <value>Primary Server:</value>
</data> </data>
@ -168,6 +222,15 @@
<data name="locReplicaServer.Text" xml:space="preserve"> <data name="locReplicaServer.Text" xml:space="preserve">
<value>Replica Server:</value> <value>Replica Server:</value>
</data> </data>
<data name="locSizeData.Text" xml:space="preserve">
<value>Size of data yet to be replicated:</value>
</data>
<data name="locSuccessfulReplicationCycles.Text" xml:space="preserve">
<value>Successful replication cycles:</value>
</data>
<data name="locToTime.Text" xml:space="preserve">
<value>To time:</value>
</data>
<data name="locVHDs.Text" xml:space="preserve"> <data name="locVHDs.Text" xml:space="preserve">
<value>Choose Replication VHDs:</value> <value>Choose Replication VHDs:</value>
</data> </data>
@ -177,12 +240,18 @@
<data name="radRecoveryPointsLast.Text" xml:space="preserve"> <data name="radRecoveryPointsLast.Text" xml:space="preserve">
<value>Maintain only the latest recovery point</value> <value>Maintain only the latest recovery point</value>
</data> </data>
<data name="secPendingReplication.Text" xml:space="preserve">
<value>Pending replication:</value>
</data>
<data name="secReplication.Text" xml:space="preserve"> <data name="secReplication.Text" xml:space="preserve">
<value>Replication Configuration</value> <value>Replication Configuration</value>
</data> </data>
<data name="secReplicationDetails.Text" xml:space="preserve"> <data name="secReplicationDetails.Text" xml:space="preserve">
<value>Health</value> <value>Health</value>
</data> </data>
<data name="secStatisticPanel.Text" xml:space="preserve">
<value>Statistic for past </value>
</data>
<data name="valCeritficateRequire.ErrorMessage" xml:space="preserve"> <data name="valCeritficateRequire.ErrorMessage" xml:space="preserve">
<value>SSL certificate is required</value> <value>SSL certificate is required</value>
</data> </data>

View file

@ -133,7 +133,7 @@ namespace WebsitePanel.Portal.VPS2012.UserControls
if ((vm.ExternalNetworkEnabled || vm.PrivateNetworkEnabled) && !createError) if ((vm.ExternalNetworkEnabled || vm.PrivateNetworkEnabled) && !createError)
tabsList.Add(CreateTab("vps_network", "Tab.Network")); 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_replication", "Tab.Replication"));
//tabsList.Add(CreateTab("vps_permissions", "Tab.Permissions")); //tabsList.Add(CreateTab("vps_permissions", "Tab.Permissions"));
@ -161,7 +161,7 @@ namespace WebsitePanel.Portal.VPS2012.UserControls
if(createError && idx == 0) if(createError && idx == 0)
messageBox.ShowErrorMessage("VPS_PROVISION_ERROR"); messageBox.ShowErrorMessage("VPS_PROVISION_ERROR");
} }
private void BindTask(VirtualMachine vm) private void BindTask(VirtualMachine vm)
{ {
task = ES.Services.Tasks.GetTaskWithLogRecords(vm.CurrentTaskId, DateTime.MinValue); task = ES.Services.Tasks.GetTaskWithLogRecords(vm.CurrentTaskId, DateTime.MinValue);

View file

@ -73,6 +73,11 @@
<%# Eval("UserName") %> <%# Eval("UserName") %>
</asp:hyperlink> </asp:hyperlink>
</ItemTemplate> </ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Replication" meta:resourcekey="gvReplication" >
<ItemTemplate>
<asp:Localize id="locReplication" runat="server" Text='<%# GetReplicationStatus((int)Eval("ItemID")) %>'></asp:Localize>
</ItemTemplate>
</asp:TemplateField> </asp:TemplateField>
<asp:TemplateField> <asp:TemplateField>
<ItemTemplate> <ItemTemplate>

View file

@ -27,11 +27,10 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System; using System;
using System.Collections.Generic; using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls; using System.Web.UI.WebControls;
using WebsitePanel.EnterpriseServer; using WebsitePanel.EnterpriseServer;
using WebsitePanel.Providers.Virtualization;
namespace WebsitePanel.Portal.VPS2012 namespace WebsitePanel.Portal.VPS2012
{ {
@ -52,15 +51,19 @@ namespace WebsitePanel.Portal.VPS2012
gvServers.Columns[3].Visible = !isUserSelected; gvServers.Columns[3].Visible = !isUserSelected;
gvServers.Columns[4].Visible = !isUserSelected; gvServers.Columns[4].Visible = !isUserSelected;
// replication
gvServers.Columns[5].Visible = VirtualMachines2012Helper.IsReplicationEnabled(PanelSecurity.PackageId);
// check package quotas // check package quotas
bool manageAllowed = VirtualMachines2012Helper.IsVirtualMachineManagementAllowed(PanelSecurity.PackageId); bool manageAllowed = VirtualMachines2012Helper.IsVirtualMachineManagementAllowed(PanelSecurity.PackageId);
btnCreate.Visible = manageAllowed; btnCreate.Visible = manageAllowed;
btnImport.Visible = (PanelSecurity.EffectiveUser.Role == UserRole.Administrator); btnImport.Visible = (PanelSecurity.EffectiveUser.Role == UserRole.Administrator);
gvServers.Columns[5].Visible = manageAllowed; // delete column gvServers.Columns[6].Visible = manageAllowed; // delete column
// admin operations 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) public string GetServerEditUrl(string itemID)
@ -79,6 +82,22 @@ namespace WebsitePanel.Portal.VPS2012
return PortalUtils.GetUserHomePageUrl(userId); 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) protected void odsServersPaged_Selected(object sender, ObjectDataSourceStatusEventArgs e)
{ {
if (e.Exception != null) if (e.Exception != null)

View file

@ -53,15 +53,20 @@
<wsp:ServerTabs ID="tabs" runat="server" SelectedTab="vps_replication" /> <wsp:ServerTabs ID="tabs" runat="server" SelectedTab="vps_replication" />
<wsp:SimpleMessageBox ID="messageBox" runat="server" /> <wsp:SimpleMessageBox ID="messageBox" runat="server" />
<asp:ValidationSummary ID="validatorsSummary" runat="server" <asp:ValidationSummary ID="validatorsSummary" runat="server"
ValidationGroup="Vps" ShowMessageBox="True" ShowSummary="False" /> ValidationGroup="Vps" ShowMessageBox="True" ShowSummary="False" />
<wsp:CollapsiblePanel ID="secReplicationDetails" runat="server" Visible="False" <wsp:CollapsiblePanel ID="secReplicationDetails" runat="server" Visible="False"
TargetControlID="ReplicationDetailsPanel" meta:ResourceKey="secReplicationDetails" Text="Health"> TargetControlID="ReplicationDetailsPanel" meta:ResourceKey="secReplicationDetails" Text="Health"></wsp:CollapsiblePanel>
</wsp:CollapsiblePanel>
<asp:Panel ID="ReplicationDetailsPanel" runat="server" Height="0" Style="overflow: hidden; padding: 10px; width: 750px;"> <asp:Panel ID="ReplicationDetailsPanel" runat="server" Height="0" Style="overflow: hidden; padding: 10px; width: 750px;">
<asp:Localize ID="locHealth" runat="server" meta:resourcekey="locHealth" Text="Health:"></asp:Localize>
<asp:Label ID="labHealth" runat="server"></asp:Label>
<asp:Button ID="btnDetailInfo" runat="server" CausesValidation="false" CssClass="ActionButtonRename" <asp:Button ID="btnDetailInfo" runat="server" CausesValidation="false" CssClass="ActionButtonRename"
meta:resourcekey="btnDetailInfo" Text="Details"></asp:Button> meta:resourcekey="btnDetailInfo" Text="Details" Style="margin-left: 20px"></asp:Button>
<asp:Button ID="btnPause" runat="server" CausesValidation="false" CssClass="ActionButtonRename"
meta:resourcekey="btnPause" Text="Pause" OnClick="btnPause_Click" Style="margin-left: 20px"></asp:Button>
<asp:Button ID="btnResume" runat="server" CausesValidation="false" CssClass="ActionButtonRename"
meta:resourcekey="btnResume" Text="Resume" OnClick="btnResume_Click" Style="margin-left: 20px"></asp:Button>
</asp:Panel> </asp:Panel>
<wsp:CollapsiblePanel ID="secReplication" runat="server" Visible="True" <wsp:CollapsiblePanel ID="secReplication" runat="server" Visible="True"
@ -69,7 +74,7 @@
</wsp:CollapsiblePanel> </wsp:CollapsiblePanel>
<asp:Panel ID="ReplicationPanel" runat="server" Height="0" Style="overflow: hidden; padding: 10px; width: 750px;"> <asp:Panel ID="ReplicationPanel" runat="server" Height="0" Style="overflow: hidden; padding: 10px; width: 750px;">
<div class="FormButtonsBarClean"> <div class="FormButtonsBarClean">
<asp:CheckBox ID="chbEnable" runat="server" meta:resourcekey="chbEnable" Text="Enable replication" AutoPostBack="True" /> <asp:CheckBox ID="chbEnable" runat="server" meta:resourcekey="chbEnable" Text="Enable replication" AutoPostBack="True" />
</div> </div>
<table runat="server" id="ReplicaTable" class="ReplicaTable" style="margin: 10px; width: 100%;"> <table runat="server" id="ReplicaTable" class="ReplicaTable" style="margin: 10px; width: 100%;">
<tr> <tr>
@ -209,8 +214,7 @@
<tr> <tr>
<td class="Popup-HeaderLeft"></td> <td class="Popup-HeaderLeft"></td>
<td class="Popup-HeaderTitle"> <td class="Popup-HeaderTitle">
<asp:Localize ID="locRenameSnapshot" runat="server" Text="Rename snapshot" <asp:Localize ID="locDetails" runat="server" Text="Replication details" meta:resourcekey="locDetails"></asp:Localize>
meta:resourcekey="locRenameSnapshot"></asp:Localize>
</td> </td>
<td class="Popup-HeaderRight"></td> <td class="Popup-HeaderRight"></td>
</tr> </tr>
@ -221,31 +225,145 @@
<table cellspacing="10"> <table cellspacing="10">
<tr> <tr>
<td> <td style="width: 180px">
<asp:TextBox ID="txtSnapshotName" runat="server" CssClass="NormalTextBox" Width="300"></asp:TextBox> <asp:Localize ID="locDetailsState" runat="server" Text="Replication State:" meta:resourcekey="locDetailsState"></asp:Localize>
</td>
<asp:RequiredFieldValidator ID="SnapshotNameValidator" runat="server" Text="*" Display="Dynamic" <td>
ControlToValidate="txtSnapshotName" meta:resourcekey="SnapshotNameValidator" SetFocusOnError="true" <asp:Label ID="labDetailsState" runat="server"></asp:Label>
ValidationGroup="RenameSnapshot">*</asp:RequiredFieldValidator> </td>
</td> </tr>
</tr> <tr>
<td>
<asp:Localize ID="locDetailsMode" runat="server" Text="Replication Mode:" meta:resourcekey="locDetailsMode"></asp:Localize>
</td>
<td>
<asp:Label ID="labDetailsMode" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locDetailsPrimary" runat="server" Text="Current Primary Server:" meta:resourcekey="locDetailsPrimary"></asp:Localize>
</td>
<td>
<asp:Label ID="labDetailsPrimary" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locDetailsReplica" runat="server" Text="Current Replica Server:" meta:resourcekey="locDetailsReplica"></asp:Localize>
</td>
<td>
<asp:Label ID="labDetailsReplica" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locDetailsHealth" runat="server" Text="Replication Health:" meta:resourcekey="locDetailsHealth"></asp:Localize>
</td>
<td>
<asp:Label ID="labDetailsHealth" runat="server"></asp:Label>
<br/>
<asp:Label ID="labDetailsHealthDetails" runat="server"></asp:Label>
</td>
</tr>
</table> </table>
<wsp:CollapsiblePanel ID="StatisticCollapsiblePanel" runat="server" Visible="True"
TargetControlID="StatisticPanel" meta:ResourceKey="secStatisticPanel" Text="Statistic for past "></wsp:CollapsiblePanel>
<asp:Panel ID="StatisticPanel" runat="server" Height="0" Style="overflow: hidden; padding: 10px; width: 400px;">
<table cellspacing="10">
<tr>
<td style="width: 180px">
<asp:Localize ID="locFromTime" runat="server" Text="From time:" meta:resourcekey="locFromTime"></asp:Localize>
</td>
<td>
<asp:Label ID="labFromTime" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locToTime" runat="server" Text="To time:" meta:resourcekey="locToTime"></asp:Localize>
</td>
<td>
<asp:Label ID="labToTime" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locAverageSize" runat="server" Text="Average size:" meta:resourcekey="locAverageSize"></asp:Localize>
</td>
<td>
<asp:Label ID="labAverageSize" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locMaximumSize" runat="server" Text="Maximum size:" meta:resourcekey="locMaximumSize"></asp:Localize>
</td>
<td>
<asp:Label ID="labMaximumSize" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locAverageLatency" runat="server" Text="Average latency:" meta:resourcekey="locAverageLatency"></asp:Localize>
</td>
<td>
<asp:Label ID="labAverageLatency" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locErrorsEncountered" runat="server" Text="Errors encountered:" meta:resourcekey="locErrorsEncountered"></asp:Localize>
</td>
<td>
<asp:Label ID="labErrorsEncountered" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locSuccessfulReplicationCycles" runat="server" Text="Successful replication cycles:" meta:resourcekey="locSuccessfulReplicationCycles"></asp:Localize>
</td>
<td>
<asp:Label ID="labSuccessfulReplicationCycles" runat="server"></asp:Label>
</td>
</tr>
</table>
</asp:Panel>
<wsp:CollapsiblePanel ID="PendingReplicationCollapsiblePanel" runat="server" Visible="True"
TargetControlID="PendingReplicationPanel" meta:ResourceKey="secPendingReplication" Text="Pending replication"></wsp:CollapsiblePanel>
<asp:Panel ID="PendingReplicationPanel" runat="server" Height="0" Style="overflow: hidden; padding: 10px; width: 400px;">
<table cellspacing="10">
<tr>
<td style="width: 180px">
<asp:Localize ID="locSizeData" runat="server" Text="Size of data yet to be replicated:" meta:resourcekey="locSizeData"></asp:Localize>
</td>
<td>
<asp:Label ID="labSizeData" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:Localize ID="locLastSyncro" runat="server" Text="Last synchronized at:" meta:resourcekey="locLastSyncro"></asp:Localize>
</td>
<td>
<asp:Label ID="labLastSyncro" runat="server"></asp:Label>
</td>
</tr>
</table>
</asp:Panel>
<br /> <br />
</div> </div>
<div class="FormFooter"> <div class="FormFooter">
<asp:Button ID="btnRenameSnapshot" runat="server" CssClass="Button1" &nbsp;<asp:Button ID="btnCancel" runat="server" CssClass="Button1" meta:resourcekey="btnCancel" Text="Cancel" CausesValidation="false" />
meta:resourcekey="btnRenameSnapshot" Text="Rename"
ValidationGroup="RenameSnapshot" />
<asp:Button ID="btnCancelRename" runat="server" CssClass="Button1"
meta:resourcekey="btnCancelRename" Text="Cancel" CausesValidation="false" />
</div> </div>
</div> </div>
</asp:Panel> </asp:Panel>
<ajaxToolkit:ModalPopupExtender ID="DetailModal" runat="server" BehaviorID="DetailModal" <ajaxToolkit:ModalPopupExtender ID="DetailModal" runat="server" BehaviorID="DetailModal"
TargetControlID="btnDetailInfo" PopupControlID="DetailsPanel" TargetControlID="btnDetailInfo" PopupControlID="DetailsPanel"
BackgroundCssClass="modalBackground" DropShadow="false" CancelControlID="btnCancelRename" /> BackgroundCssClass="modalBackground" DropShadow="false" CancelControlID="btnCancel" />

View file

@ -40,6 +40,8 @@ namespace WebsitePanel.Portal.VPS2012
{ {
public partial class VpsDetailsReplications : WebsitePanelModuleBase public partial class VpsDetailsReplications : WebsitePanelModuleBase
{ {
private const string DateFormat = "MM/dd/yyyy h:mm:ss tt";
protected void Page_Load(object sender, EventArgs e) protected void Page_Load(object sender, EventArgs e)
{ {
if (!IsPostBack) if (!IsPostBack)
@ -74,27 +76,31 @@ namespace WebsitePanel.Portal.VPS2012
var packageVm = ES.Services.VPS2012.GetVirtualMachineItem(PanelRequest.ItemID); var packageVm = ES.Services.VPS2012.GetVirtualMachineItem(PanelRequest.ItemID);
var vm = ES.Services.VPS2012.GetVirtualMachineExtendedInfo(packageVm.ServiceId, packageVm.VirtualMachineId); 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 replicaMode = Enum.Parse(typeof(ReplicaMode), serviceSettings["ReplicaMode"]);
var computerName = serviceSettings["ServerName"]; var computerName = serviceSettings["ServerName"];
var vmReplica = ES.Services.VPS2012.GetReplication(PanelRequest.ItemID); var vmReplica = ES.Services.VPS2012.GetReplication(PanelRequest.ItemID);
var vmReplicaInfo = ES.Services.VPS2012.GetReplicationInfo(PanelRequest.ItemID); var vmReplicaInfo = ES.Services.VPS2012.GetReplicationInfo(PanelRequest.ItemID);
// Enable checkpoint // Enable checkpoint
chbEnable.Checked = ReplicaTable.Visible = vmReplica != null; chbEnable.Checked = ReplicaTable.Visible = vmReplica != null;
// General labels
if (vmReplicaInfo != null) if (vmReplicaInfo != null)
{ {
// General labels
labPrimaryServer.Text = vmReplicaInfo.PrimaryServerName; labPrimaryServer.Text = vmReplicaInfo.PrimaryServerName;
labReplicaServer.Text = vmReplicaInfo.ReplicaServerName; labReplicaServer.Text = vmReplicaInfo.ReplicaServerName;
labLastSynchronized.Text = vmReplicaInfo.LastSynhronizedAt.ToShortTimeString(); labLastSynchronized.Text = vmReplicaInfo.LastSynhronizedAt.ToString(DateFormat);
// Details
labHealth.Text = vmReplicaInfo.Health.ToString();
} }
else else
{ {
labPrimaryServer.Text = labReplicaServer.Text = labLastSynchronized.Text = na; labPrimaryServer.Text = labReplicaServer.Text = labLastSynchronized.Text = na;
labHealth.Text = "";
} }
// Certificates list // Certificates list
@ -126,7 +132,7 @@ namespace WebsitePanel.Portal.VPS2012
labVHDs.Text = ""; labVHDs.Text = "";
foreach (var disk in vm.Disks) 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 + "<br>"; labVHDs.Text += disk.Path + "<br>";
} }
trVHDEditable.Visible = false; trVHDEditable.Visible = false;
@ -163,9 +169,24 @@ namespace WebsitePanel.Portal.VPS2012
txtRecoveryPointsVSS.Text = vmReplica.VSSSnapshotFrequencyHour.ToString(); txtRecoveryPointsVSS.Text = vmReplica.VSSSnapshotFrequencyHour.ToString();
} }
} }
BindDetailsPopup(vmReplicaInfo);
} }
// Details
secReplicationDetails.Visible = ReplicationDetailsPanel.Visible = vmReplica != null; 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) 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) protected void btnUpdate_Click(object sender, EventArgs e)
{ {
if (!Page.IsValid) if (!Page.IsValid)
@ -191,8 +239,7 @@ namespace WebsitePanel.Portal.VPS2012
vmReplica.VhdToReplicate = chlVHDs.Items.Cast<ListItem>() vmReplica.VhdToReplicate = chlVHDs.Items.Cast<ListItem>()
.Where(li => li.Selected) .Where(li => li.Selected)
.Select(li => li.Value) .Select(li => li.Value)
.ToList() .ToArray();
.FirstOrDefault();
vmReplica.Thumbprint = ddlCeritficateDiv.Visible ? ddlCeritficate.SelectedValue : txtCeritficate.Text; vmReplica.Thumbprint = ddlCeritficateDiv.Visible ? ddlCeritficate.SelectedValue : txtCeritficate.Text;
vmReplica.ReplicaFrequency = (ReplicaFrequency) Convert.ToInt32(ddlFrequency.SelectedValue); vmReplica.ReplicaFrequency = (ReplicaFrequency) Convert.ToInt32(ddlFrequency.SelectedValue);
@ -206,11 +253,11 @@ namespace WebsitePanel.Portal.VPS2012
if (res.IsSuccess) if (res.IsSuccess)
Bind(); Bind();
else else
messageBox.ShowMessage(res, "VPS_ERROR_SET_VM_REPLICATION", "VPS"); messageBox.ShowMessage(res, "VPS_SET_REPLICA_SERVER_ERROR", "VPS");
} }
catch (Exception ex) 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) if (res.IsSuccess)
Bind(); Bind();
else else
messageBox.ShowMessage(res, "VPS_ERROR_DISABLE_VM_REPLICATION", "VPS"); messageBox.ShowMessage(res, "VPS_DISABLE_REPLICATION_ERROR", "VPS");
} }
catch (Exception ex) 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(); try
foreach (string setting in settings)
{ {
int idx = setting.IndexOf('='); ResultObject res = ES.Services.VPS2012.ResumeReplication(PanelRequest.ItemID);
r.Add(setting.Substring(0, idx), setting.Substring(idx + 1));
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;
} }
} }
} }

View file

@ -102,6 +102,24 @@ namespace WebsitePanel.Portal.VPS2012 {
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.Panel ReplicationDetailsPanel; protected global::System.Web.UI.WebControls.Panel ReplicationDetailsPanel;
/// <summary>
/// locHealth control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locHealth;
/// <summary>
/// labHealth control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labHealth;
/// <summary> /// <summary>
/// btnDetailInfo control. /// btnDetailInfo control.
/// </summary> /// </summary>
@ -111,6 +129,24 @@ namespace WebsitePanel.Portal.VPS2012 {
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.Button btnDetailInfo; protected global::System.Web.UI.WebControls.Button btnDetailInfo;
/// <summary>
/// btnPause control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button btnPause;
/// <summary>
/// btnResume control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button btnResume;
/// <summary> /// <summary>
/// secReplication control. /// secReplication control.
/// </summary> /// </summary>
@ -427,49 +463,319 @@ namespace WebsitePanel.Portal.VPS2012 {
protected global::System.Web.UI.WebControls.Panel DetailsPanel; protected global::System.Web.UI.WebControls.Panel DetailsPanel;
/// <summary> /// <summary>
/// locRenameSnapshot control. /// locDetails control.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Auto-generated field. /// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file. /// To modify move field declaration from designer file to code-behind file.
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.Localize locRenameSnapshot; protected global::System.Web.UI.WebControls.Localize locDetails;
/// <summary> /// <summary>
/// txtSnapshotName control. /// locDetailsState control.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Auto-generated field. /// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file. /// To modify move field declaration from designer file to code-behind file.
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtSnapshotName; protected global::System.Web.UI.WebControls.Localize locDetailsState;
/// <summary> /// <summary>
/// SnapshotNameValidator control. /// labDetailsState control.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Auto-generated field. /// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file. /// To modify move field declaration from designer file to code-behind file.
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.RequiredFieldValidator SnapshotNameValidator; protected global::System.Web.UI.WebControls.Label labDetailsState;
/// <summary> /// <summary>
/// btnRenameSnapshot control. /// locDetailsMode control.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Auto-generated field. /// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file. /// To modify move field declaration from designer file to code-behind file.
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.Button btnRenameSnapshot; protected global::System.Web.UI.WebControls.Localize locDetailsMode;
/// <summary> /// <summary>
/// btnCancelRename control. /// labDetailsMode control.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Auto-generated field. /// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file. /// To modify move field declaration from designer file to code-behind file.
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.Button btnCancelRename; protected global::System.Web.UI.WebControls.Label labDetailsMode;
/// <summary>
/// locDetailsPrimary control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locDetailsPrimary;
/// <summary>
/// labDetailsPrimary control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labDetailsPrimary;
/// <summary>
/// locDetailsReplica control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locDetailsReplica;
/// <summary>
/// labDetailsReplica control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labDetailsReplica;
/// <summary>
/// locDetailsHealth control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locDetailsHealth;
/// <summary>
/// labDetailsHealth control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labDetailsHealth;
/// <summary>
/// labDetailsHealthDetails control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labDetailsHealthDetails;
/// <summary>
/// StatisticCollapsiblePanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.CollapsiblePanel StatisticCollapsiblePanel;
/// <summary>
/// StatisticPanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Panel StatisticPanel;
/// <summary>
/// locFromTime control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locFromTime;
/// <summary>
/// labFromTime control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labFromTime;
/// <summary>
/// locToTime control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locToTime;
/// <summary>
/// labToTime control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labToTime;
/// <summary>
/// locAverageSize control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locAverageSize;
/// <summary>
/// labAverageSize control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labAverageSize;
/// <summary>
/// locMaximumSize control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locMaximumSize;
/// <summary>
/// labMaximumSize control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labMaximumSize;
/// <summary>
/// locAverageLatency control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locAverageLatency;
/// <summary>
/// labAverageLatency control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labAverageLatency;
/// <summary>
/// locErrorsEncountered control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locErrorsEncountered;
/// <summary>
/// labErrorsEncountered control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labErrorsEncountered;
/// <summary>
/// locSuccessfulReplicationCycles control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locSuccessfulReplicationCycles;
/// <summary>
/// labSuccessfulReplicationCycles control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labSuccessfulReplicationCycles;
/// <summary>
/// PendingReplicationCollapsiblePanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.CollapsiblePanel PendingReplicationCollapsiblePanel;
/// <summary>
/// PendingReplicationPanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Panel PendingReplicationPanel;
/// <summary>
/// locSizeData control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locSizeData;
/// <summary>
/// labSizeData control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labSizeData;
/// <summary>
/// locLastSyncro control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locLastSyncro;
/// <summary>
/// labLastSyncro control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label labLastSyncro;
/// <summary>
/// btnCancel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button btnCancel;
/// <summary> /// <summary>
/// DetailModal control. /// DetailModal control.