cloud-mu 3.2.0 → 3.3.0

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/bin/mu-adopt +12 -1
  4. data/bin/mu-load-config.rb +2 -1
  5. data/bin/mu-run-tests +14 -2
  6. data/cloud-mu.gemspec +3 -3
  7. data/modules/mu.rb +2 -2
  8. data/modules/mu/adoption.rb +5 -5
  9. data/modules/mu/cleanup.rb +47 -25
  10. data/modules/mu/cloud.rb +29 -1
  11. data/modules/mu/cloud/dnszone.rb +0 -2
  12. data/modules/mu/cloud/resource_base.rb +9 -3
  13. data/modules/mu/cloud/wrappers.rb +4 -0
  14. data/modules/mu/config.rb +1 -1
  15. data/modules/mu/config/bucket.rb +31 -2
  16. data/modules/mu/config/cache_cluster.rb +1 -1
  17. data/modules/mu/config/cdn.rb +100 -0
  18. data/modules/mu/config/container_cluster.rb +1 -1
  19. data/modules/mu/config/database.rb +1 -1
  20. data/modules/mu/config/dnszone.rb +4 -3
  21. data/modules/mu/config/endpoint.rb +1 -0
  22. data/modules/mu/config/function.rb +16 -7
  23. data/modules/mu/config/job.rb +89 -0
  24. data/modules/mu/config/notifier.rb +7 -18
  25. data/modules/mu/config/ref.rb +53 -7
  26. data/modules/mu/config/server.rb +1 -1
  27. data/modules/mu/config/vpc.rb +1 -0
  28. data/modules/mu/defaults/AWS.yaml +26 -26
  29. data/modules/mu/deploy.rb +13 -0
  30. data/modules/mu/master.rb +21 -0
  31. data/modules/mu/mommacat.rb +1 -0
  32. data/modules/mu/mommacat/daemon.rb +13 -7
  33. data/modules/mu/providers/aws.rb +115 -16
  34. data/modules/mu/providers/aws/alarm.rb +2 -2
  35. data/modules/mu/providers/aws/bucket.rb +274 -40
  36. data/modules/mu/providers/aws/cache_cluster.rb +4 -4
  37. data/modules/mu/providers/aws/cdn.rb +782 -0
  38. data/modules/mu/providers/aws/collection.rb +2 -2
  39. data/modules/mu/providers/aws/container_cluster.rb +57 -37
  40. data/modules/mu/providers/aws/database.rb +11 -11
  41. data/modules/mu/providers/aws/dnszone.rb +24 -7
  42. data/modules/mu/providers/aws/endpoint.rb +535 -50
  43. data/modules/mu/providers/aws/firewall_rule.rb +6 -3
  44. data/modules/mu/providers/aws/folder.rb +1 -1
  45. data/modules/mu/providers/aws/function.rb +288 -125
  46. data/modules/mu/providers/aws/group.rb +9 -7
  47. data/modules/mu/providers/aws/habitat.rb +2 -2
  48. data/modules/mu/providers/aws/job.rb +466 -0
  49. data/modules/mu/providers/aws/loadbalancer.rb +9 -8
  50. data/modules/mu/providers/aws/log.rb +3 -3
  51. data/modules/mu/providers/aws/msg_queue.rb +12 -3
  52. data/modules/mu/providers/aws/nosqldb.rb +96 -5
  53. data/modules/mu/providers/aws/notifier.rb +135 -63
  54. data/modules/mu/providers/aws/role.rb +51 -37
  55. data/modules/mu/providers/aws/search_domain.rb +165 -29
  56. data/modules/mu/providers/aws/server.rb +12 -9
  57. data/modules/mu/providers/aws/server_pool.rb +26 -13
  58. data/modules/mu/providers/aws/storage_pool.rb +2 -2
  59. data/modules/mu/providers/aws/user.rb +4 -4
  60. data/modules/mu/providers/aws/userdata/linux.erb +5 -4
  61. data/modules/mu/providers/aws/vpc.rb +3 -3
  62. data/modules/mu/providers/azure/server.rb +2 -1
  63. data/modules/mu/providers/google.rb +1 -0
  64. data/modules/mu/providers/google/bucket.rb +1 -1
  65. data/modules/mu/providers/google/container_cluster.rb +1 -1
  66. data/modules/mu/providers/google/database.rb +1 -1
  67. data/modules/mu/providers/google/firewall_rule.rb +1 -1
  68. data/modules/mu/providers/google/folder.rb +1 -1
  69. data/modules/mu/providers/google/function.rb +1 -1
  70. data/modules/mu/providers/google/group.rb +1 -1
  71. data/modules/mu/providers/google/habitat.rb +1 -1
  72. data/modules/mu/providers/google/loadbalancer.rb +1 -1
  73. data/modules/mu/providers/google/role.rb +4 -2
  74. data/modules/mu/providers/google/server.rb +1 -1
  75. data/modules/mu/providers/google/server_pool.rb +1 -1
  76. data/modules/mu/providers/google/user.rb +1 -1
  77. data/modules/mu/providers/google/vpc.rb +1 -1
  78. data/modules/tests/aws-jobs-functions.yaml +46 -0
  79. data/modules/tests/centos6.yaml +4 -0
  80. data/modules/tests/centos7.yaml +4 -0
  81. data/modules/tests/ecs.yaml +2 -2
  82. data/modules/tests/eks.yaml +1 -1
  83. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  84. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  85. data/modules/tests/microservice_app.yaml +288 -0
  86. data/modules/tests/rds.yaml +5 -5
  87. data/modules/tests/regrooms/rds.yaml +5 -5
  88. data/modules/tests/server-with-scrub-muisms.yaml +1 -1
  89. data/modules/tests/super_complex_bok.yml +2 -2
  90. data/modules/tests/super_simple_bok.yml +2 -2
  91. metadata +12 -4
