opsworks-cli 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bcc4c1284a99afeda1c929e55f80643e5a2aad36
4
- data.tar.gz: 028437c8044bb146a5ecbfe8febbd125682cdc82
3
+ metadata.gz: b5ab9727e55ff6564f7d6f82d6cbeee4d55005f9
4
+ data.tar.gz: 02ce23e2d07cdccc433660baaf45a9ea031d741a
5
5
  SHA512:
6
- metadata.gz: 16b3ff5a4ceb89c025944ec12ad119e6303bdd763d8a3634ed9d1aca51ff259382f1e61aa062eeba70f01f82c5bec6dcfd2f819a144b1f57646ef9edc032db7f
7
- data.tar.gz: cb5f4440c3428f3773747386fdbed8ca4049a38816e895ac0d78816542299f2ea711441f9f3f4fd798065d72eede476ffbb9045859bf573914fad1cb4f80b387
6
+ metadata.gz: 97b2db684720a9bfc43df78b9ce0ea49afe4687ab40833ac23aeb0f41708807062b5de207736bdb44fe94061c2a945ff42f1d09054b40ac8b28d29650b425595
7
+ data.tar.gz: 1e2201866045a971e81bc2bc10db039576565ad5d94bd910fe852361542b61065fc1d453c2dea310c8821f2598f55d0b71dbe50d418b612036931420c8b24139
@@ -11,6 +11,7 @@ require_relative 'subcommands/status'
11
11
  require_relative 'subcommands/allow'
12
12
  require_relative 'subcommands/lockdown'
13
13
  require_relative 'subcommands/upgrade_chef'
14
+ require_relative 'subcommands/config'
14
15
 
15
16
  module OpsWorks
16
17
  module CLI
@@ -24,6 +25,7 @@ module OpsWorks
24
25
  include Subcommands::Allow
25
26
  include Subcommands::Lockdown
26
27
  include Subcommands::UpgradeChef
28
+ include Subcommands::Config
27
29
 
28
30
  desc 'version', 'Print OpsWorks CLI version'
29
31
  def version
@@ -0,0 +1,54 @@
1
+ require 'aws'
2
+ require 'opsworks/stack'
3
+
4
+ module OpsWorks
5
+ module CLI
6
+ module Subcommands
7
+ module Config
8
+ # rubocop:disable MethodLength
9
+ # rubocop:disable CyclomaticComplexity
10
+ def self.included(thor)
11
+ thor.class_eval do
12
+ include Helpers::Keychain
13
+ include Helpers::Options
14
+
15
+ desc 'config:get KEY [--stack STACK]', 'Get a single config value'
16
+ option :stack, type: :array
17
+ define_method 'config:get' do |key|
18
+ fetch_keychain_credentials unless env_credentials?
19
+ table = parse_stacks(options).map do |stack|
20
+ value = stack.custom_json_at(key)
21
+ [stack.name, value || '(null)']
22
+ end
23
+ table.compact!
24
+ table.sort! { |x, y| x.first <=> y.first }
25
+ print_table table
26
+ end
27
+
28
+ desc 'config:set KEY VALUE [--stack STACK]', 'Set a config value'
29
+ option :stack, type: :array
30
+ define_method 'config:set' do |key, value|
31
+ fetch_keychain_credentials unless env_credentials?
32
+ parse_stacks(options).each do |stack|
33
+ say "Updating #{stack.name}..."
34
+ stack.set_custom_json_at(key, value)
35
+ end
36
+ end
37
+
38
+ desc 'config:unset KEY [--stack STACK]', 'Unset a config value'
39
+ option :stack, type: :array
40
+ define_method 'config:unset' do |key|
41
+ fetch_keychain_credentials unless env_credentials?
42
+ parse_stacks(options).map do |stack|
43
+ say "Updating #{stack.name}..."
44
+ stack.set_custom_json_at(key, nil)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ # rubocop:enable CyclomaticComplexity
50
+ # rubocop:enable MethodLength
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,5 @@
1
1
  require 'aws'
2
- require 'opsworks/deployment'
2
+ require 'opsworks/stack'
3
3
 
4
4
  module OpsWorks
5
5
  module CLI
@@ -1,5 +1,5 @@
1
1
  module OpsWorks
2
2
  module CLI
3
- VERSION = '0.2.3'
3
+ VERSION = '0.2.4'
4
4
  end
5
5
  end
@@ -1,17 +1,24 @@
1
+ require 'jsonpath'
2
+
1
3
  require 'opsworks/resource'
2
4
  require 'opsworks/app'
3
5
  require 'opsworks/instance'
4
6
  require 'opsworks/permission'
