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

This commit is contained in:
Alexander Trofimov 2015-04-17 22:40:39 +03:00
parent 019ad51eae
commit 12d026e8b0
9 changed files with 910 additions and 4 deletions

View file

@ -115,6 +115,8 @@
// Replication // Replication
public const string SET_REPLICA_SERVER_ERROR = "SET_REPLICA_SERVER_ERROR"; public const string SET_REPLICA_SERVER_ERROR = "SET_REPLICA_SERVER_ERROR";
public const string SET_NO_REPLICA_SERVER_ERROR = "SET_NO_REPLICA_SERVER_ERROR";
public const string SET_SET_REPLICATION_ERROR = "SET_SET_REPLICATION_ERROR";
public const string HOST_NAMER_IS_ALREADY_USED = "HOST_NAMER_IS_ALREADY_USED"; public const string HOST_NAMER_IS_ALREADY_USED = "HOST_NAMER_IS_ALREADY_USED";

View file

@ -3751,6 +3751,50 @@ namespace WebsitePanel.EnterpriseServer
return vs.IsReplicaServer(remoteServer); return vs.IsReplicaServer(remoteServer);
} }
public static VmReplication GetReplication(int itemId)
{
VirtualMachine vm = GetVirtualMachineByItemId(itemId);
VirtualizationServer2012 vs = GetVirtualizationProxy(vm.ServiceId);
return vs.GetReplication(vm.VirtualMachineId);
}
public static ResultObject SetVmReplication(int itemId, string replicaServer, VmReplication replication)
{
ResultObject result = new ResultObject();
try
{
VirtualMachine vm = GetVirtualMachineByItemId(itemId);
VirtualizationServer2012 vs = GetVirtualizationProxy(vm.ServiceId);
// Get replica server name
StringDictionary vsSesstings = ServerController.GetServiceSettings(vm.ServiceId);
string replicaServiceId = vsSesstings["ReplicaServerId"];
if (string.IsNullOrEmpty(replicaServiceId))
{
result.ErrorCodes.Add(VirtualizationErrorCodes.SET_NO_REPLICA_SERVER_ERROR);
return result;
}
//StringDictionary vsSesstings = ServerController.GetServiceSettings(vm.replicaServiceId);
//string replicaServiceId = vsSesstings["ReplicaServerId"];
//if (string.IsNullOrEmpty(replicaServiceId))
//{
// result.ErrorCodes.Add(VirtualizationErrorCodes.SET_NO_REPLICA_SERVER_ERROR);
// return result;
//}
vs.SetVmReplication(vm.VirtualMachineId, replicaServer, replication);
result.IsSuccess = true;
}
catch (Exception ex)
{
result.AddError(VirtualizationErrorCodes.SET_SET_REPLICATION_ERROR, ex);
}
return result;
}
#endregion #endregion
} }
} }

View file

@ -658,6 +658,7 @@
<Control key="vps_dvd" src="WebsitePanel/VPS2012/VpsDetailsDvd.ascx" title="VpsDetailsDvd" type="View" /> <Control key="vps_dvd" src="WebsitePanel/VPS2012/VpsDetailsDvd.ascx" title="VpsDetailsDvd" type="View" />
<Control key="vps_insert_dvd" src="WebsitePanel/VPS2012/VpsDetailsInsertDvd.ascx" title="VpsDetailsInsertDvd" type="View" /> <Control key="vps_insert_dvd" src="WebsitePanel/VPS2012/VpsDetailsInsertDvd.ascx" title="VpsDetailsInsertDvd" type="View" />
<Control key="vps_snapshots" src="WebsitePanel/VPS2012/VpsDetailsSnapshots.ascx" title="VpsDetailsSnapshots" type="View" /> <Control key="vps_snapshots" src="WebsitePanel/VPS2012/VpsDetailsSnapshots.ascx" title="VpsDetailsSnapshots" type="View" />
<Control key="vps_replication" src="WebsitePanel/VPS2012/VpsDetailsReplications.ascx" title="VpsDetailReplications" type="View" />
<Control key="vps_network" src="WebsitePanel/VPS2012/VpsDetailsNetwork.ascx" title="VpsDetailsNetwork" type="View" /> <Control key="vps_network" src="WebsitePanel/VPS2012/VpsDetailsNetwork.ascx" title="VpsDetailsNetwork" type="View" />
<Control key="vps_add_external_ip" src="WebsitePanel/VPS2012/VpsDetailsAddExternalAddress.ascx" title="VpsDetailsAddExternalAddress" type="View" /> <Control key="vps_add_external_ip" src="WebsitePanel/VPS2012/VpsDetailsAddExternalAddress.ascx" title="VpsDetailsAddExternalAddress" type="View" />
<Control key="vps_add_private_ip" src="WebsitePanel/VPS2012/VpsDetailsAddPrivateAddress.ascx" title="VpsDetailsAddPrivateAddress" type="View" /> <Control key="vps_add_private_ip" src="WebsitePanel/VPS2012/VpsDetailsAddPrivateAddress.ascx" title="VpsDetailsAddPrivateAddress" type="View" />

