jackal-cfn 0.1.2 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +3 -0
- data/lib/jackal-cfn/resource/ami_manager.rb +109 -0
- data/lib/jackal-cfn/resource/hash_extractor.rb +2 -16
- data/lib/jackal-cfn/resource.rb +19 -4
- data/lib/jackal-cfn/version.rb +1 -1
- metadata +3 -2
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'jackal-cfn'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Cfn
|
5
|
+
class Resource
|
6
|
+
# Manage AMI Resources
|
7
|
+
#
|
8
|
+
# Expected resource:
|
9
|
+
# {
|
10
|
+
# "Type": "Custom::AmiManager",
|
11
|
+
# "Properties": {
|
12
|
+
# "Parameters": {
|
13
|
+
# "InstanceId": "",
|
14
|
+
# "AmiId": "",
|
15
|
+
# "Action": "",
|
16
|
+
# "Region": ""
|
17
|
+
# }
|
18
|
+
# }
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
# Required configuration:
|
22
|
+
# {
|
23
|
+
# "config": {
|
24
|
+
# "credentials": {
|
25
|
+
# "compute": {
|
26
|
+
# FOG_CREDENTIALS
|
27
|
+
# }
|
28
|
+
# }
|
29
|
+
# }
|
30
|
+
# }
|
31
|
+
class AmiManager < Resource
|
32
|
+
|
33
|
+
PHYSICAL_ID_JOINER = '__-__'
|
34
|
+
|
35
|
+
# Process message, send value back to CFN
|
36
|
+
#
|
37
|
+
# @param message [Carnivore::Message]
|
38
|
+
def execute(message)
|
39
|
+
payload = unpack(message)
|
40
|
+
parameters = transform_parameters(payload[:resource_properties]['Parameters'])
|
41
|
+
debug "Processing payload: #{payload.inspect}"
|
42
|
+
response = build_response(payload)
|
43
|
+
case payload[:request_type]
|
44
|
+
when :create
|
45
|
+
ami_response_update(response, parameters)
|
46
|
+
when :delete
|
47
|
+
destroy_ami(response, payload, parameters)
|
48
|
+
when :update
|
49
|
+
else
|
50
|
+
error "Unknown request type received: #{payload[:request_type].inspect}"
|
51
|
+
response['Status'] = 'FAILED'
|
52
|
+
response['Reason'] = 'Unknown request type received'
|
53
|
+
end
|
54
|
+
respond_to_stack(response, payload[:response_url])
|
55
|
+
completed(
|
56
|
+
new_payload(
|
57
|
+
config.fetch(:name, :ami_manager),
|
58
|
+
:cfn_resource => payload
|
59
|
+
),
|
60
|
+
message
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Update the physical resource id to include the ami id
|
65
|
+
#
|
66
|
+
# @param response [Hash] cfn response
|
67
|
+
# @param parameters [Hash] resource parameters
|
68
|
+
# @return [Hash] updated response hash
|
69
|
+
def ami_response_update(response, parameters)
|
70
|
+
response['PhysicalResourceId'] = [
|
71
|
+
response['PhysicalResourceId'],
|
72
|
+
parameters[:ami_id]
|
73
|
+
].join(PHYSICAL_ID_JOINER)
|
74
|
+
response
|
75
|
+
end
|
76
|
+
|
77
|
+
# Destroy the AMI referenced by the resource
|
78
|
+
#
|
79
|
+
# @param response [Hash] cfn response
|
80
|
+
# @param payload [Hash] message payload
|
81
|
+
# @param parameters [Hash] resource parameters
|
82
|
+
# @return [TrueClass]
|
83
|
+
def destroy_ami(response, payload, parameters)
|
84
|
+
ami_id = payload[:physical_resource_id].split(PHYSICAL_ID_JOINER).last
|
85
|
+
begin
|
86
|
+
compute_api(parameters[:region]).deregister_image(ami_id)
|
87
|
+
rescue Fog::Compute::AWS::Error => e
|
88
|
+
warn "Non-fatal error encountered on AMI removal: #{e.class}: #{e}"
|
89
|
+
response['Reason'] = e.message
|
90
|
+
rescue => e
|
91
|
+
error "Failed to remove AMI: #{e.class}: #{e}"
|
92
|
+
response['Status'] = 'FAILED'
|
93
|
+
response['Reason'] = e.message
|
94
|
+
end
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
# Build new compute api connection
|
99
|
+
#
|
100
|
+
# @param region [String] AWS region ami exists
|
101
|
+
# @return [Fog::Compute]
|
102
|
+
def compute_api(region)
|
103
|
+
Fog::Compute.new({:provider => :aws}.merge(config.fetch(:credentials, :compute, {}).merge(:region => region)))
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -5,8 +5,9 @@ module Jackal
|
|
5
5
|
class Resource
|
6
6
|
# Extract value from hash
|
7
7
|
#
|
8
|
-
# Expected resource
|
8
|
+
# Expected resource:
|
9
9
|
# {
|
10
|
+
# "Type": "Custom::HashExtractor",
|
10
11
|
# "Properties": {
|
11
12
|
# "Parameters": {
|
12
13
|
# "Key": "path.to.value.in.hash",
|
@@ -16,21 +17,6 @@ module Jackal
|
|
16
17
|
# }
|
17
18
|
class HashExtractor < Resource
|
18
19
|
|
19
|
-
# Setup the dependency requirements for the callback
|
20
|
-
def setup(*_)
|
21
|
-
require 'patron'
|
22
|
-
end
|
23
|
-
|
24
|
-
# Validity of message
|
25
|
-
#
|
26
|
-
# @param message [Carnivore::Message]
|
27
|
-
# @return [Truthy, Falsey]
|
28
|
-
# def valid?(message)
|
29
|
-
# super do |payload|
|
30
|
-
# payload.get('ResourceProperties', 'Action') == 'hash_extractor'
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
|
34
20
|
# Process message, send value back to CFN
|
35
21
|
#
|
36
22
|
# @param message [Carnivore::Message]
|
data/lib/jackal-cfn/resource.rb
CHANGED
@@ -8,6 +8,12 @@ module Jackal
|
|
8
8
|
VALID_RESOURCE_STATUS = ['SUCCESS', 'FAILED']
|
9
9
|
|
10
10
|
autoload :HashExtractor, 'jackal-cfn/resource/hash_extractor'
|
11
|
+
autoload :AmiManager, 'jackal-cfn/resource/ami_manager'
|
12
|
+
|
13
|
+
# Setup the dependency requirements for the callback
|
14
|
+
def setup(*_)
|
15
|
+
require 'patron'
|
16
|
+
end
|
11
17
|
|
12
18
|
# Physical ID of the resource created
|
13
19
|
#
|
@@ -92,8 +98,10 @@ module Jackal
|
|
92
98
|
payload.fetch('Body', 'Message', payload)
|
93
99
|
)
|
94
100
|
)
|
101
|
+
payload = transform_parameters(payload)
|
95
102
|
payload[:origin_type] = message[:message].get('Body', 'Type')
|
96
103
|
payload[:origin_subject] = message[:message].get('Body', 'Subject')
|
104
|
+
payload[:request_type] = snakecase(payload[:request_type])
|
97
105
|
payload
|
98
106
|
end
|
99
107
|
|
@@ -103,10 +111,10 @@ module Jackal
|
|
103
111
|
# @return [TrueClass, FalseClass]
|
104
112
|
def valid?(message)
|
105
113
|
super do |payload|
|
106
|
-
resource_type = payload[
|
114
|
+
resource_type = payload[:resource_type].split('::').last
|
107
115
|
result = payload[:origin_type] == 'Notification' &&
|
108
116
|
payload[:origin_subject].downcase.include?('cloudformation custom resource') &&
|
109
|
-
|
117
|
+
resource_type == self.class.name.split('::').last
|
110
118
|
if(result && block_given?)
|
111
119
|
yield payload
|
112
120
|
else
|
@@ -136,12 +144,19 @@ module Jackal
|
|
136
144
|
def transform_parameters(params)
|
137
145
|
Smash.new.tap do |new_hash|
|
138
146
|
params.each do |key, value|
|
139
|
-
key
|
140
|
-
new_hash[key] = value
|
147
|
+
new_hash[snakecase(key)] = value
|
141
148
|
end
|
142
149
|
end
|
143
150
|
end
|
144
151
|
|
152
|
+
# Snake case string
|
153
|
+
#
|
154
|
+
# @param v [String]
|
155
|
+
# @return [Symbol]
|
156
|
+
def snakecase(v)
|
157
|
+
v.to_s.gsub(/(?<![A-Z])([A-Z])/, '_\1').sub(/^_/, '').downcase.to_sym
|
158
|
+
end
|
159
|
+
|
145
160
|
end
|
146
161
|
end
|
147
162
|
end
|
data/lib/jackal-cfn/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jackal-cfn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-07-
|
12
|
+
date: 2014-07-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: jackal
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/jackal-cfn/version.rb
|
55
55
|
- lib/jackal-cfn/resource.rb
|
56
56
|
- lib/jackal-cfn/resource/hash_extractor.rb
|
57
|
+
- lib/jackal-cfn/resource/ami_manager.rb
|
57
58
|
- jackal-cfn.gemspec
|
58
59
|
- README.md
|
59
60
|
- CHANGELOG.md
|