opsicle 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/opsicle CHANGED
@@ -147,10 +147,12 @@ arg_name '<environment>'
147
147
  arg_name '<recipe>'
148
148
  command 'execute-recipes' do |c|
149
149
  c.switch [:m, :monitor], :desc => "Run the Stack Monitor on deploy", :default_value => true
150
+ c.switch [:e, :eip], :desc => "Executes recipes on a single instance with an elastic IP", :default_value => false
150
151
  c.switch [:t, :track], :desc => "Tracks to deploy and exits when completed. Exits with non-zero if the deploy fails."
151
152
  c.flag [:r, :recipes], :desc => 'The recipes to execute', :type => Array, :required => true
152
153
  c.flag [:i, :instance_ids], :desc => 'The specific instances to execute recipes on', :type => Array
153
154
  c.flag [:l, :layers], :desc => 'The specific layers to execute recipes on', :type => Array
155
+ c.flag [:a, :ip_addresses], :desc => 'The specific ip addresses of instance to execute recipes on', :type => Array
154
156
  c.action do |global_options, options, args|
155
157
  raise ArgumentError, "Environment is required" unless args.first
156
158
 
@@ -18,7 +18,8 @@ module Opsicle
18
18
  command_args = {}
19
19
  command_args["recipes"] = options[:recipes]
20
20
  command_opts = {}
21
- command_opts["instance_ids"] = determine_instance_ids(options) if options[:instance_ids] || options[:layers]
21
+ command_opts["instance_ids"] = determine_instance_ids(options)
22
+ command_opts.reject! {|key,value| value.nil?}
22
23
 
23
24
  response = client.run_command('execute_recipes', command_args, command_opts)
24
25
  launch_stack_monitor(response, options)
@@ -28,9 +29,39 @@ module Opsicle
28
29
  if options[:instance_ids]
29
30
  options[:instance_ids]
30
31
  elsif options[:layers]
31
- Opsicle::Layer.instance_ids(client, options[:layers])
32
+ determine_from_layers(options[:layers])
33
+ elsif options[:ip_addresses]
34
+ determine_from_ips(options[:ip_addresses])
35
+ elsif options[:eip]
36
+ determine_from_eip
32
37
  end
33
38
  end
34
39
 
40
+ def determine_from_ips(ips)
41
+ if instances = Opsicle::Instances.find_by_ip(client, ips)
42
+ instances.map { |instance| instance[:instance_id] }
43
+ else
44
+ raise NoInstanceError, "Unable to find instances with given IP"
45
+ end
46
+ end
47
+
48
+ def determine_from_eip
49
+ if instance = Opsicle::Instances.find_by_eip(client).first
50
+ Array(instance[:instance_id])
51
+ else
52
+ raise NoInstanceError, "Unable to find instances with elastic IPs"
53
+ end
54
+ end
55
+
56
+ def determine_from_layers(layers)
57
+ if instances = Opsicle::Layer.instance_ids(client, layers)
58
+ instances
59
+ else
60
+ raise NoInstanceError, "Unable to find instances in specified layers"
61
+ end
62
+ end
63
+
64
+ NoInstanceError = Class.new(StandardError)
65
+
35
66
  end
36
67
  end
@@ -15,8 +15,8 @@ module Opsicle
15
15
 
16
16
  def aws_config
17
17
  return @aws_config if @aws_config
18
- fog_confg = load_config(File.expand_path(FOG_CONFIG_PATH))
19
- @aws_config = { access_key_id: fog_confg[:aws_access_key_id], secret_access_key: fog_confg[:aws_secret_access_key] }
18
+ fog_config = load_config(File.expand_path(FOG_CONFIG_PATH))
19
+ @aws_config = { access_key_id: fog_config[:aws_access_key_id], secret_access_key: fog_config[:aws_secret_access_key] }
20
20
  end
21
21
 
22
22
  def opsworks_config
@@ -1,6 +1,11 @@
1
1
  module Opsicle
2
2
  class Instances
3
3
 
4
+ attr_accessor :client
5
+ class <<self
6
+ attr_accessor :client
7
+ end
8
+
4
9
  def initialize(client)
5
10
  @client = client
6
11
  end
@@ -9,11 +14,28 @@ module Opsicle
9
14
  instances(reload: true)
10
15
  end
11
16
 
