eb_deployer_updated 0.8.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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +14 -0
  6. data/CHANGELOG.md +127 -0
  7. data/Gemfile +10 -0
  8. data/LICENSE +22 -0
  9. data/README.md +136 -0
  10. data/Rakefile +12 -0
  11. data/TODOS.md +11 -0
  12. data/bin/eb_deploy +13 -0
  13. data/eb_deployer.gemspec +22 -0
  14. data/lib/eb_deployer/application.rb +96 -0
  15. data/lib/eb_deployer/aws_driver/beanstalk.rb +158 -0
  16. data/lib/eb_deployer/aws_driver/cloud_formation_driver.rb +53 -0
  17. data/lib/eb_deployer/aws_driver/s3_driver.rb +35 -0
  18. data/lib/eb_deployer/aws_driver.rb +8 -0
  19. data/lib/eb_deployer/cf_event_source.rb +26 -0
  20. data/lib/eb_deployer/cloud_formation_provisioner.rb +120 -0
  21. data/lib/eb_deployer/component.rb +45 -0
  22. data/lib/eb_deployer/config_loader.rb +64 -0
  23. data/lib/eb_deployer/default_component.rb +32 -0
  24. data/lib/eb_deployer/default_config.rb +20 -0
  25. data/lib/eb_deployer/default_config.yml +159 -0
  26. data/lib/eb_deployer/deployment_strategy/blue_green.rb +79 -0
  27. data/lib/eb_deployer/deployment_strategy/blue_only.rb +45 -0
  28. data/lib/eb_deployer/deployment_strategy/inplace_update.rb +16 -0
  29. data/lib/eb_deployer/deployment_strategy.rb +20 -0
  30. data/lib/eb_deployer/eb_environment.rb +204 -0
  31. data/lib/eb_deployer/eb_event_source.rb +35 -0
  32. data/lib/eb_deployer/environment.rb +60 -0
  33. data/lib/eb_deployer/event_poller.rb +51 -0
  34. data/lib/eb_deployer/package.rb +39 -0
  35. data/lib/eb_deployer/resource_stacks.rb +20 -0
  36. data/lib/eb_deployer/smoke_test.rb +23 -0
  37. data/lib/eb_deployer/tasks.rb +45 -0
  38. data/lib/eb_deployer/throttling_handling.rb +17 -0
  39. data/lib/eb_deployer/utils.rb +33 -0
  40. data/lib/eb_deployer/version.rb +3 -0
  41. data/lib/eb_deployer/version_cleaner.rb +30 -0
  42. data/lib/eb_deployer.rb +339 -0
  43. data/lib/generators/eb_deployer/install/install_generator.rb +82 -0
  44. data/lib/generators/eb_deployer/install/templates/eb_deployer.rake +1 -0
  45. data/lib/generators/eb_deployer/install/templates/eb_deployer.yml.erb +181 -0
  46. data/lib/generators/eb_deployer/install/templates/ebextensions/01_postgres_packages.config +5 -0
  47. data/lib/generators/eb_deployer/install/templates/postgres_rds.json +88 -0
  48. data/test/aws_driver_stubs.rb +350 -0
  49. data/test/beanstalk_test.rb +23 -0
  50. data/test/blue_green_deploy_test.rb +114 -0
  51. data/test/blue_only_deploy_test.rb +78 -0
  52. data/test/cf_event_poller_test.rb +32 -0
  53. data/test/cloud_formation_provisioner_test.rb +47 -0
  54. data/test/config_loader_test.rb +205 -0
  55. data/test/deploy_test.rb +42 -0
  56. data/test/eb_environment_test.rb +120 -0
  57. data/test/eb_event_poller_test.rb +32 -0
  58. data/test/inplace_update_deploy_test.rb +110 -0
  59. data/test/multi_components_deploy_test.rb +164 -0
  60. data/test/rails_generators_test.rb +67 -0
  61. data/test/resources_deploy_test.rb +191 -0
  62. data/test/smoke_test_test.rb +23 -0
  63. data/test/template_deploy_test.rb +13 -0
  64. data/test/test_helper.rb +68 -0
  65. data/test/tier_setting_deploy_test.rb +24 -0
  66. data/test/versions_deploy_test.rb +120 -0
  67. metadata +194 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b8c974d8d01b507b9e0d46aa4859350f626434b12c50d9b0d687d78eaace650a