View file

@ -237,7 +237,7 @@ namespace WebsitePanel.Portal.ProviderControls
continue; continue;
var currentServiceSettings = ConvertArrayToDictionary(ES.Services.Servers.GetServiceSettings(serviceId)); var currentServiceSettings = ConvertArrayToDictionary(ES.Services.Servers.GetServiceSettings(serviceId));
if (currentServiceSettings["ReplicaMode"] == ReplicaMode.IsReplicaServer.ToString()) if (currentServiceSettings["ReplicaMode"] != ReplicaMode.IsReplicaServer.ToString())
continue; continue;
var exists = false; var exists = false;
@ -294,11 +294,10 @@ namespace WebsitePanel.Portal.ProviderControls
ManagePreferredNameServerRow.Visible = ManageNicConfigRow.Visible && (ddlManageNicConfig.SelectedIndex == 0); ManagePreferredNameServerRow.Visible = ManageNicConfigRow.Visible && (ddlManageNicConfig.SelectedIndex == 0);
// Replica // Replica
IsReplicaServerRow.Visible = IsReplicaServer;
EnableReplicaRow.Visible = EnabledReplica; EnableReplicaRow.Visible = EnabledReplica;
ddlCertThumbnail.Visible = !IsRemoteServer;
txtCertThumbnail.Visible = CertificateThumbnailValidator.Visible = IsRemoteServer;
IsReplicaServerRow.Visible = IsReplicaServer; IsReplicaServerRow.Visible = IsReplicaServer;
ddlCertThumbnail.Visible = CertificateDdlThumbnailValidator.Visible = !IsRemoteServer;
txtCertThumbnail.Visible = CertificateThumbnailValidator.Visible = IsRemoteServer;
ReplicaPathErrorTr.Visible = ReplicaErrorTr.Visible = false; ReplicaPathErrorTr.Visible = ReplicaErrorTr.Visible = false;
if (IsReplicaServer) BindCertificates(); if (IsReplicaServer) BindCertificates();
if (EnabledReplica) BindReplicaServices(); if (EnabledReplica) BindReplicaServices();

