Esempio n. 1
0
        /// <summary>
        /// Performs common node configuration.
        /// </summary>
        /// <param name="controller">The setup controller.</param>
        /// <param name="clusterManifest">The cluster manifest.</param>
        public void SetupNode(ISetupController controller, ClusterManifest clusterManifest)
        {
            Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller));
            Covenant.Requires <ArgumentNullException>(clusterManifest != null, nameof(clusterManifest));

            var nodeDefinition    = NeonHelper.CastTo <NodeDefinition>(Metadata);
            var clusterDefinition = Cluster.Definition;
            var hostingManager    = controller.Get <IHostingManager>(KubeSetupProperty.HostingManager);

            InvokeIdempotent("setup/node",
                             () =>
            {
                PrepareNode(controller);
                ConfigureEnvironmentVariables(controller);
                SetupPackageProxy(controller);
                UpdateHostname(controller);
                NodeInitialize(controller);
                NodeInstallCriO(controller, clusterManifest);
                NodeInstallIPVS(controller);
                NodeInstallPodman(controller);
                NodeInstallKubernetes(controller);
                SetupKublet(controller);
            });
        }
Esempio n. 2
0
        /// <summary>
        /// Configures cluster package manager caching.
        /// </summary>
        /// <param name="controller">The setup controller.</param>
        public void SetupPackageProxy(ISetupController controller)
        {
            Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller));

            var nodeDefinition    = NeonHelper.CastTo <NodeDefinition>(Metadata);
            var clusterDefinition = Cluster.Definition;
            var hostingManager    = controller.Get <IHostingManager>(KubeSetupProperty.HostingManager);

            InvokeIdempotent("setup/package-caching",
                             () =>
            {
                controller.LogProgress(this, verb: "configure", message: "apt package proxy");

                // Configure the [apt-cacher-ng] pckage proxy service on control-plane nodes.

                if (NodeDefinition.Role == NodeRole.ControlPlane)
                {
                    var proxyServiceScript =
                        $@"
	set -eou pipefail	# Enable full failure detection

	{KubeNodeFolder.Bin}/safe-apt-get update
	{KubeNodeFolder.Bin}/safe-apt-get install -yq apt-cacher-ng

	# Configure the cache to pass-thru SSL requests
	# and then restart.

	echo ""PassThroughPattern:^.*:443$"" >> /etc/apt-cacher-ng/acng.conf
	systemctl restart apt-cacher-ng

	set -eo pipefail	# Revert back to partial failure detection

	# Give the proxy service a chance to start.

	sleep 5
";
                    SudoCommand(CommandBundle.FromScript(proxyServiceScript), RunOptions.FaultOnError);
                }

                var sbPackageProxies = new StringBuilder();

                if (clusterDefinition.PackageProxy != null)
                {
                    foreach (var proxyEndpoint in clusterDefinition.PackageProxy.Split(' ', StringSplitOptions.RemoveEmptyEntries))
                    {
                        sbPackageProxies.AppendWithSeparator(proxyEndpoint);
                    }
                }

                // Configure the package manager to use the first control-plane as the proxy by default,
                // failing over to the other control-plane nodes (in order) when necessary.

                var proxySelectorScript =
                    $@"
# Configure APT proxy selection.

echo {sbPackageProxies} > {KubeNodeFolder.Config}/package-proxy

cat <<EOF > /usr/local/bin/get-package-proxy
#!/bin/bash
#------------------------------------------------------------------------------
# FILE:        get-package-proxy
# CONTRIBUTOR: Generated by [neon-cli] during cluster setup.
#
# This script determine which (if any) configured APT proxy caches are running
# and returns its endpoint or ""DIRECT"" if none of the proxies are available and 
# the distribution's mirror should be accessed directly.  This uses the
# [{KubeNodeFolder.Config}/package-proxy] file to obtain the list of proxies.
#
# This is called when the following is specified in the APT configuration,
# as we do further below:
#
#		Acquire::http::Proxy-Auto-Detect ""/usr/local/bin/get-package-proxy"";
#
# See this link for more information:
#
#		https://trent.utfs.org/wiki/Apt-get#Failover_Proxy
NEON_PACKAGE_PROXY=$(cat {KubeNodeFolder.Config}/package-proxy)
if [ ""\${{NEON_PACKAGE_PROXY}}"" == """" ] ; then
    echo DIRECT
    exit 0
fi
for proxy in ${{NEON_PACKAGE_PROXY}}; do
	if nc -w1 -z \${{proxy/:/ }}; then
		echo http://\${{proxy}}/
		exit 0
	fi
done
echo DIRECT
exit 0
EOF

chmod 775 /usr/local/bin/get-package-proxy

cat <<EOF > /etc/apt/apt.conf
//-----------------------------------------------------------------------------
// FILE:        /etc/apt/apt.conf
// CONTRIBUTOR: Generated by during neonKUBE cluster setup.
//
// This file configures APT on the local machine to proxy requests through the
// [apt-cacher-ng] instance(s) at the configured.  This uses the [/usr/local/bin/get-package-proxy] 
// script to select a working PROXY if there are more than one, or to go directly to the package
// mirror if none of the proxies are available.
//
// Presumably, this cache is running on the local network which can dramatically
// reduce external network traffic to the APT mirrors and improve cluster setup 
// and update performance.

Acquire::http::Proxy-Auto-Detect ""/usr/local/bin/get-package-proxy"";
EOF
";
                SudoCommand(CommandBundle.FromScript(proxySelectorScript), RunOptions.FaultOnError);
            });
        }
Esempio n. 3
0
        /// <summary>
        /// Configures the global environment variables that describe the configuration
        /// of the server within the cluster.
        /// </summary>
        /// <param name="controller">The setup controller.</param>
        public void ConfigureEnvironmentVariables(ISetupController controller)
        {
            Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller));

            controller.LogProgress(this, verb: "configure", message: "environment");

            var clusterDefinition = Cluster.Definition;
            var nodeDefinition    = NeonHelper.CastTo <NodeDefinition>(Metadata);

            // We're going to append the new variables to the existing Linux [/etc/environment] file.

            var sb = new StringBuilder();

            // Append all of the existing environment variables except for those
            // whose names start with "NEON_" to make the operation idempotent.
            //
            // Note that we're going to special case PATH to add any Neon
            // related directories.

            using (var currentEnvironmentStream = new MemoryStream())
            {
                Download("/etc/environment", currentEnvironmentStream);

                currentEnvironmentStream.Position = 0;

                using (var reader = new StreamReader(currentEnvironmentStream))
                {
                    foreach (var line in reader.Lines())
                    {
                        if (line.StartsWith("PATH="))
                        {
                            if (!line.Contains(KubeNodeFolder.Bin))
                            {
                                sb.AppendLine(line + $":/snap/bin:{KubeNodeFolder.Bin}");
                            }
                            else
                            {
                                sb.AppendLine(line);
                            }
                        }
                        else if (!line.StartsWith("NEON_"))
                        {
                            sb.AppendLine(line);
                        }
                    }
                }
            }

            // Add the global cluster related environment variables.

            sb.AppendLine($"NEON_CLUSTER={clusterDefinition.Name}");
            sb.AppendLine($"NEON_DATACENTER={clusterDefinition.Datacenter.ToLowerInvariant()}");
            sb.AppendLine($"NEON_ENVIRONMENT={clusterDefinition.Purpose.ToString().ToLowerInvariant()}");

            var sbPackageProxies = new StringBuilder();

            if (clusterDefinition.PackageProxy != null)
            {
                foreach (var proxyEndpoint in clusterDefinition.PackageProxy.Split(' ', StringSplitOptions.RemoveEmptyEntries))
                {
                    sbPackageProxies.AppendWithSeparator(proxyEndpoint);
                }
            }

            sb.AppendLine($"NEON_PACKAGE_PROXY={sbPackageProxies}");

            if (clusterDefinition.Hosting != null)
            {
                sb.AppendLine($"NEON_HOSTING={clusterDefinition.Hosting.Environment.ToMemberString().ToLowerInvariant()}");
            }

            sb.AppendLine($"NEON_NODE_NAME={Name}");

            if (nodeDefinition != null)
            {
                sb.AppendLine($"NEON_NODE_ROLE={nodeDefinition.Role}");
                sb.AppendLine($"NEON_NODE_IP={nodeDefinition.Address}");
                sb.AppendLine($"NEON_NODE_HDD={nodeDefinition.Labels.StorageHDD.ToString().ToLowerInvariant()}");
            }

            sb.AppendLine($"NEON_BIN_FOLDER={KubeNodeFolder.Bin}");
            sb.AppendLine($"NEON_CONFIG_FOLDER={KubeNodeFolder.Config}");
            sb.AppendLine($"NEON_SETUP_FOLDER={KubeNodeFolder.Setup}");
            sb.AppendLine($"NEON_STATE_FOLDER={KubeNodeFolder.State}");
            sb.AppendLine($"NEON_RUN_FOLDER={KubeNodeFolder.NeonRun}");
            sb.AppendLine($"NEON_TMPFS_FOLDER={KubeNodeFolder.Tmpfs}");

            // Kubernetes related variables for control-plane nodes.

            if (nodeDefinition.IsControlPane)
            {
                sb.AppendLine($"KUBECONFIG=/etc/kubernetes/admin.conf");
            }

            // Upload the new environment to the server.

            UploadText("/etc/environment", sb, tabStop: 4);
        }