5
7
 
6
8
  module OpsWorks
9
+ # rubocop:disable ClassLength
7
10
  class Stack < Resource
8
- attr_accessor :id, :name
11
+ attr_accessor :id, :name, :custom_json
9
12
 
10
13
  AVAILABLE_CHEF_VERSIONS = %w(0.9 11.4 11.10)
11
14
 
12
15
  def self.all
13
16
  client.describe_stacks.data[:stacks].map do |hash|
14
- new(id: hash[:stack_id], name: hash[:name])
17
+ new(
18
+ id: hash[:stack_id],
19
+ name: hash[:name],
20
+ custom_json: JSON.parse(hash[:custom_json])
21
+ )
15
22
  end
16
23
  end
17
24
 
@@ -77,6 +84,19 @@ module OpsWorks
77
84
  instances.any?(&:online?)
78
85
  end
79
86
 
87
+ def custom_json_at(key)
88
+ JsonPath.new(key).first(custom_json)
89
+ end
90
+
91
+ def set_custom_json_at(key, value)
92
+ self.custom_json = replace_hash_at_path(custom_json, key, value)
93
+
94
+ self.class.client.update_stack(
95
+ stack_id: id,
96
+ custom_json: custom_json.to_json
97
+ )
98
+ end
99
+
80
100
  private
81
101
 
82
102
  def initialize_apps
@@ -85,6 +105,24 @@ module OpsWorks
85
105
  App.from_collection_response(response)
86
106
  end
87
107
 
108
+ # rubocop:disable Eval
109
+ def replace_hash_at_path(hash, key, value)
110
+ path = JsonPath.new(key).path
111
+ if value
112
+ # REVIEW: Is there a better way to parse the JSON Path and ensure
113
+ # a value at the location?
114
+ hash.default_proc = ->(h, k) { h[k] = Hash.new(&h.default_proc) }
115
+ eval("hash#{path.join('')} = #{value.inspect}")
116
+ elsif JsonPath.new(key).on(hash).count > 0
117
+ # Path value is present, but we need to unset it
118
+ leaf_key = eval(path[-1]).first
119
+ eval("hash#{path[0...-1].join('')}.delete(#{leaf_key.inspect})")
120
+ end
121
+
122
+ hash
123
+ end
124
+ # rubocop:enable Eval
125
+
88
126
  def initialize_permissions
89
127
  return [] unless id
90
128
  response = self.class.client.describe_permissions(stack_id: id)
@@ -104,4 +142,5 @@ module OpsWorks
104
142
  Deployment.from_response(response)
105
143
  end
106
144
  end
145
+ # rubocop:enable ClassLength
107
146
  end
data/opsworks-cli.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_dependency 'thor'
24
24
  spec.add_dependency 'aws-sdk'
25
+ spec.add_dependency 'jsonpath'
25
26
 
26
27
  spec.add_development_dependency 'aws-keychain-util'
27
28
  spec.add_development_dependency 'bundler', '~> 1.5'
@@ -1,4 +1,5 @@
1
1
  Fabricator(:stack, from: OpsWorks::Stack) do
2
2
  id { SecureRandom.uuid }
3
3
  name { Fabricate.sequence(:name) { |i| "test-stack#{i}" } }
4
+ custom_json { { 'env' => { 'FOO' => 'bar' } } }
4
5
  end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpsWorks::CLI::Agent do