View file

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="btnApply.OnClientClick" xml:space="preserve">
<value>if(this.disabled) return false;if(!confirm('Do you want to apply selected snapshot to VPS?')) return false;ShowProgressDialog('Applying snapshot...');</value>
</data>
<data name="btnDelete.OnClientClick" xml:space="preserve">
<value>if(this.disabled) return false;if(!confirm('Do you want to completely delete selected snapshot?')) return false;ShowProgressDialog('Deleting snapshot...');</value>
</data>
<data name="btnDeleteSubtree.OnClientClick" xml:space="preserve">
<value>if(!confirm('Do you want to completely delete selected snapshot and all its sub-tree?')) return false;ShowProgressDialog('Deleting snapshot sub-tree...');</value>
</data>
<data name="btnRenameSnapshot.OnClientClick" xml:space="preserve">
<value>ShowProgressDialog('Renaming snapshot...', 'RenameSnapshotModal');</value>
</data>
<data name="btnTakeSnapshot.OnClientClick" xml:space="preserve">
<value>ShowProgressDialog('Taking snapshot...');</value>
</data>
<data name="Now.Text" xml:space="preserve">
<value>Now</value>
</data>
<data name="locNoSnapshots.Text" xml:space="preserve">
<value>This virtual server has no snapshots.</value>
</data>
<data name="btnApply.Text" xml:space="preserve">
<value>Apply</value>
</data>
<data name="btnCancelRename.Text" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="btnDelete.Text" xml:space="preserve">
<value>Delete</value>
</data>
<data name="btnDeleteSubtree.Text" xml:space="preserve">
<value>Delete Subtree</value>
</data>
<data name="btnRename.Text" xml:space="preserve">
<value>Rename</value>
</data>
<data name="btnRenameSnapshot.Text" xml:space="preserve">
<value>Rename</value>
</data>
<data name="FormComments.Text" xml:space="preserve">
<value>&lt;p&gt;To take a &lt;b&gt;snapshot&lt;/b&gt; is much like to take a picture of current VPS state: its configuration, memory and hard disk.&lt;/p&gt;&lt;p&gt;Snapshots maybe used as backup/restore points when installing new software or using VPS for development or testing purposes. If something has gone wrong there is an ability to roll-back and &lt;b&gt;"Apply"&lt;/b&gt; a snapshot with good configuration.&lt;/p&gt;&lt;p&gt;&lt;b&gt;"Rename"&lt;/b&gt; button allows renaming snapshot and giving it some informative name, for example "Before applying service pack".&lt;/p&gt;</value>
</data>
<data name="locCreated.Text" xml:space="preserve">
<value>Created:</value>
</data>
<data name="locQuota.Text" xml:space="preserve">
<value>Number of Snapshots:</value>
</data>
<data name="locRenameSnapshot.Text" xml:space="preserve">
<value>Rename Snapshot</value>
</data>
<data name="locTitle.Text" xml:space="preserve">
<value>Snapshots</value>
</data>
</root>

View file

