Esempio n. 1
0
        /// <inheritdoc/>
        public override void Run(HiveProxy hive)
        {
            Covenant.Requires <ArgumentNullException>(hive != null);

            var node = hive.GetNode(nodeName);

            node.SudoCommand("docker-volume-rm", volumeName);
        }
Esempio n. 2
0
        /// <summary>
        /// Signals the Docker orchestrator to drain all service tasks from a node.
        /// </summary>
        /// <param name="nodeName">Identifies the target node.</param>
        /// <exception cref="KeyNotFoundException">Thrown if the named node does not exist.</exception>
        /// <exception cref="InvalidOperationException">Thrown if the node is not part of the swarm.</exception>
        public void DrainNode(string nodeName)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(nodeName));

            var node = hive.GetNode(nodeName);

            if (!node.Metadata.InSwarm)
            {
                throw new InvalidOperationException($"Node [{nodeName}] is not part of the swarm.");
            }

            // I've see transient errors, so we'll retry a few times.

            var manager = hive.GetReachableManager();
            var retry   = new LinearRetryPolicy(typeof(Exception), maxAttempts: 5, retryInterval: TimeSpan.FromSeconds(5));

            retry.InvokeAsync(
                async() =>
            {
                var response = manager.SudoCommand($"docker node update --availability drain {nodeName}");

                if (response.ExitCode != 0)
                {
                    throw new Exception(response.ErrorSummary);
                }

                await Task.CompletedTask;
            }).Wait();

            // $todo(jeff.lill):
            //
            // Ideally, we'd wait for all of the service tasks to stop but it
            // appears that there's no easy way to check for this other than
            // listing all of the hive services and then doing a
            //
            //      docker service ps SERVICE]
            //
            // for each until none report running on this node.
            //
            // A hacky alternative would be to list local containers and try
            // to determine which ones look liks service tasks by examining
            // the container name.

            Thread.Sleep(TimeSpan.FromSeconds(30));
        }
Esempio n. 3
0
        /// <inheritdoc/>
        public override void Run(HiveProxy hive)
        {
            Covenant.Requires <ArgumentNullException>(hive != null);

            var node = hive.GetNode(nodeName);

            if (operationName != null)
            {
                node.InvokeIdempotentAction(operationName, () => action(node));
            }
            else
            {
                action(node);
            }
        }
Esempio n. 4
0
        /// <inheritdoc/>
        public override void Run(HiveProxy hive)
        {
            Covenant.Requires <ArgumentNullException>(hive != null);

            var node   = hive.GetNode(nodeName);
            var status = this.ToString();

            node.UploadText(path, text, tabStop, outputEncoding);

            if (!string.IsNullOrEmpty(permissions))
            {
                node.SudoCommand("chmod", permissions, path);
            }

            StatusPause();

            node.Status = string.Empty;
        }
Esempio n. 5
0
 /// <inheritdoc/>
 public override (string Address, int Port) GetSshEndpoint(string nodeName)
 {
     return(Address : hive.GetNode(nodeName).PrivateAddress.ToString(), Port : NetworkPorts.SSH);
 }
