eb_deployer 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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.