Ejemplo n.º 1
0
        internal static async Task SaveSecret(string key, string value)
        {
            // TODO - pull secrets id from assembly info.
            // Setting ID here so that marvel-tools secrets can be separate from project-specific secrets
            // Ideally we can remove the dependency on the user secrets tools package from the app as well, and call it directly from here, but I'm not sure what that would look like yet.
            var result = await CommandUtilities.RunCommandAsync("dotnet", $"user-secrets set --id marvel-tools-bh61t9klymwu5qfohd1paq44slmg76rpur103ewo {key} {value}", throwOnErrorExitCode : false);

            if (result.ExitCode != 0)
            {
                if (result.StandardError.Any(line => line.Contains("No executable found matching command \"dotnet-user-secrets\"")))
                {
                    // TODO add example and/or additional help link
                    throw new InvalidOperationException($"Unable to save secret for \"{key}\". dotnet-user-secrets command not found. " +
                                                        "Ensure you have \"Microsoft.Extensions.SecretManager.Tools\": \"1.1.0-preview4-final\" defined in the \"tools\" section of your project.json " +
                                                        "and you've run `dotnet restore`.");
                }
                if (result.StandardError.Concat(result.StandardOutput).Any(line => line.Contains("Missing 'userSecretsId'")))
                {
                    // TODO - add exact key needed or an example, docs link, etc.
                    throw new InvalidOperationException("Missing 'userSecretsId' in project.json.");
                }

                throw new Exception($"Unable to save secret for \"{key}\". Ensure you have \"Microsoft.Extensions.SecretManager.Tools\": \"1.1.0-preview4-final\" defined in " +
                                    $"the \"tools\" section of your project.json and you've run `dotnet restore`. StandardOutput={string.Join("\n", result.StandardOutput)} StandardError={string.Join("\n", result.StandardError)}");
            }
        }
Ejemplo n.º 2
0
        private static int PublishClientPackage(MarvelMicroserviceConfig config, string nugetApiKey, string awsAccessKey, string awsAccessSecret, string branch, string gitSha, string buildNumber)
        {
            var clientDir = config.ClientPackageDirectory;

            if (!Directory.Exists(clientDir))
            {
                Output.Info($"No client package directory found at {clientDir}.");
                Output.Info($"Skipping client package publish.");
                return(0);
            }
            Output.Info("Publishing Client NuGet package.");
            var exitCode = CommandUtilities.ExecuteCommand("dotnet", $"restore", workingDirectory: clientDir);

            if (exitCode != 0)
            {
                return(exitCode);
            }

            exitCode = CommandUtilities.ExecuteCommand("dotnet", $"library publish " +
                                                       $"-b {branch} " +
                                                       $"-k {nugetApiKey} " +
                                                       $"-a {awsAccessKey} " +
                                                       $"-s {awsAccessSecret} " +
                                                       $"-n {buildNumber} " +
                                                       $"--tests-optional", workingDirectory: clientDir);
            if (exitCode != 0)
            {
                return(exitCode);
            }

            return(0);
        }
Ejemplo n.º 3
0
        private static async Task <List <ContainerInfo> > GetContainers(string filter = null)
        {
            await EnsureDockerIsRunning();

            var format    = "\"{{.ID}}\t{{.Status}}\t{{.Image}}\t{{.CreatedAt}}\t{{.Labels}}\"";
            var filterArg = string.IsNullOrWhiteSpace(filter) ? "" : $" -f \"{filter}\" ";
            var arguments = $"ps -a {filterArg}--format {format}";
            var results   = await CommandUtilities.RunCommandAsync("docker", arguments, errorMessage : "Failed to list containers.");

            var containers = results.StandardOutput
                             .Where(outputLine => !string.IsNullOrWhiteSpace(outputLine))
                             .Select(outputLine =>
            {
                var split = outputLine.Split('\t');

                return(new ContainerInfo
                {
                    ContainerId = split[0],
                    IsRunning = split[1].StartsWith("Up"),
                    // ImageId = split[2],
                    CreatedAt = ParseDateString(split[3]),
                    Labels = ParseLabels(split[4]),
                });
            });

            return(containers.ToList());
        }
