kumo_keisei 3.0.4 → 3.0.5.pre.alpha1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: faa37c9fa0f21e7428850a43e4deb25dd50e581d
4
- data.tar.gz: d4d3a9d281e1d408f31856eb81501f3d189325c4
3
+ metadata.gz: 3d3c673fda643f764f36cdf9e17d130deb9004ae
4
+ data.tar.gz: b861c435acc83e7eb5e875f262d003dce20cc5fc
5
5
  SHA512:
6
- metadata.gz: a6f893e0c445e9c4d32b647f47cf024ef318aab7a1f2e7a66304fc3a7d42f9620851842afe0476868d7df42f97d3cc2ab36a240d5e36e96371d61a09cebd46ab
7
- data.tar.gz: 2c8a5763701b37efff2bd509b5bc4e4d703845b298cbc517a36d156253efed91422df8127939c849c50f09ead95a44d7d87f5a0f156c29ff7e73d920d9e2ec4c
6
+ metadata.gz: 293edcc0a2b44381720c8e08c7f13a0e57aa34c321fc4eb94e31e93142ccc9b149bdb72c754cab442f75b47d1754394de9bc3b39bb6629ea4c8c9195b40bef81
7
+ data.tar.gz: 986d62661c2bb354562ee024492606d905a9931d1cb99627906d6232f5517c92c22b41640a05d2a51b999dc5a9ff68931f60e3d705f2a9c02e79cc3dd376a3e4
data/README.md CHANGED
@@ -22,14 +22,170 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
+ ### Basic Usage
26
+
27
+ The basic usage will give you a CloudFormation stack named `{application}-{type}-{environment}`. The default type is `nodes`
28
+
29
+ ```ruby
30
+ application_name = "myapp"
31
+ environment_name = "production"
32
+ my_stack = KumoKeisei::Stack.new(stack_name, environment_name)
33
+
34
+ stack_config = {
35
+ config_path: File.join('/app', 'env', 'config'),
36
+ template_path: File.join('/app', 'env', 'cloudformation', 'myapp.json'),
37
+ }
38
+
39
+ my_stack.apply! stack_config
40
+ ```
41
+
42
+ ### Changing the stack type
43
+
44
+ Specify the `type` in an options object passed to the `KumoKeisei::Stack` constructor. For example the following will give you a `myapp-vpc-production` stack e.g:
45
+ ```ruby
46
+ vpc_stack_options = {
47
+ type: 'vpc'
48
+ }
49
+ vpc_stack = KumoKeisei::Stack.new('myapp', 'production', vpc_stack_options)
50
+ ```
51
+
52
+ ### Timeouts
53
+
54
+ You can tune each of the timeouts by passing options to the Stack constructor:
55
+ ```ruby
56
+ stack_options = {
57
+ confirmation_timeout: 0.5,
58
+ waiter_delay: 20,
59
+ waiter_attempts: 90,
60
+ }
61
+
62
+ KumoKeisei::Stack.new(stack_name, environment_name, stack_options)
63
+ ```
64
+
65
+ *confirmation_timeout*: how long to wait for a user to confirm delete actions
66
+ *waiter_delay*: how long to wait between checking Cfn for completion of delete and update actions
67
+ *waiter_attempts*: how many times to retry checking that a Cfn delete or update was successful
68
+
69
+ ### CloudFormation Templates, Parameter Templates and Configuration Files
70
+
71
+ The **CloudFormation Template** is a json file (e.g. app.json) describing a related set of Amazon resources using the [CloudFormation DSL](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/gettingstarted.templatebasics.html). You pass the location by specifying the `template_path` in the object passed to `apply!`,
72
+
73
+ The **Parameter Template** is a file prescribing the Cfn parameters [Embedded Ruby](http://www.stuartellis.eu/articles/erb/) form. It must be in the same folder holding the CloudFormation Template, named `{app_name}.yml.erb`.
74
+
75
+ The **Configuration Files** are a set of files in `yml` format prescribing configuration values for a given environment. They must be in the folder given by `config_path`, in the form of `{environment}.yml` and `{environment}_secrets.yml`
76
+
77
+ [KumoKi](https://github.com/redbubble/kumo_ki_gem) will be used to decrypt the _secrets_ files.
78
+
79
+ ### Configuration Hierarchy
80
+
81
+ Configuration will be loaded from the following sources:
82
+
83
+ 1. `common.yml` and `common_secrets.yml` if they exist.
84
+ 2. `{environment}.yml` and `{environment}_secrets.yml` or `development.yml` and `development_secrets.yml` if environment specific config does not exist.
85
+
86
+ ### Injecting Configuration
87
+
88
+ You can also inject configuration at run time by adding it to the object provided to the `apply!` call:
89
+
90
+ ```ruby
91
+ stack_config = {
92
+ config_path: File.join('/app', 'env', 'config'),
93
+ template_path: File.join('/app', 'env', 'cloudformation', 'myapp.json'),
94
+ injected_config: {
95
+ 'Seed' => random_seed,
96
+ }
97
+ }
98
+ stack.apply!(stack_config)
99
+ ```
100
+
101
+ ### Getting the configuration without an `apply!`
102
+
103
+ If you need to inspect the configuration without applying a stack, call `config`:
104
+ ```ruby
105
+ stack_config = {
106
+ config_path: File.join('/app', 'env', 'config'),
107
+ template_path: File.join('/app', 'env', 'cloudformation', 'myapp.json'),
108
+ injected_config: {
109
+ 'Seed' => random_seed,
110
+ }
111
+ }
112
+ marshalled_config = stack.config(stack_config)
113
+ if marshalled_config('DB_HOST').start_with? '192.' then
114
+ ...
115
+ ```
116
+
117
+ ## Upgrading from `KumoKeisei::CloudFormationStack` to `KumoKeisei::Stack`
118
+
119
+ `KumoKeisei::CloudFormationStack` is deprecated and should be replaced with a `KumoKeisei::Stack` which encompasses an environment object (`KumoKeisei::EnvironmentConfig`).
120
+
121
+ Previously you would have to construct your own `EnvironmentConfig` which would marshal it's configuration, then instantiate a `CloudFormationStack` and conduct operations on it.
122
+
123
+ E.g. `apply-env`:
124
+ ```ruby
125
+ require_relative '../env/cloudformation_stack'
126
+
127
+ environment_name = ARGV.fetch(0) rescue raise("Error! No environment name given!")
128
+
129
+ stack = CloudFormationStack.new(environment_name)
130
+ stack.apply
131
+ ```
132
+ and `environment_config.rb`:
133
+ ```ruby
134
+ require 'kumo_keisei'
135
+
136
+ class CloudFormationStack
137
+
138
+ APP_NAME = "fooapp"
139
+
140
+ attr_reader :env_name
141
+
142
+ def initialize(env_name)
143
+ @stacks = {}
144
+ @env_name = env_name
145
+ end
146
+
147
+ def env_vars
148
+ {}
149
+ end
150
+
151
+ def apply
152
+ # Inject the VPC and Subnets into the application's environment config
153
+ foo_config = KumoKeisei::EnvironmentConfig.new(
154
+ env_name: env_name,
155
+ config_dir_path: File.expand_path(File.join("..", "..", "env", "config"), __FILE__)
156
+ )
157
+
158
+ foo_stack = create_stack(:foo, foo_config)
159
+ foo_stack.apply!
160
+ end
161
+ ...
162
+ def create_stack(stack_name, environment_config)
163
+ raise "Stack '#{ stack_name }' already exists!" if @stacks[stack_name]
164
+ params_template_erb = params_template(stack_name)
165
+ stack_values = cf_params_json(get_stack_params(params_template_erb, environment_config))
166
+ write_stack_params_file(stack_values, stack_name)
167
+ @stacks[stack_name] = KumoKeisei::CloudFormationStack.new(stack_names[stack_name], "./env/cloudformation/#{stack_name}.json", stack_file_params_file_path(stack_name))
168
+ end
169
+ ...
170
+ ```
171
+
172
+ With the new `Stack` object, all you need to do is pass in the location of the template and config as in the above section. New `apply-env`:
25
173
  ```ruby
26
- stack_name = "my_awesome_stack"
27
- template = "./cloudformation/environment_template.json"
28
- template_params = "./cloudformation/environments/production/params.json"
174
+ require 'kumo_keisei'
175
+
176
+ environment_name = ARGV.fetch(0) rescue raise("Error! No environment name given!")
29
177
 
30
- KumoKeisei::CloudFormationStack.new(stack_name, template, template_params).apply!
178
+ stack_config = {
179
+ config_path: File.join('/app', 'env', 'config'),
180
+ template_path: File.join('/app', 'env', 'cloudformation', 'fooapp.json'),
181
+ }
182
+
183
+ stack = KumoKeisei::Stack.new('fooapp', environment_name)
184
+ stack.apply!(stack_config)
31
185
  ```
32
186
 
187
+
188
+
33
189
  ## Dependencies
34
190
 
35
191
  #### Ruby Versions
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.4
1
+ 3.0.5-alpha1
@@ -4,6 +4,7 @@ module KumoKeisei
4
4
  class Stack
5
5
  class CreateError < StandardError; end
6
6
  class UpdateError < StandardError; end
7
+ class UsageError < StandardError; end
7
8
 
8
9
  UPDATEABLE_STATUSES = [
9
10
  'UPDATE_ROLLBACK_COMPLETE',
@@ -39,6 +40,9 @@ module KumoKeisei
39
40
 
40
41
  def apply!(stack_config)
41
42
  stack_config.merge!(env_name: @env_name)
43
+
44
+ raise UsageError.new('You must provide a :template_path in the stack config hash for an apply! operation') unless stack_config.has_key?(:template_path)
45
+
42
46
  if updatable?
43
47
  update!(stack_config)
44
48
  else
@@ -76,6 +80,11 @@ module KumoKeisei
76
80
  !get_stack.nil?
77
81
  end
78
82
 
83
+ def config(stack_config)
84
+ raise UsageError.new('You must provide a :config_path in the stack config hash to retrieve the stack\'s config') unless stack_config.has_key?(:config_path)
85
+ environment_config(stack_config).config
86
+ end
87
+
79
88
  private
80
89
 
81
90
  def transform_logical_resource_id(id)
@@ -153,7 +162,7 @@ module KumoKeisei
153
162
  end
154
163
 
155
164
  def environment_config(stack_config)
156
- params_template_path = File.absolute_path(File.join(File.dirname(stack_config[:template_path]), "#{@app_name}.yml.erb"))
165
+ params_template_path = stack_config.has_key?(:template_path) ? File.absolute_path(File.join(File.dirname(stack_config[:template_path]), "#{@app_name}.yml.erb")) : nil
157
166
  EnvironmentConfig.new(stack_config.merge(params_template_file_path: params_template_path))
158
167
  end
159
168
 
@@ -40,6 +40,8 @@ describe KumoKeisei::Stack do
40
40
  }
41
41
  }
42
42
 
43
+ context "unit tests" do
44
+
43
45
  before do
44
46
  allow(KumoKeisei::ConsoleJockey).to receive(:flash_message)
45
47
  allow(KumoKeisei::ConsoleJockey).to receive(:write_line).and_return(nil)
@@ -73,6 +75,20 @@ describe KumoKeisei::Stack do
73
75
  end
74
76
 
75
77
  describe "#apply!" do
78
+ context "when you don't specify the location of the Cfn template" do
79
+ let(:stack_config) {
80
+ {
81
+ config_path: 'config-path',
82
+ injected_config: { 'VpcId' => 'vpc-id' },
83
+ env_name: 'non-production'
84
+ }
85
+ }
86
+
87
+ it "complains" do
88
+ expect { subject.apply!(stack_config) }.to raise_error(KumoKeisei::Stack::UsageError)
89
+ end
90
+ end
91
+
76
92
  context "when the stack is updatable" do
77
93
  UPDATEABLE_STATUSES = ['UPDATE_ROLLBACK_COMPLETE', 'CREATE_COMPLETE', 'UPDATE_COMPLETE']
78
94
 
@@ -254,15 +270,56 @@ describe KumoKeisei::Stack do
254
270
  end
255
271
  end
256
272
 
257
- describe "#type" do
258
- it "presumes stacks are of type node if the type is not set" do
259
- expect(subject.stack_name).to eq("#{app_name}-nodes-#{environment_name}")
273
+ describe "#type" do
274
+ it "presumes stacks are of type node if the type is not set" do
275
+ expect(subject.stack_name).to eq("#{app_name}-nodes-#{environment_name}")
276
+ end
277
+
278
+ it "embeds the type into the name of the stack if set" do
279
+ subject = KumoKeisei::Stack.new(app_name, environment_name, { type: "vpc" } )
280
+ expect(subject.stack_name).to eq("#{app_name}-vpc-#{environment_name}")
281
+ end
282
+ end
283
+
284
+ describe "#config" do
285
+ context "when passed a config_path and params_template_file_path" do
286
+ before do
287
+ allow(KumoKeisei::EnvironmentConfig).to receive(:new).with(stack_config.merge(params_template_file_path: "#{app_name}.yml.erb")).and_return(double(:environment_config, cf_params: {}, config: { :foo=> 'bar', :baz=> 'qux' }))
260
288
  end
261
289
 
262
- it "embeds the type into the name of the stack if set" do
263
- subject = KumoKeisei::Stack.new(app_name, environment_name, { type: "vpc" } )
264
- expect(subject.stack_name).to eq("#{app_name}-vpc-#{environment_name}")
290
+ it "will return the results of the nested KumoKeisei::EnvironmentConfig.config" do
291
+ expect(subject.config(stack_config)).to eq({:foo=> 'bar', :baz=>'qux'})
265
292
  end
266
293
  end
267
294
 
295
+ context "when a config_path and nil for params_template_file_path" do
296
+ let(:stack_config) {
297
+ {
298
+ config_path: 'config-path',
299
+ env_name: 'non-production'
300
+ }
301
+ }
302
+
303
+ before do
304
+ allow(KumoKeisei::EnvironmentConfig).to receive(:new).with(stack_config.merge(params_template_file_path: nil)).and_return(double(:environment_config, cf_params: {}, config: { :foo=> 'bar', :baz=> 'qux' }))
305
+ end
306
+
307
+ it "will return the results of the nested KumoKeisei::EnvironmentConfig.config" do
308
+ expect(subject.config(stack_config)).to eq({:foo=> 'bar', :baz=>'qux'})
309
+ end
310
+ end
311
+
312
+ context "if not given a stack_config containing a `config_path`" do
313
+ let(:stack_config) {
314
+ {
315
+ }
316
+ }
317
+ it "will raise an error" do
318
+ expect { described_class.new(app_name, environment_name).config(stack_config)}.to raise_error(KumoKeisei::Stack::UsageError)
319
+ end
320
+ end
321
+
322
+ end
323
+ end
324
+
268
325
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kumo_keisei
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4
4
+ version: 3.0.5.pre.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Redbubble
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-04 00:00:00.000000000 Z
11
+ date: 2016-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -130,12 +130,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
130
  version: '0'
131
131
  required_rubygems_version: !ruby/object:Gem::Requirement
132
132
  requirements:
133
- - - ">="
133
+ - - ">"
134
134
  - !ruby/object:Gem::Version
135
- version: '0'
135
+ version: 1.3.1
136
136
  requirements: []
137
137
  rubyforge_project:
138
- rubygems_version: 2.5.1
138
+ rubygems_version: 2.2.2
139
139
  signing_key:
140
140
  specification_version: 4
141
141
  summary: A collection of utilities for dealing with AWS Cloud Formation.