예제 #1
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
 public static Task <Either <PowershellFailure, Unit> > SetVMCheckpointType(TypedPsObject <VirtualMachineInfo> vmInfo, CheckpointType checkpointType, IPowershellEngine engine)
 {
     return(engine.RunAsync(new PsCommandBuilder()
                            .AddCommand("Set-VM")
                            .AddParameter("VM", vmInfo.PsObject)
                            .AddParameter("CheckpointType", checkpointType)));
 }
예제 #2
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static Task <Either <PowershellFailure, Unit> > DetachUndefinedDvdDrives(
            IPowershellEngine engine,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            Seq <VMDriveStorageSettings> plannedStorageSettings,
            Func <string, Task> reportProgress)

        {
            var controllersAndLocations = plannedStorageSettings.Where(x => x.Type == VirtualMachineDriveType.DVD)
                                          .Map(x => new { x.ControllerNumber, x.ControllerLocation })
                                          .GroupBy(x => x.ControllerNumber)
                                          .ToImmutableDictionary(x => x.Key, x => x.Map(y => y.ControllerLocation).ToImmutableArray());


            return(FindAndApply(vmInfo,
                                i => i.DVDDrives,
                                hd =>
            {
                //ignore cloud init drive, will be handled later
                if (hd.ControllerLocation == 63 && hd.ControllerNumber == 0)
                {
                    return false;
                }

                var detach = !controllersAndLocations.ContainsKey(hd.ControllerNumber) ||
                             !controllersAndLocations[hd.ControllerNumber].Contains(hd.ControllerLocation);

                return detach;
            },
                                i => engine.RunAsync(PsCommandBuilder.Create().AddCommand("Remove-VMDvdDrive")
                                                     .AddParameter("VMDvdDrive", i.PsObject))).Map(x => x.Lefts().HeadOrNone())
                   .MatchAsync(
                       Some: l => LeftAsync <PowershellFailure, Unit>(l).ToEither(),
                       None: () => RightAsync <PowershellFailure, Unit>(Unit.Default)
                       .ToEither()));
        }
예제 #3
0
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > CloudInit(
            TypedPsObject <VirtualMachineInfo> vmInfo,
            string vmConfigPath,
            string storageIdentifier,
            string hostname,
            JObject userdata,
            IPowershellEngine engine,
            Func <string, Task <Unit> > reportProgress
            )
        {
            var vmPath             = Path.Combine(vmConfigPath, storageIdentifier);
            var configDriveIsoPath = Path.Combine(vmPath, "configdrive.iso");

            await reportProgress("Updating configdrive disk").ConfigureAwait(false);

            var res = await CreateConfigDriveDirectory(vmPath)
                      .Bind(_ => EjectConfigDriveDisk(configDriveIsoPath, vmInfo, engine))
                      .ToAsync()
                      .IfRightAsync(
                info =>
            {
                GenerateConfigDriveDisk(configDriveIsoPath, hostname, userdata);
                return(InsertConfigDriveDisk(configDriveIsoPath, info, engine));
            }).ConfigureAwait(false);

            return(res.Return(vmInfo));
        }
예제 #4
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        private static Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > InsertConfigDriveDisk(
            string configDriveIsoPath,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            IPowershellEngine engine)
        {
            return
                (from dvdDrive in GetOrCreateInfoAsync(vmInfo,
                                                       l => l.DVDDrives,
                                                       drive => drive.ControllerLocation == 63 && drive.ControllerNumber == 0,
                                                       () => engine.GetObjectsAsync <DvdDriveInfo>(
                                                           PsCommandBuilder.Create().AddCommand("Add-VMDvdDrive")
                                                           .AddParameter("VM", vmInfo.PsObject)
                                                           .AddParameter("ControllerNumber", 0)
                                                           .AddParameter("ControllerLocation", 63)
                                                           .AddParameter("PassThru"))
                                                       )

                 from _ in engine.RunAsync(PsCommandBuilder.Create()

                                           .AddCommand("Set-VMDvdDrive")
                                           .AddParameter("VMDvdDrive", dvdDrive.PsObject)
                                           .AddParameter("Path", configDriveIsoPath))

                 from vmInfoRecreated in vmInfo.RecreateOrReload(engine)
                 select vmInfoRecreated);
        }
