Exemplo n.º 1
0
        /// <summary>
        /// <para>
        /// Installs the tool scripts, making them executable.
        /// </para>
        /// <note>
        /// Any <b>".sh"</b> file extensions will be removed for ease-of-use.
        /// </note>
        /// </summary>
        /// <param name="controller">The setup controller.</param>
        public void BaseInstallToolScripts(ISetupController controller)
        {
            Covenant.Requires <ArgumentException>(controller != null, nameof(controller));

            InvokeIdempotent("base/tool-scripts",
                             () =>
            {
                controller.LogProgress(this, verb: "setup", message: "tools (base)");

                // Upload any tool scripts to the neonKUBE bin folder, stripping
                // the [*.sh] file type (if present) and then setting execute
                // permissions.

                var scriptsFolder = KubeHelper.Resources.GetDirectory("/Tools");        // $hack(jefflill): https://github.com/nforgeio/neonKUBE/issues/1121

                foreach (var file in scriptsFolder.GetFiles())
                {
                    var targetName = file.Name;

                    if (Path.GetExtension(targetName) == ".sh")
                    {
                        targetName = Path.GetFileNameWithoutExtension(targetName);
                    }

                    using (var toolStream = file.OpenStream())
                    {
                        UploadText(LinuxPath.Combine(KubeNodeFolder.Bin, targetName), toolStream, permissions: "744");
                    }
                }
            });
        }