@ -0,0 +1,146 @@
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VpsDetailsReplications.ascx.cs" Inherits="WebsitePanel.Portal.VPS2012.VpsDetailsReplications" %>
<%@ Register Src="../UserControls/SimpleMessageBox.ascx" TagName="SimpleMessageBox" TagPrefix="wsp" %>
<%@ Register Src="UserControls/ServerTabs.ascx" TagName="ServerTabs" TagPrefix="wsp" %>
<%@ Register Src="UserControls/Menu.ascx" TagName="Menu" TagPrefix="wsp" %>
<%@ Register Src="UserControls/Breadcrumb.ascx" TagName="Breadcrumb" TagPrefix="wsp" %>
<%@ Register Src="UserControls/FormTitle.ascx" TagName="FormTitle" TagPrefix="wsp" %>
<%@ Register Src="../UserControls/QuotaViewer.ascx" TagName="QuotaViewer" TagPrefix="wsp" %>
<%@ Register Src="../UserControls/EnableAsyncTasksSupport.ascx" TagName="EnableAsyncTasksSupport" TagPrefix="wsp" %>
<wsp:EnableAsyncTasksSupport id="asyncTasks" runat="server"/>
<div id="VpsContainer">
<div class="Module">
<div class="Header">
<wsp:Breadcrumb id="breadcrumb" runat="server" />
</div>
<div class="Left">
<wsp:Menu id="menu" runat="server" SelectedItem="" />
</div>
<div class="Content">
<div class="Center">
<div class="Title">
<asp:Image ID="imgIcon" SkinID="Snapshot48" runat="server" />
<wsp:FormTitle ID="locTitle" runat="server" meta:resourcekey="locTitle" Text="Snapshots" />
</div>
<div class="FormBody">
<wsp:ServerTabs id="tabs" runat="server" SelectedTab="vps_replications" />
<wsp:SimpleMessageBox id="messageBox" runat="server" />
<table style="width:100%;">
<tr>
<td valign="top">
<div class="FormButtonsBarClean">
<asp:Button ID="btnTakeSnapshot" runat="server" meta:resourcekey="btnTakeSnapshot"
Text="Take Snapshot" CssClass="Button1" onclick="btnTakeSnapshot_Click" />
</div>
<br />
<asp:TreeView ID="SnapshotsTree" runat="server"
onselectednodechanged="SnapshotsTree_SelectedNodeChanged" ShowLines="True">
<SelectedNodeStyle CssClass="SelectedTreeNode" />
<Nodes>
</Nodes>
<NodeStyle CssClass="TreeNode" />
</asp:TreeView>
<div id="NoSnapshotsPanel" runat="server" style="padding: 5px;">
<asp:Localize ID="locNoSnapshots" runat="server" meta:resourcekey="locNoSnapshots" Text="No snapshots"></asp:Localize>
</div>
<br />
<br />
<asp:Localize ID="locQuota" runat="server" meta:resourcekey="locQuota"
Text="Number of Snapshots:"></asp:Localize>
&nbsp;&nbsp;&nbsp;
<wsp:QuotaViewer ID="snapshotsQuota" runat="server" QuotaTypeId="2" />
</td>
<td valign="top" id="SnapshotDetailsPanel" runat="server">
<asp:Image ID="imgThumbnail" runat="server" Width="160" Height="120" />
<p>
<asp:Localize ID="locCreated" runat="server" meta:resourcekey="locCreated"
Text="Created:"></asp:Localize>
<asp:Literal ID="litCreated" runat="server"></asp:Literal>
</p>
<ul class="ActionButtons">
<li>
<asp:LinkButton ID="btnApply" runat="server" CausesValidation="false" CssClass="ActionButtonApplySnapshot"
meta:resourcekey="btnApply" Text="Apply" onclick="btnApply_Click"></asp:LinkButton>
</li>
<li>
<asp:LinkButton ID="btnRename" runat="server" CausesValidation="false" CssClass="ActionButtonRename"
meta:resourcekey="btnRename" Text="Rename"></asp:LinkButton>
</li>
<li>
<asp:LinkButton ID="btnDelete" runat="server" CausesValidation="false" CssClass="ActionButtonDeleteSnapshot"
meta:resourcekey="btnDelete" Text="Delete" onclick="btnDelete_Click"></asp:LinkButton>
</li>
<li>
<asp:LinkButton ID="btnDeleteSubtree" runat="server" CausesValidation="false" CssClass="ActionButtonDeleteSnapshotTree"
meta:resourcekey="btnDeleteSubtree" Text="Delete subtree"
onclick="btnDeleteSubtree_Click"></asp:LinkButton>
</li>
</ul>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<asp:Panel ID="RenamePanel" runat="server" CssClass="Popup" style="display:none;">
<table class="Popup-Header" cellpadding="0" cellspacing="0">
<tr>
<td class="Popup-HeaderLeft"></td>
<td class="Popup-HeaderTitle">
<asp:Localize ID="locRenameSnapshot" runat="server" Text="Rename snapshot"
meta:resourcekey="locRenameSnapshot"></asp:Localize>
</td>
<td class="Popup-HeaderRight"></td>
</tr>
</table>
<div class="Popup-Content">
<div class="Popup-Body">
<br />
<table cellspacing="10">
<tr>
<td>
<asp:TextBox ID="txtSnapshotName" runat="server" CssClass="NormalTextBox" Width="300"></asp:TextBox>
<asp:RequiredFieldValidator ID="SnapshotNameValidator" runat="server" Text="*" Display="Dynamic"
ControlToValidate="txtSnapshotName" meta:resourcekey="SnapshotNameValidator" SetFocusOnError="true"
ValidationGroup="RenameSnapshot">*</asp:RequiredFieldValidator>
</td>
</tr>
</table>
<br />
</div>
<div class="FormFooter">
<asp:Button ID="btnRenameSnapshot" runat="server" CssClass="Button1"
meta:resourcekey="btnRenameSnapshot" Text="Rename" onclick="btnRenameSnapshot_Click"
ValidationGroup="RenameSnapshot" />
<asp:Button ID="btnCancelRename" runat="server" CssClass="Button1"
meta:resourcekey="btnCancelRename" Text="Cancel" CausesValidation="false" />
</div>
</div>
</asp:Panel>
<ajaxToolkit:ModalPopupExtender ID="RenameSnapshotModal" runat="server" BehaviorID="RenameSnapshotModal"
TargetControlID="btnRename" PopupControlID="RenamePanel"
BackgroundCssClass="modalBackground" DropShadow="false" CancelControlID="btnCancelRename" />

