cloudformer2 1.0.18

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 507b885f8e308609bc0790cb86f143032b5b2c8c
4
+ data.tar.gz: 92308039a57f4a25fb641cc39322ad8654f2a833
5
+ SHA512:
6
+ metadata.gz: d7b4bce27d8b8b8a506c9147ecf683ce7b11579bc9f5cc6560e90223146c1369c4d5d22569bb012eeee1379f987887c87c7a2ba0f58b30df7e244a7158629ea8
7
+ data.tar.gz: 82c9575f3f6784b742e4c8fa6a7bd81697abb86f2888d4a93bb496063d73a6bb0cf8e44c6a0b76aa72fc3fdabd8199a9df64f2ccc6cf32de4b382812be143f1f
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
+ .DS_Store
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/).
6
+
7
+ ## 1.0.19 (Next Release)
8
+
9
+ ## [1.0.18]
10
+ * Initial release of cloudformer fork that uses the aws-sdk-v1 gem and aws-sdk ~> 2.10.9
11
+
data/Dockerfile ADDED
@@ -0,0 +1,5 @@
1
+ FROM ruby:2.1.2
2
+
3
+ ADD . /usr/local/app
4
+ WORKDIR /usr/local/app
5
+ RUN bundle install
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Arvind Kunday
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,222 @@
1
+ # CloudFormer 2
2
+
3
+ Cloudformer attempts to simplify AWS Cloudformation stack creation process in ruby projects by providing reusable rake tasks to perform common operations such as apply(create/update), delete, recreate on stack along with validations on templates. Task executions which enforce a stack change will wait until ROLLBACK/COMPLETE or DELETE is signalled on the stack (useful in continuous deployment environments to wait until deployment is successful). Refer [examples section](#example) for more information.
4
+
5
+ ### Note:
6
+ Forked from abandoned https://github.com/kunday/cloudformer
7
+
8
+ The list of rake tasks provided are:
9
+
10
+ ```
11
+
12
+ rake apply # Apply Stack with Cloudformation script and parameters(And wait till complete - supports updates)
13
+ rake delete # Delete stack from CloudFormation(And wait till stack is complete)
14
+ rake events # Get the recent events from the stack
15
+ rake outputs # Get the outputs of stack
16
+ rake recreate # Recreate stack(runs delete & apply)
17
+ rake status # Get the deployed app status
18
+
19
+ ```
20
+
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'cloudformer2'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install cloudformer2
35
+
36
+ ## AWS Environment configuration
37
+
38
+ Cloudformer depends on the aws-sdk gem to query AWS API. You will need to export AWS configuration to environment variables to your .bashrc/.bash_profile or your build server:
39
+
40
+ export AWS_ACCESS_KEY=your access key
41
+ export AWS_REGION=ap-southeast-2
42
+ export AWS_SECRET_ACCESS_KEY=your secret access key
43
+
44
+
45
+ ## Configuration
46
+
47
+ You can add cloudformer tasks to your project by adding the following to your rake file:
48
+
49
+ require 'cloudformer2'
50
+ Cloudformer::Tasks.new("earmark") do |t|
51
+ t.template = "cloudformation/cloudformation.json"
52
+ t.parameters = parameters
53
+ end
54
+
55
+ where `cloudformation/cloudformation.json` is the stack json file and parameters is a hash of parameters used in the template.
56
+ For a template which takes the following parameters:
57
+
58
+ "Parameters": {
59
+ "PackageUrl": {
60
+ "Type": "String"
61
+ },
62
+ "PackageVersion": {
63
+ "Type": "String"
64
+ }
65
+ }
66
+
67
+ the parameter hash(Ruby Object) would look like:
68
+
69
+ {
70
+ "PackageUrl" => "http://localhost/app.rpm",
71
+ "PackageVersion" => "123"
72
+ }
73
+
74
+ If you have a template with no parameters, pass an empty hash `{}` instead.
75
+
76
+ ## Example
77
+
78
+ Here is a simple Cloudformation Stack(Code available in the samples directory) with a Single EC2 Server:
79
+
80
+ {
81
+ "AWSTemplateFormatVersion": "2010-09-09",
82
+ "Description": "Cloudformer - Demo App",
83
+ "Parameters": {
84
+ "AmiId": {
85
+ "Type": "String"
86
+ }
87
+ },
88
+ "Resources": {
89
+ "ApplicationServer": {
90
+ "Type": "AWS::EC2::Instance",
91
+ "Properties": {
92
+ "ImageId": {
93
+ "Ref": "AmiId"
94
+ },
95
+ "InstanceType": "t1.micro",
96
+ "Monitoring": "false"
97
+ }
98
+ }
99
+ },
100
+ "Outputs": {
101
+ "Server": {
102
+ "Value": {
103
+ "Fn::GetAtt": [
104
+ "ApplicationServer",
105
+ "PrivateIp"
106
+ ]
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ Then, in your Rakefile add,
113
+
114
+ require 'cloudformer/tasks'
115
+
116
+ Cloudformer::Tasks.new("app") do |t|
117
+ t.template = "basic_template.json"
118
+ t.tags = [{'Key' => 'Name', 'Value' => 'BASIC-TMPLT'},
119
+ {'Key' => 'Owner', 'Value' => 'APPOWNER'}]
120
+
121
+ #AMI Works in Sydney region only, ensure you supply the right AMI.
122
+ t.parameters = {"AmiId" => "ami-8da439b7"}
123
+ end
124
+
125
+ You should then see following commands:
126
+
127
+ rake apply # Apply Stack with Cloudformation script and parameters
128
+ rake delete # Delete stack from CloudFormation
129
+ rake events # Get the recent events from the stack
130
+ rake outputs # Get the outputs of stack
131
+ rake recreate # Recreate stack
132
+ rake status # Get the deployed app status
133
+
134
+ Running `rake status` gives us:
135
+
136
+ ===============================================
137
+ app - Not Deployed
138
+ ================================================
139
+
140
+ Running `rake apply` will create an environment or update existing depending on the nature of action requested in parameters:
141
+
142
+ Initializing stack creation...
143
+ ==================================================================================================
144
+ 2013-10-24 07:55:24 UTC - AWS::CloudFormation::Stack - CREATE_IN_PROGRESS - User Initiated
145
+ 2013-10-24 07:55:36 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS -
146
+ 2013-10-24 07:55:37 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS - Resource creation Initiated
147
+ 2013-10-24 07:56:25 UTC - AWS::EC2::Instance - CREATE_COMPLETE -
148
+ 2013-10-24 07:56:26 UTC - AWS::CloudFormation::Stack - CREATE_COMPLETE -
149
+ ==================================================================================================
150
+
151
+ Running `rake apply` again gives us:
152
+
153
+ No updates are to be performed.
154
+
155
+ To remove the stack `rake delete` gives us:
156
+
157
+ ==============================================================================================
158
+ Attempting to delete stack - app
159
+ ==============================================================================================
160
+ 2013-10-24 07:55:24 UTC - AWS::CloudFormation::Stack - CREATE_IN_PROGRESS - User Initiated
161
+ 2013-10-24 07:55:36 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS -
162
+ 2013-10-24 07:55:37 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS - Resource creation Initiated
163
+ 2013-10-24 07:56:25 UTC - AWS::EC2::Instance - CREATE_COMPLETE -
164
+ 2013-10-24 07:56:26 UTC - AWS::CloudFormation::Stack - CREATE_COMPLETE -
165
+ 2013-10-24 07:58:54 UTC - AWS::CloudFormation::Stack - DELETE_IN_PROGRESS - User Initiated
166
+ 2013-10-24 07:58:56 UTC - AWS::EC2::Instance - DELETE_IN_PROGRESS -
167
+
168
+ Attempts to delete a non-existing stack will result in:
169
+
170
+ ==============================================
171
+ Attempting to delete stack - app
172
+ ==============================================
173
+ Stack not up.
174
+ ==============================================
175
+
176
+ To recreate the stack use `rake recreate`:
177
+
178
+ =================================================================================================
179
+ Attempting to delete stack - app
180
+ =================================================================================================
181
+ 2013-10-24 08:04:11 UTC - AWS::CloudFormation::Stack - CREATE_IN_PROGRESS - User Initiated
182
+ 2013-10-24 08:04:22 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS -
183
+ 2013-10-24 08:04:23 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS - Resource creation Initiated
184
+ 2013-10-24 08:05:12 UTC - AWS::EC2::Instance - CREATE_COMPLETE -
185
+ 2013-10-24 08:05:13 UTC - AWS::CloudFormation::Stack - CREATE_COMPLETE -
186
+ 2013-10-24 08:05:52 UTC - AWS::CloudFormation::Stack - DELETE_IN_PROGRESS - User Initiated
187
+ 2013-10-24 08:06:02 UTC - AWS::EC2::Instance - DELETE_IN_PROGRESS -
188
+ Stack deleted successfully.
189
+ Initializing stack creation...
190
+ =================================================================================================
191
+ 2013-10-24 08:06:31 UTC - AWS::CloudFormation::Stack - CREATE_IN_PROGRESS - User Initiated
192
+ 2013-10-24 08:06:52 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS -
193
+ 2013-10-24 08:06:54 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS - Resource creation Initiated
194
+ 2013-10-24 08:07:41 UTC - AWS::EC2::Instance - CREATE_COMPLETE -
195
+ =================================================================================================
196
+ =================================================================================================
197
+ Server - - 172.31.3.52
198
+ =================================================================================================
199
+
200
+ To see the stack outputs `rake outputs`:
201
+
202
+ ==============================
203
+ Server - - 172.31.3.52
204
+ ==============================
205
+
206
+ To see recent events on the stack `rake events`:
207
+
208
+ ==================================================================================================
209
+ 2013-10-24 08:06:31 UTC - AWS::CloudFormation::Stack - CREATE_IN_PROGRESS - User Initiated
210
+ 2013-10-24 08:06:52 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS -
211
+ 2013-10-24 08:06:54 UTC - AWS::EC2::Instance - CREATE_IN_PROGRESS - Resource creation Initiated
212
+ 2013-10-24 08:07:41 UTC - AWS::EC2::Instance - CREATE_COMPLETE -
213
+ 2013-10-24 08:07:43 UTC - AWS::CloudFormation::Stack - CREATE_COMPLETE -
214
+ ==================================================================================================
215
+
216
+ ## Contributing
217
+
218
+ 1. Fork it
219
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
220
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
221
+ 4. Push to the branch (`git push origin my-new-feature`)
222
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec'
3
+
4
+ begin
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task :default => :spec
10
+ rescue LoadError
11
+ # no rspec available
12
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cloudformer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cloudformer2"
8
+ spec.version = Cloudformer::VERSION
9
+ spec.authors = ["Sentia MPC", "Dennis Vink"]
10
+ spec.email = ["dennis.vink@sentia.com"]
11
+ spec.description = %q{Cloudformation tasks for apply(create/update), delete, recreate on stack along with validations on templates}
12
+ spec.summary = %q{Cloudformer attempts to simplify AWS Cloudformation stack creation process in ruby projects by providing reusable rake tasks to perform common operations such as apply(create/update), delete, recreate on stack along with validations on templates.}
13
+ spec.homepage = "https://github.com/sentialabs/cloudformer2"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_dependency "rake"
24
+ spec.add_dependency "aws-sdk-v1", '~> 1.67.0'
25
+ spec.add_dependency "aws-sdk", '~> 2.10.9'
26
+ spec.add_dependency "httparty"
27
+ end
@@ -0,0 +1,2 @@
1
+ app:
2
+ build: .
@@ -0,0 +1,6 @@
1
+ require "cloudformer/version"
2
+ require "cloudformer/stack"
3
+ require "cloudformer/tasks"
4
+
5
+ module Cloudformer
6
+ end
@@ -0,0 +1,189 @@
1
+ require "aws-sdk-v1"
2
+ require "aws-sdk"
3
+ require "httparty"
4
+
5
+ # Class to simplify AWS CloudFormation stack creation
6
+ class Stack
7
+ attr_accessor :stack, :name, :deployed
8
+
9
+ SUCESS_STATES = %w[CREATE_COMPLETE UPDATE_COMPLETE].freeze
10
+ FAILURE_STATES = %w[
11
+ CREATE_FAILED DELETE_FAILED UPDATE_ROLLBACK_FAILED
12
+ ROLLBACK_FAILED ROLLBACK_COMPLETE ROLLBACK_FAILED
13
+ UPDATE_ROLLBACK_COMPLETE UPDATE_ROLLBACK_FAILED
14
+ ].freeze
15
+ END_STATES = SUCESS_STATES + FAILURE_STATES
16
+
17
+ # WAITING_STATES = ["CREATE_IN_PROGRESS","DELETE_IN_PROGRESS","ROLLBACK_IN_PROGRESS","UPDATE_COMPLETE_CLEANUP_IN_PROGRESS","UPDATE_IN_PROGRESS","UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS","UPDATE_ROLLBACK_IN_PROGRESS"]
18
+ def initialize(stack_name)
19
+ @name = stack_name
20
+ @cf = AWS::CloudFormation.new
21
+ @stack = @cf.stacks[name]
22
+ @ec2 = AWS::EC2.new
23
+ end
24
+
25
+ def deployed
26
+ stack.exists?
27
+ end
28
+
29
+ def apply(template_file, parameters, disable_rollback = false,
30
+ capabilities = [], notify = [], tags = [])
31
+ if template_file =~ %r{^https:\/\/s3\S+\.amazonaws\.com\/(.*)}
32
+ template = template_file
33
+ elsif template_file =~ %r{^http.*(.json)$/}
34
+ begin
35
+ response = HTTParty.get(template_file)
36
+ template = response.body
37
+ rescue => e
38
+ puts "Unable to retieve json file for template from #{template_file} - #{e.class}, #{e}"
39
+ return :Failed
40
+ end
41
+ else
42
+ template = File.read(template_file)
43
+ end
44
+ validation = validate(template)
45
+ unless validation["valid"]
46
+ puts "Unable to update - #{validation['response'][:code]} - #{validation['response'][:message]}"
47
+ return :Failed
48
+ end
49
+ pending_operations = false
50
+ begin
51
+ if deployed
52
+ pending_operations = update(template, parameters, capabilities)
53
+ else
54
+ pending_operations = create(template, parameters, disable_rollback, capabilities, notify, tags)
55
+ end
56
+ rescue ::AWS::CloudFormation::Errors::ValidationError => e
57
+ puts e.message
58
+ return e.message == "No updates are to be performed." ? :NoUpdates : :Failed
59
+ end
60
+ wait_until_end if pending_operations
61
+ deploy_succeeded? ? :Succeeded : :Failed
62
+ end
63
+
64
+ def deploy_succeeded?
65
+ return true unless FAILURE_STATES.include?(stack.status)
66
+ puts "Unable to deploy template. Check log for more information."
67
+ false
68
+ end
69
+
70
+ def stop_instances
71
+ update_instances("stop")
72
+ end
73
+
74
+ def start_instances
75
+ update_instances("start")
76
+ end
77
+
78
+ def delete
79
+ with_highlight do
80
+ puts "Attempting to delete stack - #{name}"
81
+ stack.delete
82
+ wait_until_end
83
+ return deploy_succeeded?
84
+ end
85
+ end
86
+
87
+ def status
88
+ with_highlight do
89
+ if deployed
90
+ puts "#{stack.name} - #{stack.status} - #{stack.status_reason}"
91
+ else
92
+ puts "#{name} - Not Deployed"
93
+ end
94
+ end
95
+ end
96
+
97
+ def events(options = {})
98
+ with_highlight do
99
+ if !deployed
100
+ puts "Stack not up."
101
+ return
102
+ end
103
+ stack.events.sort_by { |a| a.timestamp }.each do |event|
104
+ puts "#{event.timestamp} - #{event.physical_resource_id.to_s} - #{event.logical_resource_id} - #{event.resource_type} - #{event.resource_status} - #{event.resource_status_reason.to_s}"
105
+ end
106
+ end
107
+ end
108
+
109
+ def outputs
110
+ with_highlight do
111
+ if !deployed
112
+ puts "Stack not up."
113
+ return 1
114
+ end
115
+ stack.outputs.each do |output|
116
+ puts "#{output.key} - #{output.description} - #{output.value}"
117
+ end
118
+ end
119
+ return 0
120
+ end
121
+
122
+ def validate(template)
123
+ response = @cf.validate_template(template)
124
+ return {
125
+ "valid" => response[:code].nil?,
126
+ "response" => response
127
+ }
128
+ end
129
+
130
+ private
131
+
132
+ def wait_until_end
133
+ printed = []
134
+ current_time = Time.now
135
+ with_highlight do
136
+ if !deployed
137
+ puts "Stack not up."
138
+ return
139
+ end
140
+ loop do
141
+ printable_events = stack.events.reject { |a| (a.timestamp < current_time) }.sort_by { |a| a.timestamp }.reject { |a| a if printed.include?(a.event_id) }
142
+ printable_events.each { |event| puts "#{event.timestamp} - #{event.physical_resource_id.to_s} - #{event.resource_type} - #{event.resource_status} - #{event.resource_status_reason.to_s}" }
143
+ printed.concat(printable_events.map(&:event_id))
144
+ break if END_STATES.include?(stack.status)
145
+ sleep(30)
146
+ end
147
+ end
148
+ end
149
+
150
+ def with_highlight(&block)
151
+ cols = `tput cols`.chomp!.to_i
152
+ puts "=" * cols
153
+ yield
154
+ puts "=" * cols
155
+ end
156
+
157
+ def update(template, parameters, capabilities)
158
+ stack.update({
159
+ :template => template,
160
+ :parameters => parameters,
161
+ :capabilities => capabilities
162
+ })
163
+ return true
164
+ end
165
+
166
+ def create(template, parameters, disable_rollback, capabilities, notify, tags)
167
+ puts "Initializing stack creation..."
168
+ @cf.stacks.create(name, template, :parameters => parameters, :disable_rollback => disable_rollback, :capabilities => capabilities, :notify => notify, :tags => tags)
169
+ sleep 10
170
+ return true
171
+ end
172
+
173
+ def update_instances(action)
174
+ with_highlight do
175
+ puts "Attempting to #{action} all ec2 instances in the stack #{stack.name}"
176
+ return "Stack not up" if !deployed
177
+ stack.resources.each do |resource|
178
+ begin
179
+ next if resource.resource_type != "AWS::EC2::Instance"
180
+ physical_resource_id = resource.physical_resource_id
181
+ puts "Attempting to #{action} Instance with physical_resource_id: #{physical_resource_id}"
182
+ @ec2.instances[physical_resource_id].send(action)
183
+ rescue
184
+ puts "Some resources are not up."
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,114 @@
1
+ require "cloudformer/version"
2
+ require "cloudformer/stack"
3
+ require "rake/tasklib"
4
+
5
+ module Cloudformer
6
+ # CloudFormer Rake Tasks
7
+ class Tasks < Rake::TaskLib
8
+ def initialize(stack_name)
9
+ @stack_name = stack_name
10
+ @stack = Stack.new(stack_name)
11
+ if block_given?
12
+ yield self
13
+ define_tasks
14
+ end
15
+ end
16
+
17
+ attr_accessor :template, :parameters, :disable_rollback, :retry_delete, :capabilities, :notify, :tags
18
+
19
+ private
20
+
21
+ def define_tasks
22
+ define_create_task
23
+ define_validate_task
24
+ define_delete_task
25
+ define_delete_with_stop_task
26
+ define_events_task
27
+ define_status_task
28
+ define_outputs_task
29
+ define_recreate_task
30
+ define_stop_task
31
+ define_start_task
32
+ end
33
+
34
+ def define_create_task
35
+ desc "Apply Stack with Cloudformation script and parameters."
36
+ task :apply do
37
+ retry_delete && @stack.delete
38
+ result = @stack.apply(template, parameters, disable_rollback, capabilities, notify, tags)
39
+ result == :Failed && exit(1)
40
+ result == :NoUpdates && exit(0)
41
+ end
42
+ end
43
+
44
+ def define_delete_task
45
+ desc "Delete stack from CloudFormation"
46
+ task :delete do
47
+ begin
48
+ exit 1 unless @stack.delete
49
+ rescue
50
+ puts "Stack deleted successfully."
51
+ end
52
+ end
53
+ end
54
+
55
+ def define_delete_with_stop_task
56
+ desc "Delete stack after stopping all instances"
57
+ task :force_delete do
58
+ begin
59
+ @stack.stop_instances
60
+ exit 1 unless @stack.delete
61
+ rescue => e
62
+ puts "Stack delete message - #{e.message}"
63
+ end
64
+ end
65
+ end
66
+
67
+ def define_status_task
68
+ desc "Get the deployed app status."
69
+ task :status do
70
+ @stack.status
71
+ end
72
+ end
73
+
74
+ def define_events_task
75
+ desc "Get the recent events from the stack."
76
+ task :events do
77
+ @stack.events
78
+ end
79
+ end
80
+
81
+ def define_outputs_task
82
+ desc "Get the outputs of stack."
83
+ task :outputs do
84
+ @stack.outputs
85
+ end
86
+ end
87
+
88
+ def define_recreate_task
89
+ desc "Recreate stack."
90
+ task :recreate => %i[delete apply outputs]
91
+ end
92
+
93
+ def define_stop_task
94
+ desc "Stop EC2 instances in stack."
95
+ task :stop do
96
+ @stack.stop_instances
97
+ end
98
+ end
99
+
100
+ def define_start_task
101
+ desc "Start EC2 instances in stack."
102
+ task :start do
103
+ @stack.start_instances
104
+ end
105
+ end
106
+
107
+ def define_validate_task
108
+ desc "Validate the Stack."
109
+ task :validate do
110
+ @stack.validate(template)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,3 @@
1
+ module Cloudformer
2
+ VERSION = "1.0.18".freeze
3
+ end
data/samples/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'cloudformer2'
2
+
3
+ Cloudformer::Tasks.new("dennis-test") do |t|
4
+ t.template = "basic_template.json"
5
+ #AMI Works in Sydney region only, ensure you supply the right AMI.
6
+ t.parameters = {"AmiId" => "ami-8da439b7"}
7
+ t.disable_rollback = true
8
+ t.capabilities=[]
9
+ end
@@ -0,0 +1,31 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Description": "Cloudformer - Demo App",
4
+ "Parameters": {
5
+ "AmiId": {
6
+ "Type": "String"
7
+ }
8
+ },
9
+ "Resources": {
10
+ "ApplicationServer": {
11
+ "Type": "AWS::EC2::Instance",
12
+ "Properties": {
13
+ "ImageId": {
14
+ "Ref": "AmiId"
15
+ },
16
+ "InstanceType": "t1.micro",
17
+ "Monitoring": "false"
18
+ }
19
+ }
20
+ },
21
+ "Outputs": {
22
+ "Server": {
23
+ "Value": {
24
+ "Fn::GetAtt": [
25
+ "ApplicationServer",
26
+ "PrivateIp"
27
+ ]
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,87 @@
1
+ require 'cloudformer/stack'
2
+
3
+ describe Stack do
4
+ before :each do
5
+ @cf = double(AWS::CloudFormation)
6
+ @cf_stack = double(AWS::CloudFormation::Stack)
7
+ @collection = double(AWS::CloudFormation::StackCollection)
8
+ AWS::CloudFormation.should_receive(:new).and_return(@cf)
9
+ @collection.should_receive(:[]).and_return(@cf_stack)
10
+ @cf.should_receive(:stacks).and_return(@collection)
11
+ end
12
+ describe "when deployed" do
13
+ before :each do
14
+ @stack = Stack.new("stack")
15
+ end
16
+
17
+ it "should report as the stack being deployed" do
18
+ @cf_stack.should_receive(:exists?).and_return(true)
19
+ @stack.deployed.should be
20
+ end
21
+
22
+ ## Broken spec from original repo
23
+ # describe "#delete" do
24
+ # it "should return a true if delete fails" do
25
+ # pending
26
+ # @cf_stack.should_receive(:exists?).and_return(false)
27
+ # @cf_stack.should_receive(:status)
28
+ # @stack.delete.should be
29
+ # end
30
+ # end
31
+ end
32
+
33
+ describe "when stack is not deployed" do
34
+ before :each do
35
+ @stack = Stack.new("stack")
36
+ end
37
+
38
+ it "should report as the stack not being deployed" do
39
+ @cf_stack.should_receive(:exists?).and_return(false)
40
+ @stack.deployed.should_not be
41
+ end
42
+ end
43
+
44
+ describe "when stack operation throws ValidationError" do
45
+ before :each do
46
+ @stack = Stack.new("stack")
47
+ @cf_stack.should_receive(:exists?).and_return(true)
48
+ File.should_receive(:read).and_return("template")
49
+ @cf.should_receive(:validate_template).and_return({"valid" => true})
50
+ @cf_stack.should_receive(:update).and_raise(AWS::CloudFormation::Errors::ValidationError)
51
+ end
52
+
53
+ it "apply should return Failed to signal the error" do
54
+ @stack.apply(nil, nil).should be(:Failed)
55
+ end
56
+ end
57
+
58
+ describe "when stack operation throws ValidationError because no updates are to be performed" do
59
+ before :each do
60
+ @stack = Stack.new("stack")
61
+ @cf_stack.should_receive(:exists?).and_return(true)
62
+ File.should_receive(:read).and_return("template")
63
+ @cf.should_receive(:validate_template).and_return({"valid" => true})
64
+ @cf_stack.should_receive(:update).and_raise(AWS::CloudFormation::Errors::ValidationError.new("No updates are to be performed."))
65
+ end
66
+
67
+ it "apply should return NoUpdate to signal the error" do
68
+ @stack.apply(nil, nil).should be(:NoUpdates)
69
+ end
70
+ end
71
+
72
+ describe "when stack update succeeds" do
73
+ before :each do
74
+ @stack = Stack.new("stack")
75
+ @cf_stack.should_receive(:exists?).at_least(:once).and_return(true)
76
+ File.should_receive(:read).and_return("template")
77
+ @cf.should_receive(:validate_template).and_return({"valid" => true})
78
+ @cf_stack.should_receive(:update).and_return(false)
79
+ @cf_stack.should_receive(:events).and_return([])
80
+ @cf_stack.should_receive(:status).at_least(:once).and_return("UPDATE_COMPLETE")
81
+ end
82
+
83
+ it "apply should return Succeeded" do
84
+ @stack.apply(nil, nil).should be(:Succeeded)
85
+ end
86
+ end
87
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudformer2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.18
5
+ platform: ruby
6
+ authors:
7
+ - Sentia MPC
8
+ - Dennis Vink
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-07-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.3'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: aws-sdk-v1
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 1.67.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.67.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: aws-sdk
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 2.10.9
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 2.10.9
84
+ - !ruby/object:Gem::Dependency
85
+ name: httparty
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: Cloudformation tasks for apply(create/update), delete, recreate on stack
99
+ along with validations on templates
100
+ email:
101
+ - dennis.vink@sentia.com
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - CHANGELOG.md
108
+ - Dockerfile
109
+ - Gemfile
110
+ - LICENSE.txt
111
+ - README.md
112
+ - Rakefile
113
+ - cloudformer2.gemspec
114
+ - docker-compose.yml
115
+ - lib/cloudformer/cloudformer.rb
116
+ - lib/cloudformer/stack.rb
117
+ - lib/cloudformer/tasks.rb
118
+ - lib/cloudformer/version.rb
119
+ - samples/Rakefile
120
+ - samples/basic_template.json
121
+ - spec/stack_spec.rb
122
+ homepage: https://github.com/sentialabs/cloudformer2
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.5.1
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Cloudformer attempts to simplify AWS Cloudformation stack creation process
146
+ in ruby projects by providing reusable rake tasks to perform common operations such
147
+ as apply(create/update), delete, recreate on stack along with validations on templates.
148
+ test_files:
149
+ - spec/stack_spec.rb