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

标签 c# vmware vsphere

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

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

当它到达 CloneVM_Task 时,出现异常,并显示消息“当前状态不允许该操作。”被抛出。该异常并没有给我太多的帮助,而且我在 vSphere 中找不到任何有用的日志。 vSphere 只是在事件日志中显示“错误阻止虚拟机被克隆”。我们使用的是 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 以将厚虚拟机转换为瘦虚拟机并根据需要进行网络连接。

关于c# - vSphere VMware.Vim Clone_VM 'The operation is not allowed in the current state.',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61082308/

相关文章:

ruby-on-rails - virtualbox + vagrant 和 VMWare 融合的区别

powershell - 无法比较创建日期和当前日期

python - 使用 pyvmomi 在 vmware 中获取实例的实际使用(分配)磁盘空间

java - 如何通过 vSphere 客户端 API 获取 VMWare 中的适配器类型列表

c# - 无法理解 C# 泛型

c# - 如何在 C# 中的表单中使用具有不同控件的多个面板

python-3.x - 使用 pyvmomi 从关闭状态启动 VM

python - vSphere 中的虚拟交换机保存在哪里? (通过 pyVmomi)

c# - 使用属性节点解析 Linq To Xml

c# - 我是否了解 ASP.NET MVC 和 Entity Framework 的架构设计?