Пример #1
0
        protected override async Task <bool> PerformActionAsync()
        {
            var skipPush          = this.GetBoolValueOrDefault(this.DeployServiceProperties.SkipImagePush, ECSDefinedCommandOptions.ARGUMENT_SKIP_IMAGE_PUSH, false).GetValueOrDefault();
            var ecsContainer      = this.GetStringValueOrDefault(this.TaskDefinitionProperties.ContainerName, ECSDefinedCommandOptions.ARGUMENT_CONTAINER_NAME, true);
            var ecsTaskDefinition = this.GetStringValueOrDefault(this.TaskDefinitionProperties.TaskDefinitionName, ECSDefinedCommandOptions.ARGUMENT_TD_NAME, true);


            this.PushDockerImageProperties.DockerImageTag = this.GetStringValueOrDefault(this.PushDockerImageProperties.DockerImageTag, ECSDefinedCommandOptions.ARGUMENT_DOCKER_TAG, true).ToLower();

            if (!this.PushDockerImageProperties.DockerImageTag.Contains(":"))
            {
                this.PushDockerImageProperties.DockerImageTag += ":latest";
            }

            if (skipPush)
            {
                this.PushDockerImageProperties.DockerImageTag = await ECSUtilities.ExpandImageTagIfNecessary(this.Logger, this.ECRClient, this.PushDockerImageProperties.DockerImageTag);
            }
            else
            {
                var pushCommand = new PushDockerImageCommand(this.Logger, this.WorkingDirectory, this.OriginalCommandLineArguments)
                {
                    ConfigFile         = this.ConfigFile,
                    DisableInteractive = this.DisableInteractive,
                    Credentials        = this.Credentials,
                    ECRClient          = this.ECRClient,
                    Profile            = this.Profile,
                    ProfileLocation    = this.ProfileLocation,
                    ProjectLocation    = this.ProjectLocation,
                    Region             = this.Region,
                    WorkingDirectory   = this.WorkingDirectory,

                    PushDockerImageProperties = this.PushDockerImageProperties,
                };
                var success = await pushCommand.ExecuteAsync();

                if (!success)
                {
                    return(false);
                }

                this.PushDockerImageProperties.DockerImageTag = pushCommand.PushedImageUri;
            }


            var taskDefinitionArn = await ECSUtilities.CreateOrUpdateTaskDefinition(this.Logger, this.ECSClient,
                                                                                    this, this.TaskDefinitionProperties, this.PushDockerImageProperties.DockerImageTag, IsFargateLaunch(this.ClusterProperties.LaunchType));

            var ecsCluster = this.GetStringValueOrDefault(this.ClusterProperties.ECSCluster, ECSDefinedCommandOptions.ARGUMENT_ECS_CLUSTER, true);
            await ECSUtilities.EnsureClusterExistsAsync(this.Logger, this.ECSClient, ecsCluster);

            var ecsService = this.GetStringValueOrDefault(this.DeployServiceProperties.ECSService, ECSDefinedCommandOptions.ARGUMENT_ECS_SERVICE, true);

            await CreateOrUpdateService(ecsCluster, ecsService, taskDefinitionArn, ecsContainer);

            this.Logger?.WriteLine($"Service {ecsService} on ECS cluster {ecsCluster} has been updated. The Cluster will now deploy the new service version.");


            return(true);
        }
        public override async Task <bool> ExecuteAsync()
        {
            try
            {
                var skipPush          = this.GetBoolValueOrDefault(this.DeployTaskProperties.SkipImagePush, ECSDefinedCommandOptions.ARGUMENT_SKIP_IMAGE_PUSH, false).GetValueOrDefault();
                var ecsContainer      = this.GetStringValueOrDefault(this.TaskDefinitionProperties.ContainerName, ECSDefinedCommandOptions.ARGUMENT_CONTAINER_NAME, true);
                var ecsTaskDefinition = this.GetStringValueOrDefault(this.TaskDefinitionProperties.TaskDefinitionName, ECSDefinedCommandOptions.ARGUMENT_TD_NAME, true);


                this.PushDockerImageProperties.DockerImageTag = this.GetStringValueOrDefault(this.PushDockerImageProperties.DockerImageTag, ECSDefinedCommandOptions.ARGUMENT_DOCKER_TAG, true).ToLower();

                if (!this.PushDockerImageProperties.DockerImageTag.Contains(":"))
                {
                    this.PushDockerImageProperties.DockerImageTag += ":latest";
                }

                if (skipPush)
                {
                    this.PushDockerImageProperties.DockerImageTag = await ECSUtilities.ExpandImageTagIfNecessary(this.Logger, this.ECRClient, this.PushDockerImageProperties.DockerImageTag);
                }
                else
                {
                    var pushCommand = new PushDockerImageCommand(this.Logger, this.WorkingDirectory, this.OriginalCommandLineArguments)
                    {
                        ConfigFile         = this.ConfigFile,
                        DisableInteractive = this.DisableInteractive,
                        Credentials        = this.Credentials,
                        ECRClient          = this.ECRClient,
                        Profile            = this.Profile,
                        ProfileLocation    = this.ProfileLocation,
                        ProjectLocation    = this.ProjectLocation,
                        Region             = this.Region,
                        WorkingDirectory   = this.WorkingDirectory,

                        PushDockerImageProperties = this.PushDockerImageProperties,
                    };
                    var success = await pushCommand.ExecuteAsync();

                    if (!success)
                    {
                        return(false);
                    }

                    this.PushDockerImageProperties.DockerImageTag = pushCommand.PushedImageUri;
                }

                var taskDefinitionArn = await ECSUtilities.CreateOrUpdateTaskDefinition(this.Logger, this.ECSClient,
                                                                                        this, this.TaskDefinitionProperties, this.PushDockerImageProperties.DockerImageTag, IsFargateLaunch(this.ClusterProperties.LaunchType));

                var ecsCluster = this.GetStringValueOrDefault(this.ClusterProperties.ECSCluster, ECSDefinedCommandOptions.ARGUMENT_ECS_CLUSTER, true);
                await ECSUtilities.EnsureClusterExistsAsync(this.Logger, this.ECSClient, ecsCluster);

                var taskCount = this.GetIntValueOrDefault(this.DeployTaskProperties.TaskCount, ECSDefinedCommandOptions.ARGUMENT_ECS_TASK_COUNT, false);
                if (!taskCount.HasValue)
                {
                    taskCount = 1;
                }

                var taskGroup  = this.GetStringValueOrDefault(this.DeployTaskProperties.TaskGroup, ECSDefinedCommandOptions.ARGUMENT_ECS_TASK_GROUP, false);
                var launchType = this.GetStringValueOrDefault(this.ClusterProperties.LaunchType, ECSDefinedCommandOptions.ARGUMENT_LAUNCH_TYPE, true);

                var runTaskRequest = new Amazon.ECS.Model.RunTaskRequest
                {
                    Cluster        = ecsCluster,
                    TaskDefinition = taskDefinitionArn,
                    Count          = taskCount.Value,
                    LaunchType     = launchType
                };

                if (IsFargateLaunch(this.ClusterProperties.LaunchType))
                {
                    var subnets        = this.GetStringValuesOrDefault(this.ClusterProperties.SubnetIds, ECSDefinedCommandOptions.ARGUMENT_LAUNCH_SUBNETS, false);
                    var securityGroups = this.GetStringValuesOrDefault(this.ClusterProperties.SecurityGroupIds, ECSDefinedCommandOptions.ARGUMENT_LAUNCH_SECURITYGROUPS, false);

                    var networkConfiguration = new Amazon.ECS.Model.NetworkConfiguration();
                    await ECSUtilities.SetupAwsVpcNetworkConfigurationAsync(this, networkConfiguration);

                    runTaskRequest.NetworkConfiguration = networkConfiguration;

                    await this.AttemptToCreateServiceLinkRoleAsync();
                }
                else
                {
                    runTaskRequest.PlacementConstraints = ECSUtilities.ConvertPlacementConstraint(this.GetStringValuesOrDefault(this.DeployTaskProperties.PlacementConstraints, ECSDefinedCommandOptions.ARGUMENT_PLACEMENT_CONSTRAINTS, false));
                    runTaskRequest.PlacementStrategy    = ECSUtilities.ConvertPlacementStrategy(this.GetStringValuesOrDefault(this.DeployTaskProperties.PlacementStrategy, ECSDefinedCommandOptions.ARGUMENT_PLACEMENT_STRATEGY, false));
                }

                if (!string.IsNullOrEmpty(taskGroup))
                {
                    runTaskRequest.Group = taskGroup;
                }


                try
                {
                    var response = await this.ECSClient.RunTaskAsync(runTaskRequest);

                    this.Logger?.WriteLine($"Started {response.Tasks.Count} task:");
                    foreach (var task in response.Tasks)
                    {
                        this.Logger?.WriteLine($"\t{task.TaskArn}");
                    }
                }
                catch (Exception e)
                {
                    throw new DockerToolsException("Error executing deploy-task: " + e.Message, DockerToolsException.ECSErrorCode.RunTaskFail);
                }

                if (this.GetBoolValueOrDefault(this.PersistConfigFile, CommonDefinedCommandOptions.ARGUMENT_PERSIST_CONFIG_FILE, false).GetValueOrDefault())
                {
                    this.SaveConfigFile();
                }
            }
            catch (DockerToolsException e)
            {
                this.Logger?.WriteLine(e.Message);
                this.LastToolsException = e;
                return(false);
            }
            catch (Exception e)
            {
                this.Logger?.WriteLine($"Unknown error executing deploy-task: {e.Message}");
                this.Logger?.WriteLine(e.StackTrace);
                return(false);
            }
            return(true);
        }