예제 #5
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > CloudInit(
            TypedPsObject <VirtualMachineInfo> vmInfo,
            string vmConfigPath,
            VirtualMachineProvisioningConfig provisioningConfig,
            IPowershellEngine engine,
            Func <string, Task <Unit> > reportProgress
            )
        {
            var remove = await RemoveConfigDriveDisk(vmInfo, engine).BindAsync(u => vmInfo.RecreateOrReload(engine)).ConfigureAwait(false);


            if (provisioningConfig.Method == ProvisioningMethod.None || remove.IsLeft)
            {
                return(remove);
            }


            var configDriveIsoPath = Path.Combine(vmConfigPath, "configdrive.iso");

            await reportProgress("Updating configdrive disk").ConfigureAwait(false);

            await from _ in CreateConfigDriveDirectory(vmConfigPath).AsTask()
            select _;

            GenerateConfigDriveDisk(configDriveIsoPath, provisioningConfig.Hostname,
                                    provisioningConfig.UserData);

            return(await InsertConfigDriveDisk(configDriveIsoPath, vmInfo, engine));
        }
예제 #6
0
        private static Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > EjectConfigDriveDisk(
            string configDriveIsoPath,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            IPowershellEngine engine)
        {
            var res = vmInfo.GetList(l => l.DVDDrives,
                                     drive => configDriveIsoPath.Equals(drive.Path, StringComparison.OrdinalIgnoreCase))
                      .Apply(dvdDriveList =>
            {
                var array = dvdDriveList.ToArray();

                if (array.Length > 1)
                {
                    array.Take(array.Length - 1).Iter(r =>
                                                      engine.Run(PsCommandBuilder.Create()
                                                                 .AddCommand("Remove-VMDvdDrive")
                                                                 .AddParameter("VMDvdDrive", r.PsObject)));
                }

                return(vmInfo.GetList(l => l.DVDDrives, drive => configDriveIsoPath.Equals(drive.Path, StringComparison.OrdinalIgnoreCase)));
            }).Apply(driveInfos =>
            {
                return(driveInfos.Map(driveInfo => engine.Run(PsCommandBuilder.Create()
                                                              .AddCommand("Set-VMDvdDrive")
                                                              .AddParameter("VMDvdDrive", driveInfo.PsObject)
                                                              .AddParameter("Path", null)))
                       .Traverse(x => x).Map(
                           x => vmInfo.Recreate()));
            });

            return(res);
        }
예제 #7
0
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > Disk(
            VirtualMachineDiskConfig diskConfig,
            IPowershellEngine engine,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            MachineConfig vmConfig,
            Func <string, Task> reportProgress)
        {
            if (!File.Exists(diskConfig.Path))
            {
                await reportProgress($"Create VHD: {diskConfig.Name}").ConfigureAwait(false);

                await engine.RunAsync(PsCommandBuilder.Create().Script(
                                          $"New-VHD -Path \"{diskConfig.Path}\" -ParentPath \"{diskConfig.Template}\" -Differencing"),
                                      reportProgress : p => ReportPowershellProgress($"Create VHD {diskConfig.Name}", p, reportProgress)).ConfigureAwait(false);
            }

            await GetOrCreateInfoAsync(vmInfo,
                                       i => i.HardDrives,
                                       disk => diskConfig.Path.Equals(disk.Path, StringComparison.OrdinalIgnoreCase),
                                       async() =>
            {
                await reportProgress($"Add VHD: {diskConfig.Name}").ConfigureAwait(false);
                return(await engine.GetObjectsAsync <HardDiskDriveInfo>(PsCommandBuilder.Create()
                                                                        .AddCommand("Add-VMHardDiskDrive")
                                                                        .AddParameter("VM", vmInfo.PsObject)
                                                                        .AddParameter("Path", diskConfig.Path)).ConfigureAwait(false));
            }).ConfigureAwait(false);

            return(vmInfo.Recreate());
        }