View file

@ -0,0 +1,262 @@
// Copyright (c) 2015, Outercurve Foundation.
// 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.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// 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;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebsitePanel.Providers.Common;
using WebsitePanel.Providers.Virtualization;
namespace WebsitePanel.Portal.VPS2012
{
public partial class VpsDetailsReplications : WebsitePanelModuleBase
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindSnapshotsTree();
}
}
private void BindSnapshotsTree()
{
VirtualMachineSnapshot[] snapshots = ES.Services.VPS2012.GetVirtualMachineSnapshots(PanelRequest.ItemID);
// clear tree
SnapshotsTree.Nodes.Clear();
// fill tree by root nodes
AddChildNodes(SnapshotsTree.Nodes, null, snapshots);
// select first node
if (SnapshotsTree.Nodes.Count > 0)
{
SnapshotsTree.Nodes[0].Selected = true;
}
// refresh
BindSelectedNode();
// quotas
VirtualMachine vm = ES.Services.VPS2012.GetVirtualMachineItem(PanelRequest.ItemID);
snapshotsQuota.QuotaUsedValue = snapshots.Length;
snapshotsQuota.QuotaValue = vm.SnapshotsNumber;
btnTakeSnapshot.Enabled = snapshots.Length < vm.SnapshotsNumber;
}
private void BindSelectedNode()
{
TreeNode node = SnapshotsTree.SelectedNode;
btnApply.Enabled =
btnRename.Enabled =
btnDelete.Enabled =
btnDeleteSubtree.Enabled =
SnapshotDetailsPanel.Visible = (node != null);
NoSnapshotsPanel.Visible = (SnapshotsTree.Nodes.Count == 0);
if (node != null)
{
// set name
txtSnapshotName.Text = node.Text;
// load snapshot details
VirtualMachineSnapshot snapshot = ES.Services.VPS2012.GetSnapshot(PanelRequest.ItemID, node.Value);
if (snapshot != null)
litCreated.Text = snapshot.Created.ToString();
// set image
imgThumbnail.ImageUrl =
string.Format("~/DesktopModules/WebsitePanel/VPS2012/VirtualMachineSnapshotImage.ashx?ItemID={0}&SnapshotID={1}&rnd={2}",
PanelRequest.ItemID, HttpUtility.UrlEncode(node.Value), DateTime.Now.Ticks);
}
}
private void AddChildNodes(TreeNodeCollection parent, string parentId, VirtualMachineSnapshot[] snapshots)
{
foreach (VirtualMachineSnapshot snapshot in snapshots)
{
if (snapshot.ParentId == parentId)
{
// add node
TreeNode node = new TreeNode(snapshot.Name, snapshot.Id);
node.Expanded = true;
node.ImageUrl = PortalUtils.GetThemedImage("VPS/snapshot.png");
parent.Add(node);
// check if the current
if (snapshot.IsCurrent)
{
TreeNode nowNode = new TreeNode(GetLocalizedString("Now.Text"), "");
nowNode.ImageUrl = PortalUtils.GetThemedImage("VPS/start2.png");
nowNode.SelectAction = TreeNodeSelectAction.None;
node.ChildNodes.Add(nowNode);
}
// fill children
AddChildNodes(node.ChildNodes, snapshot.Id, snapshots);
}
}
}
protected void btnTakeSnapshot_Click(object sender, EventArgs e)
{
try
{
ResultObject res = ES.Services.VPS2012.CreateSnapshot(PanelRequest.ItemID);
if (res.IsSuccess)
{
// bind tree
BindSnapshotsTree();
return;
}
else
{
// show error
messageBox.ShowMessage(res, "VPS_ERROR_TAKE_SNAPSHOT", "VPS");
}
}
catch (Exception ex)
{
messageBox.ShowErrorMessage("VPS_ERROR_TAKE_SNAPSHOT", ex);
}
}
protected void btnApply_Click(object sender, EventArgs e)
{
try
{
ResultObject res = ES.Services.VPS2012.ApplySnapshot(PanelRequest.ItemID, GetSelectedSnapshot());
if (res.IsSuccess)
{
// bind tree
BindSnapshotsTree();
return;
}
else
{
// show error
messageBox.ShowMessage(res, "VPS_ERROR_APPLY_SNAPSHOT", "VPS");
}
}
catch (Exception ex)
{
messageBox.ShowErrorMessage("VPS_ERROR_APPLY_SNAPSHOT", ex);
}
}
protected void btnRenameSnapshot_Click(object sender, EventArgs e)
{
try
{
string newName = txtSnapshotName.Text.Trim();
ResultObject res = ES.Services.VPS2012.RenameSnapshot(PanelRequest.ItemID, GetSelectedSnapshot(), newName);
if (res.IsSuccess)
{
// bind tree
SnapshotsTree.SelectedNode.Text = newName;
return;
}
else
{
// show error
messageBox.ShowMessage(res, "VPS_ERROR_RENAME_SNAPSHOT", "VPS");
}
}
catch (Exception ex)
{
messageBox.ShowErrorMessage("VPS_ERROR_RENAME_SNAPSHOT", ex);
}
}
protected void btnDelete_Click(object sender, EventArgs e)
{
try
{
ResultObject res = ES.Services.VPS2012.DeleteSnapshot(PanelRequest.ItemID, GetSelectedSnapshot());
if (res.IsSuccess)
{
// bind tree
BindSnapshotsTree();
return;
}
else
{
// show error
messageBox.ShowMessage(res, "VPS_ERROR_DELETE_SNAPSHOT", "VPS");
}
}
catch (Exception ex)
{
messageBox.ShowErrorMessage("VPS_ERROR_DELETE_SNAPSHOT", ex);
}
}
protected void btnDeleteSubtree_Click(object sender, EventArgs e)
{
try
{
ResultObject res = ES.Services.VPS2012.DeleteSnapshotSubtree(PanelRequest.ItemID, GetSelectedSnapshot());
if (res.IsSuccess)
{
// bind tree
BindSnapshotsTree();
return;
}
else
{
// show error
messageBox.ShowMessage(res, "VPS_ERROR_DELETE_SNAPSHOT_SUBTREE", "VPS");
}
}
catch (Exception ex)
{
messageBox.ShowErrorMessage("VPS_ERROR_DELETE_SNAPSHOT_SUBTREE", ex);
}
}
private string GetSelectedSnapshot()
{
return SnapshotsTree.SelectedNode.Value;
}
protected void SnapshotsTree_SelectedNodeChanged(object sender, EventArgs e)
{
BindSelectedNode();
}
}
}