@@ -155,6 +155,7 @@ module MU
155
155
  # return [Struct]
156
156
  def cloud_desc(use_cache: true)
157
157
  return @cloud_desc_cache if @cloud_desc_cache and use_cache
158
+ return nil if !@mu_name
158
159
  @cloud_desc_cache = MU::Cloud::AWS.iam(credentials: @config['credentials']).get_group(
159
160
  group_name: @mu_name
160
161
  )
@@ -186,12 +187,12 @@ module MU
186
187
  # @param noop [Boolean]: If true, will only print what would be done
187
188
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
188
189
  # @return [void]
189
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
190
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
190
191
  MU.log "AWS::Group.cleanup: need to support flags['known']", MU::DEBUG, details: flags
191
192
  MU.log "Placeholder: AWS Group artifacts do not support tags, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: ignoremaster
192
193
 
193
194
  resp = MU::Cloud::AWS.iam(credentials: credentials).list_groups(
194
- path_prefix: "/"+MU.deploy_id+"/"
195
+ path_prefix: "/"+deploy_id+"/"
195
196
  )
196
197
  if resp and resp.groups
197
198
  resp.groups.each { |g|
@@ -274,14 +275,15 @@ module MU
274
275
  MU.log "toKitten failed to load a cloud_desc from #{@cloud_id}", MU::ERR, details: @config
275
276
  return nil
276
277
  end
277
-
278
- bok["name"] = cloud_desc.group.group_name
279
278
 
280
- if cloud_desc.group.path != "/"
281
- bok["path"] = cloud_desc.group.path
279
+ group_desc = cloud_desc(use_cache: false).respond_to?(:group) ? cloud_desc.group : cloud_desc
280
+ bok["name"] = group_desc.group_name
281
+
282
+ if group_desc.path != "/"
283
+ bok["path"] = group_desc.path
282
284
  end
283
285
 
284
- if cloud_desc.users and cloud_desc.users.size > 0
286
+ if cloud_desc.respond_to?(:users) and cloud_desc.users and cloud_desc.users.size > 0
285
287
  bok["members"] = cloud_desc.users.map { |u| u.user_name }
286
288
  end
287
289
 
@@ -90,7 +90,7 @@ module MU
90
90
  # @param noop [Boolean]: If true, will only print what would be done
91
91
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
92
92
  # @return [void]
93
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
93
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
94
94
  return if !orgMasterCreds?(credentials)
95
95
  MU.log "AWS::Habitat.cleanup: need to support flags['known']", MU::DEBUG, details: flags
96
96
  MU.log "Placeholder: AWS Habitat artifacts do not support tags, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: ignoremaster
@@ -99,7 +99,7 @@ module MU
99
99
 
100
100
  if resp and resp.accounts
101
101
  resp.accounts.each { |acct|
102
- if acct.name.match(/^#{Regexp.quote(MU.deploy_id)}/) or acct.name.match(/BUNS/)
102
+ if acct.name.match(/^#{Regexp.quote(deploy_id)}/) or acct.name.match(/BUNS/)
103
103
  if !noop
104
104
  pp acct
105
105
  end
@@ -0,0 +1,466 @@
1
+ # Copyright:: Copyright (c) 2020 eGlobalTech, Inc., all rights reserved
2
+ #
3
+ # Licensed under the BSD-3 license (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License in the root of the project or at
6
+ #
7
+ # http://egt-labs.com/mu/LICENSE.html
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module MU
16
+ class Cloud
17
+ class AWS
18
+ # A scheduled task facility as configured in {MU::Config::BasketofKittens::jobs}
19
+ class Job < MU::Cloud::Job
20
+
21
+ # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us.
22
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
23
+ def initialize(**args)
24
+ super
25
+ @mu_name ||= @deploy.getResourceName(@config["name"])
26
+ end
27
+
28
+ # Called automatically by {MU::Deploy#createResources}
29
+ def create
30
+ @cloud_id = @mu_name
31
+
32
+ params = get_properties
33
+
34
+ MU.log "Creating CloudWatch Event #{@mu_name}", MU::NOTICE, details: params
35
+
36
+ MU::Cloud::AWS.cloudwatchevents(region: @config['region'], credentials: @credentials).put_rule(params)
37
+ end
38
+
39
+ # Called automatically by {MU::Deploy#createResources}
40
+ def groom
41
+ new_props = get_properties
42
+ current = MU.structToHash(cloud_desc(use_cache: false))
43
+ params = {}
44
+ new_props.each_pair { |k, v|
45
+ next if k == :tags # doesn't seem to do anything
46
+ if v != current[k]
47
+ params[k] = v
48
+ end
49
+ }
50
+
51
+ if params.size > 0
52
+ MU.log "Updating CloudWatch Event #{@cloud_id}", MU::NOTICE, details: params
53
+ MU::Cloud::AWS.cloudwatchevents(region: @config['region'], credentials: @credentials).put_rule(new_props)
54
+ end
55
+
56
+ if @config['targets']
57
+ target_params = []
58
+ @config['targets'].each { |t|
59
+ MU.retrier([MuNonFatal], max:5, wait: 9) {
60
+ target_ref = MU::Config::Ref.get(t)
61
+ target_obj = target_ref.kitten(cloud: "AWS")
62
+ this_target = if target_ref.is_mu_type? and target_obj and
63
+ !target_obj.arn.nil?
64
+ {
65
+ id: target_obj.cloud_id,
66
+ arn: target_obj.arn
67
+ }
68
+ elsif target_ref.id and target_ref.id.match(/^arn:/)
69
+ {
70
+ id: target_ref.id || target_ref.name,
71
+ arn: target_ref.id
72
+ }
73
+ else
74
+ raise MuNonFatal.new "Failed to retrieve ARN from CLoudWatch Event target descriptor", details: target_ref.to_h
75
+ end
76
+ if t['role']
77
+ role_obj = MU::Config::Ref.get(t['role']).kitten(@deploy, cloud: "AWS")
78
+ raise MuError.new "Failed to fetch object from role reference", details: t['role'].to_h if !role_obj
79
+ params[:role_arn] = role_obj.arn
80
+ end
81
+ [:input, :input_path, :input_transformer, :kinesis_parameters, :run_command_parameters, :batch_parameters, :sqs_parameters, :ecs_parameters].each { |attr|
82
+ if t[attr.to_s]
83
+ this_target[attr] = MU.structToHash(t[attr.to_s])
84
+ end
85
+ }
86
+ target_params << this_target
87
+ }
88
+ }
89
+ MU::Cloud::AWS.cloudwatchevents(region: @config['region'], credentials: @credentials).put_targets(
90
+ rule: @cloud_id,
91
+ event_bus_name: cloud_desc.event_bus_name,
92
+ targets: target_params
93
+ )
94
+ end
95
+
96
+ end
97
+
98
+ # Canonical Amazon Resource Number for this resource
99
+ # @return [String]
100
+ def arn
101
+ cloud_desc ? cloud_desc.arn : nil
102
+ end
103
+
104
+ # Return the metadata for this job
105
+ # @return [Hash]
106
+ def notify
107
+ MU.structToHash(cloud_desc, stringify_keys: true)
108
+ end
109
+
110
+ # Does this resource type exist as a global (cloud-wide) artifact, or
111
+ # is it localized to a region/zone?
112
+ # @return [Boolean]
113
+ def self.isGlobal?
114
+ false
115
+ end
116
+
117
+ # Denote whether this resource implementation is experiment, ready for
118
+ # testing, or ready for production use.
119
+ def self.quality
120
+ MU::Cloud::BETA
121
+ end
122
+
123
+ # Remove all jobs associated with the currently loaded deployment.
124
+ # @param noop [Boolean]: If true, will only print what would be done
125
+ # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
126
+ # @param region [String]: The cloud provider region
127
+ # @return [void]
128
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
129
+ found = find(region: region, credentials: credentials)
130
+
131
+ found.each_pair { |id, desc|
132
+ if (desc.description and desc.description == deploy_id) or
133
+ (flags and flags['known'] and flags['known'].include?(id))
134
+ MU.log "Deleting CloudWatch Event #{id}"
135
+ if !noop
136
+ resp = MU::Cloud::AWS.cloudwatchevents(region: region, credentials: credentials).list_targets_by_rule(
137
+ rule: id,
138
+ event_bus_name: desc.event_bus_name,
139
+ )
140
+ if resp and resp.targets and !resp.targets.empty?
141
+ MU::Cloud::AWS.cloudwatchevents(region: region, credentials: credentials).remove_targets(
142
+ rule: id,
143
+ event_bus_name: desc.event_bus_name,
144
+ ids: resp.targets.map { |t| t.id }
145
+ )
146
+ end
147
+
148
+ MU::Cloud::AWS.cloudwatchevents(region: region, credentials: credentials).delete_rule(
149
+ name: id,
150
+ event_bus_name: desc.event_bus_name
151
+ )
152
+ end
153
+ end
154
+ }
155
+ end
156
+
157
+ # Locate an existing event.
158
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching CloudWatch Event
159
+ def self.find(**args)
160
+ found = {}
161
+
162
+ MU::Cloud::AWS.cloudwatchevents(region: args[:region], credentials: args[:credentials]).list_rules.rules.each { |r|
163
+ next if args[:cloud_id] and ![r.name, r.arn].include?(args[:cloud_id])
164
+ found[r.name] = r
165
+ }
166
+
167
+ found
168
+ end
169
+
170
+ # Reverse-map our cloud description into a runnable config hash.
171
+ # We assume that any values we have in +@config+ are placeholders, and
172
+ # calculate our own accordingly based on what's live in the cloud.
173
+ def toKitten(**_args)
174
+ bok = {
175
+ "cloud" => "AWS",
176
+ "credentials" => @config['credentials'],
177
+ "cloud_id" => @cloud_id,
178
+ "region" => @config['region']
179
+ }
180
+
181
+ if !cloud_desc
182
+ MU.log "toKitten failed to load a cloud_desc from #{@cloud_id}", MU::ERR, details: @config
183
+ return nil
184
+ end
185
+ bok['name'] = cloud_desc.name
186
+ if cloud_desc.description and !cloud_desc.description.empty?
187
+ bok['description'] = cloud_desc.description
188
+ end
189
+
190
+ bok['disabled'] = true if cloud_desc.state == "DISABLED"
191
+
192
+ # schedule_expression="cron(15 6 * * ? *)"
193
+ if cloud_desc.schedule_expression
194
+ if cloud_desc.schedule_expression.match(/cron\((\S+) (\S+) (\S+) (\S+) (\S+) (\S+)\)/)
195
+ bok['schedule'] = {
196
+ "minute" => Regexp.last_match[1],
197
+ "hour" => Regexp.last_match[2],
198
+ "day_of_month" => Regexp.last_match[3],
199
+ "month" => Regexp.last_match[4],
200
+ "day_of_week" => Regexp.last_match[5],
201
+ "year" => Regexp.last_match[6]
202
+ }
203
+ else
204
+ MU.log "HALP", MU::ERR, details: cloud_desc.schedule_expression
205
+ end
206
+ end
207
+
208
+ if cloud_desc.role_arn
209
+ shortname = cloud_desc.role_arn.sub(/.*?role\/([^\/]+)$/, '\1')
210
+ bok['role'] = MU::Config::Ref.get(
211
+ id: shortname,
212
+ cloud: "AWS",
213
+ type: "roles"
214
+ )
215
+ end
216
+
217
+ targets = MU::Cloud::AWS.cloudwatchevents(region: @config['region'], credentials: @credentials).list_targets_by_rule(
218
+ rule: @cloud_id,
219
+ event_bus_name: cloud_desc.event_bus_name
220
+ ).targets
221
+ targets.each { |t|
222
+ bok['targets'] ||= []
223
+ _arn, _plat, service, region, account, resource = t.arn.split(/:/, 6)
224
+ target_type = if service == "lambda"
225
+ resource.sub!(/^function:/, '')
226
+ "functions"
227
+ elsif service == "sns"
228
+ "notifiers"
229
+ elsif service == "sqs"
230
+ "msg_queues"
231
+ else
232
+ service
233
+ end
234
+ ref_params = {
235
+ id: resource,
236
+ region: region,
237
+ type: target_type,
238
+ cloud: "AWS",
239
+ credentials: @credentials,
240
+ habitat: MU::Config::Ref.get(
241
+ id: account,
242
+ cloud: "AWS",
243
+ credentials: @credentials
244
+ )
245
+ }
246
+ [:input, :input_path, :input_transformer, :kinesis_parameters, :run_command_parameters, :batch_parameters, :sqs_parameters].each { |attr|
247
+ if t.respond_to?(attr) and !t.send(attr).nil?
248
+ ref_params[attr] = MU.structToHash(t.send(attr), stringify_keys: true)
249
+ end
250
+ }
251
+
252
+ bok['targets'] << MU::Config::Ref.get(ref_params)
253
+ }
254
+
255
+ # XXX cloud_desc.event_pattern - what do we want to do with this?
256
+
257
+ bok
258
+ end
259
+
260
+
261
+ # Cloud-specific configuration properties.
262
+ # @param _config [MU::Config]: The calling MU::Config object
263
+ # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
264
+ def self.schema(_config)
265
+ toplevel_required = []
266
+
267
+ target_schema = MU::Config::Ref.schema(any_type: true, desc: "A resource which will be invoked by this event. Can be a reference to a sibling Mu resource, typically a +Function+ or +MsgQueue+, or to an unadorned external cloud resource.")
268
+ target_params = {
269
+ "role" => MU::Config::Ref.schema(type: "roles", desc: "A sibling {MU::Config::BasketofKittens::roles} entry or the id of an existing IAM role to assign to use when interacting with this target.", omit_fields: ["region", "tag"]),
270
+ "input" => {
271
+ "type" => "string"
272
+ },
273
+ "input_path" => {
274
+ "type" => "string"
275
+ },
276
+ "run_command_parameters" => {
277
+ "type" => "object",
278
+ "description" => "Parameters used when you are using the rule to invoke Amazon EC2 Run Command",
279
+ "required" => ["run_command_targets"],
280
+ "properties" => {
281
+ "run_command_targets" => {
282
+ "type" => "array",
283
+ "items" => {
284
+ "type" => "object",
285
+ "description" => "Currently, AWS supports including only one +run_command_targets+ block, which specifies either an array of InstanceIds or a tag.",
286
+ "required" => ["key", "values"],
287
+ "properties" => {
288
+ "key" => {
289
+ "type" => "string",
290
+ "description" => "Can be either +tag: tag-key+ or +InstanceIds+"
291
+ },
292
+ "values" => {
293
+ "type" => "array",
294
+ "items" => {
295
+ "description" => "If +key+ is +tag: tag-key+, +values+ is a list of tag values; if +key+ is +InstanceIds+, +values+ is a list of Amazon EC2 instance IDs.",
296
+ "type" => "string"
297
+ }
298
+ }
299
+ }
300
+ }
301
+ }
302
+ }
303
+ },
304
+ "input_transformer" => {
305
+ "type" => "object",
306
+ "description" => "Settings to enable you to provide custom input to a target based on certain event data. You can extract one or more key-value pairs from the event and then use that data to send customized input to the target.",
307
+ "required" => ["input_template"],
308
+ "properties" => {
309
+ "input_template" => {
310
+ "type" => "string",
311
+ "description" => "Input template where you specify placeholders that will be filled with the values of the keys from +input_paths_map+ to customize the data sent to the target."
312
+ },
313
+ "input_paths_map" => {
314
+ "type" => "object",
315
+ "description" => "Hash representing JSON paths to be extracted from the event"
316
+ }
317
+ }
318
+ },
319
+ "batch_parameters" => {
320
+ "type" => "object",
321
+ "description" => "If the event target is an AWS Batch job, this contains the job definition, job name, and other parameters. See: https://docs.aws.amazon.com/batch/latest/userguide/jobs.html",
322
+ "required" => ["job_definition", "job_name"],
323
+ "properties" => {
324
+ "job_definition" => {
325
+ "description" => "The ARN or name of the job definition to use if the event target is an AWS Batch job.",
326
+ "type" => "string"
327
+ },
328
+ "job_name" => {
329
+ "description" => "The name to use for this execution of the job, if the target is an AWS Batch job.",
330
+ "type" => "string"
331
+ },
332
+ "array_properties" => {
333
+ "type" => "object",
334
+ "description" => "The array properties for the submitted job, such as the size of the array.",
335
+ "properties" => {
336
+ "size" => {
337
+ "description" => "Size of the submitted array",
338
+ "type" => "integer"
339
+ }
340
+ }
341
+ },
342
+ "retry_strategy" => {
343
+ "type" => "object",
344
+ "description" => "The retry strategy to use for failed jobs, if the target is an AWS Batch job.",
345
+ "properties" => {
346
+ "attempts" => {
347
+ "description" => "Number of retry attempts, valid values from 1-10",
348
+ "type" => "integer"
349
+ }
350
+ }
351
+ }
352
+ }
353
+ },
354
+ "sqs_parameters" => {
355
+ "type" => "object",
356
+ "description" => "Contains the message group ID to use when the target is an SQS FIFO queue.",
357
+ "required" => ["message_group_id"],
358
+ "properties" => {
359
+ "message_group_id" => {
360
+ "type" => "string"
361
+ }
362
+ }
363
+ },
364
+ "kinesis_parameters" => {
365
+ "type" => "object",
366
+ "description" => "The custom parameter you can use to control the shard assignment, when the target is a Kinesis data stream.",
367
+ "required" => ["partition_key_path"],
368
+ "properties" => {
369
+ "partition_key_path" => {
370
+ "type" => "string"
371
+ }
372
+ }
373
+ },
374
+ "http_parameters" => {
375
+ "type" => "object",
376
+ "description" => "Contains the HTTP parameters to use when the target is a API Gateway REST endpoint.",
377
+ "properties" => {
378
+ "path_parameter_values" => {
379
+ "type" => "array",
380
+ "items" => {
381
+ "description" => "The path parameter values to be used to populate API Gateway REST API path wildcards (\"*\").",
382
+ "type" => "string"
383
+ }
384
+ },
385
+ "header_parameters" => {
386
+ "description" => "Key => value pairs to pass as headers",
387
+ "type" => "object"
388
+ },
389
+ "query_string_parameters" => {
390
+ "description" => "Key => value pairs to pass as query strings",
391
+ "type" => "object"
392
+ }
393
+ }
394
+ }
395
+ }
396
+ target_schema["properties"].merge!(target_params)
397
+
398
+ schema = {
399
+ "disabled" => {
400
+ "type" => "boolean",
401
+ "description" => "Leave this job in place but disabled",
402
+ "default" => false
403
+ },
404
+ "role" => MU::Config::Ref.schema(type: "roles", desc: "A sibling {MU::Config::BasketofKittens::roles} entry or the id of an existing IAM role to assign to this CloudWatch Event.", omit_fields: ["region", "tag"]),
405
+ "targets" => {
406
+ "type" => "array",
407
+ "items" => target_schema
408
+ }
409
+ }
410
+ [toplevel_required, schema]
411
+ end
412
+
413
+ # Cloud-specific pre-processing of {MU::Config::BasketofKittens::jobs}, bare and unvalidated.
414
+ # @param job [Hash]: The resource to process and validate
415
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
416
+ # @return [Boolean]: True if validation succeeded, False otherwise
417
+ def self.validateConfig(job, _configurator)
418
+ ok = true
419
+
420
+ job['targets'].each { |t|
421
+ target_ref = MU::Config::Ref.get(t)
422
+ if target_ref.is_mu_type? and target_ref.name
423
+ MU::Config.addDependency(job, target_ref.name, target_ref.type)
424
+ end
425
+ }
426
+
427
+ ok
428
+ end
429
+
430
+ private
431
+
432
+ def get_properties
433
+ params = {
434
+ name: @cloud_id,
435
+ state: @config['disabled'] ? "DISABLED" : "ENABLED",
436
+ event_bus_name: "default" # XXX expose, or create a deploy-specific one?
437
+ }
438
+
439
+ params[:description] = if @config['description'] and @config['scrub_mu_isms']
440
+ @config['description']
441
+ else
442
+ @deploy.deploy_id
443
+ end
444
+
445
+ if @tags
446
+ params[:tags] = @tags.each_key.map { |k| { :key => k, :value => @tags[k] } }
447
+ end
448
+
449
+ if @config['role']
450
+ role_obj = MU::Config::Ref.get(@config['role']).kitten(@deploy, cloud: "AWS")
451
+ raise MuError.new "Failed to fetch object from role reference", details: @config['role'].to_h if !role_obj
452
+ params[:role_arn] = role_obj.arn
453
+ end
454
+
455
+ if @config['schedule']
456
+ params[:schedule_expression] = "cron(" + ["minute", "hour", "day_of_month", "month", "day_of_week", "year"].map { |i| @config['schedule'][i] }.join(" ") +")"
457
+ end
458
+
459
+
460
+ params
461
+ end
462
+
463
+ end
464
+ end
465
+ end
466
+ end