예제 #8
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
 private static Task <IEnumerable <TRes> > FindAndApply <T, TSub, TRes>(TypedPsObject <T> parentInfo,
                                                                        Expression <Func <T, IList <TSub> > > listProperty,
                                                                        Func <TSub, bool> predicateFunc,
                                                                        Func <TypedPsObject <TSub>, Task <TRes> > applyFunc)
 {
     return(parentInfo.GetList(listProperty, predicateFunc).ToArray().Map(applyFunc)
            .Traverse(l => l));
 }
예제 #9
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static Task <Either <PowershellFailure, Unit> > VirtualDisks(TypedPsObject <VirtualMachineInfo> vmInfo,
                                                                            Seq <VMDriveStorageSettings> plannedDriveStorageSettings, HostSettings hostSettings, IPowershellEngine engine, Func <string, Task> reportProgress)
        {
            var plannedDiskSettings = plannedDriveStorageSettings
                                      .Where(x => x.Type == VirtualMachineDriveType.VHD || x.Type == VirtualMachineDriveType.SharedVHD)
                                      .Cast <VMDiskStorageSettings>().ToSeq();

            return(from currentDiskSettings in Storage.DetectDiskStorageSettings(vmInfo.Value.HardDrives, hostSettings, engine)
                   from _ in plannedDiskSettings.MapToEitherAsync(s => VirtualDisk(s, engine, vmInfo, currentDiskSettings, reportProgress))
                   select Unit.Default);
        }
예제 #10
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
 public static Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > RenameVirtualMachine(
     IPowershellEngine engine,
     TypedPsObject <VirtualMachineInfo> vmInfo,
     string newName)
 {
     return(engine.RunAsync(PsCommandBuilder.Create()
                            .AddCommand("Rename-VM")
                            .AddParameter("VM", vmInfo.PsObject)
                            .AddParameter("NewName", newName)
                            ).BindAsync(u => vmInfo.RecreateOrReload(engine)));
 }
예제 #11
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
 private static Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > RemoveConfigDriveDisk(
     TypedPsObject <VirtualMachineInfo> vmInfo,
     IPowershellEngine engine)
 {
     return(FindAndApply(vmInfo, l => l.DVDDrives,
                         drive => drive.ControllerLocation == 63 && drive.ControllerNumber == 0,
                         drive => engine.RunAsync(PsCommandBuilder.Create()
                                                  .AddCommand("Remove-VMDvdDrive")
                                                  .AddParameter("VMDvdDrive", drive.PsObject)))
            .Map(list => list.Lefts().HeadOrNone()).MatchAsync(
                None: () => vmInfo.RecreateOrReload(engine),
                Some: l => LeftAsync <PowershellFailure, TypedPsObject <VirtualMachineInfo> >(l).ToEither()));
 }
예제 #12
0
        public void SetInfo(TypedPsObject <VirtualMachineInfo> info)
        {
            if (info == null)
            {
                return;
            }

            if (_buffer.ContainsKey(info.Value.Id))
            {
                _buffer.TryRemove(info.Value.Id, out _);
            }

            _buffer.TryAdd(info.Value.Id, info);
        }
예제 #13
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static Task <Either <PowershellFailure, Unit> > DetachUndefinedDrives(
            IPowershellEngine engine,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            Seq <VMDriveStorageSettings> plannedStorageSettings,
            HostSettings hostSettings,
            Func <string, Task> reportProgress)

        {
            return((from currentDiskSettings in Storage.DetectDiskStorageSettings(vmInfo.Value.HardDrives,
                                                                                  hostSettings, engine).ToAsync()
                    from _ in DetachUndefinedHardDrives(engine, vmInfo, plannedStorageSettings,
                                                        currentDiskSettings, reportProgress).ToAsync()
                    from __ in DetachUndefinedDvdDrives(engine, vmInfo, plannedStorageSettings, reportProgress).ToAsync()
                    select Unit.Default).ToEither());
        }
