jackal-cfn 0.2.16 → 0.2.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c074ac269a3949f7b1e9554a1d3d301d7656195a
4
- data.tar.gz: 75fd37b327ca6ee8c562ed0f2bfc4be4fb1e97a6
3
+ metadata.gz: d68462a480bb426c377656d7bc2ba63725dd1e61
4
+ data.tar.gz: 35b702d77313eaead8aac1d61e66ddbdbfb55f5c
5
5
  SHA512:
6
- metadata.gz: 4f8d1552c3b1fc950357808137c461f0f21b06db494a9660d9cd9fbc67e69820dc503b8491e9a6d6b6ce3812d6a0274c88453ded523680672a282146764119b2
7
- data.tar.gz: e6441d30aaaaa8fba8f69b40c157e38499d5c3530ac5f730d2f932d15784c9e33fee47b08534f79f61851d087785987f10f3555ea431fcda332313b6d5f3a950
6
+ metadata.gz: a49947efa919dc54ded09b699239054a7648747b474d2317ae7bef30f82a980c2a06ec6274462956abbbb4824c56d62502365f3368bc9984230a01b789a857fd
7
+ data.tar.gz: 0012138672f9a8c7eaccadba908166d0a053b441c292f11c6fa4de86b9caf1189efa8fa2af68ef72956f93208a2900718d5365114ee091570f10da4f06b61533
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # v0.2.18
2
+ * [feature] Add OrchestrationUnit resource
3
+
1
4
  # v0.2.16
2
5
  * [feature] Allow image re-registration when options provided
3
6
  * [enhancement] Add resource scrubber helper
data/README.md CHANGED
@@ -316,6 +316,77 @@ Configuration:
316
316
  }
