eb_deployer 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/eb_deployer.gemspec +20 -0
- data/lib/eb_deployer/beanstalk.rb +82 -0
- data/lib/eb_deployer/cloud_formation_provisioner.rb +82 -0
- data/lib/eb_deployer/deployment_strategy.rb +74 -0
- data/lib/eb_deployer/environment.rb +82 -0
- data/lib/eb_deployer/event_poller.rb +41 -0
- data/lib/eb_deployer/package.rb +33 -0
- data/lib/eb_deployer/s3_driver.rb +33 -0
- data/lib/eb_deployer/version.rb +3 -0
- data/lib/eb_deployer.rb +54 -0
- data/test/aws_driver_stubs.rb +93 -0
- data/test/deploy_test.rb +147 -0
- metadata +98 -0
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Copyright (c) 2013 tworker
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            MIT License
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 6 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 7 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 8 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 9 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 10 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 11 | 
            +
            the following conditions:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 14 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 17 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 18 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 19 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 20 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 21 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 22 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            # EbDeployer
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            TODO: Write a gem description
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Installation
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Add this line to your application's Gemfile:
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                gem 'eb_deployer'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            And then execute:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                $ bundle
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            Or install it yourself as:
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                $ gem install eb_deployer
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ## Usage
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            TODO: Write usage instructions here
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ## Contributing
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            1. Fork it
         | 
| 26 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 27 | 
            +
            3. Commit your changes (`git commit -am 'Added some feature'`)
         | 
| 28 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 29 | 
            +
            5. Create new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    
    
        data/eb_deployer.gemspec
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            require File.expand_path('../lib/eb_deployer/version', __FILE__)
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Gem::Specification.new do |gem|
         | 
| 5 | 
            +
              gem.authors       = ["wpc", "betarelease"]
         | 
| 6 | 
            +
              gem.email         = ["alex.hal9000@gmail.com", "sudhindra.r.rao@gmail.com"]
         | 
| 7 | 
            +
              gem.description   = %q{Elastic Beanstalk Deployer with different deployment strategies.}
         | 
| 8 | 
            +
              gem.summary       = %q{Pick strategies like InplaceUpdate, Blue/Green.}
         | 
| 9 | 
            +
              gem.homepage      = "https://github.com/ThoughtWorksStudios/eb_deployer"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              gem.add_runtime_dependency 'aws-sdk'
         | 
| 12 | 
            +
              gem.add_development_dependency 'minitest'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              gem.files         = `git ls-files`.split($\)
         | 
| 15 | 
            +
              gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
         | 
| 16 | 
            +
              gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
         | 
| 17 | 
            +
              gem.name          = "eb_deployer"
         | 
| 18 | 
            +
              gem.require_paths = ["lib"]
         | 
| 19 | 
            +
              gem.version       = EbDeployer::VERSION
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            module EbDeployer
         | 
| 2 | 
            +
              class Beanstalk
         | 
| 3 | 
            +
                attr_reader :client
         | 
| 4 | 
            +
                def initialize(client=AWS::ElasticBeanstalk.new.client)
         | 
| 5 | 
            +
                  @client = client
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def update_environment(app_name, env_name, version, settings)
         | 
| 9 | 
            +
                  env_id = convert_env_name_to_id(app_name, [env_name]).first
         | 
| 10 | 
            +
                  @client.update_environment(:environment_id => env_id,
         | 
| 11 | 
            +
                                             :version_label => version,
         | 
| 12 | 
            +
                                             :option_settings => settings)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def environment_exists?(app_name, env_name)
         | 
| 16 | 
            +
                  alive_envs(app_name, [env_name]).any?
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def create_environment(app_name, env_name, stack_name, cname_prefix, version, settings)
         | 
| 20 | 
            +
                  request = {:application_name => app_name,
         | 
| 21 | 
            +
                    :environment_name => env_name,
         | 
| 22 | 
            +
                    :solution_stack_name => stack_name,
         | 
| 23 | 
            +
                    :version_label => version,
         | 
| 24 | 
            +
                    :option_settings => settings }
         | 
| 25 | 
            +
                  request[:cname_prefix] = cname_prefix if cname_prefix
         | 
| 26 | 
            +
                  @client.create_environment(request)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def create_application_version(app_name, version_label, source_bundle)
         | 
| 30 | 
            +
                  @client.create_application_version(:application_name => app_name,
         | 
| 31 | 
            +
                                                     :source_bundle => source_bundle,
         | 
| 32 | 
            +
                                                     :version_label => version_label)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def application_version_labels
         | 
| 36 | 
            +
                  @client.describe_application_versions[:application_versions].map { |apv| apv[:version_label] }
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def fetch_events(app_name, env_name, params, &block)
         | 
| 40 | 
            +
                  response = @client.describe_events(params.merge(:application_name => app_name,
         | 
| 41 | 
            +
                                                                  :environment_name => env_name))
         | 
| 42 | 
            +
                  return [response[:events], response[:next_token]]
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def environment_cname_prefix(app_name, env_name)
         | 