예제 #14
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static async Task Definition(
            IPowershellEngine engine,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            MachineConfig vmConfig,
            Func <string, Task> reportProgress)
        {
            if (vmInfo.Value.Generation >= 2)
            {
                await engine.GetObjectsAsync <VMFirmwareInfo>(PsCommandBuilder.Create()
                                                              .AddCommand("Get-VMFirmware")
                                                              .AddParameter("VM", vmInfo.PsObject)).MapAsync(async(firmwareInfo) =>
                {
                    if (firmwareInfo.Head.Value.SecureBoot != OnOffState.Off)
                    {
                        await reportProgress($"Configure VM Firmware - Secure Boot: {OnOffState.Off}")
                        .ConfigureAwait(false);

                        await engine.RunAsync(PsCommandBuilder.Create()
                                              .AddCommand("Set-VMFirmware")
                                              .AddParameter("VM", vmInfo.PsObject)
                                              .AddParameter("EnableSecureBoot", OnOffState.Off)).ConfigureAwait(false);
                    }
                }).ConfigureAwait(false);
            }


            if (vmInfo.Value.ProcessorCount != vmConfig.VM.Cpu.Count)
            {
                await reportProgress($"Configure VM Processor: Count: {vmConfig.VM.Cpu.Count}").ConfigureAwait(false);

                await engine.RunAsync(PsCommandBuilder.Create()
                                      .AddCommand("Set-VMProcessor")
                                      .AddParameter("VM", vmInfo.PsObject)
                                      .AddParameter("Count", vmConfig.VM.Cpu.Count)).ConfigureAwait(false);
            }

            var memoryStartupBytes = vmConfig.VM.Memory.Startup * 1024L * 1024;

            if (vmInfo.Value.MemoryStartup != memoryStartupBytes)
            {
                await reportProgress($"Configure VM Memory: Startup: {vmConfig.VM.Memory.Startup} MB").ConfigureAwait(false);

                await engine.RunAsync(PsCommandBuilder.Create()
                                      .AddCommand("Set-VMMemory")
                                      .AddParameter("VM", vmInfo.PsObject)
                                      .AddParameter("StartupBytes", memoryStartupBytes)).ConfigureAwait(false);
            }
        }
예제 #15
0
 private static Task <Either <PowershellFailure, Unit> > InsertConfigDriveDisk(
     string configDriveIsoPath,
     TypedPsObject <VirtualMachineInfo> vmInfo,
     IPowershellEngine engine)
 {
     return(vmInfo.GetList(l => l.DVDDrives, drive => string.IsNullOrWhiteSpace(drive.Path))
            .HeadOrNone().MatchAsync(
                None: () => engine.RunAsync(
                    PsCommandBuilder.Create().AddCommand("Add-VMDvdDrive")
                    .AddParameter("VM", vmInfo.PsObject).AddParameter("Path", configDriveIsoPath)),
                Some: dvdDriveInfo => engine.RunAsync(PsCommandBuilder.Create()
                                                      .AddCommand("Set-VMDvdDrive")
                                                      .AddParameter("VMDvdDrive", dvdDriveInfo.PsObject)
                                                      .AddParameter("Path", configDriveIsoPath)
                                                      )));
 }