Exemplo n.º 2
0
        /// <summary>
        /// Edits the [neon-proxy-public-bridge.sh] and [neon-proxy-private-bridge.sh]
        /// scripts to remove the [VAULT_CREDENTIALS] environment variable so the new
        /// .NET based proxy bridge image will work properly.
        /// </summary>
        /// <param name="node">The target node.</param>
        private void UpdateProxyBridgeScripts(SshProxy <NodeDefinition> node)
        {
            var scriptNames =
                new string[]
            {
                "neon-proxy-public-bridge.sh",
                "neon-proxy-private-bridge.sh"
            };

            foreach (var scriptName in scriptNames)
            {
                var scriptPath = LinuxPath.Combine(HiveHostFolders.Scripts, scriptName);
                var scriptText = node.DownloadText(scriptName);
                var sbEdited   = new StringBuilder();

                using (var reader = new StringReader(scriptText))
                {
                    foreach (var line in reader.Lines())
                    {
                        if (!line.Contains("--env VAULT_CREDENTIALS="))
                        {
                            sbEdited.AppendLineLinux(line);
                        }
                    }
                }

                node.UploadText(scriptPath, sbEdited.ToString(), permissions: "700");
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Starts a neonHIVE related Docker container on a node and also uploads a script
        /// to make it easy to restart the container manually or for hive updates.
        /// </summary>
        /// <param name="node">The target hive node.</param>
        /// <param name="containerName">Identifies the container.</param>
        /// <param name="image">The Docker image to be used by the container.</param>
        /// <param name="runOptions">Optional run options (defaults to <see cref="RunOptions.FaultOnError"/>).</param>
        /// <param name="commands">The commands required to start the container.</param>
        /// <remarks>
        /// <para>
        /// This method performs the following steps:
        /// </para>
        /// <list type="number">
        ///     <item>
        ///     Passes <paramref name="image"/> to <see cref="Program.ResolveDockerImage(string)"/> to
        ///     obtain the actual image to be started.
        ///     </item>
        ///     <item>
        ///     Generates the first few lines of the script file that sets the
        ///     default image as the <c>TARGET_IMAGE</c> macro and then overrides
        ///     this with the script parameter (if there is one).
        ///     </item>
        ///     <item>
        ///     Appends the commands to the script, replacing any text that matches
        ///     <see cref="ImagePlaceholderArg"/> with <c>${TARGET_IMAGE}</c> to make it easy
        ///     for services to be upgraded later.
        ///     </item>
        ///     <item>
        ///     Starts the container.
        ///     </item>
        ///     <item>
        ///     Uploads the generated script to the node to [<see cref="HiveHostFolders.Scripts"/>/<paramref name="containerName"/>.sh].
        ///     </item>
        /// </list>
        /// </remarks>
        public static void StartContainer(SshProxy <NodeDefinition> node, string containerName, string image, RunOptions runOptions = RunOptions.FaultOnError, params IBashCommandFormatter[] commands)
        {
            Covenant.Requires <ArgumentNullException>(node != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(containerName));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(image));
            Covenant.Requires <ArgumentNullException>(commands != null);
            Covenant.Requires <ArgumentNullException>(commands.Length > 0);

            node.Status = $"start: {containerName}";

            // Generate the container start script.

            var script = CreateStartScript(containerName, image, true, commands);

            // Upload the script to the target node and set permissions.

            var scriptPath = LinuxPath.Combine(HiveHostFolders.Scripts, $"{containerName}.sh");

            node.UploadText(scriptPath, script);
            node.SudoCommand($"chmod 740 {scriptPath}");

            // Run the script without a parameter to start the container.

            node.IdempotentDockerCommand($"setup/{containerName}", null, runOptions, scriptPath);

            node.Status = string.Empty;
        }
Exemplo n.º 4
0
        /// <summary>
        /// Pushes a file to device
        /// </summary>
        /// <param name="localFilePath">the absolute path to file on local host</param>
        /// <returns>destination path on device for file</returns>
        /// <exception cref="IOException">if fatal error occurred when pushing file</exception>
        public String SyncPackageToDevice(String localFilePath)
        {
            try {
                String packageFileName = Path.GetFileName(localFilePath);
                // only root has access to /data/local/tmp/... not sure how adb does it then...
                // workitem: 16823
                // workitem: 19711
                String remoteFilePath = LinuxPath.Combine(TEMP_DIRECTORY_FOR_INSTALL, packageFileName);

                Console.WriteLine(String.Format("Uploading {0} onto device '{1}'", packageFileName, SerialNumber));
                Log.d(packageFileName, String.Format("Uploading {0} onto device '{1}'", packageFileName, SerialNumber));

                SyncService sync = SyncService;
                if (sync != null)
                {
                    String message = String.Format("Uploading file onto device '{0}'", SerialNumber);
                    Log.d(LOG_TAG, message);
                    SyncResult result = sync.PushFile(localFilePath, remoteFilePath, SyncService.NullProgressMonitor);

                    if (result.Code != ErrorCodeHelper.RESULT_OK)
                    {
                        throw new IOException(String.Format("Unable to upload file: {0}", result.Message));
                    }
                }
                else
                {
                    throw new IOException("Unable to open sync connection!");
                }
                return(remoteFilePath);
            } catch (IOException e) {
                Log.e(LOG_TAG, String.Format("Unable to open sync connection! reason: {0}", e.Message));
                throw;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// this is a fallback if the mkdir -p fails for somereason
        /// </summary>
        /// <param name="path"></param>
        internal void MakeDirectoryFallbackInternal(string path, CommandErrorReceiver cer)
        {
            string[]  segs    = path.Split(new char[] { LinuxPath.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
            FileEntry current = Device.FileListingService.Root;

            foreach (var pathItem in segs)
            {
                FileEntry[] entries = Device.FileListingService.GetChildren(current, true, null);
                bool        found   = false;
                foreach (var e in entries)
                {
                    if (string.Compare(e.Name, pathItem, false) == 0)
                    {
                        current = e;
                        found   = true;
                        break;
                    }
                }

                if (!found)
                {
                    current = FileEntry.FindOrCreate(Device, LinuxPath.Combine(current.FullPath, pathItem + new string(new char[] { LinuxPath.DirectorySeparatorChar })));
                    Device.ExecuteShellCommand("mkdir {0}", cer, current.FullEscapedPath);
                }
            }
        }
Exemplo n.º 6
0
        public void When2ArgsAndPath1IsEmptyAndPath2IsRooted_ShouldReturnRootedPath2( )
        {
            var fixture = new Fixture( );
            var p2      = fixture.Create("/path2-");
            var result  = LinuxPath.Combine(string.Empty, p2);

            Assert.Equal("/{0}/".With(p2).REReplace("//", "/"), result);
        }
Exemplo n.º 7
0
        public void When2ArgsAndPath1IsEmpty_ShouldReturnRelativePath2( )
        {
            var fixture = new Fixture( );
            var p2      = fixture.Create("path2-");
            var result  = LinuxPath.Combine(string.Empty, p2);

            Assert.Equal("./{0}/".With(p2), result);
        }
Exemplo n.º 8
0
        public void When4ArgsAndPath4IsNull_ShouldThrowArgumentNullException( )
        {
            var fixture = new Fixture( );

            Assert.Throws <ArgumentNullException> (() => {
                var result = LinuxPath.Combine(fixture.Create("path1"), fixture.Create("path2"), fixture.Create("path3"), null);
            });
        }
Exemplo n.º 9
0
        public void WhenArgsArrayIsNull_ShouldThrowArgumentNullException( )
        {
            var fixture = new Fixture( );

            string[] args = null;
            Assert.Throws <ArgumentNullException> (() => {
                LinuxPath.Combine(args);
            });
        }
Exemplo n.º 10
0
        public void When2ArgsAndPath2IsRooted_ShouldReturnPath2( )
        {
            var fixture = new Fixture( );
            var p1      = fixture.Create("/path1-");
            var p2      = fixture.Create("/path2-");
            var result  = LinuxPath.Combine(p1, p2);

            Assert.Equal("{0}/".With(p2), result);
        }
Exemplo n.º 11
0
        public void When2ArgsAndPathsHaveSeparators_ShouldReturnCombined( )
        {
            var fixture = new Fixture( );
            var p1      = "{0}/".With(fixture.Create("/path1"));
            var p2      = fixture.Create("path2");
            var result  = LinuxPath.Combine(p1, p2);

            Assert.Equal("{0}/{1}".With(p1, p2).REReplace("//", "/"), result);
        }
Exemplo n.º 12
0
        public void When2Args_ShouldReturnCombined( )
        {
            var fixture = new Fixture( );
            var p1      = fixture.Create("/path1");
            var p2      = fixture.Create("path2");
            var result  = LinuxPath.Combine(p1, p2);

            Assert.Equal("{0}/{1}".With(p1, p2), result);
        }
Exemplo n.º 13
0
        public void WhenPathIsDirectory_ShouldReturnEmpty( )
        {
            var fixture = new Fixture( );
            var p1      = fixture.Create("/path1-");
            var p2      = "{0}/".With(fixture.Create("path2-"));
            var p       = LinuxPath.Combine(p1, p2);
            var result  = LinuxPath.GetFileName(p);

            Assert.Equal(string.Empty, result);
        }
Exemplo n.º 14
0
        public void When4Args_ShouldReturnCombined( )
        {
            var fixture = new Fixture( );
            var p1      = fixture.Create("/path1");
            var p2      = fixture.Create("path2/");
            var p3      = fixture.Create("./path3");
            var p4      = fixture.Create("path4/");
            var result  = LinuxPath.Combine(p1, p2, p3, p4);

            Assert.Equal("{0}/{1}/{2}/{3}".With(p1, p2, p3, p4), result);
        }
Exemplo n.º 15
0
        public void WhenPathIsFileWithoutExtension_ShouldReturnFileWithoutExtension( )
        {
            var fixture = new Fixture( );
            var p1      = fixture.Create("/path1-");
            var p2      = "{0}/".With(fixture.Create("path2-"));
            var f       = "{0}".With(fixture.Create("file-"));
            var p       = LinuxPath.Combine(p1, p2, f);
            var result  = LinuxPath.GetFileName(p);

            Assert.Equal(f, result);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Updates a service or container start script on a hive node with a new image.
        /// </summary>
        /// <param name="node">The target hive node.</param>
        /// <param name="scriptName">The script name (without the <b>.sh</b>).</param>
        /// <param name="image">The fully qualified image name.</param>
        private static void UpdateStartScript(SshProxy <NodeDefinition> node, string scriptName, string image)
        {
            var scriptPath = LinuxPath.Combine(HiveHostFolders.Scripts, $"{scriptName}.sh");

            node.Status = $"edit: {scriptPath}";

            if (node.FileExists(scriptPath))
            {
                var curScript   = node.DownloadText(scriptPath);
                var sbNewScript = new StringBuilder();

                // Scan for the generated code section and then replace the first
                // line that looks like:
                //
                //      TARGET_IMAGE=OLD-IMAGE
                //
                // with the new image and then upload the change.

                using (var reader = new StringReader(curScript))
                {
                    var inGenerated = false;
                    var wasEdited   = false;

                    foreach (var line in reader.Lines())
                    {
                        if (wasEdited)
                        {
                            sbNewScript.AppendLine(line);
                            continue;
                        }

                        if (!inGenerated && line.StartsWith(ServiceHelper.ParamSectionMarker))
                        {
                            inGenerated = true;
                        }

                        if (line.StartsWith("TARGET_IMAGE="))
                        {
                            sbNewScript.AppendLine($"TARGET_IMAGE={image}");
                            wasEdited = true;
                        }
                        else
                        {
                            sbNewScript.AppendLine(line);
                        }
                    }
                }

                node.UploadText(scriptPath, sbNewScript.ToString(), permissions: "740");
            }

            node.Status = string.Empty;
        }
Exemplo n.º 17
0
        public SyncResult DoPush(IEnumerable <FileSystemInfo> files, string remotePath, ISyncProgressMonitor monitor)
        {
            if (monitor == null)
            {
                throw new ArgumentNullException("monitor", "Monitor cannot be null");
            }

            // check if we're canceled
            if (monitor.IsCanceled)
            {
                return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED));
            }

            foreach (FileSystemInfo f in files)
            {
                // check if we're canceled
                if (monitor.IsCanceled)
                {
                    return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED));
                }

                // append the name of the directory/file to the remote path
                string dest = LinuxPath.Combine(remotePath, f.Name);
                if (f.Exists)
                {
                    if (f.IsDirectory())
                    {
                        DirectoryInfo fsiDir = f as DirectoryInfo;
                        monitor.StartSubTask(f.FullName, dest);
                        SyncResult result = this.DoPush(fsiDir.GetFileSystemInfos(), dest, monitor);

                        if (result.Code != ErrorCodeHelper.RESULT_OK)
                        {
                            return(result);
                        }

                        monitor.Advance(1);
                    }
                    else if (f.IsFile())
                    {
                        monitor.StartSubTask(f.FullName, dest);
                        SyncResult result = this.DoPushFile(f.FullName, dest, monitor);
                        if (result.Code != ErrorCodeHelper.RESULT_OK)
                        {
                            return(result);
                        }
                    }
                }
            }

            return(new SyncResult(ErrorCodeHelper.RESULT_OK));
        }
Exemplo n.º 18
0
        public void WhenArgsArray_ShouldReturnCombined( )
        {
            var fixture  = new Fixture( );
            var p1       = fixture.Create("/path1");
            var p2       = fixture.Create("path2");
            var p3       = fixture.Create("path3");
            var p4       = fixture.Create("path4");
            var p5       = fixture.Create("path5");
            var result   = LinuxPath.Combine(p1, p2, p3, p4, p5);
            var expected = "{0}/{1}/{2}/{3}/{4}".With(p1, p2, p3, p4, p5);

            Assert.Equal(expected, result);
        }
Exemplo n.º 19
0
        public void WhenArgsArrayContainsNullItem_ShouldThrowArgumentNullException( )
        {
            var    fixture = new Fixture( );
            var    p1      = fixture.Create("/path1");
            string p2      = null;
            var    p3      = fixture.Create("path3");
            var    p4      = fixture.Create("path4");
            var    p5      = fixture.Create("path5");

            Assert.Throws <ArgumentNullException> (() => {
                LinuxPath.Combine(p1, p2, p3, p4, p5);
            });
        }
Exemplo n.º 20
0
        /// <summary>
        /// Static constructor.
        /// </summary>
        static Node()
        {
            if (NeonHelper.IsLinux)
            {
                Name = File.ReadAllLines(LinuxPath.Combine(HostMount, "etc/hostname")).First().Trim();
            }
            else
            {
                Name = "emulated";
            }

            AgentId = Guid.NewGuid().ToString("d");
        }
Exemplo n.º 21
0
        public virtual bool Adapt(string localDirectory, string file, string remoteDirectory)
        {
            ValidateState();

            mEventProvider.OnActivityLog(new ActivityLogEventArgs(Resources.MsgActivityAdaptPushFile, true));
            if (!Push(Path.Combine(localDirectory, file), remoteDirectory))
            {
                return(false);
            }

            mEventProvider.OnActivityLog(new ActivityLogEventArgs(Resources.MsgActivityAdaptChangePermissions, true));

            return(Shell(string.Format("chmod 644 {0}", LinuxPath.Combine(remoteDirectory, file))));
        }
Exemplo n.º 22
0
        /// <summary>
        /// <para>
        /// Installs one of the Helm charts that was pre-positioned on the node
        /// VM image.  These can be fond in the <see cref="KubeNodeFolder.Helm"/>
        /// with a folder for each chart.
        /// </para>
        /// <note>
        /// This command <b>DOES NOT WAIT</b> for the Helm chart to be completely
        /// installed and any target services or assets to be running because that
        /// does not appear to be reliable.  You'll need to explicitly verify that
        /// deployment has completed when necessary.
        /// </note>
        /// </summary>
        /// <param name="chartName">The Helm chart folder name.</param>
        /// <param name="releaseName">Optional component release name.  This defaults to <paramref name="chartName"/>.</param>
        /// <param name="namespace">
        /// Optional namespace where Kubernetes namespace where the Helm chart should
        /// be installed. This defaults to <b>"default"</b>.
        /// </param>
        /// <param name="timeout">Optional timeout.  This defaults to <b>unlimited</b>.</param>
        /// <param name="values">Optional Helm chart value overrides.</param>
        public void InstallProvisionedHelmChart(
            string chartName,
            string releaseName = null,
            string @namespace  = "default",
            TimeSpan timeout   = default,
            List <KeyValuePair <string, object> > values = null)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(chartName), nameof(chartName));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(@namespace), nameof(@namespace));

            if (string.IsNullOrEmpty(releaseName))
            {
                releaseName = chartName;
            }

            var valueArgs = new StringBuilder();

            if (values != null)
            {
                foreach (var value in values)
                {
                    var valueType = value.Value.GetType();

                    if (valueType == typeof(string))
                    {
                        valueArgs.AppendWithSeparator($"--set-string {value.Key}=\"{value.Value}\"", @"\n");
                    }
                    else if (valueType == typeof(int))
                    {
                        valueArgs.AppendWithSeparator($"--set {value.Key}={value.Value}", @"\n");
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
            }

            var timeoutArg = string.Empty;

            if (timeout > TimeSpan.Zero)
            {
                timeoutArg = $"--timeout {(int)Math.Ceiling(timeout.TotalSeconds)}s";
            }

            var chartFolderPath = LinuxPath.Combine(KubeNodeFolder.Helm, chartName);
            var chartValuesPath = LinuxPath.Combine(chartFolderPath, "values.yaml");

            SudoCommand($"helm install {releaseName} {chartFolderPath} --namespace {@namespace} -f {chartValuesPath} {valueArgs} {timeoutArg}", RunOptions.Defaults | RunOptions.FaultOnError);
        }
Exemplo n.º 23
0
        public void When2ArgsAndPath2ContainsInvalidCharacter_ShouldThrowArgumentException( )
        {
            var fixture    = new Fixture( );
            int errorCount = 0;

            for (var x = 0; x < LinuxPathConsts.InvalidPathChars.Length; ++x)
            {
                try {
                    string result = LinuxPath.Combine("/{0}".With(fixture.Create("path1")), "{0}-{1}".With(fixture.Create("path2"), LinuxPathConsts.InvalidPathChars[x]));
                } catch (ArgumentException) {
                    errorCount++;
                }
            }

            Assert.Equal(LinuxPathConsts.InvalidPathChars.Length, errorCount);
        }
Exemplo n.º 24
0
        /// <summary>
        /// Installs the Helm charts as a single ZIP archive written to the
        /// neonKUBE node's Helm folder.
        /// </summary>
        /// <param name="node">The node instance.</param>
        /// <param name="controller">The setup controller.</param>
        public static void NodeInstallHelmArchive(this ILinuxSshProxy node, ISetupController controller)
        {
            Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller));

            using (var ms = new MemoryStream())
            {
                controller.LogProgress(node, verb: "setup", message: "helm charts (zip)");

                var helmFolder = KubeSetup.Resources.GetDirectory("/Helm");    // $hack(jefflill): https://github.com/nforgeio/neonKUBE/issues/1121

                helmFolder.Zip(ms, searchOptions: SearchOption.AllDirectories, zipOptions: StaticZipOptions.LinuxLineEndings);

                ms.Seek(0, SeekOrigin.Begin);
                node.Upload(LinuxPath.Combine(KubeNodeFolder.Helm, "charts.zip"), ms, permissions: "660");
            }
        }
