cfer 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.codeclimate.yml +25 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +1168 -0
- data/.travis.yml +14 -1
- data/Gemfile +2 -0
- data/README.md +48 -10
- data/Rakefile +6 -7
- data/cfer.gemspec +2 -1
- data/examples/chef_instance.rb +56 -0
- data/examples/common/instance_deps.rb +34 -0
- data/examples/instance.rb +3 -36
- data/examples/vpc.rb +1 -1
- data/lib/cfer.rb +42 -23
- data/lib/cfer/cfn/client.rb +124 -50
- data/lib/cfer/cli.rb +13 -4
- data/lib/cfer/core/client.rb +0 -4
- data/lib/cfer/core/fn.rb +7 -7
- data/lib/cfer/core/resource.rb +1 -1
- data/lib/cfer/core/stack.rb +24 -36
- data/lib/cfer/util/error.rb +3 -0
- data/lib/cfer/version.rb +1 -1
- data/lib/cferext/aws/auto_scaling/launch_configuration.rb +15 -0
- data/lib/cferext/aws/ec2/instance.rb +3 -0
- data/lib/cferext/provisioning.rb +12 -2
- data/lib/cferext/provisioning/cfn-bootstrap.rb +186 -0
- data/lib/cferext/provisioning/chef.rb +75 -0
- metadata +58 -36
- data/cfer-demo.gif +0 -0
data/.travis.yml
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
language: ruby
|
2
2
|
install: bundle install --without debug --jobs=3 --retry=3
|
3
3
|
rvm:
|
4
|
-
- 2.1
|
4
|
+
- 2.1
|
5
|
+
- 2.2
|
6
|
+
- 2.3.0
|
5
7
|
- ruby-head
|
8
|
+
matrix:
|
9
|
+
allow_failures:
|
10
|
+
- rvm: ruby-head
|
11
|
+
branches:
|
12
|
+
only:
|
13
|
+
- master
|
14
|
+
- develop
|
6
15
|
script:
|
7
16
|
- bundle exec rspec
|
8
17
|
- bundle exec yard
|
18
|
+
addons:
|
19
|
+
code_climate:
|
20
|
+
repo_token:
|
21
|
+
secure: yokaltZRMTADMBq/htRjXYxchq4e7e66Zlvv0DrLs3yppy3bpCKbXkmtZdUm4XoxOA8fcoeFB0/VVuijmkdpJd2fAj1dc8RDb5uEdwA6ifI2ni1wKZHg15YheL4VwvDK1Nhb9Gr06uXReQ1Fy6jYcXDktyirbX7/AN/csD83IEQ29U58DVCwPxtG1k3h8ji6r/BMayzAd3T/bAeNkLd6t7YIdUAQHqIQsHsER/wQEYRTBVrx+D9b5rj2UluctfJDmpM61lvQnMt6VfgewzGXZCKNdY2DAvySaNg4+9/saZt3Ygpnt7Ef7uBMqgWTayNQ0Wk2VZSUvvLDRAKg+3WLBXTUnbFKK4/GT2T/37Rw9KQGDBJATjDLvNkS1V6Ikzg/4eNtni9RsV/bIwEaYg4CjhVEccj9fa1iPl+2Nzyw7q15UUT89TYJR3L00MQ+M7j5BDgg48kmg2tXBL62kIj/mFzEGuwNLn5nuVkwlnciQ5KCNDrQmN7XL3sPSDyIQ1dAezuj/CAqrRu43KukNZPn9TK9z/NPLUfHvco2E10Mlsw4gXiSp8j1WOmgcenivAoP2x4z5isZ2FShXkxLGq/sT0R4Ko+oGTnD/ghIHuhY3dUDfBhpOkq1wrFB73GjnUh5cYetlS3MvOj0dxT0iUK4oNp1/ds2Bn8in6juiOkN/Zc=
|
9
22
|
deploy:
|
10
23
|
provider: rubygems
|
11
24
|
api_key:
|
data/Gemfile
CHANGED
@@ -8,6 +8,7 @@ group :test do
|
|
8
8
|
gem 'rspec-mocks'
|
9
9
|
gem 'guard-rspec'
|
10
10
|
gem 'coveralls', require: false
|
11
|
+
gem "codeclimate-test-reporter", require: nil
|
11
12
|
end
|
12
13
|
|
13
14
|
group :debug do
|
@@ -15,4 +16,5 @@ group :debug do
|
|
15
16
|
gem 'pry-byebug'
|
16
17
|
gem 'pry-rescue'
|
17
18
|
gem 'pry-stack_explorer'
|
19
|
+
gem 'travis'
|
18
20
|
end
|
data/README.md
CHANGED
@@ -1,13 +1,22 @@
|
|
1
1
|
# Cfer
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/seanedwards/cfer.svg?branch=master)](https://travis-ci.org/seanedwards/cfer)
|
4
|
-
[![Coverage Status](https://coveralls.io/repos/seanedwards/cfer/badge.svg)](https://coveralls.io/r/seanedwards/cfer)
|
5
4
|
[![Gem Version](https://badge.fury.io/rb/cfer.svg)](http://badge.fury.io/rb/cfer)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/seanedwards/cfer/badges/gpa.svg)](https://codeclimate.com/github/seanedwards/cfer)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/seanedwards/cfer/badges/coverage.svg)](https://codeclimate.com/github/seanedwards/cfer/coverage)
|
7
|
+
[![Issue Count](https://codeclimate.com/github/seanedwards/cfer/badges/issue_count.svg)](https://codeclimate.com/github/seanedwards/cfer)
|
8
|
+
|
6
9
|
|
7
10
|
Cfer is a lightweight toolkit for managing CloudFormation templates.
|
8
11
|
|
9
12
|
Read about Cfer [here](http://tilmonedwards.com/2015/07/28/cfer.html).
|
10
13
|
|
14
|
+
## Support
|
15
|
+
|
16
|
+
Cfer is pre-1.0 software, and may contain bugs or incomplete features. Please see the [license](https://github.com/seanedwards/cfer/blob/master/LICENSE.txt) for disclaimers.
|
17
|
+
|
18
|
+
If you would like support or guidance on Cfer, or CloudFormation in general, I offer DevOps consulting services. Please [Contact Bitlancer](http://www.bitlancer.com/contact-us/) and we'll be happy to discuss your needs.
|
19
|
+
|
11
20
|
## Installation
|
12
21
|
|
13
22
|
Add this line to your application's Gemfile:
|
@@ -35,12 +44,12 @@ cfer converge instance -t examples/instance.rb --profile [YOUR-PROFILE] --region
|
|
35
44
|
|
36
45
|
You should see something like this:
|
37
46
|
|
38
|
-
![Demo](cfer-demo.gif)
|
47
|
+
![Demo](https://raw.githubusercontent.com/seanedwards/cfer/master/doc/cfer-demo.gif)
|
39
48
|
|
40
49
|
### Command line
|
41
50
|
|
42
51
|
Commands:
|
43
|
-
cfer converge [OPTIONS] <stack-name> #
|
52
|
+
cfer converge [OPTIONS] <stack-name> # Creates or updates a cloudformation stack according to the template
|
44
53
|
cfer generate [OPTIONS] <template.rb> # Generates a CloudFormation template by evaluating a Cfer template
|
45
54
|
cfer help [COMMAND] # Describe available commands or one specific command
|
46
55
|
cfer tail <stack-name> # Follows stack events on standard output as they occur
|
@@ -65,10 +74,12 @@ Creates or updates a CloudFormation stack according to the specified template.
|
|
65
74
|
|
66
75
|
The following options may be used with the `converge` command:
|
67
76
|
|
68
|
-
* `--follow` (`-f`): Follows stack events on standard output as the create/update process takes place.
|
77
|
+
* `--follow` (`-f`): Follows stack events on standard output as the create/update process takes place.
|
69
78
|
* `--stack-file <template.rb>`: Reads this file from the filesystem, rather than the default `<stack-name>.rb`
|
70
79
|
* `--parameters <Key1>:<Value1> <Key2>:<Value2> ...`: Specifies input parameters, which will be available to Ruby in the `parameters` hash, or to CloudFormation by using the `Fn::ref` function
|
71
80
|
* `--on-failure <DELETE|ROLLBACK|DO_NOTHING>`: Specifies the action to take when a stack creation fails. Has no effect if the stack already exists and is being updated.
|
81
|
+
* `--stack-policy <filename|URL|JSON string>` (`-s`): Stack policy to apply to the stack in order to control updates; takes a local filename containing the policy, a URL to an S3 object, or a raw JSON string.
|
82
|
+
* `--stack-policy-during-update <filename|URL|JSON string>` (`-u`): Stack policy as in `--stack-policy` option above, but applied as a temporary override to the permanent policy during stack update.
|
72
83
|
|
73
84
|
#### `tail <stack-name>`
|
74
85
|
|
@@ -76,7 +87,7 @@ Prints the latest `n` stack events, and optionally follows events while a stack
|
|
76
87
|
|
77
88
|
The following options may be used with the `tail` command:
|
78
89
|
|
79
|
-
* `--follow` (`-f`): Follows stack events on standard output as the create/update process takes place.
|
90
|
+
* `--follow` (`-f`): Follows stack events on standard output as the create/update process takes place.
|
80
91
|
* `--number` (`-n`): Print the last `n` stack events.
|
81
92
|
|
82
93
|
### Template Anatomy
|
@@ -93,8 +104,6 @@ parameter :ParameterName,
|
|
93
104
|
default: 'ParameterValue'
|
94
105
|
```
|
95
106
|
|
96
|
-
A parameter's value may have the form `@stack.output` to look up output values from other stacks in the same account and region. This works anywhere a parameter value is specified, including defaults and inputs. (See the SDK section on [Cfer Stacks](#cfer-stacks) for caveats.)
|
97
|
-
|
98
107
|
Any parameter can be referenced either in Ruby by using the `parameters` hash:
|
99
108
|
|
100
109
|
```ruby
|
@@ -139,6 +148,12 @@ Outputs may be defined using the `output` function:
|
|
139
148
|
output :OutputName, Fn::ref(:ResourceName)
|
140
149
|
```
|
141
150
|
|
151
|
+
Outputs may be retireved from other stacks anywhere in a template by using the `lookup_output` function.
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
lookup_output('stack_name', 'output_name')
|
155
|
+
```
|
156
|
+
|
142
157
|
#### Including code from multiple files
|
143
158
|
|
144
159
|
Templates can get pretty large, and splitting template code into multiple
|
@@ -229,15 +244,13 @@ stack = Cfer::stack_from_block(client: <client>) do
|
|
229
244
|
end
|
230
245
|
```
|
231
246
|
|
232
|
-
Note: Specifying a client is optional, but if no client is specified, parameter mappings will not occur.
|
233
|
-
|
234
247
|
## Contributing
|
235
248
|
|
236
249
|
This project uses [git-flow](http://nvie.com/posts/a-successful-git-branching-model/). Please name branches and pull requests according to that convention.
|
237
250
|
|
238
251
|
Always use `--no-ff` when merging into `develop` or `master`.
|
239
252
|
|
240
|
-
This project also contains a [Code of Conduct](CODE_OF_CONDUCT.md), which should be followed when submitting feedback or contributions to this project.
|
253
|
+
This project also contains a [Code of Conduct](https://github.com/seanedwards/cfer/blob/master/CODE_OF_CONDUCT.md), which should be followed when submitting feedback or contributions to this project.
|
241
254
|
|
242
255
|
### New features
|
243
256
|
|
@@ -263,3 +276,28 @@ This project also contains a [Code of Conduct](CODE_OF_CONDUCT.md), which should
|
|
263
276
|
* Merge into `develop` and `master`
|
264
277
|
* Name branch `release/<major.minor>`
|
265
278
|
|
279
|
+
# Release Notes
|
280
|
+
|
281
|
+
## 0.3.0
|
282
|
+
|
283
|
+
### Enhancements:
|
284
|
+
* `parameters` hash now includes parameters that are set on the existing stack, but not passed in via CLI during a stack update.
|
285
|
+
* `parameters` hash now includes defaults for parameters that were not passed on the CLI during a stack creation.
|
286
|
+
* Adds a `lookup_output` function, for looking up outputs of stacks in the same account+region. (See #8)
|
287
|
+
* Adds provisioning for cfn-init and chef-solo, including resource signaling.
|
288
|
+
* Adds support for stack policies.
|
289
|
+
* Cfer no longer validates parameters itself. CloudFormation will throw an error if something is wrong.
|
290
|
+
* Adds release notes to the README.
|
291
|
+
|
292
|
+
### Bugfixes:
|
293
|
+
* Removes automatic parameter mapping in favor of an explicit function available to resources. (Fixes Issue #8)
|
294
|
+
* No more double-printing the stack summary when converging a stack with tailing enabled.
|
295
|
+
* Update demo to only use 2 AZs, since us-west-1 only has two.
|
296
|
+
* `AllowedValues` attribute on parameters is now an array, not a CSV string. (Thanks to @rlister)
|
297
|
+
|
298
|
+
## 0.2.0
|
299
|
+
|
300
|
+
### Enhancements:
|
301
|
+
* Adds support for including other files via `include_template` function.
|
302
|
+
* Adds basic Dockerfile
|
303
|
+
|
data/Rakefile
CHANGED
@@ -3,13 +3,11 @@ gem 'cfer'
|
|
3
3
|
require 'cfer'
|
4
4
|
require 'highline'
|
5
5
|
|
6
|
-
Cfer::LOGGER.level = Logger::DEBUG
|
7
|
-
|
8
6
|
task :default => [:spec]
|
9
7
|
|
10
8
|
task :config_aws, [:profile] do |t, args|
|
11
|
-
Aws.config.update region: ENV['AWS_REGION'] || 'us-east-1',
|
12
|
-
credentials: Aws::SharedCredentials.new(profile_name: ENV['AWS_PROFILE'] || 'default')
|
9
|
+
Aws.config.update region: ENV['AWS_REGION'] || ask('AWS Region?') { |q| q.default = 'us-east-1' },
|
10
|
+
credentials: Aws::SharedCredentials.new(profile_name: ENV['AWS_PROFILE'] || ask('AWS Profile?') { |q| q.default = 'default' })
|
13
11
|
end
|
14
12
|
|
15
13
|
task :vpc => :config_aws do |t, args|
|
@@ -22,7 +20,7 @@ task :describe_vpc => :config_aws do
|
|
22
20
|
Cfer.describe! 'vpc'
|
23
21
|
end
|
24
22
|
|
25
|
-
task :instance => :
|
23
|
+
task :instance => :vpc do |t, args|
|
26
24
|
key_pair = ask("Enter your EC2 KeyPair name: ")
|
27
25
|
|
28
26
|
Cfer.converge! 'instance',
|
@@ -48,10 +46,11 @@ task :converge => [:vpc, :instance]
|
|
48
46
|
# This task isn't really part of Cfer.
|
49
47
|
# It just makes it easier for me to release new versions.
|
50
48
|
task :release do
|
49
|
+
`git checkout master`
|
50
|
+
`git merge develop --no-ff -m 'Merge from develop for release'`
|
51
|
+
|
51
52
|
require_relative 'lib/cfer/version.rb'
|
52
53
|
|
53
|
-
`git checkout master`
|
54
|
-
`git merge develop --no-ff -m 'Merge from develop for release v#{Cfer::VERSION}'`
|
55
54
|
`git tag -m "Release v#{Cfer::VERSION}" #{Cfer::VERSION}`
|
56
55
|
end
|
57
56
|
|
data/cfer.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "cfer"
|
8
8
|
spec.version = Cfer::VERSION
|
9
9
|
spec.authors = ["Sean Edwards"]
|
10
|
-
spec.email = ["stedwards87+
|
10
|
+
spec.email = ["stedwards87+cfer@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{Toolkit for automating infrastructure using AWS CloudFormation}
|
13
13
|
spec.description = spec.summary
|
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_runtime_dependency 'highline'
|
31
31
|
spec.add_runtime_dependency 'table_print'
|
32
32
|
spec.add_runtime_dependency "rake"
|
33
|
+
spec.add_runtime_dependency "erubis"
|
33
34
|
|
34
35
|
spec.add_development_dependency "bundler"
|
35
36
|
spec.add_development_dependency "yard"
|
@@ -0,0 +1,56 @@
|
|
1
|
+
description 'Example stack template for a small EC2 instance'
|
2
|
+
|
3
|
+
# NOTE: This template depends on vpc.rb
|
4
|
+
|
5
|
+
# Include common template code that will be used for examples that create EC2 instances.
|
6
|
+
include_template 'common/instance_deps.rb'
|
7
|
+
|
8
|
+
resource :instance, "AWS::EC2::Instance",
|
9
|
+
# Set a creation policy so that the stack will wait for
|
10
|
+
# on-instance provisioning to complete before marking the instance
|
11
|
+
# as done.
|
12
|
+
:CreationPolicy => {
|
13
|
+
:ResourceSignal => {
|
14
|
+
:Count => 1
|
15
|
+
}
|
16
|
+
} do
|
17
|
+
# Chef provisioning depends on cfn-init, so set that up first.
|
18
|
+
# We will have the initial provisioning set up cfn-hup, install chef, and run our cookbooks.
|
19
|
+
# Cfn-hup will only rerun chef when the metadata changes.
|
20
|
+
cfn_init_setup signal: :instance,
|
21
|
+
cfn_init_config_set: [ :cfn_hup, :install_chef, :run_chef],
|
22
|
+
cfn_hup_config_set: [ :cfn_hup, :run_chef]
|
23
|
+
|
24
|
+
# Configure chef to generate a Berksfile that will download the AWS cookbook from the Chef supermarket.
|
25
|
+
# Set the run list to run the AWS cookbook, so our instance will have the AWS SDK available.
|
26
|
+
chef_solo version: 'latest',
|
27
|
+
node: {
|
28
|
+
cfer: {
|
29
|
+
demo: {
|
30
|
+
welcome: "Welcome to Cfer!"
|
31
|
+
}
|
32
|
+
},
|
33
|
+
run_list: 'recipe[ec2-demo]'
|
34
|
+
},
|
35
|
+
# We specify a berksfile inline, but you could read this from somewhere else in your repo too.
|
36
|
+
# This uses a simple cookbook to write a file, similar to the instance.rb example.
|
37
|
+
# Review this cookbook here: https://github.com/seanedwards/cfer-cookbook-demo
|
38
|
+
berksfile: <<-EOF
|
39
|
+
source "https://supermarket.chef.io"
|
40
|
+
cookbook 'ec2-demo', github: 'seanedwards/cfer-cookbook-demo', branch: 'master'
|
41
|
+
EOF
|
42
|
+
|
43
|
+
image_id Fn::ref(:ImageId)
|
44
|
+
instance_type Fn::ref(:InstanceType)
|
45
|
+
key_name Fn::ref(:KeyName)
|
46
|
+
|
47
|
+
network_interfaces [ {
|
48
|
+
AssociatePublicIpAddress: "true",
|
49
|
+
DeviceIndex: "0",
|
50
|
+
GroupSet: [ Fn::ref(:instancesg) ],
|
51
|
+
SubnetId: Fn::ref(:SubnetId)
|
52
|
+
} ]
|
53
|
+
end
|
54
|
+
|
55
|
+
output :instance, Fn::ref(:instance)
|
56
|
+
output :instanceip, Fn::get_att(:instance, :PublicIp)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# By not specifying a default value, a parameter becomes required.
|
2
|
+
# Specify this parameter by adding `--parameters KeyName:<ec2-keyname>` to your CLI options.
|
3
|
+
parameter :KeyName
|
4
|
+
|
5
|
+
# We define some more parameters the same way we did in the VPC template.
|
6
|
+
# Cfer will fetch the output values from the `vpc` stack we created earlier.
|
7
|
+
#
|
8
|
+
# If you created the VPC stack with a different name, you can overwrite these default values
|
9
|
+
# by adding `Vpc:<vpc_stack_name> to your `--parameters` option
|
10
|
+
parameter :Vpc, default: 'vpc'
|
11
|
+
parameter :VpcId, default: lookup_output(parameters[:Vpc], 'vpcid')
|
12
|
+
parameter :SubnetId, default: lookup_output(parameters[:Vpc], 'subnetid1')
|
13
|
+
|
14
|
+
# This is the Ubuntu 14.04 LTS HVM AMI provided by Amazon.
|
15
|
+
parameter :ImageId, default: 'ami-fce3c696'
|
16
|
+
parameter :InstanceType, default: 't2.nano'
|
17
|
+
|
18
|
+
# Define a security group to be applied to an instance.
|
19
|
+
# This one will allow SSH access from anywhere, and no other inbound traffic.
|
20
|
+
resource :instancesg, "AWS::EC2::SecurityGroup" do
|
21
|
+
group_description 'Wide-open SSH'
|
22
|
+
vpc_id Fn::ref(:VpcId)
|
23
|
+
|
24
|
+
# Parameter values can be Ruby arrays and hashes. These will be transformed to JSON.
|
25
|
+
# You could write your own functions to make stuff like this easier, too.
|
26
|
+
security_group_ingress [
|
27
|
+
{
|
28
|
+
CidrIp: '0.0.0.0/0',
|
29
|
+
IpProtocol: 'tcp',
|
30
|
+
FromPort: 22,
|
31
|
+
ToPort: 22
|
32
|
+
}
|
33
|
+
]
|
34
|
+
end
|
data/examples/instance.rb
CHANGED
@@ -2,42 +2,8 @@ description 'Example stack template for a small EC2 instance'
|
|
2
2
|
|
3
3
|
# NOTE: This template depends on vpc.rb
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
# Specify this parameter by adding `--parameters KeyName:<ec2-keyname>` to your CLI options.
|
8
|
-
parameter :KeyName
|
9
|
-
|
10
|
-
# We define some more parameters the same way we did in the VPC template.
|
11
|
-
# Cfer will interpret the default value by looking up the stack output named `vpcid`
|
12
|
-
# on the stack named `vpc`.
|
13
|
-
#
|
14
|
-
# If you created the VPC stack with a different name, you can overwrite these default values
|
15
|
-
# by adding `VpcId:@<vpc-stack-name>.vpcid SubnetId:@<vpc-stack-name>.subnetid1`
|
16
|
-
# to your `--parameters` option
|
17
|
-
parameter :VpcId, default: '@vpc.vpcid'
|
18
|
-
parameter :SubnetId, default: '@vpc.subnetid1'
|
19
|
-
|
20
|
-
# This is the Ubuntu 14.04 LTS HVM AMI provided by Amazon.
|
21
|
-
parameter :ImageId, default: 'ami-d05e75b8'
|
22
|
-
parameter :InstanceType, default: 't2.medium'
|
23
|
-
|
24
|
-
# Define a security group to be applied to an instance.
|
25
|
-
# This one will allow SSH access from anywhere, and no other inbound traffic.
|
26
|
-
resource :instancesg, "AWS::EC2::SecurityGroup" do
|
27
|
-
group_description 'Wide-open SSH'
|
28
|
-
vpc_id Fn::ref(:VpcId)
|
29
|
-
|
30
|
-
# Parameter values can be Ruby arrays and hashes. These will be transformed to JSON.
|
31
|
-
# You could write your own functions to make stuff like this easier, too.
|
32
|
-
security_group_ingress [
|
33
|
-
{
|
34
|
-
CidrIp: '0.0.0.0/0',
|
35
|
-
IpProtocol: 'tcp',
|
36
|
-
FromPort: 22,
|
37
|
-
ToPort: 22
|
38
|
-
}
|
39
|
-
]
|
40
|
-
end
|
5
|
+
# Include common template code that will be used for examples that create EC2 instances.
|
6
|
+
include_template 'common/instance_deps.rb'
|
41
7
|
|
42
8
|
# We can define extension objects, which extend the basic JSON-building
|
43
9
|
# functionality of Cfer. Cfer provides a few of these, but you're free
|
@@ -82,3 +48,4 @@ resource :instance, "AWS::EC2::Instance" do
|
|
82
48
|
end
|
83
49
|
|
84
50
|
output :instance, Fn::ref(:instance)
|
51
|
+
output :instanceip, Fn::get_att(:instance, :PublicIp)
|
data/examples/vpc.rb
CHANGED
@@ -49,7 +49,7 @@ resource :routetable, 'AWS::EC2::RouteTable' do
|
|
49
49
|
vpc_id Fn::ref(:vpc)
|
50
50
|
end
|
51
51
|
|
52
|
-
(1..
|
52
|
+
(1..2).each do |i|
|
53
53
|
resource "subnet#{i}", 'AWS::EC2::Subnet' do
|
54
54
|
# Other CloudFormation intrinsics, such as `Fn::Select` and `AWS::Region` are available as Ruby objects
|
55
55
|
# Inspecting these functions will reveal that they simply return a Ruby hash representing the same CloudFormation structures
|
data/lib/cfer.rb
CHANGED
@@ -20,22 +20,30 @@ module Cfer
|
|
20
20
|
module Core
|
21
21
|
end
|
22
22
|
|
23
|
+
%w{
|
24
|
+
DB
|
25
|
+
ASG
|
26
|
+
}.each do |acronym|
|
27
|
+
ActiveSupport::Inflector.inflections.acronym acronym
|
28
|
+
end
|
29
|
+
|
23
30
|
# The Cfer logger
|
24
31
|
LOGGER = Logger.new(STDERR)
|
25
32
|
LOGGER.level = Logger::INFO
|
26
|
-
LOGGER.formatter = proc { |severity,
|
27
|
-
msg =
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
LOGGER.formatter = proc { |severity, _datetime, _progname, msg|
|
34
|
+
msg =
|
35
|
+
case severity
|
36
|
+
when 'FATAL'
|
37
|
+
Rainbow(msg).red.bright
|
38
|
+
when 'ERROR'
|
39
|
+
Rainbow(msg).red
|
40
|
+
when 'WARN'
|
41
|
+
Rainbow(msg).yellow
|
42
|
+
when 'DEBUG'
|
43
|
+
Rainbow(msg).black.bright
|
44
|
+
else
|
45
|
+
msg
|
46
|
+
end
|
39
47
|
|
40
48
|
"#{msg}\n"
|
41
49
|
}
|
@@ -47,8 +55,8 @@ module Cfer
|
|
47
55
|
tmpl = options[:template] || "#{stack_name}.rb"
|
48
56
|
cfn = options[:aws_options] || {}
|
49
57
|
|
50
|
-
cfn_stack = Cfer::Cfn::Client.new(cfn.merge(stack_name: stack_name))
|
51
|
-
stack = Cfer::stack_from_file(tmpl, options.merge(client: cfn_stack))
|
58
|
+
cfn_stack = options[:cfer_client] || Cfer::Cfn::Client.new(cfn.merge(stack_name: stack_name))
|
59
|
+
stack = options[:cfer_stack] || Cfer::stack_from_file(tmpl, options.merge(client: cfn_stack))
|
52
60
|
|
53
61
|
begin
|
54
62
|
cfn_stack.converge(stack, options)
|
@@ -58,25 +66,36 @@ module Cfer
|
|
58
66
|
rescue Aws::CloudFormation::Errors::ValidationError => e
|
59
67
|
Cfer::LOGGER.info "CFN validation error: #{e.message}"
|
60
68
|
end
|
61
|
-
describe! stack_name, options
|
69
|
+
describe! stack_name, options unless options[:follow]
|
62
70
|
end
|
63
71
|
|
64
72
|
def describe!(stack_name, options = {})
|
65
73
|
config(options)
|
66
74
|
cfn = options[:aws_options] || {}
|
67
|
-
cfn_stack = Cfer::Cfn::Client.new(cfn.merge(stack_name: stack_name))
|
75
|
+
cfn_stack = options[:cfer_client] || Cfer::Cfn::Client.new(cfn.merge(stack_name: stack_name))
|
76
|
+
cfn_stack = cfn_stack.fetch_stack
|
68
77
|
|
69
78
|
Cfer::LOGGER.debug "Describe stack: #{cfn_stack}"
|
70
79
|
|
71
|
-
case options[:output_format]
|
80
|
+
case options[:output_format]
|
72
81
|
when 'json'
|
73
82
|
puts render_json(cfn_stack, options)
|
74
|
-
when 'table'
|
83
|
+
when 'table', nil
|
75
84
|
puts "Status: #{cfn_stack[:stack_status]}"
|
76
85
|
puts "Description: #{cfn_stack[:description]}" if cfn_stack[:description]
|
77
86
|
puts ""
|
78
|
-
|
79
|
-
|
87
|
+
def tablify(list, type)
|
88
|
+
list ||= []
|
89
|
+
list.map { |param|
|
90
|
+
{
|
91
|
+
:Type => type.to_s.titleize,
|
92
|
+
:Key => param[:"#{type}_key"],
|
93
|
+
:Value => param[:"#{type}_value"]
|
94
|
+
}
|
95
|
+
}
|
96
|
+
end
|
97
|
+
parameters = tablify(cfn_stack[:parameters] || [], 'parameter')
|
98
|
+
outputs = tablify(cfn_stack[:outputs] || [], 'output')
|
80
99
|
tp parameters + outputs, :Type, :Key, {:Value => {:width => 80}}
|
81
100
|
else
|
82
101
|
raise Cfer::Util::CferError, "Invalid output format #{options[:output_format]}."
|
@@ -86,7 +105,7 @@ module Cfer
|
|
86
105
|
def tail!(stack_name, options = {}, &block)
|
87
106
|
config(options)
|
88
107
|
cfn = options[:aws_options] || {}
|
89
|
-
cfn_client = Cfer::Cfn::Client.new(cfn.merge(stack_name: stack_name))
|
108
|
+
cfn_client = options[:cfer_client] || Cfer::Cfn::Client.new(cfn.merge(stack_name: stack_name))
|
90
109
|
if block
|
91
110
|
cfn_client.tail(options, &block)
|
92
111
|
else
|
@@ -143,7 +162,7 @@ module Cfer
|
|
143
162
|
|
144
163
|
def render_json(obj, options = {})
|
145
164
|
if options[:pretty_print]
|
146
|
-
puts JSON.pretty_generate(obj)
|
165
|
+
puts JSON.pretty_generate(obj, options)
|
147
166
|
else
|
148
167
|
puts obj.to_json
|
149
168
|
end
|