예제 #16
0
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > NetworkAdapter(
            VirtualMachineNetworkAdapterConfig networkAdapterConfig,
            IPowershellEngine engine,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            MachineConfig machineConfig,
            Func <string, Task> reportProgress)
        {
            var optionalAdapter = await GetOrCreateInfoAsync(vmInfo,
                                                             i => i.NetworkAdapters,
                                                             adapter => networkAdapterConfig.Name.Equals(adapter.Name, StringComparison.OrdinalIgnoreCase),
                                                             async() =>
            {
                await reportProgress($"Add Network Adapter: {networkAdapterConfig.Name}").ConfigureAwait(false);
                return(await engine.GetObjectsAsync <VMNetworkAdapter>(PsCommandBuilder.Create()
                                                                       .AddCommand("Add-VmNetworkAdapter")
                                                                       .AddParameter("Passthru")
                                                                       .AddParameter("VM", vmInfo.PsObject)
                                                                       .AddParameter("Name", networkAdapterConfig.Name)
                                                                       .AddParameter("StaticMacAddress", UseOrGenerateMacAddress(networkAdapterConfig, vmInfo))
                                                                       .AddParameter("SwitchName", networkAdapterConfig.SwitchName)).ConfigureAwait(false));
            }).ConfigureAwait(false);

            return(optionalAdapter.Map(_ => vmInfo.Recreate()));

            //optionalAdapter.Map(async (adapter) =>
            //{
            //    if (!adapter.Value.Connected || adapter.Value.SwitchName != networkConfig.SwitchName)
            //    {
            //        await reportProgress($"Connect Network Adapter {adapter.Value.Name} to switch {networkConfig.SwitchName}").ConfigureAwait(false);
            //        await engine.RunAsync(
            //            PsCommandBuilder.Create().AddCommand("Connect-VmNetworkAdapter")
            //                .AddParameter("VMNetworkAdapter", adapter.PsObject)
            //                .AddParameter("SwitchName", networkConfig.SwitchName)).ConfigureAwait(false);

            //    }
            //});
            return(vmInfo.Recreate());
        }
예제 #17
0
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > Disks(TypedPsObject <VirtualMachineInfo> vmInfo,
                                                                                                          Seq <VirtualMachineDiskConfig> diskConfig, MachineConfig vmConfig, IPowershellEngine engine, Func <string, Task> reportProgress)
        {
            var seq = diskConfig.Map(disk => Disk(disk, engine, vmInfo, vmConfig, reportProgress));

            if (seq.IsEmpty)
            {
                return(vmInfo);
            }

            return(await seq.Last);
        }
예제 #18
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > Firmware(TypedPsObject <VirtualMachineInfo> vmInfo,
                                                                                                             MachineConfig config, IPowershellEngine engine, Func <string, Task> reportProgress)
        {
            if (vmInfo.Value.Generation < 2)
            {
                return(vmInfo);
            }

            return(await engine.GetObjectsAsync <VMFirmwareInfo>(PsCommandBuilder.Create()
                                                                 .AddCommand("Get-VMFirmware")
                                                                 .AddParameter("VM", vmInfo.PsObject))
                   .BindAsync(firmwareInfoSeq =>
                              firmwareInfoSeq.HeadOrNone()
                              .Match <Either <PowershellFailure, TypedPsObject <VMFirmwareInfo> > >(
                                  None: () => new PowershellFailure {
                Message = "Failed to get VM Firmware"
            },
                                  Some: s => s
                                  ))
                   .BindAsync(async firmwareInfo =>
            {
                if (firmwareInfo.Value.SecureBoot != OnOffState.Off)
                {
                    await reportProgress($"Configure VM Firmware - Secure Boot: {OnOffState.Off}")
                    .ConfigureAwait(false);


                    var res = await engine.RunAsync(PsCommandBuilder.Create()
                                                    .AddCommand("Set-VMFirmware")
                                                    .AddParameter("VM", vmInfo.PsObject)
                                                    .AddParameter("EnableSecureBoot", OnOffState.Off)).BindAsync(_ => vmInfo.RecreateOrReload(engine)
                                                                                                                 ).ConfigureAwait(false);
                    return res;
                }

                return await vmInfo.RecreateOrReload(engine).ConfigureAwait(false);
            }
                              ).ConfigureAwait(false));
        }