Exemplo n.º 25
0
        /// <summary>
        /// Prepends any required generic hive updates initialization steps
        /// to a setup controller.
        /// </summary>
        /// <param name="controller">The setup controller.</param>
        protected void Initialize(SetupController <NodeDefinition> controller)
        {
            Covenant.Requires <ArgumentNullException>(controller != null);

            controller.AddStep(GetStepLabel("initialize"),
                               (node, stepDelay) =>
            {
                node.Status = "update state";

                var updateFolder = LinuxPath.Combine(HiveHostFolders.State, "update", ToVersion.ToString());

                node.SudoCommand("mkdir -p", updateFolder);
                node.SudoCommand("chmod 770", updateFolder);
            },
                               noParallelLimit: true,
                               position: 0);
        }
Exemplo n.º 26
0
        public override bool Push(string localFile, string remotePath)
        {
            ValidateState();

            string remoteFile = remotePath;

            try
            {
                if (ADBDevice.FileListingService.FindFileEntry(remotePath).IsDirectory)
                {
                    remoteFile = LinuxPath.Combine(remotePath, Path.GetFileName(localFile));
                }
            }
            catch (FileNotFoundException) { }

            return(ProcessSyncResult(ADBDevice.SyncService.PushFile(localFile, remoteFile, new SingleFileProgressMonitor(this, localFile))));
        }
