eb_deployer 0.2.9 → 0.3.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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2M0YzZlNzgzYzJkODBlNzhmYWEzNjNhZDA5MWVjYTlhMWRmYzkyMg==
5
+ data.tar.gz: !binary |-
6
+ MTc3YTc2ODk4YjAzYjEyNzEwYmI3ODE2MTkyNDgzM2FlYjA3MTM1Yw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MmQwNGE5ZTViNzlmNGE4MDhhMDBjNDg0M2NiNmM3YjIzZWFiZjYyMmQ1NGE5
10
+ MTE1MDNjYzMwZGMzMjI5NmFmMGQ3OTdkODY1M2E1NGIzOTkyYjZkNGFkNGQw
11
+ MWY5Mjc1ZTVlOTA0NjU0YmM3NzI1ZWUwODY1YmY3ZDQxMGVhN2I=
12
+ data.tar.gz: !binary |-
13
+ Y2UwZTliNTE1ZWI1OTRkMWM0Mzk3NmIxNTJmZDYzNGU4ZGMzOGRiNjIwYTYw
14
+ ZWM5ZDgyMjkzZmRiNWRkZTQwZDU0ODYyZDM3ZTJkMGQ1M2Q1ZjA0YTk5MWI1
15
+ OWY5Y2EyOTgzODA4MmM1NzU4MTA5NThkMTU4ODA2ODgxZjQxZWU=
data/.gitignore CHANGED
@@ -19,3 +19,5 @@ tmp
19
19
  _site
20
20
  /samples/jruby_rails4/jruby_rails4.war