예제 #19
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > Cpu(TypedPsObject <VirtualMachineInfo> vmInfo,
                                                                                                        Option <VirtualMachineCpuConfig> cpuConfig, IPowershellEngine engine, Func <string, Task> reportProgress)
        {
            return(await cpuConfig.MatchAsync(
                       None : () => vmInfo,
                       Some : async config =>
            {
                if (vmInfo.Value.ProcessorCount != config.Count)
                {
                    await reportProgress($"Configure VM Processor: Count: {config.Count}").ConfigureAwait(false);

                    await engine.RunAsync(PsCommandBuilder.Create()
                                          .AddCommand("Set-VMProcessor")
                                          .AddParameter("VM", vmInfo.PsObject)
                                          .AddParameter("Count", config.Count)).ConfigureAwait(false);

                    return await vmInfo.RecreateOrReload(engine).ConfigureAwait(false);
                }

                return vmInfo;
            }).ConfigureAwait(false));
        }
예제 #20
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        private static async Task <Either <PowershellFailure, TypedPsObject <TSub> > > GetOrCreateInfoAsync <T, TSub>(TypedPsObject <T> parentInfo,
                                                                                                                      Expression <Func <T, IList <TSub> > > listProperty,
                                                                                                                      Func <TSub, bool> predicateFunc,
                                                                                                                      Func <Task <Either <PowershellFailure, Seq <TypedPsObject <TSub> > > > > creatorFunc)
        {
            var result = parentInfo.GetList(listProperty, predicateFunc).ToArray();

            if (result.Length() != 0)
            {
                return(Try(result.Single()).Try().Match <Either <PowershellFailure, TypedPsObject <TSub> > >(
                           Fail: ex =>
                {
                    return Left(new PowershellFailure {
                        Message = ex.Message
                    });
                },
                           Succ: x => Right(x)
                           ));
            }


            var creatorResult = await creatorFunc().ConfigureAwait(false);

            var res = creatorResult.Bind(
                seq => seq.HeadOrNone().ToEither(() =>
                                                 new PowershellFailure {
                Message = "Object creation was successful, but no result was returned."
            }));

            return(res);
        }
예제 #21
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        private static string UseOrGenerateMacAddress(VirtualMachineNetworkAdapterConfig adapterConfig, TypedPsObject <VirtualMachineInfo> vmInfo)
        {
            var result = adapterConfig.MacAddress;

            if (string.IsNullOrWhiteSpace(result))
            {
                result = GenerateMacAddress(vmInfo.Value.Id, adapterConfig.Name);
            }
            return(result);
        }
예제 #22
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > NetworkAdapters(TypedPsObject <VirtualMachineInfo> vmInfo,
                                                                                                                    Seq <VirtualMachineNetworkAdapterConfig> adapterConfig, MachineConfig vmConfig, IPowershellEngine engine, Func <string, Task> reportProgress)
        {
            var seq = adapterConfig.Map(adapter => NetworkAdapter(adapter, engine, vmInfo, vmConfig, reportProgress));

            if (seq.IsEmpty)
            {
                return(vmInfo);
            }

            return(await seq.Last);
        }