| 46 | 
            +
                  cname = environment_cname(app_name, env_name)
         | 
| 47 | 
            +
                  if cname =~ /^(.+)\.elasticbeanstalk\.com/
         | 
| 48 | 
            +
                    $1
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def environment_cname(app_name, env_name)
         | 
| 53 | 
            +
                  env = alive_envs(app_name, [env_name]).first
         | 
| 54 | 
            +
                  env && env[:cname]
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def environment_health_state(app_name, env_name)
         | 
| 58 | 
            +
                  env = alive_envs(app_name, [env_name]).first
         | 
| 59 | 
            +
                  env && env[:health]
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def environment_swap_cname(app_name, env1, env2)
         | 
| 63 | 
            +
                  env1_id, env2_id = convert_env_name_to_id(app_name, [env1, env2])
         | 
| 64 | 
            +
                  @client.swap_environment_cnam_es(:source_environment_id => env1_id,
         | 
| 65 | 
            +
                                                   :destination_environment_id => env2_id)
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                private
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def convert_env_name_to_id(app_name, env_names)
         | 
| 71 | 
            +
                  envs = alive_envs(app_name, env_names)
         | 
| 72 | 
            +
                  envs.map { |env| env[:environment_id] }
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def alive_envs(app_name, env_names=[])
         | 
| 76 | 
            +
                  envs = @client.describe_environments(:application_name => app_name, :environment_names => env_names)[:environments]
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  envs.select {|e| e[:status] != 'Terminated' }
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
| @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            module EbDeployer
         | 
| 2 | 
            +
              class CloudFormationProvisioner
         | 
| 3 | 
            +
                SUCCESS_STATS = [:create_complete, :update_complete, :update_rollback_complete]
         | 
| 4 | 
            +
                FAILED_STATS = [:create_failed, :update_failed]
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(stack_name)
         | 
| 7 | 
            +
                  @stack_name = stack_name
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def provision(resources)
         | 
| 11 | 
            +
                  params = extract_params
         | 
| 12 | 
            +
                  template = File.read(resources[:template])
         | 
| 13 | 
            +
                  transforms = resources[:transforms]
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  stack.exists? ? update_stack(template, params) : create_stack(template, params)
         | 
| 16 | 
            +
                  wait_for_stack_op_terminate
         | 
| 17 | 
            +
                  transform_output_to_settings(transforms)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def update_stack(template, params)
         | 
| 23 | 
            +
                  begin
         | 
| 24 | 
            +
                    stack.update(:template => template, :parameters => params)
         | 
| 25 | 
            +
                  rescue AWS::CloudFormation::Errors::ValidationError => e
         | 
| 26 | 
            +
                    if e.message =~ /No updates are to be performed/
         | 
| 27 | 
            +
                      log(e.message)
         | 
| 28 | 
            +
                    else
         | 
| 29 | 
            +
                      raise
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def create_stack(template, params)
         | 
| 35 | 
            +
                  cloud_formation.stacks.create(@stack_name, template, {
         | 
| 36 | 
            +
                                                  :disable_rollback => true,
         | 
| 37 | 
            +
                                                  :parameters => params
         | 
| 38 | 
            +
                                                })
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def transform_output_to_settings(transforms)
         | 
| 42 | 
            +
                  (transforms || []).inject([]) do |settings, pair|
         | 
| 43 | 
            +
                    key, transform = pair
         | 
| 44 | 
            +
                    settings << transform.call(output(key))
         | 
| 45 | 
            +
                    settings
         | 
| 46 | 
            +
                  end.flatten
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def wait_for_stack_op_terminate
         | 
| 50 | 
            +
                  begin
         | 
| 51 | 
            +
                    sleep 15
         | 
| 52 | 
            +
                    stats = stack_status
         | 
| 53 | 
            +
                    raise "Resource stack update failed!" if FAILED_STATS.include?(stats)
         | 
| 54 | 
            +
                    log "current status: #{stack_status}"
         | 
| 55 | 
            +
                  end while !SUCCESS_STATS.include?(stats)
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def output(key)
         | 
| 59 | 
            +
                  stack.outputs.find { |o| o.key == key }.try(:value)
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def extract_params
         | 
| 63 | 
            +
                  Hash[ENV.map {|k, v| k =~ /^AWSRESOURCES_(.*)/ ? [$1, v] : nil }.compact]
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def log(msg)
         | 
| 67 | 
            +
                  puts "[#{Time.now.utc}][resources-stack] #{msg}"
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def stack_status
         | 
| 71 | 
            +
                  stack.status.downcase.to_sym
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def stack
         | 
| 75 | 
            +
                  cloud_formation.stacks[@stack_name]
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def cloud_formation
         | 
| 79 | 
            +
                  AWS::CloudFormation.new
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            module EbDeployer
         | 
| 2 | 
            +
              module DeploymentStrategy
         | 
| 3 | 
            +
                class InplaceUpdate
         | 
| 4 | 
            +
                  def initialize(app, env_name, eb_driver, env_creation_opts)
         | 
| 5 | 
            +
                    @app = app
         | 
