opsicle 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZDhlY2I5Nzg3ZjU2OTMyOGZlMjgxMzM3ZjMzOGQ1YWE5MmNjNTZhNg==
4
+ ZGZlNmRhOWYwZGQwYWNmYmUwZDc1NDUwMDkyNjBlNzYyZDk3NjU3OA==
5
5
  data.tar.gz: !binary |-
6
- ZjEyMTIwODVjOGQyM2E1ZTFlZjg3NzU5OGJkNTlmYThmMjA2NGNhMA==
6
+ NTA5Zjk5Y2E1OWU3OTc2YjQ0MDZmY2ZjODJhYmM0ZmYzMDE1NjY2Yw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OWRkNDRiMmUxMzdiMmE4MGUyY2JiNzc0ZDY3YzcyZjdlYmJmM2RlNGZmZDVi
10
- MzQ4ZjdjMDFkMjQ4MTY4ODRkNWQ3YTE2NDMzMTQ2MDA2NTY5ZmIwZmQ1YTNj
11
- ZWFjYTQxYmY3YTQ0ZjQ3MTA3NWUxYzcxM2Y5ZTQyZTk5OTIxYzQ=
9
+ OTNjYmVmYzg2NzIzMTE2ZTA2MmEwMGEwNGZjMGMwMmI4OTkxNzgyZWM0OWQy
10
+ YWZlNzRhYmJjYjFhZWM0NjU0NDgxODk1ZmViM2E1YzEzYWRkNWQxYzU5MTlk
11
+ ZTg0M2U4YTM3NWUzNzFhNWIwNmI3NmVjMjQzZWNjMjU2MzhjMzM=
12
12
  data.tar.gz: !binary |-
13
- MjAzZjJkYzFlNjEwYjQzMjczM2I0MGY3OGQ1ZjgxZGExN2NiMmFlZGE2NmVj
14
- MGM3OWVlMjZlNmJiOTIyNjVhYTUyOWZlOTBkYTU0YjAxZmE0OTYzYjk2OTk2
15
- YTIxMTE1ZTQ4ZGY4MGI0MWRkOThiZTY2YzI2MjU0NTFlZDc0MTY=
13
+ YjAwMzVjZThkNDFiZTNhZGYxMTgwM2FiNDRjMjE0NTZhZGEyYmM0MjZmMDZi
14
+ YmNjOTc3NzQzNGZlNzU5ZDJkMjk3NjI3ZjUzOTNlNzdkOGU2ZDc5ZDUxMmNj
15
+ MzA2YmJlOTRkZDFjMTAyMmJhNGFiMTY3NzU0NGNjMDdkZTc5ZDc=
@@ -37,6 +37,7 @@ desc "Deploy your current app to the given environment stack"
37
37
  arg_name '<environment>'
38
38
  command :deploy do |c|
39
39
  c.switch [:b, :browser], :desc => "Open the OpsWorks deployments screen for this stack on deploy"
40
+ c.switch [:g, :migrate], :desc => "Deploy with migrations"
40
41
  c.switch [:m, :monitor], :desc => "Run the Stack Monitor on deploy", :default_value => true
41
42
  c.action do |global_options, options, args|
42
43
  raise ArgumentError, 'You must specify an environment' unless args.first
@@ -129,4 +130,27 @@ command 'chef-update' do |c|
129
130
  end
130
131
  end
131
132
 
133
+ desc "Execute arbitrary recipes on the Stack"
134
+ arg_name '<environment>'
135
+ arg_name '<recipe>'
136
+ command 'execute-recipes' do |c|
137
+ c.switch [:m, :monitor], :desc => "Run the Stack Monitor on deploy", :default_value => true
138
+ c.flag [:r, :recipes], :desc => 'The recipes to execute', :type => Array, :required => true
139
+ c.flag [:i, :instance_ids], :desc => 'The specific instances to execute recipes on', :type => Array
140
+ c.action do |global_options, options, args|
141
+ raise ArgumentError, "Environment is required" unless args.first
142
+
143
+ Opsicle::ExecuteRecipes.new(*args).execute global_options.merge(options)
144
+ end
145
+ end
146
+
147
+ desc "List all instances in the given environment stack"
148
+ arg_name '<environment>'
149
+ command :instances do |c|
150
+ c.action do |global_options, options, args|
151
+ raise ArgumentError, "Environment is required" unless args.first
152
+ Opsicle::ListInstances.new(args.first).execute global_options.merge options
153
+ end
154
+ end
155
+
132
156
  exit run(ARGV)