4
+ data.tar.gz: 919d802cac6b4afafdd81361262afea60cec9f8c8531285b6e2d50995bd3afa9
5
+ SHA512:
6
+ metadata.gz: 43013bd6ab07142e757427def47cec62b1e5b3e3711a8514aae5ebb827ee6f80ec8afb2a5fefb2c8f408648c9c8516862554b08fce9072b77bd4ee835dd7c614
7
+ data.tar.gz: 659aa0a7fc8547bcb0347cb294a37371549dc01d8b4492939accf68af85e09e3a6f3fa071ff6676e22a07a1b5c812e51c1ca47df36f075c832a132f6c200f359
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /Gemfile.lock
2
+ /pkg
3
+ /test/tmp
4
+ /tmp
5
+ /.rvmrc
6
+ /samples/jruby_rails4/jruby_rails4.war
7
+ /samples/jruby_rails4/public/assets/*
8
+ /TAGS
9
+ /.aws
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ eb_deployer
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.0
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.2.10
4
+ - 2.3.8
5
+ - 2.4.5
6
+ - 2.5.3
7
+ - jruby-9.2.4.0
8
+ before_install:
9
+ - gem install bundler
10
+ script: "bundle exec rake"
11
+ bundler_args: "--without repl documentation"
12
+ branches:
13
+ only:
14
+ - master
data/CHANGELOG.md ADDED
@@ -0,0 +1,127 @@
1
+ 0.7.0
2
+ =====
3
+
4
+ * Add service specific AWS sdk gems
5
+ * [#79](https://github.com/ThoughtWorksStudios/eb_deployer/pull/79): Environment updates can complete with errors
6
+ * [#82](https://github.com/ThoughtWorksStudios/eb_deployer/pull/82): Added a line to force STDOUT output every line
7
+ * [#85](https://github.com/ThoughtWorksStudios/eb_deployer/pull/85): Improve package not found error message
8
+ * [#86](https://github.com/ThoughtWorksStudios/eb_deployer/pull/86): Fix to for inactive stack updates when instances are 0
9
+
10
+ 0.6.6
11
+ =====
12
+
13
+ * Add support for specifying (and overriding) a [stack policy](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html) for the CloudFormation resource stack. (contributed by @jlabrecque)
14
+ * Fix issue where deployment hangs if resource stack update fails and stack is rolled back, deployment will now fail when the resource stack update fails. (contributed by @jlabrecque)
15
+ * Add support for creating environment base on a elasticbeanstalk template. (contributed by @djpate)
16
+
17
+ 0.6.5
18
+ =====
19
+
20
+ * #66: Making it possible to specify other accepted health states when deploying (@dziemid)
21
+
22
+ 0.6.4
23
+ =====
24
+
25
+ * fixes #65 - aws driver should be able to detect CNAME prefixes from both regionalized and legacy EB domains
26
+
27
+ 0.6.3
28
+ =====
29
+
30
+ * Wait until inactive environment status is ready before applying settings.
31
+
32
+ 0.6.0
33
+ =====
34
+
35
+ * Use aws-sdk 2.0
36
+ * Ruby 2.2 support
37
+ * Robust error handling on CloudFormation resource stack provisioning
38
+
39
+ 0.5.1
40
+ =====
41
+
42
+ * Fix issue: worker tier is picking up old version of aws-sqsd
43
+
44
+ 0.5.0
45
+ =====
46
+
47
+ * Worker tier support
48
+
49
+ 0.4.12
50
+ ======
51
+
52
+ * Update default solution stacks.
53
+ * Rails generator generates SECRET_KEY_BASE for rails 4 app.
54
+
55
+ 0.4.11
56
+ ======
57
+
58
+ * Make gem depend on aws-sdk-v1 until we put in support for both v1 and v2
59
+
60
+ 0.4.10
61
+ ======
62
+
63
+ * Fix #33
64
+
65
+ 0.4.9
66
+ ====
67
+
68
+ * Ignore AWS::ElasticBeanstalk::Errors::OperationInProgressFailure error when delete application version
69
+
70
+ 0.4.8
71
+ ====
72
+ * Raise an error if the environment launched with problems (contributed by kmanning)
73
+ * Add --stack-name option that let's use choose the name of the cloud
74
+ formation stack to operate on (contributed by NET-A-PORTER)
75
+ * Document typo/grammar fix (contributed by stig)
76
+ * Retry on AWS API throttling error when operating on versions
77
+
78
+ 0.4.7
79
+ ====
80
+ * Added blue-only deployment strategy (a variant of blue-green) that
81
+ skips the cname swap so that the newly deployed code remains on the
82
+ inactive "blue" instance. (contributed by jlabrecque)
83
+
84
+ 0.4.6
85
+ ====
86
+ * Make elasticbeanstalk event polling robust against clock shifting problem.
87
+
88
+ 0.4.5
89
+ ====
90
+ * Rails 3+ support: Rails Generator to install default configurations with
91
+ Postgres RDS resource and everything need for blue-green
92
+ deployment
93
+ * Add ability to tag beanstalk environment (from @pmcfadden)
94
+
95
+ 0.4.4
96
+ =====
97
+ * Fix S3 upload on Windows.
98
+ * Experimental support for "inactve_settings" options, which can be used to automatically scale down the inactive environment.
99
+ * Update default solution stack name to latest supported JAVA stack.
100
+ * Validate solution_stack option before creating environment and list available solution_stacks if not valid.
101
+
102
+ 0.4.3
103
+ =====
104
+ * Backoff and retry when AWS::ElasticBeanstalk::Errors::Throttling happens during polling events
105
+
106
+ 0.4.2
107
+ =====
108
+ * Allow provding different deploy strategy for different components.
109
+
110
+ 0.4.1
111
+ =====
112
+ * Remove options for delete all environments ("-d --all"), because it is too destructive and not recoverable.
113
+ * Experimental support for multiple components deployment.
114
+
115
+ 0.4.0
116
+ ====
117
+ * revert back all changes from 0.3.8 to 0.3.9. Elasticbeanstalk haven't relex the real unique constain. The actually contrain is you can not have environment name cross different application
118
+
119
+ 0.3.9
120
+ ====
121
+ * Fix hang problem introduced in 0.3.8 when migrating old ElasticBeanstalk environment.
122
+ * Fix issue #13 (Deployment via S3 object broken since 0.3.7)
123
+
124
+ 0.3.8
125
+ =====
126
+ * Change ElasticBeanstalk environment name pattern. Stop using sufix hash to make eb environment global unique. (Because ElasticBeanstalk does not require environment has globally uniqe name any more.)
127
+ * Add migration logic so that if a ElasticBeanstalk environment with legcy name exists, eb_deployer will automaticly terminate it and replace it with ElasticBeanstalk environment has new name pattern.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in eb_deployer.gemspec
4
+ gemspec
5
+
6
+ gem 'redcarpet', :platform => :mri
7
+ gem 'yard'
8
+ gem 'rake'
9
+ gem 'railties', '~> 5.0', '>= 5.0.0.1'
10
+ gem 'test-unit'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Thoughtworks Inc.
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,136 @@
1
+ # EbDeployer [![Build Status](https://snap-ci.com/ThoughtWorksStudios/eb_deployer/branch/master/build_image)](https://snap-ci.com/ThoughtWorksStudios/eb_deployer/branch/master) [![Build Status](https://travis-ci.org/ThoughtWorksStudios/eb_deployer.png?branch=master)](https://travis-ci.org/ThoughtWorksStudios/eb_deployer) [![Gem Version](https://badge.fury.io/rb/eb_deployer.svg)](http://badge.fury.io/rb/eb_deployer) [![Dependency Status](https://www.versioneye.com/ruby/eb_deployer/0.6.1/badge.svg)](https://www.versioneye.com/ruby/eb_deployer/0.6.1)
2
+
3
+ [Built with :yellow_heart: and :coffee: in San Francisco](http://www.thoughtworks.com/mingle/team/)
4
+
5
+ Low friction deployments should be a breeze. Elastic Beanstalk provides a great foundation for performing Blue-Green deployments, and EbDeployer add a missing link to automate the whole flow out of box.
6
+
7
+ [Deploy Service by EbDeployer](http://www.thoughtworks.com/mingle/infrastructure/2015/06/01/deploy-service-by-ebdeployer.html)
8
+
9
+ ## Installation
10
+
11
+ $ gem install eb_deployer
12
+
13
+ ## Usage
14
+
15
+ ### Step One: AWS Account Setup
16
+
17
+ Create an AWS IAM user for deploy and give it privilege to operate Elastic Beanstalk. Download the access keys for executing the deployment tasks later. Ensure your command line is primed with appropriate access_keys using one of techniques mentioned on [aws blog](http://ruby.awsblog.com/blog/tag/config). For example using environment variable:
18
+
19
+ $ export AWS_ACCESS_KEY_ID=xxx
20
+ $ export AWS_SECRET_ACCESS_KEY=xxx
21
+
22
+
23
+ ### Step Two: Packaging
24
+
25
+ You need to package your application for Elastic Beanstalk stack first. For Java app a warball is appropriate. For Ruby on Rails app a tar.gz file is good. You can also package a Rails/Sinatra app as a war ball using warbler and deploy to Java stack. (Please remember to run rake assets:precompile first for a rails app.)
26
+
27
+ If you were deploying to Elastic Beanstalk Ruby stack, simply zip your codebase is good enough, for example:
28
+
29
+ $ git ls-files | zip your-app-name.zip -@
30
+
31
+ ### Step Three: Generate configuration and Configure deployment process
32
+
33
+ $ eb_deploy
34
+
35
+ This will generate a default configuration at location 'config/eb_deployer.yml'. It is almost empty but working one. And it will generate settings for two environments 'development' and 'production'. Some options can be tweaked. The yml files includes documentation on how you can best suit it to your purpose.
36
+
37
+
38
+ ### Step Four: Fasten your seat belt
39
+ run deploy
40
+
41
+ $ eb_deploy -p <package built> -e <environment>
42
+
43
+ Then open aws console for Elastic Beanstalk to see the result of this deployment.
44
+
45
+
46
+ ### Configure Smoke Testing your stack
47
+
48
+ EB_Deployer allows you to automate your deployment and then some. You can also add smoke tests to your deployment - thus ensuring that the app you deployed is also working correctly.
49
+ Adding a smoke test suite is also simple. Check "smoke_test" section in your eb_deployer.yml. We show a simple curl based smoke test that helps you test if your app is up and responding to http.
50
+
51
+ smoke_test: |
52
+ curl_http_code = "curl -s -o /dev/null -w \"%{http_code}\" http://#{host_name}"
53
+ Timeout.timeout(600) do
54
+ until ['200', '302'].include?(`#{curl_http_code}`.strip)
55
+ sleep 5
56
+ end
57
+ end
58
+
59
+
60
+ Any rakeable test suite can be run as part of the smoke test(selenium, cucumber, capybara, and so on.)
61
+ You can add more smoke tests by calling arbitrary rake tasks (Please make sure check return status):
62
+
63
+ smoke_test: |
64
+ `rake test:smoke HOST_NAME=#{host_name}`
65
+ raise("Smoke failed!") unless $?.success?
66
+
67
+ Smoke testing gets you one step closer to continuous delivery.
68
+
69
+ ### Blue-Green deployment
70
+ Since every deployment now runs smoke test, you now have a better safety net around your deployments. This allows us to trigger automatic blue-green deployments.
71
+
72
+ To do this you need not do anything special. So far we have deployed the application only once. Let's call this the 'green' stack. Any subsequent calls to deployment will deployment a copy of this application to a new stack - the 'blue' stack. Smoke tests will be run on it and once everything passes the 'blue'(new) stack will be switched to the 'green' stack. Thus your new code will now be on the active stack and the user will experience no downtime.
73
+
74
+ Once this new stack is stable or has run for a while you can choose to delete the old stack. Or if you are doing continuous delivery you may be ready to another 'blue' deployment. You could just trigger another deployment and repeat this every hour/day/week... you get the idea.
75
+
76
+
77
+
78
+ ### Destroying a stack
79
+ So you are done with this environment, you can destroy it easily as well.
80
+
81
+ # destroy one environment
82
+ $ eb_deployer -d -e <environment>
83
+
84
+
85
+ and you are done!
86
+
87
+ Later tutorials coming soon will cover
88
+ * how to setup RDS or other AWS resource and share them between blue green environments
89
+
90
+ Take a look at code if you can not wait for the documentation.
91
+
92
+ ### eb_deploy.yml configuration file
93
+
94
+ Like Rails database.yml file, EbDeployer will read eb_deploy.yml file as ERB template file. So you can trade it as standard ERB template file, and substitute Ruby script. For example, the following eb_deployer.yml file partial configures DBPassword parameter for your CloudFormation template from an environment variable:
95
+
96
+ resources:
97
+ template: config/my_rds.json
98
+ inputs:
99
+ DBPassword: <%= ENV['MYDBPASSWORD'] %>
100
+
101
+
102
+ EbDeployer also provides the following help methods for convenience:
103
+
104
+ 1. random_hash: it basically is `SecureRandom.hex[0..9]`
105
+ 2. package_digest: it is your eb package file digest
106
+ 3. environment: environment name you passed in when executing eb_deploy script using -e option.
107
+
108
+ ## More
109
+
110
+ [Automated zero downtime deployment to AWS Elastic Beanstalk for Rails with EbDeployer](http://helabs.com/blog/2015/05/19/automated-zero-downtime-deployment-to-aws-elastic-beanstalk-for-rails-with-eb-deployer/?utm_content=buffer12098&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer)
111
+
112
+ Co-presented session with Amazon ElasticBeanstalk team at AWS re:Invent 2013: [slideshare](http://www.slideshare.net/AmazonWebServices/aws-elastic-beanstalk-under-the-hood-dmg301-aws-reinvent-2013-28428616) and [video (starting at 27:46)](http://www.youtube.com/watch?v=U06-QLd4FL4)
113
+
114
+ [Deploy Service by EbDeployer](http://www.thoughtworks.com/mingle/infrastructure/2015/06/01/deploy-service-by-ebdeployer.html)
115
+
116
+ [Rails 3/4 Support](https://github.com/ThoughtWorksStudios/eb_deployer/wiki/Rails-3-Support)
117
+
118
+ [EbDeployer environment](https://github.com/ThoughtWorksStudios/eb_deployer/wiki/EbDeployer-environment)
119
+
120
+ [Introduction to EbDeployer](https://www.thoughtworks.com/mingle/scaling/2014/06/13/introduction-to-eb-deployer.html)
121
+
122
+ [Papertrail Solution for Rails Applications on ElasticBeanstalk
123
+ ](http://www.thoughtworks.com/mingle/infrastructure/2015/06/10/simple-solution-for-papertrail-on-elasticbeanstalk.html)
124
+
125
+ [Elastic Beanstalk Tips and Tricks](https://github.com/ThoughtWorksStudios/eb_deployer/wiki/Elastic-Beanstalk-Tips-and-Tricks) (* recommended to read for new Elastic Beanstalk users )
126
+
127
+ ## Contributing
128
+
129
+ 1. Fork it
130
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
131
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
132
+ 4. Push to the branch (`git push origin my-new-feature`)
133
+ 5. Create new Pull Request
134
+
135
+
136
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ThoughtWorksStudios/eb_deployer/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.libs << "lib"
8
+ t.test_files = FileList['test/*test.rb']
9
+ t.verbose = true
10
+ end
11
+
12
+ task :default => :test
data/TODOS.md ADDED
@@ -0,0 +1,11 @@
1
+ * Support warmup_script option, which runs after smoke test to enhance smoothness of DNS switching in Blue Green deployment.
2
+ * Wait for all auto scaling group to reach MIN size before running smoke tests in Blue Green deployment. This will make sure DNS switching not generating 50x error under big load, even without warmup steps.
3
+ * Refactoring: extract Config class wrapping config defaut and merging logic.
4
+ * Make clear solution_stack is a creation only option in document
5
+ * Updating an EB environment with a different solution_stack should give warning
6
+ * Remove all old environment settings to keep settings always sync up
7
+ * Make it possible to provide an environment specific components settings
8
+ * Support smoke_test_script option
9
+ * Document for how to use components
10
+ * Document for how to use inactive-settings
11
+ * Support bucket folders for different environments (e.g. tworker/dev,tworker/ci)
data/bin/eb_deploy ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ git_path = File.join(File.expand_path('../..', __FILE__), '.git')
4
+
5
+ if File.exists?(git_path)
6
+ lib_path = File.expand_path('../../lib', __FILE__)
7
+ $:.unshift(lib_path)
8
+ end
9
+
10
+ STDOUT.sync = true # Forces output after every line.
11
+
12
+ require 'eb_deployer'
13
+ EbDeployer.cli
@@ -0,0 +1,22 @@
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", "xli"]
6
+ gem.email = ["alex.hal9000@gmail.com", "sudhindra.r.rao@gmail.com", 'swing1979@gmail.com']
7
+ gem.description = %q{For automating Blue-Green deployment flows on Elastic Beanstalk.}
8
+ gem.summary = %q{Low friction deployments should be a breeze. Elastic Beanstalk provides a great foundation for performing Blue-Green deployments, and EbDeployer add a missing top to automate the whole flow out of the box.}
9
+ gem.homepage = "https://github.com/ThoughtWorksStudios/eb_deployer"
10
+ gem.license = 'MIT'
11
+
12
+ gem.add_runtime_dependency 'aws-sdk-cloudformation', '~> 1.4', '>= 1.76.0'
13
+ gem.add_runtime_dependency 'aws-sdk-elasticbeanstalk', '~> 1.52', '~> 1.54.0'
14
+ gem.add_runtime_dependency 'aws-sdk-s3', '~> 1.117', '~> 1.119.0'
15
+
16
+ gem.files = `git ls-files`.split($\).reject {|f| f =~ /^samples\// }
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.name = "eb_deployer_updated"
20
+ gem.require_paths = ["lib"]
21
+ gem.version = EbDeployer::VERSION
22
+ end
@@ -0,0 +1,96 @@
1
+ require 'yaml'
2
+ module EbDeployer
3
+ class Application
4
+ attr_reader :name
5
+
6
+ def initialize(name, eb_driver, s3_driver, bucket = nil)
7
+ @name = name
8
+ @eb_driver = eb_driver
9
+ @s3_driver = s3_driver
10
+ @bucket = bucket || @name
11
+ raise "application name can only contain any combination of uppercase letters, lowercase letters, numbers, dashes (-)" unless @name =~ /^[a-zA-Z0-9.-]+$/
12
+ end
13
+
14
+ def create_version(version_label, package)
15
+ create_application_if_not_exists
16
+
17
+ source_bundle = if File.exist?(package)
18
+ if File.extname(package) == '.yml'
19
+ YAML.load(File.read(package))
20
+ else
21
+ package = Package.new(package, @bucket + ".packages", @s3_driver)
22
+ package.upload
23
+ package.source_bundle
24
+ end
25
+ elsif package =~ /:/
26
+ bucket, obj_key = package.split(':')
27
+ {'s3_bucket' => bucket, 's3_key' => obj_key}
28
+ else
29
+ raise "Neither the file exists nor it is a valid s3 url: #{package.inspect}"
30
+ end
31
+
32
+ unless @eb_driver.application_version_labels(@name).include?(version_label)
33
+ log("Create application version with label #{version_label}")
34
+ @eb_driver.create_application_version(@name, version_label, source_bundle)
35
+ end
36
+ end
37
+
38
+ def delete(env_name_prefix)
39
+ if @eb_driver.application_exists?(@name)
40
+ available_envs = @eb_driver.environment_names_for_application(@name).select do |name|
41
+ name =~ /^#{env_name_prefix}-/
42
+ end
43
+
44
+ if available_envs.empty?
45
+ log("Environment #{env_name_prefix.inspect} does not exist in application #{@name.inspect}. Skipping delete.")
46
+ return
47
+ end
48
+
49
+ available_envs.each do |env|
50
+ log("Terminating environment #{env}")
51
+ @eb_driver.delete_environment(@name, env)
52
+ end
53
+ end
54
+ end
55
+
56
+ def versions
57
+ @eb_driver.application_versions(@name).map do |apv|
58
+ {
59
+ :version => apv[:version_label],
60
+ :date_created => apv[:date_created],
61
+ :date_updated => apv[:date_updated]
62
+ }
63
+ end
64
+ end
65
+
66
+ def remove(versions, delete_from_s3)
67
+ versions.each do |version|
68
+ begin
69
+ log("Removing #{version}")
70
+ @eb_driver.delete_application_version(@name, version, delete_from_s3)
71
+ rescue Aws::ElasticBeanstalk::Errors::SourceBundleDeletionFailure => e
72
+ log(e.message)
73
+ rescue Aws::ElasticBeanstalk::Errors::OperationInProgressFailure => e
74
+ log(e.message)
75
+ end
76
+ end
77
+ end
78
+
79
+ def clean_versions(version_prefix, retentions)
80
+ VersionCleaner.new(self, retentions).clean(version_prefix)
81
+ end
82
+
83
+ private
84
+
85
+ def create_application_if_not_exists
86
+ unless @eb_driver.application_exists?(@name)
87
+ log("Creating application")
88
+ @eb_driver.create_application(@name)
89
+ end
90
+ end
91
+
92
+ def log(msg)
93
+ puts "[#{Time.now.utc}][application:#{@name}] #{msg}"
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,158 @@
1
+ module EbDeployer
2
+ module AWSDriver
3
+ class Beanstalk
4
+ include Utils
5
+ attr_reader :client
6
+
7
+ def initialize(client=Aws::ElasticBeanstalk::Client.new)
8
+ @client = client
9
+ end
10
+
11
+ def create_application(app)
12
+ @client.create_application(:application_name => app)
13
+ end
14
+
15
+ def delete_application(app)
16
+ @client.delete_application(:application_name => app)
17
+ end
18
+
19
+ def application_exists?(app)
20
+ @client.describe_applications(:application_names => [app])[:applications].any?
21
+ end
22
+
23
+ def update_environment_settings(app, env, settings)
24
+ env_id = convert_env_name_to_id(app, [env]).first
25
+ @client.update_environment(:environment_id => env_id, :option_settings => settings)
26
+ end
27
+
28
+ def update_environment(app_name, env_name, version, tier, settings, template_name)
29
+ env_id = convert_env_name_to_id(app_name, [env_name]).first
30
+ request = reject_nil({
31
+ :environment_id => env_id,
32
+ :version_label => version,
33
+ :option_settings => settings,
34
+ :tier => environment_tier(tier),
35
+ :template_name => template_name
36
+ })
37
+ @client.update_environment(request)
38
+ end
39
+
40
+ def environment_exists?(app_name, env_name)
41
+ alive_envs(app_name, [env_name]).any?
42
+ end
43
+
44
+ def environment_names_for_application(app_name)
45
+ alive_envs(app_name).collect { |env| env[:environment_name] }
46
+ end
47
+
48
+ def create_environment(app_name, env_name, stack_name, cname_prefix, version, tier, tags, settings, template_name)
49
+ request = reject_nil({
50
+ :application_name => app_name,
51
+ :environment_name => env_name,
52
+ :solution_stack_name => stack_name,
53
+ :version_label => version,
54
+ :option_settings => settings,
55
+ :tier => environment_tier(tier),
56
+ :cname_prefix => cname_prefix,
57
+ :tags => tags,
58
+ :template_name => template_name
59
+ })
60
+ @client.create_environment(request)
61
+ end
62
+
63
+ def delete_environment(app_name, env_name)
64
+ @client.terminate_environment(:environment_name => env_name)
65
+ end
66
+
67
+ def delete_application_version(app_name, version, delete_source_bundle)
68
+ request = {
69
+ :application_name => app_name,
70
+ :version_label => version,
71
+ :delete_source_bundle => delete_source_bundle
72
+ }
73
+ @client.delete_application_version(request)
74
+ end
75
+
76
+ def create_application_version(app_name, version_label, source_bundle)
77
+ @client.create_application_version(:application_name => app_name,
78
+ :source_bundle => source_bundle,
79
+ :version_label => version_label)
80
+ end
81
+
82
+ def application_version_labels(app_name)
83
+ application_versions(app_name).map { |apv| apv[:version_label] }
84
+ end
85
+
86
+ def application_versions(app_name)
87
+ request = { :application_name => app_name }
88
+ @client.describe_application_versions(request)[:application_versions]
89
+ end
90
+
91
+ def fetch_events(app_name, env_name, params, &block)
92
+ response = @client.describe_events(params.merge(:application_name => app_name,
93
+ :environment_name => env_name))
94
+ return [response[:events], response[:next_token]]
95
+ end
96
+
97
+ def environment_cname_prefix(app_name, env_name)
98
+ cname = environment_cname(app_name, env_name)
99
+ if cname =~ /^([^\.]+)(?:\.(?:[a-z0-9\-]+))?\.elasticbeanstalk\.com/i
100
+ $1
101
+ end
102
+ end
103
+
104
+ def environment_cname(app_name, env_name)
105
+ get_environment_attribute(app_name, env_name, :cname)
106
+ end
107
+
108
+ def environment_health_state(app_name, env_name)
109
+ get_environment_attribute(app_name, env_name, :health)
110
+ end
111
+
112
+ def environment_status(app_name, env_name)
113
+ get_environment_attribute(app_name, env_name, :status)
114
+ end
115
+
116
+ def environment_verion_label(app_name, env_name)
117
+ get_environment_attribute(app_name, env_name, :version_label)
118
+ end
119
+
120
+ def environment_swap_cname(app_name, env1, env2)
121
+ env1_id, env2_id = convert_env_name_to_id(app_name, [env1, env2])
122
+ @client.swap_environment_cnames(:source_environment_id => env1_id,
123
+ :destination_environment_id => env2_id)
124
+ end
125
+
126
+ def list_solution_stack_names
127
+ @client.list_available_solution_stacks[:solution_stacks]
128
+ end
129
+
130
+ private
131
+
132
+ TIERS = [
133
+ {:name=>"Worker", :type=>"SQS/HTTP"},
134
+ {:name=>"WebServer", :type=>"Standard"}
135
+ ]
136
+
137
+ def get_environment_attribute(app_name, env_name, attribute)
138
+ env = alive_envs(app_name, [env_name]).first
139
+ env && env[attribute]
140
+ end
141
+
142
+ def environment_tier(name)
143
+ TIERS.find {|t| t[:name].downcase == name.downcase} || raise("No tier found with name #{name.inspect}")
144
+ end
145
+
146
+ def convert_env_name_to_id(app_name, env_names)
147
+ envs = alive_envs(app_name, env_names)
148
+ envs.map { |env| env[:environment_id] }
149
+ end
150
+
151
+ def alive_envs(app_name, env_names=[])
152
+ envs = @client.describe_environments(:application_name => app_name, :environment_names => env_names)[:environments]
153
+
154
+ envs.select {|e| e[:status] != 'Terminated' }
155
+ end
156
+ end
157
+ end
158
+ end