private static Task <Either <PowershellFailure, VMStorageSettings> > ConfigToVMStorageSettings(MachineConfig config, HostSettings hostSettings) { var projectName = Prelude.Some("default"); var environmentName = Prelude.Some("default"); var dataStoreName = Prelude.Some("default"); var storageIdentifier = Option <string> .None; var names = new StorageNames() { ProjectName = projectName, EnvironmentName = environmentName, DataStoreName = dataStoreName, }; if (!string.IsNullOrWhiteSpace(config.VM.Slug)) { storageIdentifier = Prelude.Some(config.VM.Slug); } return(ResolveStorageBasePath(names, hostSettings.DefaultDataPath).MapAsync(path => new VMStorageSettings { StorageNames = names, StorageIdentifier = storageIdentifier, VMPath = path })); }
private static Task <Either <PowershellFailure, string> > JoinPathAndProject(string dsPath, string projectName) { var result = dsPath; if (projectName != "default") { result = Path.Combine(dsPath, $"haipa_p{projectName}"); } return(Prelude.RightAsync <PowershellFailure, string>(result).ToEither()); }
public static (StorageNames Names, Option <string> StorageIdentifier) PathToStorageNames(string path, string defaultPath) { var projectName = Prelude.Some("default"); var environmentName = Prelude.Some("default"); var dataStoreName = Option <string> .None; var dataStorePath = Option <string> .None; var storageIdentifier = Option <string> .None; if (path.StartsWith(defaultPath, StringComparison.InvariantCultureIgnoreCase)) { dataStoreName = Prelude.Some("default"); dataStorePath = defaultPath; } if (dataStorePath.IsSome) { var pathAfterDS = path.Remove(0, dataStorePath.ValueUnsafe().Length).TrimStart('\\'); var pathRoot = Path.GetPathRoot(pathAfterDS); if (pathRoot.StartsWith("haipa_p")) { projectName = pathRoot.Remove(0, "haipa_p".Length); } var idCandidate = pathAfterDS; if (idCandidate.Contains(Path.DirectorySeparatorChar)) { idCandidate = Path.GetDirectoryName(pathAfterDS); } if (!string.IsNullOrWhiteSpace(idCandidate) && pathRoot != idCandidate) { storageIdentifier = idCandidate; } } var names = new StorageNames { DataStoreName = dataStoreName, ProjectName = projectName, EnvironmentName = environmentName }; return(names, storageIdentifier); }
public static Task <Either <PowershellFailure, Option <VMStorageSettings> > > DetectVMStorageSettings( Option <TypedPsObject <VirtualMachineInfo> > optionalVmInfo, HostSettings hostSettings, Func <string, Task> reportProgress) { return(optionalVmInfo .MatchAsync( Some: s => { var namesAndId = PathToStorageNames(s.Value.Path, hostSettings.DefaultDataPath); var settings = (from resolvedPath in ResolveStorageBasePath(namesAndId.Names, hostSettings.DefaultDataPath) from storageSettings in ComparePath(resolvedPath, s.Value.Path, namesAndId.StorageIdentifier) select storageSettings); return settings.Bind(e => e.Match( Right: matchedPath => Prelude.RightAsync <PowershellFailure, VMStorageSettings>( new VMStorageSettings { StorageNames = namesAndId.Names, StorageIdentifier = namesAndId.StorageIdentifier, VMPath = matchedPath, }).ToEither(), Left: async(l) => { //current behaviour is to soft fail by disabling storage changes //however later we should add a option to strictly fail on all operations await reportProgress( "Invalid machine storage settings. Storage management is disabled."); return Prelude.Right <PowershellFailure, VMStorageSettings>( new VMStorageSettings { StorageNames = namesAndId.Names, StorageIdentifier = namesAndId.StorageIdentifier, VMPath = s.Value.Path, Frozen = true } ); })).MapAsync(r => r.ToSome().ToOption()); }, None: () => Option <VMStorageSettings> .None)); }
private static Task <Either <PowershellFailure, string> > ComparePath(string firstPath, string secondPath, Option <string> storageIdentifier) { return(storageIdentifier.ToEither(new PowershellFailure { Message = "unknown VM storage identifier" }) .BindAsync(id => { var fullPath = Path.Combine(firstPath, id); if (!secondPath.Equals(fullPath, StringComparison.InvariantCultureIgnoreCase)) { return Prelude .LeftAsync <PowershellFailure, string>(new PowershellFailure { Message = "Path calculation failure" }) .ToEither(); } return Prelude .RightAsync <PowershellFailure, string>(firstPath) .ToEither(); })); }
private static Task <Either <PowershellFailure, VMStorageSettings> > EnsureStorageId(VMStorageSettings first, VMStorageSettings second, Func <Task <Either <PowershellFailure, string> > > idGeneratorFunc) { if (second.Frozen) { return(Prelude.RightAsync <PowershellFailure, VMStorageSettings>(second).ToEither()); } return(first.StorageIdentifier.MatchAsync( None: () => second.StorageIdentifier.MatchAsync( None: idGeneratorFunc, Some: s => Prelude.RightAsync <PowershellFailure, string>(s).ToEither()), Some: s => Prelude.RightAsync <PowershellFailure, string>(s).ToEither() ).MapAsync(storageIdentifier => new VMStorageSettings { StorageNames = first.StorageNames, StorageIdentifier = storageIdentifier, VMPath = first.VMPath })); }
public static IImmutableList <Either <T, Exception> > ToList <T>(this TryOption <T> self) => Prelude.toList(self.AsEnumerable());
public static async Task <Option <A> > lastOrNoneAsync <FOLD, F, A>(F fa) where FOLD : FoldableAsync <F, A> => (await toSeqAsync <FOLD, F, A>(fa)) .Map(x => Prelude.Some(x)) .DefaultIfEmpty(Option <A> .None) .LastOrDefault();
public static Option <A> lastOrNone <FOLD, F, A>(F fa) where FOLD : struct, Foldable <F, A> => toSeq <FOLD, F, A>(fa) .Map(x => Prelude.Some(x)) .DefaultIfEmpty(Option <A> .None) .LastOrDefault();
public static Either <L, R> ForceLeft <L, R>(this Either <L, R> either, Func <R, L> force) { return(either.Bind( _ => Prelude.Left <L, R>(force(_)))); }
public static Either <L, R> ForceRight <L, R>(this Either <L, R> either, Func <L, R> force) { return(either.BindLeft( _ => Prelude.Right <L, R>(force(_)))); }
/// <summary> /// Safely use a disposable resource /// </summary> /// <param name="Acq">Acquire resource</param> /// <param name="Use">Use resource</param> public static Eff <R> Use <H, R>(this Eff <H> Acq, Func <H, Eff <R> > Use) where H : IDisposable => Prelude.use(Acq, Use);
public static Seq <B> rights <CHOICE, CH, A, B>(Seq <CH> ma) where CHOICE : struct, ChoiceUnsafe <CH, A, B> => Prelude.toSeq(rights <CHOICE, CH, A, B>(ma.AsEnumerable()));
public static ImmutableArray <Either <T, Exception> > ToArray <T>(this TryOption <T> self) => Prelude.toArray(self.AsEnumerable());
public T[] ToArray() => Prelude.toArray(AsEnumerable());
public Either <L, T> ToEither <L>(Func <L> Left) => IsSome ? Prelude.Right <L, T>(Value) : Prelude.Left <L, T>(Left());
public static async Task <Seq <B> > rightsUnsafeAsync <CHOICE, CH, A, B>(Seq <CH> ma) where CHOICE : struct, ChoiceUnsafeAsync <CH, A, B> => Prelude.toSeq(await rightsUnsafeAsync <CHOICE, CH, A, B>(ma.AsEnumerable()).ConfigureAwait(false));
public Either <L, T> ToEither <L>(L defaultLeftValue) => IsSome ? Prelude.Right <L, T>(Value) : Prelude.Left <L, T>(defaultLeftValue);
public Seq <A> ToSeq() => Prelude.Seq(this);
/// <summary> /// Safe pop /// </summary> /// <returns>Tuple of popped stack and optional top-of-stack value</returns> public Tuple <Stck <T>, Option <T> > TryPop() => Count > 0 ? Tuple.Create(tail, Prelude.Some(value)) : Tuple.Create <Stck <T>, Option <T> >(this, Prelude.None);
/// <summary> /// Safely use a disposable resource /// </summary> /// <param name="Acq">Acquire resource</param> /// <param name="Use">Use resource</param> public static Eff <RT, R> Use <RT, H, R>(this Eff <RT, H> Acq, Func <H, Eff <RT, R> > Use) where RT : struct, HasCancel <RT> where H : IDisposable => Prelude.use(Acq, Use);
public IImmutableList <T> ToList() => Prelude.toList(AsEnumerable());
private static Task <Either <PowershellFailure, VMDriveStorageSettings> > DriveConfigToDriveStorageSettings(int index, VirtualMachineDriveConfig driveConfig, VMStorageSettings storageSettings, HostSettings hostSettings) { const int controllerNumber = 0; //currently this will not be configurable, but keep it here at least as constant var controllerLocation = index; //later, when adding controller config support, we will have to add a logic to //set location relative to the free slots for each controller //if it is not a vhd, we only need controller settings if (driveConfig.Type != VirtualMachineDriveType.VHD) { VMDriveStorageSettings result; if (driveConfig.Type == VirtualMachineDriveType.DVD) { result = new VMDVdStorageSettings { ControllerNumber = controllerNumber, ControllerLocation = controllerLocation, Type = VirtualMachineDriveType.DVD }; } else { result = new VMDriveStorageSettings { ControllerNumber = controllerNumber, ControllerLocation = controllerLocation, Type = driveConfig.Type.GetValueOrDefault(VirtualMachineDriveType.PHD) }; } return(Prelude.RightAsync <PowershellFailure, VMDriveStorageSettings>(result).ToEither()); } //so far for the simple part, now the complicated case - a vhd disk... var projectName = Prelude.Some("default"); var environmentName = Prelude.Some("default"); var dataStoreName = Prelude.Some("default"); var storageIdentifier = Option <string> .None; var names = new StorageNames() { ProjectName = projectName, EnvironmentName = environmentName, DataStoreName = dataStoreName, }; if (storageIdentifier.IsNone) { storageIdentifier = storageSettings.StorageIdentifier; } return ((from resolvedPath in ResolveStorageBasePath(names, hostSettings.DefaultVirtualHardDiskPath).ToAsync() from identifier in storageIdentifier.ToEither(new PowershellFailure { Message = $"Unexpected missing storage identifier for disk '{driveConfig.Name}'." }) .ToAsync() .ToEither().ToAsync() let planned = new VMDiskStorageSettings { Type = driveConfig.Type.Value, StorageNames = names, StorageIdentifier = storageIdentifier, ParentPath = driveConfig.Template, Path = Path.Combine(resolvedPath, identifier), AttachPath = Path.Combine(Path.Combine(resolvedPath, identifier), $"{driveConfig.Name}.vhdx"), // ReSharper disable once StringLiteralTypo Name = driveConfig.Name, SizeBytes = driveConfig.Size.ToOption().Match(None: () => 1 * 1024L * 1024 * 1024, Some: s => s * 1024L * 1024 * 1024), ControllerNumber = controllerNumber, ControllerLocation = controllerLocation } select planned as VMDriveStorageSettings).ToEither()); }
public ImmutableArray <T> ToArray() => Prelude.toArray(AsEnumerable());
static Dispatch() { ProcessName broadcast = "broadcast"; ProcessName leastBusy = "least-busy"; ProcessName random = "random"; ProcessName roundRobin = "round-robin"; ProcessName first = "first"; ProcessName second = "second"; ProcessName third = "third"; ProcessName last = "last"; var processes = fun((ProcessId leaf) => { if (!leaf.IsValid) { return(new ProcessId[0]); } if (leaf.IsSelection) { return(leaf.GetSelection()); } if (leaf.Head().Name == "disp") { leaf = leaf.Skip(1); if (!leaf.IsValid) { return(new ProcessId[0]); } return(getFunc(leaf.Head().Name)(leaf.Skip(1))); } return(new ProcessId[1] { leaf }); }); // Broadcast Broadcast = register(broadcast, processes); // First First = register(first, leaf => processes(leaf).Take(1)); // Second Second = register(second, leaf => processes(leaf).Skip(1).Take(1)); // Third Third = register(third, leaf => processes(leaf).Skip(2).Take(1)); // Last Last = register(last, leaf => processes(leaf).Reverse().Take(1)); // Least busy LeastBusy = register(leastBusy, leaf => processes(leaf) .Map(pid => Tuple(inboxCount(pid), pid)) .OrderBy(tup => tup.Item1) .Map(tup => tup.Item2) .Take(1)); // Random Random = register(random, leaf => { var workers = processes(leaf).ToArray(); return(new ProcessId[1] { workers[Prelude.random(workers.Length)] }); }); // Round-robin object sync = new object(); Map <string, int> roundRobinState = Map.empty <string, int>(); RoundRobin = register(roundRobin, leaf => { var key = leaf.ToString(); var workers = processes(leaf).ToArray(); int index = 0; lock (sync) { roundRobinState = roundRobinState.AddOrUpdate(key, x => { index = x % workers.Length; return(x + 1); }, 0); } return(new ProcessId[1] { workers[index] }); }); }
/// <summary> /// Static ctor /// Sets up the default roles /// </summary> static Role() { ProcessName first = "role-first"; ProcessName second = "role-second"; ProcessName third = "role-third"; ProcessName last = "role-last"; ProcessName next = "role-next"; ProcessName prev = "role-prev"; ProcessName broadcast = "role-broadcast"; ProcessName leastBusy = "role-least-busy"; ProcessName random = "role-random"; ProcessName roundRobin = "role-round-robin"; var nextNode = fun((bool fwd) => fun((ProcessId leaf) => { var self = leaf.Take(1).Name; var isNext = false; var nodeMap = Nodes(leaf); var nodes = fwd ? nodeMap.Values.Append(nodeMap.Values) : nodeMap.Values.Append(nodeMap.Values).Reverse(); //< TODO: Inefficient foreach (var node in nodes) { if (isNext) { return(new[] { ProcessId.Top[node.NodeName].Append(leaf.Skip(1)) }.AsEnumerable()); } if (node.NodeName == self) { isNext = true; } } return(new ProcessId[0].AsEnumerable()); })); // Next nextRoot = Dispatch.register(next, nextNode(true)); // Prev prevRoot = Dispatch.register(prev, nextNode(false)); // First First = Dispatch.register(first, leaf => NodeIds(leaf).Take(1)); // Second Second = Dispatch.register(second, leaf => NodeIds(leaf).Skip(1).Take(1)); // Third Third = Dispatch.register(third, leaf => NodeIds(leaf).Skip(2).Take(1)); // Last Last = Dispatch.register(last, leaf => NodeIds(leaf).Reverse().Take(1)); // Broadcast Broadcast = Dispatch.register(broadcast, NodeIds); // Least busy LeastBusy = Dispatch.register(leastBusy, leaf => NodeIds(leaf) .Map(pid => Tuple(inboxCount(pid), pid)) .OrderBy(tup => tup.Item1) .Map(tup => tup.Item2) .Take(1)); // Random Random = Dispatch.register(random, leaf => { var workers = NodeIds(leaf).ToArray(); return(new ProcessId[1] { workers[Prelude.random(workers.Length)] }); }); // Round-robin object sync = new object(); Map <string, int> roundRobinState = Map.empty <string, int>(); RoundRobin = Dispatch.register(roundRobin, leaf => { var key = leaf.ToString(); var workers = NodeIds(leaf).ToArray(); int index = 0; lock (sync) { roundRobinState = roundRobinState.AddOrUpdate(key, x => { index = x % workers.Length; return(x + 1); }, 0); } return(new ProcessId[1] { workers[index] }); }); }
public Option <T> TryPeek() => Count > 0 ? Prelude.Some(value) : Prelude.None;
public Lst <T> ToList() => Prelude.toList(AsEnumerable());