21
21
  /samples/jruby_rails4/public/assets/*
22
+ /TAGS
23
+ /.aws
data/eb_deployer.gemspec CHANGED
@@ -10,7 +10,6 @@ Gem::Specification.new do |gem|
10
10
  gem.license = 'MIT'
11
11
 
12
12
  gem.add_runtime_dependency 'aws-sdk'
13
- gem.add_development_dependency 'minitest'
14
13
 
15
14
  gem.files = `git ls-files`.split($\).reject {|f| f =~ /^samples\// }
16
15
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -14,7 +14,8 @@ module EbDeployer
14
14
  package = Package.new(package, @bucket + ".packages", @s3_driver)
15
15
  package.upload
16
16
 
17
- unless @eb_driver.application_version_labels.include?(version_label)
17
+ unless @eb_driver.application_version_labels(@name).include?(version_label)
18
+ log("Create application version with label #{version_label}")
18
19
  @eb_driver.create_application_version(@name, version_label, package.source_bundle)
19
20
  end
20
21
  end
@@ -22,19 +23,47 @@ module EbDeployer
22
23
  def delete
23
24
  if @eb_driver.application_exists?(@name)
24
25
  @eb_driver.environment_names_for_application(@name).each do |env|
26
+ log("Terminating environment #{env}")
25
27
  @eb_driver.delete_environment(@name, env)
26
28
  end
27
29
 
30
+ log("Deleting application")
28
31
  @eb_driver.delete_application(@name)
29
32
  end
30
33
  end
31
34
 
35
+ def versions
36
+ @eb_driver.application_versions(@name).map do |apv|
37
+ {
38
+ :version => apv[:version_label],
39
+ :date_created => apv[:date_created],
40
+ :date_updated => apv[:date_updated]
41
+ }
42
+ end
43
+ end
44
+
45
+ def remove(versions, delete_from_s3)
46
+ versions.each do |version|
47
+ begin
48
+ log("Removing #{version}")
49
+ @eb_driver.delete_application_version(@name, version, delete_from_s3)
50
+ rescue AWS::ElasticBeanstalk::Errors::SourceBundleDeletionFailure => e
51
+ log(e.message)
52
+ end
53
+ end
54
+ end
55
+
32
56
  private
33
57
 
34
58
  def create_application_if_not_exists
35
59
  unless @eb_driver.application_exists?(@name)
60
+ log("Creating application")
36
61
  @eb_driver.create_application(@name)
37
62
  end
38
63
  end
64
+
65
+ def log(msg)
66
+ puts "[#{Time.now.utc}][application:#{@name}] #{msg}"
67
+ end
39
68
  end
40
69
  end
@@ -46,14 +46,28 @@ module EbDeployer
46
46
  @client.terminate_environment(:environment_name => env_name)
47
47
  end
48
48
 
49
+ def delete_application_version(app_name, version, delete_source_bundle)
50
+ request = {
51
+ :application_name => app_name,
52
+ :version_label => version,
53
+ :delete_source_bundle => delete_source_bundle
54
+ }
55
+ @client.delete_application_version(request)
56
+ end
57
+
49
58
  def create_application_version(app_name, version_label, source_bundle)
50
59
  @client.create_application_version(:application_name => app_name,
51
60
  :source_bundle => source_bundle,
52
61
  :version_label => version_label)
53
62
  end
54
63
 
55
- def application_version_labels
56
- @client.describe_application_versions[:application_versions].map { |apv| apv[:version_label] }
64
+ def application_version_labels(app_name)
65
+ application_versions(app_name).map { |apv| apv[:version_label] }
66
+ end
67
+
68
+ def application_versions(app_name)
69
+ request = { :application_name => app_name }
70
+ @client.describe_application_versions(request)[:application_versions]
57
71
  end
58
72
 
59
73
  def fetch_events(app_name, env_name, params, &block)
@@ -41,7 +41,7 @@ module EbDeployer
41
41
  end
42
42
 
43
43
  def log(msg)
44
- puts "[#{Time.now.utc}][cloud_formation] #{msg}"
44
+ puts "[#{Time.now.utc}][cloud_formation_driver] #{msg}"
45
45
  end
46
46
  end
47
47
 
@@ -88,7 +88,7 @@ module EbDeployer
88
88
  end
89
89
 
90
90
  def log(msg)
91
- puts "[#{Time.now.utc}][resources-stack] #{msg}"
91
+ puts "[#{Time.now.utc}][cloud_formation_provisioner] #{msg}"
92
92
  end
93
93
  end
94
94
  end
@@ -29,7 +29,7 @@ module EbDeployer
29
29
 
30
30
  env = options[:environment]
31
31
  envs = config_settings.delete(:environments)
32
- raise 'Environment #{evn} is not defined in #{config_file}' unless envs.has_key?(env)
32
+ raise "Environment #{env} is not defined in #{config_file}" unless envs.has_key?(env)
33
33
  env_settings = symbolize_keys(envs[env] || {})
34
34
  env_option_settings = env_settings.delete(:option_settings) || []
35
35
 
@@ -34,6 +34,17 @@ common:
34
34
  # you override it to 'on' for production environment.
35
35
  # phoenix_mode: false
36
36
 
37
+ # Specifies the maximum number of versions to keep. Older versions are removed
38
+ # and deleted from the S3 source bucket as well. If specified as zero or not
39
+ # specified, all versions will be kept. If a version_prefix is given, only removes
40
+ # version starting with the prefix.
41
+ # keep_latest: 200
42
+
43
+ # Specifies a prefix to prepend to the version label.
44
+ # This can be useful if you want to use different binaries for different
45
+ # environments.
46
+ # version_prefix:
47
+
37
48
  # Generating version label for package to be deployed. A readable version label will
38
49
  # provide better traceablity of your deployment process.
39
50
  # By default setting is:
@@ -36,7 +36,7 @@ module EbDeployer
36
36
  end
37
37
 
38
38
  def log(msg)
39
- puts "[#{Time.now.utc}][beanstalk:#{@name}] #{msg}"
39
+ puts "[#{Time.now.utc}][environment:#{@name}] #{msg}"
40
40
  end
41
41
 
42
42
  private
@@ -100,7 +100,7 @@ module EbDeployer
100
100
 
101
101
 
102
102
  def log_event(event)
103
- puts "[#{event[:event_date]}][beanstalk:#{@name}] #{event[:message]}"
103
+ puts "[#{event[:event_date]}][environment:#{@name}] #{event[:message]}"
104
104
  end
105
105
  end
106
106
  end
@@ -1,3 +1,3 @@
1
1
  module EbDeployer
2
- VERSION = "0.2.9"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,30 @@
1
+ module EbDeployer
2
+ class VersionCleaner
3
+ def initialize(app, number_to_keep)
4
+ @app = app
5
+ @number_to_keep = number_to_keep
6
+ end
7
+
8
+ def clean(version_prefix = "")
9
+ if @number_to_keep > 0
10
+ versions_to_remove = versions_to_clean(version_prefix)
11
+ @app.remove(versions_to_remove, true)
12
+ end
13
+ end
14
+
15
+ private
16
+ def versions_to_clean(version_prefix = "")
17
+ all_versions = @app.versions.select do |apv|
18
+ apv[:version].start_with?(version_prefix)
19
+ end
20
+
21
+ all_versions.sort! { |x, y| y[:date_updated] <=> x[:date_updated] }
22
+ versions_to_keep = all_versions.slice!(range_to_keep)
23
+ all_versions.map { |apv| apv[:version] }
24
+ end
25
+
26
+ def range_to_keep
27
+ (0..(@number_to_keep-1))
28
+ end
29
+ end
30
+ end
data/lib/eb_deployer.rb CHANGED
@@ -11,6 +11,7 @@ require 'eb_deployer/cloud_formation_driver'
11
11
  require 'eb_deployer/config_loader'
12
12
  require 'eb_deployer/default_config'
13
13
  require 'eb_deployer/smoke_test'
14
+ require 'eb_deployer/version_cleaner'
14
15
  require 'digest'
15
16
  require 'set'
16
17
  require 'time'
@@ -152,6 +153,14 @@ module EbDeployer
152
153
  # :version_label => ENV['MY_PIPELINE_COUNTER']
153
154
  # || "dev-" + Digest::MD5.file(my_package).hexdigest
154
155
  #
156
+ # @options opts [Symbol] :version_prefix. Specifies a prefix to prepend to the
157
+ # version label. This can be useful if you want to use different binaries for
158
+ # different environments.
159
+ #
160
+ # @option opts [Symbol] :keep_latest. Specifies the maximum number of versions to
161
+ # keep. Older versions are removed and deleted from the S3 source bucket as well.
162
+ # If specified as zero or not specified, all versions will be kept. If a
163
+ # version_prefix is given, only removes version starting with the prefix.
155
164
  def self.deploy(opts)
156
165
  # AWS.config(:logger => Logger.new($stdout))
157
166
  if region = opts[:region]
@@ -164,7 +173,8 @@ module EbDeployer
164
173
  stack_name = opts[:solution_stack_name] || "64bit Amazon Linux running Tomcat 7"
165
174
  app = opts[:application]
166
175
  env_name = opts[:environment]
167
- version_label = opts[:version_label].to_s.strip
176
+ version_prefix = opts[:version_prefix].to_s.strip
177
+ version_label = "#{version_prefix}#{opts[:version_label].to_s.strip}"
168
178
  cname = opts[:cname]
169
179
  env_settings = opts[:option_settings] || opts[:settings] || []
170
180
  strategy_name = opts[:strategy] || :blue_green
@@ -173,6 +183,7 @@ module EbDeployer
173
183
  phoenix_mode = opts[:phoenix_mode]
174
184
  bucket = opts[:package_bucket] || app
175
185
  skip_resource = opts[:skip_resource_stack_update]
186
+ keep_latest = opts[:keep_latest].to_i || 0
176
187
 
177
188
  application = Application.new(app, bs, s3, bucket)
178
189
 
@@ -184,6 +195,8 @@ module EbDeployer
184
195
  :smoke_test => smoke_test,
185
196
  :phoenix_mode => phoenix_mode)
186
197
 
198
+ cleaner = VersionCleaner.new(application, keep_latest)
199
+
187
200
  if resources = opts[:resources]
188
201
  cf.provision(resources) unless skip_resource
189
202
  env_settings += cf.transform_outputs(resources)
@@ -191,6 +204,7 @@ module EbDeployer
191
204
 
192
205
  application.create_version(version_label, opts[:package])
193
206
  strategy.deploy(version_label, env_settings)
207
+ cleaner.clean(version_prefix)
194
208
  end
195
209
 
196
210
  def self.destroy(opts)
@@ -4,6 +4,7 @@ class EBStub
4
4
  @envs = {}
5
5
  @versions = {}
6
6
  @envs_been_deleted = {}
7
+ @versions_deleted = {}
7
8
  end
8
9
 
9
10
  def create_application(app)
@@ -48,11 +49,30 @@ class EBStub
48
49
 
49
50
  def create_application_version(app_name, version_label, source_bundle)
50
51
  @versions[app_name] ||= []
51
- @versions[app_name] = { version_label => source_bundle }
52
+ @versions[app_name] << {
53
+ :version_label => version_label,
54
+ :source_bundle => source_bundle,
55
+ :date_created => Time.now,
56
+ :date_updated => Time.now
57
+ }
52
58
  end
53
59
 
54
- def application_version_labels
55
- @versions.values.map(&:keys).flatten
60
+ def delete_application_version(app_name, version, delete_source_bundle)
61
+ @versions_deleted[app_name] ||= []
62
+ @versions_deleted[app_name] << version
63
+ @versions[app_name].delete_if { |apv| apv[:version_label] == version }
64
+ end
65
+
66
+ def application_versions(app_name)
67
+ @versions[app_name]
68
+ end
69
+
70
+ def application_version_labels(app_name)
71
+ if @versions[app_name]
72
+ @versions[app_name].map { |appv| appv[:version_label]}
73
+ else
74
+ []
75
+ end
56
76
  end
57
77
 
58
78
  def fetch_events(app_name, env_name, options={})
@@ -88,7 +108,6 @@ class EBStub
88
108
  'Green'
89
109
  end
90
110
 
91
-
92
111
  #test only
93
112
  def environment_verion_label(app_name, env_name)
94
113
  @envs[env_key(app_name, env_name)][:version]
@@ -110,6 +129,10 @@ class EBStub
110
129
  @envs_been_deleted[app] || []
111
130
  end
112
131
 
132
+ def versions_deleted(app_name)
133
+ @versions_deleted[app_name]
134
+ end
135
+
113
136
  private
114
137
 
115
138
  def env_key(app, name)
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class CloudFormationProvisionerTest < Minitest::Test
3
+ class CloudFormationProvisionerTest < MiniTest::Unit::TestCase
4
4
  def setup
5
5
  @cf = CFStub.new
6
6
  @provisioner = EbDeployer::CloudFormationProvisioner.new("myresources", @cf)
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ConfigLoaderTest < Minitest::Test
3
+ class ConfigLoaderTest < MiniTest::Unit::TestCase
4
4
  def setup
5
5
  @loader = EbDeployer::ConfigLoader.new
6
6
  @sample_package = sample_file('app-package.war')
@@ -108,6 +108,20 @@ YAML
108
108
  'value' => "2"}], config[:option_settings])
109
109
  end
110
110
 
111
+ def test_env_is_required
112
+ error = assert_raises(RuntimeError) {
113
+ @loader.load(generate_input(<<-YAML, :environment => 'non_existant'))
114
+ application: myapp
115
+ common:
116
+ strategy: inplace-update
117
+ environments:
118
+ dev:
119
+ YAML
120
+ }
121
+
122
+ assert_match(/non_existant/, error.message)
123
+ end
124
+
111
125
  private
112
126
 
113
127
  def md5_digest(file)
data/test/deploy_test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class DeployTest < Minitest::Test
3
+ class DeployTest < MiniTest::Unit::TestCase
4
4
  def setup
5
5
  @eb_driver = EBStub.new
6
6
  @s3_driver = S3Stub.new
@@ -60,6 +60,55 @@ class DeployTest < Minitest::Test
60
60
  assert_equal '2', @eb_driver.environment_verion_label('simple', eb_envname('simple', 'production'))
61
61
  end
62
62
 
63
+ def test_version_prefix_should_be_prepended_to_version_label
64
+ deploy(:application => 'simple',
65
+ :environment => "production",
66
+ :version_label => 1,
67
+ :version_prefix => "prod-")
68
+ assert_equal 'prod-1', @eb_driver.environment_verion_label('simple', eb_envname('simple', 'production'))
69
+ end
70
+
71
+ def test_should_keep_only_number_of_versions_specified
72
+ deploy(:application => 'simple',
73
+ :environment => "production",
74
+ :version_label => 1)
75
+
76
+ deploy(:application => 'simple',
77
+ :environment => "production",
78
+ :version_label => 2)
79
+
80
+ deploy(:application => 'simple',
81
+ :environment => "production",
82
+ :version_label => 3,
83
+ :keep_latest => 2)
84
+
85
+ assert_equal '1', @eb_driver.versions_deleted('simple').first
86
+ end
87
+
88
+ def test_should_only_remove_versions_with_matching_prefix
89
+ deploy(:application => 'simple',
90
+ :environment => "production",
91
+ :version_label => 1,
92
+ :version_prefix => "prod1-",
93
+ :keep_latest => 1)
94
+ deploy(:application => 'simple',
95
+ :environment => "production",
96
+ :version_label => 2,
97
+ :version_prefix => "prod1-",
98
+ :keep_latest => 1)
99
+ deploy(:application => 'simple',
100
+ :environment => "production",
101
+ :version_label => 1,
102
+ :version_prefix => "prod2-",
103
+ :keep_latest => 1)
104
+
105
+ assert_equal 'prod1-1', @eb_driver.versions_deleted('simple').first
106
+ assert_equal 1, @eb_driver.versions_deleted('simple').count
107
+
108
+ app_versions = @eb_driver.application_versions('simple').map { |apv| apv[:version_label] }
109
+ assert_equal ["prod1-2", "prod2-1"], app_versions
110
+ end
111
+
63
112
  def test_default_cname_that_deployed_should_app_env_name
64
113
  deploy(:application => 'simple',
65
114
  :environment => "production",
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class SmokeTestTest < MiniTest::Test
3
+ class SmokeTestTest < MiniTest::Unit::TestCase
4
4
  def test_call_proc_type_smoke_tests
5
5
  host_name_in_proc = nil
6
6
  EbDeployer::SmokeTest.new(lambda {|v| host_name_in_proc = v }).run("foo")
data/test/test_helper.rb CHANGED
@@ -7,7 +7,7 @@ require 'minitest/autorun'
7
7
  require 'minitest/pride'
8
8
 
9
9
 
10
- class Minitest::Test
10
+ class MiniTest::Unit::TestCase
11
11
  def sample_file(file_name, content='s' * 100)
12
12
  path = File.join('/tmp', file_name)
13
13
  File.open(path, 'w') { |f| f << content }
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eb_deployer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - wpc
@@ -10,12 +9,11 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-10-31 00:00:00.000000000 Z
12
+ date: 2014-01-07 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: aws-sdk
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
18
  - - ! '>='
21
19
  - !ruby/object:Gem::Version
@@ -23,23 +21,6 @@ dependencies:
23
21
  type: :runtime
24
22
  prerelease: false
25
23
  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
24
  requirements:
44
25
  - - ! '>='
45
26
  - !ruby/object:Gem::Version
@@ -77,6 +58,7 @@ files:
77
58
  - lib/eb_deployer/s3_driver.rb
78
59
  - lib/eb_deployer/smoke_test.rb
79
60
  - lib/eb_deployer/version.rb
61
+ - lib/eb_deployer/version_cleaner.rb
80
62
  - test/aws_driver_stubs.rb
81
63
  - test/cloud_formation_provisioner_test.rb
82
64
  - test/config_loader_test.rb
@@ -86,27 +68,26 @@ files:
86
68
  homepage: https://github.com/ThoughtWorksStudios/eb_deployer
87
69
  licenses:
88
70
  - MIT
71
+ metadata: {}
89
72
  post_install_message:
90
73
  rdoc_options: []
91
74
  require_paths:
92
75
  - lib
93
76
  required_ruby_version: !ruby/object:Gem::Requirement
94
- none: false
95
77
  requirements:
96
78
  - - ! '>='
97
79
  - !ruby/object:Gem::Version
98
80
  version: '0'
99
81
  required_rubygems_version: !ruby/object:Gem::Requirement
100
- none: false
101
82
  requirements:
102
83
  - - ! '>='
103
84
  - !ruby/object:Gem::Version
104
85
  version: '0'
105
86
  requirements: []
106
87
  rubyforge_project:
107
- rubygems_version: 1.8.24
88
+ rubygems_version: 2.2.0
108
89
  signing_key:
109
- specification_version: 3
90
+ specification_version: 4
110
91
  summary: Low friction deployments should be a breeze. Elastic Beanstalk provides a
111
92
  great foundation for performing Blue-Green deployments, and EbDeployer add a missing
112
93
  top to automate the whole flow out of box.