momentum 0.0.3
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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +92 -0
- data/Rakefile +1 -0
- data/lib/momentum/opsworks.rb +89 -0
- data/lib/momentum/railtie.rb +14 -0
- data/lib/momentum/tasks.rb +19 -0
- data/lib/momentum/version.rb +3 -0
- data/lib/momentum.rb +21 -0
- data/lib/tasks/init.rake +6 -0
- data/lib/tasks/librarian.rake +28 -0
- data/lib/tasks/ow-config.rake +26 -0
- data/lib/tasks/ow-console.rake +26 -0
- data/lib/tasks/ow-cookbooks.rake +66 -0
- data/lib/tasks/ow-deploy.rake +21 -0
- data/momentum.gemspec +26 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e6d9f5cfb124f1061f031e1830abf34dc1c9dab3
|
4
|
+
data.tar.gz: 85c8676d3ca113bda88117ec61d6eda40260316a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3a4991c287f2fe675ec3293040a2adf55260420d1c3ae3ed859f53be884b400572c0475facd367ef764c67d4b036ac6a997f038a9c705dcf3fa37db793732527
|
7
|
+
data.tar.gz: 0f99656306f1ce62477c222088d6cad42e4a0de76655ccab35f5fcd62fba1b3ebc679a5e36f2d833f175fa94fb5ecd8481eae6ce95bbcba1ab38bd3d5b00ff3c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Artsy
|
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,92 @@
|
|
1
|
+
# Momentum
|
2
|
+
|
3
|
+
Shared utilities for managing and deploying OpsWorks apps at Artsy.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile, probably in the `:development` group:
|
9
|
+
|
10
|
+
gem 'momentum', github: 'artsy/momentum', require: false
|
11
|
+
|
12
|
+
In your application's Rakefile, add this line above the `load_tasks` command:
|
13
|
+
|
14
|
+
begin
|
15
|
+
require 'momentum' # necessary b/c tasks from gems in :development group aren't loaded automatically
|
16
|
+
Momentum.configure do |conf|
|
17
|
+
conf[:app_base_name] = 'your_app_name'
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
# momentum should only be installed in development
|
21
|
+
end
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
$ gem install librarian-chef # ideally this would be in the bundle, but has conflicts
|
27
|
+
$ bundle exec rake momentum:init
|
28
|
+
|
29
|
+
|
30
|
+
## Rake Tasks
|
31
|
+
|
32
|
+
This gem adds a few useful rake tasks to your project. In general, the `aws_id` and `aws_secret` arguments are taken from `AWS_ID` and `AWS_SECRET` ENV variables. The `to` argument can refer to an environment or developer (e.g., _joey_ in the case of _reflection-joey_, or _staging_ in the case of _gravity-staging_). It's assumed that this value can be appended to the `app_base_name` to form the stack name.
|
33
|
+
|
34
|
+
### momentum:init
|
35
|
+
|
36
|
+
Initialize a default librarian-chef config.
|
37
|
+
|
38
|
+
### ow:config[to,aws_id,aws_secret]
|
39
|
+
|
40
|
+
Print the custom configuration values for the given stack. E.g.:
|
41
|
+
|
42
|
+
bundle exec rake ow:config[joey]
|
43
|
+
|
44
|
+
### ow:config:from_env[to,aws_id,aws_secret]
|
45
|
+
|
46
|
+
Add the given stack's custom configuration values to the current task's ENV. Can be prepended to other rake tasks that depend on the ENV, e.g.:
|
47
|
+
|
48
|
+
bundle exec rake ow:config:from_env[production] some:migration
|
49
|
+
|
50
|
+
### ow:console[to,env,aws_id,aws_secret]
|
51
|
+
|
52
|
+
Start a rails console on the given remote OpsWorks stack. Chooses an instance of the _rails-app_ layer by default, or the configured `rails_console_layer` if provided. E.g.:
|
53
|
+
|
54
|
+
bundle exec rake ow:console[production]
|
55
|
+
|
56
|
+
For stacks with labels not matching the Rails environment (e.g., _reflection-joey_), provide a 2nd argument with the desired environment:
|
57
|
+
|
58
|
+
bundle exec rake ow:console[joey,staging]
|
59
|
+
|
60
|
+
### ow:cookbooks:update[to,aws_id,aws_secret]
|
61
|
+
|
62
|
+
Zip, upload, and propagate custom cookbooks to the given stack. Or, more concisely:
|
63
|
+
|
64
|
+
bundle exec rake ow:cookbooks:update[staging]
|
65
|
+
# or just:
|
66
|
+
bundle exec rake ow:cookbooks:update:staging
|
67
|
+
|
68
|
+
### ow:deploy[to,aws_id,aws_secret]
|
69
|
+
|
70
|
+
Trigger an OpsWorks deploy to the given stack. By default, deploys app to all running instances of the _rails-app_ layer, or the list configured in `app_layers`. E.g.:
|
71
|
+
|
72
|
+
bundle exec rake ow:deploy[staging]
|
73
|
+
# or just:
|
74
|
+
bundle exec rake ow:deploy:staging
|
75
|
+
|
76
|
+
## Configuration:
|
77
|
+
|
78
|
+
* **app_base_name** - Your app's name. Stacks are assumed to be named like _appbasename-env_ (e.g., _gravity-staging_ or _reflection-joey_).
|
79
|
+
* **app_layers** - Array of OpsWorks layer names to which this rails app should be deployed. Default: `['rails-app']`
|
80
|
+
* **cookbooks_install_path** - Local path where librarian-chef will install cookbooks. Default: _tmp/cookbooks_
|
81
|
+
* **custom_cookbooks_bucket** - Bucket to which custom cookbooks are uploaded. Default: _artsy-cookbooks_
|
82
|
+
* **rails_console_layer** - The OpsWorks layer used for SSH-ing and starting a rails console. Default: _rails-app_
|
83
|
+
|
84
|
+
|
85
|
+
## To Do
|
86
|
+
|
87
|
+
* git/branch helpers
|
88
|
+
* Integrate librarian-chef as legit dependency once rails/chef conflicts resolved
|
89
|
+
|
90
|
+
|
91
|
+
© 2014 [Artsy](http://artsy.net). See [LICENSE](LICENSE.txt) for details.
|
92
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Momentum::OpsWorks
|
2
|
+
|
3
|
+
def self.client(aws_id, aws_secret)
|
4
|
+
raise "You must specify aws_id and aws_secret!" unless aws_id.present? && aws_secret.present?
|
5
|
+
require 'aws-sdk'
|
6
|
+
AWS::OpsWorks::Client.new(access_key_id: aws_id, secret_access_key: aws_secret)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.get_stack(client, stack_name)
|
10
|
+
client.describe_stacks[:stacks].detect { |k, v| k[:name] == stack_name }.tap do |stack|
|
11
|
+
raise "No #{stack_name} stack found!" unless stack
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_app(client, stack, app_name)
|
16
|
+
client.describe_apps(stack_id: stack[:stack_id])[:apps].detect { |a| a[:name] == app_name }
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.get_layers(client, stack, layer_names)
|
20
|
+
client.describe_layers(stack_id: stack[:stack_id])[:layers].select { |l| layer_names.include?(l[:shortname]) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.get_online_instance_ids(client, query = {})
|
24
|
+
get_online_instances(client, query).map { |i| i[:instance_id] }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.get_online_instances(client, query = {})
|
28
|
+
client.describe_instances(query)[:instances].select { |i| i[:status] == 'online' }
|
29
|
+
end
|
30
|
+
|
31
|
+
class Config
|
32
|
+
|
33
|
+
def self.from_stack(client, stack_name, app_name = Momentum.config[:app_base_name])
|
34
|
+
@@configs ||= {}
|
35
|
+
@@configs[[stack_name, app_name]] ||= load_from_stack(client, stack_name, app_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def self.load_from_stack(client, stack_name, app_name)
|
41
|
+
stack = Momentum::OpsWorks.get_stack(client, stack_name)
|
42
|
+
JSON.parse(stack[:custom_json])["custom_env"][app_name].tap do |config|
|
43
|
+
# Custom config from OpsWorks doesn't include RAILS_ENV, so add it.
|
44
|
+
config['RAILS_ENV'] = Momentum::OpsWorks.get_app(client, stack, app_name)[:attributes]['RailsEnv']
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
class Deployer
|
52
|
+
TIMEOUT = 15 * 60 # wait up to 15 minutes
|
53
|
+
|
54
|
+
def initialize(aws_id, aws_secret)
|
55
|
+
@ow = Momentum::OpsWorks.client(aws_id, aws_secret)
|
56
|
+
end
|
57
|
+
|
58
|
+
def deploy!(stack_name, app_name = Momentum.config[:app_base_name])
|
59
|
+
stack = Momentum::OpsWorks.get_stack(@ow, stack_name)
|
60
|
+
app = Momentum::OpsWorks.get_app(@ow, stack, app_name)
|
61
|
+
layers = Momentum::OpsWorks.get_layers(@ow, stack, Momentum.config[:app_layers])
|
62
|
+
instance_ids = layers.inject([]) { |ids, l| ids + Momentum::OpsWorks.get_online_instance_ids(@ow, layer_id: l[:layer_id]) }
|
63
|
+
raise 'No online instances found!' if instance_ids.empty?
|
64
|
+
@ow.create_deployment(
|
65
|
+
stack_id: stack[:stack_id],
|
66
|
+
app_id: app[:app_id],
|
67
|
+
command: { name: 'deploy' },
|
68
|
+
instance_ids: instance_ids
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def wait_for_success!(deployment, timeout = TIMEOUT)
|
73
|
+
Timeout.timeout(timeout) do
|
74
|
+
status = @ow.describe_deployments(deployment_ids: [deployment[:deployment_id]])[:deployments].first[:status]
|
75
|
+
$stderr.puts 'Polling deploy status...'
|
76
|
+
while status == 'running'
|
77
|
+
sleep 10
|
78
|
+
status = @ow.describe_deployments(deployment_ids: [deployment[:deployment_id]])[:deployments].first[:status]
|
79
|
+
$stderr.print '.'
|
80
|
+
end
|
81
|
+
raise "Deploy failed (status: #{status})!" unless status == 'successful'
|
82
|
+
end
|
83
|
+
$stderr.puts 'Success!'
|
84
|
+
rescue Timeout::Error
|
85
|
+
raise "Timed out waiting for deploy to succeed after #{timeout} seconds."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Momentum::Railtie < ::Rails::Railtie
|
2
|
+
|
3
|
+
railtie_name :momentum
|
4
|
+
|
5
|
+
rake_tasks do
|
6
|
+
load 'tasks/init.rake'
|
7
|
+
load 'tasks/librarian.rake'
|
8
|
+
load 'tasks/ow-config.rake'
|
9
|
+
load 'tasks/ow-console.rake'
|
10
|
+
load 'tasks/ow-cookbooks.rake'
|
11
|
+
load 'tasks/ow-deploy.rake'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Helpers for rake tasks
|
2
|
+
|
3
|
+
def require_credentials!(args)
|
4
|
+
args.with_defaults aws_id: ENV['AWS_ID'], aws_secret: ENV['AWS_SECRET'], to: ENV['RAILS_ENV']
|
5
|
+
raise "Must specify target environment (e.g., staging)!" unless args[:to]
|
6
|
+
raise "Must set aws_id and aws_secret!" unless args[:aws_id] && args[:aws_secret]
|
7
|
+
end
|
8
|
+
|
9
|
+
def cookbooks_s3_key(to)
|
10
|
+
"#{stack_name(to)}.zip"
|
11
|
+
end
|
12
|
+
|
13
|
+
def stack_name(to)
|
14
|
+
"#{Momentum.config[:app_base_name]}-#{to}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def cookbooks_zip
|
18
|
+
"#{Momentum.config[:cookbooks_install_path]}.zip"
|
19
|
+
end
|
data/lib/momentum.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "momentum/version"
|
2
|
+
require 'momentum/railtie' if defined?(::Rails)
|
3
|
+
|
4
|
+
module Momentum
|
5
|
+
|
6
|
+
DEFAULT_CONFIG = {
|
7
|
+
cookbooks_install_path: 'tmp/cookbooks',
|
8
|
+
custom_cookbooks_bucket: 'artsy-cookbooks',
|
9
|
+
rails_console_layer: 'rails-app',
|
10
|
+
app_layers: ['rails-app']
|
11
|
+
}
|
12
|
+
|
13
|
+
def self.config
|
14
|
+
@@config ||= DEFAULT_CONFIG.dup
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.configure(&block)
|
18
|
+
yield self.config
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/tasks/init.rake
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
namespace :librarian do
|
2
|
+
|
3
|
+
LIBRARIAN_CONFIG = <<-EOF
|
4
|
+
---
|
5
|
+
LIBRARIAN_CHEF_PATH: #{Momentum.config[:cookbooks_install_path]}
|
6
|
+
LIBRARIAN_CHEF_INSTALL__STRIP_DOT_GIT: '1'
|
7
|
+
EOF
|
8
|
+
|
9
|
+
task :config do
|
10
|
+
FileUtils.mkdir_p './.librarian/chef'
|
11
|
+
File.open('./.librarian/chef/config', 'w+') do |f|
|
12
|
+
f.write(LIBRARIAN_CONFIG)
|
13
|
+
end
|
14
|
+
$stderr.puts "Wrote .librarian/chef/config"
|
15
|
+
end
|
16
|
+
|
17
|
+
task :init => :require do
|
18
|
+
# librarian-chef and rails declare incompatible json dependencies,
|
19
|
+
# so librarian-chef must be installed but can't be in the bundle
|
20
|
+
Bundler.with_clean_env do
|
21
|
+
system "librarian-chef init"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
task :require do
|
26
|
+
raise "librarian-chef must be installed!" if `which librarian-chef`.empty?
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
namespace :ow do
|
2
|
+
|
3
|
+
require 'momentum/tasks'
|
4
|
+
|
5
|
+
desc "Print current configuration values for given stack."
|
6
|
+
task :config, [:to, :aws_id, :aws_secret] do |t, args|
|
7
|
+
require_credentials!(args)
|
8
|
+
ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
|
9
|
+
Momentum::OpsWorks::Config.from_stack(ow, stack_name(args[:to])).each do |k, v|
|
10
|
+
puts "#{k}: #{v}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :config do
|
15
|
+
desc "Set configuration values from OpsWorks on the current environment. Can be chained to other tasks that need the ENV."
|
16
|
+
task :from_env, [:to, :aws_id, :aws_secret] do |t, args|
|
17
|
+
require_credentials!(args)
|
18
|
+
ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
|
19
|
+
Momentum::OpsWorks::Config.from_stack(ow, stack_name(args[:to])).each do |k, v|
|
20
|
+
ENV[k] = v.to_s
|
21
|
+
end
|
22
|
+
@ow_config_from_env = true # allow chained tasks to raise an error unless this is set
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
namespace :ow do
|
2
|
+
|
3
|
+
require 'momentum/opsworks'
|
4
|
+
require 'momentum/tasks'
|
5
|
+
|
6
|
+
desc "Open a Rails console on the given remote OpsWorks stack (uses AWS_USER as SSH username or falls back to local username)."
|
7
|
+
task :console, [:to, :env, :aws_id, :aws_secret] do |t, args|
|
8
|
+
require_credentials!(args)
|
9
|
+
ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
|
10
|
+
name = stack_name(args[:to])
|
11
|
+
stack = Momentum::OpsWorks.get_stack(ow, name)
|
12
|
+
layer = ow.describe_layers(stack_id: stack[:stack_id])[:layers].detect { |l| l[:shortname] == Momentum.config[:rails_console_layer] }
|
13
|
+
instance = Momentum::OpsWorks.get_online_instances(ow, layer_id: layer[:layer_id]).sample
|
14
|
+
raise "No online #{Momentum.config[:rails_console_layer]} instances found for #{name} stack!" unless instance
|
15
|
+
|
16
|
+
$stderr.puts "Starting remote console... (use Ctrl-D to exit cleanly)"
|
17
|
+
sh [
|
18
|
+
'ssh -t',
|
19
|
+
(['-i', ENV['AWS_PUBLICKEY']] if ENV['AWS_PUBLICKEY']),
|
20
|
+
(['-l', ENV['AWS_USER']] if ENV['AWS_USER']),
|
21
|
+
instance[:public_dns],
|
22
|
+
"'sudo su deploy --session-command=\"cd /srv/www/#{Momentum.config[:app_base_name]}/current && RAILS_ENV=#{args[:env] || args[:to]} bundle exec rails console\"'"
|
23
|
+
].compact.flatten.join(' ')
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
namespace :ow do
|
2
|
+
namespace :cookbooks do
|
3
|
+
|
4
|
+
require 'momentum/opsworks'
|
5
|
+
require 'momentum/tasks'
|
6
|
+
|
7
|
+
# TODO add dependency on librarian-chef once chef/json conflict resolved
|
8
|
+
# desc "Run librarian-chef install"
|
9
|
+
# task :install do
|
10
|
+
# `librarian-chef install`
|
11
|
+
# end
|
12
|
+
|
13
|
+
desc "Zip the #{Momentum.config[:cookbooks_install_path]} directory into #{Momentum.config[:cookbooks_install_path]}.zip"
|
14
|
+
task :zip do
|
15
|
+
raise "No cookbooks found at #{Momentum.config[:cookbooks_install_path]}! Run librarian-chef install." unless File.exists?(Momentum.config[:cookbooks_install_path])
|
16
|
+
dir = File.dirname(Momentum.config[:cookbooks_install_path])
|
17
|
+
base = File.basename(Momentum.config[:cookbooks_install_path])
|
18
|
+
system "rm -f #{cookbooks_zip} && pushd #{dir} && zip -r #{base} #{base} && popd"
|
19
|
+
$stderr.puts "Zipped cookbooks to #{cookbooks_zip}"
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Upload custom cookbooks from #{cookbooks_zip} to S3 (at bucket/appname-env.zip)."
|
23
|
+
task :upload, [:to, :aws_id, :aws_secret] => [:require_app_base_name] do |t, args|
|
24
|
+
require_credentials!(args)
|
25
|
+
require 'aws-sdk'
|
26
|
+
AWS.config(access_key_id: args[:aws_id], secret_access_key: args[:aws_secret])
|
27
|
+
|
28
|
+
key = cookbooks_s3_key(args[:to])
|
29
|
+
File.open(cookbooks_zip) do |zip|
|
30
|
+
AWS::S3.new.client.put_object bucket_name: Momentum.config[:custom_cookbooks_bucket], key: key, data: zip
|
31
|
+
end
|
32
|
+
$stderr.puts "Uploaded cookbooks.zip to #{Momentum.config[:custom_cookbooks_bucket]}/#{key}."
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Install, zip and upload custom cookbooks, then trigger update_custom_cookbooks command."
|
36
|
+
task :update, [:to, :aws_id, :aws_secret] => [:require_app_base_name, :zip, :upload] do |t, args|
|
37
|
+
require_credentials!(args)
|
38
|
+
|
39
|
+
ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
|
40
|
+
stack = Momentum::OpsWorks.get_stack(ow, stack_name(args[:to]))
|
41
|
+
instance_ids = Momentum::OpsWorks.get_online_instance_ids(ow, stack_id: stack[:stack_id])
|
42
|
+
if instance_ids.any?
|
43
|
+
ow.create_deployment(
|
44
|
+
stack_id: stack[:stack_id],
|
45
|
+
command: {name: 'update_custom_cookbooks'},
|
46
|
+
instance_ids: instance_ids
|
47
|
+
)
|
48
|
+
$stderr.puts "Triggered 'update_custom_cookbooks' command for #{stack[:name]}... (it might take a few moments)."
|
49
|
+
else
|
50
|
+
$stderr.puts "No online instances found."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
namespace :update do
|
55
|
+
%w{staging production}.each do |env|
|
56
|
+
desc "Zip, upload, and propagate custom OpsWorks cookbooks to the #{env} stack."
|
57
|
+
task(env.to_sym) { Rake::Task['ow:cookbooks:update'].invoke(env) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
task :require_app_base_name do
|
62
|
+
raise "An app_base_name must be configured!" unless Momentum.config[:app_base_name]
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
namespace :ow do
|
2
|
+
|
3
|
+
require 'momentum/tasks'
|
4
|
+
|
5
|
+
namespace :deploy do
|
6
|
+
%w{staging production}.each do |env|
|
7
|
+
desc "Deploy the #{Momentum.config[:app_base_name]} to the #{stack_name(env)} OpsWorks stack."
|
8
|
+
task(env.to_sym) { Rake::Task['ow:deploy'].invoke(env) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Deploy to the given OpsWorks stack."
|
13
|
+
task :deploy, [:to, :aws_id, :aws_secret] do |t, args|
|
14
|
+
require_credentials!(args)
|
15
|
+
deployer = Momentum::OpsWorks::Deployer.new(args[:aws_id], args[:aws_secret])
|
16
|
+
name = stack_name(args[:to])
|
17
|
+
deployment = deployer.deploy!(name)
|
18
|
+
$stderr.puts "Triggered deployment #{deployment[:deployment_id]} to #{name}..."
|
19
|
+
deployer.wait_for_success!(deployment)
|
20
|
+
end
|
21
|
+
end
|
data/momentum.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'momentum/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "momentum"
|
8
|
+
spec.version = Momentum::VERSION
|
9
|
+
spec.authors = ["Joey Aghion"]
|
10
|
+
spec.email = ["joey@aghion.com"]
|
11
|
+
spec.description = %q{Utilities for working with OpsWorks apps in the style of Artsy Engineering.}
|
12
|
+
spec.summary = %q{Utilities for working with OpsWorks apps in the style of Artsy Engineering.}
|
13
|
+
spec.homepage = "https://github.com/artsy/momentum"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "aws-sdk", "~> 1.30"
|
22
|
+
# spec.add_dependency "librarian-chef" # rails/chef require incompatible json versions
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: momentum
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joey Aghion
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.30'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.30'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Utilities for working with OpsWorks apps in the style of Artsy Engineering.
|
56
|
+
email:
|
57
|
+
- joey@aghion.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- lib/momentum.rb
|
68
|
+
- lib/momentum/opsworks.rb
|
69
|
+
- lib/momentum/railtie.rb
|
70
|
+
- lib/momentum/tasks.rb
|
71
|
+
- lib/momentum/version.rb
|
72
|
+
- lib/tasks/init.rake
|
73
|
+
- lib/tasks/librarian.rake
|
74
|
+
- lib/tasks/ow-config.rake
|
75
|
+
- lib/tasks/ow-console.rake
|
76
|
+
- lib/tasks/ow-cookbooks.rake
|
77
|
+
- lib/tasks/ow-deploy.rake
|
78
|
+
- momentum.gemspec
|
79
|
+
homepage: https://github.com/artsy/momentum
|
80
|
+
licenses:
|
81
|
+
- MIT
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 2.1.11
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: Utilities for working with OpsWorks apps in the style of Artsy Engineering.
|
103
|
+
test_files: []
|