Exemplo n.º 27
0
        /// <summary>
        /// Update the Elasticsearch container launch scripts to enable automatic
        /// memory settings based on any cgroup limits.
        /// </summary>
        /// <param name="node">The target node.</param>
        private void UpdateElasticsearch(SshProxy <NodeDefinition> node)
        {
            // This method is called for all cluster nodes, even those
            // that aren't currently hosting Elasticsearch, so we can
            // update any scripts that may have been orphaned (for
            // consistency).
            //
            // The update consists of replacing the script line that
            // sets the [ES_JAVA_OPTS] environment variable with:
            //
            //      --env ES_JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap \
            //
            // To ensure that this feature is enabled in favor of the
            // old hacked memory level settings.

            var scriptPath = LinuxPath.Combine(HiveHostFolders.Scripts, "neon-log-esdata.sh");

            node.InvokeIdempotentAction(GetIdempotentTag("neon-log-esdata"),
                                        () =>
            {
                if (node.FileExists(scriptPath))
                {
                    node.Status = $"edit: {scriptPath}";

                    var orgScript = node.DownloadText(scriptPath);
                    var newScript = new StringBuilder();

                    foreach (var line in new StringReader(orgScript).Lines())
                    {
                        if (line.Contains("ES_JAVA_OPTS="))
                        {
                            newScript.AppendLine("    --env \"ES_JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap\" \\");
                        }
                        else
                        {
                            newScript.AppendLine(line);
                        }
                    }

                    node.UploadText(scriptPath, newScript.ToString(), permissions: "");

                    node.Status = string.Empty;
                }
            });
        }
