ufo 6.1.3 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cody/acceptance/bin/build.sh +1 -1
- data/CHANGELOG.md +9 -0
- data/lib/ufo/aws_services/concerns.rb +55 -0
- data/lib/ufo/aws_services.rb +9 -40
- data/lib/ufo/cfn/stack/status.rb +1 -1
- data/lib/ufo/cfn/stack.rb +4 -4
- data/lib/ufo/cli/central/base.rb +1 -0
- data/lib/ufo/cli/central/update.rb +1 -0
- data/lib/ufo/cli/destroy.rb +1 -1
- data/lib/ufo/config.rb +3 -0
- data/lib/ufo/docker/builder.rb +1 -1
- data/lib/ufo/docker/compiler.rb +3 -3
- data/lib/ufo/docker/state/base.rb +14 -0
- data/lib/ufo/docker/state/bucket.rb +2 -0
- data/lib/ufo/docker/state/file.rb +52 -0
- data/lib/ufo/docker/state/s3.rb +80 -0
- data/lib/ufo/docker/state.rb +16 -50
- data/lib/ufo/info.rb +1 -1
- data/lib/ufo/s3/aws_setup.rb +17 -0
- data/lib/ufo/s3/bucket.rb +174 -0
- data/lib/ufo/s3/rollback.rb +52 -0
- data/lib/ufo/version.rb +1 -1
- data/ufo.gemspec +1 -0
- metadata +24 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5b86133b126853170107907bce7c02f4620387d8b11c4a5e6e0f03176fda1349
         | 
| 4 | 
            +
              data.tar.gz: 3c543c7b436ec7214043d5f5cf45a798af2ce054aed970fa5de991848f6a4664
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: f4658807edc6f36b07cf8048f9f7f9c75ed90f3a03cd481ea1b763d4332bdf887a17d9199988021fa3866d73e7d0b0f43b1d03ef031915fdf5e0d3ad00a5904c
         | 
| 7 | 
            +
              data.tar.gz: d52d10df7faf76256f336abfc89a9ccd1afb999973d52e7cbf660481c17eb54ae8333c09e600de12455020c707fd1821a32beee0a893c72750337c1aecbcfaaa
         | 
