simple_deploy 0.6.7 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/lib/simple_deploy/cli/create.rb +30 -10
- data/lib/simple_deploy/cli/execute.rb +4 -2
- data/lib/simple_deploy/cli/outputs.rb +24 -10
- data/lib/simple_deploy/exceptions.rb +6 -0
- data/lib/simple_deploy/misc/attribute_merger.rb +45 -0
- data/lib/simple_deploy/misc.rb +1 -0
- data/lib/simple_deploy/stack/output_mapper.rb +88 -0
- data/lib/simple_deploy/stack/ssh.rb +16 -1
- data/lib/simple_deploy/stack.rb +1 -0
- data/lib/simple_deploy/template.rb +21 -0
- data/lib/simple_deploy/version.rb +1 -1
- data/lib/simple_deploy.rb +2 -0
- data/spec/cli/create_spec.rb +51 -0
- data/spec/cli/outputs_spec.rb +48 -0
- data/spec/misc/attribute_merger_spec.rb +41 -0
- data/spec/stack/output_mapper_spec.rb +108 -0
- data/spec/stack/ssh_spec.rb +79 -38
- data/spec/template_spec.rb +24 -0
- metadata +35 -51
data/CHANGELOG
CHANGED
@@ -17,8 +17,13 @@ simple_deploy create -n STACK_NAME -t PATH_TO_TEMPLATE -e ENVIRONMENT -a KEY1=VA
|
|
17
17
|
|
18
18
|
EOS
|
19
19
|
opt :help, "Display Help"
|
20
|
-
opt :attributes, "= seperated attribute and it's value
|
20
|
+
opt :attributes, "= seperated attribute(s) and it's value. \
|
21
|
+
Can be specified multiple times.", :type => :string,
|
21
22
|
:multi => true
|
23
|
+
opt :input_stack, "Read outputs from given stack(s) and map them \
|
24
|
+
to parameter inputs in the new stack. These will be passed to inputs with \
|
25
|
+
matching or pluralized names. Can be specified multiple times.", :type => :string,
|
26
|
+
:multi => true
|
22
27
|
opt :environment, "Set the target environment", :type => :string
|
23
28
|
opt :log_level, "Log level: debug, info, warn, error", :type => :string,
|
24
29
|
:default => 'info'
|
@@ -29,29 +34,44 @@ EOS
|
|
29
34
|
valid_options? :provided => @opts,
|
30
35
|
:required => [:environment, :name, :template]
|
31
36
|
|
32
|
-
config = Config.new.environment @opts[:environment]
|
33
|
-
|
34
|
-
attributes = parse_attributes :attributes => @opts[:attributes]
|
37
|
+
@config = Config.new.environment @opts[:environment]
|
35
38
|
|
36
39
|
stack = Stack.new :environment => @opts[:environment],
|
37
40
|
:name => @opts[:name],
|
38
|
-
:config => config,
|
41
|
+
:config => @config,
|
39
42
|
:logger => logger
|
40
43
|
|
41
44
|
rescue_stackster_exceptions_and_exit do
|
42
|
-
stack.create :attributes =>
|
45
|
+
stack.create :attributes => merged_attributes,
|
43
46
|
:template => @opts[:template]
|
44
47
|
end
|
45
48
|
end
|
46
49
|
|
47
|
-
def logger
|
48
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
49
|
-
end
|
50
|
-
|
51
50
|
def command_summary
|
52
51
|
'Create a new stack'
|
53
52
|
end
|
54
53
|
|
54
|
+
private
|
55
|
+
|
56
|
+
def merged_attributes
|
57
|
+
provided_attributes = parse_attributes :attributes => @opts[:attributes]
|
58
|
+
|
59
|
+
attribute_merger.merge :attributes => provided_attributes,
|
60
|
+
:config => @config,
|
61
|
+
:logger => @logger,
|
62
|
+
:environment => @opts[:environment],
|
63
|
+
:input_stacks => @opts[:input_stack],
|
64
|
+
:template => @opts[:template]
|
65
|
+
end
|
66
|
+
|
67
|
+
def attribute_merger
|
68
|
+
SimpleDeploy::Misc::AttributeMerger.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def logger
|
72
|
+
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
73
|
+
end
|
74
|
+
|
55
75
|
end
|
56
76
|
|
57
77
|
end
|
@@ -50,8 +50,10 @@ EOS
|
|
50
50
|
:internal => @opts[:internal]
|
51
51
|
|
52
52
|
begin
|
53
|
-
stack.execute :command => @opts[:command],
|
54
|
-
|
53
|
+
unless stack.execute :command => @opts[:command],
|
54
|
+
:sudo => @opts[:sudo]
|
55
|
+
exit 1
|
56
|
+
end
|
55
57
|
rescue SimpleDeploy::Exceptions::NoInstances
|
56
58
|
logger.error "Stack has no running instances."
|
57
59
|
exit 1
|
@@ -17,6 +17,8 @@ simple_deploy outputs -n STACK_NAME -e ENVIRONMENT
|
|
17
17
|
|
18
18
|
EOS
|
19
19
|
opt :help, "Display Help"
|
20
|
+
opt :as_command_args,
|
21
|
+
"Displays the attributes in a format suitable for using on the command line"
|
20
22
|
opt :environment, "Set the target environment", :type => :string
|
21
23
|
opt :log_level, "Log level: debug, info, warn, error", :type => :string,
|
22
24
|
:default => 'warn'
|
@@ -34,25 +36,37 @@ EOS
|
|
34
36
|
:logger => logger
|
35
37
|
|
36
38
|
rescue_stackster_exceptions_and_exit do
|
37
|
-
outputs = stack.outputs
|
39
|
+
@outputs = stack.outputs
|
38
40
|
|
39
|
-
logger.info "No outputs." unless outputs.any?
|
41
|
+
logger.info "No outputs." unless @outputs.any?
|
40
42
|
|
41
|
-
|
42
|
-
puts "%s: %s" % [hash['OutputKey'], hash['OutputValue']]
|
43
|
-
end
|
43
|
+
@opts[:as_command_args] ? command_args_output : default_output
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
def logger
|
48
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
49
|
-
end
|
50
|
-
|
51
47
|
def command_summary
|
52
48
|
'Show outputs of a stack'
|
53
49
|
end
|
54
50
|
|
55
|
-
|
51
|
+
private
|
52
|
+
|
53
|
+
def command_args_output
|
54
|
+
@outputs.each do |hash|
|
55
|
+
print "-a %s=%s " % [hash['OutputKey'], hash['OutputValue']]
|
56
|
+
end
|
57
|
+
puts ""
|
58
|
+
end
|
56
59
|
|
60
|
+
def default_output
|
61
|
+
@outputs.each do |hash|
|
62
|
+
puts "%s: %s" % [hash['OutputKey'], hash['OutputValue']]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def logger
|
67
|
+
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
57
71
|
end
|
58
72
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module SimpleDeploy
|
2
|
+
module Misc
|
3
|
+
class AttributeMerger
|
4
|
+
|
5
|
+
def merge(args)
|
6
|
+
@attributes = args[:attributes]
|
7
|
+
@config = args[:config]
|
8
|
+
@environment = args[:environment]
|
9
|
+
@logger = args[:logger]
|
10
|
+
@input_stacks = args[:input_stacks]
|
11
|
+
@template = args[:template]
|
12
|
+
|
13
|
+
combine_provided_and_mapped_attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def combine_provided_and_mapped_attributes
|
19
|
+
@attributes + mapped_attributes_not_provided
|
20
|
+
end
|
21
|
+
|
22
|
+
def mapped_attributes
|
23
|
+
mapper.map_outputs_from_stacks :stacks => @input_stacks,
|
24
|
+
:template => @template
|
25
|
+
end
|
26
|
+
|
27
|
+
def mapped_attributes_not_provided
|
28
|
+
mapped_attributes.reject do |a|
|
29
|
+
provided_attribute_keys.include? a.keys.first
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def provided_attribute_keys
|
34
|
+
@attributes.map {|a| a.keys.first}
|
35
|
+
end
|
36
|
+
|
37
|
+
def mapper
|
38
|
+
@om ||= Stack::OutputMapper.new :environment => @environment,
|
39
|
+
:config => @config,
|
40
|
+
:logger => @logger
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'simple_deploy/misc/attribute_merger'
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module SimpleDeploy
|
2
|
+
class Stack
|
3
|
+
class OutputMapper
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
@config = args[:config]
|
7
|
+
@environment = args[:environment]
|
8
|
+
@logger = args[:logger]
|
9
|
+
end
|
10
|
+
|
11
|
+
def map_outputs_from_stacks(args)
|
12
|
+
@stacks = args[:stacks]
|
13
|
+
@template = args[:template]
|
14
|
+
@results = {}
|
15
|
+
|
16
|
+
merge_stacks_outputs
|
17
|
+
|
18
|
+
pluralize_keys
|
19
|
+
|
20
|
+
prune_unused_parameters
|
21
|
+
|
22
|
+
@results.each_pair do |key, value|
|
23
|
+
@logger.info "Mapping output '#{key}' to input parameter with value '#{value}'."
|
24
|
+
end
|
25
|
+
|
26
|
+
@results.map { |x| { x.first => x.last } }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def merge_stacks_outputs
|
32
|
+
count = 0
|
33
|
+
|
34
|
+
@stacks.each do |s|
|
35
|
+
count += 1
|
36
|
+
@logger.info "Reading outputs from stack '#{s}'."
|
37
|
+
stack = Stack.new :environment => @environment,
|
38
|
+
:config => @config,
|
39
|
+
:logger => @logger,
|
40
|
+
:name => s
|
41
|
+
stack.wait_for_stable
|
42
|
+
merge_outputs stack
|
43
|
+
SimpleDeploy::Backoff.exp_periods(count < 5 ? count : 5) do |backoff|
|
44
|
+
@logger.info "Backing off for #{backoff} seconds."
|
45
|
+
sleep backoff
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def merge_outputs(stack)
|
51
|
+
stack.outputs.each do |output|
|
52
|
+
key = output['OutputKey']
|
53
|
+
value = output['OutputValue']
|
54
|
+
|
55
|
+
@logger.debug "Read output #{key}=#{value}."
|
56
|
+
|
57
|
+
if @results.has_key? key
|
58
|
+
@results[key] += ",#{value}"
|
59
|
+
else
|
60
|
+
@results[key] = value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def pluralize_keys
|
66
|
+
plural_params = @results.each_with_object({}) do |results, new|
|
67
|
+
key = results.first
|
68
|
+
pluralized_key = "#{key}s"
|
69
|
+
|
70
|
+
if template_parameters.include? pluralized_key
|
71
|
+
new[pluralized_key] = results[1]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@results.merge! plural_params
|
76
|
+
end
|
77
|
+
|
78
|
+
def prune_unused_parameters
|
79
|
+
@results.select! { |key| template_parameters.include? key }
|
80
|
+
end
|
81
|
+
|
82
|
+
def template_parameters
|
83
|
+
@parameters ||= Template.new(:file => @template).parameters
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -20,7 +20,22 @@ module SimpleDeploy
|
|
20
20
|
def execute(args)
|
21
21
|
return false if @instances.nil? || @instances.empty?
|
22
22
|
create_execute_task args
|
23
|
-
|
23
|
+
|
24
|
+
status = false
|
25
|
+
|
26
|
+
begin
|
27
|
+
@task.execute
|
28
|
+
status = true
|
29
|
+
@logger.info "Command executed against instances successfully."
|
30
|
+
rescue ::Capistrano::CommandError => error
|
31
|
+
@logger.error "Error running execute statement: #{error}"
|
32
|
+
rescue ::Capistrano::ConnectionError => error
|
33
|
+
@logger.error "Error connecting to instances: #{error}"
|
34
|
+
rescue ::Capistrano::Error => error
|
35
|
+
@logger.error "Error: #{error}"
|
36
|
+
end
|
37
|
+
|
38
|
+
status
|
24
39
|
end
|
25
40
|
|
26
41
|
private
|
data/lib/simple_deploy/stack.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module SimpleDeploy
|
2
|
+
class Template
|
3
|
+
def initialize(args)
|
4
|
+
@file = args[:file]
|
5
|
+
end
|
6
|
+
|
7
|
+
def parameters
|
8
|
+
parsed_template_contents.fetch('Parameters', {}).keys
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def parsed_template_contents
|
14
|
+
JSON.parse contents
|
15
|
+
end
|
16
|
+
|
17
|
+
def contents
|
18
|
+
@contents ||= IO.read @file
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/simple_deploy.rb
CHANGED
@@ -3,6 +3,8 @@ require 'simple_deploy/exceptions'
|
|
3
3
|
require 'simple_deploy/config'
|
4
4
|
require 'simple_deploy/artifact'
|
5
5
|
require 'simple_deploy/stack'
|
6
|
+
require 'simple_deploy/misc'
|
7
|
+
require 'simple_deploy/template'
|
6
8
|
require 'simple_deploy/notifier'
|
7
9
|
require 'simple_deploy/logger'
|
8
10
|
require 'simple_deploy/version'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleDeploy::CLI::Create do
|
4
|
+
before do
|
5
|
+
@config_object = mock 'config'
|
6
|
+
@config_env = mock 'environment config'
|
7
|
+
@stack_mock = mock 'stack'
|
8
|
+
@attribute_merger_mock = mock 'attribute merger'
|
9
|
+
@logger = stub 'logger', :info => true
|
10
|
+
|
11
|
+
@options = { :attributes => [ 'attr1=val1' ],
|
12
|
+
:input_stack => [ 'stack1' ],
|
13
|
+
:environment => 'test',
|
14
|
+
:name => 'mytest',
|
15
|
+
:log_level => 'info',
|
16
|
+
:template => '/tmp/test.json' }
|
17
|
+
Trollop.stub :options => @options
|
18
|
+
SimpleDeploy::Config.stub :new => @config_object
|
19
|
+
SimpleDeploy::SimpleDeployLogger.should_receive(:new).
|
20
|
+
with(:log_level => 'info').
|
21
|
+
and_return @logger
|
22
|
+
@config_object.stub :environments => { 'test' => 'config_data' }
|
23
|
+
@config_object.should_receive(:environment).with('test').
|
24
|
+
and_return 'config_data'
|
25
|
+
SimpleDeploy::Stack.should_receive(:new).
|
26
|
+
with(:environment => 'test',
|
27
|
+
:name => 'mytest',
|
28
|
+
:config => 'config_data',
|
29
|
+
:logger => @logger).
|
30
|
+
and_return(@stack_mock)
|
31
|
+
SimpleDeploy::Misc::AttributeMerger.stub :new => @attribute_merger_mock
|
32
|
+
merge_options = { :attributes => [ { "attr1" => "val1" } ],
|
33
|
+
:config => 'config_data',
|
34
|
+
:logger => @logger,
|
35
|
+
:environment => 'test',
|
36
|
+
:template => '/tmp/test.json',
|
37
|
+
:input_stacks => ["stack1"] }
|
38
|
+
@attribute_merger_mock.should_receive(:merge).with(merge_options).
|
39
|
+
and_return({ "attr1" => "val1",
|
40
|
+
"attr2" => "val2" })
|
41
|
+
@create = SimpleDeploy::CLI::Create.new
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should create a stack with provided and merged attributes" do
|
45
|
+
@stack_mock.should_receive(:create).
|
46
|
+
with({ :attributes => { "attr1" => "val1",
|
47
|
+
"attr2" => "val2" },
|
48
|
+
:template => '/tmp/test.json' })
|
49
|
+
@create.create
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'simple_deploy/cli'
|
3
|
+
|
4
|
+
describe SimpleDeploy::CLI::Outputs do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@config_object = mock 'config'
|
8
|
+
@config_env = mock 'environment config'
|
9
|
+
@stack = mock 'stack'
|
10
|
+
@logger = stub 'logger'
|
11
|
+
@options = { :environment => 'test',
|
12
|
+
:log_level => 'info',
|
13
|
+
:name => 'mytest' }
|
14
|
+
@data = [{ 'OutputKey' => 'key1', 'OutputValue' => 'value1' },
|
15
|
+
{ 'OutputKey' => 'key2', 'OutputValue' => 'value2' }]
|
16
|
+
Trollop.stub :options => @options
|
17
|
+
@config_object.stub(:environments => { 'test' => 'data' })
|
18
|
+
SimpleDeploy::Config.stub :new => @config_object
|
19
|
+
SimpleDeploy::SimpleDeployLogger.should_receive(:new).
|
20
|
+
with(:log_level => 'info').
|
21
|
+
and_return @logger
|
22
|
+
SimpleDeploy::Stack.should_receive(:new).
|
23
|
+
with(:environment => 'test',
|
24
|
+
:name => 'mytest',
|
25
|
+
:config => @config_env,
|
26
|
+
:logger => @logger).
|
27
|
+
and_return(@stack)
|
28
|
+
@stack.stub :outputs => @data
|
29
|
+
@config_object.should_receive(:environment).with('test').
|
30
|
+
and_return @config_env
|
31
|
+
@outputs = SimpleDeploy::CLI::Outputs.new
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should successfully return the show command with default values" do
|
35
|
+
@outputs.should_receive(:puts).with('key1: value1')
|
36
|
+
@outputs.should_receive(:puts).with('key2: value2')
|
37
|
+
@outputs.show
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should successfully return the show command with as_command_args" do
|
41
|
+
@options[:as_command_args] = true
|
42
|
+
@outputs.should_receive(:print).with('-a key1=value1 ')
|
43
|
+
@outputs.should_receive(:print).with('-a key2=value2 ')
|
44
|
+
@outputs.should_receive(:puts).with('')
|
45
|
+
@outputs.show
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleDeploy::Misc::AttributeMerger do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_mock = mock 'config'
|
7
|
+
@mapper_mock = mock 'mapper'
|
8
|
+
@logger_stub = stub 'logger', :info => true
|
9
|
+
|
10
|
+
@stacks = ['stack1', 'stack2']
|
11
|
+
@options = { :config => @config_mock,
|
12
|
+
:environment => 'default',
|
13
|
+
:logger => @logger_stub,
|
14
|
+
:attributes => [ { 'attrib1' => 'val1' } ],
|
15
|
+
:input_stacks => @stacks,
|
16
|
+
:template => '/tmp/file.json' }
|
17
|
+
SimpleDeploy::Stack::OutputMapper.should_receive(:new).
|
18
|
+
with(:environment => @options[:environment],
|
19
|
+
:config => @options[:config],
|
20
|
+
:logger => @options[:logger]).
|
21
|
+
and_return @mapper_mock
|
22
|
+
@merger = SimpleDeploy::Misc::AttributeMerger.new
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return the consolidated list of attributes" do
|
26
|
+
@mapper_mock.should_receive(:map_outputs_from_stacks).
|
27
|
+
with(:stacks => @options[:input_stacks],
|
28
|
+
:template => @options[:template]).
|
29
|
+
and_return [ { 'attrib2' => 'val2' } ]
|
30
|
+
@merger.merge(@options).should == [ { 'attrib1' => 'val1' },
|
31
|
+
{ 'attrib2' => 'val2' } ]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return provided attributes over outputs" do
|
35
|
+
@mapper_mock.should_receive(:map_outputs_from_stacks).
|
36
|
+
with(:stacks => @options[:input_stacks],
|
37
|
+
:template => @options[:template]).
|
38
|
+
and_return [ { 'attrib1' => 'val2' } ]
|
39
|
+
@merger.merge(@options).should == [ { 'attrib1' => 'val1' } ]
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleDeploy::Stack::OutputMapper do
|
4
|
+
before do
|
5
|
+
@config_mock = mock 'config'
|
6
|
+
@logger_stub = stub 'logger', :debug => true, :info => true
|
7
|
+
|
8
|
+
stack1_outputs = [ { 'OutputKey' => 'Test1', 'OutputValue' => 'val1' },
|
9
|
+
{ 'OutputKey' => 'Nother', 'OutputValue' => 'another' } ]
|
10
|
+
|
11
|
+
stack2_outputs = [ { 'OutputKey' => 'Test2', 'OutputValue' => 'val2' },
|
12
|
+
{ 'OutputKey' => 'NotMe', 'OutputValue' => 'another' } ]
|
13
|
+
|
14
|
+
stack3_outputs = [ { 'OutputKey' => 'Test1', 'OutputValue' => 'valA' } ]
|
15
|
+
|
16
|
+
stack4_outputs = [ { 'OutputKey' => 'Test', 'OutputValue' => 'val' } ]
|
17
|
+
|
18
|
+
@stack1_stub = stub 'stack1', :outputs => stack1_outputs, :wait_for_stable => true
|
19
|
+
@stack2_stub = stub 'stack2', :outputs => stack2_outputs, :wait_for_stable => true
|
20
|
+
@stack3_stub = stub 'stack3', :outputs => stack3_outputs, :wait_for_stable => true
|
21
|
+
@stack4_stub = stub 'stack4', :outputs => stack4_outputs, :wait_for_stable => true
|
22
|
+
|
23
|
+
@template_stub = stub 'template', :parameters => ["Test1", "Test2", "Tests"]
|
24
|
+
|
25
|
+
@mapper = SimpleDeploy::Stack::OutputMapper.new :config => @config_mock,
|
26
|
+
:environment => 'default',
|
27
|
+
:logger => @logger_stub
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when provided stacks" do
|
31
|
+
before do
|
32
|
+
SimpleDeploy::Template.should_receive(:new).
|
33
|
+
with(:file => '/tmp/file.json').
|
34
|
+
and_return @template_stub
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return the outputs which match parameters" do
|
38
|
+
SimpleDeploy::Stack.should_receive(:new).
|
39
|
+
with(:environment => 'default',
|
40
|
+
:config => @config_mock,
|
41
|
+
:logger => @logger_stub,
|
42
|
+
:name => 'stack1').
|
43
|
+
and_return @stack1_stub
|
44
|
+
@mapper.should_receive(:sleep)
|
45
|
+
@mapper.map_outputs_from_stacks(:stacks => ['stack1'],
|
46
|
+
:template => '/tmp/file.json').
|
47
|
+
should == [{ 'Test1' => 'val1' }]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return the outputs which match pluralized parameters" do
|
51
|
+
SimpleDeploy::Stack.should_receive(:new).
|
52
|
+
with(:environment => 'default',
|
53
|
+
:config => @config_mock,
|
54
|
+
:logger => @logger_stub,
|
55
|
+
:name => 'stack4').
|
56
|
+
and_return @stack4_stub
|
57
|
+
@mapper.should_receive(:sleep)
|
58
|
+
@mapper.map_outputs_from_stacks(:stacks => ['stack4'],
|
59
|
+
:template => '/tmp/file.json').
|
60
|
+
should == [{ 'Tests' => 'val' }]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return the outputs which match parameters from multiple stacks" do
|
64
|
+
SimpleDeploy::Stack.should_receive(:new).
|
65
|
+
with(:environment => 'default',
|
66
|
+
:config => @config_mock,
|
67
|
+
:logger => @logger_stub,
|
68
|
+
:name => 'stack1').
|
69
|
+
and_return @stack1_stub
|
70
|
+
SimpleDeploy::Stack.should_receive(:new).
|
71
|
+
with(:environment => 'default',
|
72
|
+
:config => @config_mock,
|
73
|
+
:logger => @logger_stub,
|
74
|
+
:name => 'stack2').
|
75
|
+
and_return @stack2_stub
|
76
|
+
@mapper.should_receive(:sleep).exactly(3).times
|
77
|
+
@mapper.map_outputs_from_stacks(:stacks => ['stack1', 'stack2'],
|
78
|
+
:template => '/tmp/file.json').
|
79
|
+
should == [{ 'Test1' => 'val1' }, {'Test2' => 'val2' }]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should concatenate multiple outputs of same name into CSV" do
|
83
|
+
SimpleDeploy::Stack.should_receive(:new).
|
84
|
+
with(:environment => 'default',
|
85
|
+
:config => @config_mock,
|
86
|
+
:logger => @logger_stub,
|
87
|
+
:name => 'stack1').
|
88
|
+
and_return @stack1_stub
|
89
|
+
SimpleDeploy::Stack.should_receive(:new).
|
90
|
+
with(:environment => 'default',
|
91
|
+
:config => @config_mock,
|
92
|
+
:logger => @logger_stub,
|
93
|
+
:name => 'stack3').
|
94
|
+
and_return @stack3_stub
|
95
|
+
@mapper.should_receive(:sleep).exactly(3).times
|
96
|
+
@mapper.map_outputs_from_stacks(:stacks => ['stack1', 'stack3'],
|
97
|
+
:template => '/tmp/file.json').
|
98
|
+
should == [{ 'Test1' => 'val1,valA' }]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return an empty hash if no stacks are specified" do
|
103
|
+
@mapper.map_outputs_from_stacks(:stacks => [],
|
104
|
+
:template => '/tmp/file.json').
|
105
|
+
should == []
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
data/spec/stack/ssh_spec.rb
CHANGED
@@ -6,77 +6,118 @@ describe SimpleDeploy::Stack::SSH do
|
|
6
6
|
@task_mock = mock 'task'
|
7
7
|
@config_mock = mock 'config'
|
8
8
|
@logger_stub = stub 'logger', :debug => true,
|
9
|
-
|
10
|
-
|
9
|
+
:info => true,
|
10
|
+
:error => true
|
11
11
|
@config_mock.stub :logger => @logger_stub
|
12
12
|
@config_mock.should_receive(:region).
|
13
|
-
|
14
|
-
|
13
|
+
with('test-env').
|
14
|
+
and_return 'test-us-west-1'
|
15
15
|
@stack_mock.stub :attributes => { :ssh_gateway => false }
|
16
|
+
@options = { :config => @config_mock,
|
17
|
+
:instances => ['1.2.3.4', '4.3.2.1'],
|
18
|
+
:environment => 'test-env',
|
19
|
+
:ssh_user => 'user',
|
20
|
+
:ssh_key => 'key',
|
21
|
+
:stack => @stack_mock,
|
22
|
+
:name => 'test-stack' }
|
23
|
+
@task_logger_mock = mock 'task_logger'
|
24
|
+
@ssh_options = Hash.new
|
25
|
+
@task_mock.stub :logger => @task_logger_mock,
|
26
|
+
:variables => @ssh_options
|
16
27
|
end
|
17
28
|
|
18
29
|
context "when unsuccessful" do
|
19
30
|
it "should return false when no running instances running" do
|
20
|
-
|
21
|
-
|
22
|
-
:environment => 'test-env',
|
23
|
-
:ssh_user => 'user',
|
24
|
-
:ssh_key => 'key',
|
25
|
-
:stack => @stack_mock,
|
26
|
-
:name => 'test-stack' }
|
27
|
-
@ssh = SimpleDeploy::Stack::SSH.new options
|
31
|
+
@ssh = SimpleDeploy::Stack::SSH.new @options.merge({ :instances => [] })
|
32
|
+
|
28
33
|
@ssh.execute(:sudo => true, :command => 'uname').should be_false
|
29
34
|
end
|
35
|
+
|
36
|
+
context "with capistrano configured" do
|
37
|
+
before do
|
38
|
+
Capistrano::Configuration.should_receive(:new).
|
39
|
+
with(:output => @logger_stub).
|
40
|
+
and_return @task_mock
|
41
|
+
|
42
|
+
@task_logger_mock.should_receive(:level=).with(3)
|
43
|
+
@task_mock.should_receive(:set).with :user, 'user'
|
44
|
+
@task_mock.should_receive(:server).with('1.2.3.4', :instances)
|
45
|
+
@task_mock.should_receive(:server).with('4.3.2.1', :instances)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should return false when Capistrano command error" do
|
49
|
+
@ssh = SimpleDeploy::Stack::SSH.new @options
|
50
|
+
|
51
|
+
@task_mock.should_receive(:load).with({ :string=>"task :execute do\n sudo 'a_bad_command'\n end" })
|
52
|
+
@task_mock.should_receive(:execute).and_raise Capistrano::CommandError.new 'command error'
|
53
|
+
|
54
|
+
@ssh.execute(:sudo => true, :command => 'a_bad_command').should be_false
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return false when Capistrano connection error" do
|
58
|
+
@ssh = SimpleDeploy::Stack::SSH.new @options
|
59
|
+
|
60
|
+
@task_mock.stub :logger => @task_logger_mock,
|
61
|
+
:variables => @ssh_options
|
62
|
+
@task_mock.should_receive(:load).with({ :string=>"task :execute do\n sudo 'uname'\n end" })
|
63
|
+
@task_mock.should_receive(:execute).and_raise Capistrano::ConnectionError.new 'connection error'
|
64
|
+
|
65
|
+
@ssh.execute(:sudo => true, :command => 'uname').should be_false
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return false when Capistrano generic error" do
|
69
|
+
@ssh = SimpleDeploy::Stack::SSH.new @options
|
70
|
+
|
71
|
+
@task_mock.should_receive(:load).with({ :string=>"task :execute do\n sudo 'uname'\n end" })
|
72
|
+
@task_mock.should_receive(:execute).and_raise Capistrano::Error.new 'generic error'
|
73
|
+
|
74
|
+
@ssh.execute(:sudo => true, :command => 'uname').should be_false
|
75
|
+
end
|
76
|
+
end
|
30
77
|
end
|
31
78
|
|
32
79
|
context "when successful" do
|
33
80
|
before do
|
34
|
-
|
35
|
-
:instances => ['1.2.3.4', '4.3.2.1'],
|
36
|
-
:environment => 'test-env',
|
37
|
-
:ssh_user => 'user',
|
38
|
-
:ssh_key => 'key',
|
39
|
-
:stack => @stack_mock,
|
40
|
-
:name => 'test-stack' }
|
41
|
-
@ssh = SimpleDeploy::Stack::SSH.new options
|
81
|
+
@ssh = SimpleDeploy::Stack::SSH.new @options
|
42
82
|
end
|
43
|
-
|
83
|
+
|
44
84
|
describe "when execute called" do
|
45
85
|
before do
|
46
|
-
task_logger_mock = mock 'task_logger'
|
47
|
-
@ssh_options = Hash.new
|
48
86
|
Capistrano::Configuration.should_receive(:new).
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
task_logger_mock.should_receive(:level=).with(3)
|
87
|
+
with(:output => @logger_stub).
|
88
|
+
and_return @task_mock
|
89
|
+
|
90
|
+
@task_logger_mock.should_receive(:level=).with(3)
|
54
91
|
@task_mock.should_receive(:set).with :user, 'user'
|
55
92
|
@task_mock.should_receive(:server).with('1.2.3.4', :instances)
|
56
93
|
@task_mock.should_receive(:server).with('4.3.2.1', :instances)
|
57
94
|
end
|
58
95
|
|
59
|
-
describe "when
|
96
|
+
describe "when successful" do
|
60
97
|
it "should execute a task with sudo" do
|
61
|
-
@task_mock.should_receive(:load).with({:string=>"task :execute do\n sudo 'uname'\n end"})
|
98
|
+
@task_mock.should_receive(:load).with({ :string=>"task :execute do\n sudo 'uname'\n end" })
|
62
99
|
@task_mock.should_receive(:execute).and_return true
|
100
|
+
|
63
101
|
@ssh.execute(:sudo => true,
|
64
102
|
:command => 'uname').should be_true
|
65
103
|
end
|
66
104
|
|
67
105
|
it "should execute a task as the calling user " do
|
68
|
-
@task_mock.should_receive(:load).with({:string=>"task :execute do\n run 'uname'\n end"})
|
106
|
+
@task_mock.should_receive(:load).with({ :string=>"task :execute do\n run 'uname'\n end" })
|
69
107
|
@task_mock.should_receive(:execute).and_return true
|
108
|
+
|
70
109
|
@ssh.execute(:sudo => false,
|
71
110
|
:command => 'uname').should be_true
|
72
111
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
@
|
77
|
-
|
78
|
-
|
79
|
-
|
112
|
+
|
113
|
+
it "sets the ssh options" do
|
114
|
+
@task_mock.stub(:load)
|
115
|
+
@task_mock.stub(:execute).and_return(true)
|
116
|
+
@ssh.execute :sudo => false, :command => 'uname'
|
117
|
+
|
118
|
+
@ssh_options.should == { :ssh_options => { :keys => 'key',
|
119
|
+
:paranoid => false } }
|
120
|
+
end
|
80
121
|
end
|
81
122
|
end
|
82
123
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleDeploy::Template do
|
4
|
+
before do
|
5
|
+
@contents = {
|
6
|
+
"Parameters" => {
|
7
|
+
"Test1" => {
|
8
|
+
"Type" => "String",
|
9
|
+
"Description" => "Test Param #1"
|
10
|
+
},
|
11
|
+
"Test2" => {
|
12
|
+
"Type" => "String",
|
13
|
+
"Description" => "Test Param #2"
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}.to_json
|
17
|
+
IO.should_receive(:read).with('/tmp/file').and_return @contents
|
18
|
+
@template = SimpleDeploy::Template.new :file => '/tmp/file'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return the parameters for a given template" do
|
22
|
+
@template.parameters.should == ["Test1", "Test2"]
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70295198764320 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,15 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
24
|
+
version_requirements: *70295198764320
|
30
25
|
- !ruby/object:Gem::Dependency
|
31
26
|
name: rspec
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirement: &70295198763260 !ruby/object:Gem::Requirement
|
33
28
|
none: false
|
34
29
|
requirements:
|
35
30
|
- - ~>
|
@@ -37,76 +32,51 @@ dependencies:
|
|
37
32
|
version: 2.11.0
|
38
33
|
type: :development
|
39
34
|
prerelease: false
|
40
|
-
version_requirements:
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 2.11.0
|
35
|
+
version_requirements: *70295198763260
|
46
36
|
- !ruby/object:Gem::Dependency
|
47
37
|
name: capistrano
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
38
|
+
requirement: &70295198762340 !ruby/object:Gem::Requirement
|
49
39
|
none: false
|
50
40
|
requirements:
|
51
|
-
- -
|
41
|
+
- - =
|
52
42
|
- !ruby/object:Gem::Version
|
53
43
|
version: 2.13.5
|
54
44
|
type: :runtime
|
55
45
|
prerelease: false
|
56
|
-
version_requirements:
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - '='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 2.13.5
|
46
|
+
version_requirements: *70295198762340
|
62
47
|
- !ruby/object:Gem::Dependency
|
63
48
|
name: stackster
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirement: &70295198760620 !ruby/object:Gem::Requirement
|
65
50
|
none: false
|
66
51
|
requirements:
|
67
|
-
- -
|
52
|
+
- - =
|
68
53
|
- !ruby/object:Gem::Version
|
69
54
|
version: 0.4.2
|
70
55
|
type: :runtime
|
71
56
|
prerelease: false
|
72
|
-
version_requirements:
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - '='
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: 0.4.2
|
57
|
+
version_requirements: *70295198760620
|
78
58
|
- !ruby/object:Gem::Dependency
|
79
59
|
name: tinder
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirement: &70295198759920 !ruby/object:Gem::Requirement
|
81
61
|
none: false
|
82
62
|
requirements:
|
83
|
-
- -
|
63
|
+
- - =
|
84
64
|
- !ruby/object:Gem::Version
|
85
65
|
version: 1.8.0
|
86
66
|
type: :runtime
|
87
67
|
prerelease: false
|
88
|
-
version_requirements:
|
89
|
-
none: false
|
90
|
-
requirements:
|
91
|
-
- - '='
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version: 1.8.0
|
68
|
+
version_requirements: *70295198759920
|
94
69
|
- !ruby/object:Gem::Dependency
|
95
70
|
name: trollop
|
96
|
-
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirement: &70295198758960 !ruby/object:Gem::Requirement
|
97
72
|
none: false
|
98
73
|
requirements:
|
99
|
-
- -
|
74
|
+
- - =
|
100
75
|
- !ruby/object:Gem::Version
|
101
76
|
version: '2.0'
|
102
77
|
type: :runtime
|
103
78
|
prerelease: false
|
104
|
-
version_requirements:
|
105
|
-
none: false
|
106
|
-
requirements:
|
107
|
-
- - '='
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '2.0'
|
79
|
+
version_requirements: *70295198758960
|
110
80
|
description: Opinionated gem for Managing AWS Cloud Formation stacks and deploying
|
111
81
|
updates to Instances.
|
112
82
|
email:
|
@@ -151,37 +121,46 @@ files:
|
|
151
121
|
- lib/simple_deploy/env.rb
|
152
122
|
- lib/simple_deploy/exceptions.rb
|
153
123
|
- lib/simple_deploy/logger.rb
|
124
|
+
- lib/simple_deploy/misc.rb
|
125
|
+
- lib/simple_deploy/misc/attribute_merger.rb
|
154
126
|
- lib/simple_deploy/notifier.rb
|
155
127
|
- lib/simple_deploy/notifier/campfire.rb
|
156
128
|
- lib/simple_deploy/stack.rb
|
157
129
|
- lib/simple_deploy/stack/deployment.rb
|
158
130
|
- lib/simple_deploy/stack/deployment/status.rb
|
159
131
|
- lib/simple_deploy/stack/execute.rb
|
132
|
+
- lib/simple_deploy/stack/output_mapper.rb
|
160
133
|
- lib/simple_deploy/stack/ssh.rb
|
161
134
|
- lib/simple_deploy/stack/stack_attribute_formater.rb
|
135
|
+
- lib/simple_deploy/template.rb
|
162
136
|
- lib/simple_deploy/version.rb
|
163
137
|
- simple_deploy.gemspec
|
164
138
|
- spec/artifact_spec.rb
|
165
139
|
- spec/backoff_spec.rb
|
166
140
|
- spec/cli/attributes_spec.rb
|
167
141
|
- spec/cli/clone_spec.rb
|
142
|
+
- spec/cli/create_spec.rb
|
168
143
|
- spec/cli/deploy_spec.rb
|
169
144
|
- spec/cli/destroy_spec.rb
|
145
|
+
- spec/cli/outputs_spec.rb
|
170
146
|
- spec/cli/protect_spec.rb
|
171
147
|
- spec/cli/shared_spec.rb
|
172
148
|
- spec/cli/update_spec.rb
|
173
149
|
- spec/cli_spec.rb
|
174
150
|
- spec/config_spec.rb
|
175
151
|
- spec/logger_spec.rb
|
152
|
+
- spec/misc/attribute_merger_spec.rb
|
176
153
|
- spec/notifier/campfire_spec.rb
|
177
154
|
- spec/notifier_spec.rb
|
178
155
|
- spec/spec_helper.rb
|
179
156
|
- spec/stack/deployment/status_spec.rb
|
180
157
|
- spec/stack/deployment_spec.rb
|
181
158
|
- spec/stack/execute_spec.rb
|
159
|
+
- spec/stack/output_mapper_spec.rb
|
182
160
|
- spec/stack/ssh_spec.rb
|
183
161
|
- spec/stack/stack_attribute_formater_spec.rb
|
184
162
|
- spec/stack_spec.rb
|
163
|
+
- spec/template_spec.rb
|
185
164
|
homepage: ''
|
186
165
|
licenses: []
|
187
166
|
post_install_message:
|
@@ -196,7 +175,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
196
175
|
version: '0'
|
197
176
|
segments:
|
198
177
|
- 0
|
199
|
-
hash:
|
178
|
+
hash: 1762969189670717891
|
200
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
180
|
none: false
|
202
181
|
requirements:
|
@@ -205,10 +184,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
205
184
|
version: '0'
|
206
185
|
segments:
|
207
186
|
- 0
|
208
|
-
hash:
|
187
|
+
hash: 1762969189670717891
|
209
188
|
requirements: []
|
210
189
|
rubyforge_project: simple_deploy
|
211
|
-
rubygems_version: 1.8.
|
190
|
+
rubygems_version: 1.8.16
|
212
191
|
signing_key:
|
213
192
|
specification_version: 3
|
214
193
|
summary: Opinionated gem for AWS resource management.
|
@@ -217,20 +196,25 @@ test_files:
|
|
217
196
|
- spec/backoff_spec.rb
|
218
197
|
- spec/cli/attributes_spec.rb
|
219
198
|
- spec/cli/clone_spec.rb
|
199
|
+
- spec/cli/create_spec.rb
|
220
200
|
- spec/cli/deploy_spec.rb
|
221
201
|
- spec/cli/destroy_spec.rb
|
202
|
+
- spec/cli/outputs_spec.rb
|
222
203
|
- spec/cli/protect_spec.rb
|
223
204
|
- spec/cli/shared_spec.rb
|
224
205
|
- spec/cli/update_spec.rb
|
225
206
|
- spec/cli_spec.rb
|
226
207
|
- spec/config_spec.rb
|
227
208
|
- spec/logger_spec.rb
|
209
|
+
- spec/misc/attribute_merger_spec.rb
|
228
210
|
- spec/notifier/campfire_spec.rb
|
229
211
|
- spec/notifier_spec.rb
|
230
212
|
- spec/spec_helper.rb
|
231
213
|
- spec/stack/deployment/status_spec.rb
|
232
214
|
- spec/stack/deployment_spec.rb
|
233
215
|
- spec/stack/execute_spec.rb
|
216
|
+
- spec/stack/output_mapper_spec.rb
|
234
217
|
- spec/stack/ssh_spec.rb
|
235
218
|
- spec/stack/stack_attribute_formater_spec.rb
|
236
219
|
- spec/stack_spec.rb
|
220
|
+
- spec/template_spec.rb
|