jackal-cfn 0.2.16 → 0.2.18

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.
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