jackal-cfn 0.2.8 → 0.2.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +304 -8
- data/jackal-cfn.gemspec +1 -0
- data/lib/jackal-cfn/resource/ami_manager.rb +0 -2
- data/lib/jackal-cfn/resource/hash_extractor.rb +1 -1
- data/lib/jackal-cfn/resource/jackal_stack.rb +248 -0
- data/lib/jackal-cfn/resource.rb +2 -2
- data/lib/jackal-cfn/utils.rb +1 -1
- data/lib/jackal-cfn/version.rb +1 -1
- data/lib/jackal-cfn.rb +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9fddaa1ca5447da20d6c856d2ccdf3ba4d3c89d9
|
4
|
+
data.tar.gz: acddccbce932860d09c048ba04627df5744cd4b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d5f2187fab6e8d42da3ab3351b53720b1cd351a95df76ffe40390e50786a4f457fef306f6b00b93de1dabba807bcdb1f87e1c0c5b08b67d3f9dd8985d6c5b86
|
7
|
+
data.tar.gz: 9b5b9c770c12c9158bdc2ad3bf03041b7200b3aacdaf35f2bbec8c561673646d0b1a2ec63d1acea196e8b246b29468397497291f6b7fb006e6ac96359e2447f6
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,23 +1,319 @@
|
|
1
1
|
# Jackal CFN
|
2
2
|
|
3
|
-
|
3
|
+
Provides jackal integration for AWS CloudFormation custom
|
4
|
+
resources and stack event notifications.
|
4
5
|
|
5
|
-
##
|
6
|
+
## Requirements
|
6
7
|
|
7
|
-
|
8
|
+
This library currently uses the `patron` gem for sending
|
9
|
+
notifications to AWS S3. It requires the curl development
|
10
|
+
libraries to be available, so ensure it is installed.
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
There are two ways to use this library. The first is to process
|
15
|
+
events and resources into proper payloads and inject them into the
|
16
|
+
pipeline. The other is to re-process a formatted payload.
|
17
|
+
|
18
|
+
### Pipeline Injection
|
19
|
+
|
20
|
+
Configuration for pipeline injection of resource and event notifications
|
21
|
+
is very straightforward:
|
22
|
+
|
23
|
+
```json
|
24
|
+
{
|
25
|
+
"jackal": {
|
26
|
+
"cfn": {
|
27
|
+
"config": {
|
28
|
+
},
|
29
|
+
"sources": {
|
30
|
+
"input": {
|
31
|
+
"type": "sqs",
|
32
|
+
"args": {
|
33
|
+
SQS_CONFIG
|
34
|
+
}
|
35
|
+
},
|
36
|
+
"output": {
|
37
|
+
OUTPUT_SOURCE
|
38
|
+
}
|
39
|
+
},
|
40
|
+
"callbacks": [
|
41
|
+
"Jackal::Cfn::Resource",
|
42
|
+
"Jackal::Cfn::Event"
|
43
|
+
]
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
```
|
48
|
+
|
49
|
+
With this configuration in place resources and events will be received,
|
50
|
+
formatted, and delivered to the `OUTPUT_SOURCE`. It will be the job of
|
51
|
+
a later service to handle reply notifications (for resources) in this
|
52
|
+
style of usage.
|
53
|
+
|
54
|
+
### Message Reprocessing
|
55
|
+
|
56
|
+
When using the re-processing configuration, messages do not continue
|
57
|
+
down the pipeline. Instead, the original message is received, formatted,
|
58
|
+
and then re-delivered to the originating source (generally an SQS queue).
|
59
|
+
The message will be fetched again (this time properly formatted) and
|
60
|
+
any matching callbacks will be executed. A sample configuration may look
|
61
|
+
something like this:
|
62
|
+
|
63
|
+
```json
|
64
|
+
{
|
65
|
+
"jackal": {
|
66
|
+
"cfn": {
|
67
|
+
"config": {
|
68
|
+
"reprocess": true,
|
69
|
+
"ami": {
|
70
|
+
"credentials": {
|
71
|
+
CREDENTIALS
|
72
|
+
}
|
73
|
+
}
|
74
|
+
},
|
75
|
+
"sources": {
|
76
|
+
"input": {
|
77
|
+
"type": "sqs",
|
78
|
+
"args": {
|
79
|
+
SQS_CONFIG
|
80
|
+
}
|
81
|
+
},
|
82
|
+
"output": {
|
83
|
+
OUTPUT_SOURCE
|
84
|
+
}
|
85
|
+
},
|
86
|
+
"callbacks": [
|
87
|
+
"Jackal::Cfn::Resource",
|
88
|
+
"Jackal::Cfn::AmiRegister"
|
89
|
+
]
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
```
|
94
|
+
|
95
|
+
The important item to note is the `"reprocess": true` which enables the
|
96
|
+
automatic re-processing of messages.
|
97
|
+
|
98
|
+
## Custom Resources
|
99
|
+
|
100
|
+
This library provides support for creating new custom resources. Creation
|
101
|
+
is as simple as subclassing:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
module Jackal
|
105
|
+
module Cfn
|
106
|
+
class LocalPrinter < Jackal::Cfn::Resource
|
107
|
+
|
108
|
+
def execute(message)
|
109
|
+
failure_wrap(message) do |payload|
|
110
|
+
cfn_resource = rekey_hash(payload.get(:data, :cfn_resource))
|
111
|
+
cfn_response = build_response(cfn_resource)
|
112
|
+
info "CFN Resource: #{cfn_resource.inspect}"
|
113
|
+
info "CFN Response: #{cfn_response.inspect}"
|
114
|
+
respond_to_stack(cfn_response, cfn_resource[:response_url])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
This will match `Custom::LocalPrinter` resource requests that are received. It
|
124
|
+
will print information into the log about the request and then send a successful
|
125
|
+
response back to the stack.
|
126
|
+
|
127
|
+
### Builtin Custom Resources
|
128
|
+
|
129
|
+
This library provides a few custom resources builtin. These can be used directly or
|
130
|
+
as examples for building new custom resources.
|
131
|
+
|
132
|
+
#### `Jackal::Cfn::AmiRegister`
|
133
|
+
|
134
|
+
Generates and registers an AMI based on an EC2 resource. This allows for building a
|
135
|
+
single EC2 resource within a stack that is fully configured, creating and registering
|
136
|
+
an AMI based on that EC2 resource, and using the new AMI for instances created within
|
137
|
+
an ASG. It is an integrated way to speed up ASG instance launches, but keep all resources
|
138
|
+
for the stack fully managed.
|
139
|
+
|
140
|
+
Resource usage:
|
11
141
|
|
12
142
|
```json
|
143
|
+
{
|
144
|
+
"Type": "Custom::AmiRegister",
|
145
|
+
"Properties": {
|
146
|
+
"Parameters": {
|
147
|
+
"Name": String,
|
148
|
+
"InstanceId": String,
|
149
|
+
"Description": String,
|
150
|
+
"NoReboot": Boolean,
|
151
|
+
"BlockDeviceMappings": Array,
|
152
|
+
"HaltInstance": Boolean,
|
153
|
+
"Region": String
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
13
157
|
```
|
14
158
|
|
15
|
-
|
159
|
+
Resource Response:
|
160
|
+
|
161
|
+
```json
|
162
|
+
{
|
163
|
+
"AmiId": String
|
164
|
+
}
|
165
|
+
```
|
166
|
+
|
167
|
+
Configuration:
|
168
|
+
|
169
|
+
```json
|
170
|
+
{
|
171
|
+
"jackal": {
|
172
|
+
"cfn": {
|
173
|
+
"config": {
|
174
|
+
"ami": {
|
175
|
+
"credentials": {
|
176
|
+
"compute": {
|
177
|
+
FOG_CREDENTIALS
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
185
|
+
```
|
186
|
+
|
187
|
+
#### `Jackal::Cfn::AmiManager`
|
188
|
+
|
189
|
+
This resource is a simplification of the `AmiRegister` resource. The
|
190
|
+
`AmiManager` is used to ensure an AMI is removed from the system when
|
191
|
+
a stack is destroyed. This allows for customized AMI generation to be
|
192
|
+
integrated and ensure that once the stack is destroyed all custom AMIs
|
193
|
+
for that stack are destroyed as well.
|
194
|
+
|
195
|
+
Resource usage:
|
196
|
+
|
197
|
+
```json
|
198
|
+
{
|
199
|
+
"Type": "Custom::AmiManager",
|
200
|
+
"Properties": {
|
201
|
+
"Parameters": {
|
202
|
+
"AmiId": "",
|
203
|
+
"Region": ""
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
```
|
208
|
+
|
209
|
+
Resource Response:
|
210
|
+
|
211
|
+
```json
|
212
|
+
{
|
213
|
+
}
|
214
|
+
```
|
215
|
+
|
216
|
+
Configuration:
|
217
|
+
|
218
|
+
```json
|
219
|
+
{
|
220
|
+
"jackal": {
|
221
|
+
"cfn": {
|
222
|
+
"config": {
|
223
|
+
"ami": {
|
224
|
+
"credentials": {
|
225
|
+
"compute": {
|
226
|
+
FOG_CREDENTIALS
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
230
|
+
}
|
231
|
+
}
|
232
|
+
}
|
233
|
+
}
|
234
|
+
```
|
235
|
+
|
236
|
+
#### `Jackal::Cfn::HashExtractor`
|
237
|
+
|
238
|
+
This resource will extract a nested hash value from a JSON string. Useful
|
239
|
+
for when a result may be serialized JSON and a value from that structure
|
240
|
+
is required elsewhere.
|
241
|
+
|
242
|
+
Resource usage:
|
243
|
+
|
244
|
+
```json
|
245
|
+
{
|
246
|
+
"Type": "Custom::HashExtractor",
|
247
|
+
"Properties": {
|
248
|
+
"Parameters": {
|
249
|
+
"Key": "path.to.value.in.hash",
|
250
|
+
"Value": JSON
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}
|
254
|
+
```
|
255
|
+
|
256
|
+
Resource Response:
|
257
|
+
|
258
|
+
```json
|
259
|
+
{
|
260
|
+
"Payload": VALUE
|
261
|
+
}
|
262
|
+
```
|
263
|
+
|
264
|
+
#### `Jackal::Cfn::JackalStack`
|
265
|
+
|
266
|
+
This resource provides an integration point for building stacks
|
267
|
+
on remote endpoints. Remote end points are provided via configuration
|
268
|
+
and referenced via the `Location` property in the custom resource.
|
269
|
+
|
270
|
+
Resource usage:
|
271
|
+
|
272
|
+
```json
|
273
|
+
{
|
274
|
+
"Type": "Custom::JackalStack",
|
275
|
+
"Properties": {
|
276
|
+
"Parameters": {
|
277
|
+
STACK_PARAMETERS
|
278
|
+
},
|
279
|
+
"Location": LOCATION,
|
280
|
+
"TemplateURL": URL
|
281
|
+
}
|
282
|
+
}
|
283
|
+
```
|
284
|
+
|
285
|
+
Resource Response:
|
286
|
+
|
287
|
+
The outputs of the stack will be proxied:
|
288
|
+
|
289
|
+
```json
|
290
|
+
{
|
291
|
+
"Outputs.OUTPUT_NAME": "OUTPUT_VALUE"
|
292
|
+
}
|
293
|
+
```
|
16
294
|
|
17
|
-
|
18
|
-
following structure:
|
295
|
+
Configuration:
|
19
296
|
|
20
297
|
```json
|
298
|
+
{
|
299
|
+
"jackal": {
|
300
|
+
"cfn": {
|
301
|
+
"config": {
|
302
|
+
"jackal_stack": {
|
303
|
+
"credentials": {
|
304
|
+
"storage": {
|
305
|
+
TEMPLATE_S3_CREDENTIALS
|
306
|
+
},
|
307
|
+
LOCATION: {
|
308
|
+
"provider": NAME,
|
309
|
+
MIASMA_CREDENTIALS
|
310
|
+
}
|
311
|
+
}
|
312
|
+
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
}
|
316
|
+
}
|
21
317
|
```
|
22
318
|
|
23
319
|
## Info
|
data/jackal-cfn.gemspec
CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.require_path = 'lib'
|
12
12
|
s.license = 'Apache 2.0'
|
13
13
|
s.add_dependency 'jackal'
|
14
|
+
s.add_dependency 'miasma'
|
14
15
|
s.add_dependency 'patron'
|
15
16
|
s.files = Dir['lib/**/*'] + %w(jackal-cfn.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
|
16
17
|
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'jackal-cfn'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Cfn
|
5
|
+
# Manage AMI Resources
|
6
|
+
#
|
7
|
+
# Expected resource:
|
8
|
+
# {
|
9
|
+
# "Type": "Custom::JackalStack",
|
10
|
+
# "Properties": {
|
11
|
+
# "Parameters": {
|
12
|
+
# STACK_PARAMETERS
|
13
|
+
# },
|
14
|
+
# "Location": LOCATION,
|
15
|
+
# "TemplateURL": "URL"
|
16
|
+
# }
|
17
|
+
# }
|
18
|
+
#
|
19
|
+
# Required configuration:
|
20
|
+
# {
|
21
|
+
# "config": {
|
22
|
+
# "jackal_stack": {
|
23
|
+
# "credentials": {
|
24
|
+
# "storage": {
|
25
|
+
# AWS_CREDENTIALS
|
26
|
+
# },
|
27
|
+
# LOCATION: {
|
28
|
+
# "provider": "NAME",
|
29
|
+
# MIAMSA_CREDENTIALS
|
30
|
+
# }
|
31
|
+
# }
|
32
|
+
# }
|
33
|
+
# }
|
34
|
+
# }
|
35
|
+
class JackalStack < Jackal::Cfn::Resource
|
36
|
+
|
37
|
+
# Load miasma for stack building
|
38
|
+
def setup(*_)
|
39
|
+
require 'miasma'
|
40
|
+
end
|
41
|
+
|
42
|
+
# Perform requested stack action
|
43
|
+
#
|
44
|
+
# @param message [Carnivore::Message]
|
45
|
+
def execute(message)
|
46
|
+
failure_wrap(message) do |payload|
|
47
|
+
cfn_resource = rekey_hash(payload.get(:data, :cfn_resource))
|
48
|
+
properties = rekey_hash(cfn_resource[:resource_properties])
|
49
|
+
parameters = rekey_hash(properties[:parameters])
|
50
|
+
cfn_response = build_response(cfn_resource)
|
51
|
+
case cfn_resource[:request_type].to_sym
|
52
|
+
when :create
|
53
|
+
create_stack(cfn_response, cfn_resource, properties, parameters, message)
|
54
|
+
when :update
|
55
|
+
update_stack(cfn_response, cfn_resource, properties, parameters, message)
|
56
|
+
when :delete
|
57
|
+
destroy_stack(cfn_response, cfn_resource, message)
|
58
|
+
else
|
59
|
+
error "Unknown request type received: #{cfn_resource[:request_type].inspect}"
|
60
|
+
cfn_response['Status'] = 'FAILED'
|
61
|
+
cfn_response['Reason'] = 'Unknown request type received'
|
62
|
+
end
|
63
|
+
respond_to_stack(cfn_response, cfn_resource[:response_url])
|
64
|
+
job_completed(:jackal_cfn, payload, message)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Build API connection to base template storage bucket
|
69
|
+
#
|
70
|
+
# @param bucket_region [String] location of bucket
|
71
|
+
# @return [Miasma::Models::Storage]
|
72
|
+
def storage_api(bucket_region)
|
73
|
+
Miasma.api(
|
74
|
+
:type => :storage,
|
75
|
+
:provider => :aws,
|
76
|
+
:credentials => config.get(:jackal_stack, :credentials, :storage).merge(
|
77
|
+
:aws_bucket_region => bucket_region
|
78
|
+
)
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Build orchestration API connection for provided location
|
83
|
+
#
|
84
|
+
# @param location [String, Symbol]
|
85
|
+
# @return [Miasma::Models::Orchestration]
|
86
|
+
def remote_api(location)
|
87
|
+
l_config = config.get(:jackal_stack, :credentials, location)
|
88
|
+
if(l_config)
|
89
|
+
Miasma.api(
|
90
|
+
:type => :orchestration,
|
91
|
+
:provider => l_config[:provider],
|
92
|
+
:credentials => l_config
|
93
|
+
)
|
94
|
+
else
|
95
|
+
raise ArgumentError.new "Unknown target location provided `#{location}`!"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Fetch a template from a storage bucket
|
100
|
+
#
|
101
|
+
# @param endpoint [String] URL to template
|
102
|
+
# @return [Hash] loaded template data
|
103
|
+
def fetch_template(endpoint)
|
104
|
+
url = URI.parse(endpoint)
|
105
|
+
region = url.host.split('.').first.split('-', 2).last
|
106
|
+
if(region == 's3')
|
107
|
+
region = 'us-east-1'
|
108
|
+
end
|
109
|
+
bucket, path = url.path.sub('/', '').split('/', 2)
|
110
|
+
MultiJson.load(
|
111
|
+
storage_api(region).buckets.get(
|
112
|
+
bucket.sub('/', '')
|
113
|
+
).files.get(path).body.read
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Create a new stack and update the response values
|
118
|
+
#
|
119
|
+
# @param response [Hash] response data of action
|
120
|
+
# @param resource [Hash] request resource
|
121
|
+
# @param properties [Hash] properties of request resource
|
122
|
+
# @param parameters [Hash] parmeters provided via properties
|
123
|
+
# @param message [Carnivore::Message] original message
|
124
|
+
# @return [TrueClass, FalseClass]
|
125
|
+
def create_stack(response, resource, properties, parameters, message)
|
126
|
+
stack = remote_api(properties[:location]).stacks.build(
|
127
|
+
:name => [
|
128
|
+
'JackalStack',
|
129
|
+
resource[:logical_resource_id],
|
130
|
+
resource[:stack_id].split('/').last
|
131
|
+
].join('-'),
|
132
|
+
:template => properties.fetch(:stack, fetch_template(properties[:template_url])),
|
133
|
+
:parameters => Hash[parameters.map{|k,v| [Bogo::Utility.camel(k), v] }]
|
134
|
+
)
|
135
|
+
stack.save
|
136
|
+
until(stack.state.to_s.end_with?('complete'))
|
137
|
+
message.touch!
|
138
|
+
debug "Waiting for created stack to reach completion..."
|
139
|
+
sleep 5
|
140
|
+
stack.reload
|
141
|
+
end
|
142
|
+
if(stack.state.to_s.end_with?('complete') || stack.state.to_s.end_with?('failed'))
|
143
|
+
stack.outputs.each do |output|
|
144
|
+
response['Data']["Outputs.#{output.key}"] = output.value
|
145
|
+
end
|
146
|
+
response['PhysicalResourceId'] = "#{properties[:location]}-#{stack.id}"
|
147
|
+
true
|
148
|
+
else
|
149
|
+
response['Status'] = 'FAILED'
|
150
|
+
response['Reason'] = 'Stack creation failed!'
|
151
|
+
stack.destroy
|
152
|
+
false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Update an existing stack and update the response values
|
157
|
+
#
|
158
|
+
# @param response [Hash] response data of action
|
159
|
+
# @param resource [Hash] request resource
|
160
|
+
# @param properties [Hash] properties of request resource
|
161
|
+
# @param parameters [Hash] parmeters provided via properties
|
162
|
+
# @param message [Carnivore::Message] original message
|
163
|
+
# @return [TrueClass, FalseClass]
|
164
|
+
def update_stack(response, resource, properties, parameters, message)
|
165
|
+
c_location, stack_id = resource[:physical_resource_id].split('-', 2)
|
166
|
+
if(c_location != properties[:location])
|
167
|
+
warn "Stack resource has changed location! #{c_location} -> #{properties[:location]}"
|
168
|
+
warn "Starting destruction of existing resource: #{stack_id}"
|
169
|
+
if(destroy_stack(response, resource, message))
|
170
|
+
info "Destruction of stack `#{stack_id}` complete. Creating replacement stack."
|
171
|
+
create_stack(response, resource, properties, parameters, message)
|
172
|
+
else
|
173
|
+
error "Failed to destroy existing stack for replacement `#{stack_id}`"
|
174
|
+
end
|
175
|
+
else
|
176
|
+
stack = remote_api(c_location).stacks.get(stack_id)
|
177
|
+
if(stack)
|
178
|
+
info "Stack resource update on: #{stack_id}"
|
179
|
+
stack.template = fetch_template(properties['TemplateURL'])
|
180
|
+
stack.parameters = Hash[parameters.map{|k,v| [Bogo::Utility.camel(k), v] }]
|
181
|
+
stack.save
|
182
|
+
until(stack.state.to_s.end_with?('complete') || stack.state.to_s.end_with?('failed'))
|
183
|
+
debug "Waiting for created stack to reach completion..."
|
184
|
+
sleep 5
|
185
|
+
stack.reload
|
186
|
+
end
|
187
|
+
if(stack.state.to_s.end_with?('complete'))
|
188
|
+
stack.outputs.each do |output|
|
189
|
+
response['Data']["Outputs.#{output.key}"] = output.value
|
190
|
+
end
|
191
|
+
response['PhysicalResourceId'] = stack.id
|
192
|
+
else
|
193
|
+
response['Status'] = 'FAILED'
|
194
|
+
response['Reason'] = 'Stack update failed!'
|
195
|
+
end
|
196
|
+
else
|
197
|
+
response['Status'] = 'FAILED'
|
198
|
+
response['Reason'] = "No stack was found matching request: #{stack_id}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Destroy the stack
|
204
|
+
#
|
205
|
+
# @param response [Hash] response data of action
|
206
|
+
# @param resource [Hash] request resource
|
207
|
+
# @param message [Carnivore::Message] original message
|
208
|
+
def destroy_stack(response, resource, message)
|
209
|
+
stack = request_destroy(resource[:physical_resource_id])
|
210
|
+
if(stack)
|
211
|
+
until(stack.state.nil? || stack.state.to_s.end_with?('complete') || stack.state.to_s.end_with?('failed'))
|
212
|
+
info "Waiting for stack destruction (#{stack.name})..."
|
213
|
+
message.touch!
|
214
|
+
sleep 5
|
215
|
+
stack.reload
|
216
|
+
end
|
217
|
+
if(stack.state.to_s.end_with?('failed'))
|
218
|
+
response['Status'] = 'FAILED'
|
219
|
+
response['Reason'] = 'Failed to delete remote stack!'
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Send a stack delete request
|
225
|
+
#
|
226
|
+
# @param stack_resource_id [String] physical resource ID
|
227
|
+
# @return [Miasma::Models::Orchestration::Stack, FalseClass]
|
228
|
+
def request_destroy(stack_resource_id)
|
229
|
+
location, stack_id = stack_resource_id.split('-', 2)
|
230
|
+
if(stack_id)
|
231
|
+
begin
|
232
|
+
info "Sending stack destruction request to: #{stack_id} in: #{location}"
|
233
|
+
stack = remote_api(location).stacks.get(stack_id)
|
234
|
+
stack.destroy
|
235
|
+
stack
|
236
|
+
rescue => e
|
237
|
+
error "Stack destruction request failed! #{e.class}: #{e.message}"
|
238
|
+
false
|
239
|
+
end
|
240
|
+
else
|
241
|
+
warn "No stack ID registered in resource. Skipping destroy: #{stack_resource_id}"
|
242
|
+
false
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
data/lib/jackal-cfn/resource.rb
CHANGED
@@ -175,12 +175,12 @@ module Jackal
|
|
175
175
|
payload = unpack(message)
|
176
176
|
yield payload
|
177
177
|
rescue => e
|
178
|
-
error "Unexpected error encountered processing custom resource - #{e.class}: #{e}"
|
178
|
+
error "Unexpected error encountered processing custom resource - #{e.class}: #{e.message}"
|
179
179
|
debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
180
180
|
cfn_resource = payload.get(:data, :cfn_resource)
|
181
181
|
cfn_response = build_response(cfn_resource)
|
182
182
|
cfn_response['Status'] = 'FAILED'
|
183
|
-
cfn_response['Reason'] = "Unexpected error encountered [#{e}]"
|
183
|
+
cfn_response['Reason'] = "Unexpected error encountered [#{e.message}]"
|
184
184
|
respond_to_stack(cfn_response, cfn_resource[:response_url])
|
185
185
|
message.confirm!
|
186
186
|
end
|
data/lib/jackal-cfn/utils.rb
CHANGED
@@ -13,7 +13,7 @@ module Jackal
|
|
13
13
|
# @return [Hash] new hash with snake cased toplevel keys
|
14
14
|
def transform_parameters(params)
|
15
15
|
Smash.new.tap do |new_hash|
|
16
|
-
params.each do |key, value|
|
16
|
+
(params || []).each do |key, value|
|
17
17
|
new_hash[snakecase(key)] = value
|
18
18
|
end
|
19
19
|
end
|
data/lib/jackal-cfn/version.rb
CHANGED
data/lib/jackal-cfn.rb
CHANGED
@@ -12,5 +12,6 @@ module Jackal
|
|
12
12
|
autoload :HashExtractor, 'jackal-cfn/resource/hash_extractor'
|
13
13
|
autoload :AmiManager, 'jackal-cfn/resource/ami_manager'
|
14
14
|
autoload :AmiRegister, 'jackal-cfn/resource/ami_register'
|
15
|
+
autoload :JackalStack, 'jackal-cfn/resource/jackal_stack'
|
15
16
|
end
|
16
17
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jackal-cfn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08
|
11
|
+
date: 2015-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jackal
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: miasma
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: patron
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,6 +70,7 @@ files:
|
|
56
70
|
- lib/jackal-cfn/resource/ami_manager.rb
|
57
71
|
- lib/jackal-cfn/resource/ami_register.rb
|
58
72
|
- lib/jackal-cfn/resource/hash_extractor.rb
|
73
|
+
- lib/jackal-cfn/resource/jackal_stack.rb
|
59
74
|
- lib/jackal-cfn/utils.rb
|
60
75
|
- lib/jackal-cfn/utils/fog.rb
|
61
76
|
- lib/jackal-cfn/utils/http.rb
|