| @@ -22,7 +22,7 @@ REPO=$(aws ecr describe-repositories --repository-name test/demo | jq -r '.repos | |
| 22 22 |  | 
| 23 23 | 
             
            # DockerHub
         | 
| 24 24 | 
             
            # toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating
         | 
| 25 | 
            -
            docker login --username $DOCKER_USER --password | 
| 25 | 
            +
            echo "$DOCKER_PASS" | docker login --username $DOCKER_USER --password-stdin
         | 
| 26 26 | 
             
            TOKEN=$(curl -s --user "$DOCKER_USER:$DOCKER_PASS" "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
         | 
| 27 27 | 
             
            echo "Current rate limit:"
         | 
| 28 28 | 
             
            curl -s --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -3,6 +3,15 @@ | |
| 3 3 | 
             
            All notable changes to this project will be documented in this file.
         | 
| 4 4 | 
             
            This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
         | 
| 5 5 |  | 
| 6 | 
            +
            ## [6.2.0] - 2022-03-16
         | 
| 7 | 
            +
            - [#152](https://github.com/tongueroo/ufo/pull/152) ufo docker base: s3 storage support
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## [6.1.5] - 2022-03-16
         | 
| 10 | 
            +
            - [#151](https://github.com/tongueroo/ufo/pull/151) fix symlink when .git ext is in the repo
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ## [6.1.4] - 2022-03-16
         | 
| 13 | 
            +
            - [#150](https://github.com/tongueroo/ufo/pull/150) ufo central: fix edge case when trying report broken symlink and logger not available
         | 
| 14 | 
            +
             | 
| 6 15 | 
             
            ## [6.1.3] - 2022-03-14
         | 
| 7 16 | 
             
            - [#149](https://github.com/tongueroo/ufo/pull/149) stack_output helper improve message when stack not found
         | 
| 8 17 |  | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            require "cfn_status"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Ufo::AwsServices
         | 
| 4 | 
            +
              module Concerns
         | 
| 5 | 
            +
                extend Memoist
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def find_stack(stack_name)
         | 
| 8 | 
            +
                  resp = cfn.describe_stacks(stack_name: stack_name)
         | 
| 9 | 
            +
                  resp.stacks.first
         | 
| 10 | 
            +
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 11 | 
            +
                  # example: Stack with id demo-web does not exist
         | 
| 12 | 
            +
                  if e.message =~ /Stack with/ && e.message =~ /does not exist/
         | 
| 13 | 
            +
                    nil
         | 
| 14 | 
            +
                  else
         | 
| 15 | 
            +
                    raise
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def stack_resources(stack_name)
         | 
| 20 | 
            +
                  resp = cfn.describe_stack_resources(stack_name: stack_name)
         | 
| 21 | 
            +
                  resp.stack_resources
         | 
| 22 | 
            +
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 23 | 
            +
                  e.message.include?("does not exist") ? return : raise
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def task_definition_arns(family, max_items=10)
         | 
| 27 | 
            +
                  resp = ecs.list_task_definitions(
         | 
| 28 | 
            +
                    family_prefix: family,
         | 
| 29 | 
            +
                    sort: "DESC",
         | 
| 30 | 
            +
                  )
         | 
| 31 | 
            +
                  arns = resp.task_definition_arns
         | 
| 32 | 
            +
                  arns = arns.select do |arn|
         | 
| 33 | 
            +
                    task_definition = arn.split('/').last.split(':').first
         | 
| 34 | 
            +
                    task_definition == family
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  arns[0..max_items]
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def status
         | 
| 40 | 
            +
                  CfnStatus.new(@stack_name) # NOTE: @stack_name must be set in the including Class
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
                memoize :status
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def find_stack_resources(stack_name)
         | 
| 45 | 
            +
                  resp = cfn.describe_stack_resources(stack_name: stack_name)
         | 
| 46 | 
            +
                  resp.stack_resources
         | 
| 47 | 
            +
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 48 | 
            +
                  if e.message.include?("does not exist")
         | 
| 49 | 
            +
                    nil
         | 
| 50 | 
            +
                  else
         | 
| 51 | 
            +
                    raise
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         | 
    
        data/lib/ufo/aws_services.rb
    CHANGED
    
    | @@ -6,15 +6,16 @@ require "aws-sdk-ec2" | |
| 6 6 | 
             
            require "aws-sdk-ecr"
         | 
| 7 7 | 
             
            require "aws-sdk-ecs"
         | 
| 8 8 | 
             
            require "aws-sdk-elasticloadbalancingv2"
         | 
| 9 | 
            +
            require "aws-sdk-s3"
         | 
| 9 10 | 
             
            require "aws-sdk-ssm"
         | 
| 10 11 | 
             
            require "aws-sdk-wafv2"
         | 
| 11 12 |  | 
| 12 13 | 
             
            require "aws_mfa_secure/ext/aws" # add MFA support
         | 
| 13 | 
            -
            require "cfn_status"
         | 
| 14 14 |  | 
| 15 15 | 
             
            module Ufo
         | 
| 16 16 | 
             
              module AwsServices
         | 
| 17 17 | 
             
                extend Memoist
         | 
| 18 | 
            +
                include Concerns
         | 
| 18 19 |  | 
| 19 20 | 
             
                def acm
         | 
| 20 21 | 
             
                  Aws::ACM::Client.new(aws_options)
         | 
| @@ -26,10 +27,10 @@ module Ufo | |
| 26 27 | 
             
                end
         | 
| 27 28 | 
             
                memoize :applicationautoscaling
         | 
| 28 29 |  | 
| 29 | 
            -
                def  | 
| 30 | 
            +
                def cfn
         | 
| 30 31 | 
             
                  Aws::CloudFormation::Client.new(aws_options)
         | 
| 31 32 | 
             
                end
         | 
| 32 | 
            -
                memoize : | 
| 33 | 
            +
                memoize :cfn
         | 
| 33 34 |  | 
| 34 35 | 
             
                def cloudwatchlogs
         | 
| 35 36 | 
             
                  Aws::CloudWatchLogs::Client.new(aws_options)
         | 
| @@ -56,6 +57,11 @@ module Ufo | |
| 56 57 | 
             
                end
         | 
| 57 58 | 
             
                memoize :elb
         | 
| 58 59 |  | 
| 60 | 
            +
                def s3
         | 
| 61 | 
            +
                  Aws::S3::Client.new(aws_options)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                memoize :s3
         | 
| 64 | 
            +
             | 
| 59 65 | 
             
                # ssm is a helper method
         | 
| 60 66 | 
             
                def ssm_client
         | 
| 61 67 | 
             
                  Aws::SSM::Client.new(aws_options)
         | 
| @@ -98,42 +104,5 @@ module Ufo | |
| 98 104 | 
             
                  ) if ENV['UFO_DEBUG_AWS_SDK']
         | 
| 99 105 | 
             
                  options
         | 
| 100 106 | 
             
                end
         | 
| 101 | 
            -
             | 
| 102 | 
            -
                def find_stack(stack_name)
         | 
| 103 | 
            -
                  resp = cloudformation.describe_stacks(stack_name: stack_name)
         | 
| 104 | 
            -
                  resp.stacks.first
         | 
| 105 | 
            -
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 106 | 
            -
                  # example: Stack with id demo-web does not exist
         | 
| 107 | 
            -
                  if e.message =~ /Stack with/ && e.message =~ /does not exist/
         | 
| 108 | 
            -
                    nil
         | 
| 109 | 
            -
                  else
         | 
| 110 | 
            -
                    raise
         | 
| 111 | 
            -
                  end
         | 
| 112 | 
            -
                end
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                def stack_resources(stack_name)
         | 
| 115 | 
            -
                  resp = cloudformation.describe_stack_resources(stack_name: stack_name)
         | 
| 116 | 
            -
                  resp.stack_resources
         | 
| 117 | 
            -
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 118 | 
            -
                  e.message.include?("does not exist") ? return : raise
         | 
| 119 | 
            -
                end
         | 
| 120 | 
            -
             | 
| 121 | 
            -
                def task_definition_arns(family, max_items=10)
         | 
| 122 | 
            -
                  resp = ecs.list_task_definitions(
         | 
| 123 | 
            -
                    family_prefix: family,
         | 
| 124 | 
            -
                    sort: "DESC",
         | 
| 125 | 
            -
                  )
         | 
| 126 | 
            -
                  arns = resp.task_definition_arns
         | 
| 127 | 
            -
                  arns = arns.select do |arn|
         | 
| 128 | 
            -
                    task_definition = arn.split('/').last.split(':').first
         | 
| 129 | 
            -
                    task_definition == family
         | 
| 130 | 
            -
                  end
         | 
| 131 | 
            -
                  arns[0..max_items]
         | 
| 132 | 
            -
                end
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                def status
         | 
| 135 | 
            -
                  CfnStatus.new(@stack_name) # NOTE: @stack_name must be set in the including Class
         | 
| 136 | 
            -
                end
         | 
| 137 | 
            -
                memoize :status
         | 
| 138 107 | 
             
              end
         | 
| 139 108 | 
             
            end
         | 
    
        data/lib/ufo/cfn/stack/status.rb
    CHANGED
    
    | @@ -122,7 +122,7 @@ class Ufo::Cfn::Stack | |
| 122 122 |  | 
| 123 123 | 
             
                # refreshes the loaded events in memory
         | 
| 124 124 | 
             
                def refresh_events
         | 
| 125 | 
            -
                  resp =  | 
| 125 | 
            +
                  resp = cfn.describe_stack_events(stack_name: @stack_name)
         | 
| 126 126 | 
             
                  @events = resp["stack_events"]
         | 
| 127 127 | 
             
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 128 128 | 
             
                  if e.message =~ /Stack .* does not exis/
         | 
    
        data/lib/ufo/cfn/stack.rb
    CHANGED
    
    | @@ -31,7 +31,7 @@ module Ufo::Cfn | |
| 31 31 | 
             
                  @stack = find_stack(@stack_name)
         | 
| 32 32 | 
             
                  if @stack && rollback_complete?(@stack)
         | 
| 33 33 | 
             
                    logger.info "Existing stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
         | 
| 34 | 
            -
                     | 
| 34 | 
            +
                    cfn.delete_stack(stack_name: @stack_name)
         | 
| 35 35 | 
             
                    status.wait
         | 
| 36 36 | 
             
                    status.reset
         | 
| 37 37 | 
             
                    @stack = nil # at this point stack has been deleted
         | 
| @@ -53,7 +53,7 @@ module Ufo::Cfn | |
| 53 53 |  | 
| 54 54 | 
             
                def perform(action)
         | 
| 55 55 | 
             
                  logger.info "#{action[0..-2].capitalize}ing stack #{@stack_name.color(:green)}"
         | 
| 56 | 
            -
                   | 
| 56 | 
            +
                  cfn.send("#{action}_stack", stack_options) # Example: cfn.send("update_stack", stack_options)
         | 
| 57 57 | 
             
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 58 58 | 
             
                  handle_stack_error(e)
         | 
| 59 59 | 
             
                end
         | 
| @@ -152,10 +152,10 @@ module Ufo::Cfn | |
| 152 152 | 
             
                  end
         | 
| 153 153 |  | 
| 154 154 | 
             
                  if stack.stack_status == "CREATE_IN_PROGRESS"
         | 
| 155 | 
            -
                     | 
| 155 | 
            +
                    cfn.delete_stack(stack_name: @stack_name)
         | 
| 156 156 | 
             
                    logger.info "Canceling stack creation"
         | 
| 157 157 | 
             
                  elsif stack.stack_status == "UPDATE_IN_PROGRESS"
         | 
| 158 | 
            -
                     | 
| 158 | 
            +
                    cfn.cancel_update_stack(stack_name: @stack_name)
         | 
| 159 159 | 
             
                    logger.info "Canceling stack update"
         | 
| 160 160 | 
             
                  else
         | 
| 161 161 | 
             
                    logger.info "The stack is not in a state to that is cancelable: #{stack.stack_status}"
         | 
    
        data/lib/ufo/cli/central/base.rb
    CHANGED
    
    
    
        data/lib/ufo/cli/destroy.rb
    CHANGED
    
    
    
        data/lib/ufo/config.rb
    CHANGED
    
    | @@ -114,7 +114,10 @@ module Ufo | |
| 114 114 | 
             
                  config.ship.docker.quiet = false # only affects ufo ship docker commands output
         | 
| 115 115 |  | 
| 116 116 | 
             
                  config.state = ActiveSupport::OrderedOptions.new
         | 
| 117 | 
            +
                  config.state.bucket = nil # Set to use existing bucket. When not set ufo creates a managed s3 bucket
         | 
| 118 | 
            +
                  config.state.managed = true # false will disable creation of managed bucket entirely
         | 
| 117 119 | 
             
                  config.state.reminder = true
         | 
| 120 | 
            +
                  config.state.storage = "s3" # s3 or file
         | 
| 118 121 |  | 
| 119 122 | 
             
                  config.waf = ActiveSupport::OrderedOptions.new
         | 
| 120 123 | 
             
                  config.waf.web_acl_arn = nil
         | 
    
        data/lib/ufo/docker/builder.rb
    CHANGED
    
    | @@ -162,7 +162,7 @@ module Ufo::Docker | |
| 162 162 |  | 
| 163 163 | 
             
                def update_dockerfile
         | 
| 164 164 | 
             
                  updater = if File.exist?("#{Ufo.root}/Dockerfile.erb") # dont use @dockerfile on purpose
         | 
| 165 | 
            -
                    State.new( | 
| 165 | 
            +
                    State.new(@options.merge(base_image: docker_image))
         | 
| 166 166 | 
             
                  else
         | 
| 167 167 | 
             
                    Dockerfile.new(docker_image, @options)
         | 
| 168 168 | 
             
                  end
         | 
    
        data/lib/ufo/docker/compiler.rb
    CHANGED
    
    | @@ -9,9 +9,9 @@ module Ufo::Docker | |
| 9 9 | 
             
                  return unless File.exist?(@erb_file)
         | 
| 10 10 |  | 
| 11 11 | 
             
                  puts "Compiled #{File.basename(@erb_file).color(:green)} to #{File.basename(@dockerfile).color(:green)}"
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                   | 
| 14 | 
            -
                  vars  | 
| 12 | 
            +
             | 
| 13 | 
            +
                  state = State.new
         | 
| 14 | 
            +
                  vars = state.read
         | 
| 15 15 | 
             
                  result = RenderMePretty.result(@erb_file, vars)
         | 
| 16 16 | 
             
                  comment =<<~EOL.chop # remove the trailing newline
         | 
| 17 17 | 
             
                    # IMPORTANT: This file was generated from #{File.basename(@erb_file)} as a part of running:
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            class Ufo::Docker::State
         | 
| 2 | 
            +
              class Base
         | 
| 3 | 
            +
                include Ufo::Utils::Logging
         | 
| 4 | 
            +
                include Ufo::Utils::Pretty
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(options={})
         | 
| 7 | 
            +
                  @options = options
         | 
| 8 | 
            +
                  # base_image only passed in with: ufo docker base
         | 
| 9 | 
            +
                  # State#update uses it.
         | 
| 10 | 
            +
                  # State#read wont have access to it and gets it from stored state
         | 
| 11 | 
            +
                  @base_image = options[:base_image]
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            class Ufo::Docker::State
         | 
| 2 | 
            +
              class File < Base
         | 
| 3 | 
            +
                def read
         | 
| 4 | 
            +
                  current_data
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def update
         | 
| 8 | 
            +
                  data = current_data
         | 
| 9 | 
            +
                  data["base_image"] = @base_image
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  pretty_path = state_path.sub("#{Ufo.root}/", "")
         | 
| 12 | 
            +
                  FileUtils.mkdir_p(::File.dirname(state_path))
         | 
| 13 | 
            +
                  IO.write(state_path, YAML.dump(data))
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  logger.info "The #{pretty_path} base_image has been updated with the latest base image:".color(:green)
         | 
| 16 | 
            +
                  logger.info "    #{@base_image}".color(:green)
         | 
| 17 | 
            +
                  reminder_message
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def current_data
         | 
| 21 | 
            +
                  ::File.exist?(state_path) ? YAML.load_file(state_path) : {}
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def state_path
         | 
| 25 | 
            +
                  "#{Ufo.root}/.ufo/state/#{Ufo.app}/#{Ufo.env}/data.yml"
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def reminder_message
         | 
| 29 | 
            +
                  return unless Ufo.config.state.reminder
         | 
| 30 | 
            +
                  repo = ENV['UFO_CENTRAL_REPO']
         | 
| 31 | 
            +
                  return unless repo
         | 
| 32 | 
            +
                  logger.info "It looks like you're using a central deployer pattern".color(:yellow)
         | 
| 33 | 
            +
                  logger.info <<~EOL
         | 
| 34 | 
            +
                    Remember to commit the state file:
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                        state file: #{pretty_path(state_path)}
         | 
| 37 | 
            +
                        repo:       #{repo}
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  EOL
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  logger.info <<~EOL
         | 
| 42 | 
            +
                    You can disable these reminder messages with:
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    .ufo/config.rb
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                        Ufo.configure do |config|
         | 
| 47 | 
            +
                          config.state.reminder = false
         | 
| 48 | 
            +
                        end
         | 
| 49 | 
            +
                  EOL
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,80 @@ | |
| 1 | 
            +
            class Ufo::Docker::State
         | 
| 2 | 
            +
              class S3 < Base
         | 
| 3 | 
            +
                extend Memoist
         | 
| 4 | 
            +
                include Ufo::AwsServices
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def read
         | 
| 7 | 
            +
                  current_data
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def update
         | 
| 11 | 
            +
                  data = current_data
         | 
| 12 | 
            +
                  data["base_image"] = @base_image
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  # write data to s3
         | 
| 15 | 
            +
                  body = YAML.dump(data)
         | 
| 16 | 
            +
                  s3.put_object(
         | 
| 17 | 
            +
                    body: body,
         | 
| 18 | 
            +
                    bucket: s3_bucket,
         | 
| 19 | 
            +
                    key: s3_key,
         | 
| 20 | 
            +
                  )
         | 
| 21 | 
            +
                  logger.info "Updated base image in s3://#{s3_bucket}/#{s3_key}"
         | 
| 22 | 
            +
                  logger.info "    #{@base_image}".color(:green)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                # TODO: edge cases: no bucket, no permission
         | 
| 26 | 
            +
                def current_data
         | 
| 27 | 
            +
                  resp = s3.get_object(bucket: s3_bucket, key: s3_key)
         | 
| 28 | 
            +
                  YAML.load(resp.body)
         | 
| 29 | 
            +
                rescue Aws::S3::Errors::NoSuchKey
         | 
| 30 | 
            +
                  logger.debug "WARN: s3 key does not exist: #{s3_key}"
         | 
| 31 | 
            +
                  {}
         | 
| 32 | 
            +
                rescue Aws::S3::Errors::NoSuchBucket
         | 
| 33 | 
            +
                  logger.error "ERROR: S3 bucket does not exist to store state: #{s3_bucket}".color(:red)
         | 
| 34 | 
            +
                  logger.error <<~EOL
         | 
| 35 | 
            +
                      Please double check the config.
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                      See: http://ufoships.com/docs/config/state/
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  EOL
         | 
| 40 | 
            +
                  exit 1
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def s3_key
         | 
| 44 | 
            +
                  "ufo/state/#{app}/#{Ufo.env}/data.yml"
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                # ufo docker base is called before Ufo.config is loaded. This ensures it is loaded
         | 
| 48 | 
            +
                def app
         | 
| 49 | 
            +
                  Ufo.config
         | 
| 50 | 
            +
                  Ufo.app
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def s3_bucket
         | 
| 54 | 
            +
                  state = Ufo.config.state
         | 
| 55 | 
            +
                  if state.bucket
         | 
| 56 | 
            +
                    state.bucket
         | 
| 57 | 
            +
                  elsif state.managed
         | 
| 58 | 
            +
                    ensure_s3_bucket_exist
         | 
| 59 | 
            +
                    Ufo::S3::Bucket.name
         | 
| 60 | 
            +
                  else
         | 
| 61 | 
            +
                    logger.error "ERROR: No s3 bucket to store state".color(:red)
         | 
| 62 | 
            +
                    logger.error <<~EOL
         | 
| 63 | 
            +
                      UFO needs a bucket to store the built docker base image.
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                      Configure an existing bucket or enable UFO to create a bucket.
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      See: http://ufoships.com/docs/config/state/
         | 
| 68 | 
            +
                    EOL
         | 
| 69 | 
            +
                    exit 1
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def ensure_s3_bucket_exist
         | 
| 74 | 
            +
                  bucket = Ufo::S3::Bucket.new
         | 
| 75 | 
            +
                  return if bucket.exist?
         | 
| 76 | 
            +
                  bucket.deploy
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
                memoize :ensure_s3_bucket_exist
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
    
        data/lib/ufo/docker/state.rb
    CHANGED
    
    | @@ -1,63 +1,29 @@ | |
| 1 1 | 
             
            module Ufo::Docker
         | 
| 2 2 | 
             
              class State
         | 
| 3 | 
            -
                 | 
| 4 | 
            -
                include Ufo::Utils::Pretty
         | 
| 3 | 
            +
                extend Memoist
         | 
| 5 4 |  | 
| 6 | 
            -
                def initialize( | 
| 7 | 
            -
                  @ | 
| 5 | 
            +
                def initialize(options={})
         | 
| 6 | 
            +
                  @options = options
         | 
| 8 7 | 
             
                end
         | 
| 9 8 |  | 
| 10 9 | 
             
                def update
         | 
| 11 | 
            -
                   | 
| 12 | 
            -
                  data[Ufo.env] ||= {}
         | 
| 13 | 
            -
                  data[Ufo.env]["base_image"] = @docker_image
         | 
| 14 | 
            -
                  pretty_path = state_path.sub("#{Ufo.root}/", "")
         | 
| 15 | 
            -
                  FileUtils.mkdir_p(File.dirname(state_path))
         | 
| 16 | 
            -
                  IO.write(state_path, YAML.dump(data))
         | 
| 17 | 
            -
                  logger.info "The #{pretty_path} base_image has been updated with the latest base image:".color(:green)
         | 
| 18 | 
            -
                  logger.info "  #{@docker_image}".color(:green)
         | 
| 19 | 
            -
                  reminder_message
         | 
| 10 | 
            +
                  storage.update
         | 
| 20 11 | 
             
                end
         | 
| 21 12 |  | 
| 22 | 
            -
                def  | 
| 23 | 
            -
                   | 
| 13 | 
            +
                def read
         | 
| 14 | 
            +
                  storage.read
         | 
| 24 15 | 
             
                end
         | 
| 25 16 |  | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
                   | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
                  return unless Ufo.config.state.reminder
         | 
| 36 | 
            -
                  repo = ENV['UFO_CENTRAL_REPO']
         | 
| 37 | 
            -
                  return unless repo
         | 
| 38 | 
            -
                  logger.info "It looks like you're using a central deployer pattern".color(:yellow)
         | 
| 39 | 
            -
                  logger.info <<~EOL
         | 
| 40 | 
            -
                    Remember to commit the state file:
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                        state file: #{pretty_path(state_path)}
         | 
| 43 | 
            -
                        repo:       #{repo}
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                  EOL
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                  unless ENV['UFO_APP']
         | 
| 48 | 
            -
                    logger.info "WARN: It also doesnt look like UFO_ENV is set".color(:yellow)
         | 
| 49 | 
            -
                    logger.info "UFO_ENV should be set when you're using ufo in a central manner"
         | 
| 50 | 
            -
                  end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                  logger.info <<~EOL
         | 
| 53 | 
            -
                    You can disable these reminder messages with:
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                    .ufo/config.rb
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                        Ufo.configure do |config|
         | 
| 58 | 
            -
                          config.state.reminder = false
         | 
| 59 | 
            -
                        end
         | 
| 60 | 
            -
                  EOL
         | 
| 17 | 
            +
              private
         | 
| 18 | 
            +
                # Examples:
         | 
| 19 | 
            +
                #   File.new(@docker_image, @options)
         | 
| 20 | 
            +
                #   S3.new(@docker_image, @options)
         | 
| 21 | 
            +
                def storage
         | 
| 22 | 
            +
                  storage = Ufo.config.state.storage
         | 
| 23 | 
            +
                  class_name = "Ufo::Docker::State::#{storage.camelize}"
         | 
| 24 | 
            +
                  klass = class_name.constantize
         | 
| 25 | 
            +
                  klass.new(@options)
         | 
| 61 26 | 
             
                end
         | 
| 27 | 
            +
                memoize :storage
         | 
| 62 28 | 
             
              end
         | 
| 63 29 | 
             
            end
         | 
    
        data/lib/ufo/info.rb
    CHANGED
    
    
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module Ufo::S3
         | 
| 2 | 
            +
              class AwsSetup
         | 
| 3 | 
            +
                include Ufo::AwsServices
         | 
| 4 | 
            +
                include Ufo::Utils::Logging
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def check!
         | 
| 7 | 
            +
                  s3.config.region
         | 
| 8 | 
            +
                rescue Aws::Errors::MissingRegionError => e
         | 
| 9 | 
            +
                  logger.info "ERROR: #{e.class}: #{e.message}".color(:red)
         | 
| 10 | 
            +
                  logger.info <<~EOL
         | 
| 11 | 
            +
                    Unable to detect the AWS_REGION to make AWS API calls. This is might be because the AWS access
         | 
| 12 | 
            +
                    has not been set up yet. Please either your ~/.aws files.
         | 
| 13 | 
            +
                  EOL
         | 
| 14 | 
            +
                  exit 1
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,174 @@ | |
| 1 | 
            +
            module Ufo::S3
         | 
| 2 | 
            +
              class Bucket
         | 
| 3 | 
            +
                extend Memoist
         | 
| 4 | 
            +
                extend Ufo::AwsServices
         | 
| 5 | 
            +
                include Ufo::AwsServices
         | 
| 6 | 
            +
                include Ufo::Utils::Logging
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                STACK_NAME = ENV['UFO_STACK_NAME'] || "ufo"
         | 
| 9 | 
            +
                def initialize(options={})
         | 
| 10 | 
            +
                  @options = options
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def deploy
         | 
| 14 | 
            +
                  stack = find_stack
         | 
| 15 | 
            +
                  if rollback.complete?
         | 
| 16 | 
            +
                    logger.info "Existing '#{STACK_NAME}' stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
         | 
| 17 | 
            +
                    disable_termination_protection
         | 
| 18 | 
            +
                    cfn.delete_stack(stack_name: STACK_NAME)
         | 
| 19 | 
            +
                    status.wait
         | 
| 20 | 
            +
                    stack = nil
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  if stack
         | 
| 24 | 
            +
                    update
         | 
| 25 | 
            +
                  else
         | 
| 26 | 
            +
                    create
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def exist?
         | 
| 31 | 
            +
                  !!bucket_name
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def bucket_name
         | 
| 35 | 
            +
                  self.class.name
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def show
         | 
| 39 | 
            +
                  if bucket_name
         | 
| 40 | 
            +
                    logger.info "UFO bucket name: #{bucket_name}"
         | 
| 41 | 
            +
                  else
         | 
| 42 | 
            +
                    logger.info "UFO bucket does not exist yet."
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                # Launches a cloudformation to create an s3 bucket
         | 
| 47 | 
            +
                def create
         | 
| 48 | 
            +
                  logger.info "Creating #{STACK_NAME} stack for s3 bucket to store state"
         | 
| 49 | 
            +
                  cfn.create_stack(
         | 
| 50 | 
            +
                    stack_name: STACK_NAME,
         | 
| 51 | 
            +
                    template_body: template_body,
         | 
| 52 | 
            +
                    enable_termination_protection: true,
         | 
| 53 | 
            +
                  )
         | 
| 54 | 
            +
                  success = status.wait
         | 
| 55 | 
            +
                  unless success
         | 
| 56 | 
            +
                    logger.info "ERROR: Unable to create UFO stack with managed s3 bucket".color(:red)
         | 
| 57 | 
            +
                    exit 1
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def update
         | 
| 62 | 
            +
                  logger.info "Updating #{STACK_NAME} stack with the s3 bucket"
         | 
| 63 | 
            +
                  cfn.update_stack(stack_name: STACK_NAME, template_body: template_body)
         | 
| 64 | 
            +
                rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 65 | 
            +
                  raise unless e.message.include?("No updates are to be performed")
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def delete
         | 
| 69 | 
            +
                  are_you_sure?
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  logger.info "Deleting #{STACK_NAME} stack with the s3 bucket"
         | 
| 72 | 
            +
                  disable_termination_protection
         | 
| 73 | 
            +
                  empty_bucket!
         | 
| 74 | 
            +
                  cfn.delete_stack(stack_name: STACK_NAME)
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def disable_termination_protection
         | 
| 78 | 
            +
                  cfn.update_termination_protection(
         | 
| 79 | 
            +
                    stack_name: STACK_NAME,
         | 
| 80 | 
            +
                    enable_termination_protection: false,
         | 
| 81 | 
            +
                  )
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                def find_stack
         | 
| 85 | 
            +
                  resp = cfn.describe_stacks(stack_name: STACK_NAME)
         | 
| 86 | 
            +
                  resp.stacks.first
         | 
| 87 | 
            +
                rescue Aws::CloudFormation::Errors::ValidationError
         | 
| 88 | 
            +
                  nil
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                def status
         | 
| 92 | 
            +
                  CfnStatus.new(STACK_NAME)
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
              private
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def empty_bucket!
         | 
| 98 | 
            +
                  return unless bucket_name # in case of UFO stack ROLLBACK_COMPLETE from failed bucket creation
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  resp = s3.list_objects(bucket: bucket_name)
         | 
| 101 | 
            +
                  if resp.contents.size > 0
         | 
| 102 | 
            +
                    # IE: objects = [{key: "objectkey1"}, {key: "objectkey2"}]
         | 
| 103 | 
            +
                    objects = resp.contents.map { |item| {key: item.key} }
         | 
| 104 | 
            +
                    s3.delete_objects(
         | 
| 105 | 
            +
                      bucket: bucket_name,
         | 
| 106 | 
            +
                      delete: {
         | 
| 107 | 
            +
                        objects: objects,
         | 
| 108 | 
            +
                        quiet: false,
         | 
| 109 | 
            +
                      }
         | 
| 110 | 
            +
                    )
         | 
| 111 | 
            +
                    empty_bucket! # keep deleting objects until bucket is empty
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
             | 
| 116 | 
            +
                def are_you_sure?
         | 
| 117 | 
            +
                  return true if @options[:yes]
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  if bucket_name.nil?
         | 
| 120 | 
            +
                    logger.info "The UFO stack and s3 bucket does not exist."
         | 
| 121 | 
            +
                    exit
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                  logger.info "Are you yes you want the UFO bucket #{bucket_name.color(:green)} to be emptied and deleted? (y/N)"
         | 
| 125 | 
            +
                  yes = $stdin.gets.strip
         | 
| 126 | 
            +
                  confirmed = yes =~ /^Y/i
         | 
| 127 | 
            +
                  unless confirmed
         | 
| 128 | 
            +
                    logger.info "Phew that was close."
         | 
| 129 | 
            +
                    exit
         | 
| 130 | 
            +
                  end
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                def template_body
         | 
| 134 | 
            +
                  <<~YAML
         | 
| 135 | 
            +
                    Description: UFO managed s3 bucket
         | 
| 136 | 
            +
                    Resources:
         | 
| 137 | 
            +
                      Bucket:
         | 
| 138 | 
            +
                        Type: AWS::S3::Bucket
         | 
| 139 | 
            +
                        Properties:
         | 
| 140 | 
            +
                          BucketEncryption:
         | 
| 141 | 
            +
                             ServerSideEncryptionConfiguration:
         | 
| 142 | 
            +
                             - ServerSideEncryptionByDefault:
         | 
| 143 | 
            +
                                SSEAlgorithm: AES256
         | 
| 144 | 
            +
                          Tags:
         | 
| 145 | 
            +
                            - Key: Name
         | 
| 146 | 
            +
                              Value: UFO
         | 
| 147 | 
            +
                    Outputs:
         | 
| 148 | 
            +
                      Bucket:
         | 
| 149 | 
            +
                        Value:
         | 
| 150 | 
            +
                          Ref: Bucket
         | 
| 151 | 
            +
                  YAML
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                def rollback
         | 
| 155 | 
            +
                  Rollback.new(STACK_NAME)
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                class << self
         | 
| 159 | 
            +
                  @@name = nil
         | 
| 160 | 
            +
                  def name
         | 
| 161 | 
            +
                    return @@name if @@name # only memoize once bucket has been created
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                    AwsSetup.new.check!
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                    stack = new.find_stack
         | 
| 166 | 
            +
                    return unless stack
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                    stack_resources = find_stack_resources(STACK_NAME)
         | 
| 169 | 
            +
                    bucket = stack_resources.find { |r| r.logical_resource_id == "Bucket" }
         | 
| 170 | 
            +
                    @@name = bucket.physical_resource_id # actual bucket name
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
                end
         | 
| 173 | 
            +
              end
         | 
| 174 | 
            +
            end
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            module Ufo::S3
         | 
| 2 | 
            +
              class Rollback
         | 
| 3 | 
            +
                extend Memoist
         | 
| 4 | 
            +
                include Ufo::AwsServices
         | 
| 5 | 
            +
                include Ufo::Utils::Logging
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(stack)
         | 
| 8 | 
            +
                  @stack = stack
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def delete_stack
         | 
| 12 | 
            +
                  return unless complete?
         | 
| 13 | 
            +
                  logger.info "Existing stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
         | 
| 14 | 
            +
                  cfn.delete_stack(stack_name: @stack)
         | 
| 15 | 
            +
                  status.wait
         | 
| 16 | 
            +
                  status.reset
         | 
| 17 | 
            +
                  true
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def continue_update
         | 
| 21 | 
            +
                  continue_update?
         | 
| 22 | 
            +
                  begin
         | 
| 23 | 
            +
                    cfn.continue_update_rollback(stack_name: @stack)
         | 
| 24 | 
            +
                  rescue Aws::CloudFormation::Errors::ValidationError => e
         | 
| 25 | 
            +
                    logger.info "ERROR: Continue update: #{e.message}".color(:red)
         | 
| 26 | 
            +
                    quit 1
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def continue_update?
         | 
| 31 | 
            +
                  logger.info <<~EOL
         | 
| 32 | 
            +
                    The stack is in the UPDATE_ROLLBACK_FAILED state. More info here: https://amzn.to/2IiEjc5
         | 
| 33 | 
            +
                    Would you like to try to continue the update rollback? (y/N)
         | 
| 34 | 
            +
                  EOL
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  yes = @options[:yes] ? "y" : $stdin.gets
         | 
| 37 | 
            +
                  unless yes =~ /^y/
         | 
| 38 | 
            +
                    logger.info "Exiting without continuing the update rollback."
         | 
| 39 | 
            +
                    quit 0
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def complete?
         | 
| 44 | 
            +
                  stack&.stack_status == 'ROLLBACK_COMPLETE'
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def stack
         | 
| 48 | 
            +
                  find_stack(@stack)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                memoize :stack
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
    
        data/lib/ufo/version.rb
    CHANGED
    
    
    
        data/ufo.gemspec
    CHANGED
    
    | @@ -28,6 +28,7 @@ Gem::Specification.new do |spec| | |
| 28 28 | 
             
              spec.add_dependency "aws-sdk-ecr"
         | 
| 29 29 | 
             
              spec.add_dependency "aws-sdk-ecs"
         | 
| 30 30 | 
             
              spec.add_dependency "aws-sdk-elasticloadbalancingv2"
         | 
| 31 | 
            +
              spec.add_dependency "aws-sdk-s3"
         | 
| 31 32 | 
             
              spec.add_dependency "aws-sdk-ssm"
         | 
| 32 33 | 
             
              spec.add_dependency "aws-sdk-wafv2"
         | 
| 33 34 | 
             
              spec.add_dependency "aws_data"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ufo
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 6. | 
| 4 | 
            +
              version: 6.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Tung Nguyen
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022-03- | 
| 11 | 
            +
            date: 2022-03-16 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: aws-logs
         | 
| @@ -150,6 +150,20 @@ dependencies: | |
| 150 150 | 
             
                - - ">="
         | 
| 151 151 | 
             
                  - !ruby/object:Gem::Version
         | 
| 152 152 | 
             
                    version: '0'
         | 
| 153 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 154 | 
            +
              name: aws-sdk-s3
         | 
| 155 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 156 | 
            +
                requirements:
         | 
| 157 | 
            +
                - - ">="
         | 
| 158 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 159 | 
            +
                    version: '0'
         | 
| 160 | 
            +
              type: :runtime
         | 
| 161 | 
            +
              prerelease: false
         | 
| 162 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 163 | 
            +
                requirements:
         | 
| 164 | 
            +
                - - ">="
         | 
| 165 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 166 | 
            +
                    version: '0'
         | 
| 153 167 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 154 168 | 
             
              name: aws-sdk-ssm
         | 
| 155 169 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -472,6 +486,7 @@ files: | |
| 472 486 | 
             
            - lib/ufo.rb
         | 
| 473 487 | 
             
            - lib/ufo/autoloader.rb
         | 
| 474 488 | 
             
            - lib/ufo/aws_services.rb
         | 
| 489 | 
            +
            - lib/ufo/aws_services/concerns.rb
         | 
| 475 490 | 
             
            - lib/ufo/booter.rb
         | 
| 476 491 | 
             
            - lib/ufo/cfn/base.rb
         | 
| 477 492 | 
             
            - lib/ufo/cfn/deploy.rb
         | 
| @@ -581,6 +596,10 @@ files: | |
| 581 596 | 
             
            - lib/ufo/docker/dockerfile.rb
         | 
| 582 597 | 
             
            - lib/ufo/docker/pusher.rb
         | 
| 583 598 | 
             
            - lib/ufo/docker/state.rb
         | 
| 599 | 
            +
            - lib/ufo/docker/state/base.rb
         | 
| 600 | 
            +
            - lib/ufo/docker/state/bucket.rb
         | 
| 601 | 
            +
            - lib/ufo/docker/state/file.rb
         | 
| 602 | 
            +
            - lib/ufo/docker/state/s3.rb
         | 
| 584 603 | 
             
            - lib/ufo/ecr/auth.rb
         | 
| 585 604 | 
             
            - lib/ufo/ecr/cleaner.rb
         | 
| 586 605 | 
             
            - lib/ufo/ecs/service.rb
         | 
| @@ -598,6 +617,9 @@ files: | |
| 598 617 | 
             
            - lib/ufo/logger/formatter.rb
         | 
| 599 618 | 
             
            - lib/ufo/names.rb
         | 
| 600 619 | 
             
            - lib/ufo/param.rb
         | 
| 620 | 
            +
            - lib/ufo/s3/aws_setup.rb
         | 
| 621 | 
            +
            - lib/ufo/s3/bucket.rb
         | 
| 622 | 
            +
            - lib/ufo/s3/rollback.rb
         | 
| 601 623 | 
             
            - lib/ufo/task_definition.rb
         | 
| 602 624 | 
             
            - lib/ufo/task_definition/builder.rb
         | 
| 603 625 | 
             
            - lib/ufo/task_definition/context.rb
         |