vSphere VMware.Vim Clone_VM 'The operation is not allowed in the current state.'

vSphere VMware.Vim Clone_VM 'The operation is not allowed in the current state.'

我的团队正在开发一个需要在我们的 vSphere 环境中克隆现有模板的应用程序。我们在 C# 应用程序中使用 VMware.Vim 来执行此操作。我们正在替换使用 PowerShell 的现有实施。

下面是抛出错误的代码。我们最终会根据内存使用情况进行负载平衡,但目前我们是随机选择主机。这就是为什么有一些额外的代码来收集所有主机然后选择一个。

当它到达 CloneVM_Task 时,抛出消息 'The operation is not allowed in the current state.' 的异常。这个异常并没有给我太多帮助,我在 vSphere 中找不到任何有用的日志。 vSphere 只是在事件日志中显示 "An error prevented the virtual machine from being cloned"。我们正在使用 6.7 版。我是 VMWare 的新手,所以感谢您的帮助。至少可以说,他们的文件是缺乏的。

public async void CreateVirtualMachineAsync(NewVMRequest newVMRequest)
{
    var appliance = await _applianceService.GetAppliance(newVMRequest.Appliance);

    var vimClient = new VimClientImpl
    {
        IgnoreServerCertificateErrors = true, ServiceUrl = appliance.ServiceUrl
    };
    vimClient.Login(appliance.User, appliance.Password);

    var datacenter = GetDatacenter(vimClient);

    var hostCollection = GetListOfHosts(vimClient, datacenter);

    var randomHost = PickRandomHost(hostCollection);

    var sourceVm = GetSelectedVm(vimClient, newVMRequest);

    if (sourceVm == null)
    {
        _logger.LogDebug($"Could not find virtual machine {newVMRequest.Source} to use for template");
        _logger.LogError($"Could not find virtual machine {newVMRequest.Source} to use for template", null);
        return;
    }

    var selectedStore = ConnectToDataStore(vimClient);

    var cluster = GetCluster(vimClient);

    var mySpec = CreateCloneSpec(selectedStore, randomHost, cluster, sourceVm);

    vimClient.WaitForTask(sourceVm.CloneVM_Task(sourceVm.Parent, newVMRequest.Name, mySpec));

    vimClient.Disconnect();
}

private VirtualMachineCloneSpec CreateCloneSpec(Datastore selectedStore, ManagedObjectReference randomHost, ClusterComputeResource cluster, VirtualMachine sourceVm)
{
    var mySpec =  new VirtualMachineCloneSpec
    {
        Location = new VirtualMachineRelocateSpec
        {
            Datastore = selectedStore.MoRef,
            Transform = VirtualMachineRelocateTransformation.sparse,
            Host = randomHost,
            Pool = cluster.ResourcePool
        },
        Config = new VirtualMachineConfigSpec()
    };

    var networkDevice = new VirtualDevice();
    foreach (var vDevice in sourceVm.Config.Hardware.Device)
    {
        if (vDevice.DeviceInfo.Label.Contains("Network"))
        {
            networkDevice = vDevice;
        }
    }

    var devSpec = new VirtualDeviceConfigSpec
    {
        Device = networkDevice, FileOperation = VirtualDeviceConfigSpecFileOperation.create
    };
    mySpec.Config.DeviceChange = new[] { devSpec };

    return mySpec;
}

private Datacenter GetDatacenter(VimClient vimClient)
{
    var entities = vimClient.FindEntityViews(typeof(Datacenter), null, null, null);
    return (Datacenter)entities.First();
}

private List<ManagedObjectReference> GetListOfHosts(VimClient vimClient, Datacenter datacenter)
{
    var hostCollection = new List<ManagedObjectReference>();
    var hostFolderMoRef = datacenter.HostFolder;
    var hostFolder = (Folder)vimClient.GetView(hostFolderMoRef, null);
    var childEntityMoRefs = hostFolder.ChildEntity;
    foreach (var childEntityMoRef in childEntityMoRefs)
    {
        var thisCluster = (ClusterComputeResource)vimClient.GetView(childEntityMoRef, null);
        var clusterHostMoRefs = thisCluster.Host;
        foreach (var clusterHostMoRef in clusterHostMoRefs)
        {
            var hostSystem = (HostSystem)vimClient.GetView(clusterHostMoRef, null);
            hostCollection.Add(hostSystem.MoRef);
        }
    }

    return hostCollection;
}

private ManagedObjectReference PickRandomHost(List<ManagedObjectReference> hostCollection)
{
    var rand = new Random();
    return hostCollection[rand.Next(0, hostCollection.Count)];
}

private VirtualMachine GetSelectedVm(VimClient vimClient, NewVMRequest newVMRequest)
{
    var filter = new NameValueCollection
    {
        {"name", newVMRequest.Source},
        {"Config.Template", newVMRequest.UseTemplate.ToString().ToLower()}
    };
    var entityViews = vimClient.FindEntityViews(typeof(VMware.Vim.VirtualMachine), null, filter, null);

    if (entityViews.Count == 0)
    {
        return null;
    }
    return (VirtualMachine)vimClient.FindEntityViews(typeof(VMware.Vim.VirtualMachine), null, filter, null).First();
}

private Datastore ConnectToDataStore(VimClient vimClient)
{  
    var myDs = vimClient.FindEntityView(typeof(Datastore), null, null /*dsFilter*/, null);
    return (Datastore)myDs;
}

private ClusterComputeResource GetCluster(VimClient vimClient)
{
    var appClusters = vimClient.FindEntityViews(typeof(ClusterComputeResource), null, null, null);
    return (ClusterComputeResource)appClusters?.FirstOrDefault();
}

在大多数情况下,您的代码看起来不错。我建议更改规范文件并使用尽可能少的信息从现有模板创建克隆。成功后,您可以添加更多详细信息并查看是否出错。

从这个开始,看看它是否能让你继续下去。

private VirtualMachineCloneSpec CreateCloneSpec(Datastore selectedStore, ManagedObjectReference randomHost, ClusterComputeResource cluster, VirtualMachine sourceVm)
{
    var mySpec =  new VirtualMachineCloneSpec
    {
        Location = new VirtualMachineRelocateSpec
        {
            Datastore = selectedStore.MoRef,
            Host = randomHost,
            Pool = cluster.ResourcePool
        },
        PowerOn = false,
        Template = false
    };

    return mySpec;
}

如果以上都通过,则添加 VirtualMachineRelocateTransformation 以根据需要将胖 VM 转换为瘦 VM 和网络连接。