public Task Handle(AcceptedOperation <ConvergeVirtualMachineCommand> message)
        {
            var command = message.Command;
            var config  = command.Config;

            _operationId = command.OperationId;

            var chain =
                from normalizedVMConfig in Converge.NormalizeMachineConfig(config, _engine, ProgressMessage)
                from vmList in GetVmInfo(normalizedVMConfig.Id, _engine)
                from optionalVmInfo in EnsureUnique(vmList, normalizedVMConfig.Id)
                from storageSettings in DetectStorageSettings(optionalVmInfo)
                from vmConfig in ApplyStorageSettings(normalizedVMConfig, storageSettings, GetHostSettings())
                from vmInfoCreated in EnsureCreated(optionalVmInfo, vmConfig, storageSettings, _engine)
                from vmInfo in EnsureNameConsistent(vmInfoCreated, vmConfig, _engine)
                from _ in AttachToOperation(vmInfo, _bus, command.OperationId)
                from vmInfoConverged in ConvergeVm(vmInfo, vmConfig, storageSettings, _engine)
                select vmInfoConverged;

            return(chain.ToAsync().MatchAsync(
                       LeftAsync: HandleError,
                       RightAsync: vmInfo2 => _bus.Send(new OperationCompletedEvent
            {
                OperationId = command.OperationId,
            }).ToUnit()));
        }
 private static Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > EnsureCreated(Option <TypedPsObject <VirtualMachineInfo> > vmInfo, MachineConfig config, VMStorageSettings storageSettings, IPowershellEngine engine)
 {
     return(vmInfo.MatchAsync(
                None: () => Converge.CreateVirtualMachine(engine, config.Name, storageSettings.StorageIdentifier,
                                                          config.VM.Path,
                                                          config.VM.Memory.Startup),
                Some: s => s
                ));
 }
        private static Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > EnsureNameConsistent(TypedPsObject <VirtualMachineInfo> vmInfo, MachineConfig config, IPowershellEngine engine)
        {
            return(Prelude.Cond <(string currentName, string newName)>((names) =>
                                                                       !string.IsNullOrWhiteSpace(names.newName) &&
                                                                       !names.newName.Equals(names.currentName, StringComparison.InvariantCulture))((vmInfo.Value.Name,
                                                                                                                                                     config.Name))

                   .MatchAsync(
                       None: () => vmInfo,
                       Some: (some) => Converge.RenameVirtualMachine(engine, vmInfo, config.Name)));
        }
 private static Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > EnsureCreated(Option <TypedPsObject <VirtualMachineInfo> > vmInfo, MachineConfig config, VMStorageSettings storageSettings, IPowershellEngine engine)
 {
     return(vmInfo.MatchAsync(
                None: () =>
                storageSettings.StorageIdentifier.ToEither(new PowershellFailure {
         Message = "Unknown storage identifier, cannot create new virtual machine"
     })
                .BindAsync(storageIdentifier => Converge.CreateVirtualMachine(engine, config.Name, storageIdentifier,
                                                                              storageSettings.VMPath,
                                                                              config.VM.Memory.Startup)),
                Some: s => s
                ));
 }
 private Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > ConvergeVm(
     TypedPsObject <VirtualMachineInfo> vmInfo,
     MachineConfig machineConfig,
     VMStorageSettings storageSettings,
     HostSettings hostSettings,
     IPowershellEngine engine)
 {
     return
         (from infoFirmware in Converge.Firmware(vmInfo, machineConfig, engine, ProgressMessage)
          from infoCpu in Converge.Cpu(infoFirmware, machineConfig.VM.Cpu, engine, ProgressMessage)
          from infoDrives in Converge.Drives(infoCpu, machineConfig, storageSettings, hostSettings, engine, ProgressMessage)
          from infoNetworks in Converge.NetworkAdapters(infoDrives, machineConfig.VM.NetworkAdapters.ToSeq(), machineConfig, engine, ProgressMessage)
          from infoCloudInit in Converge.CloudInit(infoNetworks, storageSettings.VMPath, machineConfig.Provisioning, engine, ProgressMessage)
          select infoCloudInit);
 }
        private Task <Either <PowershellFailure, TypedPsObject <VirtualMachineInfo> > > ConvergeVm(TypedPsObject <VirtualMachineInfo> vmInfo, MachineConfig machineConfig, VMStorageSettings storageSettings, IPowershellEngine engine)
        {
            return
                (from infoFirmware in Converge.Firmware(vmInfo, machineConfig, engine, ProgressMessage)
                 from infoCpu in Converge.Cpu(infoFirmware, machineConfig.VM.Cpu, engine, ProgressMessage)
                 from infoDisks in Converge.Disks(infoCpu, machineConfig.VM.Disks.ToSeq(), machineConfig, engine, ProgressMessage)
                 from infoNetworks in Converge.NetworkAdapters(infoDisks, machineConfig.VM.NetworkAdapters.ToSeq(), machineConfig, engine, ProgressMessage)
                 from infoCloudInit in Converge.CloudInit(infoNetworks, machineConfig.VM.Path, storageSettings.StorageIdentifier, machineConfig.Provisioning.Hostname, machineConfig.Provisioning?.UserData, engine, ProgressMessage)
                 select infoCloudInit);

            //Converge.Firmware(vmInfo, machineConfig, engine, ProgressMessage)
            //.BindAsync(info => Converge.Cpu(info, machineConfig.VMConfig.Cpu, engine, ProgressMessage))
            //.BindAsync(info => Converge.Disks(info, machineConfig.VMConfig.Disks?.ToSeq(), machineConfig, engine, ProgressMessage))

            //.BindAsync(info => Converge.CloudInit(
            //    info, machineConfig.VMConfig.Path, machineConfig.Provisioning.Hostname, machineConfig.Provisioning?.UserData, engine, ProgressMessage)).ConfigureAwait(false);

            //await Converge.Definition(engine, vmInfo, config, ProgressMessage).ConfigureAwait(false);
            //await ProgressMessage("Generate Virtual Machine provisioning disk").ConfigureAwait(false);
        }
        public Task Handle(AcceptedOperationTask <ConvergeVirtualMachineCommand> message)
        {
            var command = message.Command;
            var config  = command.Config;

            _operationId = command.OperationId;
            _taskId      = command.TaskId;

            var hostSettings = GetHostSettings();

            var chain =

                from normalizedVMConfig in Converge.NormalizeMachineConfig(config, _engine, ProgressMessage)
                from vmList in GetVmInfo(normalizedVMConfig.Id, _engine)
                from optionalVmInfo in EnsureUnique(vmList, normalizedVMConfig.Id)

                from currentStorageSettings in Storage.DetectVMStorageSettings(optionalVmInfo, hostSettings, ProgressMessage)
                from plannedStorageSettings in Storage.PlanVMStorageSettings(normalizedVMConfig, currentStorageSettings, hostSettings, GenerateId)

                from vmInfoCreated in EnsureCreated(optionalVmInfo, config, plannedStorageSettings, _engine)
                from _ in AttachToOperation(vmInfoCreated, _bus, command.OperationId)
                from vmInfo in EnsureNameConsistent(vmInfoCreated, config, _engine)

                from vmInfoConverged in ConvergeVm(vmInfo, config, plannedStorageSettings, hostSettings, _engine)
                select vmInfoConverged;

            return(chain.ToAsync().MatchAsync(
                       LeftAsync: HandleError,
                       RightAsync: async vmInfo2 =>
            {
                await ProgressMessage($"Virtual machine '{vmInfo2.Value.Name}' has been converged.").ConfigureAwait(false);

                return await _bus.Publish(OperationTaskStatusEvent.Completed(_operationId, _taskId))
                .ToUnit().ConfigureAwait(false);
            }));
        }