cloud-mu 3.1.2 → 3.2.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 (201) 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 +10 -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 +2 -3
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +135 -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 +165 -111
  45. data/modules/mu/adoption.rb +401 -68
  46. data/modules/mu/cleanup.rb +199 -306
  47. data/modules/mu/cloud.rb +100 -1632
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +46 -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 +920 -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 +165 -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 +4 -4
  61. data/modules/mu/config/cache_cluster.rb +1 -1
  62. data/modules/mu/config/collection.rb +4 -4
  63. data/modules/mu/config/container_cluster.rb +9 -4
  64. data/modules/mu/config/database.rb +83 -104
  65. data/modules/mu/config/database.yml +1 -2
  66. data/modules/mu/config/dnszone.rb +6 -6
  67. data/modules/mu/config/doc_helpers.rb +516 -0
  68. data/modules/mu/config/endpoint.rb +4 -4
  69. data/modules/mu/config/firewall_rule.rb +103 -4
  70. data/modules/mu/config/folder.rb +4 -4
  71. data/modules/mu/config/function.rb +3 -3
  72. data/modules/mu/config/group.rb +4 -4
  73. data/modules/mu/config/habitat.rb +4 -4
  74. data/modules/mu/config/loadbalancer.rb +60 -14
  75. data/modules/mu/config/log.rb +4 -4
  76. data/modules/mu/config/msg_queue.rb +4 -4
  77. data/modules/mu/config/nosqldb.rb +4 -4
  78. data/modules/mu/config/notifier.rb +3 -3
  79. data/modules/mu/config/ref.rb +365 -0
  80. data/modules/mu/config/role.rb +4 -4
  81. data/modules/mu/config/schema_helpers.rb +509 -0
  82. data/modules/mu/config/search_domain.rb +4 -4
  83. data/modules/mu/config/server.rb +97 -70
  84. data/modules/mu/config/server.yml +1 -0
  85. data/modules/mu/config/server_pool.rb +5 -9
  86. data/modules/mu/config/storage_pool.rb +1 -1
  87. data/modules/mu/config/tail.rb +200 -0
  88. data/modules/mu/config/user.rb +4 -4
  89. data/modules/mu/config/vpc.rb +70 -27
  90. data/modules/mu/config/vpc.yml +0 -1
  91. data/modules/mu/defaults/AWS.yaml +83 -60
  92. data/modules/mu/defaults/Azure.yaml +1 -0
  93. data/modules/mu/defaults/Google.yaml +3 -2
  94. data/modules/mu/deploy.rb +30 -26
  95. data/modules/mu/groomer.rb +17 -2
  96. data/modules/mu/groomers/ansible.rb +188 -41
  97. data/modules/mu/groomers/chef.rb +116 -55
  98. data/modules/mu/logger.rb +127 -148
  99. data/modules/mu/master.rb +389 -2
  100. data/modules/mu/master/chef.rb +3 -4
  101. data/modules/mu/master/ldap.rb +3 -3
  102. data/modules/mu/master/ssl.rb +12 -3
  103. data/modules/mu/mommacat.rb +217 -2612
  104. data/modules/mu/mommacat/daemon.rb +397 -0
  105. data/modules/mu/mommacat/naming.rb +473 -0
  106. data/modules/mu/mommacat/search.rb +495 -0
  107. data/modules/mu/mommacat/storage.rb +722 -0
  108. data/modules/mu/{clouds → providers}/README.md +1 -1
  109. data/modules/mu/{clouds → providers}/aws.rb +271 -112
  110. data/modules/mu/{clouds → providers}/aws/alarm.rb +5 -3
  111. data/modules/mu/{clouds → providers}/aws/bucket.rb +26 -22
  112. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +33 -67
  113. data/modules/mu/{clouds → providers}/aws/collection.rb +24 -23
  114. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +681 -721
  115. data/modules/mu/providers/aws/database.rb +1744 -0
  116. data/modules/mu/{clouds → providers}/aws/dnszone.rb +64 -63
  117. data/modules/mu/{clouds → providers}/aws/endpoint.rb +22 -27
  118. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +214 -244
  119. data/modules/mu/{clouds → providers}/aws/folder.rb +7 -7
  120. data/modules/mu/{clouds → providers}/aws/function.rb +17 -22
  121. data/modules/mu/{clouds → providers}/aws/group.rb +23 -23
  122. data/modules/mu/{clouds → providers}/aws/habitat.rb +17 -14
  123. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +57 -48
  124. data/modules/mu/{clouds → providers}/aws/log.rb +15 -12
  125. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +17 -16
  126. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +18 -11
  127. data/modules/mu/{clouds → providers}/aws/notifier.rb +11 -6
  128. data/modules/mu/{clouds → providers}/aws/role.rb +112 -86
  129. data/modules/mu/{clouds → providers}/aws/search_domain.rb +39 -33
  130. data/modules/mu/{clouds → providers}/aws/server.rb +835 -1133
  131. data/modules/mu/{clouds → providers}/aws/server_pool.rb +56 -60
  132. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +24 -42
  133. data/modules/mu/{clouds → providers}/aws/user.rb +21 -22
  134. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  135. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
  136. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  137. data/modules/mu/{clouds → providers}/aws/vpc.rb +523 -929
  138. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  139. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  140. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  141. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  142. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  143. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  144. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  145. data/modules/mu/{clouds → providers}/azure/server.rb +95 -48
  146. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  147. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  148. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  149. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  150. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  151. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  152. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  153. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  154. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  155. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  156. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  160. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  161. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  162. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  163. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  164. data/modules/mu/{clouds → providers}/google.rb +67 -30
  165. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  166. data/modules/mu/{clouds → providers}/google/container_cluster.rb +84 -77
  167. data/modules/mu/{clouds → providers}/google/database.rb +10 -20
  168. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  169. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  170. data/modules/mu/{clouds → providers}/google/function.rb +139 -167
  171. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  172. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  173. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +18 -20
  174. data/modules/mu/{clouds → providers}/google/role.rb +92 -58
  175. data/modules/mu/{clouds → providers}/google/server.rb +242 -155
  176. data/modules/mu/{clouds → providers}/google/server_pool.rb +25 -44
  177. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  178. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  179. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  180. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  181. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  182. data/modules/tests/bucket.yml +4 -0
  183. data/modules/tests/centos6.yaml +11 -0
  184. data/modules/tests/centos7.yaml +11 -0
  185. data/modules/tests/centos8.yaml +12 -0
  186. data/modules/tests/ecs.yaml +23 -0
  187. data/modules/tests/includes-and-params.yaml +2 -1
  188. data/modules/tests/rds.yaml +108 -0
  189. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  190. data/modules/tests/regrooms/bucket.yml +19 -0
  191. data/modules/tests/regrooms/rds.yaml +123 -0
  192. data/modules/tests/server-with-scrub-muisms.yaml +1 -0
  193. data/modules/tests/super_simple_bok.yml +1 -3
  194. data/modules/tests/win2k12.yaml +17 -5
  195. data/modules/tests/win2k16.yaml +25 -0
  196. data/modules/tests/win2k19.yaml +25 -0
  197. data/requirements.txt +1 -0
  198. data/spec/mu/clouds/azure_spec.rb +2 -2
  199. metadata +232 -154
  200. data/extras/image-generators/AWS/windows.yaml +0 -18
  201. data/modules/mu/clouds/aws/database.rb +0 -1985