| 6 | 
            +
                    @env_name = env_name
         | 
| 7 | 
            +
                    @eb_driver = eb_driver
         | 
| 8 | 
            +
                    @env_creation_opts = env_creation_opts
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def deploy(version_label, env_settings)
         | 
| 12 | 
            +
                    Environment.new(@app, @env_name, @eb_driver, @env_creation_opts).
         | 
| 13 | 
            +
                      deploy(version_label, env_settings)
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                class BlueGreen
         | 
| 18 | 
            +
                  def initialize(app, env_name, eb_driver, env_creation_opts)
         | 
| 19 | 
            +
                    @app = app
         | 
| 20 | 
            +
                    @env_name = env_name
         | 
| 21 | 
            +
                    @eb_driver = eb_driver
         | 
| 22 | 
            +
                    @major_cname_prefix = env_creation_opts[:cname_prefix]
         | 
| 23 | 
            +
                    @solution_stack = env_creation_opts[:solution_stack]
         | 
| 24 | 
            +
                    @smoke_test = env_creation_opts[:smoke_test]
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def deploy(version_label, env_settings)
         | 
| 28 | 
            +
                    if !envs.any?(&method(:active_env?))
         | 
| 29 | 
            +
                      env('blue', @major_cname_prefix).
         | 
| 30 | 
            +
                        deploy(version_label, env_settings)
         | 
| 31 | 
            +
                      return
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    active_env = envs.detect(&method(:active_env?))
         | 
| 35 | 
            +
                    inactive_env = envs.reject(&method(:active_env?)).first
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    inactive_env.deploy(version_label, env_settings)
         | 
| 38 | 
            +
                    active_env.swap_cname_with(inactive_env)
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  private
         | 
| 42 | 
            +
                  def active_env?(env)
         | 
| 43 | 
            +
                    env.cname_prefix == @major_cname_prefix
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def envs
         | 
| 47 | 
            +
                    [env('blue'), env('green')]
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def env(color, cname_prefix=nil)
         | 
| 51 | 
            +
                    Environment.new(@app, @env_name + '-' + color, @eb_driver,
         | 
| 52 | 
            +
                                    :solution_stack => @solution_stack,
         | 
| 53 | 
            +
                                    :cname_prefix => cname_prefix || inactive_cname_prefix,
         | 
| 54 | 
            +
                                    :smoke_test => @smoke_test)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def inactive_cname_prefix
         | 
| 58 | 
            +
                    "#{@app}-#{@env_name}-inactive"
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def self.create(strategy_name, app, env_name, eb_driver, env_creation_opts={})
         | 
| 63 | 
            +
                  case strategy_name.to_sym
         | 
| 64 | 
            +
                  when :inplace_update
         | 
| 65 | 
            +
                    InplaceUpdate.new(app, env_name, eb_driver, env_creation_opts)
         | 
| 66 | 
            +
                  when :blue_green
         | 
| 67 | 
            +
                    BlueGreen.new(app, env_name, eb_driver, env_creation_opts)
         | 
| 68 | 
            +
                  else
         | 
| 69 | 
            +
                    raise 'strategy_name:' + strategy_name + ' not supported'
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
| @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            module EbDeployer
         | 
| 2 | 
            +
              class Environment
         | 
| 3 | 
            +
                attr_reader :app, :name
         | 
| 4 | 
            +
                def initialize(app, env_name, eb_driver, creation_opts={})
         | 
| 5 | 
            +
                  @app = app
         | 
| 6 | 
            +
                  @name = env_name
         | 
| 7 | 
            +
                  @bs = eb_driver
         | 
| 8 | 
            +
                  @creation_opts = creation_opts
         | 
| 9 | 
            +
                  @poller = EventPoller.new(@app, @name, @bs)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def deploy(version_label, settings)
         | 
| 13 | 
            +
                  create_or_update_env(version_label, settings)
         | 
| 14 | 
            +
                  poll_events
         | 
| 15 | 
            +
                  smoke_test
         | 
| 16 | 
            +
                  wait_for_env_become_healthy
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def cname_prefix
         | 
| 20 | 
            +
                  @bs.environment_cname_prefix(@app, @name)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def ==(another)
         | 
| 24 | 
            +
                  self.app == another.app && self.name == another.name
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def swap_cname_with(another)
         | 
| 28 | 
            +
                  @bs.environment_swap_cname(self.app, self.name, another.name)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def create_or_update_env(version_label, settings)
         | 
| 34 | 
            +
                  if @bs.environment_exists?(@app, @name)
         | 
| 35 | 
            +
                    @bs.update_environment(@app, @name, version_label, settings)
         | 
| 36 | 
            +
                  else
         | 
| 37 | 
            +
                    @bs.create_environment(@app, @name, @creation_opts[:solution_stack], @creation_opts[:cname_prefix], version_label, settings)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def smoke_test
         | 
| 42 | 
            +
                  if smoke = @creation_opts[:smoke_test]
         | 
| 43 | 
            +
                    host = @bs.environment_cname(@app, @name)
         | 
