Activate the conversion VPX and get the service IP address without employing the conversion plug-in.

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
This commit is contained in:
Konstantina Chremmou 2019-08-29 11:40:21 +01:00 committed by Mihaela Stoica
parent 6066de3ae2
commit 1a88c3713d
5 changed files with 277 additions and 47 deletions

View File

@ -39,12 +39,12 @@ using System.Text;
using System.Threading;
using System.Windows.Forms;
using XenAdmin.Actions;
using XenAdmin.Actions.Xcm;
using XenAdmin.XCM;
using XenAdmin.Core;
using XenAdmin.Network;
using XenAdmin.Wizards.ConversionWizard;
using XenAPI;
using XenCenterLib;
namespace XenAdmin.Dialogs
@ -62,6 +62,7 @@ namespace XenAdmin.Dialogs
private volatile bool _updating;
private volatile bool _updateRequired;
private VM _conversionVm;
private ActivateConversionVpxAction _activateAction;
private static readonly string[] DetailHeaders =
{
@ -124,8 +125,19 @@ namespace XenAdmin.Dialogs
protected override void OnFormClosing(FormClosingEventArgs e)
{
timerVpx.Stop();
if (_conversionVm != null)
_conversionVm.PropertyChanged -= _conversionVm_PropertyChanged;
if (_activateAction != null)
{
_activateAction.Completed -= ActivateConversionVpxAction_Completed;
_activateAction.Changed -= ActivateConversionVpxAction_Changed;
if (!_activateAction.IsCompleted)
_activateAction.Cancel();
}
base.OnFormClosing(e);
}
@ -138,62 +150,49 @@ namespace XenAdmin.Dialogs
statusLabel.Text = Messages.CONVERSION_INITIALIZING_VPX;
statusLinkLabel.Reset();
ThreadPool.QueueUserWorkItem(obj =>
_activateAction = new ActivateConversionVpxAction(connection);
_activateAction.Completed += ActivateConversionVpxAction_Completed;
_activateAction.Changed += ActivateConversionVpxAction_Changed;
_activateAction.RunAsync();
}
private void ActivateConversionVpxAction_Completed(ActionBase obj)
{
if (!(obj is ActivateConversionVpxAction action))
return;
action.Completed -= ActivateConversionVpxAction_Completed;
action.Changed -= ActivateConversionVpxAction_Changed;
Program.Invoke(this, () =>
{
var master = Helpers.GetMaster(connection);
string serviceIp = null;
try
if (!action.Succeeded)
{
serviceIp = Host.call_plugin(connection.Session, master.opaque_ref, "conversion", "main", null);
}
catch (Exception e)
{
log.Error("Cannot communicate with the conversion plugin.", e);
statusLabel.Image = Images.StaticImages._000_error_h32bit_16;
statusLabel.Text = action.Exception.Message;
statusLinkLabel.Reset(Messages.CONVERSION_TRY_AGAIN, ConnectToVpx);
return;
}
Program.Invoke(this, () =>
{
if (string.IsNullOrEmpty(serviceIp))
{
statusLabel.Image = Images.StaticImages._000_error_h32bit_16;
statusLabel.Text = Messages.CONVERSION_INITIALIZING_VPX_FAILURE;
statusLinkLabel.Reset(Messages.CONVERSION_TRY_AGAIN, ConnectToVpx);
return;
}
var useSsl = Properties.Settings.Default.ConversionClientUseSsl;
_conversionClient = new ConversionClient(connection, action.ServiceIp, useSsl);
var useSsl = Properties.Settings.Default.ConversionClientUseSsl;
_conversionClient = new ConversionClient(connection, serviceIp, useSsl);
RegisterVM(serviceIp);
CheckVersionCompatibility();
});
// if we're reconnecting the conversion VM, we need to clear the old one
if (_conversionVm != null)
_conversionVm.PropertyChanged -= _conversionVm_PropertyChanged;
_conversionVm = action.ConversionVm;
_conversionVm.PropertyChanged += _conversionVm_PropertyChanged;
CheckVersionCompatibility();
});
}
private void RegisterVM(string ipAddress)
private void ActivateConversionVpxAction_Changed(ActionBase obj)
{
// if we're reconnecting the conversion VM, we need to clear the old one
if (_conversionVm != null)
{
_conversionVm.PropertyChanged -= _conversionVm_PropertyChanged;
_conversionVm = null;
}
if (!(obj is ActivateConversionVpxAction action))
return;
var vifs = connection.Cache.VIFs;
foreach (var vif in vifs)
{
if (!vif.IPAddresses().Contains(ipAddress))
continue;
var vm = connection.Resolve(vif.VM);
if (!vm.IsConversionVM())
continue;
_conversionVm = vm;
_conversionVm.PropertyChanged += _conversionVm_PropertyChanged;
break;
}
Program.Invoke(this, () => { statusLabel.Text = action.Description; });
}
private void _conversionVm_PropertyChanged(object sender, PropertyChangedEventArgs e)

View File

@ -0,0 +1,146 @@
/* Copyright (c) Citrix Systems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Linq;
using System.Threading;
using XenAdmin.Network;
using XenAPI;
namespace XenAdmin.Actions.Xcm
{
public class ActivateConversionVpxAction : AsyncAction
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private const int TIMEOUT = 2 * 60 * 1000; //milliseconds
private const int SLEEP = 2000; //milliseconds
public ActivateConversionVpxAction(IXenConnection connection)
: base(connection, "", true)
{
}
public VM ConversionVm { get; private set; }
public string ServiceIp { get; private set; }
protected override void Run()
{
ConversionVm = Connection.Cache.VMs.FirstOrDefault(vm => vm.IsConversionVM());
if (ConversionVm == null)
throw new Exception(Messages.CONVERSION_CANNOT_FIND_VPX);
switch (ConversionVm.power_state)
{
case vm_power_state.Halted:
case vm_power_state.Paused:
case vm_power_state.Suspended:
case vm_power_state.Running:
break;
default:
log.Error($"The conversion VPX {ConversionVm.uuid} is in an unknown power state");
throw new Exception(Messages.CONVERSION_VPX_UNKNOWN_POWER_STATE);
}
try
{
switch (ConversionVm.power_state)
{
case vm_power_state.Halted:
Description = Messages.CONVERSION_VPX_START;
VM.start(Connection.Session, ConversionVm.opaque_ref, false, false);
break;
case vm_power_state.Paused:
Description = Messages.CONVERSION_VPX_UNPAUSE;
VM.unpause(Connection.Session, ConversionVm.opaque_ref);
break;
case vm_power_state.Suspended:
Description = Messages.CONVERSION_VPX_RESUME;
VM.resume(Connection.Session, ConversionVm.opaque_ref, false, false);
break;
}
}
catch (Exception e)
{
if (e is Failure f && f.ErrorDescription.Count > 0 && f.ErrorDescription[0] == Failure.VM_BAD_POWER_STATE)
{
//ignore
}
else
{
log.Error($"Failed to activate conversion VPX {ConversionVm.uuid}", e);
throw new Exception(Messages.CONVERSION_INITIALIZING_VPX_FAILURE);
}
}
Description = Messages.CONVERSION_VPX_OBTAIN_IP;
string ipAddress = null;
var tries = TIMEOUT / SLEEP;
while (tries > 0)
{
if (Cancelling)
throw new CancelledException();
if (Helper.IsNullOrEmptyOpaqueRef(ConversionVm.guest_metrics.opaque_ref))
{
ConversionVm = Connection.Resolve(new XenRef<VM>(ConversionVm.opaque_ref));
}
else
{
var metrics = Connection.Resolve(ConversionVm.guest_metrics);
if (metrics != null)
{
// device 0 is the internal network for the VM; find an external one
var vif = Connection.ResolveAll(ConversionVm.VIFs).FirstOrDefault(v => v.device != "0");
if (vif != null && metrics.networks.TryGetValue($"{vif.device}/ip", out ipAddress))
break;
}
}
Thread.Sleep(SLEEP);
tries--;
}
if (string.IsNullOrEmpty(ipAddress))
{
log.Error($"Cannot obtain an IP address for conversion VPX {ConversionVm.uuid}.");
throw new Exception(Messages.CONVERSION_CANNOT_OBTAIN_VPX_IP);
}
ServiceIp = ipAddress;
}
}
}

View File

@ -8979,6 +8979,24 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot find a Conversion Manager Virtual Appliance..
/// </summary>
public static string CONVERSION_CANNOT_FIND_VPX {
get {
return ResourceManager.GetString("CONVERSION_CANNOT_FIND_VPX", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot obtain an IP address for the Conversion Manager Virtual Appliance..
/// </summary>
public static string CONVERSION_CANNOT_OBTAIN_VPX_IP {
get {
return ResourceManager.GetString("CONVERSION_CANNOT_OBTAIN_VPX_IP", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This action will clear all the completed conversions from the Conversion Manager Virtual Appliance history.
///
@ -9613,6 +9631,51 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to Obtaining an IP address for the Conversion Manager Virtual Appliance....
/// </summary>
public static string CONVERSION_VPX_OBTAIN_IP {
get {
return ResourceManager.GetString("CONVERSION_VPX_OBTAIN_IP", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Resuming the Conversion Manager Virtual Appliance....
/// </summary>
public static string CONVERSION_VPX_RESUME {
get {
return ResourceManager.GetString("CONVERSION_VPX_RESUME", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Starting the Conversion Manager Virtual Appliance....
/// </summary>
public static string CONVERSION_VPX_START {
get {
return ResourceManager.GetString("CONVERSION_VPX_START", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot deduce the power state of the Conversion Manager Virtual Appliance..
/// </summary>
public static string CONVERSION_VPX_UNKNOWN_POWER_STATE {
get {
return ResourceManager.GetString("CONVERSION_VPX_UNKNOWN_POWER_STATE", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Un-pausing the Conversion Manager Virtual Appliance....
/// </summary>
public static string CONVERSION_VPX_UNPAUSE {
get {
return ResourceManager.GetString("CONVERSION_VPX_UNPAUSE", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to New Conversion.
/// </summary>

View File

@ -3256,6 +3256,12 @@ This action cannot be undone. Are you sure you want to continue?</value>
<data name="CONVERSION_CANCEL_FAILURE" xml:space="preserve">
<value>Cannot cancel the conversion. Please see logs for details.</value>
</data>
<data name="CONVERSION_CANNOT_FIND_VPX" xml:space="preserve">
<value>Cannot find a Conversion Manager Virtual Appliance.</value>
</data>
<data name="CONVERSION_CANNOT_OBTAIN_VPX_IP" xml:space="preserve">
<value>Cannot obtain an IP address for the Conversion Manager Virtual Appliance.</value>
</data>
<data name="CONVERSION_CONNECTING_VMWARE" xml:space="preserve">
<value>Connecting to the VMware server...</value>
</data>
@ -3462,6 +3468,21 @@ This action cannot be undone. Are you sure you want to continue?</value>
<data name="CONVERSION_VM_PAGE_TITLE" xml:space="preserve">
<value>Select the VMs to convert</value>
</data>
<data name="CONVERSION_VPX_OBTAIN_IP" xml:space="preserve">
<value>Obtaining an IP address for the Conversion Manager Virtual Appliance...</value>
</data>
<data name="CONVERSION_VPX_RESUME" xml:space="preserve">
<value>Resuming the Conversion Manager Virtual Appliance...</value>
</data>
<data name="CONVERSION_VPX_START" xml:space="preserve">
<value>Starting the Conversion Manager Virtual Appliance...</value>
</data>
<data name="CONVERSION_VPX_UNPAUSE" xml:space="preserve">
<value>Un-pausing the Conversion Manager Virtual Appliance...</value>
</data>
<data name="CONVERSION_VPX_UNKNOWN_POWER_STATE" xml:space="preserve">
<value>Cannot deduce the power state of the Conversion Manager Virtual Appliance.</value>
</data>
<data name="CONVERSION_WIZARD_TEXT" xml:space="preserve">
<value>New Conversion</value>
</data>

View File

@ -156,6 +156,7 @@
<Compile Include="Actions\VM\VMSnapshotCreateAction.cs" />
<Compile Include="Actions\VM\VMStartAction.cs" />
<Compile Include="Actions\WLB\WlbRetrieveVmRecommendationsAction.cs" />
<Compile Include="Actions\XCM\ActivateConversionVpxAction.cs" />
<Compile Include="Actions\ZipStatusReportAction.cs" />
<Compile Include="Alerts\Types\Alert.cs" />
<Compile Include="XCM\ConversionClient.cs" />