예제 #23
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > VirtualDisk(
            VMDiskStorageSettings diskSettings,
            IPowershellEngine engine,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            Seq <CurrentVMDiskStorageSettings> currentStorageSettings,
            Func <string, Task> reportProgress)
        {
            var currentSettings =
                currentStorageSettings.Find(x => diskSettings.Path.Equals(x.Path, StringComparison.OrdinalIgnoreCase) &&
                                            diskSettings.Name.Equals(x.Name, StringComparison.InvariantCultureIgnoreCase));
            var frozenOptional = currentSettings.Map(x => x.Frozen);

            if (frozenOptional.IsSome && frozenOptional.ValueUnsafe())
            {
                await reportProgress($"Skipping disk '{diskSettings.Name}': storage management is disabled for this disk.").ConfigureAwait(false);

                return(vmInfo);
            }



            return(await diskSettings.AttachPath.Map(async (vhdPath) =>
            {
                if (!File.Exists(vhdPath))
                {
                    await reportProgress($"Create VHD: {diskSettings.Name}").ConfigureAwait(false);

                    var createDiskResult = await diskSettings.ParentPath.Match(Some: parentPath =>
                    {
                        return engine.RunAsync(PsCommandBuilder.Create().Script(
                                                   $"New-VHD -Path \"{vhdPath}\" -ParentPath \"{parentPath}\" -Differencing"));
                    },
                                                                               None: () =>
                    {
                        return engine.RunAsync(PsCommandBuilder.Create().Script(
                                                   $"New-VHD -Path \"{vhdPath}\" -Dynamic -SizeBytes {diskSettings.SizeBytes}"));
                    });

                    if (createDiskResult.IsLeft)
                    {
                        return Prelude.Left(createDiskResult.LeftAsEnumerable().FirstOrDefault());
                    }
                }

                var sizeResult = await engine
                                 .GetObjectsAsync <VhdInfo>(new PsCommandBuilder().AddCommand("get-vhd").AddArgument(vhdPath))
                                 .BindAsync(x => x.HeadOrLeft(new PowershellFailure())).BindAsync(async(vhdInfo) =>
                {
                    if (vhdInfo.Value.Size != diskSettings.SizeBytes && diskSettings.SizeBytes > 0)
                    {
                        var gb = Math.Round(diskSettings.SizeBytes / 1024d / 1024 / 1024, 1);
                        await reportProgress(
                            $"Resizing disk {diskSettings.Name} to {gb} GB");
                        return await engine.RunAsync(PsCommandBuilder.Create().AddCommand("Resize-VHD")
                                                     .AddArgument(vhdPath)
                                                     .AddParameter("Size", diskSettings.SizeBytes));
                    }

                    return Unit.Default;
                });

                if (sizeResult.IsLeft)
                {
                    return Prelude.Left(sizeResult.LeftAsEnumerable().FirstOrDefault());
                }


                return await GetOrCreateInfoAsync(vmInfo,
                                                  i => i.HardDrives,
                                                  disk => currentSettings.Map(x => x.AttachedVMId) == disk.Id,
                                                  async() =>
                {
                    await reportProgress($"Attaching disk {diskSettings.Name} to controller: {diskSettings.ControllerNumber}, Location: {diskSettings.ControllerLocation}").ConfigureAwait(false);
                    return (await engine.GetObjectsAsync <HardDiskDriveInfo>(PsCommandBuilder.Create()
                                                                             .AddCommand("Add-VMHardDiskDrive")
                                                                             .AddParameter("VM", vmInfo.PsObject)
                                                                             .AddParameter("Path", vhdPath)
                                                                             .AddParameter("ControllerNumber", diskSettings.ControllerNumber)
                                                                             .AddParameter("ControllerLocation", diskSettings.ControllerLocation)
                                                                             .AddParameter("PassThru")
                                                                             ).ConfigureAwait(false));
                }).BindAsync(_ => vmInfo.RecreateOrReload(engine))


                .ConfigureAwait(false);
            }).IfNone(vmInfo.RecreateOrReload(engine)));
        }
예제 #24
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static async Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > Drives(TypedPsObject <VirtualMachineInfo> vmInfo,
                                                                                                           MachineConfig vmConfig,
                                                                                                           VMStorageSettings storageSettings,
                                                                                                           HostSettings hostSettings, IPowershellEngine engine, Func <string, Task> reportProgress)
        {
            if (storageSettings.Frozen)
            {
                return(Right <PowershellFailure, TypedPsObject <VirtualMachineInfo> >(vmInfo));
            }

            var currentCheckpointType = vmInfo.Value.CheckpointType;

            try
            {
                await(
                    //prevent snapshots creating during running disk converge
                    from _ in SetVMCheckpointType(vmInfo, CheckpointType.Disabled, engine).ToAsync()
                    //make a plan
                    from plannedDriveStorageSettings in Storage.PlanDriveStorageSettings(vmConfig, storageSettings, hostSettings, engine).ToAsync()
                    //ensure that the changes reflect the current VM settings
                    from infoReloaded in vmInfo.Reload(engine).ToAsync()
                    //detach removed disks
                    from __ in DetachUndefinedDrives(engine, infoReloaded, plannedDriveStorageSettings, hostSettings, reportProgress).ToAsync()
                    from infoRecreated in vmInfo.RecreateOrReload(engine).ToAsync()
                    from ___ in VirtualDisks(infoRecreated, plannedDriveStorageSettings, hostSettings, engine, reportProgress).ToAsync()

                    select Unit.Default).ToEither().ConfigureAwait(false);
            }
            finally
            {
                await SetVMCheckpointType(vmInfo, currentCheckpointType, engine).ConfigureAwait(false);
            }

            return(await vmInfo.Reload(engine).ConfigureAwait(false));
        }