| 44 | 
            +
                    log("running smoke test for #{host}...")
         | 
| 45 | 
            +
                    smoke.call(host)
         | 
| 46 | 
            +
                    log("smoke test succeeded.")
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def poll_events
         | 
| 51 | 
            +
                  @poller.poll do |event|
         | 
| 52 | 
            +
                    raise event[:message] if event[:message] =~ /Failed to deploy application/
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    log_event(event)
         | 
| 55 | 
            +
                    break if event[:message] =~ /Environment update completed successfully/ ||
         | 
| 56 | 
            +
                      event[:message] =~ /Successfully launched environment/
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def wait_for_env_become_healthy
         | 
| 61 | 
            +
                  Timeout.timeout(600) do
         | 
| 62 | 
            +
                    current_health_status = @bs.environment_health_state(@app, @name)
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    while current_health_status != 'Green'
         | 
| 65 | 
            +
                      log("health status: #{current_health_status}")
         | 
| 66 | 
            +
                      sleep 15
         | 
| 67 | 
            +
                      current_health_status = @bs.environment_health_state(@app, @name)
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    log("health status: #{current_health_status}")
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def log(msg)
         | 
| 75 | 
            +
                  puts "[#{Time.now.utc}][beanstalk-#{@name}] #{msg}"
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def log_event(event)
         | 
| 79 | 
            +
                  puts "[#{event[:event_date]}][beanstalk-#{@name}] #{event[:message]}"
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            module EbDeployer
         | 
| 2 | 
            +
              class EventPoller
         | 
| 3 | 
            +
                def initialize(app, env, beanstalk)
         | 
| 4 | 
            +
                  @app, @env, @beanstalk, @start_time = app, env, beanstalk, Time.now
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def poll(&block)
         | 
| 8 | 
            +
                  handled = Set.new
         | 
| 9 | 
            +
                  loop do
         | 
| 10 | 
            +
                    fetch_events do |events|
         | 
| 11 | 
            +
                      new_events = events.reject { |e| handled.include?(digest(e)) }
         | 
| 12 | 
            +
                      handle(new_events, &block)
         | 
| 13 | 
            +
                      handled += new_events.map { |e| digest(e) }
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                    sleep 15
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                private
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def digest(event)
         | 
| 22 | 
            +
                  JSON.dump(event)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def handle(events, &block)
         | 
| 26 | 
            +
                  events.reverse.each(&block)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def fetch_events(&block)
         | 
| 30 | 
            +
                  events, next_token = @beanstalk.fetch_events(@app, @env, :start_time => @start_time.iso8601)
         | 
| 31 | 
            +
                  yield(events)
         | 
| 32 | 
            +
                  fetch_next(next_token, &block) if next_token
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def fetch_next(next_token, &block)
         | 
| 36 | 
            +
                  events, next_token = @beanstalk.fetch_events(@app, @env, :next_token => next_token)
         | 
| 37 | 
            +
                  yield(events)
         | 
| 38 | 
            +
                  fetch_next(next_token, &block) if next_token
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module EbDeployer
         | 
| 2 | 
            +
              class Package
         | 
| 3 | 
            +
                def initialize(file, bucket_name, s3_driver)
         | 
| 4 | 
            +
                  @file, @bucket_name = file, bucket_name
         | 
| 5 | 
            +
                  @s3 = s3_driver
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def upload
         | 
| 9 | 
            +
                  ensure_bucket(@bucket_name)
         | 
| 10 | 
            +
                  upload_if_not_exists(@file, @bucket_name)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def source_bundle
         | 
| 14 | 
            +
                  { :s3_bucket => @bucket_name, :s3_key => s3_path }
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                private
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def s3_path
         | 
| 20 | 
            +
                  @_s3_path ||= Digest::MD5.file(@file).hexdigest + "-" + File.basename(@file)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def ensure_bucket(bucket_name)
         | 
| 24 | 
            +
                  @s3.create_bucket(@bucket_name) unless @s3.bucket_exists?(@bucket_name)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def upload_if_not_exists(file, bucket_name)
         | 
| 28 | 
            +
                  if @s3.object_length(@bucket_name, s3_path) != File.size(file)
         | 
| 29 | 
            +
                    @s3.upload_file(@bucket_name, s3_path, file)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module EbDeployer
         | 
| 2 | 
            +
              class S3Driver
         | 
| 3 | 
            +
                def create_bucket(bucket_name)
         | 
| 4 | 
            +
                  buckets.create(bucket_name)
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def bucket_exists?(bucket_name)
         | 
| 8 | 
            +
                  buckets[bucket_name].exists?
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def object_length(bucket_name, obj_name)
         | 
| 12 | 
            +
                  obj(bucket_name, obj_name).content_length rescue nil
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def upload_file(bucket_name, obj_name, file)
         | 
| 16 | 
            +
                  o = obj(bucket_name, obj_name)
         | 
| 17 | 
            +
                  File.open(file) { |f| o.write(f) }
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                private
         | 
| 21 | 
            +
                def s3
         | 
| 22 | 
            +
                  AWS::S3.new
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def obj(bucket_name, obj_name)
         | 