Ejemplo n.º 4
0
 private static async Task EnsureDockerIsInstalled()
 {
     try
     {
         await CommandUtilities.RunCommandAsync("docker", "-v", throwOnErrorExitCode : true);
     }
     catch (Exception e)
     {
         throw new Exception("Docker is not found. Docker is required to run integration tests.", e);
     }
 }
Ejemplo n.º 5
0
        // private static async Task<ContainerInfo> GetContainerById(string containerId)
        // {
        //     return await GetContainer($"id={containerId}");
        // }

        public static async Task <ContainerInfo> CreateContainer(string arguments)
        {
            await EnsureDockerIsRunning();

            var create = await CommandUtilities.RunCommandAsync("docker", $"create -i {arguments}");

            var containerId = create.StandardOutput.FirstOrDefault();

            return(new ContainerInfo
            {
                ContainerId = containerId,
                IsRunning = false,
            });
        }
Ejemplo n.º 6
0
        protected override async Task <int> Run(MarvelMicroserviceConfig config)
        {
            var launchOptionsResult = await _launchOptions.ProcessOptions();

            if (!launchOptionsResult.AreValid)
            {
                return(1);
            }

            var exitCode = await LaunchCommand.Launch(config, launchOptionsResult.Value);

            if (exitCode != 0)
            {
                return(exitCode);
            }

            var containerName = config.DevContainerName;

            var container = await DockerCommands.GetContainerByName(containerName);

            if (container?.IsRunning != true)
            {
                Output.Info($"Could not find running container {containerName}");
                return(1);
            }

            // Call basic command to see if we're executing in a TTY
            var ttyTest = await CommandUtilities.RunCommandAsync("docker", $"exec -it {container.ContainerId} /bin/bash -c echo hi", throwOnErrorExitCode : false);

            var isTty = true;

            if (ttyTest.ExitCode != 0)
            {
                var stdErr = string.Join("\n", ttyTest.StandardError);
                if (!stdErr.Contains("input device is not a TTY"))
                {
                    throw new Exception($"Unexpected exception encounterd checking for TTY StandardError={stdErr}");
                }
                isTty = false;
            }

            Output.Info($"Attaching to container {containerName}");
            // Use TTY option when available so that Ctrl+C in the terminal kills the process inside the container as well. Option cannot be used during integration test runs.
            var ttyArg = isTty ? "t" : "";

            exitCode = CommandUtilities.ExecuteCommand("docker", $"exec -i{ttyArg} {container.ContainerId} /bin/bash {ContainerPaths.DockerTaskScriptPath} watchAndRun");

            return(exitCode);
        }
Ejemplo n.º 7
0
        // public static async Task<ImageInfo> GetImageInfoByImageId(string imageId)
        // {
        //     var result = await ProcessEx.RunAsync("docker", $"images --format {ImageInfoFormat}");
        //     if (result.ExitCode != 0)
        //     {
        //         throw new Exception($"Failed to list images.");
        //     }

        //     // This can return multiple matches of a single image ID with varying repository:tag, but the CreatedAt field will be the same.
        //     var matchingImage = result.StandardOutput.Select(ParseImageInfo)
        //         .Where(image => image.ImageId == imageId)
        //         .FirstOrDefault();

        //     if (matchingImage == null)
        //     {
        //         throw new Exception($"No image found matching id `{imageId}`");
        //     }
        //     return matchingImage;
        // }

        public static async Task <ImageInfo> GetImageInfoByName(string imageName)
        {
            await EnsureDockerIsRunning();

            var result = await CommandUtilities.RunCommandAsync("docker", $"images {imageName} --format {ImageInfoFormat}", errorMessage : $"Failed to list images for image name {imageName}.");

            // This can return multiple matches of a single image ID with varying repository:tag, but the CreatedAt field will be the same.
            var image = result.StandardOutput.Select(ParseImageInfo)
                        .FirstOrDefault();

            if (image == null)
            {
                throw new Exception($"No image found matching name `{imageName}`");
            }
            return(image);
        }