Exemplo n.º 28
0
        /// <summary>
        /// Appends the steps required to start a neonHIVE related Docker container and upload
        /// a script to the hive managers to make it easy to restart the service manually or
        /// for hive updates.
        /// </summary>
        /// <param name="hive">The target hive.</param>
        /// <param name="steps">The target step list.</param>
        /// <param name="node">The target hive node.</param>
        /// <param name="containerName">Identifies the service.</param>
        /// <param name="image">The Docker image to be used by the container.</param>
        /// <param name="command">The <c>docker service create ...</c> command.</param>
        /// <param name="runOptions">Optional run options (defaults to <see cref="RunOptions.FaultOnError"/>).</param>
        /// <remarks>
        /// <para>
        /// This method performs the following steps:
        /// </para>
        /// <list type="number">
        ///     <item>
        ///     Passes <paramref name="image"/> to <see cref="Program.ResolveDockerImage(string)"/> to
        ///     obtain the actual image to be started.
        ///     </item>
        ///     <item>
        ///     Generates the first few lines of the script file that sets the
        ///     default image as the <c>TARGET_IMAGE</c> macro and then overrides
        ///     this with the script parameter (if there is one).  We also add
        ///     a Docker command that pulls the image.
        ///     </item>
        ///     <item>
        ///     Appends the commands to the script, replacing any text that matches
        ///     <see cref="ImagePlaceholderArg"/> with <c>${TARGET_IMAGE}</c> to make it easy
        ///     for services to be upgraded later.
        ///     </item>
        ///     <item>
        ///     Starts the service.
        ///     </item>
        ///     <item>
        ///     Uploads the generated script to each hive manager to [<see cref="HiveHostFolders.Scripts"/>/<paramref name="containerName"/>.sh].
        ///     </item>
        /// </list>
        /// </remarks>
        public static void AddContainerStartSteps(HiveProxy hive, ConfigStepList steps, SshProxy <NodeDefinition> node, string containerName, string image, IBashCommandFormatter command, RunOptions runOptions = RunOptions.FaultOnError)
        {
            Covenant.Requires <ArgumentNullException>(hive != null);
            Covenant.Requires <ArgumentNullException>(steps != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(containerName));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(image));
            Covenant.Requires <ArgumentNullException>(command != null);

            // Generate the container start script.

            var script = CreateStartScript(containerName, image, true, command);

            // Add steps to upload the script to the managers and then call the script
            // to create the container on the target node.

            var scriptPath = LinuxPath.Combine(HiveHostFolders.Scripts, $"{containerName}.sh");

            steps.Add(hive.GetFileUploadSteps(node, scriptPath, script, permissions: "740"));
            steps.Add(CommandStep.CreateIdempotentDocker(node.Name, $"setup/{containerName}", scriptPath));
        }
