stax 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0444c2ae4f050d73ba7cfd720eca476667102bf2
4
- data.tar.gz: 764f80db2e413eade8840ef8f04c33d93003e190
2
+ SHA256:
3
+ metadata.gz: 6fb67f05d66f75c3ee95f2f244189b9f0a24cf84c510280a02f17325b0f6c29b
4
+ data.tar.gz: e8a9c6ab1f3b869f36c688ffc7c9caf69799ed9fd9730f23beabd29a750ddfa2
5
5
  SHA512:
6
- metadata.gz: bb84fb5b04019ef607f8f4a6658414fdda2b3dbf641a31bbedadfb785ab20f1e76c8d039529c71a52d5f18419ead4c5594297bdfc7303efef8ccb4f8d0ef0191
7
- data.tar.gz: f65676b1870954bcc39c5d53a0ecd7b238d5b2fafd7bd2ea5761fc993dece0e33c7b8c2205ebf6a61021b148ba01f84f8856a523fd4d4c2fa6ff3bbfcea6fb41
6
+ metadata.gz: e31cf509ed73dbfc5045f5d2971d47894be9194f0a78d33812544ee5e854f15095c32ff3d4be868a168cf4d29475e9bf2bd03338f8f9043a6b43774bbecf3fa0
7
+ data.tar.gz: fad98ced6ce0cced2e8fa45405e6e3f5dd47d168ab5134a41c66e42cea280f2b36d9169b11d367aeb19e88cfbac3b093aa72541b619ca3de2a3b52c933dff9f2
data/README.md CHANGED
@@ -1,12 +1,71 @@
1
1
  # Stax
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/stax`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Stax is a highly-opionated framework for managing Cloudformation
4
+ stacks along with all the crappy glue code you need around them.
4
5
 
5
- TODO: Delete this and the text above, and describe your gem
6
+ Stax is built as a set of ruby classes, with configuration based
7
+ around sub-classing and monkey-patching.
8
+
9
+ For now, Stax reads template files written using the
10
+ [cfer](https://github.com/seanedwards/cfer) ruby wrapper. It should be
11
+ straightforward to change to raw json/yaml, or a different wrapper by
12
+ re-implementing the methods in `lib/stax/stack/crud.rb`.
13
+
14
+ ## Concepts
15
+
16
+ ### Application
17
+
18
+ You have an application in a git repo. Our example will be called
19
+ `website`. The Stax infrastructure code and cloudformation templates
20
+ live in the same repo as the application code.
21
+
22
+ ### Branch
23
+
24
+ You can check out any branch of your repo and deploy a
25
+ fully-operational infrastructure using Stax.
26
+
27
+ Example branches might be `prod`, `stg`, `dev`, or perhaps your model
28
+ is `release/37`, `feature/38`, `hotfix/1234`, etc.
29
+
30
+ ### Stacks
31
+
32
+ Each deployable branch consists of one or more actual cloudformation
33
+ stacks. For example, our website app may consist of stacks `vpc`, `db`
34
+ and `app`.
35
+
36
+ In our experience it is better to build multiple coupled
37
+ cloudformation stacks, handling discrete parts of an application
38
+ infrastructure, rather than having a single giant template.
39
+
40
+ These stacks are connected via their outputs and input parameters. For
41
+ example, `vpc` stack outputs its subnet IDs, which are passed as
42
+ parameters to the `app` stack. Stax is designed to handle this wiring
43
+ for us.
44
+
45
+ ### Extensions
46
+
47
+ Stax is intended to be modified to handle all the hackery needed in
48
+ real-world app deployments. Each stack is modeled by subclassing the
49
+ `Stax::Stack` class, and you are encouraged to monkey-patch methods,
50
+ for example to perform extra work before/after creating or destroying
51
+ stacks.
6
52
 
7
53
  ## Installation
8
54
 
9
- Add this line to your application's Gemfile:
55
+ We like to keep all infrastructure code in a subdirectory `ops` of
56
+ application repos, but you can use any layout you like.
57
+
58
+ Example directory structure:
59
+
60
+ ```
61
+ ops/
62
+ ├── Gemfile
63
+ ├── Staxfile
64
+ ├── cf/
65
+ ├── lib/
66
+ ```
67
+
68
+ Add this line to your `ops/Gemfile`:
10
69
 
11
70
  ```ruby
12
71
  gem 'stax'
@@ -14,27 +73,160 @@ gem 'stax'
14
73
 
15
74
  And then execute:
16
75
 
17
- $ bundle
76
+ ```
77
+ $ cd ops
78
+ $ bundle
79
+ $ bundle exec stax version
80
+ ```
18
81
 
19
- Or install it yourself as:
82
+ ## Usage
20
83
 
21
- $ gem install stax
84
+ Add each of your stacks to `ops/Staxfile`:
22
85
 
23
- ## Usage
86
+ ```ruby
87
+ stack :vpc
88
+ stack :db
89
+ stack :app
90
+ ```
24
91
 
25
- TODO: Write usage instructions here
92
+ Run stax to see it has created subcommands for each of your stacks:
93
+
94
+ ```
95
+ $ bundle exec stax
96
+ Commands:
97
+ stax app # app stack
98
+ stax create # meta create task
99
+ stax db # db stack
100
+ stax delete # meta delete task
101
+ stax help [COMMAND] # Describe available commands or one specific command
102
+ stax ls # list stacks for this branch
103
+ stax version # show version
104
+ stax vpc # vpc stack
105
+
106
+ ```
107
+
108
+ with the standard create/update/delete tasks for each:
109
+
110
+ ```
111
+ $ bundle exec stax vpc
112
+ Commands:
113
+ stax vpc create # create stack
114
+ stax vpc delete # delete stack
115
+ stax vpc events # show all events for stack
116
+ stax vpc exists # test if stack exists
117
+ stax vpc generate # generate cloudformation template
118
+ stax vpc help [COMMAND] # Describe subcommands or one specific subcommand
119
+ stax vpc id [LOGICAL_ID] # get physical ID from resource logical ID
120
+ stax vpc outputs # show stack outputs
121
+ stax vpc parameters # show stack input parameters
122
+ stax vpc protection # show/set termination protection for stack
123
+ stax vpc resources # list resources for this stack
124
+ stax vpc tail # tail stack events
125
+ stax vpc template # get template of existing stack from cloudformation
126
+ stax vpc update # update stack
127
+ ```
128
+
129
+ ## Cloudformation templates
130
+
131
+ Stax will load template files from the path relative to its `Staxfile`
132
+ as `cf/$stack.rb`, e.g. `cf/vpc.rb`. Modify this using the method `Stax::Stack::cfer_template`.
133
+ See `examples` for a typical setup.
134
+
135
+ Simply control stacks using the relevant subcommands:
136
+
137
+ ```
138
+ $ stax vpc create
139
+ $ stax vpc update
140
+ $ stax vpc delete
141
+ ```
142
+
143
+ By default Stax will name stacks as `$app-$branch-$stack`. For our
144
+ example we will have e.g. `website-master-vpc`, `website-master-db`,
145
+ etc.
146
+
147
+ To change this scheme modify the methods `Stax::Base::stack_prefix`
148
+ and/or `Stax::Stack::stack_name`.
149
+
150
+ ## Stack parameters
151
+
152
+ For any given stack, subclass `Stax::Stack` and return define a hash of
153
+ parameters from the method `cfer_parameters`. For example:
154
+
155
+ ```ruby
156
+ module Stax
157
+ class App < Stack
158
+ no_commands do
159
+
160
+ def cfer_parameters
161
+ {
162
+ vpc: stack(:vpc).stack_name, # how to reference other stacks
163
+ db: stack(:db).stack_name,
164
+ ami: 'ami-e582d29f',
165
+ }
166
+ end
167
+
168
+ end
169
+ end
170
+ end
171
+ ```
172
+
173
+ Note, `Stax::Stack` objects are subclassed from
174
+ [Thor](https://github.com/erikhuda/thor), and any non-CLI command
175
+ methods must be defined inside a `no_commands` block. See examples for
176
+ clearer illustration of this.
177
+
178
+ ## Adding and modifying tasks
179
+
180
+ A strong underlying assumption of Stax is that you will always need
181
+ extra non-cloudformation glue code to handle edge-cases in your
182
+ infrastructure. This is handled by sub-classing and monkey-patching
183
+ `Stax::Stack`.
184
+
185
+ For example, in our `Stax::App` class:
186
+
187
+ ```ruby
188
+ module Stax
189
+ class App < Stack
190
+
191
+ desc 'create', 'create stack'
192
+ def create
193
+ ensure_stack :vpc, :db # make sure vpc and db stacks are created first
194
+ super # create the stack
195
+ notify_slack() # define and call any extra code you need
196
+ end
197
+
198
+ desc 'delete', 'delete stack'
199
+ def delete
200
+ super # delete the stack
201
+ cleanup_code() # do some extra work
202
+ notify_slack() # etc
203
+ end
204
+
205
+ end
206
+ end
207
+ ```
26
208
 
27
209
  ## Development
28
210
 
29
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
211
+ After checking out the repo, run `bin/setup` to install
212
+ dependencies. You can also run `bin/console` for an interactive prompt
213
+ that will allow you to experiment.
30
214
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
215
+ To install this gem onto your local machine, run `bundle exec rake
216
+ install`. To release a new version, update the version number in
217
+ `version.rb`, and then run `bundle exec rake release`, which will
218
+ create a git tag for the version, push git commits and tags, and push
219
+ the `.gem` file to [rubygems.org](https://rubygems.org).
32
220
 
33
221
  ## Contributing
34
222
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/stax. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
-
223
+ Bug reports and pull requests are welcome on GitHub at
224
+ https://github.com/[USERNAME]/stax. This project is intended to be a
225
+ safe, welcoming space for collaboration, and contributors are expected
226
+ to adhere to the [Contributor
227
+ Covenant](http://contributor-covenant.org) code of conduct.
37
228
 
38
229
  ## License
39
230
 
40
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
231
+ The gem is available as open source under the terms of the [MIT
232
+ License](http://opensource.org/licenses/MIT).
@@ -14,8 +14,10 @@ require 'stax/cfer'
14
14
  require 'stax/stack'
15
15
  require 'stax/stack/cfn'
16
16
  require 'stax/stack/crud'
17
+ require 'stax/stack/changeset'
17
18
  require 'stax/stack/parameters'
18
19
  require 'stax/stack/outputs'
20
+ require 'stax/stack/imports'
19
21
  require 'stax/stack/resources'
20
22
 
21
23
  require 'stax/mixin/ec2'
@@ -25,6 +27,7 @@ require 'stax/mixin/sg'
25
27
  require 'stax/mixin/s3'
26
28
  require 'stax/mixin/asg'
27
29
  require 'stax/mixin/ecs'
30
+ require 'stax/mixin/ecr'
28
31
  require 'stax/mixin/sqs'
29
32
  require 'stax/mixin/kms'
30
33
  require 'stax/mixin/ssm'
@@ -35,4 +38,6 @@ require 'stax/mixin/lambda'
35
38
  require 'stax/mixin/dynamodb'
36
39
  require 'stax/mixin/logs'
37
40
  require 'stax/mixin/apigw'
38
- require 'stax/mixin/firehose'
41
+ require 'stax/mixin/firehose'
42
+ require 'stax/mixin/codebuild'
43
+ require 'stax/mixin/codepipeline'
@@ -16,6 +16,7 @@ module Stax
16
16
 
17
17
  def instances(names)
18
18
  ids = describe(names).map(&:instances).flatten.map(&:instance_id)
19
+ return [] if ids.empty? # below call will return all instances in a/c if this empty
19
20
  paginate(:auto_scaling_instances) do |token|
20
21
  client.describe_auto_scaling_instances(instance_ids: ids, next_token: token)
21
22
  end
@@ -13,6 +13,7 @@ module Stax
13
13
  ]
14
14
 
15
15
  COLORS = {
16
+ ## stack status
16
17
  CREATE_COMPLETE: :green,
17
18
  DELETE_COMPLETE: :green,
18
19
  UPDATE_COMPLETE: :green,
@@ -21,6 +22,10 @@ module Stax
21
22
  UPDATE_FAILED: :red,
22
23
  ROLLBACK_IN_PROGRESS: :red,
23
24
  ROLLBACK_COMPLETE: :red,
25
+ ## resource action
26
+ Add: :green,
27
+ Modify: :yellow,
28
+ Remove: :red,
24
29
  }
25
30
 
26
31
  class << self
@@ -55,8 +60,6 @@ module Stax
55
60
  paginate(:stack_events) do |token|
56
61
  client.describe_stack_events(stack_name: name, next_token: token)
57
62
  end
58
- rescue ::Aws::CloudFormation::Errors::ValidationError => e
59
- puts e.message
60
63
  end
61
64
 
62
65
  def id(name, id)
@@ -72,7 +75,7 @@ module Stax
72
75
  end
73
76
 
74
77
  def exists?(name)
75
- Cfn.describe(name) && true
78
+ Aws::Cfn.describe(name) && true
76
79
  rescue ::Aws::CloudFormation::Errors::ValidationError
77
80
  false
78
81
  end
@@ -87,14 +90,72 @@ module Stax
87
90
  outputs(name)[key]
88
91
  end
89
92
 
93
+ ## list of this stack output exports
94
+ def exports(name)
95
+ describe(name).outputs.select(&:export_name)
96
+ end
97
+
98
+ ## list of stacks that import from this one
99
+ def imports(name)
100
+ paginate(:imports) do |next_token|
101
+ client.list_imports(export_name: name, next_token: next_token)
102
+ end
103
+ rescue ::Aws::CloudFormation::Errors::ValidationError
104
+ []
105
+ end
106
+
107
+ def validate(opt)
108
+ client.validate_template(opt)
109
+ end
110
+
111
+ def create(opt)
112
+ client.create_stack(opt)&.stack_id
113
+ end
114
+
115
+ def update(opt)
116
+ client.update_stack(opt)&.stack_id
117
+ end
118
+
90
119
  def delete(name)
91
120
  client.delete_stack(stack_name: name)
92
121
  end
93
122
 
123
+ def cancel(name)
124
+ client.cancel_update_stack(stack_name: name)
125
+ end
126
+
94
127
  def protection(name, enable)
95
128
  client.update_termination_protection(stack_name: name, enable_termination_protection: enable)
96
129
  end
97
130
 
131
+ def get_policy(opt)
132
+ client.get_stack_policy(opt).stack_policy_body
133
+ end
134
+
135
+ def set_policy(opt)
136
+ client.set_stack_policy(opt)
137
+ end
138
+
139
+ def list_change_sets(name)
140
+ paginate(:summaries) do |next_token|
141
+ client.list_change_sets(stack_name: name, next_token: next_token)
142
+ end
143
+ end
144
+
145
+ def changes(opt)
146
+ paginate(:changes) do |next_token|
147
+ client.describe_change_set(opt.merge(next_token: next_token))
148
+ end
149
+ end
150
+
151
+ def changeset(opt)
152
+ client.create_change_set(opt)
153
+ end
154
+
155
+ def execute(opt)
156
+ client.execute_change_set(opt)
157
+ end
158
+
98
159
  end
99
160
 
100
161
  end
@@ -0,0 +1,41 @@
1
+ module Stax
2
+ module Aws
3
+ class Codebuild < Sdk
4
+
5
+ class << self
6
+
7
+ def client
8
+ @_client ||= ::Aws::CodeBuild::Client.new
9
+ end
10
+
11
+ def projects(names)
12
+ client.batch_get_projects(names: names).projects
13
+ end
14
+
15
+ ## returns ids of num most recent builds for project
16
+ def builds_for_project(name, num = 100)
17
+ count = 0
18
+ next_token = nil
19
+ builds = []
20
+ loop do
21
+ r = client.list_builds_for_project(project_name: name, next_token: next_token)
22
+ builds += r.ids
23
+ break if (count += r.ids.count) >= num
24
+ break if (next_token = r.next_token).nil?
25
+ end
26
+ builds.first(num)
27
+ end
28
+
29
+ def builds(ids)
30
+ client.batch_get_builds(ids: ids).builds
31
+ end
32
+
33
+ def start(opt)
34
+ client.start_build(opt).build
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ module Stax
2
+ module Aws
3
+ class Codepipeline < Sdk
4
+
5
+ class << self
6
+
7
+ def client
8
+ @_client ||= ::Aws::CodePipeline::Client.new
9
+ end
10
+
11
+ def stages(name)
12
+ client.get_pipeline(name: name).pipeline.stages
13
+ end
14
+
15
+ def executions(name, num = nil)
16
+ opt = {pipeline_name: name, max_results: num}
17
+ token = nil
18
+ summaries = []
19
+ loop do
20
+ s = client.list_pipeline_executions(opt.merge(next_token: token))
21
+ summaries += s.pipeline_execution_summaries
22
+ break if (token = s.next_token).nil?
23
+ break if summaries.count >= num
24
+ end
25
+ summaries.first(num)
26
+ end
27
+
28
+ def execution(name, id)
29
+ client.get_pipeline_execution(pipeline_name: name, pipeline_execution_id: id).pipeline_execution
30
+ end
31
+
32
+ def state(name)
33
+ client.get_pipeline_state(name: name)
34
+ end
35
+
36
+ def start(name)
37
+ client.start_pipeline_execution(name: name).pipeline_execution_id
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+ end