vSphere VMware.Vim Clone_VM 'Операция не разрешена в текущем состоянии.' - PullRequest
1 голос
/ 07 апреля 2020

Моя команда разрабатывает приложение, которое должно клонировать существующие шаблоны в нашей среде vSphere. Для этого мы используем VMware.Vim в приложении C#. Мы заменяем уже существующую реализацию, которая использует 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();
}

1 Ответ

1 голос
/ 05 мая 2020

По большей части ваш код выглядит хорошо. Я бы предложил изменить файл spe c и использовать наименьшую возможную информацию для создания клона из существующего шаблона. Как только вы добьетесь успеха, вы можете добавить больше деталей и посмотреть, будут ли эти ошибки.

Начните с этого и посмотрите, поможет ли это вам.

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, чтобы преобразовать вашу толстую виртуальную машину в тонкую виртуальную машину и сетевые соединения, если это необходимо.

...