コード例 #1
0
        /// <summary>
        /// If true, the caller should exit
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override async Task <bool> UpdateCoreAsync(GetDeviceConfigurationResponse configuration, CancellationToken cancellationToken)
        {
            string currentVersion = await GetCurrentVersionAsync(cancellationToken);

            VersionReference nextVersion = configuration.AgentVersion;

            if (nextVersion == null)
            {
                return(false);
            }

            if (currentVersion == nextVersion.ImageId)
            {
                return(false);
            }

            //We don't support updating on linux
            if (!_platformDetecter.IsLinux)
            {
                Logger.Warning("Agent update is only supported on Linux.");
                return(false);
            }


            //Get all of the containers
            var containers = await _dockerClient.Containers.ListContainersAsync(
                new ContainersListParameters()
            {
                All = true
            }, cancellationToken);

            var a = containers.FindByName(DockerContainerNames.AgentA);
            var b = containers.FindByName(DockerContainerNames.AgentB);

            if (a == null && b == null)
            {
                Logger.Fatal("Unable to find the agent container.");
                return(false);
            }

            if (a != null && b != null)
            {
                Logger.Fatal("Two agent containers found. Unable to continue update.");
                return(false);
            }

            string existingContainerName;
            string newContainerName;

            ContainerListResponse existingContainer;

            if (a != null)
            {
                existingContainerName = DockerContainerNames.AgentA;
                newContainerName      = DockerContainerNames.AgentB;
                existingContainer     = a;
            }
            else
            {
                existingContainerName = DockerContainerNames.AgentB;
                newContainerName      = DockerContainerNames.AgentA;
                existingContainer     = b;
            }

            Logger.Information("The existing agent container is {ExistingContainer}. The new one will be {NewContainer}.", existingContainerName, newContainerName);

            //Make sure that the image is downloaded
            if (!await _dockerClient.DoesImageExistAsync(nextVersion.ImageId, cancellationToken))
            {
                await DownloadImageAsync(_dockerClient, nextVersion, cancellationToken);
            }

            Logger.Information("Creating new agent container...");

            //Create the new updated container
            var createContainerResponse = await _dockerContainerFactory.CreateContainerForUpdateAsync(
                _dockerClient,
                nextVersion.ImageId,
                existingContainerName,
                newContainerName,
                cancellationToken);

            //Show the warnings
            if (createContainerResponse.Warnings != null && createContainerResponse.Warnings.Any())
            {
                string formattedWarnings = string.Join(",", createContainerResponse.Warnings);

                Logger.Warning("Warnings during container creation: {Warnings}", formattedWarnings);
            }

            Logger.Information("Container {ContainerId} created for agent {ImageId}. Starting new agent...", createContainerResponse.ID, nextVersion.ImageId);

            //This is our last chance to get the hell out before committing
            if (cancellationToken.IsCancellationRequested)
            {
                return(false);
            }

            //Attempt to start the container
            var started = await _dockerClient.Containers.StartContainerAsync(
                createContainerResponse.ID,
                new ContainerStartParameters(),
                new CancellationToken());

            //Check to see if the application started
            if (started)
            {
                //Commit container suicide (this should kill the container that we're in)
                await _dockerClient.Containers.RemoveContainerAsync(existingContainer.ID,
                                                                    new ContainerRemoveParameters()
                {
                    Force = true
                }, new CancellationToken());

                //We may never get here
                return(true);
            }

            Logger.Warning("Warning: New agent not started. Not entirely sure why.");
            return(false);
        }