| 26 | 
            +
                  buckets[bucket_name].objects[obj_name]
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def buckets
         | 
| 30 | 
            +
                  s3.buckets
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
    
        data/lib/eb_deployer.rb
    ADDED
    
    | @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            require "eb_deployer/version"
         | 
| 2 | 
            +
            require "eb_deployer/deployment_strategy"
         | 
| 3 | 
            +
            require "eb_deployer/beanstalk"
         | 
| 4 | 
            +
            require "eb_deployer/cloud_formation_provisioner"
         | 
| 5 | 
            +
            require "eb_deployer/environment"
         | 
| 6 | 
            +
            require "eb_deployer/event_poller"
         | 
| 7 | 
            +
            require "eb_deployer/package"
         | 
| 8 | 
            +
            require 'eb_deployer/s3_driver'
         | 
| 9 | 
            +
            require 'digest'
         | 
| 10 | 
            +
            require 'set'
         | 
| 11 | 
            +
            require 'time'
         | 
| 12 | 
            +
            require 'json'
         | 
| 13 | 
            +
            require 'timeout'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            module EbDeployer
         | 
| 16 | 
            +
              def self.deploy(opts)
         | 
| 17 | 
            +
                # AWS.config(:logger => Logger.new($stdout))
         | 
| 18 | 
            +
                if region = opts[:region]
         | 
| 19 | 
            +
                  AWS.config(:region => region)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                bs = opts[:bs_driver] || Beanstalk.new
         | 
| 23 | 
            +
                s3 = opts[:s3_driver] || S3Driver.new
         | 
| 24 | 
            +
                stack_name = opts[:solution_stack_name] || "64bit Amazon Linux running Tomcat 7"
         | 
| 25 | 
            +
                app = opts[:application]
         | 
| 26 | 
            +
                env_name = opts[:environment]
         | 
| 27 | 
            +
                version_label = opts[:version_label].to_s.strip
         | 
| 28 | 
            +
                cname = opts[:cname]
         | 
| 29 | 
            +
                env_settings = opts[:settings] || []
         | 
| 30 | 
            +
                strategy_name = opts[:strategy] || :inplace_update
         | 
| 31 | 
            +
                cname_prefix = opts[:cname_prefix] || [app, env_name].join('-')
         | 
| 32 | 
            +
                smoke_test = opts[:smoke_test] || Proc.new {}
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                package = Package.new(opts[:package], app + "-packages", s3)
         | 
| 35 | 
            +
                cf = CloudFormationProvisioner.new("#{app}-#{env_name}")
         | 
| 36 | 
            +
                strategy = DeploymentStrategy.create(strategy_name, app, env_name, bs,
         | 
| 37 | 
            +
                                                     :solution_stack => stack_name,
         | 
| 38 | 
            +
                                                     :cname_prefix => cname_prefix,
         | 
| 39 | 
            +
                                                     :smoke_test => smoke_test)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                if resources = opts[:resources]
         | 
| 42 | 
            +
                  env_settings += cf.provision(resources)
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                package.upload
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                unless bs.application_version_labels.include?(version_label)
         | 
| 48 | 
            +
                  bs.create_application_version(app, version_label, package.source_bundle)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                strategy.deploy(version_label, env_settings)
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            end
         | 
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            class EBStub
         | 
| 2 | 
            +
              def initialize
         | 
| 3 | 
            +
                @envs = {}
         | 
| 4 | 
            +
                @versions = {}
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              def create_environment(app, env, solution_stack, cname_prefix, version, settings)
         | 
| 8 | 
            +
                raise 'cname prefix is not avaible' if @envs.values.detect { |env| env[:cname_prefix] == cname_prefix }
         | 
| 9 | 
            +
                @envs[env_key(app, env)] = {
         | 
| 10 | 
            +
                  :solution_stack => solution_stack,
         | 
| 11 | 
            +
                  :version => version,
         | 
| 12 | 
            +
                  :cname_prefix => cname_prefix,
         | 
| 13 | 
            +
                  :settings => settings}
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def update_environment(app, env, version, settings)
         | 
| 17 | 
            +
                @envs[env_key(app, env)].merge!(:version => version, :settings => settings)
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def environment_exists?(app_name, env_name)
         | 
| 21 | 
            +
                @envs.has_key?(env_key(app_name, env_name))
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def create_application_version(app_name, version_label, source_bundle)
         | 
| 25 | 
            +
                @versions[app_name] ||= []
         | 
| 26 | 
            +
                @versions[app_name] = { version_label => source_bundle }
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def application_version_labels
         | 
| 30 | 
            +
                @versions.values.map(&:keys).flatten
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def fetch_events(app_name, env_name, options={})
         | 
| 34 | 
            +
                [[{:event_date => Time.now.utc,
         | 
| 35 | 
            +
                    :message => 'Environment update completed successfully'}],
         | 
| 36 | 
            +
                 nil]
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def environment_cname_prefix(app_name, env_name)
         | 
| 40 | 
            +
                return unless @envs[env_key(app_name, env_name)]
         | 