Esempio n. 6
0
        /// <summary>
        /// Provision the virtual machines on the XenServer.
        /// </summary>
        /// <param name="xenSshProxy">The XenServer SSH proxy.</param>
        private void ProvisionVirtualMachines(SshProxy <XenClient> xenSshProxy)
        {
            var xenHost = xenSshProxy.Metadata;

            foreach (var node in GetHostedNodes(xenHost))
            {
                var vmName      = GetVmName(node);
                var processors  = node.Metadata.GetVmProcessors(hive.Definition);
                var memoryBytes = node.Metadata.GetVmMemory(hive.Definition);
                var diskBytes   = node.Metadata.GetVmDisk(hive.Definition);

                xenSshProxy.Status = FormatVmStatus(vmName, "create virtual machine");

                // We need to create a raw drive if the node hosts a Ceph OSD.

                var extraDrives = new List <XenVirtualDrive>();

                if (node.Metadata.Labels.CephOSD)
                {
                    extraDrives.Add(
                        new XenVirtualDrive()
                    {
                        Size = node.Metadata.GetCephOSDDriveSize(hive.Definition)
                    });
                }

                var vm = xenHost.Machine.Create(vmName, hive.Definition.Hosting.XenServer.TemplateName,
                                                processors:                 processors,
                                                memoryBytes:                memoryBytes,
                                                diskBytes:                  diskBytes,
                                                snapshot:                   hive.Definition.Hosting.XenServer.Snapshot,
                                                extraDrives:                extraDrives,
                                                primaryStorageRepository:   hive.Definition.Hosting.XenServer.StorageRepository,
                                                extraStorageRespository:    hive.Definition.Hosting.XenServer.OsdStorageRepository);

                xenSshProxy.Status = FormatVmStatus(vmName, "start virtual machine");

                xenHost.Machine.Start(vm);

                // We need to wait for the virtual machine to start and obtain
                // and IP address via DHCP.

                var address = string.Empty;

                xenSshProxy.Status = FormatVmStatus(vmName, "fetch ip address");

                try
                {
                    NeonHelper.WaitFor(
                        () =>
                    {
                        while (true)
                        {
                            vm = xenHost.Machine.Find(vmName);

                            if (!string.IsNullOrEmpty(vm.Address))
                            {
                                address = vm.Address;
                                return(true);
                            }

                            Thread.Sleep(1000);
                        }
                    },
                        TimeSpan.FromSeconds(120));
                }
                catch (TimeoutException)
                {
                    xenSshProxy.Fault("Timeout waiting for virtual machine to start and set an IP address.");
                }

                // SSH into the VM using the DHCP address, configure the static IP
                // address and extend the primary partition and file system to fill
                // the drive and then reboot.

                var subnet    = NetworkCidr.Parse(hive.Definition.Network.PremiseSubnet);
                var gateway   = hive.Definition.Network.Gateway;
                var broadcast = hive.Definition.Network.Broadcast;

                // We're going to temporarily set the node to the current VM address
                // so we can connect via SSH.

                var savedNodeAddress = node.PrivateAddress;

                try
                {
                    node.PrivateAddress = IPAddress.Parse(address);

                    using (var nodeProxy = hive.GetNode(node.Name))
                    {
                        xenSshProxy.Status = FormatVmStatus(vmName, "connect");
                        nodeProxy.WaitForBoot();

                        // Replace the [/etc/network/interfaces] file to configure the static
                        // IP and then reboot to reinitialize networking subsystem.

                        var primaryInterface = node.GetNetworkInterface(node.PrivateAddress);

                        xenSshProxy.Status = FormatVmStatus(vmName, $"set static ip [{node.PrivateAddress}]");

                        var interfacesText =
                            $@"# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto {primaryInterface}
iface {primaryInterface} inet static
address {savedNodeAddress}
netmask {subnet.Mask}
gateway {gateway}
broadcast {broadcast}
";
                        nodeProxy.UploadText("/etc/network/interfaces", interfacesText);

                        // Temporarily configure the public Google DNS servers as
                        // the name servers so DNS will work after we reboot with
                        // the static IP.  Note that hive setup will eventually
                        // configure the name servers specified in the hive
                        // definition.

                        // $todo(jeff.lill):
                        //
                        // Is there a good reason why we're not just configuring the
                        // DNS servers from the hive definition here???
                        //
                        // Using the Google DNS seems like it could break some hive
                        // network configurations (e.g. for hives that don't have
                        // access to the public Internet).  Totally private hives
                        // aren't really a supported scenario right now though because
                        // we assume we can use [apt-get]... to pull down packages.

                        var resolvBaseText =
                            $@"nameserver 8.8.8.8
nameserver 8.8.4.4
";
                        nodeProxy.UploadText("/etc/resolvconf/resolv.conf.d/base", resolvBaseText);

                        // Extend the primary partition and file system to fill
                        // the virtual the drive.

                        xenSshProxy.Status = FormatVmStatus(vmName, $"resize primary partition");

                        // $hack(jeff.lill):
                        //
                        // I've seen a transient error here but can't reproduce it.  I'm going
                        // to assume for now that the file system might not be quite ready for
                        // this operation directly after the VM has been rebooted, so we're going
                        // to delay for a few seconds before performing the operations.

                        Thread.Sleep(TimeSpan.FromSeconds(5));
                        nodeProxy.SudoCommand("growpart /dev/xvda 1");
                        nodeProxy.SudoCommand("resize2fs /dev/xvda1");

                        // Reboot to pick up the changes.

                        xenSshProxy.Status = FormatVmStatus(vmName, "reboot");
                        nodeProxy.Reboot(wait: false);
                    }
                }
                finally
                {
                    // Restore the node's IP address.

                    node.PrivateAddress = savedNodeAddress;
                }
            }
        }