Ejemplo n.º 8
0
        protected override async Task <int> Run(MarvelMicroserviceConfig config)
        {
            var exitCode = 0;

            var containerName = config.DevContainerName;

            var container = await DockerCommands.GetContainerByName(containerName);

            if (container?.IsRunning != true)
            {
                Output.Info($"Could not find running container {containerName}");
                return(1);
            }

            Output.Info($"Attaching to container {containerName}");

            exitCode = CommandUtilities.ExecuteCommand("docker", $"exec -i {container.ContainerId} /bin/bash {ContainerPaths.DockerTaskScriptPath} watchAndDebug");

            return(exitCode);
        }
Ejemplo n.º 9
0
        internal static async Task EnsureDockerIsRunning()
        {
            await EnsureDockerIsInstalled();

            var result = await CommandUtilities.RunCommandAsync("docker", "ps", throwOnErrorExitCode : false);

            if (result.ExitCode == 0)
            {
                return;
            }

            if (result.StandardError.Any(line => line.Contains("Cannot connect to the Docker daemon")))
            {
                throw new Exception("Failed to connect to Docker. Ensure Docker is running. If Docker is running, it may need restarted.");
            }
            else
            {
                throw new Exception("Unexpected error connecting to Docker. If Docker is running, it may need restarted.");
            }
        }
Ejemplo n.º 10
0
        public static async Task <string> GetFriendlyHostName()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // Using LocalHostName config on a Mac because HostName commonly isn't set, resulting in something like "ip-192-168-1-127"
                // from Environment.MachineName (as well as the `hostname` command). LocalHostName is also easily configurable via the Sharing panel in System Preferences.
                var localHostName = (await CommandUtilities.RunCommandAsync("scutil", "--get LocalHostName")).StandardOutput.FirstOrDefault()?.ToLower();
                // TODO - ensure localHostName is valid subdomain
                if (!string.IsNullOrWhiteSpace(localHostName))
                {
                    Output.Verbose($"[{nameof(NetworkUtility.GetFriendlyHostName)}] Using macOS local hostname (configurable via \"System Preferences > Sharing\"): {localHostName}");
                    return(localHostName);
                }
            }

            var machineName = Environment.MachineName;

            Output.Verbose($"[{nameof(NetworkUtility.GetFriendlyHostName)}] Using general machine name: {machineName}");

            return(machineName);
        }
Ejemplo n.º 11
0
        internal async Task <string> GetClientVersionSuffix(string branchName, string buildNumber)
        {
            await CommandUtilities.RunCommandAsync(
                "dotnet",
                "restore",
                workingDirectory : _serviceConfig.ClientPackageDirectory
                );

            var result = await CommandUtilities.RunCommandAsync(
                "dotnet",
                $"library create-version-suffix " +
                $"-b {branchName} -n {buildNumber}",
                workingDirectory : _serviceConfig.ClientPackageDirectory,
                errorMessage : "Failed to retrieve version suffix for client package"
                );

            // This is potentially fragile, as the first line of the output currently is "baseDir is ..."
            // Ideally we would only return the version suffix to stdout. We don't log anything
            // afterward in the library CLI main, so this is safe enough for now, but we might want to
            // change this in the future. If we can call the library code directly, we won't have this
            // issue anyway.
            return((result.StandardOutput.LastOrDefault() ?? "").Trim());
        }
        public async Task MergeConfigurationFilesAsync(string baseDirectory, string defaultPath, string overridesPath, string outputPath)
        {
            var buildImageUri = await EcrResources.HsdImageUrl.EnsureImageIsPulled();

            if (!buildImageUri.WasSuccessful)
            {
                throw new Exception($"Unable to get image {buildImageUri.Value} from ECR");
            }

            var dockerRunOptions = new List <string>
            {
                $"--rm",
                $"-v {baseDirectory}:{ContainerPaths.MountedSourceDirectory}"
            };

            var hsdMergeCommand = $"/bin/bash hsd-merge.sh {ContainerPaths.MountedSourceDirectory}/{defaultPath} {ContainerPaths.MountedSourceDirectory}/{overridesPath} {ContainerPaths.MountedSourceDirectory}/{outputPath}";
            var exitCode        = CommandUtilities.ExecuteCommand("docker", $"run {string.Join(" ", dockerRunOptions)} {buildImageUri.Value} {hsdMergeCommand}");

            if (exitCode != 0)
            {
                throw new Exception("HSD merge failed.");
            }
        }