17
+ def self.find_by_ip(client, ips)
18
+ instances = new(client).data.reject { |instance| instances_matching_ips(instance, ips) }
19
+ instances.empty? ? nil : instances
20
+ end
21
+
22
+ def self.instances_matching_ips(instance, ip_addresses)
23
+ instance_ips = [instance[:public_ip], instance[:elastic_ip], instance[:private_ip]].compact
24
+ (ip_addresses & instance_ips).empty?
25
+ end
26
+
27
+ private_class_method :instances_matching_ips
28
+
29
+ def self.find_by_eip(client)
30
+ instances = new(client).data.reject { |instance| instance[:elastic_ip] == nil }
31
+ instances.empty? ? nil : instances
32
+ end
33
+
12
34
  def instances(options={})
13
35
  # Only call the API again if you need to
14
36
  @instances = nil if options[:reload]
15
- @instances ||= @client.api_call('describe_instances',
16
- :stack_id => @client.config.opsworks_config[:stack_id]
37
+ @instances ||= client.api_call('describe_instances',
38
+ :stack_id => client.config.opsworks_config[:stack_id]
17
39
  )[:instances]
18
40
  end
19
41
  private :instances
@@ -1,3 +1,3 @@
1
1
  module Opsicle
2
- VERSION = "0.7.1"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -87,8 +87,55 @@ module Opsicle
87
87
 
88
88
  it "returns the instance_ids when a layer is passed in" do
89
89
  options = {:layers => ["main-util"]}
90
+ expect(subject).to receive(:determine_from_layers)
91
+ subject.determine_instance_ids(options)
92
+ end
93
+
94
+ it "returns an instance_id when eip is set to true" do
95
+ options = {:eip => true}
96
+ expect(subject).to receive(:determine_from_eip)
97
+ subject.determine_instance_ids(options)
98
+ end
99
+
100
+ it "returns an instance_id when an ip is passed in" do
101
+ options = {:ip_addresses => true}
102
+ expect(subject).to receive(:determine_from_ips)
103
+ subject.determine_instance_ids(options)
104
+ end
105
+ end
106
+
107
+ context "#determine_from_layer" do
108
+ let(:layers) {["main-util"]}
109
+ before do
110
+ allow(Client).to receive(:new).with('derp').and_return(client)
111
+ end
112
+
113
+ it "returns the instance_ids when a layer is passed in" do
90
114
  allow(Opsicle::Layer).to receive(:instance_ids).and_return(["a1b2c3"])
91
- expect(subject.determine_instance_ids(options)).to eq(["a1b2c3"])
115
+ expect(subject.determine_from_layers(layers)).to eq(["a1b2c3"])
116
+ end
117
+ end
118
+
119
+ context "#determine_from_ips" do
120
+ let(:ips) {['1.2.3.4','5.6.7.8']}
121
+ before do
122
+ allow(Client).to receive(:new).with('derp').and_return(client)
123
+ end
124
+
125
+ it "returns an instance_id when an ip is passed in" do
126
+ allow(Opsicle::Instances).to receive(:find_by_ip).and_return([{instance_id: "a1b2c3"}, {instance_id: "1234567"}])
127
+ expect(subject.determine_from_ips(ips)).to eq(["a1b2c3","1234567"])
128
+ end
129
+ end
130
+
131
+ context "#determine_from_eip" do
132
+ before do
133
+ allow(Client).to receive(:new).with('derp').and_return(client)
134
+ end
135
+ it "returns an instance_id when eip is set to true" do
136
+ eip = true
137
+ allow(Opsicle::Instances).to receive(:find_by_eip).and_return([{instance_id: "a1b2c3"}, {instance_id: "1234567"}])
138
+ expect(subject.determine_from_eip).to eq(["a1b2c3"])
92
139
  end
93
140
  end
94
141
 
@@ -0,0 +1,77 @@
1
+ require "spec_helper"
2
+ require "opsicle"
3
+
4
+ module Opsicle
5
+ describe Instances do
6
+ let(:client) { double }
7
+ let(:config) { double }
8
+
9
+ let(:instance1) { {private_ip: "10.0.0.1", elastic_ip: "100.0.0.1", public_ip: "200.0.0.1"} }
10
+ let(:instance2) { {private_ip: "10.0.0.2", elastic_ip: "100.0.0.2", public_ip: "200.0.0.2"} }
11
+
12
+ subject {Opsicle::Instances}
13
+ before do
14
+ allow_any_instance_of(subject).to receive(:data).and_return([instance1,instance2])
15
+ end
16
+
17
+ context ".instances_matching_ips" do
18
+ it "returns false if no instances have a given ip" do
19
+ expect(subject.send(:instances_matching_ips, instance1, ["10.0.0.4","100.0.0.4"])).to eq(true)
20
+ end
21
+
22
+ it "returns true if an instance hasa given ip" do
23
+ expect(subject.send(:instances_matching_ips, instance1, ["10.0.0.1","100.0.0.4"])).to eq(false)
24
+ end
25
+ end
26
+
27
+ context ".find_by_ip" do
28
+ before do
29
+ allow(subject).to receive(:instances_matching_ips)
30
+ end
31
+
32
+ it "returns nil if no instances have a given ip" do
33
+ allow(subject).to receive(:instances_matching_ips).and_return(true)
34
+ expect(subject.find_by_ip(client,["10.0.0.4","100.0.0.4"])).to eq(nil)
35
+ end
36
+
37
+ it "returns an instance if an instance has a given private_ip" do
38
+ allow(subject).to receive(:instances_matching_ips).and_return(false,true)
39
+ expect(subject.find_by_ip(client,["10.0.0.1","100.0.0.4"])).to eq([instance1])
40
+ end
41
+
42
+ it "returns an instance if an instance has a given public_ip" do
43
+ allow(subject).to receive(:instances_matching_ips).and_return(true,false)
44
+ expect(subject.find_by_ip(client,["100.0.0.2","100.0.0.4"])).to eq([instance2])
45
+ end
46
+
47
+ it "returns multiple instances with a given set of ips" do
48
+ allow(subject).to receive(:instances_matching_ips).and_return(false)
49
+ expect(subject.find_by_ip(client,["100.0.0.2","200.0.0.1"])).to eq([instance1,instance2])
50
+ end
51
+ end
52
+
53
+ context ".find_by_eip" do
54
+ it "returns instances with an elastic_ip" do
55
+ expect(subject.find_by_eip(client)).to eq([instance1,instance2])
56
+ end
57
+
58
+ context "one instance has an elastic_ip" do
59
+ let(:instance2) { {private_ip: "10.0.0.2", public_ip: "200.0.0.2"} }
60
+ it "returns instances with an elastic_ip" do
61
+ expect(subject.find_by_eip(client)).to eq([instance1])
62
+ end
63
+ end
64
+
65
+ context "no instances have an elastic_ip" do
66
+ let(:instance1) { {private_ip: "10.0.0.1", public_ip: "200.0.0.1"} }
67
+ let(:instance2) { {private_ip: "10.0.0.2", public_ip: "200.0.0.2"} }
68
+
69
+ it "returns nil if no instances have a given ip" do
70
+ expect(subject.find_by_eip(client)).to eq(nil)
71
+ end
72
+
73
+ end
74
+ end
75
+
76
+ end
77
+ end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opsicle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Andy Fleener
@@ -9,11 +10,12 @@ authors:
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2014-11-06 00:00:00.000000000 Z
13
+ date: 2014-11-11 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: aws-sdk
16
17
  requirement: !ruby/object:Gem::Requirement
18
+ none: false
17
19
  requirements:
18
20
  - - ~>
19
21
  - !ruby/object:Gem::Version
@@ -21,6 +23,7 @@ dependencies:
21
23
  type: :runtime
22
24
  prerelease: false
23
25
  version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
24
27
  requirements:
25
28
  - - ~>
26
29
  - !ruby/object:Gem::Version
@@ -28,6 +31,7 @@ dependencies:
28
31
  - !ruby/object:Gem::Dependency
29
32
  name: gli
30
33
  requirement: !ruby/object:Gem::Requirement
34
+ none: false
31
35
  requirements:
32
36
  - - ~>
33
37
  - !ruby/object:Gem::Version
@@ -35,6 +39,7 @@ dependencies:
35
39
  type: :runtime
36
40
  prerelease: false
37
41
  version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
38
43
  requirements:
39
44
  - - ~>
40
45
  - !ruby/object:Gem::Version
@@ -42,6 +47,7 @@ dependencies:
42
47
  - !ruby/object:Gem::Dependency
43
48
  name: highline
44
49
  requirement: !ruby/object:Gem::Requirement
50
+ none: false
45
51
  requirements:
46
52
  - - ~>
47
53
  - !ruby/object:Gem::Version
@@ -49,6 +55,7 @@ dependencies:
49
55
  type: :runtime
50
56
  prerelease: false
51
57
  version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
52
59
  requirements:
53
60
  - - ~>
54
61
  - !ruby/object:Gem::Version
@@ -56,6 +63,7 @@ dependencies:
56
63
  - !ruby/object:Gem::Dependency
57
64
  name: terminal-table
58
65
  requirement: !ruby/object:Gem::Requirement
66
+ none: false
59
67
  requirements:
60
68
  - - ~>
61
69
  - !ruby/object:Gem::Version
@@ -63,6 +71,7 @@ dependencies:
63
71
  type: :runtime
64
72
  prerelease: false
65
73
  version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
66
75
  requirements:
67
76
  - - ~>
68
77
  - !ruby/object:Gem::Version
@@ -70,6 +79,7 @@ dependencies:
70
79
  - !ruby/object:Gem::Dependency
71
80
  name: minitar
72
81
  requirement: !ruby/object:Gem::Requirement
82
+ none: false
73
83
  requirements:
74
84
  - - ~>
75
85
  - !ruby/object:Gem::Version
@@ -77,6 +87,7 @@ dependencies:
77
87
  type: :runtime
78
88
  prerelease: false
79
89
  version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
80
91
  requirements:
81
92
  - - ~>
82
93
  - !ruby/object:Gem::Version
@@ -84,6 +95,7 @@ dependencies:
84
95
  - !ruby/object:Gem::Dependency
85
96
  name: bundler
86
97
  requirement: !ruby/object:Gem::Requirement
98
+ none: false
87
99
  requirements:
88
100
  - - ~>
89
101
  - !ruby/object:Gem::Version
@@ -91,6 +103,7 @@ dependencies:
91
103
  type: :development
92
104
  prerelease: false
93
105
  version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
94
107
  requirements:
95
108
  - - ~>
96
109
  - !ruby/object:Gem::Version
@@ -98,6 +111,7 @@ dependencies:
98
111
  - !ruby/object:Gem::Dependency
99
112
  name: rake
100
113
  requirement: !ruby/object:Gem::Requirement
114
+ none: false
101
115
  requirements:
102
116
  - - ~>
103
117
  - !ruby/object:Gem::Version
@@ -105,6 +119,7 @@ dependencies:
105
119
  type: :development
106
120
  prerelease: false
107
121
  version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
108
123
  requirements:
109
124
  - - ~>
110
125
  - !ruby/object:Gem::Version
@@ -112,6 +127,7 @@ dependencies:
112
127
  - !ruby/object:Gem::Dependency
113
128
  name: rspec
114
129
  requirement: !ruby/object:Gem::Requirement
130
+ none: false
115
131
  requirements:
116
132
  - - ~>
117
133
  - !ruby/object:Gem::Version
@@ -119,6 +135,7 @@ dependencies:
119
135
  type: :development
120
136
  prerelease: false
121
137
  version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
122
139
  requirements:
123
140
  - - ~>
124
141
  - !ruby/object:Gem::Version
@@ -126,6 +143,7 @@ dependencies:
126
143
  - !ruby/object:Gem::Dependency
127
144
  name: guard
128
145
  requirement: !ruby/object:Gem::Requirement
146
+ none: false
129
147
  requirements:
130
148
  - - ~>
131
149
  - !ruby/object:Gem::Version
@@ -133,6 +151,7 @@ dependencies:
133
151
  type: :development
134
152
  prerelease: false
135
153
  version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
136
155
  requirements:
137
156
  - - ~>
138
157
  - !ruby/object:Gem::Version
@@ -140,6 +159,7 @@ dependencies:
140
159
  - !ruby/object:Gem::Dependency
141
160
  name: guard-rspec
142
161
  requirement: !ruby/object:Gem::Requirement
162
+ none: false
143
163
  requirements:
144
164
  - - ~>
145
165
  - !ruby/object:Gem::Version
@@ -147,6 +167,7 @@ dependencies:
147
167
  type: :development
148
168
  prerelease: false
149
169
  version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
150
171
  requirements:
151
172
  - - ~>
152
173
  - !ruby/object:Gem::Version
@@ -159,11 +180,7 @@ executables:
159
180
  extensions: []
160
181
  extra_rdoc_files: []
161
182
  files:
162
- - LICENSE
163
- - bin/opsicle
164
- - lib/opsicle.rb
165
183
  - lib/opsicle/client.rb
166
- - lib/opsicle/commands.rb
167
184
  - lib/opsicle/commands/chef_update.rb
168
185
  - lib/opsicle/commands/deploy.rb
169
186
  - lib/opsicle/commands/execute_recipes.rb
@@ -171,6 +188,7 @@ files:
171
188
  - lib/opsicle/commands/list_instances.rb
172
189
  - lib/opsicle/commands/ssh.rb
173
190
  - lib/opsicle/commands/ssh_key.rb
191
+ - lib/opsicle/commands.rb
174
192
  - lib/opsicle/config.rb
175
193
  - lib/opsicle/deploy_helper.rb
176
194
  - lib/opsicle/deployment.rb
@@ -178,7 +196,6 @@ files:
178
196
  - lib/opsicle/errors.rb
179
197
  - lib/opsicle/instances.rb
180
198
  - lib/opsicle/layer.rb
181
- - lib/opsicle/monitor.rb
182
199
  - lib/opsicle/monitor/app.rb
183
200
  - lib/opsicle/monitor/panel.rb
184
201
  - lib/opsicle/monitor/panels/deployments.rb
@@ -191,10 +208,14 @@ files:
191
208
  - lib/opsicle/monitor/spy/instances.rb
192
209
  - lib/opsicle/monitor/subpanel.rb
193
210
  - lib/opsicle/monitor/translatable.rb
211
+ - lib/opsicle/monitor.rb
194
212
  - lib/opsicle/output.rb
195
213
  - lib/opsicle/s3_bucket.rb
196
214
  - lib/opsicle/stack.rb
197
215
  - lib/opsicle/version.rb
216
+ - lib/opsicle.rb
217
+ - bin/opsicle
218
+ - LICENSE
198
219
  - spec/opsicle/client_spec.rb
199
220
  - spec/opsicle/commands/chef_update_spec.rb
200
221
  - spec/opsicle/commands/deploy_spec.rb
@@ -205,6 +226,7 @@ files:
205
226
  - spec/opsicle/commands/ssh_spec.rb
206
227
  - spec/opsicle/config_spec.rb
207
228
  - spec/opsicle/errors_spec.rb
229
+ - spec/opsicle/instances_spec.rb
208
230
  - spec/opsicle/layer_spec.rb
209
231
  - spec/opsicle/monitor/app_spec.rb
210
232
  - spec/opsicle/monitor/panel_spec.rb
@@ -216,26 +238,27 @@ files:
216
238
  homepage: https://github.com/sportngin/opsicle
217
239
  licenses:
218
240
  - MIT
219
- metadata: {}
220
241
  post_install_message:
221
242
  rdoc_options: []
222
243
  require_paths:
223
244
  - lib
224
245
  required_ruby_version: !ruby/object:Gem::Requirement
246
+ none: false
225
247
  requirements:
226
248
  - - ! '>='
227
249
  - !ruby/object:Gem::Version
228
250
  version: '0'
229
251
  required_rubygems_version: !ruby/object:Gem::Requirement
252
+ none: false
230
253
  requirements:
231
254
  - - ! '>='
232
255
  - !ruby/object:Gem::Version
233
256
  version: '0'
234
257
  requirements: []
235
258
  rubyforge_project:
236
- rubygems_version: 2.2.2
259
+ rubygems_version: 1.8.25
237
260
  signing_key:
238
- specification_version: 4
261
+ specification_version: 3
239
262
  summary: An opsworks specific abstraction on top of the aws sdk
240
263
  test_files:
241
264
  - spec/opsicle/client_spec.rb
@@ -248,6 +271,7 @@ test_files:
248
271
  - spec/opsicle/commands/ssh_spec.rb
249
272
  - spec/opsicle/config_spec.rb
250
273
  - spec/opsicle/errors_spec.rb
274
+ - spec/opsicle/instances_spec.rb
251
275
  - spec/opsicle/layer_spec.rb
252
276
  - spec/opsicle/monitor/app_spec.rb
253
277
  - spec/opsicle/monitor/panel_spec.rb
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- YzdlMWE1YmRhMzZmNWJkYWM0MmI0OWRhN2VmODZjMmYxYjA5NDM3NQ==
5
- data.tar.gz: !binary |-
6
- NGYzZGVhY2RkZjM3NzRiNzdmZWRjZmQ0NTNiNTZjNzNlZDRmMDA3OQ==
7
- SHA512:
8
- metadata.gz: !binary |-
9
- Y2QwZjVkN2FiMjA4YWZiZGFjZjkxNmY3ZjU1MWY1ZDdhZDBhMWM2MDYxNmVm
10
- NjExMTFiMDJjZDliMDVlNjc5YTYyZDQ1NjU2ZDU1OWJiMmIwNmIyNTk5MGIx
11
- YzRkYzE0YTg5NmFkN2U2OTcwNzEwMGZjMjc1ZWJmNGQ4ZTQ4YTI=
12
- data.tar.gz: !binary |-
13
- OTRjMGNjZTJmODI5YWMyMjY5ZWI3MzMyZWJiNjg1OWE5NjdmZWYyYzQ2NGU5
14
- M2NkMzYxZmZjMWY1ZjE0NmVmZDhkYjk0OTk3ODBlMzI2NGJjNzI4ZTVlNTRl
15
- Y2ViNzAzNjAyNzM1MTU1ZjgyNzFmYTQ0NjhlYzZiZDc1ZTc4MjQ=