| 41 | 
            +
                @envs[env_key(app_name, env_name)][:cname_prefix] || app_name + "-" + SecureRandom.hex
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def environment_cname(app_name, env_name)
         | 
| 45 | 
            +
                return unless @envs[env_key(app_name, env_name)]
         | 
| 46 | 
            +
                environment_cname_prefix(app_name, env_name) + ".elasticbeanstalk.com"
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
             | 
| 50 | 
            +
              def environment_swap_cname(app_name, env1_name, env2_name)
         | 
| 51 | 
            +
                env1, env2 = @envs[env_key(app_name, env1_name)], @envs[env_key(app_name, env2_name)]
         | 
| 52 | 
            +
                temp = env1[:cname_prefix]
         | 
| 53 | 
            +
                env1[:cname_prefix] = env2[:cname_prefix]
         | 
| 54 | 
            +
                env2[:cname_prefix] = temp
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              def environment_health_state(app_name, env_name)
         | 
| 58 | 
            +
                'Green'
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              #test only
         | 
| 62 | 
            +
              def environment_verion_label(app_name, env_name)
         | 
| 63 | 
            +
                @envs[env_key(app_name, env_name)][:version]
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              private
         | 
| 67 | 
            +
              def env_key(app, name)
         | 
| 68 | 
            +
                [app, name].join("-")
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            class S3Stub
         | 
| 74 | 
            +
              def initialize
         | 
| 75 | 
            +
                @buckets = {}
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              def create_bucket(bucket_name)
         | 
| 79 | 
            +
                @buckets[bucket_name] = {}
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              def bucket_exists?(bucket_name)
         | 
| 83 | 
            +
                @buckets.has_key?(bucket_name)
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              def object_length(bucket_name, obj_name)
         | 
| 87 | 
            +
                @buckets[bucket_name][obj_name] && File.size(@buckets[bucket_name][obj_name])
         | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
              def upload_file(bucket_name, obj_name, file)
         | 
| 91 | 
            +
                @buckets[bucket_name][obj_name] = file
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
            end
         | 
    
        data/test/deploy_test.rb
    ADDED
    
    | @@ -0,0 +1,147 @@ | |
| 1 | 
            +
            require 'eb_deployer'
         | 
| 2 | 
            +
            require 'aws_driver_stubs'
         | 
| 3 | 
            +
            require 'minitest/autorun'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class DeployTest < Minitest::Test
         | 
| 6 | 
            +
              def setup
         | 
| 7 | 
            +
                @eb_driver = EBStub.new
         | 
| 8 | 
            +
                @s3_driver = S3Stub.new
         | 
| 9 | 
            +
                @sample_package = '/tmp/app-package.war'
         | 
| 10 | 
            +
                File.open(@sample_package, 'w') { |f| f << 's' * 100 }
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def deploy(opts)
         | 
| 14 | 
            +
                EbDeployer.deploy({:package => @sample_package,
         | 
| 15 | 
            +
                                    :bs_driver => @eb_driver,
         | 
| 16 | 
            +
                                    :s3_driver => @s3_driver,
         | 
| 17 | 
            +
                                    :version_label => 1}.merge(opts))
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
             | 
| 21 | 
            +
              def test_first_deployment_create_environment
         | 
| 22 | 
            +
                assert !@eb_driver.environment_exists?('simple', 'production')
         | 
| 23 | 
            +
                deploy(:application => 'simple', :environment => "production")
         | 
| 24 | 
            +
                assert @eb_driver.environment_exists?('simple', 'production')
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
             | 
| 28 | 
            +
              def test_update_environment_with_new_version_should_change_version_that_deployed
         | 
| 29 | 
            +
                deploy(:application => 'simple',
         | 
| 30 | 
            +
                       :environment => "production",
         | 
| 31 | 
            +
                       :version_label => 1)
         | 
| 32 | 
            +
                assert_equal '1', @eb_driver.environment_verion_label('simple', 'production')
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                deploy(:application => 'simple',
         | 
| 35 | 
            +
                       :environment => "production",
         | 
| 36 | 
            +
                       :version_label => 2)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                assert_equal '2', @eb_driver.environment_verion_label('simple', 'production')
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              def test_default_cname_that_deployed_should_app_env_name
         | 
| 42 | 
            +
                deploy(:application => 'simple',
         | 
| 43 | 
            +
                       :environment => "production",
         | 
| 44 | 
            +
                       :version_label => 42)
         | 
| 45 | 
            +
                assert_equal "simple-production", @eb_driver.environment_cname_prefix('simple', 'production')
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def test_cname_prefix_can_be_override
         | 
| 49 | 
            +
                deploy(:application => 'simple',
         | 
| 50 | 
            +
                       :environment => "production",
         | 
| 51 | 
            +
                       :cname_prefix => 'sports123',
         | 
| 52 | 
            +
                       :version_label => 42)
         | 
| 53 | 
            +
                assert_equal "sports123", @eb_driver.environment_cname_prefix('simple', 'production')
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
             | 