Ejemplo n.º 13
0
        public async Task <IValidatorResults> ValidateConfigurationFile(string baseDirectory, string fileToValidate)
        {
            var buildImageUri = await EcrResources.HsdImageUrl.EnsureImageIsPulled();

            if (!buildImageUri.WasSuccessful)
            {
                throw new Exception($"Unable to get image {buildImageUri.Value} from ECR");
            }
            var validationOutputFile = $"{fileToValidate}.validation-output";
            var dockerRunOptions     = new List <string>
            {
                $"--rm",
                $"-v {baseDirectory}:{ContainerPaths.MountedSourceDirectory}"
            };

            var hsdValidateCommand = $"/bin/bash hsd-validate.sh {ContainerPaths.MountedSourceDirectory}/{fileToValidate} {ContainerPaths.MountedSourceDirectory}/{validationOutputFile}";
            var exitCode           = CommandUtilities.ExecuteCommand("docker", $"run {string.Join(" ", dockerRunOptions)} {buildImageUri.Value} {hsdValidateCommand}");

            if (exitCode != 0)
            {
                throw new Exception("HSD Validation failed.");
            }
            var outputFilePath = Path.Combine(baseDirectory, validationOutputFile);
            var outputContents = File.ReadAllText(outputFilePath);

            try
            {
                File.Delete(outputFilePath);
            }
            catch (Exception ex)
            {
                Output.Error($"Unable to delete validation output file: {ex.Message}");
            }
            var validationResult = new ValidationResult(outputContents);

            return(validationResult);
        }
