jackal-cfn 0.1.2 → 0.1.4
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/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
|