cloud-mu 3.1.3 → 3.3.0

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