opsicle 0.4.2 → 0.5.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 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