@@ -0,0 +1,286 @@
1
+ # Copyright:: Copyright (c) 2020 eGlobalTech, Inc., all rights reserved
2
+ #
3
+ # Licensed under the BSD-3 license (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License in the root of the project or at
6
+ #
7
+ # http://egt-labs.com/mu/LICENSE.html
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module MU
16
+ class Cloud
17
+ class AWS
18
+
19
+ # Creation of Virtual Private Clouds and associated artifacts (routes, subnets, etc).
20
+ class VPC < MU::Cloud::VPC
21
+
22
+ # Subnets are almost a first-class resource. So let's kinda sorta treat
23
+ # them like one. This should only be invoked on objects that already
24
+ # exists in the cloud layer.
25
+ class Subnet < MU::Cloud::AWS::VPC
26
+
27
+ attr_reader :cloud_id
28
+ attr_reader :ip_block
29
+ attr_reader :mu_name
30
+ attr_reader :name
31
+ attr_reader :az
32
+ attr_reader :cloud_desc
33
+
34
+ # @param parent [MU::Cloud::AWS::VPC]: The parent VPC of this subnet.
35
+ # @param config [Hash<String>]:
36
+ def initialize(parent, config)
37
+ @parent = parent
38
+ @config = MU::Config.manxify(config)
39
+ @cloud_id = config['cloud_id']
40
+ @mu_name = config['mu_name']
41
+ @name = config['name']
42
+ @deploydata = config # This is a dummy for the sake of describe()
43
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
44
+ @az = resp.availability_zone
45
+ @ip_block = resp.cidr_block
46
+ @cloud_desc = resp # XXX this really isn't the cloud implementation's business
47
+
48
+ end
49
+
50
+ # Return the cloud identifier for the default route of this subnet.
51
+ # @return [String,nil]
52
+ def defaultRoute
53
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
54
+ filters: [{name: "association.subnet-id", values: [@cloud_id]}]
55
+ )
56
+ if resp.route_tables.size == 0 # use default route table for the VPC
57
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
58
+ filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
59
+ )
60
+ end
61
+ resp.route_tables.each { |route_table|
62
+ route_table.routes.each { |route|
63
+ if route.destination_cidr_block =="0.0.0.0/0" and route.state != "blackhole"
64
+ return route.instance_id if !route.instance_id.nil?
65
+ return route.gateway_id if !route.gateway_id.nil?
66
+ return route.vpc_peering_connection_id if !route.vpc_peering_connection_id.nil?
67
+ return route.network_interface_id if !route.network_interface_id.nil?
68
+ end
69
+ }
70
+ }
71
+ return nil
72
+ end
73
+
74
+ # Is this subnet privately-routable only, or public?
75
+ # @return [Boolean]
76
+ def private?
77
+ return false if @cloud_id.nil?
78
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
79
+ filters: [{name: "association.subnet-id", values: [@cloud_id]}]
80
+ )
81
+ if resp.route_tables.size == 0 # use default route table for the VPC
82
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
83
+ filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
84
+ )
85
+ end
86
+ resp.route_tables.each { |route_table|
87
+ route_table.routes.each { |route|
88
+ return false if !route.gateway_id.nil? and route.gateway_id != "local" # you can have an IgW and route it to a subset of IPs instead of 0.0.0.0/0
89
+ if route.destination_cidr_block == "0.0.0.0/0"
90
+ return true if !route.instance_id.nil?
91
+ return true if route.nat_gateway_id
92
+ end
93
+ }
94
+ }
95
+ return true
96
+ end
97
+ end # VPC::Subnet class
98
+
99
+ private
100
+
101
+ def create_subnets
102
+ return [] if @config['subnets'].nil? or @config['subnets'].empty?
103
+ nat_gateways = []
104
+
105
+ @eip_allocation_ids ||= []
106
+
107
+ subnetthreads = Array.new
108
+
109
+ azs = MU::Cloud::AWS.listAZs(region: @config['region'], credentials: @config['credentials'])
110
+ @config['subnets'].each { |subnet|
111
+ subnet_name = @config['name']+"-"+subnet['name']
112
+ az = subnet['availability_zone'] ? subnet['availability_zone'] : azs.op
113
+ MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']}) in #{az}", details: subnet
114
+
115
+ subnetthreads << Thread.new {
116
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_subnet(
117
+ vpc_id: @cloud_id,
118
+ cidr_block: subnet['ip_block'],
119
+ availability_zone: az
120
+ ).subnet
121
+ subnet_id = subnet['subnet_id'] = resp.subnet_id
122
+
123
+ tag_me(subnet_id, @mu_name+"-"+subnet['name'])
124
+
125
+ loop_if = Proc.new {
126
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
127
+ (!resp or resp.state != "available")
128
+ }
129
+
130
+ MU.retrier([Aws::EC2::Errors::InvalidSubnetIDNotFound, NoMethodError], wait: 5, loop_if: loop_if) { |retries, _wait|
131
+ MU.log "Waiting for Subnet #{subnet_name} (#{subnet_id}) to become available", MU::NOTICE if retries > 0 and (retries % 3) == 0
132
+ }
133
+
134
+ if !subnet['route_table'].nil?
135
+ routes = {}
136
+ @config['route_tables'].each { |tbl|
137
+ routes[tbl['name']] = tbl
138
+ }
139
+ if routes[subnet['route_table']].nil?
140
+ raise "Subnet #{subnet_name} references nonexistent route #{subnet['route_table']}"
141
+ end
142
+ MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
143
+ MU.retrier([Aws::EC2::Errors::InvalidRouteTableIDNotFound], wait: 10, max: 10) {
144
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_route_table(
145
+ route_table_id: routes[subnet['route_table']]['route_table_id'],
146
+ subnet_id: subnet_id
147
+ )
148
+ }
149
+ end
150
+
151
+ if subnet.has_key?("map_public_ips")
152
+ MU.retrier([Aws::EC2::Errors::InvalidSubnetIDNotFound], wait: 10, max: 10) {
153
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_subnet_attribute(
154
+ subnet_id: subnet_id,
155
+ map_public_ip_on_launch: {
156
+ value: subnet['map_public_ips'],
157
+ }
158
+ )
159
+ }
160
+ end
161
+
162
+ if subnet['is_public'] and subnet['create_nat_gateway']
163
+ nat_gateways << create_nat_gateway(subnet)
164
+ end
165
+
166
+ if subnet["enable_traffic_logging"]
167
+ loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
168
+ logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
169
+ MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
170
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
171
+ resource_ids: [subnet_id],
172
+ resource_type: "Subnet",
173
+ traffic_type: subnet["traffic_type_to_log"],
174
+ log_group_name: loggroup.mu_name,
175
+ deliver_logs_permission_arn: logrole.cloudobj.arn
176
+ )
177
+ end
178
+ }
179
+ }
180
+
181
+ subnetthreads.each { |t|
182
+ t.join
183
+ }
184
+
185
+ nat_gateways
186
+ end
187
+
188
+ def allocate_eip_for_nat
189
+ MU::MommaCat.lock("nat-gateway-eipalloc")
190
+
191
+ eips = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_addresses(
192
+ filters: [
193
+ {
194
+ name: "domain",
195
+ values: ["vpc"]
196
+ }
197
+ ]
198
+ ).addresses
199
+
200
+ allocation_id = nil
201
+ eips.each { |eip|
202
+ next if !eip.association_id.nil? and !eip.association_id.empty?
203
+ if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
204
+ if !@eip_allocation_ids.include?(eip.allocation_id)
205
+ allocation_id = eip.allocation_id
206
+ break
207
+ end
208
+ end
209
+ }
210
+
211
+ if allocation_id.nil?
212
+ allocation_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).allocate_address(domain: "vpc").allocation_id
213
+ MU::MommaCat.lock(allocation_id, false, true)
214
+ end
215
+
216
+ @eip_allocation_ids << allocation_id
217
+
218
+ MU::MommaCat.unlock("nat-gateway-eipalloc")
219
+
220
+ allocation_id
221
+ end
222
+
223
+ def create_nat_gateway(subnet)
224
+ allocation_id = allocate_eip_for_nat
225
+
226
+ nat_gateway_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_nat_gateway(
227
+ subnet_id: subnet['subnet_id'],
228
+ allocation_id: allocation_id,
229
+ ).nat_gateway.nat_gateway_id
230
+
231
+ ensure_unlock = Proc.new { MU::MommaCat.unlock(allocation_id, true) }
232
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
233
+ loop_if = Proc.new {
234
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
235
+ resp.class != Aws::EC2::Types::NatGateway or resp.state == "pending"
236
+ }
237
+
238
+ MU.retrier([Aws::EmptyStructure, NoMethodError], wait: 5, max: 30, always: ensure_unlock, loop_if: loop_if) { |retries, _wait|
239
+ MU.log "Waiting for nat gateway #{nat_gateway_id} to become available (EIP allocation: #{allocation_id})" if retries % 5 == 0
240
+ }
241
+
242
+ raise MuError, "NAT Gateway failed #{nat_gateway_id}: #{resp}" if resp.state == "failed"
243
+
244
+ tag_me(nat_gateway_id)
245
+
246
+ {'id' => nat_gateway_id, 'availability_zone' => subnet['availability_zone']}
247
+ end
248
+
249
+ # Remove all subnets associated with the currently loaded deployment.
250
+ # @param noop [Boolean]: If true, will only print what would be done
251
+ # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
252
+ # @param region [String]: The cloud provider region
253
+ # @return [void]
254
+ def self.purge_subnets(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
255
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_subnets(
256
+ filters: tagfilters
257
+ )
258
+ subnets = resp.data.subnets
259
+
260
+ return if subnets.nil? or subnets.size == 0
261
+
262
+ subnets.each { |subnet|
263
+ on_retry = Proc.new {
264
+ MU::Cloud::AWS::VPC.purge_interfaces(noop, [{name: "subnet-id", values: [subnet.subnet_id]}], region: region, credentials: credentials)
265
+ }
266
+
267
+ MU.log "Deleting Subnet #{subnet.subnet_id}"
268
+ MU.retrier([Aws::EC2::Errors::DependencyViolation], ignoreme: [Aws::EC2::Errors::InvalidSubnetIDNotFound], max: 20, on_retry: on_retry) { |_retries, wait|
269
+ begin
270
+ if subnet.state != "available"
271
+ MU.log "Waiting for #{subnet.subnet_id} to be in a removable state...", MU::NOTICE
272
+ sleep wait
273
+ else
274
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_subnet(subnet_id: subnet.subnet_id) if !noop
275
+ end
276
+ end while subnet.state != "available"
277
+ }
278
+ }
279
+ end
280
+ private_class_method :purge_subnets
281
+
282
+ end # VPC class
283
+
284
+ end #class
285
+ end
286
+ end #module
@@ -47,6 +47,11 @@ module MU
47
47
  guid_chunks.join("-")
48
48
  end
49
49
 
50
+ # List all Azure subscriptions available to our credentials
51
+ def self.listHabitats(credentials = nil, use_cache: true)
52
+ []
53
+ end
54
+
50
55
  # A hook that is always called just before any of the instance method of
51
56
  # our resource implementations gets invoked, so that we can ensure that
52
57
  # repetitive setup tasks (like resolving +:resource_group+ for Azure
@@ -77,6 +82,11 @@ module MU
77
82
  [:resource_group]
78
83
  end
79
84
 
85
+ # Is this a "real" cloud provider, or a stub like CloudFormation?
86
+ def self.virtual?
87
+ false
88
+ end
89
+
80
90
  # Stub class to represent Azure's resource identifiers, which look like:
81
91
  # /subscriptions/3d20ddd8-4652-4074-adda-0d127ef1f0e0/resourceGroups/mu/providers/Microsoft.Network/virtualNetworks/mu-vnet
82
92
  # Various API calls need chunks of this in different contexts, and this
@@ -101,11 +111,11 @@ module MU
101
111
  def initialize(*args)
102
112
  if args.first.is_a?(String)
103
113
  @raw = args.first
104
- junk, junk, @subscription, junk, @resource_group, junk, @provider, @resource_type, @name = @raw.split(/\//)
114
+ _junk, _junk2, @subscription, _junk3, @resource_group, _junk4, @provider, @resource_type, @name = @raw.split(/\//)
105
115
  if @subscription.nil? or @resource_group.nil? or @provider.nil? or @resource_type.nil? or @name.nil?
106
116
  # Not everything has a resource group
107
117
  if @raw.match(/^\/subscriptions\/#{Regexp.quote(@subscription)}\/providers/)
108
- junk, junk, @subscription, junk, @provider, @resource_type, @name = @raw.split(/\//)
118
+ _junk, _junk2, @subscription, _junk3, @provider, @resource_type, @name = @raw.split(/\//)
109
119
  if @subscription.nil? or @provider.nil? or @resource_type.nil? or @name.nil?
110
120
  raise MuError, "Failed to parse Azure resource id string #{@raw} (got subscription: #{@subscription}, provider: #{@provider}, resource_type: #{@resource_type}, name: #{@name}"
111
121
  end
@@ -266,7 +276,7 @@ module MU
266
276
 
267
277
  begin
268
278
  sdk_response = MU::Cloud::Azure.subs(credentials: credentials).subscriptions().list_locations(subscription)
269
- rescue Exception => e
279
+ rescue StandardError => e
270
280
  MU.log e.inspect, MU::ERR, details: e.backtrace
271
281
  #pp "Error Getting the list of regions from Azure" #TODO: SWITCH THIS TO MU LOG
272
282
  if @@regions and @@regions.size > 0
@@ -274,6 +284,9 @@ module MU
274
284
  end
275
285
  raise e
276
286
  end
287
+ if !sdk_response
288
+ raise MuError, "Nil response from Azure API attempting list_locations(#{subscription})"
289
+ end
277
290
 
278
291
  sdk_response.value.each do | region |
279
292
  @@regions.push(region.name)
@@ -378,7 +391,7 @@ module MU
378
391
  rg_obj = MU::Cloud::Azure.resources(:ResourceGroup).new
379
392
  rg_obj.location = region
380
393
  rg_obj.tags = MU::MommaCat.listStandardTags
381
- rg_obj.tags.reject! { |k, v| v.nil? }
394
+ rg_obj.tags.reject! { |_k, v| v.nil? }
382
395
 
383
396
  MU::Cloud::Azure.resources(credentials: credentials).resource_groups.list.each { |rg|
384
397
  if rg.name == name and rg.location == region and rg.tags == rg_obj.tags
@@ -519,7 +532,7 @@ module MU
519
532
  end
520
533
  return @@metadata
521
534
 
522
- rescue Timeout::Error => e
535
+ rescue Timeout::Error
523
536
  # MU.log "Timeout querying Azure Metadata"
524
537
  return nil
525
538
  rescue
@@ -906,7 +919,6 @@ module MU
906
919
  # END SDK STUBS
907
920
 
908
921
  # BEGIN SDK CLIENT
909
- private
910
922
 
911
923
  @@authorization_api = {}
912
924
  @@subscriptions_api = {}
@@ -967,7 +979,7 @@ module MU
967
979
  begin
968
980
  modelpath = "::Azure::#{api}::Mgmt::#{profile}::#{@subclass}"
969
981
  @api = Object.const_get(modelpath).new(@cred_obj)
970
- rescue NameError => e
982
+ rescue NameError
971
983
  raise MuError, "Unable to locate a profile #{profile} of Azure API #{api}. I tried:\n#{stdpath}\n#{modelpath}"
972
984
  end
973
985
  end
@@ -1017,6 +1029,7 @@ module MU
1017
1029
  # @param arguments [Array]
1018
1030
  def method_missing(method_sym, *arguments)
1019
1031
  MU.log "Calling #{@parentname}.#{@myname}.#{method_sym.to_s}", MU::DEBUG, details: arguments
1032
+ retries = 0
1020
1033
  begin
1021
1034
  if !arguments.nil? and arguments.size == 1
1022
1035
  retval = @myobject.method(method_sym).call(arguments[0])
@@ -1025,9 +1038,16 @@ module MU
1025
1038
  else
1026
1039
  retval = @myobject.method(method_sym).call
1027
1040
  end
1028
- rescue ::Net::ReadTimeout, ::Faraday::TimeoutError => e
1041
+ rescue ::Net::ReadTimeout, ::Faraday::TimeoutError, ::Faraday::ConnectionFailed => e
1029
1042
  sleep 5
1030
- retry
1043
+ if retries < 12
1044
+ MU.log e.message+" calling #{@parentname}.#{@myname}.#{method_sym.to_s}(#{arguments.map { |a| a.to_s }.join(", ")})", MU::DEBUG, details: caller
1045
+ retries += 1
1046
+ retry
1047
+ else
1048
+ MU.log e.message+" calling #{@parentname}.#{@myname}.#{method_sym.to_s}(#{arguments.map { |a| a.to_s }.join(", ")})", MU::ERR, details: caller
1049
+ raise e
1050
+ end
1031
1051
  rescue ::MsRestAzure::AzureOperationError, ::MsRest::HttpOperationError => e
1032
1052
  MU.log "Error calling #{@parent.api.class.name}.#{@myname}.#{method_sym.to_s}", MU::DEBUG, details: arguments
1033
1053
  begin
@@ -119,7 +119,6 @@ module MU
119
119
 
120
120
  # Register a description of this cluster instance with this deployment's metadata.
121
121
  def notify
122
- base = {}
123
122
  base = MU.structToHash(cloud_desc)
124
123
  base["cloud_id"] = @cloud_id.name
125
124
  base.merge!(@config.to_h)
@@ -146,9 +145,9 @@ module MU
146
145
  end
147
146
 
148
147
  # Cloud-specific configuration properties.
149
- # @param config [MU::Config]: The calling MU::Config object
148
+ # @param _config [MU::Config]: The calling MU::Config object
150
149
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
151
- def self.schema(config)
150
+ def self.schema(_config)
152
151
  toplevel_required = []
153
152
  schema = {
154
153
  "flavor" => {
@@ -219,11 +218,7 @@ module MU
219
218
  "Azure Kubernetes Service Cluster Admin Role"
220
219
  ]
221
220
  }
222
- cluster['dependencies'] ||= []
223
- cluster['dependencies'] << {
224
- "type" => "user",
225
- "name" => cluster["name"]+"user"
226
- }
221
+ MU::Config.addDependency(cluster, cluster['name']+"user", "user")
227
222
 
228
223
  ok = false if !configurator.insertKitten(svcacct_desc, "users")
229
224
 
@@ -53,7 +53,7 @@ module MU
53
53
  oldrules[rule.name] = rule
54
54
  end
55
55
  }
56
- used_priorities = oldrules.values.map { |r| r.priority }
56
+ # used_priorities = oldrules.values.map { |r| r.priority }
57
57
 
58
58
  newrules_semaphore = Mutex.new
59
59
  num_rules = 0
@@ -136,12 +136,12 @@ module MU
136
136
  }
137
137
  end
138
138
 
139
- resolved_lbs = []
140
- if lbs
141
- lbs.each { |lb|
139
+ # resolved_lbs = []
140
+ # if lbs
141
+ # lbs.each { |lb|
142
142
  # TODO awaiting LoadBalancer implementation
143
- }
144
- end
143
+ # }
144
+ # end
145
145
 
146
146
  if egress
147
147
  rule_obj.direction = MU::Cloud::Azure.network(:SecurityRuleDirection)::Outbound
@@ -295,7 +295,7 @@ module MU
295
295
  resp = MU::Cloud::Azure.network(credentials: args[:credentials]).network_security_groups.get(rg, id_str)
296
296
  next if resp.nil?
297
297
  found[Id.new(resp.id)] = resp
298
- rescue MU::Cloud::Azure::APIError => e
298
+ rescue MU::Cloud::Azure::APIError
299
299
  # this is fine, we're doing a blind search after all
300
300
  end
301
301
  }
@@ -336,16 +336,23 @@ module MU
336
336
  # Reverse-map our cloud description into a runnable config hash.
337
337
  # We assume that any values we have in +@config+ are placeholders, and
338
338
  # calculate our own accordingly based on what's live in the cloud.
339
- def toKitten(rootparent: nil, billing: nil)
340
- bok = {}
339
+ def toKitten(**args)
340
+
341
+ bok = {
342
+ "cloud" => "Azure",
343
+ "name" => cloud_desc.name,
344
+ "project" => @config['project'],
345
+ "credentials" => @config['credentials'],
346
+ "cloud_id" => @cloud_id.to_s
347
+ }
341
348
 
342
349
  bok
343
350
  end
344
351
 
345
352
  # Cloud-specific configuration properties.
346
- # @param config [MU::Config]: The calling MU::Config object
353
+ # @param _config [MU::Config]: The calling MU::Config object
347
354
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
348
- def self.schema(config = nil)
355
+ def self.schema(_config = nil)
349
356
  toplevel_required = []
350
357
  hosts_schema = MU::Config::CIDR_PRIMITIVE
351
358
  hosts_schema["pattern"] = "^(\\d+\\.\\d+\\.\\d+\\.\\d+\/[0-9]{1,2}|\\*)$"