| 57 | 
            +
              def test_smoke_test_should_be_run_after_env_created_or_update
         | 
| 58 | 
            +
                host_for_smoke_test = nil
         | 
| 59 | 
            +
                deploy(:application => 'simple',
         | 
| 60 | 
            +
                       :environment => "production",
         | 
| 61 | 
            +
                       :cname_prefix => 'foobar',
         | 
| 62 | 
            +
                       :smoke_test => lambda { |host| host_for_smoke_test = host },
         | 
| 63 | 
            +
                       :version_label => 42)
         | 
| 64 | 
            +
                assert_equal 'foobar.elasticbeanstalk.com', host_for_smoke_test
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                host_for_smoke_test = nil
         | 
| 67 | 
            +
                deploy(:application => 'simple',
         | 
| 68 | 
            +
                       :environment => "production",
         | 
| 69 | 
            +
                       :cname_prefix => 'foobar',
         | 
| 70 | 
            +
                       :smoke_test => lambda { |host| host_for_smoke_test = host },
         | 
| 71 | 
            +
                       :version_label => 43)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                assert_equal 'foobar.elasticbeanstalk.com', host_for_smoke_test
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
             | 
| 77 | 
            +
             | 
| 78 | 
            +
              def test_blue_green_deployment_strategy_should_create_blue_env_on_first_deployment
         | 
| 79 | 
            +
                deploy(:application => 'simple',
         | 
| 80 | 
            +
                       :environment => "production",
         | 
| 81 | 
            +
                       :strategy => 'blue_green',
         | 
| 82 | 
            +
                       :version_label => 42)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                assert @eb_driver.environment_exists?('simple', 'production-blue')
         | 
| 85 | 
            +
                assert_equal 'simple-production',  @eb_driver.environment_cname_prefix('simple', 'production-blue')
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
             | 
| 89 | 
            +
              def test_blue_green_deployment_should_create_green_env_if_blue_exists
         | 
| 90 | 
            +
                deploy(:application => 'simple',
         | 
| 91 | 
            +
                       :environment => "production",
         | 
| 92 | 
            +
                       :strategy => 'blue_green',
         | 
| 93 | 
            +
                       :version_label => 42)
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                deploy(:application => 'simple',
         | 
| 96 | 
            +
                       :environment => "production",
         | 
| 97 | 
            +
                       :strategy => 'blue_green',
         | 
| 98 | 
            +
                       :version_label => 43)
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                assert @eb_driver.environment_exists?('simple', 'production-blue')
         | 
| 101 | 
            +
                assert @eb_driver.environment_exists?('simple', 'production-green')
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
             | 
| 105 | 
            +
              def test_blue_green_deployment_should_swap_cname_to_make_active_most_recent_updated_env
         | 
| 106 | 
            +
                deploy(:application => 'simple',
         | 
| 107 | 
            +
                       :environment => "production",
         | 
| 108 | 
            +
                       :strategy => 'blue_green',
         | 
| 109 | 
            +
                       :version_label => 42)
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                deploy(:application => 'simple',
         | 
| 112 | 
            +
                       :environment => "production",
         | 
| 113 | 
            +
                       :strategy => 'blue_green',
         | 
| 114 | 
            +
                       :version_label => 43)
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                assert_match(/simple-production-inactive/,  @eb_driver.environment_cname_prefix('simple', 'production-blue'))
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                assert_equal 'simple-production',  @eb_driver.environment_cname_prefix('simple', 'production-green')
         | 
| 119 | 
            +
             | 
| 120 | 
            +
             | 
| 121 | 
            +
                deploy(:application => 'simple',
         | 
| 122 | 
            +
                       :environment => "production",
         | 
| 123 | 
            +
                       :strategy => 'blue_green',
         | 
| 124 | 
            +
                       :version_label => 44)
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                assert_match(/simple-production-inactive/,  @eb_driver.environment_cname_prefix('simple', 'production-green'))
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                assert_equal 'simple-production',  @eb_driver.environment_cname_prefix('simple', 'production-blue')
         | 
| 129 | 
            +
              end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
             | 
| 132 | 
            +
              def test_blue_green_deploy_should_run_smoke_test_before_cname_switch
         | 
| 133 | 
            +
                smoked_host = []
         | 
| 134 | 
            +
                smoke_test = lambda { |host| smoked_host << host }
         | 
| 135 | 
            +
                [42, 43, 44].each do |version_label|
         | 
| 136 | 
            +
                  deploy(:application => 'simple',
         | 
| 137 | 
            +
                         :environment => "production",
         | 
| 138 | 
            +
                         :strategy => 'blue_green',
         | 
| 139 | 
            +
                         :smoke_test => smoke_test,
         | 
| 140 | 
            +
                         :version_label => version_label)
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                assert_equal ['simple-production.elasticbeanstalk.com',
         | 
| 144 | 
            +
                              'simple-production-inactive.elasticbeanstalk.com',
         | 
| 145 | 
            +
                              'simple-production-inactive.elasticbeanstalk.com'], smoked_host
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,98 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: eb_deployer
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
              prerelease: 
         | 
