admiral-cloudformation 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ sublime.sublime-*
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p547
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in admiral.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Peter T. Brown
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Admiral for AWS CloudFormation
2
+
3
+ An Admiral module that implements tasks for wielding AWS CloudFormation templates. Use it to manage CloudFormation templates and their parameters.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile (recommended):
8
+
9
+ gem 'admiral-cloudformation'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install admiral-cloudformation
18
+
19
+ ## Usage
20
+
21
+ On your command line type:
22
+
23
+ $ admiral cf help
24
+
25
+ To see a list of available commands. Make sure your bundle bin is in your PATH.
26
+
27
+ The following commands are available:
28
+
29
+ ```
30
+ Commands:
31
+ admiral cf create # Create new CloudFormation stack for environment.
32
+ admiral cf destroy # Destroy the existing CloudFormation stack.
33
+ admiral cf help [COMMAND] # Describe subcommands or one specific subcommand
34
+ admiral cf update # Update the existing CloudFormation stack
35
+
36
+ Options:
37
+ --env, [--environment=ENVIRONMENT] # The environment (e.g. staging or production). Can also be specified with ADMIRAL_ENV.
38
+ # Default: production
39
+ [--template=TEMPLATE] # Path to CloudFormation JSON template.
40
+ # Default: CloudFormation.template
41
+ [--params=PARAMS] # Path to override parameter definitions file. Defaults to <environment>.json
42
+ ```
43
+
44
+ # Setup and Configuration
45
+
46
+ Admiral CloudFormation is designed around the concept of deployment environments. You parameterize your CloudFormation templates, then encode specific parameter values in JSON files for each distinct environment.
47
+
48
+ For example you may have CloudFormation templates for your database servers and your web application servers, and distinct configurations for production, staging and test environments.
49
+
50
+ CloudFormation provides a facility to parameterize templates via the [`Parameters`](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html) section. For example:
51
+
52
+ ```javascript
53
+ ...
54
+ "InstanceType": {
55
+ "Description": "The type of instance to launch.",
56
+ "Type": "String",
57
+ "Default": "t2.small"
58
+ },
59
+ ...
60
+ ```
61
+
62
+ Admiral CloudFormation let's you specify specific values. For example:
63
+
64
+ ```javascript
65
+ {
66
+ "InstanceCount":"2",
67
+ "InstanceType": "t2.medium",
68
+ }
69
+ ```
70
+
71
+ ## Examples
72
+
73
+ To create a new CloudFormation stack (and its associated resources) using a staging configuration:
74
+
75
+ $ admiral cf create --environment staging --template ./CloudFormation.template
76
+
77
+ # CloudFormation Templates
78
+
79
+ Example CloudFormation templates for ElasticSearch, Meteor and MongoDB are included in the `examples` directory.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/admiral.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "admiral-cloudformation"
7
+ spec.version = '0.0.2'
8
+ spec.authors = ["Peter T. Brown"]
9
+ spec.email = ["p@ptb.io"]
10
+ spec.description = %q{An Admiral module that implements tasks for wielding AWS CloudFormation templates. Use it to manage CloudFormation templates and their parameters.}
11
+ spec.summary = %q{A command line tool for wielding cloudformation templates.}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake"
21
+ spec.add_dependency 'aws-sdk', '< 2'
22
+ spec.add_dependency 'thor', '~> 0.19'
23
+ spec.add_dependency 'admiral', '~> 0.0.1'
24
+ end
@@ -0,0 +1,315 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Parameters": {
4
+ "CookbookRepo": {
5
+ "Description": "GitURL",
6
+ "Type": "String",
7
+ "Default": "https://github.com/ThoughtWorksStudios/opsworks-elasticsearch-cookbook"
8
+ },
9
+
10
+ "CookbookRepoRevision": {
11
+ "Description": "Git Revision/Tag",
12
+ "Type": "String",
13
+ "Default": "0.0.1"
14
+ },
15
+
16
+ "ElasticSearchVersion": {
17
+ "Description": "The version of ElasticSearch to install.",
18
+ "Type": "String",
19
+ "Default": "1.3.5"
20
+ },
21
+
22
+ "AwsRegion": {
23
+ "Description": "The AWS region",
24
+ "Type": "String",
25
+ "Default": "us-west-2"
26
+ },
27
+
28
+ "ElasticSearchAWSCloudPluginVersion": {
29
+ "Description": "The version of the ElasticSearch AWS Cloud Plugin to install. Note that this version MUST correspond to the targeted version of ElasticSearch. See https://github.com/elasticsearch/elasticsearch-cloud-aws for the version compatibility table.",
30
+ "Type": "String",
31
+ "Default": "2.3.0"
32
+ },
33
+
34
+ "RecipeList": {
35
+ "Description": "The list of cookbooks to include when setting up the cluster.",
36
+ "Type": "CommaDelimitedList",
37
+ "Default":"apt, ark,elasticsearch, elasticsearch::aws, elasticsearch::proxy, java, layer-custom::esplugins, layer-custom::allocation-awareness, layer-custom::esmonit, layer-custom::cloudwatch-custom"
38
+ },
39
+
40
+ "SSLCertificateName": {
41
+ "Description": "The SSL certificate.",
42
+ "Type": "String"
43
+ },
44
+
45
+ "InstanceCount": {
46
+ "Description": "Number of nodes to spin up in the cluster. This also configures the `expected_nodes` setting in ElasticSearch, which serves as a hint when the cluster considers shard reallocation.",
47
+ "Type": "String"
48
+ },
49
+
50
+ "InstanceType": {
51
+ "Description": "The type of instance to launch.",
52
+ "Type": "String",
53
+ "Default": "t2.small"
54
+ },
55
+
56
+ "MinMasterNodes": {
57
+ "Description": "Number of master eligible nodes visible to a given node before accepting requests. When this criterion is not satisfied, a given node will assume it has split off from from the cluster. This setting this helps avoid a catastrophic split-brain scenario in the cluster. This is typically is set to [N/2 + 1] nodes.",
58
+ "Type": "String"
59
+ },
60
+
61
+ "SearchUser": {
62
+ "Description": "username to access the ElasticSearch cluster.",
63
+ "Type": "String"
64
+ },
65
+
66
+ "SearchPassword": {
67
+ "Description": "password to access the ElasticSearch cluster.",
68
+ "Type": "String"
69
+ },
70
+
71
+ "ClusterName": {
72
+ "Description": "The name of the ElasticSearch cluster.",
73
+ "Type": "String"
74
+ },
75
+
76
+ "Route53ZoneName": {
77
+ "Description": "Route53 zone under which to setup the DNS record.",
78
+ "Type": "String"
79
+ },
80
+
81
+ "SearchDomainName": {
82
+ "Description": "Domain name to register for the cluster under Route53.",
83
+ "Type": "String"
84
+ },
85
+
86
+ "SshKeyName": {
87
+ "Description": "SSH key name for EC2 instances.",
88
+ "Type": "String"
89
+ },
90
+
91
+ "PaperTrailHost": {
92
+ "Description": "The PaperTrail endpoint hostname. Only required if you add the papertrail cookbook.",
93
+ "Type": "String",
94
+ "Default": "logs.papertrailapp.com"
95
+ },
96
+
97
+ "PaperTrailPort": {
98
+ "Description": "The PaperTrail endpoint port. Only required if you add the papertrail cookbook.",
99
+ "Type": "Number",
100
+ "Default": 0,
101
+ "MinValue" : "0",
102
+ "MaxValue" : "65535"
103
+ },
104
+
105
+ "SecurityGroupLoadBalancer": {
106
+ "Description": "The load balancer security group.",
107
+ "Type": "String"
108
+ },
109
+
110
+ "SecurityGroupSearchLayer": {
111
+ "Description": "The search layer security group.",
112
+ "Type": "String"
113
+ }
114
+
115
+ },
116
+
117
+ "Outputs": {
118
+ "StackId": {
119
+ "Description": "opsworks stack id ",
120
+ "Value": { "Ref": "SearchStack"}
121
+ },
122
+
123
+ "LayerId": {
124
+ "Description": "opsworks search layer id ",
125
+ "Value": { "Ref": "SearchLayer"}
126
+ }
127
+
128
+ },
129
+
130
+ "Resources": {
131
+
132
+ "LoadBalancer" : {
133
+ "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
134
+ "Properties" : {
135
+ "AvailabilityZones" : { "Fn::GetAZs" : "" },
136
+ "Listeners" : [
137
+ {
138
+ "LoadBalancerPort" : "443",
139
+ "InstancePort" : "80",
140
+ "Protocol" : "HTTPS",
141
+ "SSLCertificateId": {
142
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":server-certificate/", { "Ref" : "SSLCertificateName" }]]
143
+ }
144
+ }
145
+ ],
146
+ "HealthCheck" : {
147
+ "Target" : "TCP:80",
148
+ "HealthyThreshold" : "2",
149
+ "UnhealthyThreshold" : "8",
150
+ "Interval" : "30",
151
+ "Timeout" : "20"
152
+ },
153
+ "SecurityGroups": [
154
+ {"Ref": "SecurityGroupLoadBalancer"}
155
+ ]
156
+ }
157
+ },
158
+
159
+ "DNSRecord": {
160
+ "Type" : "AWS::Route53::RecordSet",
161
+ "Properties" : {
162
+ "HostedZoneName" : {"Ref": "Route53ZoneName"},
163
+ "Type" : "CNAME",
164
+ "Name" : { "Ref": "SearchDomainName"},
165
+ "ResourceRecords" : [ {"Fn::GetAtt":["LoadBalancer","DNSName"]}],
166
+ "TTL" : "30"
167
+ }
168
+ },
169
+
170
+ "ELBAttachment" : {
171
+ "Type" : "AWS::OpsWorks::ElasticLoadBalancerAttachment",
172
+ "Properties" : {
173
+ "ElasticLoadBalancerName" : { "Ref" : "LoadBalancer" },
174
+ "LayerId" : { "Ref" : "SearchLayer" }
175
+ }
176
+ },
177
+
178
+
179
+ "SearchStack": {
180
+ "Type": "AWS::OpsWorks::Stack",
181
+ "Properties": {
182
+ "Name": {
183
+ "Ref": "AWS::StackName"
184
+ },
185
+ "CustomJson": {
186
+ "java": {
187
+ "jdk_version": "7",
188
+ "oracle": {
189
+ "accept_oracle_download_terms": "true"
190
+ },
191
+ "accept_license_agreement": "true",
192
+ "install_flavor": "oracle"
193
+ },
194
+ "papertrail": {
195
+ "remote_host": { "Ref": "PaperTrailHost" },
196
+ "remote_port": { "Ref": "PaperTrailPort" },
197
+ "watch_files": [
198
+ { "filename": { "Fn::Join": ["", ["/usr/local/var/log/elasticsearch/", { "Ref": "ClusterName" }, ".log"]] }, "tag": "search" },
199
+ { "filename": { "Fn::Join": ["", ["/usr/local/var/log/elasticsearch/", { "Ref": "ClusterName" }, "_index_indexing_slowlog.log"]] }, "tag": "indexing-slowlog" },
200
+ { "filename": { "Fn::Join": ["", ["/usr/local/var/log/elasticsearch/", { "Ref": "ClusterName" }, "_index_search_slowlog.log"]] }, "tag": "search-slowlog" }
201
+ ]
202
+ },
203
+ "elasticsearch": {
204
+ "version": { "Ref": "ElasticSearchVersion" },
205
+ "plugins" : {
206
+ "elasticsearch/elasticsearch-cloud-aws": {
207
+ "version": { "Ref": "ElasticSearchAWSCloudPluginVersion" }
208
+ }
209
+ },
210
+ "nginx": {
211
+ "users": [{
212
+ "username": { "Ref": "SearchUser" },
213
+ "password": { "Ref": "SearchPassword" }
214
+ }],
215
+ "allow_cluster_api": "true",
216
+ "port": 80
217
+ },
218
+ "cluster": {
219
+ "name": { "Ref" : "ClusterName" }
220
+ },
221
+ "gateway": {
222
+ "expected_nodes": { "Ref": "InstanceCount" }
223
+ },
224
+ "discovery": {
225
+ "type": "ec2",
226
+ "zen": {
227
+ "minimum_master_nodes": { "Ref": "MinMasterNodes" },
228
+ "ping": {
229
+ "multicast": {
230
+ "enabled": false
231
+ }
232
+ }
233
+ },
234
+ "ec2": {
235
+ "tag": {
236
+ "opsworks:stack": {
237
+ "Ref": "AWS::StackName"
238
+ }
239
+ }
240
+ }
241
+ },
242
+ "path": {
243
+ "data": "/mnt/elasticsearch-data"
244
+ },
245
+ "cloud": {
246
+ "aws": {
247
+ "region": { "Ref": "AwsRegion" }
248
+ }
249
+ },
250
+ "custom_config": {
251
+ "cluster.routing.allocation.awareness.attributes": "rack_id",
252
+ "index": "\n analysis:\n analyzer:\n default_index:\n filter:\n - standard\n - lowercase\n - snowball\n tokenizer: standard\n default_search:\n tokenizer: standard\n filter:\n - standard\n - lowercase\n - snowball\n"
253
+ }
254
+ }
255
+ },
256
+ "ServiceRoleArn": {
257
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":role/aws-opsworks-service-role"]]
258
+ },
259
+ "DefaultInstanceProfileArn": {
260
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":instance-profile/aws-opsworks-ec2-role"]]
261
+ },
262
+ "ConfigurationManager": {
263
+ "Name": "Chef",
264
+ "Version": "11.10"
265
+ },
266
+ "ChefConfiguration": {
267
+ "BerkshelfVersion": "3.1.3",
268
+ "ManageBerkshelf": true
269
+ },
270
+ "DefaultOs": "Amazon Linux 2015.03",
271
+ "DefaultRootDeviceType": "ebs",
272
+ "DefaultSshKeyName": { "Ref": "SshKeyName" },
273
+ "UseCustomCookbooks": true,
274
+ "UseOpsworksSecurityGroups": false,
275
+ "CustomCookbooksSource": {
276
+ "Type": "git",
277
+ "Url": {
278
+ "Ref": "CookbookRepo"
279
+ },
280
+ "Revision": { "Ref": "CookbookRepoRevision" }
281
+ }
282
+ }
283
+ },
284
+
285
+ "SearchLayer": {
286
+ "Type": "AWS::OpsWorks::Layer",
287
+ "Properties": {
288
+ "StackId": {
289
+ "Ref": "SearchStack"
290
+ },
291
+ "Name": "Search",
292
+ "Type": "custom",
293
+ "Shortname": "search",
294
+ "CustomRecipes": {
295
+ "Setup": { "Ref": "RecipeList" }
296
+ },
297
+ "EnableAutoHealing": false,
298
+ "AutoAssignElasticIps": false,
299
+ "AutoAssignPublicIps": true,
300
+ "VolumeConfigurations": [
301
+ {
302
+ "MountPoint": "/mnt/elasticsearch-data",
303
+ "NumberOfDisks": 1,
304
+ "Size": 200,
305
+ "VolumeType": "gp2"
306
+ }
307
+ ],
308
+ "CustomSecurityGroupIds": [
309
+ {"Ref": "SecurityGroupSearchLayer"}
310
+ ]
311
+ }
312
+ }
313
+
314
+ }
315
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "Route53ZoneName": "example.io.",
3
+ "SearchDomainName": "search.example.io",
4
+ "SSLCertificateName": "search.example.io",
5
+ "SshKeyName": "production",
6
+ "InstanceCount":"2",
7
+ "InstanceType": "t2.medium",
8
+ "ElasticSearchVersion": "1.4.4",
9
+ "ElasticSearchAWSCloudPluginVersion": "2.4.1",
10
+ "SearchUser":"admin",
11
+ "SearchPassword":"example-password",
12
+ "ClusterName": "staging-cluster",
13
+ "MinMasterNodes": "1",
14
+ "SecurityGroupLoadBalancer": "sg-8aab365ef",
15
+ "SecurityGroupSearchLayer": "sg-9e9d35f8"
16
+ }
@@ -0,0 +1,249 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Parameters": {
4
+ "CookbookRepo": {
5
+ "Description": "GitURL",
6
+ "Type": "String",
7
+ "Default": "https://github.com/flippyhead/chef-mongodb"
8
+ },
9
+
10
+ "CookbookRepoRevision": {
11
+ "Description": "Git Revision/Tag",
12
+ "Type": "String",
13
+ "Default": "0.0.1"
14
+ },
15
+
16
+ "Route53ZoneName": {
17
+ "Description": "Route53 zone under which to setup the DNS record.",
18
+ "Type": "String"
19
+ },
20
+
21
+ "AppDomainName": {
22
+ "Description": "Domain name to register for the app under Route53.",
23
+ "Type": "String"
24
+ },
25
+
26
+ "SSLCertificateName": {
27
+ "Description": "The SSL certificate.",
28
+ "Type": "String"
29
+ },
30
+
31
+ "SshKeyName": {
32
+ "Description": "SSH key name for EC2 instances.",
33
+ "Type": "String"
34
+ },
35
+
36
+ "InstanceCount": {
37
+ "Description": "The number of instances to launch.",
38
+ "Type": "Number",
39
+ "Default": 1
40
+ },
41
+
42
+ "InstanceType": {
43
+ "Description": "The type of instance to launch.",
44
+ "Type": "String",
45
+ "Default": "t2.small"
46
+ },
47
+
48
+ "SecurityGroupLoadBalancer": {
49
+ "Description": "The load balancer security group.",
50
+ "Type": "String"
51
+ },
52
+
53
+ "SecurityGroupMeteorLayer": {
54
+ "Description": "The meteor layer security group.",
55
+ "Type": "String"
56
+ }
57
+
58
+ },
59
+
60
+ "Outputs": {
61
+ "StackId": {
62
+ "Description": "opsworks stack id ",
63
+ "Value": { "Ref": "MeteorStack"}
64
+ },
65
+
66
+ "LayerId": {
67
+ "Description": "opsworks search layer id ",
68
+ "Value": { "Ref": "MeteorLayer"}
69
+ },
70
+
71
+ "PrimaryAppId": {
72
+ "Description": "fetching app id ",
73
+ "Value": { "Ref": "FetchingApp"}
74
+ },
75
+
76
+ "SecondaryAppId": {
77
+ "Description": "exporter app id ",
78
+ "Value": { "Ref": "FetchingExporter"}
79
+ }
80
+
81
+ },
82
+
83
+ "Resources": {
84
+
85
+ "LoadBalancer" : {
86
+ "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
87
+ "Properties" : {
88
+ "AvailabilityZones" : { "Fn::GetAZs" : "" },
89
+ "Listeners" : [
90
+ {
91
+ "LoadBalancerPort" : "443",
92
+ "InstancePort" : "80",
93
+ "Protocol" : "SSL",
94
+ "SSLCertificateId": {
95
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":server-certificate/", { "Ref" : "SSLCertificateName" }]]
96
+ }
97
+ },
98
+ {
99
+ "LoadBalancerPort" : "80",
100
+ "InstancePort" : "80",
101
+ "Protocol" : "HTTP"
102
+ }
103
+ ],
104
+ "HealthCheck" : {
105
+ "Target" : "TCP:80",
106
+ "HealthyThreshold" : "2",
107
+ "UnhealthyThreshold" : "8",
108
+ "Interval" : "30",
109
+ "Timeout" : "20"
110
+ },
111
+ "SecurityGroups": [
112
+ {"Ref": "SecurityGroupLoadBalancer"}
113
+ ]
114
+ }
115
+ },
116
+
117
+ "DNSRecord": {
118
+ "Type" : "AWS::Route53::RecordSet",
119
+ "Properties" : {
120
+ "HostedZoneName" : {"Ref": "Route53ZoneName"},
121
+ "Type" : "CNAME",
122
+ "Name" : { "Ref": "AppDomainName"},
123
+ "ResourceRecords" : [ {"Fn::GetAtt":["LoadBalancer","DNSName"]}],
124
+ "TTL" : "30"
125
+ }
126
+ },
127
+
128
+ "ELBAttachment" : {
129
+ "Type" : "AWS::OpsWorks::ElasticLoadBalancerAttachment",
130
+ "Properties" : {
131
+ "ElasticLoadBalancerName" : { "Ref" : "LoadBalancer" },
132
+ "LayerId" : { "Ref" : "MeteorLayer" }
133
+ }
134
+ },
135
+
136
+ "MeteorStack": {
137
+ "Type": "AWS::OpsWorks::Stack",
138
+ "Properties": {
139
+ "Name": {
140
+ "Ref": "AWS::StackName"
141
+ },
142
+ "CustomJson": {
143
+ "opsworks_nodejs":{
144
+ "version":"0.10.38"
145
+ },
146
+ "deploy": {
147
+ "primary-app": {
148
+ "nodejs": {
149
+ "port": 80
150
+ },
151
+ "environment_variables": {
152
+ "METEOR_SETTINGS": "{}"
153
+ }
154
+ },
155
+ "secondary-app": {
156
+ "nodejs": {
157
+ "port": 8081
158
+ },
159
+ "environment_variables": {
160
+ "METEOR_SETTINGS": "{}"
161
+ }
162
+ }
163
+ }
164
+ },
165
+ "ServiceRoleArn": {
166
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":role/aws-opsworks-service-role"]]
167
+ },
168
+ "DefaultInstanceProfileArn": {
169
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":instance-profile/aws-opsworks-ec2-role"]]
170
+ },
171
+ "ConfigurationManager": {
172
+ "Name": "Chef",
173
+ "Version": "11.10"
174
+ },
175
+ "ChefConfiguration": {
176
+ "BerkshelfVersion": "3.1.3",
177
+ "ManageBerkshelf": true
178
+ },
179
+ "DefaultOs": "Amazon Linux 2015.03",
180
+ "DefaultRootDeviceType": "ebs",
181
+ "DefaultSshKeyName": { "Ref": "SshKeyName" },
182
+ "UseCustomCookbooks": false,
183
+ "UseOpsworksSecurityGroups": false,
184
+ "CustomCookbooksSource": {
185
+ "Type": "git",
186
+ "Url": {
187
+ "Ref": "CookbookRepo"
188
+ },
189
+ "Revision": { "Ref": "CookbookRepoRevision" }
190
+ }
191
+ }
192
+ },
193
+
194
+ "MeteorLayer": {
195
+ "Type": "AWS::OpsWorks::Layer",
196
+ "Properties": {
197
+ "StackId": {
198
+ "Ref": "MeteorStack"
199
+ },
200
+ "Name": "Meteor",
201
+ "Type": "nodejs-app",
202
+ "Shortname": "meteor",
203
+ "EnableAutoHealing": false,
204
+ "AutoAssignElasticIps": false,
205
+ "AutoAssignPublicIps": true,
206
+ "CustomSecurityGroupIds": [
207
+ {"Ref": "SecurityGroupMeteorLayer"}
208
+ ]
209
+ }
210
+ },
211
+
212
+ "PrimaryApp": {
213
+ "Type":"AWS::OpsWorks::App",
214
+ "Properties": {
215
+ "Type": "nodejs",
216
+ "Name": "Fetching Application",
217
+ "Shortname": "fetching-app",
218
+ "StackId": {
219
+ "Ref": "MeteorStack"
220
+ },
221
+ "AppSource": {
222
+ "Username": "AKDIKDSKSKEWS",
223
+ "Password": "x6gYSTr+qDSKDFJSLdksldjfLAKDjdRE8mKi1bAZXm",
224
+ "Type": "s3",
225
+ "Url":"https://s3-us-west-2.amazonaws.com/primary-builds/primary-app.tar.gz"
226
+ }
227
+ }
228
+ },
229
+
230
+ "SecondaryApp": {
231
+ "Type":"AWS::OpsWorks::App",
232
+ "Properties": {
233
+ "Type": "nodejs",
234
+ "Name": "Fetching Exporter",
235
+ "Shortname": "fetching-exporter",
236
+ "StackId": {
237
+ "Ref": "MeteorStack"
238
+ },
239
+ "AppSource": {
240
+ "Username": "AKDIKDSKSKEWS",
241
+ "Password": "x6gYSTr+qDSKDFJSLdksldjfLAKDjdRE8mKi1bAZXm",
242
+ "Type": "s3",
243
+ "Url":"https://s3-us-west-2.amazonaws.com/secondary-builds/secondary-app.tar.gz"
244
+ }
245
+ }
246
+ }
247
+
248
+ }
249
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "Route53ZoneName": "example.io.",
3
+ "AppDomainName": "app.example.io",
4
+ "SSLCertificateName": "app.example.io",
5
+ "SshKeyName": "production",
6
+ "InstanceCount":"1",
7
+ "InstanceType": "t2.small",
8
+ "SecurityGroupLoadBalancer": "sg-8ad62234ef",
9
+ "SecurityGroupMeteorLayer": "sg-2265dsd7"
10
+ }
@@ -0,0 +1,132 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Parameters": {
4
+ "CookbookRepo": {
5
+ "Description": "GitURL",
6
+ "Type": "String",
7
+ "Default": "https://github.com/flippyhead/chef-mongodb"
8
+ },
9
+
10
+ "MongoVersion": {
11
+ "Description": "The version of MongoDB to install.",
12
+ "Type": "String",
13
+ "Default": "2.6.1"
14
+ },
15
+
16
+ "RecipeList": {
17
+ "Description": "The list of cookbooks to include when setting up the cluster.",
18
+ "Type": "CommaDelimitedList",
19
+ "Default": "mongodb::10gen_repo, mongodb::default"
20
+ },
21
+
22
+ "SshKeyName": {
23
+ "Description": "SSH key name for EC2 instances.",
24
+ "Type": "String"
25
+ },
26
+
27
+ "InstanceCount": {
28
+ "Description": "The number of instances to launch.",
29
+ "Type": "Number",
30
+ "Default": 1
31
+ },
32
+
33
+ "InstanceType": {
34
+ "Description": "The type of instance to launch.",
35
+ "Type": "String",
36
+ "Default": "t2.small"
37
+ },
38
+
39
+ "SecurityGroupMongoLayer": {
40
+ "Description": "The mongo layer security group.",
41
+ "Type": "String"
42
+ }
43
+
44
+ },
45
+
46
+ "Outputs": {
47
+ "StackId": {
48
+ "Description": "opsworks stack id ",
49
+ "Value": { "Ref": "MongoStack"}
50
+ },
51
+
52
+ "LayerId": {
53
+ "Description": "opsworks mongo layer id ",
54
+ "Value": { "Ref": "MongoLayer"}
55
+ }
56
+
57
+ },
58
+
59
+ "Resources": {
60
+
61
+ "MongoStack": {
62
+ "Type": "AWS::OpsWorks::Stack",
63
+ "Properties": {
64
+ "Name": {
65
+ "Ref": "AWS::StackName"
66
+ },
67
+ "CustomJson": {
68
+ "mongodb": {
69
+ "config":{
70
+ "dbpath": "/mnt/mongodb-data"
71
+ }
72
+ }
73
+ },
74
+ "ServiceRoleArn": {
75
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":role/aws-opsworks-service-role"]]
76
+ },
77
+ "DefaultInstanceProfileArn": {
78
+ "Fn::Join": ["", ["arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":instance-profile/aws-opsworks-ec2-role"]]
79
+ },
80
+ "ConfigurationManager": {
81
+ "Name": "Chef",
82
+ "Version": "11.10"
83
+ },
84
+ "ChefConfiguration": {
85
+ "BerkshelfVersion": "3.1.3",
86
+ "ManageBerkshelf": true
87
+ },
88
+ "DefaultOs": "Ubuntu 14.04 LTS",
89
+ "DefaultRootDeviceType": "ebs",
90
+ "DefaultSshKeyName": { "Ref": "SshKeyName" },
91
+ "UseCustomCookbooks": true,
92
+ "UseOpsworksSecurityGroups": false,
93
+ "CustomCookbooksSource": {
94
+ "Type": "git",
95
+ "Url": {
96
+ "Ref": "CookbookRepo"
97
+ }
98
+ }
99
+ }
100
+ },
101
+
102
+ "MongoLayer": {
103
+ "Type": "AWS::OpsWorks::Layer",
104
+ "Properties": {
105
+ "StackId": {
106
+ "Ref": "MongoStack"
107
+ },
108
+ "Name": "Mongo",
109
+ "Type": "custom",
110
+ "Shortname": "mongo",
111
+ "CustomRecipes": {
112
+ "Setup": { "Ref": "RecipeList" }
113
+ },
114
+ "EnableAutoHealing": false,
115
+ "AutoAssignElasticIps": false,
116
+ "AutoAssignPublicIps": true,
117
+ "VolumeConfigurations": [
118
+ {
119
+ "MountPoint": "/mnt/mongodb-data",
120
+ "NumberOfDisks": 1,
121
+ "Size": 200,
122
+ "VolumeType": "gp2"
123
+ }
124
+ ],
125
+ "CustomSecurityGroupIds": [
126
+ {"Ref": "SecurityGroupMongoLayer"}
127
+ ]
128
+ }
129
+ }
130
+
131
+ }
132
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "SshKeyName": "production",
3
+ "InstanceCount":"1",
4
+ "InstanceType": "t2.small",
5
+ "MongoVersion": "2.6.1",
6
+ "SecurityGroupMongoLayer": "sg-334rt5fc"
7
+ }
@@ -0,0 +1 @@
1
+ require "admiral-cloudformation/tasks"
@@ -0,0 +1,50 @@
1
+ require 'json'
2
+ require 'thor'
3
+ require 'admiral/base'
4
+ require_relative 'util'
5
+
6
+ module Admiral
7
+ module Tasks
8
+ class CloudFormation < Thor
9
+ extend Admiral::Base
10
+ include Util::CloudFormation
11
+
12
+ NAME = 'cf'
13
+ USAGE = 'cf <command> <options>'
14
+ DESCRIPTION = 'Commands for wielding AWS CloudFormation templates.'
15
+
16
+ namespace :cf
17
+
18
+ class_option :template,
19
+ desc: 'Path to CloudFormation JSON template.',
20
+ default: 'CloudFormation.template'
21
+
22
+ class_option :params,
23
+ desc: 'Path to override parameter definitions file. Defaults to <environment>.json'
24
+
25
+
26
+ desc 'create', 'Create new CloudFormation stack for environment.'
27
+
28
+ def create
29
+ template = File.read options[:template]
30
+ create_stack stack_name(options[:environment]), template, params(options[:environment])
31
+ end
32
+
33
+
34
+ desc 'update', 'Update the existing CloudFormation stack'
35
+
36
+ def update
37
+ template = File.read options[:template]
38
+ update_stack stack_name(options[:environment]), template, params(options[:environment])
39
+ end
40
+
41
+
42
+ desc 'destroy', 'Destroy the existing CloudFormation stack.'
43
+
44
+ def destroy
45
+ super stack_name options[:environment]
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,100 @@
1
+ require 'aws-sdk-v1'
2
+
3
+ module Admiral
4
+ module Util
5
+ module CloudFormation
6
+
7
+ SUCCESS_STATS = [:create_complete, :update_complete, :update_rollback_complete]
8
+ FAILED_STATS = [:create_failed, :update_failed, :rollback_complete]
9
+ DEFAULT_RECIPES = [].join(",")
10
+
11
+ def client
12
+ AWS::CloudFormation.new
13
+ end
14
+
15
+ def create_stack(stack_name, template, params)
16
+ stack = client.stacks[stack_name]
17
+
18
+ if stack.exists?
19
+ raise '[admiral] Stack already exists. Use update command instead.'
20
+ end
21
+
22
+ puts "[admiral] Creating CloudFormation stack #{stack_name}."
23
+ begin
24
+ stack = client.stacks.create(stack_name, template, :parameters => params)
25
+ wait_for_stack_op_to_finish stack
26
+ rescue => e
27
+ puts "[admiral] Error creating stack #{stack_name}: #{e}"
28
+ end
29
+ end
30
+
31
+ def update_stack(stack_name, template, params)
32
+ stack = client.stacks[stack_name]
33
+
34
+ unless stack.exists?
35
+ raise "[admiral] CloudFormation stack #{stack_name} doesn't exist. Use create instead."
36
+ end
37
+
38
+ begin
39
+ puts "[admiral] Updating CloudFormation stack #{stack_name}"
40
+ stack.update(:template => template, :parameters => params)
41
+ wait_for_stack_op_to_finish stack
42
+ rescue => e
43
+ puts "[admiral] Error updating stack #{stack_name}: #{e}"
44
+ # raise unless e.message =~ /No updates are to be performed/
45
+ # puts "Your CloudFormation stack is already up to date"
46
+ end
47
+ end
48
+
49
+ def destroy(stack_name)
50
+ stack = client.stacks[stack_name]
51
+
52
+ if stack.exists?
53
+ puts "Deleting stack #{stack_name}"
54
+ stack.delete
55
+ else
56
+ puts "Environment does not exist"
57
+ end
58
+ end
59
+
60
+ def stack_name(env)
61
+ "#{env}-#{name}"
62
+ end
63
+
64
+ def name
65
+ ENV["ADMIRAL_NAME"] || "test"
66
+ end
67
+
68
+ def params(env, options = {})
69
+ JSON.parse File.read(options[:params] || "#{env}.json")
70
+ end
71
+
72
+ private
73
+
74
+ def wait_for_stack_op_to_finish(stack)
75
+ stats = stack.status.downcase.to_sym
76
+ puts "[admiral] Stack #{stack.name} current status: #{stats}"
77
+
78
+ while !SUCCESS_STATS.include?(stats)
79
+ sleep 15
80
+ stats = stack.status.downcase.to_sym
81
+ raise "[admiral] Resource stack update failed." if FAILED_STATS.include?(stats)
82
+ puts "[admiral] Stack #{stack.name} current status: #{stats}"
83
+ end
84
+ end
85
+
86
+ def cf_query_output(stack, key)
87
+ output = stack.outputs.find do |o|
88
+ /#{key}/i =~ o.key
89
+ end
90
+ output && output.value
91
+ end
92
+
93
+ def all_availability_zones
94
+ ec2 = AWS::EC2.new
95
+ ec2.availability_zones.map(&:name)
96
+ end
97
+
98
+ end
99
+ end
100
+ end
data/spec/test.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "Key": "Value"
3
+ }
@@ -0,0 +1 @@
1
+ {}
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: admiral-cloudformation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Peter T. Brown
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-05-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: aws-sdk
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - <
52
+ - !ruby/object:Gem::Version
53
+ version: '2'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - <
60
+ - !ruby/object:Gem::Version
61
+ version: '2'
62
+ - !ruby/object:Gem::Dependency
63
+ name: thor
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.19'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0.19'
78
+ - !ruby/object:Gem::Dependency
79
+ name: admiral
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.0.1
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 0.0.1
94
+ description: An Admiral module that implements tasks for wielding AWS CloudFormation
95
+ templates. Use it to manage CloudFormation templates and their parameters.
96
+ email:
97
+ - p@ptb.io
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - .gitignore
103
+ - .ruby-version
104
+ - Gemfile
105
+ - LICENSE.txt
106
+ - README.md
107
+ - Rakefile
108
+ - admiral.gemspec
109
+ - examples/elasticsearch/CloudFormation.template
110
+ - examples/elasticsearch/production.json
111
+ - examples/meteor/CloudFormation.template
112
+ - examples/meteor/production.json
113
+ - examples/mongo/CloudFormation.template
114
+ - examples/mongo/production.json
115
+ - lib/admiral-cloudformation.rb
116
+ - lib/admiral-cloudformation/tasks.rb
117
+ - lib/admiral-cloudformation/util.rb
118
+ - spec/test.json
119
+ - spec/test.template
120
+ homepage: ''
121
+ licenses:
122
+ - MIT
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 1.8.23.2
142
+ signing_key:
143
+ specification_version: 3
144
+ summary: A command line tool for wielding cloudformation templates.
145
+ test_files:
146
+ - spec/test.json
147
+ - spec/test.template