Ejemplo n.º 14
0
        public static async Task <int> Build(MarvelMicroserviceConfig config, string publishedRuntimeImageName, BuildConfig buildConfig, IStaticAssetProcessor staticAssetProcessor)
        {
            var buildImageUri = await EcrResources.DotnetMicroserviceBuildImageUrl.EnsureImageIsPulled();

            if (!buildImageUri.WasSuccessful)
            {
                return(1);
            }

            var taskTimer = Stopwatch.StartNew();

            // Clear the old temp dir to ensure a fresh publish if running locally
            var outputPath = config.DotnetPublishOutputPath;

            if (Directory.Exists(outputPath))
            {
                Directory.Delete(outputPath, true);
            }
            Directory.CreateDirectory(outputPath);

            var dockerRunOptions = new List <string>
            {
                $"--rm",
                $"-e \"{LaunchCommand.ProjectNameEnvVariable}={config.ProjectName}\"",
                $"-e \"{LaunchCommand.SolutionNameEnvVariable}={config.SolutionName}\"",
                $"-e \"{WebappDirEnvVariable}={ContainerPaths.GetWebappDirectory(config)}\"",
                $"-e \"{BrowserAppDirEnvVariable}={ContainerPaths.GetBrowserAppDirectory(config)}\"",
                $"-v {config.BaseDirectory}:{ContainerPaths.MountedSourceDirectory}",
                $"-v {outputPath}:{ContainerPaths.BuildOutputDirectory}",
            };

            var runtimeImageLabelsTask = new LabelBuilder(config).GetLabels(buildConfig);

            var exitCode = 0;

            var dotnetBuildTimer = Stopwatch.StartNew();

            Output.Info($"Building dotnet webapp.");

            // Run container to build app and copy published resources to mounted output directory
            exitCode = CommandUtilities.ExecuteCommand("docker", $"run {string.Join(" ", dockerRunOptions)} {buildImageUri.Value} /bin/bash {ContainerPaths.DockerTaskScriptPath} buildWithoutCompose");
            if (exitCode != 0)
            {
                return(exitCode);
            }
            Output.Info($"dotnet webapp build completed {dotnetBuildTimer.Elapsed}");

            // Run static asset build from output directory
            await staticAssetProcessor.ProcessStaticAssets(Path.Combine(config.DotnetPublishOutputPath, "wwwroot"));

            // Build the image from the source output
            var dockerBuildTimer = Stopwatch.StartNew();

            Output.Info($"Building docker image {publishedRuntimeImageName}.");

            var labelArgs = LabelUtilities.FormatLabelsAsArguments(await runtimeImageLabelsTask);

            var buildArgs = labelArgs.Concat(new List <string> {
                $"-t {publishedRuntimeImageName}",
                $"--build-arg webappAssemblyPath={config.PublishedWebappAssemblyPath}",
                config.DotnetPublishOutputPath,
            });

            exitCode = CommandUtilities.ExecuteCommand("docker", $"build {string.Join(" ", buildArgs)}");
            if (exitCode != 0)
            {
                return(exitCode);
            }
            Output.Info($"Docker build completed {dockerBuildTimer.Elapsed}");

            Output.Info($"Build time elapsed {taskTimer.Elapsed}");

            return(exitCode);
        }
Ejemplo n.º 15
0
        public static async Task StopContainer(ContainerInfo container)
        {
            await EnsureDockerIsRunning();

            await CommandUtilities.RunCommandAsync("docker", $"stop {container.ContainerId}", errorMessage : "Failed to stop container.");
        }
