opsworks-cli 0.2.4 → 0.3.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 +4 -4
- data/README.md +14 -5
- data/lib/opsworks/cli/agent.rb +6 -10
- data/lib/opsworks/cli/subcommands/apps.rb +90 -0
- data/lib/opsworks/cli/subcommands/{allow.rb → iam.rb} +18 -3
- data/lib/opsworks/cli/subcommands/{exec.rb → recipes.rb} +21 -4
- data/lib/opsworks/cli/subcommands/update.rb +2 -1
- data/lib/opsworks/cli/version.rb +1 -1
- data/lib/opsworks/layer.rb +36 -0
- data/lib/opsworks/stack.rb +23 -1
- data/opsworks-cli.gemspec +1 -0
- data/spec/opsworks/cli/subcommands/apps_spec.rb +90 -0
- data/spec/opsworks/cli/subcommands/config_spec.rb +10 -0
- data/spec/opsworks/cli/subcommands/iam_spec.rb +68 -0
- data/spec/opsworks/cli/subcommands/recipes_spec.rb +39 -0
- metadata +26 -15
- data/lib/opsworks/cli/subcommands/deploy.rb +0 -38
- data/lib/opsworks/cli/subcommands/lockdown.rb +0 -30
- data/lib/opsworks/cli/subcommands/status.rb +0 -45
- data/spec/opsworks/cli/subcommands/allow_spec.rb +0 -42
- data/spec/opsworks/cli/subcommands/deploy_spec.rb +0 -53
- data/spec/opsworks/cli/subcommands/exec_spec.rb +0 -37
- data/spec/opsworks/cli/subcommands/lockdown_spec.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ab03c769a18190d2590e765e79e992e820685da
|
4
|
+
data.tar.gz: ce762573e029e65e1776bcfae265f7611762fc85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d347483d2342efc5d4cbbd882f310044bd327269868105eab6ea53e9f4a368cb2420c0cd2b9d4853a2cb409cfcb0e2eb0b6fddfa18932025f6bda958c0e9a8da
|
7
|
+
data.tar.gz: ca593191e47af2a66c8f072d1c1fca78f869c9cc0784c06e8b5c33819b63cba6afeabc66d0c677d98261c4f4b95ee4ef979ff9c6eb7879ddf13b0943e745948b
|
data/README.md
CHANGED
@@ -32,11 +32,20 @@ When you add credentials, make sure to name the account `default`.
|
|
32
32
|
```
|
33
33
|
$ opsworks help
|
34
34
|
Commands:
|
35
|
-
opsworks
|
36
|
-
opsworks
|
37
|
-
opsworks status [--stack STACK]
|
38
|
-
opsworks
|
39
|
-
opsworks
|
35
|
+
opsworks apps:create APP [--stack STACK] # Create a new OpsWorks app
|
36
|
+
opsworks apps:deploy APP [--stack STACK] # Deploy an OpsWorks app
|
37
|
+
opsworks apps:status APP [--stack STACK] # Display the most recent deployment of an app
|
38
|
+
opsworks config:get KEY [--stack STACK] # Get a single config value
|
39
|
+
opsworks config:set KEY VALUE [--stack STACK] # Set a config value
|
40
|
+
opsworks config:unset KEY [--stack STACK] # Unset a config value
|
41
|
+
opsworks help [COMMAND] # Describe available commands or one specific command
|
42
|
+
opsworks iam:allow USER [--stack STACK] # Allow an IAM user on a stack
|
43
|
+
opsworks iam:lockdown [--stack STACK] # Remove all stack permissions
|
44
|
+
opsworks recipes:add LAYER EVENT RECIPE [--stack STACK] # Add a recipe to a given layer and lifecycle event
|
45
|
+
opsworks recipes:run RECIPE [--stack STACK] # Execute a Chef recipe
|
46
|
+
opsworks update [--stack STACK] # Update OpsWorks custom cookbooks
|
47
|
+
opsworks upgrade-chef [--stack STACK] # Upgrade Chef version
|
48
|
+
opsworks version # Print OpsWorks CLI version
|
40
49
|
```
|
41
50
|
|
42
51
|
## Contributing
|
data/lib/opsworks/cli/agent.rb
CHANGED
@@ -5,12 +5,10 @@ require_relative 'helpers/keychain'
|
|
5
5
|
require_relative 'helpers/options'
|
6
6
|
|
7
7
|
require_relative 'subcommands/update'
|
8
|
-
require_relative 'subcommands/exec'
|
9
|
-
require_relative 'subcommands/deploy'
|
10
|
-
require_relative 'subcommands/status'
|
11
|
-
require_relative 'subcommands/allow'
|
12
|
-
require_relative 'subcommands/lockdown'
|
13
8
|
require_relative 'subcommands/upgrade_chef'
|
9
|
+
require_relative 'subcommands/recipes'
|
10
|
+
require_relative 'subcommands/apps'
|
11
|
+
require_relative 'subcommands/iam'
|
14
12
|
require_relative 'subcommands/config'
|
15
13
|
|
16
14
|
module OpsWorks
|
@@ -19,12 +17,10 @@ module OpsWorks
|
|
19
17
|
include Thor::Actions
|
20
18
|
|
21
19
|
include Subcommands::Update
|
22
|
-
include Subcommands::Exec
|
23
|
-
include Subcommands::Deploy
|
24
|
-
include Subcommands::Status
|
25
|
-
include Subcommands::Allow
|
26
|
-
include Subcommands::Lockdown
|
27
20
|
include Subcommands::UpgradeChef
|
21
|
+
include Subcommands::Recipes
|
22
|
+
include Subcommands::Apps
|
23
|
+
include Subcommands::IAM
|
28
24
|
include Subcommands::Config
|
29
25
|
|
30
26
|
desc 'version', 'Print OpsWorks CLI version'
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'opsworks/deployment'
|
2
|
+
|
3
|
+
module OpsWorks
|
4
|
+
module CLI
|
5
|
+
module Subcommands
|
6
|
+
module Apps
|
7
|
+
# rubocop:disable MethodLength
|
8
|
+
# rubocop:disable CyclomaticComplexity
|
9
|
+
# rubocop:disable PerceivedComplexity
|
10
|
+
def self.included(thor)
|
11
|
+
thor.class_eval do
|
12
|
+
desc 'apps:deploy APP [--stack STACK]', 'Deploy an OpsWorks app'
|
13
|
+
option :stack, type: :array
|
14
|
+
option :timeout, type: :numeric
|
15
|
+
define_method 'apps:deploy' do |name|
|
16
|
+
fetch_keychain_credentials unless env_credentials?
|
17
|
+
stacks = parse_stacks(options.merge(active: true))
|
18
|
+
deployments = stacks.map do |stack|
|
19
|
+
next unless (app = stack.find_app_by_name(name))
|
20
|
+
say "Deploying to #{stack.name}..."
|
21
|
+
stack.deploy_app(app)
|
22
|
+
end
|
23
|
+
deployments.compact!
|
24
|
+
OpsWorks::Deployment.wait(deployments, options[:timeout])
|
25
|
+
unless deployments.all?(&:success?)
|
26
|
+
failures = []
|
27
|
+
deployments.each_with_index do |deployment, i|
|
28
|
+
failures << stacks[i].name unless deployment.success?
|
29
|
+
end
|
30
|
+
fail "Deploy failed on #{failures.join(', ')}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'apps:status APP [--stack STACK]',
|
35
|
+
'Display the most recent deployment of an app'
|
36
|
+
option :stack, type: :array
|
37
|
+
define_method 'apps:status' do |name|
|
38
|
+
fetch_keychain_credentials unless env_credentials?
|
39
|
+
|
40
|
+
table = parse_stacks(options).map do |stack|
|
41
|
+
next unless (app = stack.find_app_by_name(name))
|
42
|
+
if (deployment = app.last_deployment)
|
43
|
+
deployed_at = formatted_time(deployment.created_at)
|
44
|
+
else
|
45
|
+
deployed_at = '-'
|
46
|
+
end
|
47
|
+
[stack.name, name, "(#{app.revision})", deployed_at]
|
48
|
+
end
|
49
|
+
# Sort output in descending date order
|
50
|
+
table.compact!
|
51
|
+
table.sort! { |x, y| y.last <=> x.last }
|
52
|
+
print_table table
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'apps:create APP [--stack STACK]', 'Create a new OpsWorks app'
|
56
|
+
option :stack, type: :array
|
57
|
+
option :type, default: 'other'
|
58
|
+
option :git_url
|
59
|
+
option :shortname
|
60
|
+
define_method 'apps:create' do |name|
|
61
|
+
unless %w(other).include?(options[:type])
|
62
|
+
fail "Unsupported type: #{options[:type]}"
|
63
|
+
end
|
64
|
+
|
65
|
+
fail 'Git URL not yet supported' if options[:git_url]
|
66
|
+
|
67
|
+
fetch_keychain_credentials unless env_credentials?
|
68
|
+
stacks = parse_stacks(options)
|
69
|
+
|
70
|
+
stacks.each do |stack|
|
71
|
+
next if stack.apps.map(&:name).include?(name)
|
72
|
+
say "Creating app on #{stack.name}."
|
73
|
+
stack.create_app(name, options)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def formatted_time(timestamp)
|
80
|
+
timestamp.strftime('%Y-%m-%d %H:%M:%S %Z')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
# rubocop:enable PerceivedComplexity
|
85
|
+
# rubocop:enable CyclomaticComplexity
|
86
|
+
# rubocop:enable MethodLength
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -3,16 +3,17 @@ require 'opsworks/permission'
|
|
3
3
|
module OpsWorks
|
4
4
|
module CLI
|
5
5
|
module Subcommands
|
6
|
-
module
|
6
|
+
module IAM
|
7
7
|
# rubocop:disable MethodLength
|
8
8
|
# rubocop:disable CyclomaticComplexity
|
9
9
|
def self.included(thor)
|
10
10
|
thor.class_eval do
|
11
|
-
desc 'allow USER [--stack STACK]',
|
11
|
+
desc 'iam:allow USER [--stack STACK]',
|
12
|
+
'Allow an IAM user on a stack'
|
12
13
|
option :stack, type: :array
|
13
14
|
option :ssh, type: :boolean, default: true
|
14
15
|
option :sudo, type: :boolean, default: true
|
15
|
-
|
16
|
+
define_method 'iam:allow' do |user|
|
16
17
|
fetch_keychain_credentials unless env_credentials?
|
17
18
|
stacks = parse_stacks(options.merge(active: true))
|
18
19
|
stacks.each do |stack|
|
@@ -22,6 +23,20 @@ module OpsWorks
|
|
22
23
|
permission.update(ssh: options[:ssh], sudo: options[:sudo])
|
23
24
|
end
|
24
25
|
end
|
26
|
+
|
27
|
+
desc 'iam:lockdown [--stack STACK]', 'Remove all stack permissions'
|
28
|
+
option :stack, type: :array
|
29
|
+
define_method 'iam:lockdown' do
|
30
|
+
fetch_keychain_credentials unless env_credentials?
|
31
|
+
stacks = parse_stacks(options.merge(active: true))
|
32
|
+
stacks.each do |stack|
|
33
|
+
say "Locking down #{stack.name}..."
|
34
|
+
stack.permissions.each do |permission|
|
35
|
+
permission.update(ssh: false, sudo: false)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
25
40
|
end
|
26
41
|
end
|
27
42
|
# rubocop:enable CyclomaticComplexity
|
@@ -3,21 +3,22 @@ require 'opsworks/deployment'
|
|
3
3
|
module OpsWorks
|
4
4
|
module CLI
|
5
5
|
module Subcommands
|
6
|
-
module
|
6
|
+
module Recipes
|
7
7
|
# rubocop:disable MethodLength
|
8
8
|
# rubocop:disable CyclomaticComplexity
|
9
9
|
def self.included(thor)
|
10
10
|
thor.class_eval do
|
11
|
-
desc '
|
11
|
+
desc 'recipes:run RECIPE [--stack STACK]', 'Execute a Chef recipe'
|
12
12
|
option :stack, type: :array
|
13
|
-
|
13
|
+
option :timeout, type: :numeric
|
14
|
+
define_method 'recipes:run' do |recipe|
|
14
15
|
fetch_keychain_credentials unless env_credentials?
|
15
16
|
stacks = parse_stacks(options.merge(active: true))
|
16
17
|
deployments = stacks.map do |stack|
|
17
18
|
say "Executing recipe on #{stack.name}..."
|
18
19
|
stack.execute_recipe(recipe)
|
19
20
|
end
|
20
|
-
OpsWorks::Deployment.wait(deployments)
|
21
|
+
OpsWorks::Deployment.wait(deployments, options[:timeout])
|
21
22
|
unless deployments.all?(&:success?)
|
22
23
|
failures = []
|
23
24
|
deployments.each_with_index do |deployment, i|
|
@@ -26,6 +27,22 @@ module OpsWorks
|
|
26
27
|
fail "Command failed on #{failures.join(', ')}"
|
27
28
|
end
|
28
29
|
end
|
30
|
+
|
31
|
+
desc 'recipes:add LAYER EVENT RECIPE [--stack STACK]',
|
32
|
+
'Add a recipe to a given layer and lifecycle event'
|
33
|
+
option :stack, type: :array
|
34
|
+
define_method 'recipes:add' do |layername, event, recipe|
|
35
|
+
fetch_keychain_credentials unless env_credentials?
|
36
|
+
stacks = parse_stacks(options)
|
37
|
+
stacks.each do |stack|
|
38
|
+
layer = stack.layers.find { |l| l.shortname == layername }
|
39
|
+
next unless layer
|
40
|
+
next if layer.custom_recipes[event].include?(recipe)
|
41
|
+
|
42
|
+
say "Adding recipe to #{stack.name}."
|
43
|
+
layer.add_custom_recipe(event, recipe)
|
44
|
+
end
|
45
|
+
end
|
29
46
|
end
|
30
47
|
end
|
31
48
|
# rubocop:enable CyclomaticComplexity
|
@@ -14,6 +14,7 @@ module OpsWorks
|
|
14
14
|
|
15
15
|
desc 'update [--stack STACK]', 'Update OpsWorks custom cookbooks'
|
16
16
|
option :stack, type: :array
|
17
|
+
option :timeout, type: :numeric
|
17
18
|
def update
|
18
19
|
fetch_keychain_credentials unless env_credentials?
|
19
20
|
stacks = parse_stacks(options.merge(active: true))
|
@@ -21,7 +22,7 @@ module OpsWorks
|
|
21
22
|
say "Updating #{stack.name}..."
|
22
23
|
stack.update_custom_cookbooks
|
23
24
|
end
|
24
|
-
OpsWorks::Deployment.wait(deployments)
|
25
|
+
OpsWorks::Deployment.wait(deployments, options[:timeout])
|
25
26
|
unless deployments.all?(&:success?)
|
26
27
|
failures = []
|
27
28
|
deployments.each_with_index do |deployment, i|
|
data/lib/opsworks/cli/version.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'opsworks/resource'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module OpsWorks
|
5
|
+
class Layer < Resource
|
6
|
+
attr_accessor :id, :name, :shortname, :custom_recipes
|
7
|
+
|
8
|
+
# rubocop:disable MethodLength
|
9
|
+
def self.from_collection_response(response)
|
10
|
+
response.data[:layers].map do |hash|
|
11
|
+
# Make custom_recipes accessible by string or symbol
|
12
|
+
custom_recipes = Thor::CoreExt::HashWithIndifferentAccess.new(
|
13
|
+
hash[:custom_recipes]
|
14
|
+
)
|
15
|
+
new(
|
16
|
+
id: hash[:layer_id],
|
17
|
+
name: hash[:name],
|
18
|
+
shortname: hash[:shortname],
|
19
|
+
custom_recipes: custom_recipes
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
# rubocop:enable MethodLength
|
24
|
+
|
25
|
+
def add_custom_recipe(event, recipe)
|
26
|
+
return if custom_recipes[event].include?(recipe)
|
27
|
+
|
28
|
+
custom_recipes[event] ||= []
|
29
|
+
custom_recipes[event].push recipe
|
30
|
+
self.class.client.update_layer(
|
31
|
+
layer_id: id,
|
32
|
+
custom_recipes: custom_recipes
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/opsworks/stack.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'jsonpath'
|
2
|
+
require 'active_support/core_ext/hash/slice'
|
2
3
|
|
3
4
|
require 'opsworks/resource'
|
4
5
|
require 'opsworks/app'
|
5
6
|
require 'opsworks/instance'
|
6
7
|
require 'opsworks/permission'
|
8
|
+
require 'opsworks/layer'
|
7
9
|
|
8
10
|
module OpsWorks
|
9
11
|
# rubocop:disable ClassLength
|
@@ -54,6 +56,10 @@ module OpsWorks
|
|
54
56
|
@instances ||= initialize_instances
|
55
57
|
end
|
56
58
|
|
59
|
+
def layers
|
60
|
+
@layers ||= initialize_layers
|
61
|
+
end
|
62
|
+
|
57
63
|
def upgrade_chef(version, options = {})
|
58
64
|
self.class.client.update_stack(
|
59
65
|
stack_id: id,
|
@@ -97,6 +103,12 @@ module OpsWorks
|
|
97
103
|
)
|
98
104
|
end
|
99
105
|
|
106
|
+
def create_app(name, options = {})
|
107
|
+
options = options.slice(:type, :shortname)
|
108
|
+
options.merge!(stack_id: id, name: name)
|
109
|
+
self.class.client.create_app(options)
|
110
|
+
end
|
111
|
+
|
100
112
|
private
|
101
113
|
|
102
114
|
def initialize_apps
|
@@ -106,12 +118,15 @@ module OpsWorks
|
|
106
118
|
end
|
107
119
|
|
108
120
|
# rubocop:disable Eval
|
121
|
+
# rubocop:disable MethodLength
|
109
122
|
def replace_hash_at_path(hash, key, value)
|
110
123
|
path = JsonPath.new(key).path
|
111
124
|
if value
|
112
125
|
# REVIEW: Is there a better way to parse the JSON Path and ensure
|
113
126
|
# a value at the location?
|
114
|
-
|
127
|
+
(0...(path.length - 1)).each do |i|
|
128
|
+
eval("hash#{path[0..i].join('')} ||= {}")
|
129
|
+
end
|
115
130
|
eval("hash#{path.join('')} = #{value.inspect}")
|
116
131
|
elsif JsonPath.new(key).on(hash).count > 0
|
117
132
|
# Path value is present, but we need to unset it
|
@@ -121,6 +136,7 @@ module OpsWorks
|
|
121
136
|
|
122
137
|
hash
|
123
138
|
end
|
139
|
+
# rubocop:enable MethodLength
|
124
140
|
# rubocop:enable Eval
|
125
141
|
|
126
142
|
def initialize_permissions
|
@@ -135,6 +151,12 @@ module OpsWorks
|
|
135
151
|
Instance.from_collection_response(response)
|
136
152
|
end
|
137
153
|
|
154
|
+
def initialize_layers
|
155
|
+
return [] unless id
|
156
|
+
response = self.class.client.describe_layers(stack_id: id)
|
157
|
+
Layer.from_collection_response(response)
|
158
|
+
end
|
159
|
+
|
138
160
|
def create_deployment(options = {})
|
139
161
|
response = self.class.client.create_deployment(
|
140
162
|
options.merge(stack_id: id)
|
data/opsworks-cli.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency 'thor'
|
24
24
|
spec.add_dependency 'aws-sdk'
|
25
25
|
spec.add_dependency 'jsonpath'
|
26
|
+
spec.add_dependency 'activesupport'
|
26
27
|
|
27
28
|
spec.add_development_dependency 'aws-keychain-util'
|
28
29
|
spec.add_development_dependency 'bundler', '~> 1.5'
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OpsWorks::CLI::Agent do
|
4
|
+
context 'apps' do
|
5
|
+
let(:app_name) { 'aptible' }
|
6
|
+
let(:stacks) { 2.times.map { Fabricate(:stack) } }
|
7
|
+
|
8
|
+
before { allow(subject).to receive(:say) }
|
9
|
+
before { allow(OpsWorks::Deployment).to receive(:wait) }
|
10
|
+
before { allow(OpsWorks::Stack).to receive(:all) { stacks } }
|
11
|
+
before { allow(OpsWorks::Stack).to receive(:active) { stacks } }
|
12
|
+
|
13
|
+
describe 'apps:deploy' do
|
14
|
+
let(:app) { Fabricate(:app, name: app_name) }
|
15
|
+
let(:success) { Fabricate(:deployment, status: 'successful') }
|
16
|
+
let(:failure) { Fabricate(:deployment, status: 'failed') }
|
17
|
+
|
18
|
+
before do
|
19
|
+
stacks.each { |stack| allow(stack).to receive(:apps) { [app] } }
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should update custom cookbooks on all stacks' do
|
23
|
+
expect(stacks[0]).to receive(:deploy_app).with(app) { success }
|
24
|
+
expect(stacks[1]).to receive(:deploy_app).with(app) { success }
|
25
|
+
subject.send('apps:deploy', app_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should not fail if some stacks are inactive' do
|
29
|
+
allow(OpsWorks::Stack).to receive(:active) { [stacks[0]] }
|
30
|
+
expect(stacks[0]).to receive(:deploy_app).with(app) { success }
|
31
|
+
expect(stacks[1]).not_to receive(:deploy_app)
|
32
|
+
subject.send('apps:deploy', app_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should optionally run on a subset of stacks' do
|
36
|
+
expect(stacks[0]).to receive(:deploy_app).with(app) { success }
|
37
|
+
expect(stacks[1]).not_to receive(:deploy_app)
|
38
|
+
|
39
|
+
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
40
|
+
subject.send('apps:deploy', app_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should not fail if a stack does not have the app' do
|
44
|
+
allow(stacks[0]).to receive(:apps) { [] }
|
45
|
+
expect(stacks[1]).to receive(:deploy_app).with(app) { success }
|
46
|
+
expect { subject.send('apps:deploy', app_name) }.not_to raise_error
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should fail if any update fails' do
|
50
|
+
expect(stacks[0]).to receive(:deploy_app).with(app) { failure }
|
51
|
+
|
52
|
+
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
53
|
+
expect { subject.send('apps:deploy', app_name) }.to raise_error
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'apps:create' do
|
58
|
+
# TODO: Figure out why Thor doesn't populate options from defaults
|
59
|
+
# when methods are invoked directly
|
60
|
+
let(:options) { { type: 'other' } }
|
61
|
+
|
62
|
+
before do
|
63
|
+
stacks.each { |stack| allow(stack).to receive(:apps) { [] } }
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should fail with a helpful error on unsupported type' do
|
67
|
+
options.merge!(type: 'foobar')
|
68
|
+
allow(subject).to receive(:options) { options }
|
69
|
+
expect { subject.send('apps:create', app_name) }.to raise_error
|
70
|
+
end
|
71
|
+
|
72
|
+
xit 'should accept a Git URL'
|
73
|
+
|
74
|
+
it 'should create an app' do
|
75
|
+
allow(subject).to receive(:options) { options }
|
76
|
+
expect(stacks[0]).to receive(:create_app).with(app_name, options)
|
77
|
+
expect(stacks[1]).to receive(:create_app).with(app_name, options)
|
78
|
+
subject.send('apps:create', app_name)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should accept a different shortname' do
|
82
|
+
options.merge!(shortname: 'foobar')
|
83
|
+
allow(subject).to receive(:options) { options }
|
84
|
+
expect(stacks[0]).to receive(:create_app).with(app_name, options)
|
85
|
+
expect(stacks[1]).to receive(:create_app).with(app_name, options)
|
86
|
+
subject.send('apps:create', app_name)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -38,6 +38,16 @@ describe OpsWorks::CLI::Agent do
|
|
38
38
|
expect(stack.custom_json['env']['FOO']).to eq 'baz'
|
39
39
|
end
|
40
40
|
|
41
|
+
it 'should work with deep nested hashes' do
|
42
|
+
stack.custom_json = { 'app' => { 'var' => 'value' } }
|
43
|
+
expect(client).to receive(:update_stack) do |hash|
|
44
|
+
json = JSON.parse(hash[:custom_json])
|
45
|
+
expect(json['app']['env']['FOO']).to eq 'baz'
|
46
|
+
end
|
47
|
+
subject.send('config:set', 'app.env.FOO', 'baz')
|
48
|
+
expect(stack.custom_json['app']['env']['FOO']).to eq 'baz'
|
49
|
+
end
|
50
|
+
|
41
51
|
it 'should set the variable, if it is unset' do
|
42
52
|
stack.custom_json = {}
|
43
53
|
expect(client).to receive(:update_stack) do |hash|
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OpsWorks::CLI::Agent do
|
4
|
+
context 'iam' do
|
5
|
+
let(:permissions) { 2.times.map { Fabricate(:permission) } }
|
6
|
+
let(:user) { permissions[0].user }
|
7
|
+
|
8
|
+
before { allow(subject).to receive(:say) }
|
9
|
+
before { allow(OpsWorks::Stack).to receive(:all) { stacks } }
|
10
|
+
before { allow(OpsWorks::Stack).to receive(:active) { stacks } }
|
11
|
+
|
12
|
+
describe 'iam:allow' do
|
13
|
+
let(:stacks) do
|
14
|
+
2.times.map do |i|
|
15
|
+
Fabricate(:stack).tap do |stack|
|
16
|
+
allow(stack).to receive(:find_permission_by_user) { permissions[i] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should update all matching permissions' do
|
22
|
+
expect(permissions[0]).to receive(:update)
|
23
|
+
expect(permissions[1]).to receive(:update)
|
24
|
+
subject.send('iam:allow', user)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should optionally run on a subset of stacks' do
|
28
|
+
expect(permissions[0]).to receive(:update)
|
29
|
+
expect(permissions[1]).not_to receive(:update)
|
30
|
+
|
31
|
+
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
32
|
+
subject.send('iam:allow', user)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should accept :ssh and :sudo options' do
|
36
|
+
expect(permissions[0]).to receive(:update).with(ssh: true, sudo: false)
|
37
|
+
|
38
|
+
allow(subject).to receive(:options) do
|
39
|
+
{ stack: [stacks[0].name], ssh: true, sudo: false }
|
40
|
+
end
|
41
|
+
subject.send('iam:allow', user)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'iam:lockdown' do
|
46
|
+
let(:stack) do
|
47
|
+
Fabricate(:stack).tap do |stack|
|
48
|
+
allow(stack).to receive(:permissions) { permissions }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
let(:stacks) { [stack] }
|
52
|
+
|
53
|
+
it 'should lock down all stacks' do
|
54
|
+
expect(permissions[0]).to receive(:update).with(ssh: false, sudo: false)
|
55
|
+
expect(permissions[1]).to receive(:update).with(ssh: false, sudo: false)
|
56
|
+
subject.send('iam:lockdown')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should optionally run on a subset of stacks' do
|
60
|
+
expect(permissions[0]).to receive(:update).with(ssh: false, sudo: false)
|
61
|
+
expect(permissions[1]).to receive(:update).with(ssh: false, sudo: false)
|
62
|
+
|
63
|
+
allow(subject).to receive(:options) { { stacks: [stack.name] } }
|
64
|
+
subject.send('iam:lockdown')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OpsWorks::CLI::Agent do
|
4
|
+
context 'recipes' do
|
5
|
+
let(:recipe) { 'hotpockets::install' }
|
6
|
+
let(:stacks) { 2.times.map { Fabricate(:stack) } }
|
7
|
+
|
8
|
+
before { allow(subject).to receive(:say) }
|
9
|
+
before { allow(OpsWorks::Deployment).to receive(:wait) }
|
10
|
+
before { allow(OpsWorks::Stack).to receive(:all) { stacks } }
|
11
|
+
before { allow(OpsWorks::Stack).to receive(:active) { stacks } }
|
12
|
+
|
13
|
+
describe 'recipes:run' do
|
14
|
+
let(:success) { Fabricate(:deployment, status: 'successful') }
|
15
|
+
let(:failure) { Fabricate(:deployment, status: 'failed') }
|
16
|
+
|
17
|
+
it 'should update custom cookbooks on all stacks' do
|
18
|
+
expect(stacks[0]).to receive(:execute_recipe).with(recipe) { success }
|
19
|
+
expect(stacks[1]).to receive(:execute_recipe).with(recipe) { success }
|
20
|
+
subject.send('recipes:run', recipe)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should optionally run on a subset of stacks' do
|
24
|
+
expect(stacks[0]).to receive(:execute_recipe).with(recipe) { success }
|
25
|
+
expect(stacks[1]).not_to receive(:execute_recipe)
|
26
|
+
|
27
|
+
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
28
|
+
subject.send('recipes:run', recipe)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should fail if any update fails' do
|
32
|
+
expect(stacks[0]).to receive(:execute_recipe).with(recipe) { failure }
|
33
|
+
|
34
|
+
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
35
|
+
expect { subject.send('recipes:run', recipe) }.to raise_error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
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.
|
4
|
+
version: 0.3.0
|
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
|
+
date: 2014-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: aws-keychain-util
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,17 +185,16 @@ files:
|
|
171
185
|
- lib/opsworks/cli/agent.rb
|
172
186
|
- lib/opsworks/cli/helpers/keychain.rb
|
173
187
|
- lib/opsworks/cli/helpers/options.rb
|
174
|
-
- lib/opsworks/cli/subcommands/
|
188
|
+
- lib/opsworks/cli/subcommands/apps.rb
|
175
189
|
- lib/opsworks/cli/subcommands/config.rb
|
176
|
-
- lib/opsworks/cli/subcommands/
|
177
|
-
- lib/opsworks/cli/subcommands/
|
178
|
-
- lib/opsworks/cli/subcommands/lockdown.rb
|
179
|
-
- lib/opsworks/cli/subcommands/status.rb
|
190
|
+
- lib/opsworks/cli/subcommands/iam.rb
|
191
|
+
- lib/opsworks/cli/subcommands/recipes.rb
|
180
192
|
- lib/opsworks/cli/subcommands/update.rb
|
181
193
|
- lib/opsworks/cli/subcommands/upgrade_chef.rb
|
182
194
|
- lib/opsworks/cli/version.rb
|
183
195
|
- lib/opsworks/deployment.rb
|
184
196
|
- lib/opsworks/instance.rb
|
197
|
+
- lib/opsworks/layer.rb
|
185
198
|
- lib/opsworks/permission.rb
|
186
199
|
- lib/opsworks/resource.rb
|
187
200
|
- lib/opsworks/stack.rb
|
@@ -191,11 +204,10 @@ files:
|
|
191
204
|
- spec/fabricators/opsworks/permission_fabricator.rb
|
192
205
|
- spec/fabricators/opsworks/stack_fabricator.rb
|
193
206
|
- spec/opsworks/cli/agent_spec.rb
|
194
|
-
- spec/opsworks/cli/subcommands/
|
207
|
+
- spec/opsworks/cli/subcommands/apps_spec.rb
|
195
208
|
- spec/opsworks/cli/subcommands/config_spec.rb
|
196
|
-
- spec/opsworks/cli/subcommands/
|
197
|
-
- spec/opsworks/cli/subcommands/
|
198
|
-
- spec/opsworks/cli/subcommands/lockdown_spec.rb
|
209
|
+
- spec/opsworks/cli/subcommands/iam_spec.rb
|
210
|
+
- spec/opsworks/cli/subcommands/recipes_spec.rb
|
199
211
|
- spec/opsworks/cli/subcommands/update_spec.rb
|
200
212
|
- spec/spec_helper.rb
|
201
213
|
homepage: https://github.com/aptible/opsworks-cli
|
@@ -228,10 +240,9 @@ test_files:
|
|
228
240
|
- spec/fabricators/opsworks/permission_fabricator.rb
|
229
241
|
- spec/fabricators/opsworks/stack_fabricator.rb
|
230
242
|
- spec/opsworks/cli/agent_spec.rb
|
231
|
-
- spec/opsworks/cli/subcommands/
|
243
|
+
- spec/opsworks/cli/subcommands/apps_spec.rb
|
232
244
|
- spec/opsworks/cli/subcommands/config_spec.rb
|
233
|
-
- spec/opsworks/cli/subcommands/
|
234
|
-
- spec/opsworks/cli/subcommands/
|
235
|
-
- spec/opsworks/cli/subcommands/lockdown_spec.rb
|
245
|
+
- spec/opsworks/cli/subcommands/iam_spec.rb
|
246
|
+
- spec/opsworks/cli/subcommands/recipes_spec.rb
|
236
247
|
- spec/opsworks/cli/subcommands/update_spec.rb
|
237
248
|
- spec/spec_helper.rb
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'opsworks/deployment'
|
2
|
-
|
3
|
-
module OpsWorks
|
4
|
-
module CLI
|
5
|
-
module Subcommands
|
6
|
-
module Deploy
|
7
|
-
# rubocop:disable MethodLength
|
8
|
-
# rubocop:disable CyclomaticComplexity
|
9
|
-
def self.included(thor)
|
10
|
-
thor.class_eval do
|
11
|
-
desc 'deploy APP [--stack STACK]', 'Deploy an OpsWorks app'
|
12
|
-
option :stack, type: :array
|
13
|
-
def deploy(name)
|
14
|
-
fetch_keychain_credentials unless env_credentials?
|
15
|
-
stacks = parse_stacks(options.merge(active: true))
|
16
|
-
deployments = stacks.map do |stack|
|
17
|
-
next unless (app = stack.find_app_by_name(name))
|
18
|
-
say "Deploying to #{stack.name}..."
|
19
|
-
stack.deploy_app(app)
|
20
|
-
end
|
21
|
-
deployments.compact!
|
22
|
-
OpsWorks::Deployment.wait(deployments)
|
23
|
-
unless deployments.all?(&:success?)
|
24
|
-
failures = []
|
25
|
-
deployments.each_with_index do |deployment, i|
|
26
|
-
failures << stacks[i].name unless deployment.success?
|
27
|
-
end
|
28
|
-
fail "Deploy failed on #{failures.join(', ')}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
# rubocop:enable CyclomaticComplexity
|
34
|
-
# rubocop:enable MethodLength
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'opsworks/permission'
|
2
|
-
|
3
|
-
module OpsWorks
|
4
|
-
module CLI
|
5
|
-
module Subcommands
|
6
|
-
module Lockdown
|
7
|
-
# rubocop:disable MethodLength
|
8
|
-
# rubocop:disable CyclomaticComplexity
|
9
|
-
def self.included(thor)
|
10
|
-
thor.class_eval do
|
11
|
-
desc 'lockdown [--stack STACK]', 'Remove all stack permissions'
|
12
|
-
option :stack, type: :array
|
13
|
-
def lockdown
|
14
|
-
fetch_keychain_credentials unless env_credentials?
|
15
|
-
stacks = parse_stacks(options.merge(active: true))
|
16
|
-
stacks.each do |stack|
|
17
|
-
say "Locking down #{stack.name}..."
|
18
|
-
stack.permissions.each do |permission|
|
19
|
-
permission.update(ssh: false, sudo: false)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
# rubocop:enable CyclomaticComplexity
|
26
|
-
# rubocop:enable MethodLength
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module OpsWorks
|
2
|
-
module CLI
|
3
|
-
module Subcommands
|
4
|
-
module Status
|
5
|
-
# rubocop:disable MethodLength
|
6
|
-
# rubocop:disable CyclomaticComplexity
|
7
|
-
def self.included(thor)
|
8
|
-
thor.class_eval do
|
9
|
-
include Helpers::Keychain
|
10
|
-
include Helpers::Options
|
11
|
-
|
12
|
-
desc 'status APP [--stack STACK]',
|
13
|
-
'Display the most recent deployment of an app'
|
14
|
-
option :stack, type: :array
|
15
|
-
def status(name)
|
16
|
-
fetch_keychain_credentials unless env_credentials?
|
17
|
-
|
18
|
-
table = parse_stacks(options).map do |stack|
|
19
|
-
next unless (app = stack.find_app_by_name(name))
|
20
|
-
if (deployment = app.last_deployment)
|
21
|
-
deployed_at = formatted_time(deployment.created_at)
|
22
|
-
else
|
23
|
-
deployed_at = '-'
|
24
|
-
end
|
25
|
-
[stack.name, name, "(#{app.revision})", deployed_at]
|
26
|
-
end
|
27
|
-
# Sort output in descending date order
|
28
|
-
table.compact!
|
29
|
-
table.sort! { |x, y| y.last <=> x.last }
|
30
|
-
print_table table
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def formatted_time(timestamp)
|
36
|
-
timestamp.strftime('%Y-%m-%d %H:%M:%S %Z')
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
# rubocop:enable CyclomaticComplexity
|
41
|
-
# rubocop:enable MethodLength
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OpsWorks::CLI::Agent do
|
4
|
-
describe '#allow' do
|
5
|
-
let(:permissions) { 2.times.map { Fabricate(:permission) } }
|
6
|
-
let(:user) { permissions[0].user }
|
7
|
-
let(:stacks) do
|
8
|
-
2.times.map do |i|
|
9
|
-
Fabricate(:stack).tap do |stack|
|
10
|
-
allow(stack).to receive(:find_permission_by_user) { permissions[i] }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
before { allow(subject).to receive(:say) }
|
16
|
-
before { allow(OpsWorks::Stack).to receive(:all) { stacks } }
|
17
|
-
before { allow(OpsWorks::Stack).to receive(:active) { stacks } }
|
18
|
-
|
19
|
-
it 'should update all matching permissions' do
|
20
|
-
expect(permissions[0]).to receive(:update)
|
21
|
-
expect(permissions[1]).to receive(:update)
|
22
|
-
subject.allow(user)
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should optionally run on a subset of stacks' do
|
26
|
-
expect(permissions[0]).to receive(:update)
|
27
|
-
expect(permissions[1]).not_to receive(:update)
|
28
|
-
|
29
|
-
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
30
|
-
subject.allow(user)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should accept :ssh and :sudo options' do
|
34
|
-
expect(permissions[0]).to receive(:update).with(ssh: true, sudo: false)
|
35
|
-
|
36
|
-
allow(subject).to receive(:options) do
|
37
|
-
{ stack: [stacks[0].name], ssh: true, sudo: false }
|
38
|
-
end
|
39
|
-
subject.allow(user)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OpsWorks::CLI::Agent do
|
4
|
-
describe '#deploy' do
|
5
|
-
let(:app_name) { 'aptible' }
|
6
|
-
let(:app) { Fabricate(:app, name: app_name) }
|
7
|
-
|
8
|
-
let(:stacks) { 2.times.map { Fabricate(:stack) } }
|
9
|
-
let(:deployment) { Fabricate(:deployment, status: 'successful') }
|
10
|
-
|
11
|
-
before { allow(subject).to receive(:say) }
|
12
|
-
before { allow(OpsWorks::Deployment).to receive(:wait) }
|
13
|
-
before { allow(OpsWorks::Stack).to receive(:all) { stacks } }
|
14
|
-
before { allow(OpsWorks::Stack).to receive(:active) { stacks } }
|
15
|
-
|
16
|
-
before { stacks.each { |stack| allow(stack).to receive(:apps) { [app] } } }
|
17
|
-
|
18
|
-
it 'should update custom cookbooks on all stacks' do
|
19
|
-
expect(stacks[0]).to receive(:deploy_app).with(app) { deployment }
|
20
|
-
expect(stacks[1]).to receive(:deploy_app).with(app) { deployment }
|
21
|
-
subject.deploy(app_name)
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'should not fail if some stacks are inactive' do
|
25
|
-
allow(OpsWorks::Stack).to receive(:active) { [stacks[0]] }
|
26
|
-
expect(stacks[0]).to receive(:deploy_app).with(app) { deployment }
|
27
|
-
expect(stacks[1]).not_to receive(:deploy_app)
|
28
|
-
subject.deploy(app_name)
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should optionally run on a subset of stacks' do
|
32
|
-
expect(stacks[0]).to receive(:deploy_app).with(app) { deployment }
|
33
|
-
expect(stacks[1]).not_to receive(:deploy_app)
|
34
|
-
|
35
|
-
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
36
|
-
subject.deploy(app_name)
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should not fail if a stack does not have the app' do
|
40
|
-
allow(stacks[0]).to receive(:apps) { [] }
|
41
|
-
expect(stacks[1]).to receive(:deploy_app).with(app) { deployment }
|
42
|
-
expect { subject.deploy(app_name) }.not_to raise_error
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'should fail if any update fails' do
|
46
|
-
failure = Fabricate(:deployment, status: 'failed')
|
47
|
-
expect(stacks[0]).to receive(:deploy_app).with(app) { failure }
|
48
|
-
|
49
|
-
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
50
|
-
expect { subject.deploy(app_name) }.to raise_error
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OpsWorks::CLI::Agent do
|
4
|
-
describe '#exec' do
|
5
|
-
let(:recipe) { 'hotpockets::install' }
|
6
|
-
|
7
|
-
let(:stacks) { 2.times.map { Fabricate(:stack) } }
|
8
|
-
let(:deployment) { Fabricate(:deployment, status: 'successful') }
|
9
|
-
|
10
|
-
before { allow(subject).to receive(:say) }
|
11
|
-
before { allow(OpsWorks::Deployment).to receive(:wait) }
|
12
|
-
before { allow(OpsWorks::Stack).to receive(:all) { stacks } }
|
13
|
-
before { allow(OpsWorks::Stack).to receive(:active) { stacks } }
|
14
|
-
|
15
|
-
it 'should update custom cookbooks on all stacks' do
|
16
|
-
expect(stacks[0]).to receive(:execute_recipe).with(recipe) { deployment }
|
17
|
-
expect(stacks[1]).to receive(:execute_recipe).with(recipe) { deployment }
|
18
|
-
subject.exec(recipe)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'should optionally run on a subset of stacks' do
|
22
|
-
expect(stacks[0]).to receive(:execute_recipe).with(recipe) { deployment }
|
23
|
-
expect(stacks[1]).not_to receive(:execute_recipe)
|
24
|
-
|
25
|
-
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
26
|
-
subject.exec(recipe)
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'should fail if any update fails' do
|
30
|
-
failure = Fabricate(:deployment, status: 'failed')
|
31
|
-
expect(stacks[0]).to receive(:execute_recipe).with(recipe) { failure }
|
32
|
-
|
33
|
-
allow(subject).to receive(:options) { { stack: [stacks[0].name] } }
|
34
|
-
expect { subject.exec(recipe) }.to raise_error
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OpsWorks::CLI::Agent do
|
4
|
-
describe '#lockdown' do
|
5
|
-
let(:permissions) { 2.times.map { Fabricate(:permission) } }
|
6
|
-
let(:user) { permissions[0].user }
|
7
|
-
let(:stack) do
|
8
|
-
Fabricate(:stack).tap do |stack|
|
9
|
-
allow(stack).to receive(:permissions) { permissions }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
before { allow(subject).to receive(:say) }
|
14
|
-
before { allow(OpsWorks::Stack).to receive(:all) { [stack] } }
|
15
|
-
before { allow(OpsWorks::Stack).to receive(:active) { [stack] } }
|
16
|
-
|
17
|
-
it 'should lock down all stacks' do
|
18
|
-
expect(permissions[0]).to receive(:update).with(ssh: false, sudo: false)
|
19
|
-
expect(permissions[1]).to receive(:update).with(ssh: false, sudo: false)
|
20
|
-
subject.lockdown
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'should optionally run on a subset of stacks' do
|
24
|
-
expect(permissions[0]).to receive(:update).with(ssh: false, sudo: false)
|
25
|
-
expect(permissions[1]).to receive(:update).with(ssh: false, sudo: false)
|
26
|
-
|
27
|
-
allow(subject).to receive(:options) { { stacks: [stack.name] } }
|
28
|
-
subject.lockdown
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|