예제 #25
0
파일: Converge.cs 프로젝트: phoenixyj/haipa
        public static Task <Either <PowershellFailure, Unit> > DetachUndefinedHardDrives(
            IPowershellEngine engine,
            TypedPsObject <VirtualMachineInfo> vmInfo,
            Seq <VMDriveStorageSettings> plannedStorageSettings,
            Seq <CurrentVMDiskStorageSettings> currentDiskStorageSettings,
            Func <string, Task> reportProgress)

        {
            var planedDiskSettings = plannedStorageSettings.Where(x =>
                                                                  x.Type == VirtualMachineDriveType.VHD || x.Type == VirtualMachineDriveType.SharedVHD)
                                     .Cast <VMDiskStorageSettings>().ToSeq();

            var attachedPaths = planedDiskSettings.Map(s => s.AttachPath).Map(x => x.IfNone(""))
                                .Where(x => !string.IsNullOrWhiteSpace(x));

            var frozenDiskIds = currentDiskStorageSettings.Where(x => x.Frozen).Map(x => x.AttachedVMId);

            return(FindAndApply(vmInfo,
                                i => i.HardDrives,
                                hd =>
            {
                var plannedDiskAtControllerPos = planedDiskSettings
                                                 .FirstOrDefault(x =>
                                                                 x.ControllerLocation == hd.ControllerLocation && x.ControllerNumber == hd.ControllerNumber);

                var detach = plannedDiskAtControllerPos == null;

                if (!detach && plannedDiskAtControllerPos.AttachPath.IsSome)
                {
                    var plannedAttachPath = plannedDiskAtControllerPos.AttachPath.IfNone("");
                    if (hd.Path == null || !hd.Path.Equals(plannedAttachPath, StringComparison.InvariantCultureIgnoreCase))
                    {
                        detach = true;
                    }
                }

                if (detach && frozenDiskIds.Contains(hd.Id))
                {
                    reportProgress(hd.Path != null
                                ? $"Skipping detach of frozen disk {Path.GetFileNameWithoutExtension(hd.Path)}"
                                : $"Skipping detach of unknown frozen disk at controller {hd.ControllerNumber}, Location: {hd.ControllerLocation}");

                    return false;
                }

                if (detach)
                {
                    reportProgress(hd.Path != null
                                ? $"Detaching disk {Path.GetFileNameWithoutExtension(hd.Path)} from controller: {hd.ControllerNumber}, Location: {hd.ControllerLocation}"
                                : $"Detaching unknown disk at controller: {hd.ControllerNumber}, Location: {hd.ControllerLocation}");
                }

                return detach;
            },
                                i => engine.RunAsync(PsCommandBuilder.Create().AddCommand("Remove-VMHardDiskDrive")
                                                     .AddParameter("VMHardDiskDrive", i.PsObject))).Map(x => x.Lefts().HeadOrNone())
                   .MatchAsync(
                       Some: l => LeftAsync <PowershellFailure, Unit>(l).ToEither(),
                       None: () => RightAsync <PowershellFailure, Unit>(Unit.Default)
                       .ToEither()));
        }