Ejemplo n.º 16
0
        public static async Task <int> Launch(MarvelMicroserviceConfig config, LaunchOptions launchOptions)
        {
            var registratorRunResultTask = EnsureRegistratorContainerIsRunning(launchOptions.EurekaServer, launchOptions.LocalIpAddress);
            var buildImageUriTask        = EcrResources.DotnetMicroserviceBuildImageUrl.EnsureImageIsPulled();

            var registratorRunResult = await registratorRunResultTask;

            if (registratorRunResult != 0)
            {
                return(registratorRunResult);
            }

            var buildImageUri = await buildImageUriTask;

            if (!buildImageUri.WasSuccessful)
            {
                return(1);
            }

            // # TODO include a hash of the tools version in the container name to ensure containers are recreated after tools update(?)
            var containerName        = config.DevContainerName;
            var dockerTaskScriptPath = ContainerPaths.DockerTaskScriptPath;

            // Build arguments list for `docker create` call so we can hash them and ensure an existing container is compatible. Argument pairs are combined into one argument for readability.
            var hostname = launchOptions.Host ?? await NetworkUtility.GetFriendlyHostName();

            var labelArgs        = LabelUtilities.FormatLabelsAsArguments(await new LabelBuilder(config).GetLabelsForLocalDev(hostname));
            var dockerCreateArgs = labelArgs.Concat(new List <string>
            {
                "-p 5000:5000",
                "--dns-search=agilesports.local",
                $"-e \"{ProjectNameEnvVariable}={config.ProjectName}\"",
                $"-e \"{SolutionNameEnvVariable}={config.SolutionName}\"",
                $"-e \"{WebappDirEnvVariable}={ContainerPaths.GetWebappDirectory(config)}\"",
                $"-e \"{BrowserAppDirEnvVariable}={ContainerPaths.GetBrowserAppDirectory(config)}\"",
                // This could probably live in the image
                $"-e ASPNETCORE_ENVIRONMENT=Development",
                $"-v {config.BaseDirectory}:{ContainerPaths.MountedSourceDirectory}",
            });

            if (launchOptions.UseSharedCache)
            {
                dockerCreateArgs = dockerCreateArgs.Concat(GetCacheVolumeArgs());
            }

            var createContainerResult = await DockerCommands.GetOrCreateContainerWithName(
                containerName,
                buildImageUri.Value,
                dockerCreateArgs.ToList(),
                $"/bin/bash {dockerTaskScriptPath} hang");

            var container      = createContainerResult.Container;
            var isNewContainer = createContainerResult.IsNewContainer;

            if (!container.IsRunning)
            {
                Output.Info($"Starting container {containerName}");
                var result = await CommandUtilities.RunCommandAsync("docker", $"start {container.ContainerId}", throwOnErrorExitCode : false);

                // Output.Info("StdErr=" + string.Join("\n", result.StandardError));
                // Output.Info("StdOut=" + string.Join("\n", result.StandardOutput));
                if (result.ExitCode != 0)
                {
                    var stdErr = string.Join("\n", result.StandardError);
                    // Message is `Bind for 0.0.0.0:5000 failed: port is already allocated`. trimming the port portion in case the port changes.
                    if (stdErr.Contains("failed: port is already allocated"))
                    {
                        Output.Info("Webapp port is already in use. Attempting to stop other container using port.");
                        // Find other containers using a partial match on suffix. This corresponds to the naming scheme defined in MarvelMicroserviceConfig.
                        var containers = await DockerCommands.GetContainersByName("marvel-dev");

                        var otherContainer = containers.FirstOrDefault(c => c.IsRunning);
                        if (otherContainer == null)
                        {
                            Output.Error("Unable to find running container using same port.");
                            Output.Error($"Failed to start container {containerName}. StandardError={stdErr}");
                            return(1);
                        }
                        Output.Info($"Stopping container {otherContainer.ContainerId}");
                        await DockerCommands.StopContainer(otherContainer);

                        Output.Info($"Starting container {containerName} again");
                        var restartResult = await ProcessEx.RunAsync("docker", $"start {container.ContainerId}");

                        if (restartResult.ExitCode != 0)
                        {
                            Output.Error($"Failed to restart container {containerName}. StandardError={stdErr}");
                            return(result.ExitCode);
                        }
                    }
                    else
                    {
                        Output.Error($"Failed to start container {containerName}. StandardError={stdErr}");
                        return(result.ExitCode);
                    }
                }

                // TODO only perform this check after failed `docker exec` commands, for better reporting?
                // Ensure the container doesn't immediately exit.
                Thread.Sleep(10);

                var runningContainer = await DockerCommands.GetContainerByName(containerName);

                if (!runningContainer.IsRunning)
                {
                    Output.Error($"Container {containerName} stopped unexpectedly. Check container logs.");
                    return(1);
                }
            }

            if (isNewContainer)
            {
                Output.Info($"Attaching to container {containerName} to run first time launch command on new container");
                var code = CommandUtilities.ExecuteCommand("docker", $"exec -i {container.ContainerId} /bin/bash {dockerTaskScriptPath} firstTimeLaunch");
                if (code != 0)
                {
                    Output.Info($"First time startup command failed. Removing container.");
                    await DockerCommands.RemoveContainer(container);

                    return(code);
                }
            }
            else
            {
                Output.Info($"Attaching to container {containerName} to run relaunch command on existing container");
                var code = CommandUtilities.ExecuteCommand("docker", $"exec -i {container.ContainerId} /bin/bash {dockerTaskScriptPath} relaunch");
                if (code != 0)
                {
                    return(code);
                }
            }

            Output.Info($"Container {containerName} launched and ready to run");
            Output.Info($"Using hostname: {hostname}");
            Output.Info($"If debugging from VS Code, switch to the Debug Console (Cmd+Shift+Y / Ctrl+Shift+Y) for app and watch process logs");

            return(0);
        }