@@ -13,8 +13,10 @@ module Opsicle
13
13
  @s3 = AWS::S3.new
14
14
  end
15
15
 
16
- def run_command(command, options={})
17
- opsworks.create_deployment(command_options(command, options))
16
+ def run_command(command, command_args={}, options={})
17
+ opts = command_options(command, command_args, options)
18
+ Output.say_verbose "OpsWorks call: create_deployment(#{opts})"
19
+ opsworks.create_deployment(opts)
18
20
  end
19
21
 
20
22
  def api_call(command, options={})
@@ -25,8 +27,8 @@ module Opsicle
25
27
  "https://console.aws.amazon.com/opsworks/home?#/stack/#{@config.opsworks_config[:stack_id]}"
26
28
  end
27
29
 
28
- def command_options(command, options={})
29
- config.opsworks_config.merge(options).merge({ command: { name: command } })
30
+ def command_options(command, command_args={}, options={})
31
+ config.opsworks_config.merge(options).merge({ command: { name: command, args: command_args } })
30
32
  end
31
33
  private :command_options
32
34
 
@@ -2,6 +2,8 @@ require 'opsicle/client'
2
2
 
3
3
  require "opsicle/commands/deploy"
4
4
  require "opsicle/commands/chef_update"
5
+ require "opsicle/commands/execute_recipes"
5
6
  require "opsicle/commands/list"
7
+ require "opsicle/commands/list_instances"
6
8
  require "opsicle/commands/ssh"
7
9
  require "opsicle/commands/ssh_key"
@@ -1,9 +1,11 @@
1
1
  require 'opsicle/s3_bucket'
2
2
  require 'zlib'
3
3
  require 'archive/tar/minitar'
4
+ require "opsicle/deploy_helper"
4
5
 
5
6
  module Opsicle
6
7
  class ChefUpdate
8
+ include DeployHelper
7
9
  attr_reader :client
8
10
  attr_reader :tar_file
9
11
  attr_reader :stack
@@ -19,8 +21,8 @@ module Opsicle
19
21
  tar_cookbooks(options[:path])
20
22
  s3_upload(options[:"bucket-name"])
21
23
  cleanup_tar
22
- update_custom_cookbooks
23
- launch_stack_monitor(options)
24
+ response = update_custom_cookbooks
25
+ launch_stack_monitor(response, options)
24
26
  end
25
27
 
26
28
  private
@@ -44,11 +46,5 @@ module Opsicle
44
46
  Output.say "Starting OpsWorks Custom Cookboks Update..."
45
47
  client.run_command('update_custom_cookbooks')
46
48
  end
47
-
48
- def launch_stack_monitor(options)
49
- Output.say_verbose "Starting Stack Monitor..."
50
- @monitor = Opsicle::Monitor::App.new(@environment, options)
51
- @monitor.start
52
- end
53
49
  end
54
50
  end
@@ -1,5 +1,8 @@
1
+ require "opsicle/deploy_helper"
2
+
1
3
  module Opsicle
2
4
  class Deploy
5
+ include DeployHelper
3
6
  attr_reader :client
4
7
 
5
8
  def initialize(environment)
@@ -9,27 +12,14 @@ module Opsicle
9
12
 
10
13
  def execute(options={ monitor: true })
11
14
  Output.say "Starting OpsWorks deploy..."
12
- response = client.run_command('deploy')
13
-
14
- # Monitoring preferences
15
- if options[:browser]
16
- open_deploy(response[:deployment_id])
17
- elsif options[:monitor] # Default option
18
- Output.say_verbose "Starting Stack Monitor..."
19
- @monitor = Opsicle::Monitor::App.new(@environment, options)
20
- @monitor.start
21
- end
22
15
 
23
- end
16
+ #so this is how to format the command arguments:
17
+ #http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/OpsWorks/Client.html#create_deployment-instance_method
18
+ command_args = {}
19
+ command_args["migrate"] = [options[:migrate].to_s] if options[:migrate]
20
+ response = client.run_command('deploy', command_args)
24
21
 
