/// <summary> /// Attempts to retrieve a named hive global setting as a <typeparamref name="T"/> /// deserialized from JSON. /// </summary> /// <typeparam name="T">The type being deserialized.</typeparam> /// <param name="name">The setting name.</param> /// <param name="output">Returns as the setting value.</param> /// <param name="strict">Optionally require that all input properties map to <typeparamref name="T"/> properties.</param> /// <returns><c>true</c> if the setting exists and was returned.</returns> /// <exception cref="FormatException">Thrown if the setting value could not be parsed.</exception> /// <remarks> /// <note> /// Well known hive setting names are defined in <see cref="HiveGlobals"/>. /// </note> /// </remarks> public bool TryGet <T>(string name, out T output, bool strict = false) { Covenant.Requires(!string.IsNullOrEmpty(name)); Covenant.Requires(HiveDefinition.IsValidName(name)); output = default(T); var key = $"{HiveConst.GlobalKey}/{name}"; var value = hive.Consul.Client.KV.GetStringOrDefault(key).Result; if (value == null) { return(false); } try { output = NeonHelper.JsonDeserialize <T>(value, strict); } catch { return(false); } return(true); }
/// <summary> /// Creates or updates a hive Docker string config. /// </summary> /// <param name="configName">The config name.</param> /// <param name="value">The config value.</param> /// <param name="options">Optional command run options.</param> /// <exception cref="HiveException">Thrown if the operation failed.</exception> public void Set(string configName, string value, RunOptions options = RunOptions.None) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(configName)); Covenant.Requires <ArgumentNullException>(value != null); Set(configName, Encoding.UTF8.GetBytes(value), options); }
/// <summary> /// Returns the Consul key for the named global. /// </summary> /// <param name="name"></param> /// <returns>The Consul key path.</returns> public string GetKey(string name) { Covenant.Requires(!string.IsNullOrEmpty(name)); Covenant.Requires(HiveDefinition.IsValidName(name)); return($"{HiveConst.GlobalKey}/{name}"); }
/// <summary> /// Removes a hive certificate if it exists. /// </summary> /// <param name="name">The certificate name.</param> public void Remove(string name) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(name)); hive.Vault.Client.DeleteAsync(HiveHelper.GetVaultCertificateKey(name)).Wait(); hive.SignalTrafficManagerUpdate(); }
/// <summary> /// Adds or updates a hive certificate. /// </summary> /// <param name="name">The certificate name.</param> /// <param name="certificate">The certificate.</param> /// <exception cref="ArgumentException">Thrown if the certificate is not valid.</exception> /// <remarks> /// <note> /// The <paramref name="certificate"/> must be fully parsed (it's /// <see cref="TlsCertificate.Parse()"/> method must have been called at /// some point to load the <see cref="TlsCertificate.Hosts"/>, /// <see cref="TlsCertificate.ValidFrom"/> and <see cref="TlsCertificate.ValidUntil"/> /// properties). /// </note> /// </remarks> public void Set(string name, TlsCertificate certificate) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(name)); Covenant.Requires <ArgumentNullException>(certificate != null); hive.Vault.Client.WriteJsonAsync(HiveHelper.GetVaultCertificateKey(name), certificate).Wait(); hive.SignalTrafficManagerUpdate(); }
/// <summary> /// Creates or updates a hive Docker object secret serialized as JSON. /// </summary> /// <typeparam name="T">The secret type.</typeparam> /// <param name="secretName">The secret name.</param> /// <param name="value">The secret value.</param> /// <param name="options">Optional command run options.</param> /// <exception cref="HiveException">Thrown if the operation failed.</exception> public void Set <T>(string secretName, T value, RunOptions options = RunOptions.None) where T : class, new() { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(secretName)); Covenant.Requires <ArgumentNullException>(value != null); Set(secretName, NeonHelper.JsonSerialize(value, Formatting.Indented), options); }
/// <summary> /// Returns a traffic manager rule if it exists. /// </summary> /// <param name="ruleName">The rule name.</param> /// <returns>The <see cref="TrafficRule"/> or <c>null</c>.</returns> public TrafficRule GetRule(string ruleName) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(ruleName)); var ruleKey = GetProxyRuleKey(ruleName); if (hive.Consul.Client.KV.Exists(ruleKey).Result) { return(TrafficRule.ParseJson(hive.Consul.Client.KV.GetString(ruleKey).Result)); } else { return(null); } }
/// <summary> /// Returns credentials for a Vault AppRole. /// </summary> /// <param name="roleName">The role name.</param> /// <param name="cancellationToken">The optional <see cref="CancellationToken"/>.</param> /// <returns>The <see cref="HiveCredentials"/>.</returns> /// <exception cref="HttpException">Thrown for Vault communication problems.</exception> public async Task <HiveCredentials> GetAppRoleCredentialsAsync(string roleName, CancellationToken cancellationToken = default) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(roleName)); string roleId; string secretId; // Verify that the role exists. try { await ReadDynamicAsync($"auth/approle/role/{roleName}", cancellationToken : cancellationToken); } catch (Exception e) { throw new HttpException($"Unable to access Vault [AppRole={roleName}]", e); } // Fetch the role ID. try { var response = await ReadDynamicAsync($"auth/approle/role/{roleName}/role-id", cancellationToken : cancellationToken); roleId = response.role_id; } catch (Exception e) { throw new HttpException($"Unable to fetch the role ID for Vault [AppRole={roleName}]", e); } // Fetch a secret ID. try { var response = (await WriteJsonAsync($"auth/approle/role/{roleName}/secret-id", cancellationToken)).data; secretId = response.secret_id; } catch (Exception e) { throw new HttpException($"Unable to fetch the role ID for Vault [AppRole={roleName}]", e); } // Return the credentials. return(HiveCredentials.FromVaultRole(roleId, secretId)); }
/// <summary> /// Sets or removes a named hive global setting, serialized saved objects as JSON. /// </summary> /// <param name="name">The setting name.</param> /// <param name="value">The setting value or <c>null</c> to remove the setting if it exists.</param> /// <returns>The tracking <see cref="Task"/>.</returns> /// <remarks> /// <note> /// Well known hive setting names are defined in <see cref="HiveGlobals"/>. /// </note> /// </remarks> public void Set(string name, object value) { Covenant.Requires(!string.IsNullOrEmpty(name)); Covenant.Requires(HiveDefinition.IsValidName(name)); var key = $"{HiveConst.GlobalKey}/{name}"; if (value == null) { hive.Consul.Client.KV.Delete(key).Wait(); } else { hive.Consul.Client.KV.PutString(key, NeonHelper.JsonSerialize(value, Formatting.Indented)).Wait(); } }
/// <summary> /// Sets or removes a named <see cref="TimeSpan"/> hive global setting. /// </summary> /// <param name="name">The setting name.</param> /// <param name="value">The setting value or <c>null</c> to remove the setting if it exists.</param> /// <returns>The tracking <see cref="Task"/>.</returns> /// <remarks> /// <note> /// Well known hive setting names are defined in <see cref="HiveGlobals"/>. /// </note> /// </remarks> public void Set(string name, TimeSpan?value) { Covenant.Requires(!string.IsNullOrEmpty(name)); Covenant.Requires(HiveDefinition.IsValidName(name)); var key = $"{HiveConst.GlobalKey}/{name}"; if (value == null) { hive.Consul.Client.KV.Delete(key).Wait(); } else { hive.Consul.Client.KV.PutString(key, value.Value.ToString()).Wait(); } }
/// <summary> /// Creates or updates a hive Docker binary config. /// </summary> /// <param name="configName">The config name.</param> /// <param name="value">The config value.</param> /// <param name="options">Optional command run options.</param> /// <exception cref="HiveException">Thrown if the operation failed.</exception> public void Set(string configName, byte[] value, RunOptions options = RunOptions.None) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(configName)); Covenant.Requires <ArgumentNullException>(value != null); var bundle = new CommandBundle("./create-config.sh"); bundle.AddFile("config.dat", value); bundle.AddFile("create-config.sh", $@"#!/bin/bash if docker config inspect {configName} ; then echo ""Config already exists; not setting it again."" else cat config.dat | docker config create {configName} - # It appears that Docker configs may not be available # immediately after they are created. So, we're going # poll for a while until we can inspect the new config. count=0 while [ $count -le 30 ] do if docker config inspect {configName} ; then exit 0 fi sleep 1 count=$(( count + 1 )) done echo ""Created config [{configName}] is not ready after 30 seconds."" >&2 exit 1 fi ", isExecutable: true); var response = hive.GetReachableManager().SudoCommand(bundle, options); if (response.ExitCode != 0) { throw new HiveException(response.ErrorSummary); } }
/// <summary> /// Attempts to retrieve a named hive global setting as a <see cref="TimeSpan"/>. /// </summary> /// <param name="name">The setting name.</param> /// <param name="output">Returns as the setting value.</param> /// <returns><c>true</c> if the setting exists and was returned.</returns> /// <exception cref="FormatException">Thrown if the setting value could not be parsed.</exception> /// <remarks> /// <note> /// Well known hive setting names are defined in <see cref="HiveGlobals"/>. /// </note> /// </remarks> public bool TryGetTimeSpan(string name, out TimeSpan output) { Covenant.Requires(!string.IsNullOrEmpty(name)); Covenant.Requires(HiveDefinition.IsValidName(name)); output = default(TimeSpan); var key = $"{HiveConst.GlobalKey}/{name}"; var value = hive.Consul.Client.KV.GetStringOrDefault(key).Result; if (value == null) { return(false); } output = TimeSpan.Parse(value); return(true); }
/// <summary> /// Validates the DNS entry. Any warning/errors will be returned as a string list. /// </summary> /// <param name="hiveDefinition">The current hive definition,</param> /// <param name="nodeGroups">The hive node groups.</param> /// <returns>The list of warnings (if any).</returns> public List <string> Validate(HiveDefinition hiveDefinition, Dictionary <string, List <NodeDefinition> > nodeGroups) { Covenant.Requires <ArgumentException>(hiveDefinition != null); Covenant.Requires <ArgumentException>(nodeGroups != null); var warnings = new List <string>(); if (string.IsNullOrEmpty(Hostname) || !HiveDefinition.IsValidName(Hostname)) { warnings.Add($"Invalid [{nameof(DnsEntry)}.{nameof(Hostname)}={Hostname}]."); } foreach (var endpoint in Endpoints) { endpoint.Validate(warnings, hiveDefinition, nodeGroups, Hostname); } return(warnings); }
/// <summary> /// Attempts to retrieve a named hive global setting as a <c>string</c>. /// </summary> /// <typeparam name="T">The type of the object to be returned.</typeparam> /// <param name="name">The setting name.</param> /// <param name="output">Returns as the setting value.</param> /// <returns><c>true</c> if the setting exists, could be parsed, and was returned.</returns> /// <remarks> /// <note> /// Well known hive setting names are defined in <see cref="HiveGlobals"/>. /// </note> /// </remarks> public bool TryGetObject <T>(string name, out T output) where T : class, new() { Covenant.Requires(!string.IsNullOrEmpty(name)); Covenant.Requires(HiveDefinition.IsValidName(name)); output = null; var key = $"{HiveConst.GlobalKey}/{name}"; var json = hive.Consul.Client.KV.GetStringOrDefault(key).Result; if (json == null) { return(false); } output = NeonHelper.JsonDeserialize <T>(json, strict: false);; return(true); }
/// <summary> /// Deletes a traffic manager rule if it exists. /// </summary> /// <param name="ruleName">The rule name.</param> /// <param name="deferUpdate"> /// <para> /// Optionally defers expicitly notifying the <b>neon-proxy-manager</b> of the /// change until <see cref="Update()"/> is called or the <b>neon-proxy-manager</b> /// performs the periodic check for changes (which defaults to 60 seconds). You /// may consider passing <paramref name="deferUpdate"/><c>=true</c> when you are /// modifying a multiple rules at the same time to avoid making the proxy manager /// and proxy instances handle each rule change individually. /// </para> /// <para> /// Instead, you could pass <paramref name="deferUpdate"/><c>=true</c> for all of /// the rule changes and then call <see cref="Update()"/> afterwards. /// </para> /// </param> /// <returns><c>true</c> if the rule existed and was deleted, <c>false</c> if it didn't exist.</returns> public bool RemoveRule(string ruleName, bool deferUpdate = false) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(ruleName)); var ruleKey = GetProxyRuleKey(ruleName); if (hive.Consul.Client.KV.Exists(ruleKey).Result) { hive.Consul.Client.KV.Delete(ruleKey); if (!deferUpdate) { Update(); } return(true); } else { return(false); } }
/// <summary> /// Validates the backend. /// </summary> /// <param name="context">The validation context.</param> /// <param name="ruleName">The parent rule name.</param> public virtual void Validate(TrafficValidationContext context, string ruleName) { if (!string.IsNullOrEmpty(Name) && !HiveDefinition.IsValidName(Name)) { context.Error($"Rule [{ruleName}] has backend server with invalid [{nameof(Name)}={Name}]."); } if (!string.IsNullOrEmpty(Group)) { if (!HiveDefinition.IsValidName(Group)) { context.Error($"Rule [{ruleName}] has backend with [{nameof(Group)}={Group}] which is not a valid group name."); } if (GroupLimit < 0) { context.Error($"Rule [{ruleName}] has backend with [{nameof(GroupLimit)}={GroupLimit}] which may not be less than zero."); } } else { if (string.IsNullOrEmpty(Server) || (!IPAddress.TryParse(Server, out var address) && !HiveDefinition.DnsHostRegex.IsMatch(Server))) { context.Error($"Rule [{ruleName}] has backend server [{Server}] which is not valid. A DNS name or IP address was expected."); } } if (!NetHelper.IsValidPort(Port)) { context.Error($"Rule [{ruleName}] has backend server with invalid [{nameof(Port)}={Port}] which is outside the range of valid TCP ports."); } if (MaxConnections < 0) { context.Error($"Rule [{ruleName}] has backend server with invalid [{nameof(MaxConnections)}={MaxConnections}]."); } }
/// <summary> /// Deletes a hive Docker config. /// </summary> /// <param name="configName">The config name.</param> /// <param name="options">Optional command run options.</param> /// <exception cref="HiveException">Thrown if the operation failed.</exception> public void Remove(string configName, RunOptions options = RunOptions.None) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(configName)); var bundle = new CommandBundle("./delete-config.sh"); bundle.AddFile("delete-config.sh", $@"#!/bin/bash docker config inspect {configName} if [ ""$?"" != ""0"" ] ; then echo ""Config doesn't exist."" else docker config rm {configName} fi ", isExecutable: true); var response = hive.GetReachableManager().SudoCommand(bundle, RunOptions.None); if (response.ExitCode != 0) { throw new HiveException(response.ErrorSummary); } }
/// <summary> /// Retrieves a hive certificate. /// </summary> /// <param name="name">The certificate name.</param> /// <returns>The certificate if present or <c>null</c> if it doesn't exist.</returns> public TlsCertificate Get(string name) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(name)); return(hive.Vault.Client.ReadJsonOrDefaultAsync <TlsCertificate>(HiveHelper.GetVaultCertificateKey(name)).Result); }
public void Validate(HiveDefinition hiveDefinition) { Covenant.Requires <ArgumentNullException>(hiveDefinition != null); switch (Environment) { case HostingEnvironments.Aws: if (Aws == null) { throw new HiveDefinitionException($"[{nameof(HostingOptions)}.{nameof(Aws)}] must be initialized when cloud provider is [{Environment}]."); } Aws.Validate(hiveDefinition); break; case HostingEnvironments.Azure: if (Azure == null) { throw new HiveDefinitionException($"[{nameof(HostingOptions)}.{nameof(Azure)}] must be initialized when cloud provider is [{Environment}]."); } Azure.Validate(hiveDefinition); break; case HostingEnvironments.Google: if (Google == null) { throw new HiveDefinitionException($"[{nameof(HostingOptions)}.{nameof(Google)}] must be initialized when cloud provider is [{Environment}]."); } Google.Validate(hiveDefinition); break; case HostingEnvironments.HyperV: HyperV = HyperV ?? new HyperVOptions(); HyperV.Validate(hiveDefinition); break; case HostingEnvironments.HyperVDev: LocalHyperV = LocalHyperV ?? new LocalHyperVOptions(); LocalHyperV.Validate(hiveDefinition); break; case HostingEnvironments.Machine: Machine = Machine ?? new MachineOptions(); Machine.Validate(hiveDefinition); break; case HostingEnvironments.XenServer: XenServer = XenServer ?? new XenServerOptions(); XenServer.Validate(hiveDefinition); break; default: throw new NotImplementedException(); } if (IsCloudProvider && !hiveDefinition.Vpn.Enabled) { // VPN is implicitly enabled when hosting on a cloud. hiveDefinition.Vpn.Enabled = true; } if (!string.IsNullOrWhiteSpace(VmNamePrefix)) { if (!HiveDefinition.IsValidName(VmNamePrefix)) { throw new HiveDefinitionException($"[{nameof(HostingOptions)}.{nameof(VmNamePrefix)}={VmNamePrefix}] must include only letters, digits, underscores, or periods."); } } }
/// <summary> /// Retrieves a hive dashboard. /// </summary> /// <param name="name">The dashboard name.</param> /// <returns>The dashboard if present or <c>null</c> if it doesn't exist.</returns> public HiveDashboard Get(string name) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(name), $"[{name}] is not a valid hive dashboard name."); return(hive.Consul.Client.KV.GetObjectOrDefault <HiveDashboard>(GetDashboardConsulKey(name)).Result); }
/// <summary> /// Removes a hive dashboard if it exists. /// </summary> /// <param name="name">The dashboard name.</param> public void Remove(string name) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(name)); hive.Consul.Client.KV.Delete(GetDashboardConsulKey(name)).Wait(); }
/// <summary> /// Adds or updates a traffic manager rule. /// </summary> /// <param name="rule">The rule definition.</param> /// <param name="deferUpdate"> /// <para> /// Optionally defers expicitly notifying the <b>neon-proxy-manager</b> of the /// change until <see cref="Update()"/> is called or the <b>neon-proxy-manager</b> /// performs the periodic check for changes (which defaults to 60 seconds). You /// may consider passing <paramref name="deferUpdate"/><c>=true</c> when you are /// modifying a multiple rules at the same time to avoid making the proxy manager /// and proxy instances handle each rule change individually. /// </para> /// <para> /// Instead, you could pass <paramref name="deferUpdate"/><c>=true</c> for all of /// the rule changes and then call <see cref="Update()"/> afterwards. /// </para> /// </param> /// <returns> /// <c>true</c> if it existed and was updated, <b>false</b> /// if the traffic manager rule didn't already exist and was added. /// </returns> /// <exception cref="HiveDefinitionException">Thrown if the rule is not valid.</exception> public bool SetRule(TrafficRule rule, bool deferUpdate = false) { Covenant.Requires <ArgumentNullException>(rule != null); Covenant.Requires <ArgumentNullException>(HiveDefinition.IsValidName(rule.Name)); if (!IsPublic) { // Ensure that the [PublicPort] is disabled for non-public rules // just to be absolutely sure that these endpoints are not exposed // to the Internet for cloud deployments and to avoid operators // being freaked out if they see a non-zero port here. var httpRule = rule as TrafficHttpRule; if (httpRule != null) { foreach (var frontEnd in httpRule.Frontends) { frontEnd.PublicPort = 0; } } else { var tcpRule = rule as TrafficTcpRule; if (tcpRule != null) { foreach (var frontEnd in tcpRule.Frontends) { frontEnd.PublicPort = 0; } } } } // $todo(jeff.lill): // // We're going to minimially ensure that the rule is valid. It would // be better to do full server side validation. var context = new TrafficValidationContext(Name, GetSettings()) { ValidateCertificates = false, // Disable this because we didn't download the certs. ValidateResolvers = false }; rule.Validate(context); context.ThrowIfErrors(); // Publish the rule. var ruleKey = GetProxyRuleKey(rule.Name); var update = hive.Consul.Client.KV.Exists(ruleKey).Result; // Load the full proxy definition and hive certificates, add/replace // the rule being set and then verify that the rule is OK. var proxyDefinition = GetDefinition(); var certificates = hive.Certificate.GetAll(); proxyDefinition.Rules[rule.Name] = rule; proxyDefinition.Validate(certificates); var validationContext = proxyDefinition.Validate(certificates); validationContext.ThrowIfErrors(); // Save the rule to the hive and signal that the // load balancers need to be updated. hive.Consul.Client.KV.PutObject(ruleKey, rule, Formatting.Indented).Wait(); if (!deferUpdate) { Update(); } return(update); }
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)); } }
/// <summary> /// Removes a Vault access control policy. /// </summary> /// <param name="policyName">The policy name.</param> /// <returns>The command response.</returns> public CommandResponse RemovePolicy(string policyName) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(policyName)); return(Command($"vault policy-delete {policyName}")); }
/// <summary> /// Removes a Vault AppRole. /// </summary> /// <param name="roleName">The role name.</param> /// <returns>The command response.</returns> public CommandResponse RemoveAppRole(string roleName) { Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(roleName)); return(Command($"vault delete auth/approle/role/{roleName}")); }