cloud-mu 3.1.3 → 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 (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