Exemplo n.º 29
0
        /// <summary>
        /// Appends the steps required to start a neonHIVE related Docker service and upload
        /// a script to the hive managers to make it easy to restart the service manually or
        /// for hive updates.
        /// </summary>
        /// <param name="hive">The target hive.</param>
        /// <param name="steps">The target step list.</param>
        /// <param name="serviceName">Identifies the service.</param>
        /// <param name="image">The Docker image to be used by the service.</param>
        /// <param name="command">The <c>docker service create ...</c> command.</param>
        /// <param name="runOptions">Optional run options (defaults to <see cref="RunOptions.FaultOnError"/>).</param>
        /// <remarks>
        /// <para>
        /// This method performs the following steps:
        /// </para>
        /// <list type="number">
        ///     <item>
        ///     Passes <paramref name="image"/> to <see cref="Program.ResolveDockerImage(string)"/> to
        ///     obtain the actual image to be started.
        ///     </item>
        ///     <item>
        ///     Generates the first few lines of the script file that sets the
        ///     default image as the <c>TARGET_IMAGE</c> macro and then overrides
        ///     this with the script parameter (if there is one).
        ///     </item>
        ///     <item>
        ///     Appends the commands to the script, replacing any text that matches
        ///     <see cref="ImagePlaceholderArg"/> with <c>${TARGET_IMAGE}</c> to make it easy
        ///     for services to be upgraded later.
        ///     </item>
        ///     <item>
        ///     Starts the service.
        ///     </item>
        ///     <item>
        ///     Uploads the generated script to each hive manager to [<see cref="HiveHostFolders.Scripts"/>/<paramref name="serviceName"/>.sh].
        ///     </item>
        /// </list>
        /// </remarks>
        public static void AddServiceStartSteps(HiveProxy hive, ConfigStepList steps, string serviceName, string image, IBashCommandFormatter command, RunOptions runOptions = RunOptions.FaultOnError)
        {
            Covenant.Requires <ArgumentNullException>(hive != null);
            Covenant.Requires <ArgumentNullException>(steps != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(serviceName));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(image));
            Covenant.Requires <ArgumentNullException>(command != null);

            // Generate the service start script.

            var script = CreateStartScript(serviceName, image, false, command);

            // Add steps to upload the script to the managers and then call the script
            // to create the service on the first manager.

            var scriptPath = LinuxPath.Combine(HiveHostFolders.Scripts, $"{serviceName}.sh");

            steps.Add(hive.GetFileUploadSteps(hive.Managers, scriptPath, script, permissions: "740"));
            steps.Add(CommandStep.CreateIdempotentDocker(hive.FirstManager.Name, $"setup/{serviceName}", scriptPath));
        }
