cloud-mu 3.1.5 → 3.3.2

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +5 -1
  3. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  4. data/ansible/roles/mu-windows/files/config.xml +76 -0
  5. data/ansible/roles/mu-windows/tasks/main.yml +16 -0
  6. data/bin/mu-adopt +16 -12
  7. data/bin/mu-azure-tests +57 -0
  8. data/bin/mu-cleanup +2 -4
  9. data/bin/mu-configure +52 -0
  10. data/bin/mu-deploy +3 -3
  11. data/bin/mu-findstray-tests +25 -0
  12. data/bin/mu-gen-docs +2 -4
  13. data/bin/mu-load-config.rb +2 -1
  14. data/bin/mu-node-manage +15 -16
  15. data/bin/mu-run-tests +37 -12
  16. data/cloud-mu.gemspec +3 -3
  17. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  18. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  19. data/cookbooks/mu-tools/libraries/helper.rb +1 -1
  20. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  21. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  22. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  23. data/cookbooks/mu-tools/recipes/windows-client.rb +25 -22
  24. data/extras/clean-stock-amis +25 -19
  25. data/extras/generate-stock-images +1 -0
  26. data/extras/image-generators/AWS/win2k12.yaml +2 -0
  27. data/extras/image-generators/AWS/win2k16.yaml +2 -0
  28. data/extras/image-generators/AWS/win2k19.yaml +2 -0
  29. data/modules/mommacat.ru +1 -1
  30. data/modules/mu.rb +86 -98
  31. data/modules/mu/adoption.rb +373 -58
  32. data/modules/mu/cleanup.rb +214 -303
  33. data/modules/mu/cloud.rb +128 -1733
  34. data/modules/mu/cloud/database.rb +49 -0
  35. data/modules/mu/cloud/dnszone.rb +44 -0
  36. data/modules/mu/cloud/machine_images.rb +212 -0
  37. data/modules/mu/cloud/providers.rb +81 -0
  38. data/modules/mu/cloud/resource_base.rb +929 -0
  39. data/modules/mu/cloud/server.rb +40 -0
  40. data/modules/mu/cloud/server_pool.rb +1 -0
  41. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  42. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  43. data/modules/mu/cloud/wrappers.rb +169 -0
  44. data/modules/mu/config.rb +123 -81
  45. data/modules/mu/config/alarm.rb +2 -6
  46. data/modules/mu/config/bucket.rb +32 -3
  47. data/modules/mu/config/cache_cluster.rb +2 -2
  48. data/modules/mu/config/cdn.rb +100 -0
  49. data/modules/mu/config/collection.rb +1 -1
  50. data/modules/mu/config/container_cluster.rb +7 -2
  51. data/modules/mu/config/database.rb +84 -105
  52. data/modules/mu/config/database.yml +1 -2
  53. data/modules/mu/config/dnszone.rb +5 -4
  54. data/modules/mu/config/doc_helpers.rb +5 -6
  55. data/modules/mu/config/endpoint.rb +2 -1
  56. data/modules/mu/config/firewall_rule.rb +3 -19
  57. data/modules/mu/config/folder.rb +1 -1
  58. data/modules/mu/config/function.rb +17 -8
  59. data/modules/mu/config/group.rb +1 -1
  60. data/modules/mu/config/habitat.rb +1 -1
  61. data/modules/mu/config/job.rb +89 -0
  62. data/modules/mu/config/loadbalancer.rb +57 -11
  63. data/modules/mu/config/log.rb +1 -1
  64. data/modules/mu/config/msg_queue.rb +1 -1
  65. data/modules/mu/config/nosqldb.rb +1 -1
  66. data/modules/mu/config/notifier.rb +8 -19
  67. data/modules/mu/config/ref.rb +92 -14
  68. data/modules/mu/config/role.rb +1 -1
  69. data/modules/mu/config/schema_helpers.rb +38 -37
  70. data/modules/mu/config/search_domain.rb +1 -1
  71. data/modules/mu/config/server.rb +12 -13
  72. data/modules/mu/config/server_pool.rb +3 -7
  73. data/modules/mu/config/storage_pool.rb +1 -1
  74. data/modules/mu/config/tail.rb +11 -0
  75. data/modules/mu/config/user.rb +1 -1
  76. data/modules/mu/config/vpc.rb +27 -23
  77. data/modules/mu/config/vpc.yml +0 -1
  78. data/modules/mu/defaults/AWS.yaml +90 -90
  79. data/modules/mu/defaults/Azure.yaml +1 -0
  80. data/modules/mu/defaults/Google.yaml +1 -0
  81. data/modules/mu/deploy.rb +34 -20
  82. data/modules/mu/groomer.rb +16 -1
  83. data/modules/mu/groomers/ansible.rb +69 -4
  84. data/modules/mu/groomers/chef.rb +51 -4
  85. data/modules/mu/logger.rb +120 -144
  86. data/modules/mu/master.rb +97 -4
  87. data/modules/mu/mommacat.rb +160 -874
  88. data/modules/mu/mommacat/daemon.rb +23 -14
  89. data/modules/mu/mommacat/naming.rb +110 -3
  90. data/modules/mu/mommacat/search.rb +497 -0
  91. data/modules/mu/mommacat/storage.rb +252 -194
  92. data/modules/mu/{clouds → providers}/README.md +1 -1
  93. data/modules/mu/{clouds → providers}/aws.rb +258 -57
  94. data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
  95. data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
  96. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
  97. data/modules/mu/providers/aws/cdn.rb +782 -0
  98. data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
  99. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +95 -84
  100. data/modules/mu/providers/aws/database.rb +1744 -0
  101. data/modules/mu/{clouds → providers}/aws/dnszone.rb +26 -12
  102. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  103. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +39 -32
  104. data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
  105. data/modules/mu/{clouds → providers}/aws/function.rb +289 -134
  106. data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
  107. data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
  108. data/modules/mu/providers/aws/job.rb +466 -0
  109. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +77 -47
  110. data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
  111. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
  112. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
  113. data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
  114. data/modules/mu/{clouds → providers}/aws/role.rb +76 -48
  115. data/modules/mu/{clouds → providers}/aws/search_domain.rb +172 -41
  116. data/modules/mu/{clouds → providers}/aws/server.rb +66 -98
  117. data/modules/mu/{clouds → providers}/aws/server_pool.rb +42 -60
  118. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
  119. data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
  120. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  121. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  122. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
  123. data/modules/mu/{clouds → providers}/aws/vpc.rb +143 -74
  124. data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
  125. data/modules/mu/{clouds → providers}/azure.rb +13 -0
  126. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
  127. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
  128. data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
  129. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
  130. data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
  131. data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
  132. data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
  133. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  134. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  135. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  136. data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
  137. data/modules/mu/{clouds → providers}/cloudformation.rb +10 -0
  138. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  139. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  140. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  141. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  142. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  143. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  144. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  145. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  146. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  147. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  148. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
  149. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  150. data/modules/mu/{clouds → providers}/google.rb +29 -6
  151. data/modules/mu/{clouds → providers}/google/bucket.rb +4 -4
  152. data/modules/mu/{clouds → providers}/google/container_cluster.rb +38 -20
  153. data/modules/mu/{clouds → providers}/google/database.rb +5 -12
  154. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +5 -5
  155. data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
  156. data/modules/mu/{clouds → providers}/google/function.rb +6 -6
  157. data/modules/mu/{clouds → providers}/google/group.rb +9 -17
  158. data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
  159. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +5 -5
  160. data/modules/mu/{clouds → providers}/google/role.rb +50 -31
  161. data/modules/mu/{clouds → providers}/google/server.rb +41 -24
  162. data/modules/mu/{clouds → providers}/google/server_pool.rb +14 -14
  163. data/modules/mu/{clouds → providers}/google/user.rb +34 -24
  164. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  165. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  166. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  167. data/modules/mu/{clouds → providers}/google/vpc.rb +45 -14
  168. data/modules/tests/aws-jobs-functions.yaml +46 -0
  169. data/modules/tests/centos6.yaml +15 -0
  170. data/modules/tests/centos7.yaml +15 -0
  171. data/modules/tests/centos8.yaml +12 -0
  172. data/modules/tests/ecs.yaml +2 -2
  173. data/modules/tests/eks.yaml +1 -1
  174. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  175. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  176. data/modules/tests/microservice_app.yaml +288 -0
  177. data/modules/tests/rds.yaml +108 -0
  178. data/modules/tests/regrooms/rds.yaml +123 -0
  179. data/modules/tests/server-with-scrub-muisms.yaml +1 -1
  180. data/modules/tests/super_complex_bok.yml +2 -2
  181. data/modules/tests/super_simple_bok.yml +3 -5
  182. data/spec/mu/clouds/azure_spec.rb +2 -2
  183. metadata +122 -92
  184. data/modules/mu/clouds/aws/database.rb +0 -1974
  185. data/modules/mu/clouds/aws/endpoint.rb +0 -596
