cloudformula 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +206 -0
- data/Rakefile +1 -0
- data/bin/cloudformula +12 -0
- data/cloudformula.gemspec +26 -0
- data/integration_tests/.ruby-gemset +1 -0
- data/integration_tests/.ruby-version +1 -0
- data/integration_tests/Gemfile +3 -0
- data/integration_tests/README.md +33 -0
- data/integration_tests/fixtures/minimal_cf_template.json +30 -0
- data/integration_tests/fixtures/minimal_cf_template_update.json +54 -0
- data/integration_tests/stack_create_update.rb +26 -0
- data/lib/cloudformula/cli.rb +113 -0
- data/lib/cloudformula/cloud_formation.rb +54 -0
- data/lib/cloudformula/help/create.txt +12 -0
- data/lib/cloudformula/help/generate.txt +10 -0
- data/lib/cloudformula/help/top.txt +20 -0
- data/lib/cloudformula/help/update.txt +12 -0
- data/lib/cloudformula/json_erb.rb +42 -0
- data/lib/cloudformula/string.rb +11 -0
- data/lib/cloudformula/template.rb +99 -0
- data/lib/cloudformula/validator.rb +172 -0
- data/lib/cloudformula/version.rb +3 -0
- data/lib/cloudformula.rb +23 -0
- data/spec/cloud_formula_spec.rb +18 -0
- data/spec/cloudformula/cloud_formation_spec.rb +55 -0
- data/spec/cloudformula/template_spec.rb +303 -0
- data/spec/fixtures/_partial.json.erb +1 -0
- data/spec/fixtures/with_custom_erb_validations.erb +4 -0
- data/spec/fixtures/with_erb_parameters.erb +3 -0
- data/spec/fixtures/with_erb_parameters.json.erb +4 -0
- data/spec/fixtures/with_erb_parameters_and_stack_options.json.erb +5 -0
- data/spec/fixtures/with_erb_parameters_answer.json +4 -0
- data/spec/fixtures/with_erb_parameters_answer.txt +3 -0
- data/spec/fixtures/with_erb_parameters_escaped_answer.json +4 -0
- data/spec/fixtures/with_erb_validations.json.erb +53 -0
- data/spec/fixtures/with_partial.json.erb +5 -0
- data/spec/fixtures/with_partial_answer.json +5 -0
- data/spec/fixtures/with_raw.json.erb +3 -0
- data/spec/fixtures/with_raw_answer.json +3 -0
- data/spec/fixtures/with_stack_options.json.erb +4 -0
- data/spec/fixtures/without_erb_parameters.erb +1 -0
- data/spec/fixtures/without_erb_parameters.json.erb +3 -0
- data/spec/spec_helper.rb +11 -0
- metadata +185 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
NAME
|
2
|
+
cloudformula
|
3
|
+
https://github.com/Kabam/cloudformula
|
4
|
+
|
5
|
+
DESCRIPTION
|
6
|
+
Dynamically generates AWS CloudFormation templates, creates, and updates
|
7
|
+
CloudFormation stacks.
|
8
|
+
|
9
|
+
USAGE
|
10
|
+
cloudformula <command> <options>
|
11
|
+
|
12
|
+
AVAILABLE COMMANDS
|
13
|
+
'cloudformula <command> --help' provides more detailed information for each
|
14
|
+
command.
|
15
|
+
|
16
|
+
generate :: Generate a template
|
17
|
+
create :: Generate a template and create a new CloudFormation stack
|
18
|
+
update :: Generate a template and update an existing CloudFormation stack
|
19
|
+
|
20
|
+
OPTIONS
|
@@ -0,0 +1,12 @@
|
|
1
|
+
NAME
|
2
|
+
cloudformula update
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
Dynamically generates an AWS CloudFormation template and uses it to update an
|
6
|
+
existing CloudFormation stack.
|
7
|
+
|
8
|
+
USAGE
|
9
|
+
cloudformula update --stack-name '<stackname>' --template '<template>' \\
|
10
|
+
--parameters '<params>' [--region '<region>']
|
11
|
+
|
12
|
+
OPTIONS
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module CloudFormula
|
4
|
+
# Custom ERB compiler which causes variable interpolation inside <%= %> to be json encoded.
|
5
|
+
# Inside regular <% %>, the variables are used without json encoding.
|
6
|
+
#
|
7
|
+
# CloudFormation stack options defaults can be set directly within a template by setting @stack_options.
|
8
|
+
# See README.md "CloudFormation stack options" for details.
|
9
|
+
#
|
10
|
+
# Basic validation functionality is possible by setting @validations.
|
11
|
+
# See README.md "Validations" for details
|
12
|
+
#
|
13
|
+
class JsonErb < ::ERB
|
14
|
+
class CompilerWithBlock < ::ERB::Compiler
|
15
|
+
def add_insert_cmd(out, content)
|
16
|
+
out.push "#{@insert_cmd}((#{content}).to_s.try_to_json)"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def make_compiler(*args)
|
21
|
+
CompilerWithBlock.new *args
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the @stack_options value set within the template.
|
25
|
+
#
|
26
|
+
# @param [Binding] b accepts a Binding or Proc object which is used to set the context of code evaluation.
|
27
|
+
# @return [Hash] The stack options set by the template or an empty Hash if none are set.
|
28
|
+
def stack_options(b = new_toplevel)
|
29
|
+
result(b)
|
30
|
+
b.eval('@stack_options') || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the @validations value set within the template.
|
34
|
+
#
|
35
|
+
# @param [Binding] b accepts a Binding or Proc object which is used to set the context of code evaluation.
|
36
|
+
# @return [Hash] The stack options set by the template or an empty Hash if none are set.
|
37
|
+
def validations(b = new_toplevel)
|
38
|
+
result(b)
|
39
|
+
b.eval('@validations') || {}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class String
|
4
|
+
# Returns the string JSON-escaped.
|
5
|
+
# If the cloudformula_raw flag is set, returns the string as-is.
|
6
|
+
# @return [String]
|
7
|
+
def try_to_json
|
8
|
+
return self if instance_variable_get :@cloudformula_raw
|
9
|
+
self.to_json
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module CloudFormula
|
4
|
+
# Defines a CloudFormula/CloudFormation template
|
5
|
+
class Template
|
6
|
+
attr :parameters, :source
|
7
|
+
|
8
|
+
# @param [String] source Path to source template
|
9
|
+
# @param [Hash] parameters Parameter names and values to use in the template
|
10
|
+
def initialize(source = '', parameters = {})
|
11
|
+
@source = source
|
12
|
+
@parameters = parameters
|
13
|
+
end
|
14
|
+
|
15
|
+
# Evaluates and returns the @source template populated with values from @parameters
|
16
|
+
# @return [String]
|
17
|
+
def generate
|
18
|
+
init_parameters @parameters
|
19
|
+
raise "Parameter validation failed.\n\nErrors:\n #{errors.join("\n")}" if invalid?
|
20
|
+
JsonErb.new(File.read(@source)).result(binding)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Evalutes and returns the @source template populated with values from @parameters
|
24
|
+
# @return [Hash]
|
25
|
+
def generate_hash
|
26
|
+
JSON.parse(generate)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Causes the given string value to be output without escape characters
|
30
|
+
# @param [String] value
|
31
|
+
# @return [String]
|
32
|
+
def raw(value)
|
33
|
+
value.instance_variable_set :@cloudformula_raw, true
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [String] source Path to source template
|
38
|
+
# @param [Hash] parameters Parameter names and values to use in the template
|
39
|
+
# @return [String] The result of generating the template
|
40
|
+
def render(source, parameters = {})
|
41
|
+
raw CloudFormula::Template.new(source, parameters).generate
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the CloudFormation stack options defined by the template.
|
45
|
+
def stack_options
|
46
|
+
init_parameters @parameters
|
47
|
+
JsonErb.new(File.read(@source), 0).stack_options(binding) rescue {}
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the validations defined by the template.
|
51
|
+
def validations
|
52
|
+
init_parameters @parameters
|
53
|
+
JsonErb.new(File.read(@source), 0).validations(binding) rescue {}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the merged options Hash for use by AWS::CloudFormation::StackCollection#create and
|
57
|
+
# AWS::CloudFormation::Stack#update
|
58
|
+
#
|
59
|
+
# @param [Hash] override_options Optional. Stack options to override. See README.md "CloudFormation stack options" for details
|
60
|
+
# @param [Hash] parameters Parameters to supply to the template. Required if the template contains any required parameters without a default value
|
61
|
+
def aws_options(override_options = {}, parameters = {})
|
62
|
+
stack_options.merge(override_options.merge({ :parameters => parameters }))
|
63
|
+
end
|
64
|
+
|
65
|
+
# Similar to Active Record Validations errors[] object
|
66
|
+
# @see http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#validations_overview-errors
|
67
|
+
def errors
|
68
|
+
validate
|
69
|
+
end
|
70
|
+
|
71
|
+
def valid?
|
72
|
+
errors.length == 0
|
73
|
+
end
|
74
|
+
|
75
|
+
def invalid?
|
76
|
+
!valid?
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Sets the given Hash as instance variables for use in the ERB template
|
82
|
+
# @param [Hash] values
|
83
|
+
def init_parameters(values = {})
|
84
|
+
values.each { |key, value| instance_variable_set("@#{key}", value) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def validate
|
88
|
+
errors = []
|
89
|
+
validations.each do |parameter_name, parameter_validations|
|
90
|
+
validator = CloudFormula::Validator.new(parameter_name, parameter_validations)
|
91
|
+
validate_result = validator.validate(@parameters[parameter_name.to_sym])
|
92
|
+
errors += validate_result
|
93
|
+
end
|
94
|
+
#puts errors.inspect
|
95
|
+
errors
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module CloudFormula
|
4
|
+
# Contains logic to perform basic validation of parameters defined in a JsonErb template.
|
5
|
+
#
|
6
|
+
# Available validations:
|
7
|
+
# :exclusion => ['val1'] Ensures a value is not in the exclusion list
|
8
|
+
# :inclusion => ['val1', 'val2'] Ensures a value is in the inclusion list
|
9
|
+
# :length => { Ensures value length
|
10
|
+
# :minimum => n,
|
11
|
+
# :maximum => n,
|
12
|
+
# :in|:within => x..y,
|
13
|
+
# :is => n
|
14
|
+
# }
|
15
|
+
# :format => /regex/ Ensures a value matches the regex
|
16
|
+
# :presence => true|false Ensures a value exists and has a length greater than 0
|
17
|
+
#
|
18
|
+
class Validator
|
19
|
+
class Rule
|
20
|
+
attr_accessor :name, :value
|
21
|
+
def initialize(name, value)
|
22
|
+
@name = name
|
23
|
+
@value = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :parameter_name, :validations
|
28
|
+
|
29
|
+
# @param [Hash] validations The rules defined for the given parameter_name
|
30
|
+
def initialize(parameter_name, validations)
|
31
|
+
@parameter_name = parameter_name
|
32
|
+
@validations = validations
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Object] value The value to check against
|
36
|
+
# @return [Array] An Array of Strings describing the failure(s) if any checks fail, or an empty Array otherwise
|
37
|
+
def validate(value)
|
38
|
+
errors = []
|
39
|
+
@validations.each do |rule_name, rule_value|
|
40
|
+
rule_result = check_rule Rule.new(rule_name, rule_value), value
|
41
|
+
errors += rule_result
|
42
|
+
end
|
43
|
+
errors
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# @param [Rule] rule The rule to check
|
49
|
+
# @param [Object] parameter_value The value to check against
|
50
|
+
# @return [Array] A string describing the failure will be returned if the check fails, or an empty Array otherwise
|
51
|
+
def check_rule(rule, parameter_value)
|
52
|
+
case rule.name
|
53
|
+
when :exclusion, :inclusion, :length, :numericality, :format, :presence
|
54
|
+
self.send("check_#{rule.name}", rule.value, @parameter_name, parameter_value)
|
55
|
+
else
|
56
|
+
raise "Unknown rule name #{rule.name} found in ERB template."
|
57
|
+
end || []
|
58
|
+
end
|
59
|
+
|
60
|
+
def check_exclusion(constraint, parameter_name, value)
|
61
|
+
unless value.nil?
|
62
|
+
if constraint.include? value
|
63
|
+
["Value '#{value}' for parameter '#{parameter_name}' must not be one of [#{constraint.join(', ')}]"]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_inclusion(constraint, parameter_name, value)
|
69
|
+
unless value.nil?
|
70
|
+
unless constraint.include? value
|
71
|
+
["Value '#{value}' for parameter '#{parameter_name}' must be one of [#{constraint.join(', ')}]"]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def check_length(constraint, parameter_name, value)
|
77
|
+
errors = []
|
78
|
+
unless value.nil?
|
79
|
+
constraint.each do |length_rule, length_value|
|
80
|
+
case length_rule
|
81
|
+
when :maximum
|
82
|
+
if value.length > length_value
|
83
|
+
errors << "Parameter '#{parameter_name}' must have length less than or equal to #{length_value}"
|
84
|
+
end
|
85
|
+
when :minimum
|
86
|
+
if value.length < length_value
|
87
|
+
errors << "Parameter '#{parameter_name}' must have length greater than or equal to #{length_value}"
|
88
|
+
end
|
89
|
+
when :in, :within
|
90
|
+
unless length_value.cover? value.length
|
91
|
+
errors << "Parameter '#{parameter_name}' must have length in the range of #{length_value}"
|
92
|
+
end
|
93
|
+
when :is
|
94
|
+
if value.length != length_value
|
95
|
+
errors << "Parameter '#{parameter_name}' must have length #{length_value}"
|
96
|
+
end
|
97
|
+
else
|
98
|
+
raise "Unknown length rule attribute #{length_rule} found in ERB template."
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
errors
|
103
|
+
end
|
104
|
+
|
105
|
+
def check_numericality(constraint, parameter_name, value)
|
106
|
+
errors = []
|
107
|
+
unless value.nil?
|
108
|
+
constraint.each do |numericality_rule, numericality_constraint|
|
109
|
+
numeric_value = (/\./ =~ value.to_s ? value.to_f : value.to_i)
|
110
|
+
case numericality_rule
|
111
|
+
when :only_integer
|
112
|
+
if numericality_constraint
|
113
|
+
unless value.to_s =~ /\A[+-]?\d+\Z/
|
114
|
+
errors << "Parameter '#{parameter_name}' must be an integer"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
when :equal_to
|
118
|
+
unless numeric_value == numericality_constraint
|
119
|
+
errors << "Parameter '#{parameter_name}' must be equal to #{numericality_constraint}"
|
120
|
+
end
|
121
|
+
when :greater_than
|
122
|
+
unless numeric_value > numericality_constraint
|
123
|
+
errors << "Parameter '#{parameter_name}' must be greater than #{numericality_constraint}"
|
124
|
+
end
|
125
|
+
when :less_than
|
126
|
+
unless numeric_value < numericality_constraint
|
127
|
+
errors << "Parameter '#{parameter_name}' must be less than #{numericality_constraint}"
|
128
|
+
end
|
129
|
+
when :greater_than_or_equal_to
|
130
|
+
unless numeric_value >= numericality_constraint
|
131
|
+
errors << "Parameter '#{parameter_name}' must be greater than or equal to #{numericality_constraint}"
|
132
|
+
end
|
133
|
+
when :less_than_or_equal_to
|
134
|
+
unless numeric_value <= numericality_constraint
|
135
|
+
errors << "Parameter '#{parameter_name}' must be less than or equal to #{numericality_constraint}"
|
136
|
+
end
|
137
|
+
when :even
|
138
|
+
if numericality_constraint
|
139
|
+
unless numeric_value.respond_to?('even?') && numeric_value.even?
|
140
|
+
errors << "Parameter '#{parameter_name}' must be even"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
when :odd
|
144
|
+
if numericality_constraint
|
145
|
+
unless numeric_value.respond_to?('odd?') && numeric_value.odd?
|
146
|
+
errors << "Parameter '#{parameter_name}' must be odd"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
else
|
150
|
+
raise "Unknown numericality rule attribute #{numericality_rule} found in ERB template."
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
errors
|
155
|
+
end
|
156
|
+
|
157
|
+
def check_format(constraint, parameter_name, value)
|
158
|
+
unless value.nil?
|
159
|
+
unless constraint =~ value
|
160
|
+
["Value '#{value}' for parameter '#{parameter_name}' must match regexp #{constraint.source}"]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def check_presence(constraint, parameter_name, value)
|
166
|
+
if constraint && (value.nil? || value.to_s == '')
|
167
|
+
["Parameter '#{parameter_name}' must exist and have a length of at least 1"]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
data/lib/cloudformula.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Dir.glob("#{File.dirname(__FILE__)}/cloudformula/*.rb") { |file| require file }
|
2
|
+
|
3
|
+
module CloudFormula
|
4
|
+
class << self # class methods
|
5
|
+
# Creates a new CloudFormula::Template object.
|
6
|
+
# @see CloudFormula::Template.initialize
|
7
|
+
def template(source = '', parameters = {})
|
8
|
+
Template.new(source, parameters)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Creates a new AWS CloudFormation stack
|
12
|
+
# @see CloudFormula::CloudFormation.create_stack
|
13
|
+
def create_stack(region, stack_name, template, override_options = {}, parameters = {}, aws_access_key_id = nil, aws_secret_key = nil)
|
14
|
+
CloudFormation.create_stack(region, stack_name, template, override_options, parameters, aws_access_key_id, aws_secret_key)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Updates an AWS CloudFormation stack
|
18
|
+
# @see CloudFormula::CloudFormation.update_stack
|
19
|
+
def update_stack(region, stack_name, template, parameters = {}, aws_access_key_id = nil, aws_secret_key = nil)
|
20
|
+
CloudFormation.update_stack(region, stack_name, template, parameters, aws_access_key_id, aws_secret_key)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
describe CloudFormula do
|
2
|
+
it 'should have a version' do
|
3
|
+
expect(CloudFormula::VERSION).to_not be_nil
|
4
|
+
expect(CloudFormula::VERSION).to_not be_empty
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'template method should return a new Template object' do
|
8
|
+
expect(CloudFormula.template).to be_an_instance_of(CloudFormula::Template)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'create_stack method' do
|
12
|
+
expect(CloudFormula).to respond_to(:create_stack)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'update_stack method' do
|
16
|
+
expect(CloudFormula).to respond_to(:update_stack)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CloudFormula
|
4
|
+
describe CloudFormation do
|
5
|
+
describe 'create_stack method' do
|
6
|
+
it 'should exist' do
|
7
|
+
expect(CloudFormula::CloudFormation).to respond_to(:create_stack)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'update_stack method' do
|
12
|
+
it 'should exist' do
|
13
|
+
expect(CloudFormula::CloudFormation).to respond_to(:update_stack)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'private get_cloud_formation method' do
|
18
|
+
it 'should raise an error with invalid credentials explicitly passed to it' do
|
19
|
+
stub_aws_env
|
20
|
+
CloudFormula::CloudFormation.instance_eval do
|
21
|
+
def test_cf
|
22
|
+
get_cloud_formation('us-east-1', 'foo', 'bar')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
expect(CloudFormula::CloudFormation.test_cf).to be_a(AWS::CloudFormation)
|
26
|
+
expect { CloudFormula::CloudFormation.test_cf.stacks.each }.to raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should work with credentials from ENV' do
|
30
|
+
# This test requires AWS credentials in ENV. Unfortunately it cannot be faked.
|
31
|
+
CloudFormula::CloudFormation.instance_eval do
|
32
|
+
def test_cf
|
33
|
+
get_cloud_formation('us-east-1')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
expect(CloudFormula::CloudFormation.test_cf).to be_a(AWS::CloudFormation)
|
37
|
+
expect { CloudFormula::CloudFormation.test_cf.stacks.each }.to_not raise_error
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def stub_aws_env
|
45
|
+
ENV.stub(:[]).with('AWS_ACCESS_KEY_ID').and_return(nil)
|
46
|
+
ENV.stub(:[]).with('AWS_SECRET_ACCESS_KEY').and_return(nil)
|
47
|
+
ENV.stub(:[]).with('AWS_SESSION_TOKEN').and_return(nil)
|
48
|
+
ENV.stub(:[]).with('AWS_CREDENTIAL_FILE').and_return(nil)
|
49
|
+
ENV.stub(:[]).with('http_proxy').and_return(nil)
|
50
|
+
ENV.stub(:[]).with('HTTP_PROXY').and_return(nil)
|
51
|
+
ENV.stub(:[]).with('AMAZON_ACCESS_KEY_ID').and_return(nil)
|
52
|
+
ENV.stub(:[]).with('AMAZON_SECRET_ACCESS_KEY').and_return(nil)
|
53
|
+
ENV.stub(:[]).with('AMAZON_SESSION_TOKEN').and_return(nil)
|
54
|
+
ENV.stub(:[]).with('AMAZON_CREDENTIAL_FILE').and_return(nil)
|
55
|
+
end
|