/// <summary> /// Returns the maximum number of bytes to disk allocate to for this node when /// hosted on a hypervisor. /// </summary> /// <param name="hiveDefinition">The hive definition.</param> /// <returns>The size in bytes.</returns> public long GetVmDisk(HiveDefinition hiveDefinition) { if (!string.IsNullOrEmpty(VmDisk)) { return(HiveDefinition.ValidateSize(VmDisk, this.GetType(), nameof(VmDisk))); } else { return(HiveDefinition.ValidateSize(hiveDefinition.Hosting.VmDisk, hiveDefinition.Hosting.GetType(), nameof(hiveDefinition.Hosting.VmDisk))); } }
/// <summary> /// Returns the minimum number of bytes of memory allocate to for this node when /// hosted on a hypervisor. /// </summary> /// <param name="hiveDefinition">The hive definition.</param> /// <returns>The size in bytes.</returns> public long GetVmMinimumMemory(HiveDefinition hiveDefinition) { if (!string.IsNullOrEmpty(VmMinimumMemory)) { return(HiveDefinition.ValidateSize(VmMinimumMemory, this.GetType(), nameof(VmMinimumMemory))); } else if (!string.IsNullOrEmpty(hiveDefinition.Hosting.VmMinimumMemory)) { return(HiveDefinition.ValidateSize(hiveDefinition.Hosting.VmMinimumMemory, hiveDefinition.Hosting.GetType(), nameof(hiveDefinition.Hosting.VmMinimumMemory))); } else { // Return [VmMemory] otherwise. return(GetVmMemory(hiveDefinition)); } }
/// <summary> /// Returns the size in bytes of RAM to allocate to the MDS cache /// on this node integrated Ceph storage cluster is enabled and /// MDS is deployed to the node. /// </summary> /// <param name="hiveDefinition">The hive definition.</param> /// <returns>The size in bytes or zero if Ceph is not enabled.</returns> public long GetCephMDSCacheSize(HiveDefinition hiveDefinition) { if (!hiveDefinition.HiveFS.Enabled) { return(0); } if (Labels.CephMDSCacheSizeMB > 0) { return(Labels.CephMDSCacheSizeMB * NeonHelper.Mega); } else { Labels.CephMDSCacheSizeMB = (int)(HiveDefinition.ValidateSize(hiveDefinition.HiveFS.MDSCacheSize, hiveDefinition.Hosting.GetType(), nameof(hiveDefinition.HiveFS.MDSCacheSize)) / NeonHelper.Mega); return((long)Labels.CephMDSCacheSizeMB * NeonHelper.Mega); } }
/// <summary> /// Validates the options and also ensures that all <c>null</c> properties are /// initialized to their default values. /// </summary> /// <param name="hiveDefinition">The hive definition.</param> /// <exception cref="HiveDefinitionException">Thrown if the definition is not valid.</exception> public void Validate(HiveDefinition hiveDefinition) { if (PublicCacheReplicas <= 0) { throw new HiveDefinitionException($"[{nameof(ProxyOptions)}.{nameof(PublicCacheReplicas)}={PublicCacheReplicas}] must be at least [1]."); } if (HiveDefinition.ValidateSize(PublicCacheSize, this.GetType(), nameof(PublicCacheSize)) < 50 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(PublicCacheSize)}={PublicCacheSize}] cannot be less than [50MB]."); } if (PrivateCacheReplicas <= 0) { throw new HiveDefinitionException($"[{nameof(ProxyOptions)}.{nameof(PrivateCacheReplicas)}={PrivateCacheReplicas}] must be at least [1]."); } if (HiveDefinition.ValidateSize(PrivateCacheSize, this.GetType(), nameof(PrivateCacheSize)) < 50 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(PrivateCacheSize)}={PrivateCacheSize}] cannot be less than [50MB]."); } }
/// <summary> /// Validates the options and also ensures that all <c>null</c> properties are /// initialized to their default values. /// </summary> /// <param name="hiveDefinition">The hive definition.</param> /// <exception cref="HiveDefinitionException">Thrown if the definition is not valid.</exception> public void Validate(HiveDefinition hiveDefinition) { if (!Enabled) { return; } VolumePluginPackage = VolumePluginPackage ?? defaultVolumePluginPackage; if (string.IsNullOrEmpty(VolumePluginPackage) || !Uri.TryCreate(VolumePluginPackage, UriKind.Absolute, out var uri)) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(VolumePluginPackage)}={VolumePluginPackage}] must be set to a valid package URL."); } Release = Release ?? defaultRelease; Release = Release.ToLowerInvariant(); if (!SupportedReleases.Contains(Release)) { throw new HiveDefinitionException($"[{Release}] is not a supported Ceph release."); } // Examine the Ceph related labels for the hive nodes to verify that any // specified Ceph service assignments are reasonable. We will also try to // automatically assign Ceph services to nodes when there are no explicit // assignments. // $hack(jeff.lill): // // It's not super clean to be doing this here but it's easy and I believe // I've already done this sort of thing elsewhere. var cephMONCount = hiveDefinition.Nodes.Count(n => n.Labels.CephMON); var cephOSDCount = hiveDefinition.Nodes.Count(n => n.Labels.CephOSD); var cephMDSCount = hiveDefinition.Nodes.Count(n => n.Labels.CephMDS); if (cephMONCount == 0) { // No Ceph monitor/manager nodes are explicitly assigned so we're going to // automatically place these on the hive managers. foreach (var node in hiveDefinition.Nodes.Where(n => n.IsManager)) { node.Labels.CephMON = true; } } if (cephOSDCount == 0) { // No Ceph OSD nodes are explicitly assigned. // // If the hive has at least three workers, we'll provision the // OSDs on all of the workers. // // If there are fewer than three workers, we'll provision ODSs on // all managers and all workers (AKA the Swarm nodes). if (hiveDefinition.Workers.Count() >= 3) { foreach (var node in hiveDefinition.Workers) { node.Labels.CephOSD = true; } } else { foreach (var node in hiveDefinition.Swarm) { node.Labels.CephOSD = true; } } } if (cephMONCount == 0) { // No Ceph MDS nodes are explicitly assigned so we're going to provision // these on the Ceph Monitor servers. foreach (var node in hiveDefinition.Nodes.Where(n => n.Labels.CephMON)) { node.Labels.CephMDS = true; } } // Recount the Ceph component instances to account for any the automatic // provisioning assignments that may have been performed above. cephMONCount = hiveDefinition.Nodes.Count(n => n.Labels.CephMON); cephOSDCount = hiveDefinition.Nodes.Count(n => n.Labels.CephOSD); cephMDSCount = hiveDefinition.Nodes.Count(n => n.Labels.CephMDS); // Validate the properties. if (string.IsNullOrWhiteSpace(Release)) { Release = defaultRelease; } if (Release == string.Empty) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(Release)}={Release}] is not valid. Please specify something like [{defaultRelease}]."); } if (HiveDefinition.ValidateSize(OSDDriveSize, this.GetType(), nameof(OSDDriveSize)) < NeonHelper.Giga) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDDriveSize)}={OSDDriveSize}] cannot be less than [1GB]."); } if (HiveDefinition.ValidateSize(OSDCacheSize, this.GetType(), nameof(OSDCacheSize)) < 64 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDCacheSize)}={OSDCacheSize}] cannot be less than [64MB]."); } if (HiveDefinition.ValidateSize(OSDJournalSize, this.GetType(), nameof(OSDJournalSize)) < 64 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDJournalSize)}={OSDJournalSize}] cannot be less than [64MB]."); } if (HiveDefinition.ValidateSize(OSDObjectSizeMax, this.GetType(), nameof(OSDObjectSizeMax)) < 64 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDObjectSizeMax)}={OSDObjectSizeMax}] cannot be less than [64MB]."); } if (HiveDefinition.ValidateSize(MDSCacheSize, this.GetType(), nameof(MDSCacheSize)) < 64 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(MDSCacheSize)}={MDSCacheSize}] cannot be less than [64MB]."); } if (cephMONCount == 0) { throw new HiveDefinitionException($"Ceph storage cluster requires at least one monitor node."); } if (cephOSDCount == 0) { throw new HiveDefinitionException($"Ceph storage cluster requires at least one OSD (data) node."); } if (cephMDSCount == 0) { throw new HiveDefinitionException($"Ceph storage cluster requires at least one MDS (metadata) node."); } if (OSDReplicaCount == 0) { // Set a reasonable default. OSDReplicaCount = Math.Min(3, cephOSDCount); } if (OSDReplicaCount < 0) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDReplicaCount)}={OSDReplicaCount}] cannot be less than zero."); } if (OSDReplicaCount > cephOSDCount) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDReplicaCount)}={OSDReplicaCount}] cannot be greater than the number of OSD nodes [{cephOSDCount}]."); } if (OSDReplicaCountMin == 0) { // Set a reasonable default. if (OSDReplicaCount == 1) { OSDReplicaCountMin = 1; } else { OSDReplicaCountMin = OSDReplicaCount - 1; } } if (OSDReplicaCountMin < 0) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDReplicaCountMin)}={OSDReplicaCountMin}] cannot be less than zero."); } if (OSDReplicaCountMin > OSDReplicaCount) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDReplicaCountMin)}={OSDReplicaCountMin}] cannot be less than [{nameof(OSDReplicaCount)}={OSDReplicaCount}]."); } if (OSDReplicaCountMin > cephOSDCount) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDReplicaCountMin)}={OSDReplicaCountMin}] cannot be greater than the number of OSD nodes [{cephOSDCount}]."); } if (OSDPlacementGroups < 8) { throw new HiveDefinitionException($"[{nameof(HiveFSOptions)}.{nameof(OSDPlacementGroups)}={OSDPlacementGroups}] cannot be less than [8]."); } }
/// <inheritdoc/> public override bool Provision(bool force) { // $todo(jeff.lill): // // I'm not entirely sure that the [force] option makes sense for // production hives and especially when there are pet nodes. // // Perhaps it would make more sense to replace this with a // [neon hive remove] command. // // https://github.com/jefflill/NeonForge/issues/156 this.forceVmOverwrite = force; if (IsProvisionNOP) { // There's nothing to do here. return(true); } // Update the node labels with the actual capabilities of the // virtual machines being provisioned. foreach (var node in hive.Definition.Nodes) { if (string.IsNullOrEmpty(node.Labels.PhysicalMachine)) { node.Labels.PhysicalMachine = Environment.MachineName; } if (node.Labels.ComputeCores == 0) { node.Labels.ComputeCores = hive.Definition.Hosting.VmProcessors; } if (node.Labels.ComputeRamMB == 0) { node.Labels.ComputeRamMB = (int)(HiveDefinition.ValidateSize(hive.Definition.Hosting.VmMemory, typeof(HostingOptions), nameof(HostingOptions.VmMemory)) / NeonHelper.Mega); } if (node.Labels.StorageCapacityGB == 0) { node.Labels.StorageCapacityGB = (int)(node.GetVmMemory(hive.Definition) / NeonHelper.Giga); } } // If a public address isn't explicitly specified, we'll assume that the // tool is running inside the network and we can access the private address. foreach (var node in hive.Definition.Nodes) { if (string.IsNullOrEmpty(node.PublicAddress)) { node.PublicAddress = node.PrivateAddress; } } // Perform the provisioning operations. controller = new SetupController <NodeDefinition>($"Provisioning [{hive.Definition.Name}] hive", hive.Nodes) { ShowStatus = this.ShowStatus, MaxParallel = 1 // We're only going to provision one VM at a time on a local Hyper-V instance. }; controller.AddGlobalStep("prepare hyper-v", () => PrepareHyperV()); controller.AddStep("create virtual machines", (node, stepDelay) => ProvisionVM(node)); controller.AddGlobalStep(string.Empty, () => Finish(), quiet: true); if (!controller.Run()) { Console.Error.WriteLine("*** ERROR: One or more configuration steps failed."); return(false); } return(true); }
public void Validate(HiveDefinition hiveDefinition) { Covenant.Requires <ArgumentNullException>(hiveDefinition != null); Labels = Labels ?? new NodeLabels(this); HostGroups = HostGroups ?? new List <string>(); if (Name == null) { throw new HiveDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}] property is required."); } if (!HiveDefinition.IsValidName(Name)) { throw new HiveDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}={Name}] property is not valid. Only letters, numbers, periods, dashes, and underscores are allowed."); } if (name == "localhost") { throw new HiveDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}={Name}] property is not valid. [localhost] is reserved."); } if (Name.StartsWith("neon-", StringComparison.InvariantCultureIgnoreCase)) { throw new HiveDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}={Name}] property is not valid because node names starting with [node-] are reserved."); } if (Name.Equals(HiveDefinition.VirtualSwarmManagerName, StringComparison.InvariantCultureIgnoreCase)) { throw new HiveDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}={Name}] property is not valid. [{HiveDefinition.VirtualSwarmManagerName}] is reserved for targeting Swarm related Ansible tasks."); } if (hiveDefinition.Hosting.IsOnPremiseProvider) { if (string.IsNullOrEmpty(PrivateAddress)) { throw new HiveDefinitionException($"Node [{Name}] requires [{nameof(PrivateAddress)}] when hosting in an on-premise facility."); } if (!IPAddress.TryParse(PrivateAddress, out var nodeAddress)) { throw new HiveDefinitionException($"Node [{Name}] has invalid IP address [{PrivateAddress}]."); } } if (IsManager && hiveDefinition.Hosting.IsOnPremiseProvider && hiveDefinition.Vpn.Enabled) { if (!NetHelper.IsValidPort(VpnFrontendPort)) { throw new HiveDefinitionException($"Manager node [{Name}] has [{nameof(VpnFrontendPort)}={VpnFrontendPort}] which is not a valid network port."); } } Labels.Validate(hiveDefinition); foreach (var group in HostGroups) { if (string.IsNullOrWhiteSpace(group)) { throw new HiveDefinitionException($"Node [{Name}] assigns an empty group in [{nameof(HostGroups)}]."); } else if (HiveHostGroups.BuiltIn.Contains(group)) { throw new HiveDefinitionException($"Node [{Name}] assigns the standard [{group}] in [{nameof(HostGroups)}]. Standard groups cannot be explicitly assigned since [neon-cli] handles them automatically."); } else if (!groupNameRegex.IsMatch(group)) { throw new HiveDefinitionException($"Node [{Name}] assigns the invalid group [{group}] in [{nameof(HostGroups)}]. Group names must start with a letter and then can be followed by zero or more letters, digits, dashes, and underscores."); } } if (Azure != null) { Azure.Validate(hiveDefinition, this.Name); } if (hiveDefinition.Hosting.IsRemoteHypervisorProvider) { if (string.IsNullOrEmpty(VmHost)) { throw new HiveDefinitionException($"Node [{Name}] does not specify a hypervisor [{nameof(NodeDefinition)}.{nameof(NodeDefinition.VmHost)}]."); } else if (hiveDefinition.Hosting.VmHosts.FirstOrDefault(h => h.Name.Equals(VmHost, StringComparison.InvariantCultureIgnoreCase)) == null) { throw new HiveDefinitionException($"Node [{Name}] references hypervisor [{VmHost}] which is defined in [{nameof(HostingOptions)}={nameof(HostingOptions.VmHosts)}]."); } } if (VmMemory != null) { HiveDefinition.ValidateSize(VmMemory, this.GetType(), nameof(VmMemory)); } if (VmMinimumMemory != null) { HiveDefinition.ValidateSize(VmMinimumMemory, this.GetType(), nameof(VmMinimumMemory)); } if (VmDisk != null) { HiveDefinition.ValidateSize(VmDisk, this.GetType(), nameof(VmDisk)); } }
internal void ValidateHypervisor(HiveDefinition hiveDefinition, bool remoteHypervisors) { Covenant.Requires <ArgumentNullException>(hiveDefinition != null); if (VmProcessors <= 0) { throw new HiveDefinitionException($"[{nameof(LocalHyperVOptions)}.{nameof(VmProcessors)}={VmProcessors}] must be positive."); } VmMemory = VmMemory ?? DefaultVmMemory; VmMinimumMemory = VmMinimumMemory ?? VmMemory; VmDisk = VmDisk ?? DefaultVmMinimumMemory; VmHosts = VmHosts ?? new List <VmHost>(); HiveDefinition.ValidateSize(VmMemory, this.GetType(), nameof(VmMemory)); HiveDefinition.ValidateSize(VmMinimumMemory, this.GetType(), nameof(VmMinimumMemory)); HiveDefinition.ValidateSize(VmDisk, this.GetType(), nameof(VmDisk)); // Verify that the hypervisor host machines have unique names and addresses. var hostNameSet = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); var hostAddressSet = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); foreach (var vmHost in hiveDefinition.Hosting.VmHosts) { if (hostNameSet.Contains(vmHost.Name)) { throw new HiveDefinitionException($"One or more hypervisor hosts are assigned the [{vmHost.Name}] name."); } hostNameSet.Add(vmHost.Name); if (hostAddressSet.Contains(vmHost.Address)) { throw new HiveDefinitionException($"One or more hypervisor hosts are assigned the [{vmHost.Address}] address."); } hostAddressSet.Add(vmHost.Address); } // Ensure that some hypervisor hosts have been specified if we're deploying to remote // hypervisors and also that each node definition specifies a host hyoervisor. if (remoteHypervisors) { if (hiveDefinition.Hosting.VmHosts.Count == 0) { throw new HiveDefinitionException($"At least one host XenServer must be specified in [{nameof(HostingOptions)}.{nameof(HostingOptions.VmHosts)}]."); } foreach (var vmHost in VmHosts) { vmHost.Validate(hiveDefinition); } foreach (var node in hiveDefinition.NodeDefinitions.Values) { if (string.IsNullOrEmpty(node.VmHost)) { throw new HiveDefinitionException($"Node [{node.Name}] does not specify a host hypervisor with [{nameof(NodeDefinition.VmHost)}]."); } if (!hostNameSet.Contains(node.VmHost)) { throw new HiveDefinitionException($"Node [{node.Name}] has [{nameof(VmHost)}={node.VmHost}] which specifies a hypervisor host that was not found in [{nameof(HostingOptions)}.{nameof(HostingOptions.VmHosts)}]."); } } } }
/// <summary> /// Validates the options and also ensures that all <c>null</c> properties are /// initialized to their default values. /// </summary> /// <param name="hiveDefinition">The hive definition.</param> /// <exception cref="HiveDefinitionException">Thrown if the definition is not valid.</exception> public void Validate(HiveDefinition hiveDefinition) { RamLimit = RamLimit ?? defaultRamLimit; RamHighWatermark = RamHighWatermark ?? defaultRamHighWatermark; SysadminPassword = SysadminPassword ?? defaultPassword; NeonPassword = NeonPassword ?? defaultPassword; AppPassword = AppPassword ?? defaultPassword; PartitionMode = PartitionMode ?? defaultPartitionMode; PartitionMode = PartitionMode.ToLowerInvariant(); if (string.IsNullOrWhiteSpace(ErlangCookie)) { ErlangCookie = NeonHelper.GetRandomPassword(20); } // RamHighWatermark: We're going to keep things simple and convert relative // percentage values to a number between [0..1] and we're going to convert // absolute bytes units into a simple number (without units). This simplifies // the RabbitMQ Docker entrypoint script so all it needs to do is look for a // decimal point to identify a relative limit vs. an absolute limit. The // script won't need to do percentage or unit conversions. if (RamHighWatermark.EndsWith("%")) { // RamHighWatermark is a relative percentage. var numberPart = RamHighWatermark.Substring(0, RamHighWatermark.Length - 1); if (!double.TryParse(numberPart, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var number) || number <= 0.0 || number >= 100.0) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(RamHighWatermark)}={RamHighWatermark}] is not within: 0% < {nameof(RamHighWatermark)} <= 100%"); } RamHighWatermark = (number / 100).ToString("0.00#", CultureInfo.InvariantCulture); } else if (RamHighWatermark.Contains('.')) { // RamHighWatermark is a relative number between [0..1]. if (!double.TryParse(RamHighWatermark, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var number) || number <= 0.0 || number >= 1.0) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(RamHighWatermark)}={RamHighWatermark}] is not within: 0.0 < {nameof(RamHighWatermark)} <= 1.0"); } RamHighWatermark = number.ToString("0.00#", CultureInfo.InvariantCulture); } else { // RamHighWaterMark is absolute. var number = HiveDefinition.ValidateSize(RamHighWatermark, this.GetType(), nameof(RamHighWatermark)); if (number <= 0) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(RamHighWatermark)}={RamHighWatermark}] must be greater than 0."); } RamHighWatermark = number.ToString(); } var ramSize = HiveDefinition.ValidateSize(RamLimit, this.GetType(), nameof(RamLimit)); if (Precompile && ramSize < 500 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(RamLimit)}={RamLimit}] cannot be less than [500MB] when [{nameof(HiveMQOptions)}.{nameof(Precompile)}={Precompile}]."); } else if (!Precompile && ramSize < 250 * NeonHelper.Mega) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(RamLimit)}={RamLimit}] cannot be less than [250MB] when [{nameof(HiveMQOptions)}.{nameof(Precompile)}={Precompile}]."); } // DiskFreeLimit: We're going to keep things simple and convert relative // percentage values to a number between [0..1] and we're going to convert // absolute bytes units into a simple number (without units). This simplifies // the RabbitMQ Docker entrypoint script so all it needs to do is look for a // decimal point to identify a relative limit vs. an absolute limit. The // script won't need to do percentage or unit conversions. if (string.IsNullOrWhiteSpace(DiskFreeLimit)) { DiskFreeLimit = ((2 * ramSize) + (1 * NeonHelper.Giga)).ToString(); } if (DiskFreeLimit.EndsWith("%")) { // DiskFreeLimit is a relative percentage. var numberPart = DiskFreeLimit.Substring(0, DiskFreeLimit.Length - 1); if (!double.TryParse(numberPart, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var number) || number <= 0.0 || number >= 100.0) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(DiskFreeLimit)}={DiskFreeLimit}] is not within: 0% < {nameof(DiskFreeLimit)} <= 100%"); } DiskFreeLimit = (number / 100).ToString("0.00#", CultureInfo.InvariantCulture); } else if (DiskFreeLimit.Contains('.')) { // DiskFreeLimit is a relative number between [0..1]. if (!double.TryParse(DiskFreeLimit, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var number) || number <= 0.0 || number >= 1.0) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(DiskFreeLimit)}={DiskFreeLimit}] is not within: 0.0 < {nameof(DiskFreeLimit)} <= 1.0"); } DiskFreeLimit = number.ToString("0.00#", CultureInfo.InvariantCulture); } else { // DiskFreeLimit is absolute. var number = HiveDefinition.ValidateSize(DiskFreeLimit, this.GetType(), nameof(DiskFreeLimit)); if (number < 1 * NeonHelper.Giga) { throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(DiskFreeLimit)}={DiskFreeLimit}] must be greater than [1GB]."); } DiskFreeLimit = number.ToString(); } switch (PartitionMode) { case "autoheal": case "pause_minority": case "pause_if_all_down": break; default: throw new HiveDefinitionException($"[{nameof(HiveMQOptions)}.{nameof(PartitionMode)}={PartitionMode}] is not valid. Specify one of [autoheal], [pause_minority], or [pause_if_all_down]."); } // We need to assign hive nodes to host the RabbitMQ instances. We're going to do // this by examining and possibly setting the RabbitMQ and RabbitMQManager node labels. // If no hive nodes have this label set, then we'll set both of these for all manager // nodes. Otherwise, we'll deploy to the nodes marked with [RabbitMQ=true]. // // Note that we always need to deploy at least one node enabling the management // plugin. If [RabbitMQManager] is not set for any nodes then we'll set it for // the first node (as sorted by name). // // Note also that [RabbitMQManager=true] implies [RabbitMQ=true]. foreach (var node in hiveDefinition.Nodes.Where(n => n.Labels.HiveMQManager)) { node.Labels.HiveMQ = true; } if (hiveDefinition.Nodes.Count(n => n.Labels.HiveMQ) == 0) { foreach (var manager in hiveDefinition.Managers) { manager.Labels.HiveMQ = true; manager.Labels.HiveMQManager = true; } } else if (hiveDefinition.Nodes.Count(n => n.Labels.HiveMQManager) == 0) { var firstRabbitMQNode = hiveDefinition.Nodes.First(n => n.Labels.HiveMQ); firstRabbitMQNode.Labels.HiveMQManager = true; } }