@@ -1,596 +0,0 @@
1
- module MU
2
- class Cloud
3
- class AWS
4
- # An API as configured in {MU::Config::BasketofKittens::endpoints}
5
- class Endpoint < MU::Cloud::Endpoint
6
-
7
- # 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.
8
- # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
9
- def initialize(**args)
10
- super
11
- @mu_name ||= @deploy.getResourceName(@config["name"])
12
- end
13
-
14
- # Called automatically by {MU::Deploy#createResources}
15
- def create
16
- resp = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).create_rest_api(
17
- name: @mu_name,
18
- description: @deploy.deploy_id,
19
- endpoint_configuration: {
20
- types: ["REGIONAL"] # XXX expose in BoK ["REGIONAL", "EDGE", "PRIVATE"]
21
- }
22
- )
23
- @cloud_id = resp.id
24
- generate_methods
25
-
26
-
27
- end
28
-
29
- # Create/update all of the methods declared for this endpoint
30
- def generate_methods
31
- resp = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).get_resources(
32
- rest_api_id: @cloud_id,
33
- )
34
- root_resource = resp.items.first.id
35
-
36
- # TODO guard this crap so we don't touch it if there are no changes
37
- @config['methods'].each { |m|
38
- m["auth"] ||= m["iam_role"] ? "AWS_IAM" : "NONE"
39
-
40
- method_arn = "arn:#{MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws"}:execute-api:#{@config["region"]}:#{MU::Cloud::AWS.credToAcct(@config['credentials'])}:#{@cloud_id}/*/#{m['type']}/#{m['path']}"
41
-
42
- resp = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).get_resources(
43
- rest_api_id: @cloud_id
44
- )
45
- ext_resource = nil
46
- resp.items.each { |resource|
47
- if resource.path_part == m['path']
48
- ext_resource = resource.id
49
- end
50
- }
51
-
52
- resp = if ext_resource
53
- MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).get_resource(
54
- rest_api_id: @cloud_id,
55
- resource_id: ext_resource,
56
- )
57
- # MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).update_resource(
58
- # rest_api_id: @cloud_id,
59
- # resource_id: ext_resource,
60
- # patch_operations: [
61
- # {
62
- # op: "replace",
63
- # path: "XXX ??",
64
- # value: m["path"]
65
- # }
66
- # ]
67
- # )
68
- else
69
- MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).create_resource(
70
- rest_api_id: @cloud_id,
71
- parent_id: root_resource,
72
- path_part: m['path']
73
- )
74
- end
75
- parent_id = resp.id
76
-
77
- resp = begin
78
- MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).get_method(
79
- rest_api_id: @cloud_id,
80
- resource_id: parent_id,
81
- http_method: m['type']
82
- )
83
- rescue Aws::APIGateway::Errors::NotFoundException
84
- resp = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).put_method(
85
- rest_api_id: @cloud_id,
86
- resource_id: parent_id,
87
- authorization_type: m['auth'],
88
- http_method: m['type']
89
- )
90
- end
91
-
92
- # XXX effectively a placeholder default
93
- begin
94
- m['responses'].each { |r|
95
- params = {
96
- :rest_api_id => @cloud_id,
97
- :resource_id => parent_id,
98
- :http_method => m['type'],
99
- :status_code => r['code'].to_s
100
- }
101
- if r['headers']
102
- params[:response_parameters] = r['headers'].map { |h|
103
- ["method.response.header."+h['header'], h['required']]
104
- }.to_h
105
- end
106
-
107
- if r['body']
108
- # XXX I'm guessing we can also have arbirary user-defined models somehow, so is_error is probably inadequate to the demand of the times
109
- params[:response_models] = r['body'].map { |b| [b['content_type'], b['is_error'] ? "Error" : "Empty"] }.to_h
110
- end
111
-
112
- MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).put_method_response(params)
113
- }
114
- rescue Aws::APIGateway::Errors::ConflictException
115
- # fine to ignore
116
- end
117
-
118
- if m['integrate_with']
119
- # role_arn = if m['iam_role']
120
- # if m['iam_role'].match(/^arn:/)
121
- # m['iam_role']
122
- # else
123
- # sib_role = @deploy.findLitterMate(name: m['iam_role'], type: "roles")
124
- # sib_role.cloudobj.arn
125
- # XXX make this more like get_role_arn in Function, or just use Role.find?
126
- # end
127
- # end
128
-
129
- function_obj = nil
130
-
131
- uri, type = if m['integrate_with']['type'] == "aws_generic"
132
- svc, action = m['integrate_with']['aws_generic_action'].split(/:/)
133
- ["arn:aws:apigateway:"+@config['region']+":#{svc}:action/#{action}", "AWS"]
134
- elsif m['integrate_with']['type'] == "function"
135
- function_obj = @deploy.findLitterMate(name: m['integrate_with']['name'], type: "functions").cloudobj
136
- ["arn:aws:apigateway:"+@config['region']+":lambda:path/2015-03-31/functions/"+function_obj.arn+"/invocations", "AWS"]
137
- elsif m['integrate_with']['type'] == "mock"
138
- [nil, "MOCK"]
139
- end
140
-
141
- params = {
142
- :rest_api_id => @cloud_id,
143
- :resource_id => parent_id,
144
- :type => type, # XXX Lambda and Firehose can do AWS_PROXY
145
- :content_handling => "CONVERT_TO_TEXT", # XXX expose in BoK
146
- :http_method => m['type']
147
- # credentials: role_arn
148
- }
149
- params[:uri] = uri if uri
150
-
151
- if m['integrate_with']['type'] != "mock"
152
- params[:integration_http_method] = m['integrate_with']['backend_http_method']
153
- else
154
- params[:integration_http_method] = nil
155
- end
156
-
157
- if m['integrate_with']['passthrough_behavior']
158
- params[:passthrough_behavior] = m['integrate_with']['passthrough_behavior']
159
- end
160
- if m['integrate_with']['request_templates']
161
- params[:request_templates] = {}
162
- m['integrate_with']['request_templates'].each { |rt|
163
- params[:request_templates][rt['content_type']] = rt['template']
164
- }
165
- end
166
-
167
- resp = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).put_integration(params)
168
-
169
- if m['integrate_with']['type'] == "function"
170
- function_obj.addTrigger(method_arn, "apigateway", @config['name'])
171
- end
172
-
173
- m['responses'].each { |r|
174
- params = {
175
- :rest_api_id => @cloud_id,
176
- :resource_id => parent_id,
177
- :http_method => m['type'],
178
- :status_code => r['code'].to_s,
179
- :selection_pattern => ""
180
- }
181
- if r['headers']
182
- params[:response_parameters] = r['headers'].map { |h|
183
- ["method.response.header."+h['header'], "'"+h['value']+"'"]
184
- }.to_h
185
- end
186
-
187
- MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).put_integration_response(params)
188
-
189
- }
190
-
191
- end
192
-
193
- }
194
- end
195
-
196
- # Called automatically by {MU::Deploy#createResources}
197
- def groom
198
- generate_methods
199
-
200
- MU.log "Deploying API Gateway #{@config['name']} to #{@config['deploy_to']}"
201
- MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).create_deployment(
202
- rest_api_id: @cloud_id,
203
- stage_name: @config['deploy_to']
204
- # cache_cluster_enabled: false,
205
- # cache_cluster_size: 0.5,
206
- )
207
- # this automatically creates a stage with the same name, so we don't
208
- # have to deal with that
209
-
210
- my_url = "https://"+@cloud_id+".execute-api."+@config['region']+".amazonaws.com/"+@config['deploy_to']
211
- MU.log "API Endpoint #{@config['name']}: "+my_url, MU::SUMMARY
212
-
213
- # resp = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).create_authorizer(
214
- # rest_api_id: @cloud_id,
215
- # )
216
-
217
- # resp = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).create_vpc_link(
218
- # )
219
-
220
- end
221
-
222
- @cloud_desc_cache = nil
223
- # @return [Struct]
224
- def cloud_desc(use_cache: true)
225
- return @cloud_desc_cache if @cloud_desc_cache and use_cache
226
- @cloud_desc_cache = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).get_rest_api(
227
- rest_api_id: @cloud_id
228
- )
229
- @cloud_desc_cache
230
- end
231
-
232
- # Return the metadata for this API
233
- # @return [Hash]
234
- def notify
235
- deploy_struct = MU.structToHash(cloud_desc)
236
- # XXX stages and whatnot
237
- return deploy_struct
238
- end
239
-
240
- # Remove all APIs associated with the currently loaded deployment.
241
- # @param noop [Boolean]: If true, will only print what would be done
242
- # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
243
- # @param region [String]: The cloud provider region
244
- # @return [void]
245
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
246
- MU.log "AWS::Endpoint.cleanup: need to support flags['known']", MU::DEBUG, details: flags
247
- MU.log "Placeholder: AWS Endpoint artifacts do not support tags, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: ignoremaster
248
-
249
- resp = MU::Cloud::AWS.apig(region: region, credentials: credentials).get_rest_apis
250
- if resp and resp.items
251
- resp.items.each { |api|
252
- # The stupid things don't have tags
253
- if api.description == MU.deploy_id
254
- MU.log "Deleting API Gateway #{api.name} (#{api.id})"
255
- if !noop
256
- MU::Cloud::AWS.apig(region: region, credentials: credentials).delete_rest_api(
257
- rest_api_id: api.id
258
- )
259
- end
260
- end
261
- }
262
- end
263
- end
264
-
265
- # Locate an existing API.
266
- # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching APIs.
267
- def self.find(**args)
268
- found = {}
269
-
270
- if args[:cloud_id]
271
- found[args[:cloud_id]] = MU::Cloud::AWS.apig(region: args[:region], credentials: args[:credentials]).get_rest_api(
272
- rest_api_id: args[:cloud_id]
273
- )
274
- else
275
- resp = MU::Cloud::AWS.apig(region: args[:region], credentials: args[:credentials]).get_rest_apis
276
- if resp and resp.items
277
- resp.items.each { |api|
278
- found[api.id] = api
279
- }
280
- end
281
- end
282
-
283
- found
284
- end
285
-
286
- # Cloud-specific configuration properties.
287
- # @param _config [MU::Config]: The calling MU::Config object
288
- # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
289
- def self.schema(_config)
290
- toplevel_required = []
291
- schema = {
292
- "deploy_to" => {
293
- "type" => "string",
294
- "description" => "The name of an environment under which to deploy our API. If not specified, will deploy to the name of the global Mu environment for this deployment."
295
- },
296
- "methods" => {
297
- "items" => {
298
- "type" => "object",
299
- "description" => "Other cloud resources to integrate as a back end to this API Gateway",
300
- "required" => ["integrate_with"],
301
- "properties" => {
302
- "integrate_with" => {
303
- "type" => "object",
304
- "description" => "Specify what application backend to invoke under this path/method combination",
305
- "properties" => {
306
- "proxy" => {
307
- "type" => "boolean",
308
- "default" => false,
309
- "description" => "For HTTP or AWS integrations, specify whether the target is a proxy (((docs unclear, is that actually what this means?)))" # XXX is that actually what this means?
310
- },
311
- "backend_http_method" => {
312
- "type" => "string",
313
- "description" => "The HTTP method to use when contacting our integrated backend. If not specified, this will be set to match our front end.",
314
- "enum" => ["GET", "POST", "PUT", "HEAD", "DELETE", "CONNECT", "OPTIONS", "TRACE"],
315
- },
316
- "url" => {
317
- "type" => "string",
318
- "description" => "For HTTP or HTTP_PROXY integrations, this should be a fully-qualified URL"
319
- },
320
- "responses"=> {
321
- "type" => "array",
322
- "items" => {
323
- "type" => "object",
324
- "description" => "Customize the response to the client for this method, by adding headers or transforming through a template. If not specified, we will default to returning an un-transformed HTTP 200 for this method.",
325
- "properties" => {
326
- "code" => {
327
- "type" => "integer",
328
- "description" => "The HTTP status code to return",
329
- "default" => 200
330
- },
331
- "headers" => {
332
- "type" => "array",
333
- "items" => {
334
- "description" => "One or more headers, used by the API Gateway integration response and filtered through the method response before returning to the client",
335
- "type" => "object",
336
- "properties" => {
337
- "header" => {
338
- "type" => "string",
339
- "description" => "The name of a header to return, such as +Access-Control-Allow-Methods+"
340
- },
341
- "value" => {
342
- "type" => "string",
343
- "description" => "The string to map to this header (ex +GET,OPTIONS+)"
344
- },
345
- "required" => {
346
- "type" => "boolean",
347
- "description" => "Indicate whether this header is required in order to return a response",
348
- "default" => true
349
- }
350
- }
351
- }
352
- },
353
- "body" => {
354
- "type" => "array",
355
- "items" => {
356
- "type" => "object",
357
- "description" => "Model for the body of our backend integration's response",
358
- "properties" => {
359
- "content_type" => {
360
- "type" => "string",
361
- "description" => "An HTTP content type to match to a response, such as +application/json+."
362
- },
363
- "is_error" => {
364
- "type" => "boolean",
365
- "description" => "Whether this response should be considered an error",
366
- "default" => false
367
- }
368
- }
369
- }
370
- }
371
- }
372
- }
373
- },
374
- "arn" => {
375
- "type" => "string",
376
- "description" => "For AWS or AWS_PROXY integrations with a compatible Amazon resource outside of Mu, a full-qualified ARN such as `arn:aws:apigateway:us-west-2:s3:action/GetObject&Bucket=`bucket&Key=key`"
377
- },
378
- "name" => {
379
- "type" => "string",
380
- "description" => "A Mu resource name, for integrations with a sibling resource (e.g. a Function)"
381
- },
382
- "cors" => {
383
- "type" => "boolean",
384
- "description" => "When enabled, this will create an +OPTIONS+ method under this path with request and response header mappings that implement Cross-Origin Resource Sharing",
385
- "default" => true
386
- },
387
- "type" => {
388
- "type" => "string",
389
- "description" => "A Mu resource type, for integrations with a sibling resource (e.g. a function), or the string +aws_generic+, which we can use in combination with +aws_generic_action+ to integrate with arbitrary AWS services.",
390
- "enum" => ["aws_generic"].concat(MU::Cloud.resource_types.values.map { |t| t[:cfg_name] }.sort)
391
- },
392
- "aws_generic_action" => {
393
- "type" => "string",
394
- "description" => "For use when +type+ is set to +aws_generic+, this should specify the action to be performed in the style of an IAM policy action, e.g. +acm:ListCertificates+ for this integration to return a list of Certificate Manager SSL certificates."
395
- },
396
- "deploy_id" => {
397
- "type" => "string",
398
- "description" => "A Mu deploy id (e.g. DEMO-DEV-2014111400-NG), for integrations with a sibling resource (e.g. a Function)"
399
- },
400
- "iam_role" => {
401
- "type" => "string",
402
- "description" => "The name of an IAM role used to grant usage of other AWS artifacts for this integration. If not specified, we will automatically generate an appropriate role."
403
- },
404
- "passthrough_behavior" => {
405
- "type" => "string",
406
- "description" => "Specifies the pass-through behavior for incoming requests based on the +Content-Type+ header in the request, and the available mapping templates specified in +request_templates+. +WHEN_NO_MATCH+ passes the request body for unmapped content types through to the integration back end without transformation. +WHEN_NO_TEMPLATES+ allows pass-through when the integration has NO content types mapped to templates. +NEVER+ rejects unmapped content types with an HTTP +415+.",
407
- "enum" => ["WHEN_NO_MATCH", "WHEN_NO_TEMPLATES", "NEVER"],
408
- "default" => "WHEN_NO_MATCH"
409
- },
410
- "request_templates" => {
411
- "type" => "array",
412
- "description" => "A JSON-encoded string which represents a map of Velocity templates that are applied on the request payload based on the value of the +Content-Type+ header sent by the client. The content type value is the key in this map, and the template (as a String) is the value.",
413
- "items" => {
414
- "type" => "object",
415
- "description" => "A JSON-encoded string which represents a map of Velocity templates that are applied on the request payload based on the value of the +Content-Type+ header sent by the client. The content type value is the key in this map, and the template (as a String) is the value.",
416
- "require" => ["content_type", "template"],
417
- "properties" => {
418
- "content_type" => {
419
- "type" => "string",
420
- "description" => "An HTTP content type to match with a template, such as +application/json+."
421
- },
422
- "template" => {
423
- "type" => "string",
424
- "description" => "A Velocity template to apply to our reques payload, encoded as a one-line string, like: "+'<tt>"#set($allParams = $input.params())\\n{\\n\\"url_data_json_encoded\\":\\"$input.params(\'url\')\\"\\n}"</tt>'
425
- }
426
- }
427
- }
428
- }
429
- }
430
- },
431
- "auth" => {
432
- "type" => "string",
433
- "enum" => ["NONE", "CUSTOM", "AWS_IAM", "COGNITO_USER_POOLS"],
434
- "default" => "NONE"
435
- }
436
- }
437
- }
438
- }
439
- }
440
- [toplevel_required, schema]
441
- end
442
-
443
- # Does this resource type exist as a global (cloud-wide) artifact, or
444
- # is it localized to a region/zone?
445
- # @return [Boolean]
446
- def self.isGlobal?
447
- false
448
- end
449
-
450
- # Denote whether this resource implementation is experiment, ready for
451
- # testing, or ready for production use.
452
- def self.quality
453
- MU::Cloud::BETA
454
- end
455
-
456
- # Canonical Amazon Resource Number for this resource
457
- # @return [String]
458
- def arn
459
- "arn:#{MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws"}:execute-api:#{@config["region"]}:#{MU::Cloud::AWS.credToAcct(@config['credentials'])}:#{@cloud_id}"
460
- end
461
-
462
-
463
- # Cloud-specific pre-processing of {MU::Config::BasketofKittens::endpoints}, bare and unvalidated.
464
- # @param endpoint [Hash]: The resource to process and validate
465
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
466
- # @return [Boolean]: True if validation succeeded, False otherwise
467
- def self.validateConfig(endpoint, configurator)
468
- ok = true
469
-
470
- append = []
471
- endpoint['deploy_to'] ||= MU.environment || $environment || "dev"
472
- endpoint['methods'].each { |m|
473
- if m['integrate_with'] and m['integrate_with']['name']
474
- if m['integrate_with']['type'] != "aws_generic"
475
- endpoint['dependencies'] ||= []
476
- endpoint['dependencies'] << {
477
- "type" => m['integrate_with']['type'],
478
- "name" => m['integrate_with']['name']
479
- }
480
- end
481
-
482
- m['integrate_with']['backend_http_method'] ||= m['type']
483
-
484
- m['responses'] ||= [
485
- "code" => 200
486
- ]
487
-
488
- if m['cors']
489
- m['responses'].each { |r|
490
- r['headers'] ||= []
491
- r['headers'] << {
492
- "header" => "Access-Control-Allow-Origin",
493
- "value" => "*",
494
- "required" => true
495
- }
496
- r['headers'].uniq!
497
- }
498
-
499
- append << cors_option_integrations(m['path'])
500
- end
501
-
502
- if !m['iam_role']
503
- m['uri'] ||= "*" if m['integrate_with']['type'] == "aws_generic"
504
-
505
- roledesc = {
506
- "name" => endpoint['name']+"-"+m['integrate_with']['name'],
507
- "credentials" => endpoint['credentials'],
508
- "can_assume" => [
509
- {
510
- "entity_id" => "apigateway.amazonaws.com",
511
- "entity_type" => "service"
512
- }
513
- ],
514
- }
515
- if m['integrate_with']['type'] == "aws_generic"
516
- roledesc["policies"] = [
517
- {
518
- "name" => m['integrate_with']['aws_generic_action'].gsub(/[^a-z]/i, ""),
519
- "permissions" => [m['integrate_with']['aws_generic_action']],
520
- "targets" => [{ "identifier" => m['uri'] }]
521
- }
522
- ]
523
- elsif m['integrate_with']['type'] == "function"
524
- roledesc["import"] = ["AWSLambdaBasicExecutionRole"]
525
- end
526
- configurator.insertKitten(roledesc, "roles")
527
-
528
- endpoint['dependencies'] ||= []
529
- m['iam_role'] = endpoint['name']+"-"+m['integrate_with']['name']
530
-
531
- endpoint['dependencies'] << {
532
- "type" => "role",
533
- "name" => endpoint['name']+"-"+m['integrate_with']['name']
534
- }
535
- end
536
- end
537
- }
538
- endpoint['methods'].concat(append.uniq) if endpoint['methods']
539
- # if something_bad
540
- # ok = false
541
- # end
542
-
543
- ok
544
- end
545
-
546
- def self.cors_option_integrations(path)
547
- {
548
- "type" => "OPTIONS",
549
- "path" => path,
550
- "auth" => "NONE",
551
- "responses" => [
552
- {
553
- "code" => 200,
554
- "headers" => [
555
- {
556
- "header" => "Access-Control-Allow-Headers",
557
- "value" => "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token",
558
- "required" => true
559
- },
560
- {
561
- "header" => "Access-Control-Allow-Methods",
562
- "value" => "GET,OPTIONS",
563
- "required" => true
564
- },
565
- {
566
- "header" => "Access-Control-Allow-Origin",
567
- "value" => "*",
568
- "required" => true
569
- }
570
- ],
571
- "body" => [
572
- {
573
- "content_type" => "application/json"
574
- }
575
- ]
576
- }
577
- ],
578
- "integrate_with" => {
579
- "type" => "mock",
580
- "passthrough_behavior" => "WHEN_NO_MATCH",
581
- "backend_http_method" => "OPTIONS",
582
- "request_templates" => [
583
- {
584
- "content_type" => "application/json",
585
- "template" => '{"statusCode": 200}'
586
- }
587
- ]
588
- }
589
- }
590
- end
591
- private_class_method :cors_option_integrations
592
-
593
- end
594
- end
595
- end
596
- end