Ejemplo n.º 17
0
        private static async Task <int> EnsureRegistratorContainerIsRunning(string eurekaServerUrl, string ipAddress)
        {
            var registratorImageUri = await EcrResources.RegistratorLatestImageUrl.EnsureImageIsPulled();

            if (!registratorImageUri.WasSuccessful)
            {
                return(1);
            }

            var registratorContainerName = "registrator-marvel";

            // Build arguments list for `docker create` call so we can hash them and ensure an existing container is compatible. Argument pairs are combined into one argument for readability.
            var dockerCreateArgs = new List <string>
            {
                "--net=host",
                "--volume=/var/run/docker.sock:/tmp/docker.sock"
            };


            var createContainerResult = await DockerCommands.GetOrCreateContainerWithName(
                registratorContainerName,
                registratorImageUri.Value,
                dockerCreateArgs,
                $"-ttl 30 -ttl-refresh 15 -ip {ipAddress} -require-label {FixEurekaServerUrlScheme(eurekaServerUrl ?? DefaultEurekaServerUrl)}");

            var container      = createContainerResult.Container;
            var isNewContainer = createContainerResult.IsNewContainer;

            if (!container.IsRunning)
            {
                Output.Info($"Starting container {registratorContainerName}");
                var result = await CommandUtilities.RunCommandAsync("docker", $"start {container.ContainerId}", throwOnErrorExitCode : false);

                if (result.ExitCode != 0)
                {
                    var stdErr = string.Join("\n", result.StandardError);
                    // Message is `Bind for 0.0.0.0:5000 failed: port is already allocated`. trimming the port portion in case the port changes.
                    // if (stdErr.Contains("failed: port is already allocated"))
                    // {
                    //     Output.Info("Webapp port is already in use. Attempting to stop other container using port.");
                    //     // Find other containers using a partial match on suffix. This corresponds to the naming scheme defined in MarvelMicroserviceConfig.
                    //     var containers = await DockerCommands.GetContainersByName("marvel-dev");
                    //     var otherContainer = containers.FirstOrDefault(c => c.IsRunning);
                    //     if (otherContainer == null)
                    //     {
                    //         Output.Error("Unable to find running container using same port.");
                    //         Output.Error($"Failed to start container {containerName}. StandardError={stdErr}");
                    //         return 1;
                    //     }
                    //     Output.Info($"Stopping container {otherContainer.ContainerId}");
                    //     await DockerCommands.StopContainer(otherContainer);

                    //     Output.Info($"Starting container {containerName} again");
                    //     var restartResult = await ProcessEx.RunAsync("docker", $"start {container.ContainerId}");
                    //     if (restartResult.ExitCode != 0)
                    //     {
                    //         Output.Error($"Failed to restart container {containerName}. StandardError={stdErr}");
                    //         return result.ExitCode;
                    //     }
                    // }
                    // else
                    // {
                    Output.Error($"Failed to start container {registratorContainerName}. StandardError={stdErr}");
                    return(result.ExitCode);
                    // }
                }

                // Ensure the container doesn't immediately exit.
                // TODO Bumped this up for registrator specifically to ensure eureka host is valid. Might want to verify by scanning logs
                // that this did in fact start up properly.
                Thread.Sleep(500);

                var runningContainer = await DockerCommands.GetContainerByName(registratorContainerName);

                if (!runningContainer.IsRunning)
                {
                    Output.Error($"Container {registratorContainerName} stopped unexpectedly. Check container logs by running {DockerCommands.GetLogsForContainerCommand(runningContainer)}.");
                    return(1);
                }
            }

            // TODO - ensure registrator is ready? pause?

            Output.Info($"Container {registratorContainerName} is running.");

            return(0);
        }