View file

@ -0,0 +1,267 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WebsitePanel.Portal.VPS2012 {
public partial class VpsDetailsReplications {
/// <summary>
/// asyncTasks control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.EnableAsyncTasksSupport asyncTasks;
/// <summary>
/// breadcrumb control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.VPS2012.UserControls.Breadcrumb breadcrumb;
/// <summary>
/// menu control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.VPS2012.UserControls.Menu menu;
/// <summary>
/// imgIcon 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.Image imgIcon;
/// <summary>
/// locTitle control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.VPS2012.UserControls.FormTitle locTitle;
/// <summary>
/// tabs control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.VPS2012.UserControls.ServerTabs tabs;
/// <summary>
/// messageBox control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.UserControls.SimpleMessageBox messageBox;
/// <summary>
/// btnTakeSnapshot 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 btnTakeSnapshot;
/// <summary>
/// SnapshotsTree 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.TreeView SnapshotsTree;
/// <summary>
/// NoSnapshotsPanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlGenericControl NoSnapshotsPanel;
/// <summary>
/// locNoSnapshots 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 locNoSnapshots;
/// <summary>
/// locQuota 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 locQuota;
/// <summary>
/// snapshotsQuota control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::WebsitePanel.Portal.QuotaViewer snapshotsQuota;
/// <summary>
/// SnapshotDetailsPanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlTableCell SnapshotDetailsPanel;
/// <summary>
/// imgThumbnail 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.Image imgThumbnail;
/// <summary>
/// locCreated 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 locCreated;
/// <summary>
/// litCreated 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.Literal litCreated;
/// <summary>
/// btnApply 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.LinkButton btnApply;
/// <summary>
/// btnRename 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.LinkButton btnRename;
/// <summary>
/// btnDelete 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.LinkButton btnDelete;
/// <summary>
/// btnDeleteSubtree 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.LinkButton btnDeleteSubtree;
/// <summary>
/// RenamePanel 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 RenamePanel;
/// <summary>
/// locRenameSnapshot 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 locRenameSnapshot;
/// <summary>
/// txtSnapshotName 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.TextBox txtSnapshotName;
/// <summary>
/// SnapshotNameValidator 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.RequiredFieldValidator SnapshotNameValidator;
/// <summary>
/// btnRenameSnapshot 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 btnRenameSnapshot;
/// <summary>
/// btnCancelRename 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 btnCancelRename;
/// <summary>
/// RenameSnapshotModal control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::AjaxControlToolkit.ModalPopupExtender RenameSnapshotModal;
}
}

