cloudformer2 1.0.18

Sign up to get free protection for your applications and to get access to all the features.
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