317
317
  ```
318
318
 
319
+ #### `Jackal::Cfn::OrchestrationUnit`
320
+
321
+ This resource provides a custom "orchestration unit". The "orchestration unit" consists
322
+ of a piece of code. It is similar to the `AWS::Lambda::Function` resource but is more
323
+ freeform. The command to be executed can be provided as an inline string, or as a remote
324
+ URL to a compressed zip file containing a `run.sh` file to execute. If the return value
325
+ is JSON, the values will be accessible using the `Fn::GetAtt` intrinsic function on the
326
+ resource.
327
+
328
+ Resource Usage:
329
+
330
+ ```json
331
+ {
332
+ "Type": "Custom::OrchestrationUnit",
333
+ "Properties": {
334
+ "Exec": "STRING_COMMAND",
335
+ "ExecZip": "REMOTE_URL_TO_ZIP",
336
+ "Env": {
337
+ "CUSTOM_ENV_VARS": "FOR_COMMAND"
338
+ },
339
+ "OnCreate": {
340
+ "Exec": "STRING_COMMAND",
341
+ "ExecZip": "REMOTE_URL_TO_ZIP",
342
+ "Env": {
343
+ "CUSTOM_ENV_VARS": "FOR_COMMAND"
344
+ }
345
+ },
346
+ "OnUpdate": {
347
+ "Exec": "STRING_COMMAND",
348
+ "ExecZip": "REMOTE_URL_TO_ZIP",
349
+ "Env": {
350
+ "CUSTOM_ENV_VARS": "FOR_COMMAND"
351
+ }
352
+ },
353
+ "OnDelete": {
354
+ "Exec": "STRING_COMMAND",
355
+ "ExecZip": "REMOTE_URL_TO_ZIP",
356
+ "Env": {
357
+ "CUSTOM_ENV_VARS": "FOR_COMMAND"
358
+ }
359
+ },
360
+
361
+ }
362
+ }
363
+ ```
364
+
365
+ The `Exec` inline string command has precedence over the `ExecZip` if both are provided. The
366
+ root `Exec` or `ExecZip` are the default commands to be run on _any action_. Customized
367
+ commands per action can be provided using the `OnCreate`, `OnUpdate`, or `OnDelete` properties.
368
+ Environment variables defined in the root properties will be merged with environment variables
369
+ defined for explicit action commands.
370
+
371
+ Resource response:
372
+
373
+ If command result is a non-JSON value:
374
+
375
+ ```json
376
+ {
377
+ "OrchestrationUnitValue": "RESULT_OF_COMMAND"
378
+ }
379
+ ```
380
+
381
+ If the result of the command is a JSON value (for example `{"MyKey": "MyValue"}`):
382
+
383
+ ```json
384
+ {
385
+ "MyKey": "MyValue",
386
+ "OrchestrationUnitValue": "{\"MyKey\": \"MyValue\"}"
387
+ }
388
+ ```
389
+
319
390
  ## Info
320
391
 
321
392
  * Repository: https://github.com/carnviore-rb/jackal-cfn
@@ -0,0 +1,188 @@
1
+ require 'jackal-cfn'
2
+
3
+ module Jackal
4
+ module Cfn
5
+ # Execute arbitrary actions
6
+ #
7
+ # Expected resource:
8
+ # {
9
+ # "Type": "Custom::OrchestrationUnit",
10
+ # "Properties": {
11
+ # "Parameters": {
12
+ # "OnCreate": {
13
+ # "Exec": "SHELL_COMMAND",
14
+ # "ExecZip": "DOWNLOAD_URI",
15
+ # "Env": {
16
+ # }
17
+ # },
18
+ # "OnUpdate": {
19
+ # "Exec": "SHELL_COMMAND",
20
+ # "ExecZip": "DOWNLOAD_URI",
21
+ # "Env": {
22
+ # }
23
+ # },
24
+ # "OnDelete": {
25
+ # "Exec": "SHELL_COMMAND",
26
+ # "ExecZip": "DOWNLOAD_URI",
27
+ # "Env": {
28
+ # }
29
+ # },
30
+ # "Exec": "SHELL_COMMAND",
31
+ # "ExecZip": "DOWNLOAD_URI",
32
+ # "Env": {
33
+ # }
34
+ # }
35
+ # }
36
+ # }
37
+ #
38
+ class OrchestrationUnit < Jackal::Cfn::Resource
39
+
40
+ # Execute orchestration unit
41
+ #
42
+ # @param message [Carnivore::Message]
43
+ def execute(message)
44
+ failure_wrap(message) do |payload|
45
+ cfn_resource = rekey_hash(payload.get(:data, :cfn_resource))
46
+ properties = rekey_hash(cfn_resource[:resource_properties])
47
+ parameters = rekey_hash(properties[:parameters])
48
+ cfn_response = build_response(cfn_resource)
49
+ unit = unit_for(cfn_resource[:request_type], parameters)
50
+ working_dir = create_working_directory(payload[:id])
51
+ run_unit(unit, working_dir, cfn_response)
52
+ FileUtils.rm_rf(working_dir)
53
+ respond_to_stack(cfn_response, cfn_resource[:response_url])
54
+ job_completed(:jackal_cfn, payload, message)
55
+ end
56
+ end
57
+
58
+ # Create a working directory for command execution
59
+ #
60
+ # @param uuid [String] unique identifier
61
+ # @return [String] path
62
+ def create_working_directory(uuid)
63
+ dir_path = File.join(
64
+ config.fetch(
65
+ :working_directory,
66
+ '/tmp/jackal-cfn'
67
+ ),
68
+ uuid
69
+ )
70
+ FileUtils.mkdir_p(dir_path)
71
+ dir_path
72
+ end
73
+
74
+ # Fetch compressed zip file from remote location and unpack into
75
+ # provided working directory
76
+ #
77
+ # @param unit [Hash] orchestration unit
78
+ # @param working_directory [String] local path to working directory
79
+ # @return [Hash] unit
80
+ # @note will automatically set `unit['Exec'] = './run.sh'`
81
+ def fetch_and_unpack_exec(unit, working_directory)
82
+ result = HTTP.get(unit[:exec_zip])
83
+ file = Tempfile.new('orchestration-unit')
84
+ while(data = result.body.readpartial(2048))
85
+ file.write data
86
+ end
87
+ file.flush
88
+ file.rewind
89
+ asset_store.unpack(file, working_directory)
90
+ unit[:exec] = File.join(working_directory, 'run.sh')
91
+ unit
92
+ end
93
+
94
+ # Run the unit and set result information into response
95
+ #
96
+ # @param unit [Hash] orchestration unit
97
+ # @param working_directory [String] path to local working directory
98
+ # @param response [Hash] CFN response
99
+ # @return [Hash] CFN response
100
+ def run_unit(unit, working_directory, response)
101
+ if(unit[:exec_zip])
102
+ fetch_and_unpack_exec(unit, working_directory)
103
+ end
104
+ if(unit[:exec])
105
+ result = Smash.new
106
+ process_manager.process(unit.hash, unit[:exec]) do |process|
107
+ stdout = process_manager.create_io_tmp(Carnivore.uuid, 'stdout')
108
+ stderr = process_manager.create_io_tmp(Carnivore.uuid, 'stderr')
109
+ process.io.stdout = stdout
110
+ process.io.stderr = stderr
111
+ process.cwd = working_directory
112
+ if(unit[:env])
113
+ process.environment.replace(unit[:env])
114
+ end
115
+ process.leader = true
116
+ result[:start_time] = Time.now.to_i
117
+ process.start
118
+ begin
119
+ process.poll_for_exit(config.fetch(:max_execution_time, 60))
120
+ rescue ChildProcess::TimeoutError
121
+ process.stop
122
+ result[:timed_out] = true
123
+ end
124
+ result[:stop_time] = Time.now.to_i
125
+ result[:exit_code] = process.exit_code
126
+ stdout.rewind
127
+ # TODO: size check
128
+ result[:content] = stdout.read
129
+ if(process.exit_code != 0)
130
+ stderr.rewind
131
+ result[:error_message] = stderr.read
132
+ end
133
+ end
134
+ if(result[:exit_code] == 0)
135
+ response['Data']['OrchestrationUnitResult'] = result[:content]
136
+ begin
137
+ j_result = MultiJson.load(result[:content])
138
+ response['Data'] = j_result.merge(response['Data'])
139
+ rescue MultiJson::ParseError => e
140
+ debug 'Command result not JSON data'
141
+ end
142
+ response
143
+ else
144
+ raise "Execution failed! Exit code: #{result[:exit_code]} Reason: #{result[:error_message]}"
145
+ end
146
+ else
147
+ response['Data']['OrchestrationUnitResult'] = 'No command executed!'
148
+ response
149
+ end
150
+ end
151
+
152
+ # Extract unit information based on received request type
153
+ #
154
+ # @param request_type [String] CFN request type
155
+ # @param parameters [Hash] resource parameters
156
+ # @return [Hash] orchestration unit
157
+ def unit_for(request_type, parameters)
158
+ base_key = "on_#{request_type.to_s.downcase}"
159
+ result = Smash.new
160
+ if(direct_unit = parameters[base_key])
161
+ [:exec, :exec_zip, :env].each do |p_key|
162
+ if(direct_unit[p_key])
163
+ result[p_key] = direct[p_key]
164
+ end
165
+ end
166
+ end
167
+ unless(result[:exec] || result[:exec_zip])
168
+ if(parameters[:exec])
169
+ result[:exec] = parameters[:exec]
170
+ elsif(parameters[:exec_zip])
171
+ result[:exec_zip] = parameters[:exec_zip]
172
+ end
173
+ end
174
+ if(parameters[:env])
175
+ if(result[:env])
176
+ result[:env] = parameters[:env].merge(result[:env])
177
+ else
178
+ result[:env] = parameters[:env]
179
+ end
180
+ end
181
+ result[:env] ||= Smash.new
182
+ result[:env]['CFN_REQUEST_TYPE'] = request_type.to_s.upcase
183
+ result
184
+ end
185
+
186
+ end
187
+ end
188
+ end
@@ -1,6 +1,6 @@
1
1
  module Jackal
2
2
  module Cfn
3
3
  # Current version
4
- VERSION = Gem::Version.new('0.2.16')
4
+ VERSION = Gem::Version.new('0.2.18')
5
5
  end
6
6
  end
data/lib/jackal-cfn.rb CHANGED
@@ -13,6 +13,7 @@ module Jackal
13
13
  autoload :AmiManager, 'jackal-cfn/resource/ami_manager'
14
14
  autoload :AmiRegister, 'jackal-cfn/resource/ami_register'
15
15
  autoload :JackalStack, 'jackal-cfn/resource/jackal_stack'
16
+ autoload :OrchestrationUnit, 'jackal-cfn/resource/orchestration_unit'
16
17
  autoload :Scrubber, 'jackal-cfn/resource/scrubber'
17
18
  end
18
19
  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.16
4
+ version: 0.2.18
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-11-18 00:00:00.000000000 Z
11
+ date: 2016-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jackal
@@ -71,6 +71,7 @@ files:
71
71
  - lib/jackal-cfn/resource/ami_register.rb
72
72
  - lib/jackal-cfn/resource/hash_extractor.rb
73
73
  - lib/jackal-cfn/resource/jackal_stack.rb
74
+ - lib/jackal-cfn/resource/orchestration_unit.rb
74
75
  - lib/jackal-cfn/resource/scrubber.rb
75
76
  - lib/jackal-cfn/utils.rb
76
77
  - lib/jackal-cfn/utils/fog.rb