View file

@ -512,6 +512,13 @@
<Compile Include="VPS2012\VpsDetailsPermissions.ascx.designer.cs"> <Compile Include="VPS2012\VpsDetailsPermissions.ascx.designer.cs">
<DependentUpon>VpsDetailsPermissions.ascx</DependentUpon> <DependentUpon>VpsDetailsPermissions.ascx</DependentUpon>
</Compile> </Compile>
<Compile Include="VPS2012\VpsDetailsReplications.ascx.cs">
<DependentUpon>VpsDetailsReplications.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="VPS2012\VpsDetailsReplications.ascx.designer.cs">
<DependentUpon>VpsDetailsReplications.ascx</DependentUpon>
</Compile>
<Compile Include="VPS2012\VpsDetailsSnapshots.ascx.cs"> <Compile Include="VPS2012\VpsDetailsSnapshots.ascx.cs">
<DependentUpon>VpsDetailsSnapshots.ascx</DependentUpon> <DependentUpon>VpsDetailsSnapshots.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType> <SubType>ASPXCodeBehind</SubType>
@ -4849,6 +4856,7 @@
<Content Include="VPS2012\VpsDetailsInsertDvd.ascx" /> <Content Include="VPS2012\VpsDetailsInsertDvd.ascx" />
<Content Include="VPS2012\VpsDetailsNetwork.ascx" /> <Content Include="VPS2012\VpsDetailsNetwork.ascx" />
<Content Include="VPS2012\VpsDetailsPermissions.ascx" /> <Content Include="VPS2012\VpsDetailsPermissions.ascx" />
<Content Include="VPS2012\VpsDetailsReplications.ascx" />
<Content Include="VPS2012\VpsDetailsSnapshots.ascx" /> <Content Include="VPS2012\VpsDetailsSnapshots.ascx" />
<Content Include="VPS2012\VpsDetailsTools.ascx" /> <Content Include="VPS2012\VpsDetailsTools.ascx" />
<Content Include="VPS2012\VpsMoveServer.ascx" /> <Content Include="VPS2012\VpsMoveServer.ascx" />
@ -5220,6 +5228,9 @@
<Content Include="VPS2012\UserControls\App_LocalResources\ServerTabs.ascx.resx"> <Content Include="VPS2012\UserControls\App_LocalResources\ServerTabs.ascx.resx">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Content> </Content>
<Content Include="VPS2012\App_LocalResources\VpsDetailsReplications.ascx.resx">
<SubType>Designer</SubType>
</Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="App_LocalResources\BandwidthReport.ascx.resx"> <Content Include="App_LocalResources\BandwidthReport.ascx.resx">