25
- def open_deploy(deployment_id)
26
- if deployment_id
27
- command = "open 'https://console.aws.amazon.com/opsworks/home?#/stack/#{client.config.opsworks_config[:stack_id]}/deployments'"
28
- Output.say_verbose "Executing shell command: #{command}"
29
- %x(#{command})
30
- else
31
- Output.say "Deploy failed. No deployment_id was received from OpsWorks", :error
32
- end
22
+ launch_stack_monitor(response, options)
33
23
  end
34
24
  end
35
25
  end
@@ -0,0 +1,28 @@
1
+ require "opsicle/deploy_helper"
2
+
3
+ module Opsicle
4
+ class ExecuteRecipes
5
+ include DeployHelper
6
+ attr_reader :client, :recipes
7
+
8
+ def initialize(environment)
9
+ @environment = environment
10
+ @client = Client.new(environment)
11
+ end
12
+
13
+ def execute(options={ monitor: true })
14
+ Output.say "Starting OpsWorks chef run..."
15
+
16
+ #so this is how to format the command arguments:
17
+ #http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/OpsWorks/Client.html#create_deployment-instance_method
18
+ command_args = {}
19
+ command_args["recipes"] = options[:recipes]
20
+
21
+ command_opts = {}
22
+ command_opts["instance_ids"] = options[:instance_ids] if options[:instance_ids]
23
+
24
+ response = client.run_command('execute_recipes', command_args, command_opts)
25
+ launch_stack_monitor(response, options)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ require 'terminal-table'
2
+
3
+ module Opsicle
4
+ class ListInstances
5
+ attr_reader :client, :layers
6
+
7
+ def initialize(environment)
8
+ @client = Client.new(environment)
9
+ end
10
+
11
+ def execute(options={})
12
+ get_layers
13
+ print(get_instances)
14
+ end
15
+
16
+ def get_layers
17
+ @layers = client.api_call('describe_layers', stack_id: @client.config.opsworks_config[:stack_id])[:layers]
18
+ end
19
+
20
+ def get_instances
21
+ Opsicle::Instances.new(client).data
22
+ end
23
+
24
+ def print(instances)
25
+ puts Terminal::Table.new headings: ['Hostname', 'Layers', 'Status', 'Instance ID'], rows: instance_data(instances)
26
+ end
27
+
28
+ def instance_data(instances)
29
+ instances.map{|instance| [instance[:hostname], layer_names(instance), instance[:status], instance[:instance_id]] }
30
+ end
31
+
32
+ def layer_names(instance)
33
+ instance[:layer_ids].map{ |layer_id| layer_name(layer_id) }.join(" | ")
34
+ end
35
+
36
+ def layer_name(layer_id)
37
+ layers.detect{ |layer| layer[:layer_id] == layer_id }[:name]
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,24 @@
1
+ module Opsicle
2
+ module DeployHelper
3
+ def launch_stack_monitor(response, options={})
4
+ # Monitoring preferences
5
+ if options[:browser]
6
+ open_deploy(response[:deployment_id])
7
+ elsif options[:monitor] # Default option
8
+ Output.say_verbose "Starting Stack Monitor..."
9
+ @monitor = Opsicle::Monitor::App.new(@environment, options)
10
+ @monitor.start
11
+ end
12
+ end
13
+
14
+ def open_deploy(deployment_id)
15
+ if deployment_id
16
+ command = "open 'https://console.aws.amazon.com/opsworks/home?#/stack/#{client.config.opsworks_config[:stack_id]}/deployments'"
17
+ Output.say_verbose "Executing shell command: #{command}"
18
+ %x(#{command})
19
+ else
20
+ Output.say "Deploy failed. No deployment_id was received from OpsWorks", :error
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module Opsicle
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -19,7 +19,7 @@ module Opsicle
19
19
  expect(config).to receive(:configure_aws!)
20
20
  expect(aws_client).to receive(:create_deployment).with(
21
21
  hash_including(
22
- command: { name: 'deploy' },
22
+ command: { name: 'deploy', args: {} },
23
23
  stack_id: 'stack',
24
24
  app_id: 'app'
25
25
  )
@@ -117,12 +117,12 @@ module Opsicle
117
117
  end
118
118
 
119
119
  context "#launch_stack_monitor" do
120
- let(:options) { { derp: 'herp' } }
120
+ let(:options) { { derp: 'herp', monitor: true } }
121
121
  it "launches the opsicle stack monitor" do
122
122
 
123
123
  expect(Monitor::App).to receive(:new).with('derp', options)
124
124
 
125
- subject.send :launch_stack_monitor, options
125
+ subject.send :launch_stack_monitor, nil, options
126
126
  end
127
127
  end
128
128
  end
@@ -10,7 +10,7 @@ module Opsicle
10
10
  let(:monitor) { double(:start => nil) }
11
11
  before do
12
12
  allow(Client).to receive(:new).with('derp').and_return(client)
13
- allow(client).to receive(:run_command).with('deploy').and_return({deployment_id: 'derp'})
13
+ allow(client).to receive(:run_command).with('deploy', {}).and_return({deployment_id: 'derp'})
14
14
 
15
15
  allow(Monitor::App).to receive(:new).and_return(monitor)
16
16
  allow(monitor).to receive(:start)
@@ -20,13 +20,25 @@ module Opsicle
20
20
  end
21
21
 
22
22
  it "creates a new deployment and opens stack monitor" do
23
- expect(client).to receive(:run_command).with('deploy').and_return({deployment_id: 'derp'})
23
+ expect(client).to receive(:run_command).with('deploy', {}).and_return({deployment_id: 'derp'})
24
24
  expect(subject).to_not receive(:open_deploy)
25
25
  expect(Monitor::App).to receive(:new)
26
26
 
27
27
  subject.execute
28
28
  end
29
29
 
30
+ it "creates a new deployment with migrations" do
31
+ expect(client).to receive(:run_command).with('deploy', {"migrate"=>["true"]}).and_return({deployment_id: 'derp'})
32
+ expect(subject).to_not receive(:open_deploy)
33
+ subject.execute({ monitor: false, migrate: true })
34
+ end
35
+
36
+ it "creates a new deployment migrations explicitly disabled" do
37
+ expect(client).to receive(:run_command).with('deploy', {}).and_return({deployment_id: 'derp'})
38
+ expect(subject).to_not receive(:open_deploy)
39
+ subject.execute({ monitor: false, migrate: false })
40
+ end
41
+
30
42
  it "opens the OpsWorks deployments screen if browser option is given" do
31
43
  expect(subject).to receive(:open_deploy)
32
44
  expect(Monitor::App).to_not receive(:new)
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+ require "opsicle"
3
+
4
+ module Opsicle
5
+ describe ExecuteRecipes do
6
+ subject { ExecuteRecipes.new('derp') }
7
+ let(:recipes) { ['herp'] }
8
+
9
+ context "#execute" do
10
+ let(:client) { double }
11
+ let(:monitor) { double(:start => nil) }
12
+ before do
13
+ allow(Client).to receive(:new).with('derp').and_return(client)
14
+ allow(client).to receive(:run_command).with('execute_recipes', {"recipes" => ['herp']}, {}).and_return({deployment_id: 'derp'})
15
+
16
+ allow(Monitor::App).to receive(:new).and_return(monitor)
17
+ allow(monitor).to receive(:start)
18
+
19
+ allow(Output).to receive(:say)
20
+ allow(Output).to receive(:say_verbose)
21
+ end
22
+
23
+ it "creates a new execute_recipes deployment and opens stack monitor" do
24
+ expect(client).to receive(:run_command).with('execute_recipes', {"recipes" => ['herp']}, {}).and_return({deployment_id: 'derp'})
25
+ expect(subject).to_not receive(:open_deploy)
26
+ expect(Monitor::App).to receive(:new)
27
+
28
+ subject.execute({ monitor: true, recipes: recipes })
29
+ end
30
+
31
+ context "multiple recipes" do
32
+ let(:recipes) { ['herp', 'flurp'] }
33
+ it "creates a new execute_recipes deployment with multiple recipes" do
34
+ expect(client).to receive(:run_command).with('execute_recipes', {"recipes" => ['herp', 'flurp']}, {}).and_return({deployment_id: 'derp'})
35
+ expect(subject).to_not receive(:open_deploy)
36
+ subject.execute({ monitor: false, recipes: recipes })
37
+ end
38
+ end
39
+
40
+ context "instance_ids provided" do
41
+ let(:instance_id) { "6df39ff7-711c-4a58-a64c-0b0e3195af73" }
42
+ it "creates a new execute_recipes deployment for the specific instance_ids" do
43
+ expect(client).to receive(:run_command).with('execute_recipes', {"recipes" => ['herp']}, {"instance_ids" => [instance_id]}).and_return({deployment_id: 'derp'})
44
+ subject.execute({ monitor: false, instance_ids: [instance_id], recipes: recipes })
45
+ end
46
+ end
47
+
48
+ it "opens the OpsWorks deployments screen if browser option is given" do
49
+ expect(subject).to receive(:open_deploy)
50
+ expect(Monitor::App).to_not receive(:new)
51
+
52
+ subject.execute({ browser: true, recipes: recipes })
53
+ end
54
+
55
+ it "doesn't open the stack monitor or open the browser window when no-monitor option is given" do
56
+ expect(subject).to_not receive(:open_deploy)
57
+ expect(Monitor::App).to_not receive(:new)
58
+
59
+ subject.execute({ monitor: false, recipes: recipes })
60
+ end
61
+ end
62
+
63
+ context "#client" do
64
+ it "generates a new aws client from the given configs" do
65
+ expect(Client).to receive(:new).with('derp')
66
+ subject.client
67
+ end
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+ require "opsicle"
3
+
4
+ module Opsicle
5
+ describe ListInstances do
6
+ subject { ListInstances.new('derp') }
7
+
8
+ context "#execute" do
9
+ let(:client) { double }
10
+ let(:layers) { [ { layer_id: 1, name: "Layer 1" }, { layer_id: 2, name: "Layer 2" }] }
11
+ let(:instances) { [
12
+ { hostname: 'test', layer_ids: [1], status: 'online', instance_id: 'opsworks-instance-id'},
13
+ { hostname: 'test2', layer_ids: [2], status: 'online', instance_id: 'opsworks-instance-id2'},
14
+ ] }
15
+ before do
16
+ allow(Client).to receive(:new).with('derp').and_return(client)
17
+ end
18
+
19
+ it "shows a table with all of the instances for the stack from OpsWorks" do
20
+ expect(subject).to receive(:get_layers).and_return(layers)
21
+ expect(subject).to receive(:get_instances).and_return(instances)
22
+ expect(subject).to receive(:print).with(instances)
23
+ subject.execute
24
+ end
25
+ end
26
+
27
+ context "#client" do
28
+ it "generates a new aws client from the given configs" do
29
+ expect(Client).to receive(:new).with('derp')
30
+ subject.client
31
+ end
32
+ end
33
+
34
+ end
35
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opsicle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Fleener
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-26 00:00:00.000000000 Z
11
+ date: 2014-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -174,10 +174,13 @@ files:
174
174
  - lib/opsicle/commands.rb
175
175
  - lib/opsicle/commands/chef_update.rb
176
176
  - lib/opsicle/commands/deploy.rb
177
+ - lib/opsicle/commands/execute_recipes.rb
177
178
  - lib/opsicle/commands/list.rb
179
+ - lib/opsicle/commands/list_instances.rb
178
180
  - lib/opsicle/commands/ssh.rb
179
181
  - lib/opsicle/commands/ssh_key.rb
180
182
  - lib/opsicle/config.rb
183
+ - lib/opsicle/deploy_helper.rb
181
184
  - lib/opsicle/deployment.rb
182
185
  - lib/opsicle/deployments.rb
183
186
  - lib/opsicle/instances.rb
@@ -202,6 +205,8 @@ files:
202
205
  - spec/opsicle/client_spec.rb
203
206
  - spec/opsicle/commands/chef_update_spec.rb
204
207
  - spec/opsicle/commands/deploy_spec.rb
208
+ - spec/opsicle/commands/execute_recipes_spec.rb
209
+ - spec/opsicle/commands/list_instances_spec.rb
205
210
  - spec/opsicle/commands/list_spec.rb
206
211
  - spec/opsicle/commands/ssh_key_spec.rb
207
212
  - spec/opsicle/commands/ssh_spec.rb
@@ -233,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
233
238
  version: '0'
234
239
  requirements: []
235
240
  rubyforge_project:
236
- rubygems_version: 2.2.1
241
+ rubygems_version: 2.2.2
237
242
  signing_key:
238
243
  specification_version: 4
239
244
  summary: An opsworks specific abstraction on top of the aws sdk
@@ -241,6 +246,8 @@ test_files:
241
246
  - spec/opsicle/client_spec.rb
242
247
  - spec/opsicle/commands/chef_update_spec.rb
243
248
  - spec/opsicle/commands/deploy_spec.rb
249
+ - spec/opsicle/commands/execute_recipes_spec.rb
250
+ - spec/opsicle/commands/list_instances_spec.rb
244
251
  - spec/opsicle/commands/list_spec.rb
245
252
  - spec/opsicle/commands/ssh_key_spec.rb
246
253
  - spec/opsicle/commands/ssh_spec.rb