| 6 | 
            +
            platform: ruby
         | 
| 7 | 
            +
            authors:
         | 
| 8 | 
            +
            - wpc
         | 
| 9 | 
            +
            - betarelease
         | 
| 10 | 
            +
            autorequire: 
         | 
| 11 | 
            +
            bindir: bin
         | 
| 12 | 
            +
            cert_chain: []
         | 
| 13 | 
            +
            date: 2013-06-12 00:00:00.000000000 Z
         | 
| 14 | 
            +
            dependencies:
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 16 | 
            +
              name: aws-sdk
         | 
| 17 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 18 | 
            +
                none: false
         | 
| 19 | 
            +
                requirements:
         | 
| 20 | 
            +
                - - ! '>='
         | 
| 21 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            +
                    version: '0'
         | 
| 23 | 
            +
              type: :runtime
         | 
| 24 | 
            +
              prerelease: false
         | 
| 25 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 26 | 
            +
                none: false
         | 
| 27 | 
            +
                requirements:
         | 
| 28 | 
            +
                - - ! '>='
         | 
| 29 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 30 | 
            +
                    version: '0'
         | 
| 31 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 32 | 
            +
              name: minitest
         | 
| 33 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 34 | 
            +
                none: false
         | 
| 35 | 
            +
                requirements:
         | 
| 36 | 
            +
                - - ! '>='
         | 
| 37 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 38 | 
            +
                    version: '0'
         | 
| 39 | 
            +
              type: :development
         | 
| 40 | 
            +
              prerelease: false
         | 
| 41 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 42 | 
            +
                none: false
         | 
| 43 | 
            +
                requirements:
         | 
| 44 | 
            +
                - - ! '>='
         | 
| 45 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 46 | 
            +
                    version: '0'
         | 
| 47 | 
            +
            description: Elastic Beanstalk Deployer with different deployment strategies.
         | 
| 48 | 
            +
            email:
         | 
| 49 | 
            +
            - alex.hal9000@gmail.com
         | 
| 50 | 
            +
            - sudhindra.r.rao@gmail.com
         | 
| 51 | 
            +
            executables: []
         | 
| 52 | 
            +
            extensions: []
         | 
| 53 | 
            +
            extra_rdoc_files: []
         | 
| 54 | 
            +
            files:
         | 
| 55 | 
            +
            - .gitignore
         | 
| 56 | 
            +
            - Gemfile
         | 
| 57 | 
            +
            - LICENSE
         | 
| 58 | 
            +
            - README.md
         | 
| 59 | 
            +
            - Rakefile
         | 
| 60 | 
            +
            - eb_deployer.gemspec
         | 
| 61 | 
            +
            - lib/eb_deployer.rb
         | 
| 62 | 
            +
            - lib/eb_deployer/beanstalk.rb
         | 
| 63 | 
            +
            - lib/eb_deployer/cloud_formation_provisioner.rb
         | 
| 64 | 
            +
            - lib/eb_deployer/deployment_strategy.rb
         | 
| 65 | 
            +
            - lib/eb_deployer/environment.rb
         | 
| 66 | 
            +
            - lib/eb_deployer/event_poller.rb
         | 
| 67 | 
            +
            - lib/eb_deployer/package.rb
         | 
| 68 | 
            +
            - lib/eb_deployer/s3_driver.rb
         | 
| 69 | 
            +
            - lib/eb_deployer/version.rb
         | 
| 70 | 
            +
            - test/aws_driver_stubs.rb
         | 
| 71 | 
            +
            - test/deploy_test.rb
         | 
| 72 | 
            +
            homepage: https://github.com/ThoughtWorksStudios/eb_deployer
         | 
| 73 | 
            +
            licenses: []
         | 
| 74 | 
            +
            post_install_message: 
         | 
| 75 | 
            +
            rdoc_options: []
         | 
| 76 | 
            +
            require_paths:
         | 
| 77 | 
            +
            - lib
         | 
| 78 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
              none: false
         | 
| 80 | 
            +
              requirements:
         | 
| 81 | 
            +
              - - ! '>='
         | 
| 82 | 
            +
                - !ruby/object:Gem::Version
         | 
| 83 | 
            +
                  version: '0'
         | 
| 84 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 85 | 
            +
              none: false
         | 
| 86 | 
            +
              requirements:
         | 
| 87 | 
            +
              - - ! '>='
         | 
| 88 | 
            +
                - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                  version: '0'
         | 
| 90 | 
            +
            requirements: []
         | 
| 91 | 
            +
            rubyforge_project: 
         | 
| 92 | 
            +
            rubygems_version: 1.8.24
         | 
| 93 | 
            +
            signing_key: 
         | 
| 94 | 
            +
            specification_version: 3
         | 
| 95 | 
            +
            summary: Pick strategies like InplaceUpdate, Blue/Green.
         | 
| 96 | 
            +
            test_files:
         | 
| 97 | 
            +
            - test/aws_driver_stubs.rb
         | 
| 98 | 
            +
            - test/deploy_test.rb
         |