public void Validate(ClusterDefinition clusterDefinition) { Covenant.Requires <ArgumentNullException>(clusterDefinition != null, nameof(clusterDefinition)); switch (Environment) { case HostingEnvironments.Aws: if (Aws == null) { throw new ClusterDefinitionException($"[{nameof(HostingOptions)}.{nameof(Aws)}] must be initialized when cloud provider is [{Environment}]."); } Aws.Validate(clusterDefinition); break; case HostingEnvironments.Azure: if (Azure == null) { throw new ClusterDefinitionException($"[{nameof(HostingOptions)}.{nameof(Azure)}] must be initialized when cloud provider is [{Environment}]."); } Azure.Validate(clusterDefinition); break; case HostingEnvironments.Google: if (Google == null) { throw new ClusterDefinitionException($"[{nameof(HostingOptions)}.{nameof(Google)}] must be initialized when cloud provider is [{Environment}]."); } Google.Validate(clusterDefinition); break; case HostingEnvironments.HyperV: HyperV = HyperV ?? new HyperVOptions(); HyperV.Validate(clusterDefinition); break; case HostingEnvironments.HyperVLocal: HyperVDev = HyperVDev ?? new LocalHyperVOptions(); HyperVDev.Validate(clusterDefinition); break; case HostingEnvironments.Machine: Machine = Machine ?? new MachineOptions(); Machine.Validate(clusterDefinition); break; case HostingEnvironments.XenServer: XenServer = XenServer ?? new XenServerOptions(); XenServer.Validate(clusterDefinition); break; default: throw new NotImplementedException(); } if (!string.IsNullOrWhiteSpace(VmNamePrefix)) { if (!ClusterDefinition.IsValidName(VmNamePrefix)) { throw new ClusterDefinitionException($"[{nameof(HostingOptions)}.{nameof(VmNamePrefix)}={VmNamePrefix}] must include only letters, digits, underscores, or periods."); } } }
/// <summary> /// Validates the node definition. /// </summary> /// <param name="clusterDefinition">The cluster definition.</param> /// <exception cref="ArgumentException">Thrown if the definition is not valid.</exception> public void Validate(ClusterDefinition clusterDefinition) { Covenant.Requires <ArgumentNullException>(clusterDefinition != null, nameof(clusterDefinition)); Vm = Vm ?? new VmNodeOptions(); var nodeDefinitionPrefix = $"{nameof(ClusterDefinition.NodeDefinitions)}"; // Ensure that the labels are wired up to the parent node. if (Labels == null) { Labels = new NodeLabels(this); } else { Labels.Node = this; } if (Name == null) { throw new ClusterDefinitionException($"The [{nodeDefinitionPrefix}.{nameof(Name)}] property is required."); } if (!ClusterDefinition.IsValidName(Name)) { throw new ClusterDefinitionException($"The [{nodeDefinitionPrefix}.{nameof(Name)}={Name}] property is not valid. Only letters, numbers, periods, dashes, and underscores are allowed."); } if (name == "localhost") { throw new ClusterDefinitionException($"The [{nodeDefinitionPrefix}.{nameof(Name)}={Name}] property is not valid. [localhost] is reserved."); } if (Name.StartsWith("neon-", StringComparison.InvariantCultureIgnoreCase) && !clusterDefinition.IsSpecialNeonCluster) { throw new ClusterDefinitionException($"The [{nodeDefinitionPrefix}.{nameof(Name)}={Name}] property is not valid because node names starting with [neon-] are reserved."); } if (name.Equals("cluster", StringComparison.InvariantCultureIgnoreCase)) { // $hack(jefflill): // // The node name [cluster] is reserved because we want to persist the // global cluster log file as [cluster.log] and we don't want this to // conflict with any of the node log files. // // See: KubeConst.ClusterSetupLogName throw new ClusterDefinitionException($"The [{nodeDefinitionPrefix}.{nameof(Name)}={Name}] property is not valid because the node name [cluster] is reserved."); } if (string.IsNullOrEmpty(Role)) { Role = NodeRole.Worker; } if (!Role.Equals(NodeRole.ControlPlane, StringComparison.InvariantCultureIgnoreCase) && !Role.Equals(NodeRole.Worker, StringComparison.InvariantCultureIgnoreCase)) { throw new ClusterDefinitionException($"[{nodeDefinitionPrefix}.{nameof(Name)}={Name}] has invalid [{nameof(Role)}={Role}]. This must be [{NodeRole.ControlPlane}] or [{NodeRole.Worker}]."); } // We don't need to check the node address for cloud providers. if (clusterDefinition.Hosting.IsOnPremiseProvider) { if (string.IsNullOrEmpty(Address)) { throw new ClusterDefinitionException($"[{nodeDefinitionPrefix}.{nameof(Name)}={Name}] requires [{nameof(Address)}] when hosting in an on-premise facility."); } if (!NetHelper.TryParseIPv4Address(Address, out var nodeAddress)) { throw new ClusterDefinitionException($"[{nodeDefinitionPrefix}.{nameof(Name)}={Name}] has invalid IP address [{Address}]."); } } switch (clusterDefinition.Hosting.Environment) { case HostingEnvironment.Aws: Aws = Aws ?? new AwsNodeOptions(); Aws.Validate(clusterDefinition, this.Name); break; case HostingEnvironment.Azure: Azure = Azure ?? new AzureNodeOptions(); Azure.Validate(clusterDefinition, this.Name); break; case HostingEnvironment.BareMetal: // No machine options to check at this time. break; case HostingEnvironment.Google: // $todo(jefflill: Implement this break; case HostingEnvironment.HyperV: case HostingEnvironment.XenServer: Vm = Vm ?? new VmNodeOptions(); Vm.Validate(clusterDefinition, this.Name); break; default: throw new NotImplementedException($"Hosting environment [{clusterDefinition.Hosting.Environment}] hosting option check is not implemented."); } }
/// <summary> /// Validates the options and also ensures that all <c>null</c> properties are /// initialized to their default values. /// </summary> /// <param name="clusterDefinition">The cluster definition.</param> /// <exception cref="ClusterDefinitionException">Thrown if the definition is not valid.</exception> public void Validate(ClusterDefinition clusterDefinition) { Covenant.Requires <ArgumentNullException>(clusterDefinition != null, nameof(clusterDefinition)); var vmHostingOptionsPrefix = $"{nameof(ClusterDefinition.Hosting)}"; // Validate the VM name prefix. if (!string.IsNullOrWhiteSpace(NamePrefix)) { if (!ClusterDefinition.IsValidName(NamePrefix)) { throw new ClusterDefinitionException($"[{nameof(HostingOptions)}.{nameof(NamePrefix)}={NamePrefix}] must include only letters, digits, underscores, or periods."); } } if (Cores <= 0) { throw new ClusterDefinitionException($"[{nameof(HyperVHostingOptions)}.{nameof(Cores)}={Cores}] must be positive."); } Memory = Memory ?? DefaultMemory; OsDisk = OsDisk ?? DefaultOsDisk; Hosts = Hosts ?? new List <HypervisorHost>(); ClusterDefinition.ValidateSize(Memory, this.GetType(), $"{vmHostingOptionsPrefix}.{nameof(Memory)}"); ClusterDefinition.ValidateSize(OsDisk, this.GetType(), $"{vmHostingOptionsPrefix}.{nameof(OsDisk)}"); ClusterDefinition.ValidateSize(OpenEbsDisk, this.GetType(), $"{vmHostingOptionsPrefix}.{nameof(OpenEbsDisk)}"); // 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 clusterDefinition.Hosting.Vm.Hosts) { if (hostNameSet.Contains(vmHost.Name)) { throw new ClusterDefinitionException($"One or more hypervisor hosts are assigned the [{vmHost.Name}] name."); } hostNameSet.Add(vmHost.Name); if (hostAddressSet.Contains(vmHost.Address)) { throw new ClusterDefinitionException($"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. if (clusterDefinition.Hosting.IsHostedHypervisor) { foreach (var vmHost in Hosts) { vmHost.Validate(clusterDefinition); } } }
public void Validate(ClusterDefinition clusterDefinition) { Covenant.Requires <ArgumentNullException>(clusterDefinition != null); // Ensure that the labels are wired up to the parent node. if (Labels == null) { Labels = new NodeLabels(this); } else { Labels.Node = this; } if (Name == null) { throw new ClusterDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}] property is required."); } if (!ClusterDefinition.IsValidName(Name)) { throw new ClusterDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}={Name}] property is not valid. Only letters, numbers, periods, dashes, and underscores are allowed."); } if (name == "localhost") { throw new ClusterDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}={Name}] property is not valid. [localhost] is reserved."); } if (Name.StartsWith("neon-", StringComparison.InvariantCultureIgnoreCase)) { throw new ClusterDefinitionException($"The [{nameof(NodeDefinition)}.{nameof(Name)}={Name}] property is not valid because node names starting with [node-] are reserved."); } if (clusterDefinition.Hosting.IsOnPremiseProvider) { if (string.IsNullOrEmpty(PrivateAddress)) { throw new ClusterDefinitionException($"Node [{Name}] requires [{nameof(PrivateAddress)}] when hosting in an on-premise facility."); } if (!IPAddress.TryParse(PrivateAddress, out var nodeAddress)) { throw new ClusterDefinitionException($"Node [{Name}] has invalid IP address [{PrivateAddress}]."); } } if (Azure != null) { Azure.Validate(clusterDefinition, this.Name); } if (clusterDefinition.Hosting.IsRemoteHypervisorProvider) { if (string.IsNullOrEmpty(VmHost)) { throw new ClusterDefinitionException($"Node [{Name}] does not specify a hypervisor [{nameof(NodeDefinition)}.{nameof(NodeDefinition.VmHost)}]."); } else if (clusterDefinition.Hosting.VmHosts.FirstOrDefault(h => h.Name.Equals(VmHost, StringComparison.InvariantCultureIgnoreCase)) == null) { throw new ClusterDefinitionException($"Node [{Name}] references hypervisor [{VmHost}] which is defined in [{nameof(HostingOptions)}={nameof(HostingOptions.VmHosts)}]."); } } if (VmMemory != null) { ClusterDefinition.ValidateSize(VmMemory, this.GetType(), nameof(VmMemory)); } if (VmDisk != null) { ClusterDefinition.ValidateSize(VmDisk, this.GetType(), nameof(VmDisk)); } }