Exemplo n.º 30
0
        /// <summary>
        /// Starts a neonHIVE related Docker service and also uploads a script to the
        /// hive managers to make it easy to restart the service manually or for hive
        /// updates.
        /// </summary>
        /// <param name="hive">The target hive.</param>
        /// <param name="serviceName">Identifies the service.</param>
        /// <param name="image">The Docker image to be used by the service.</param>
        /// <param name="command">The <c>docker service create ...</c> command.</param>
        /// <param name="runOptions">Optional run options (defaults to <see cref="RunOptions.FaultOnError"/>).</param>
        /// <remarks>
        /// <para>
        /// This method performs the following steps:
        /// </para>
        /// <list type="number">
        ///     <item>
        ///     Passes <paramref name="image"/> to <see cref="Program.ResolveDockerImage(string)"/> to
        ///     obtain the actual image to be started.
        ///     </item>
        ///     <item>
        ///     Generates the first few lines of the script file that sets the
        ///     default image as the <c>TARGET_IMAGE</c> macro and then overrides
        ///     this with the script parameter (if there is one).
        ///     </item>
        ///     <item>
        ///     Appends the commands to the script, replacing any text that matches
        ///     <see cref="ImagePlaceholderArg"/> with <c>${TARGET_IMAGE}</c> to make it easy
        ///     for services to be upgraded later.
        ///     </item>
        ///     <item>
        ///     Starts the service.
        ///     </item>
        ///     <item>
        ///     Uploads the generated script to each hive manager to [<see cref="HiveHostFolders.Scripts"/>/<paramref name="serviceName"/>.sh].
        ///     </item>
        /// </list>
        /// </remarks>
        public static void StartService(HiveProxy hive, string serviceName, string image, IBashCommandFormatter command, RunOptions runOptions = RunOptions.FaultOnError)
        {
            Covenant.Requires <ArgumentNullException>(hive != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(serviceName));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrWhiteSpace(image));
            Covenant.Requires <ArgumentNullException>(command != null);

            var firstManager = hive.FirstManager;

            firstManager.Status = $"start: {serviceName}";

            // Generate the service start script.

            var script = CreateStartScript(serviceName, image, false, command);

            // Upload the script to each of the manager nodes and set permissions.

            var scriptPath = LinuxPath.Combine(HiveHostFolders.Scripts, $"{serviceName}.sh");

            foreach (var manager in hive.Managers)
            {
                manager.UploadText(scriptPath, script);
                manager.SudoCommand($"chmod 740 {scriptPath}");
            }

            // Run the script without a parameter on the first manager to start the service.

            firstManager.IdempotentDockerCommand($"setup/{serviceName}",
                                                 response =>
            {
                if (response.ExitCode != 0)
                {
                    firstManager.Fault(response.ErrorSummary);
                }
            },
                                                 runOptions,
                                                 scriptPath);

            firstManager.Status = string.Empty;
        }