コード例 #2
0
        public override async Task <bool> UpdateCoreAsync(GetDeviceConfigurationResponse configuration, CancellationToken cancellationToken)
        {
            //Get the current and next version
            string currentVersion = await GetCurrentVersionAsync(cancellationToken);

            VersionReference nextVersion = configuration.ApplicationVersion;

            //Shouldn't ever happen
            if (configuration.EnvironmentVariables == null)
            {
                configuration.EnvironmentVariables = new EnvironmentVariable[] {};
            }

            Logger.Information("The new configuration has {EnvironmentVariableCount} environment variables.", configuration.EnvironmentVariables.Length);

            if (nextVersion == null)
            {
                Logger.Information("No application version information was specified.");
                return(false);
            }

            if (currentVersion != nextVersion.ImageId)
            {
                Logger.Information("The application version has changed from {CurrentVersion} to {NextVersion}.", currentVersion, nextVersion.ImageId);
            }
            else
            {
                Logger.Verbose("The application version has stayed {CurrentVersion}.", currentVersion);

                //Get the container
                var container = await _dockerClient.GetContainerByImageId(nextVersion.ImageId, cancellationToken);

                if (container != null)
                {
                    try
                    {
                        //Inspect the container to get its environment variables
                        var containerInspection = await _dockerClient.Containers.InspectContainerAsync(container.ID, cancellationToken);

                        var imageInspection = await _dockerClient.Images.InspectImageAsync(nextVersion.ImageId, cancellationToken);

                        EnvironmentVariable[] currentVariables = containerInspection.Config.Env
                                                                 .Select(EnvironnmentVariableParser.Parse)
                                                                 .ToArray();

                        var parsedInspectionVariables = imageInspection.Config.Env
                                                        .Select(EnvironnmentVariableParser.Parse)
                                                        .ToArray();

                        //Resolve the potentially new environment variables
                        EnvironmentVariable[] newVariables = EnvironmentVariableResolver.Resolve(parsedInspectionVariables,
                                                                                                 configuration.EnvironmentVariables);

                        //Create the environment comparer
                        var comparer = new EnvironmentVariableComparer(Logger);

                        if (comparer.AreSame(currentVariables, newVariables))
                        {
                            Logger.Verbose("The environment variables have stayed the same.");
                            return(false);
                        }

                        Logger.Information("The environment variables have changed.");
                    }
                    catch (Exception ex)
                    {
                        Logger.Warning(ex, "An error occured while checking environment variables. Skipping check: {Message}", ex.Message);
                    }
                }
            }

            //Make sure that the image is downloaded
            if (!await _dockerClient.DoesImageExistAsync(nextVersion.ImageId, cancellationToken))
            {
                //Download the application
                await DownloadImageAsync(_dockerClient, nextVersion, cancellationToken);
            }

            //Ditch the current applications
            await _dockerClient.ObliterateContainerAsync(DockerContainerNames.Application, Logger, cancellationToken);

            Logger.Information("Create the container for {ImageId} ...", nextVersion.ImageId);

            //Create the container
            var createContainerResponse = await _dockerContainerFactory.CreateContainerAsync(
                _dockerClient,
                nextVersion.ImageId,
                configuration.EnvironmentVariables,
                cancellationToken);

            if (createContainerResponse.Warnings != null && createContainerResponse.Warnings.Any())
            {
                string formattedWarnings = string.Join(",", createContainerResponse.Warnings);

                Logger.Warning("Warnings during container creation: {Warnings}", formattedWarnings);
            }

            Logger.Information("Container {ContainerId} created for application {Application}. Starting...", createContainerResponse.ID, nextVersion.ImageId);

            //Attempt to start the container
            var started = await _dockerClient.Containers.StartContainerAsync(
                createContainerResponse.ID,
                new ContainerStartParameters(),
                cancellationToken);

            //Check to see if the application started
            if (!started)
            {
                Logger.Warning("Warning: Application not started.");
            }

            //We never need to exit the agent for updating an application.
            return(false);
        }
コード例 #3
0
ファイル: BootstrapHost.cs プロジェクト: lulzzz/Boondocks
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            bool done = false;

            while (!done)
            {
                try
                {
                    if (await HasRunBefore())
                    {
                        done = true;
                    }
                    else
                    {
                        //Get the version of the agent to install.
                        var deviceConfiguration = await _deviceApiClient.Configuration.GetConfigurationAsync(cancellationToken);

                        //Make sure we have an actual version
                        if (deviceConfiguration.AgentVersion == null)
                        {
                            Logger.Warning("The server isn't giving us a agent version. Can't proceed until that changes.");

                            //Wait a bit before we start over
                            await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
                        }
                        else
                        {
                            //Make sure that the image is downloaded
                            if (!await _dockerClient.DoesImageExistAsync(deviceConfiguration.AgentVersion.ImageId, cancellationToken))
                            {
                                //Download the image
                                await _agentUpdateService.DownloadImageAsync(_dockerClient, deviceConfiguration.AgentVersion, cancellationToken);
                            }

                            await _dockerClient.ObliterateContainersAsync(new string[]
                            {
                                DockerContainerNames.AgentA,
                                DockerContainerNames.AgentB
                            }, Logger, cancellationToken);

                            //Create the new updated container
                            var createContainerResponse = await _agentDockerContainerFactory.CreateContainerForDirectAsync(
                                _dockerClient,
                                deviceConfiguration.AgentVersion.ImageId,
                                cancellationToken);

                            //Show the warnings
                            if (createContainerResponse.Warnings != null && createContainerResponse.Warnings.Any())
                            {
                                string formattedWarnings = string.Join(",", createContainerResponse.Warnings);

                                Logger.Warning("Warnings during container creation: {Warnings}", formattedWarnings);
                            }

                            Logger.Information("Container {ContainerId} created for agent {ImageId}. Starting new agent...", createContainerResponse.ID, deviceConfiguration.AgentVersion.ImageId);

                            //Attempt to start the container
                            var started = await _dockerClient.Containers.StartContainerAsync(
                                createContainerResponse.ID,
                                new ContainerStartParameters(),
                                cancellationToken);

                            if (!started)
                            {
                                Logger.Fatal("Agent container didn't start. Not sure how to deal with this.");
                            }

                            //We're good! Like totally bootstrapped and stuff.
                            done = true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, "Error attempting to bootstrap the agent.");

                    //Wait a bit before we start over
                    await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
                }
            }

            Logger.Information("We're bootstrapped! Now just wait forever.");

            //Wait forever
            await Task.Delay(Timeout.Infinite, cancellationToken);
        }