Пример #3
0
        protected override async Task <bool> PerformActionAsync()
        {
            var skipPush           = this.GetBoolValueOrDefault(this.DeployScheduledTaskProperties.SkipImagePush, ECSDefinedCommandOptions.ARGUMENT_SKIP_IMAGE_PUSH, false).GetValueOrDefault();
            var ecsContainer       = this.GetStringValueOrDefault(this.TaskDefinitionProperties.ContainerName, ECSDefinedCommandOptions.ARGUMENT_CONTAINER_NAME, true);
            var ecsTaskDefinition  = this.GetStringValueOrDefault(this.TaskDefinitionProperties.TaskDefinitionName, ECSDefinedCommandOptions.ARGUMENT_TD_NAME, true);
            var ecsPlatformVersion = this.GetStringValueOrDefault(this.TaskDefinitionProperties.TaskPlatformVersion, ECSDefinedCommandOptions.ARGUMENT_TD_PLATFORM_VERSION, false);

            this.PushDockerImageProperties.DockerImageTag = GetDockerImageTag();

            if (!this.PushDockerImageProperties.DockerImageTag.Contains(":"))
            {
                this.PushDockerImageProperties.DockerImageTag += ":latest";
            }

            if (skipPush)
            {
                this.PushDockerImageProperties.DockerImageTag = await ECSUtilities.ExpandImageTagIfNecessary(this.Logger, this.ECRClient, this.PushDockerImageProperties.DockerImageTag);
            }
            else
            {
                var pushCommand = new PushDockerImageCommand(this.Logger, this.WorkingDirectory, this.OriginalCommandLineArguments)
                {
                    ConfigFile         = this.ConfigFile,
                    DisableInteractive = this.DisableInteractive,
                    Credentials        = this.Credentials,
                    ECRClient          = this.ECRClient,
                    Profile            = this.Profile,
                    ProfileLocation    = this.ProfileLocation,
                    ProjectLocation    = this.ProjectLocation,
                    Region             = this.Region,
                    WorkingDirectory   = this.WorkingDirectory,

                    PushDockerImageProperties = this.PushDockerImageProperties,
                };
                var success = await pushCommand.ExecuteAsync();

                if (!success)
                {
                    return(false);
                }

                this.PushDockerImageProperties.DockerImageTag = pushCommand.PushedImageUri;
            }

            var taskDefinitionArn = await ECSUtilities.CreateOrUpdateTaskDefinition(this.Logger, this.ECSClient,
                                                                                    this, this.TaskDefinitionProperties, this.PushDockerImageProperties.DockerImageTag, IsFargateLaunch(this.ClusterProperties.LaunchType));

            var ecsCluster = this.GetStringValueOrDefault(this.ClusterProperties.ECSCluster, ECSDefinedCommandOptions.ARGUMENT_ECS_CLUSTER, true);
            await ECSUtilities.EnsureClusterExistsAsync(this.Logger, this.ECSClient, ecsCluster);

            if (!ecsCluster.Contains(":"))
            {
                var arnPrefix = taskDefinitionArn.Substring(0, taskDefinitionArn.LastIndexOf(":task"));
                ecsCluster = arnPrefix + ":cluster/" + ecsCluster;
            }

            var ruleName   = this.GetStringValueOrDefault(this.DeployScheduledTaskProperties.ScheduleTaskRule, ECSDefinedCommandOptions.ARGUMENT_SCHEDULED_RULE_NAME, true);
            var targetName = this.GetStringValueOrDefault(this.DeployScheduledTaskProperties.ScheduleTaskRuleTarget, ECSDefinedCommandOptions.ARGUMENT_SCHEDULED_RULE_TARGET, false);

            if (string.IsNullOrEmpty(targetName))
            {
                targetName = ruleName;
            }

            var scheduleExpression = this.GetStringValueOrDefault(this.DeployScheduledTaskProperties.ScheduleExpression, ECSDefinedCommandOptions.ARGUMENT_SCHEDULE_EXPRESSION, true);
            var cweRole            = this.GetStringValueOrDefault(this.DeployScheduledTaskProperties.CloudWatchEventIAMRole, ECSDefinedCommandOptions.ARGUMENT_CLOUDWATCHEVENT_ROLE, true);
            var desiredCount       = this.GetIntValueOrDefault(this.DeployScheduledTaskProperties.DesiredCount, ECSDefinedCommandOptions.ARGUMENT_ECS_DESIRED_COUNT, false);

            if (!desiredCount.HasValue)
            {
                desiredCount = 1;
            }

            var launchType    = this.GetStringValueOrDefault(this.ClusterProperties.LaunchType, ECSDefinedCommandOptions.ARGUMENT_LAUNCH_TYPE, true);
            var ecsParameters = new EcsParameters
            {
                TaskCount         = desiredCount.Value,
                TaskDefinitionArn = taskDefinitionArn,
                LaunchType        = launchType
            };

            if (IsFargateLaunch(this.ClusterProperties.LaunchType))
            {
                var networkConfiguration = new Amazon.CloudWatchEvents.Model.NetworkConfiguration();
                await ECSUtilities.SetupAwsVpcNetworkConfigurationCloudwatchEventAsync(this, networkConfiguration);

                ecsParameters.NetworkConfiguration = networkConfiguration;
                ecsParameters.PlatformVersion      = ecsPlatformVersion;

                await this.AttemptToCreateServiceLinkRoleAsync();
            }

            string ruleArn = null;

            try
            {
                ruleArn = (await this.CWEClient.PutRuleAsync(new PutRuleRequest
                {
                    Name = ruleName,
                    ScheduleExpression = scheduleExpression,
                    State = RuleState.ENABLED
                })).RuleArn;

                this.Logger?.WriteLine($"Put CloudWatch Event rule {ruleName} with expression {scheduleExpression}");
            }
            catch (Exception e)
            {
                throw new DockerToolsException("Error creating CloudWatch Event rule: " + e.Message, DockerToolsException.ECSErrorCode.PutRuleFail);
            }

            try
            {
                await this.CWEClient.PutTargetsAsync(new PutTargetsRequest
                {
                    Rule    = ruleName,
                    Targets = new List <Target>
                    {
                        new Target
                        {
                            Arn           = ecsCluster,
                            RoleArn       = cweRole,
                            Id            = targetName,
                            EcsParameters = ecsParameters
                        }
                    }
                });

                this.Logger?.WriteLine($"Put CloudWatch Event target {targetName}");
            }
            catch (Exception e)
            {
                throw new DockerToolsException("Error creating CloudWatch Event target: " + e.Message, DockerToolsException.ECSErrorCode.PutTargetFail);
            }

            return(true);
        }