Ejemplo n.º 18
0
        internal static async Task <int> Publish(MarvelMicroserviceConfig config, IBuildConfigurationBuilder configBuilder, IConfigurationFileMerger configMerger, IConfigurationFileUploader configUploader, IConfigurationFileValidator configValidator, IStaticAssetProcessor staticAssetProcessor, string nugetApiKey, string awsAccessKey, string awsAccessSecret, string branch, string gitSha, string buildNumber, bool mergeAndUploadServiceConfig, bool mergeServiceConfig)
        {
            Security.UseAwsCredentials(awsAccessKey, awsAccessSecret);

            var publishImage = ImageNameBuilder.CreateImageNameAndTag(
                config.ServiceName,
                branch,
                gitSha,
                DateTime.UtcNow,
                buildNumber);

            string[] serviceConfigFiles = null;
            if (mergeAndUploadServiceConfig || mergeServiceConfig)
            {
                GenerateBuildFile(configBuilder, config.BuildConfigFilePath, gitSha, branch, publishImage.FullPath, buildNumber);
                serviceConfigFiles = await MergeAllServiceConfigFiles(configMerger, config.SourceDirectory, config.ServiceConfigFileName, config.BuildConfigFilePath);

                var configIsValid = await ValidateAllServiceConfigFiles(configValidator, config.SourceDirectory, serviceConfigFiles);

                if (!configIsValid)
                {
                    Output.Error("Invalid service configuration.");
                    return(1);
                }
            }

            var exitCode = await BuildCommand.Build(config, publishImage.FullPath, new BuildConfig
            {
                BranchName  = branch,
                BuildNumber = buildNumber,
            }, staticAssetProcessor);

            if (exitCode != 0)
            {
                return(exitCode);
            }

            try
            {
                exitCode = PublishClientPackage(config, nugetApiKey, awsAccessKey, awsAccessSecret, branch, gitSha, buildNumber);
                if (exitCode != 0)
                {
                    return(exitCode);
                }

                // Publish to ECR
                Output.Info($"Publishing {publishImage.FullPath}");
                await Security.EnsureAuthenticatedWithEcr();

                exitCode = CommandUtilities.ExecuteCommand("docker", $"push {publishImage.FullPath}");
                if (exitCode != 0)
                {
                    return(exitCode);
                }
            }
            finally
            {
                // TODO always remove image, even on publish failure
                await CommandUtilities.RunCommandAsync("docker", $"rmi {publishImage.FullPath}", errorMessage : $"Failed to remove image {publishImage.FullPath}.");

                Output.Info($"Removed local image {publishImage.FullPath}");
            }

            try
            {
                if (mergeAndUploadServiceConfig && serviceConfigFiles != null)
                {
                    await UploadAllServiceConfigFiles(configUploader, config.SourceDirectory, serviceConfigFiles, publishImage.Tag);
                }
            }
            catch (Exception ex)
            {
                Output.Error($"Unable to upload service configuration files. Error: {ex.Message}");
                return(1);
            }

            File.WriteAllText(Path.Combine(config.WebappDirectory, "PublishedImageUrl.txt"), publishImage.FullPath);
            Output.Info("Publish successful");
            return(0);
        }
Ejemplo n.º 19
0
        public static async Task PullImage(string imageUri)
        {
            await EnsureDockerIsRunning();

            await CommandUtilities.RunCommandAsync("docker", $"pull {imageUri}", errorMessage : $"Failed to pull image {imageUri}.");
        }
Ejemplo n.º 20
0
        public static async Task RemoveContainer(ContainerInfo container)
        {
            await EnsureDockerIsRunning();

            await CommandUtilities.RunCommandAsync("docker", $"rm -f {container.ContainerId}", errorMessage : "Failed to remove container.");
        }