Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        /// <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}");
        }
Beispiel #4
0
        /// <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();
        }
Beispiel #5
0
        /// <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();
        }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
        /// <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);
            }
        }
Beispiel #8
0
        /// <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));
        }
Beispiel #9
0
        /// <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();
            }
        }
Beispiel #10
0
        /// <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();
            }
        }
Beispiel #11
0
        /// <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);
            }
        }
Beispiel #12
0
        /// <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);
        }
Beispiel #13
0
        /// <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);
        }
Beispiel #14
0
        /// <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);
        }
Beispiel #15
0
        /// <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);
            }
        }
Beispiel #16
0
        /// <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}].");
            }
        }
Beispiel #17
0
        /// <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);
            }
        }
Beispiel #18
0
        /// <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);
        }
Beispiel #19
0
        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.");
                }
            }
        }
Beispiel #20
0
        /// <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);
        }
Beispiel #21
0
        /// <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();
        }
Beispiel #22
0
        /// <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);
        }
Beispiel #23
0
        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));
            }
        }
Beispiel #24
0
        /// <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}"));
        }
Beispiel #25
0
        /// <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}"));
        }