4
+ context 'config' do
5
+ let(:custom_json) { { 'env' => { 'FOO' => 'bar' } } }
6
+ let(:json_path) { 'env.FOO' }
7
+ let(:stack) { Fabricate(:stack, custom_json: custom_json) }
8
+ let(:client) { double.as_null_object }
9
+
10
+ before { allow(subject).to receive(:say) }
11
+ before { allow(OpsWorks::Stack).to receive(:all) { [stack] } }
12
+ before { allow(OpsWorks::Stack).to receive(:client) { client } }
13
+
14
+ describe 'config:get' do
15
+ it 'should print the variable from the stack custom JSON' do
16
+ expect(subject).to receive(:print_table) do |table|
17
+ expect(table).to eq [[stack.name, 'bar']]
18
+ end
19
+ subject.send('config:get', json_path)
20
+ end
21
+
22
+ it 'should print (null) if the variable is unset' do
23
+ stack.custom_json = {}
24
+ expect(subject).to receive(:print_table) do |table|
25
+ expect(table).to eq [[stack.name, '(null)']]
26
+ end
27
+ subject.send('config:get', json_path)
28
+ end
29
+ end
30
+
31
+ describe 'config:set' do
32
+ it 'should reset the variable, if it is already set' do
33
+ expect(client).to receive(:update_stack) do |hash|
34
+ json = JSON.parse(hash[:custom_json])
35
+ expect(json['env']['FOO']).to eq 'baz'
36
+ end
37
+ subject.send('config:set', json_path, 'baz')
38
+ expect(stack.custom_json['env']['FOO']).to eq 'baz'
39
+ end
40
+
41
+ it 'should set the variable, if it is unset' do
42
+ stack.custom_json = {}
43
+ expect(client).to receive(:update_stack) do |hash|
44
+ json = JSON.parse(hash[:custom_json])
45
+ expect(json['env']['FOO']).to eq 'baz'
46
+ end
47
+ subject.send('config:set', json_path, 'baz')
48
+ expect(stack.custom_json['env']['FOO']).to eq 'baz'
49
+ end
50
+
51
+ it 'should leave other variables alone' do
52
+ stack.custom_json.merge!('other' => 'something')
53
+ expect(client).to receive(:update_stack) do |hash|
54
+ json = JSON.parse(hash[:custom_json])
55
+ expect(json['env']['FOO']).to eq 'baz'
56
+ expect(json['other']).to eq 'something'
57
+ end
58
+ subject.send('config:set', json_path, 'baz')
59
+ expect(stack.custom_json['env']['FOO']).to eq 'baz'
60
+ expect(stack.custom_json['other']).to eq 'something'
61
+ end
62
+ end
63
+
64
+ describe 'config:unset' do
65
+ it 'should unset the variable' do
66
+ expect(client).to receive(:update_stack) do |hash|
67
+ json = JSON.parse(hash[:custom_json])
68
+ expect(json['env'].keys).not_to include('FOO')
69
+ end
70
+ subject.send('config:unset', json_path)
71
+ expect(stack.custom_json['env'].keys).not_to include('FOO')
72
+ end
73
+
74
+ it 'should leave other variables alone' do
75
+ stack.custom_json['env'].merge!('OTHER' => 'something')
76
+ expect(client).to receive(:update_stack) do |hash|
77
+ json = JSON.parse(hash[:custom_json])
78
+ expect(json['env'].keys).not_to include('FOO')
79
+ end
80
+ subject.send('config:unset', json_path)
81
+ expect(stack.custom_json['env']).to eq('OTHER' => 'something')
82
+ end
83
+
84
+ it 'should work even with nil values' do
85
+ stack.custom_json['env'] = { 'FOO' => nil }
86
+ expect(client).to receive(:update_stack) do |hash|
87
+ json = JSON.parse(hash[:custom_json])
88
+ expect(json['env'].keys).not_to include('FOO')
89
+ end
90
+ subject.send('config:unset', json_path)
91
+ expect(stack.custom_json['env'].keys).not_to include('FOO')
92
+ end
93
+ end
94
+ end
95
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opsworks-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-17 00:00:00.000000000 Z
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: jsonpath
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: aws-keychain-util
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -158,6 +172,7 @@ files:
158
172
  - lib/opsworks/cli/helpers/keychain.rb
159
173
  - lib/opsworks/cli/helpers/options.rb
160
174
  - lib/opsworks/cli/subcommands/allow.rb
175
+ - lib/opsworks/cli/subcommands/config.rb
161
176
  - lib/opsworks/cli/subcommands/deploy.rb
162
177
  - lib/opsworks/cli/subcommands/exec.rb
163
178
  - lib/opsworks/cli/subcommands/lockdown.rb
@@ -177,6 +192,7 @@ files:
177
192
  - spec/fabricators/opsworks/stack_fabricator.rb
178
193
  - spec/opsworks/cli/agent_spec.rb
179
194
  - spec/opsworks/cli/subcommands/allow_spec.rb
195
+ - spec/opsworks/cli/subcommands/config_spec.rb
180
196
  - spec/opsworks/cli/subcommands/deploy_spec.rb
181
197
  - spec/opsworks/cli/subcommands/exec_spec.rb
182
198
  - spec/opsworks/cli/subcommands/lockdown_spec.rb
@@ -213,6 +229,7 @@ test_files:
213
229
  - spec/fabricators/opsworks/stack_fabricator.rb
214
230
  - spec/opsworks/cli/agent_spec.rb
215
231
  - spec/opsworks/cli/subcommands/allow_spec.rb
232
+ - spec/opsworks/cli/subcommands/config_spec.rb
216
233
  - spec/opsworks/cli/subcommands/deploy_spec.rb
217
234
  - spec/opsworks/cli/subcommands/exec_spec.rb
218
235
  - spec/opsworks/cli/subcommands/lockdown_spec.rb