Пример #4
0
        private async Task CreateOrUpdateService(string ecsCluster, string ecsService, string taskDefinitionArn, string ecsContainer)
        {
            try
            {
                var describeServiceResponse = await this.ECSClient.DescribeServicesAsync(new DescribeServicesRequest
                {
                    Cluster  = ecsCluster,
                    Services = new List <string> {
                        ecsService
                    }
                });

                var desiredCount                    = this.GetIntValueOrDefault(this.DeployServiceProperties.DesiredCount, ECSDefinedCommandOptions.ARGUMENT_ECS_DESIRED_COUNT, false);
                var deploymentMaximumPercent        = this.GetIntValueOrDefault(this.DeployServiceProperties.DeploymentMaximumPercent, ECSDefinedCommandOptions.ARGUMENT_DEPLOYMENT_MAXIMUM_PERCENT, false);
                var deploymentMinimumHealthyPercent = this.GetIntValueOrDefault(this.DeployServiceProperties.DeploymentMinimumHealthyPercent, ECSDefinedCommandOptions.ARGUMENT_DEPLOYMENT_MINIMUM_HEALTHY_PERCENT, false);


                var launchType = this.GetStringValueOrDefault(this.ClusterProperties.LaunchType, ECSDefinedCommandOptions.ARGUMENT_LAUNCH_TYPE, true);
                NetworkConfiguration networkConfiguration = null;
                if (IsFargateLaunch(this.ClusterProperties.LaunchType))
                {
                    if (describeServiceResponse.Services.Count != 0)
                    {
                        networkConfiguration = describeServiceResponse.Services[0].NetworkConfiguration;
                    }
                    else
                    {
                        networkConfiguration = new NetworkConfiguration();
                    }

                    await ECSUtilities.SetupAwsVpcNetworkConfigurationAsync(this, networkConfiguration);
                }

                DeploymentConfiguration deploymentConfiguration = null;
                if (deploymentMaximumPercent.HasValue || deploymentMinimumHealthyPercent.HasValue)
                {
                    deploymentConfiguration = new DeploymentConfiguration();
                    if (deploymentMaximumPercent.HasValue)
                    {
                        deploymentConfiguration.MaximumPercent = deploymentMaximumPercent.Value;
                    }
                    if (deploymentMinimumHealthyPercent.HasValue)
                    {
                        deploymentConfiguration.MinimumHealthyPercent = deploymentMinimumHealthyPercent.Value;
                    }
                }

                if (describeServiceResponse.Services.Count == 0 || describeServiceResponse.Services[0].Status == "INACTIVE")
                {
                    this.Logger?.WriteLine($"Creating new service: {ecsService}");
                    var request = new CreateServiceRequest
                    {
                        ClientToken             = Guid.NewGuid().ToString(),
                        Cluster                 = ecsCluster,
                        ServiceName             = ecsService,
                        TaskDefinition          = taskDefinitionArn,
                        DesiredCount            = desiredCount.HasValue ? desiredCount.Value : 1,
                        DeploymentConfiguration = deploymentConfiguration,
                        LaunchType              = launchType,
                        NetworkConfiguration    = networkConfiguration
                    };

                    if (IsFargateLaunch(this.ClusterProperties.LaunchType))
                    {
                        await this.AttemptToCreateServiceLinkRoleAsync();
                    }
                    else
                    {
                        request.PlacementConstraints = ECSUtilities.ConvertPlacementConstraint(this.GetStringValuesOrDefault(this.DeployServiceProperties.PlacementConstraints, ECSDefinedCommandOptions.ARGUMENT_PLACEMENT_CONSTRAINTS, false));
                        request.PlacementStrategy    = ECSUtilities.ConvertPlacementStrategy(this.GetStringValuesOrDefault(this.DeployServiceProperties.PlacementStrategy, ECSDefinedCommandOptions.ARGUMENT_PLACEMENT_STRATEGY, false));
                    }

                    var elbTargetGroup = this.GetStringValueOrDefault(this.DeployServiceProperties.ELBTargetGroup, ECSDefinedCommandOptions.ARGUMENT_ELB_TARGET_GROUP_ARN, false);
                    if (!this.OverrideIgnoreTargetGroup && !string.IsNullOrWhiteSpace(elbTargetGroup))
                    {
                        if (!IsFargateLaunch(this.ClusterProperties.LaunchType))
                        {
                            request.Role = this.GetStringValueOrDefault(this.DeployServiceProperties.ELBServiceRole, ECSDefinedCommandOptions.ARGUMENT_ELB_SERVICE_ROLE, false);
                        }

                        var port = this.GetIntValueOrDefault(this.DeployServiceProperties.ELBContainerPort, ECSDefinedCommandOptions.ARGUMENT_ELB_CONTAINER_PORT, false);
                        if (!port.HasValue)
                        {
                            port = 80;
                        }
                        request.LoadBalancers.Add(new LoadBalancer
                        {
                            TargetGroupArn = elbTargetGroup,
                            ContainerName  = ecsContainer,
                            ContainerPort  = port.Value
                        });
                    }

                    try
                    {
                        await this.ECSClient.CreateServiceAsync(request);
                    }
                    catch (Amazon.ECS.Model.InvalidParameterException e)
                    {
                        if (e.Message.StartsWith("The target group") && !string.IsNullOrEmpty(elbTargetGroup) && string.IsNullOrEmpty(this.DeployServiceProperties.ELBTargetGroup))
                        {
                            request.LoadBalancers.Clear();
                            request.Role = null;

                            var defaultFile = string.IsNullOrEmpty(this.ConfigFile) ? ECSToolsDefaults.DEFAULT_FILE_NAME : this.ConfigFile;
                            this.Logger?.WriteLine($"Warning: ELB Target Group ARN specified in config file {defaultFile} does not exist.");
                            await this.ECSClient.CreateServiceAsync(request);
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
                else
                {
                    this.Logger?.WriteLine($"Updating new service: {ecsService}");
                    var updateRequest = new UpdateServiceRequest
                    {
                        Cluster                 = ecsCluster,
                        Service                 = ecsService,
                        TaskDefinition          = taskDefinitionArn,
                        DeploymentConfiguration = deploymentConfiguration,
                        NetworkConfiguration    = networkConfiguration
                    };

                    if (desiredCount.HasValue)
                    {
                        updateRequest.DesiredCount = desiredCount.Value;
                    }

                    await this.ECSClient.UpdateServiceAsync(updateRequest);
                }
            }
            catch (DockerToolsException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new DockerToolsException($"Error updating ECS service {ecsService} on cluster {ecsCluster}: {e.Message}", DockerToolsException.ECSErrorCode.FailedToUpdateService);
            }
        }