cloud-mu 3.1.4 → 3.3.1

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 (203) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +5 -1
  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 +16 -12
  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 -1
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +37 -12
  23. data/cloud-mu.gemspec +5 -3
  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 +1 -1
  27. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  28. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  29. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  30. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  31. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  32. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  33. data/extras/clean-stock-amis +25 -19
  34. data/extras/generate-stock-images +1 -0
  35. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  36. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  37. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  38. data/modules/mommacat.ru +1 -1
  39. data/modules/mu.rb +158 -107
  40. data/modules/mu/adoption.rb +386 -59
  41. data/modules/mu/cleanup.rb +214 -303
  42. data/modules/mu/cloud.rb +128 -1632
  43. data/modules/mu/cloud/database.rb +49 -0
  44. data/modules/mu/cloud/dnszone.rb +44 -0
  45. data/modules/mu/cloud/machine_images.rb +212 -0
  46. data/modules/mu/cloud/providers.rb +81 -0
  47. data/modules/mu/cloud/resource_base.rb +926 -0
  48. data/modules/mu/cloud/server.rb +40 -0
  49. data/modules/mu/cloud/server_pool.rb +1 -0
  50. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  51. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  52. data/modules/mu/cloud/wrappers.rb +169 -0
  53. data/modules/mu/config.rb +135 -82
  54. data/modules/mu/config/alarm.rb +2 -6
  55. data/modules/mu/config/bucket.rb +32 -3
  56. data/modules/mu/config/cache_cluster.rb +2 -2
  57. data/modules/mu/config/cdn.rb +100 -0
  58. data/modules/mu/config/collection.rb +1 -1
  59. data/modules/mu/config/container_cluster.rb +7 -2
  60. data/modules/mu/config/database.rb +84 -105
  61. data/modules/mu/config/database.yml +1 -2
  62. data/modules/mu/config/dnszone.rb +5 -4
  63. data/modules/mu/config/doc_helpers.rb +5 -6
  64. data/modules/mu/config/endpoint.rb +2 -1
  65. data/modules/mu/config/firewall_rule.rb +3 -19
  66. data/modules/mu/config/folder.rb +1 -1
  67. data/modules/mu/config/function.rb +17 -8
  68. data/modules/mu/config/group.rb +1 -1
  69. data/modules/mu/config/habitat.rb +1 -1
  70. data/modules/mu/config/job.rb +89 -0
  71. data/modules/mu/config/loadbalancer.rb +57 -11
  72. data/modules/mu/config/log.rb +1 -1
  73. data/modules/mu/config/msg_queue.rb +1 -1
  74. data/modules/mu/config/nosqldb.rb +1 -1
  75. data/modules/mu/config/notifier.rb +8 -19
  76. data/modules/mu/config/ref.rb +92 -14
  77. data/modules/mu/config/role.rb +1 -1
  78. data/modules/mu/config/schema_helpers.rb +38 -37
  79. data/modules/mu/config/search_domain.rb +1 -1
  80. data/modules/mu/config/server.rb +12 -13
  81. data/modules/mu/config/server.yml +1 -0
  82. data/modules/mu/config/server_pool.rb +3 -7
  83. data/modules/mu/config/storage_pool.rb +1 -1
  84. data/modules/mu/config/tail.rb +11 -0
  85. data/modules/mu/config/user.rb +1 -1
  86. data/modules/mu/config/vpc.rb +27 -23
  87. data/modules/mu/config/vpc.yml +0 -1
  88. data/modules/mu/defaults/AWS.yaml +91 -68
  89. data/modules/mu/defaults/Azure.yaml +1 -0
  90. data/modules/mu/defaults/Google.yaml +1 -0
  91. data/modules/mu/deploy.rb +33 -19
  92. data/modules/mu/groomer.rb +16 -1
  93. data/modules/mu/groomers/ansible.rb +123 -21
  94. data/modules/mu/groomers/chef.rb +64 -11
  95. data/modules/mu/logger.rb +120 -144
  96. data/modules/mu/master.rb +97 -4
  97. data/modules/mu/master/ssl.rb +0 -1
  98. data/modules/mu/mommacat.rb +154 -867
  99. data/modules/mu/mommacat/daemon.rb +23 -14
  100. data/modules/mu/mommacat/naming.rb +110 -3
  101. data/modules/mu/mommacat/search.rb +495 -0
  102. data/modules/mu/mommacat/storage.rb +225 -192
  103. data/modules/mu/{clouds → providers}/README.md +1 -1
  104. data/modules/mu/{clouds → providers}/aws.rb +281 -64
  105. data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
  106. data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
  107. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
  108. data/modules/mu/providers/aws/cdn.rb +782 -0
  109. data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
  110. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +708 -749
  111. data/modules/mu/providers/aws/database.rb +1744 -0
  112. data/modules/mu/{clouds → providers}/aws/dnszone.rb +75 -57
  113. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  114. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +212 -242
  115. data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
  116. data/modules/mu/{clouds → providers}/aws/function.rb +289 -134
  117. data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
  118. data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
  119. data/modules/mu/providers/aws/job.rb +466 -0
  120. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +50 -41
  121. data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
  122. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
  123. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
  124. data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
  125. data/modules/mu/{clouds → providers}/aws/role.rb +94 -57
  126. data/modules/mu/{clouds → providers}/aws/search_domain.rb +173 -42
  127. data/modules/mu/{clouds → providers}/aws/server.rb +782 -1107
  128. data/modules/mu/{clouds → providers}/aws/server_pool.rb +36 -46
  129. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
  130. data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
  131. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  132. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  133. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  134. data/modules/mu/{clouds → providers}/aws/vpc.rb +429 -849
  135. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  136. data/modules/mu/{clouds → providers}/azure.rb +13 -0
  137. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
  138. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
  139. data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
  140. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
  141. data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
  142. data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
  143. data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
  144. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  145. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  146. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  147. data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
  148. data/modules/mu/{clouds → providers}/cloudformation.rb +10 -0
  149. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  150. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  151. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  152. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  153. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  154. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  155. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  156. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  158. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  159. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
  160. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  161. data/modules/mu/{clouds → providers}/google.rb +29 -6
  162. data/modules/mu/{clouds → providers}/google/bucket.rb +5 -5
  163. data/modules/mu/{clouds → providers}/google/container_cluster.rb +59 -37
  164. data/modules/mu/{clouds → providers}/google/database.rb +5 -12
  165. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +5 -5
  166. data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
  167. data/modules/mu/{clouds → providers}/google/function.rb +14 -8
  168. data/modules/mu/{clouds → providers}/google/group.rb +9 -17
  169. data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
  170. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +5 -5
  171. data/modules/mu/{clouds → providers}/google/role.rb +50 -31
  172. data/modules/mu/{clouds → providers}/google/server.rb +142 -55
  173. data/modules/mu/{clouds → providers}/google/server_pool.rb +14 -14
  174. data/modules/mu/{clouds → providers}/google/user.rb +34 -24
  175. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  176. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  177. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  178. data/modules/mu/{clouds → providers}/google/vpc.rb +46 -15
  179. data/modules/tests/aws-jobs-functions.yaml +46 -0
  180. data/modules/tests/centos6.yaml +15 -0
  181. data/modules/tests/centos7.yaml +15 -0
  182. data/modules/tests/centos8.yaml +12 -0
  183. data/modules/tests/ecs.yaml +23 -0
  184. data/modules/tests/eks.yaml +1 -1
  185. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  186. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  187. data/modules/tests/includes-and-params.yaml +2 -1
  188. data/modules/tests/microservice_app.yaml +288 -0
  189. data/modules/tests/rds.yaml +108 -0
  190. data/modules/tests/regrooms/rds.yaml +123 -0
  191. data/modules/tests/server-with-scrub-muisms.yaml +2 -1
  192. data/modules/tests/super_complex_bok.yml +2 -2
  193. data/modules/tests/super_simple_bok.yml +3 -5
  194. data/modules/tests/win2k12.yaml +25 -0
  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 +169 -93
  200. data/extras/image-generators/AWS/windows.yaml +0 -18
  201. data/modules/mu/clouds/aws/database.rb +0 -1974
  202. data/modules/mu/clouds/aws/endpoint.rb +0 -596
  203. data/modules/tests/needwork/win2k12.yaml +0 -13
@@ -89,8 +89,8 @@ module MU
89
89
  machine_type: size,
90
90
  service_accounts: [@service_acct],
91
91
  labels: labels,
92
- disks: MU::Cloud::Google::Server.diskConfig(@config, false, false, credentials: @config['credentials']),
93
- network_interfaces: MU::Cloud::Google::Server.interfaceConfig(@config, @vpc),
92
+ disks: MU::Cloud.resourceClass("Google", "Server").diskConfig(@config, false, false, credentials: @config['credentials']),
93
+ network_interfaces: MU::Cloud.resourceClass("Google", "Server").interfaceConfig(@config, @vpc),
94
94
  metadata: metadata,
95
95
  tags: MU::Cloud::Google.compute(:Tags).new(items: [MU::Cloud::Google.nameStr(@mu_name)])
96
96
  )
@@ -324,11 +324,11 @@ end
324
324
  def self.schema(config)
325
325
  toplevel_required = []
326
326
  schema = {
327
- "ssh_user" => MU::Cloud::Google::Server.schema(config)[1]["ssh_user"],
328
- "metadata" => MU::Cloud::Google::Server.schema(config)[1]["metadata"],
329
- "service_account" => MU::Cloud::Google::Server.schema(config)[1]["service_account"],
330
- "scopes" => MU::Cloud::Google::Server.schema(config)[1]["scopes"],
331
- "network_tags" => MU::Cloud::Google::Server.schema(config)[1]["network_tags"],
327
+ "ssh_user" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["ssh_user"],
328
+ "metadata" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["metadata"],
329
+ "service_account" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["service_account"],
330
+ "scopes" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["scopes"],
331
+ "network_tags" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["network_tags"],
332
332
  "availability_zone" => {
333
333
  "type" => "string",
334
334
  "description" => "Target a specific availability zone for this pool, which will create zonal instance managers and scalers instead of regional ones."
@@ -382,7 +382,7 @@ end
382
382
  if pool['basis']['launch_config']
383
383
  launch = pool["basis"]["launch_config"]
384
384
 
385
- launch['size'] = MU::Cloud::Google::Server.validateInstanceType(launch["size"], pool["region"])
385
+ launch['size'] = MU::Cloud.resourceClass("Google", "Server").validateInstanceType(launch["size"], pool["region"])
386
386
  ok = false if launch['size'].nil?
387
387
 
388
388
  if launch['image_id'].nil?
@@ -397,7 +397,7 @@ end
397
397
 
398
398
  real_image = nil
399
399
  begin
400
- real_image = MU::Cloud::Google::Server.fetchImage(launch['image_id'].to_s, credentials: pool['credentials'])
400
+ real_image = MU::Cloud.resourceClass("Google", "Server").fetchImage(launch['image_id'].to_s, credentials: pool['credentials'])
401
401
  rescue ::Google::Apis::ClientError => e
402
402
  MU.log e.inspect, MU::WARN
403
403
  end
@@ -431,9 +431,9 @@ end
431
431
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
432
432
  # @param region [String]: The cloud provider region
433
433
  # @return [void]
434
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
435
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
436
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
434
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
435
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
436
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
437
437
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
438
438
  if !ignoremaster and MU.mu_public_ip
439
439
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -444,7 +444,7 @@ end
444
444
  ["region_autoscaler", "region_instance_group_manager"].each { |type|
445
445
  MU::Cloud::Google.compute(credentials: credentials).delete(
446
446
  type,
447
- flags["project"],
447
+ flags["habitat"],
448
448
  region,
449
449
  noop
450
450
  )
@@ -452,7 +452,7 @@ end
452
452
  else
453
453
  MU::Cloud::Google.compute(credentials: credentials).delete(
454
454
  "instance_template",
455
- flags["project"],
455
+ flags["habitat"],
456
456
  noop
457
457
  )
458
458
  end
@@ -26,10 +26,12 @@ module MU
26
26
  # If we're being reverse-engineered from a cloud descriptor, use that
27
27
  # to determine what sort of account we are.
28
28
  if args[:from_cloud_desc]
29
+ @cloud_desc_cache = args[:from_cloud_desc]
29
30
  MU::Cloud::Google.admin_directory
30
31
  MU::Cloud::Google.iam
31
32
  if args[:from_cloud_desc].class == ::Google::Apis::AdminDirectoryV1::User
32
33
  @config['type'] = "interactive"
34
+ @cloud_id = args[:from_cloud_desc].primary_email
33
35
  elsif args[:from_cloud_desc].class == ::Google::Apis::IamV1::ServiceAccount
34
36
  @config['type'] = "service"
35
37
  @config['name'] = args[:from_cloud_desc].display_name
@@ -48,6 +50,10 @@ module MU
48
50
  @config['name']
49
51
  end
50
52
 
53
+ if @config['type'] == "interactive" and @config['email']
54
+ @cloud_id ||= @config['email']
55
+ end
56
+
51
57
  end
52
58
 
53
59
  # Called automatically by {MU::Deploy#createResources}
@@ -58,7 +64,7 @@ module MU
58
64
  account_id: acct_id,
59
65
  service_account: MU::Cloud::Google.iam(:ServiceAccount).new(
60
66
  display_name: @mu_name,
61
- description: @config['scrub_mu_isms'] ? nil : @deploy.deploy_id
67
+ description: @config['scrub_mu_isms'] ? @config['description'] : @deploy.deploy_id
62
68
  )
63
69
  )
64
70
  if @config['use_if_exists']
@@ -90,7 +96,7 @@ module MU
90
96
  end
91
97
  elsif @config['external']
92
98
  @cloud_id = @config['email']
93
- MU::Cloud::Google::Role.bindFromConfig("user", @cloud_id, @config['roles'], credentials: @config['credentials'])
99
+ MU::Cloud.resourceClass("Google", "Role").bindFromConfig("user", @cloud_id, @config['roles'], credentials: @config['credentials'])
94
100
  else
95
101
  if !@config['email']
96
102
  domains = MU::Cloud::Google.admin_directory(credentials: @credentials).list_domains(@customer)
@@ -122,10 +128,10 @@ module MU
122
128
  # Called automatically by {MU::Deploy#createResources}
123
129
  def groom
124
130
  if @config['external']
125
- MU::Cloud::Google::Role.bindFromConfig("user", @cloud_id, @config['roles'], credentials: @config['credentials'])
131
+ MU::Cloud.resourceClass("Google", "Role").bindFromConfig("user", @cloud_id, @config['roles'], credentials: @config['credentials'])
126
132
  elsif @config['type'] == "interactive"
127
133
  need_update = false
128
- MU::Cloud::Google::Role.bindFromConfig("user", @cloud_id, @config['roles'], credentials: @config['credentials'])
134
+ MU::Cloud.resourceClass("Google", "Role").bindFromConfig("user", @cloud_id, @config['roles'], credentials: @config['credentials'])
129
135
 
130
136
  if @config['force_password_change'] and !cloud_desc.change_password_at_next_login
131
137
  MU.log "Forcing #{@mu_name} to change their password at next login", MU::NOTICE
@@ -170,7 +176,7 @@ module MU
170
176
  end
171
177
 
172
178
  else
173
- MU::Cloud::Google::Role.bindFromConfig("serviceAccount", @cloud_id.gsub(/.*?\/([^\/]+)$/, '\1'), @config['roles'], credentials: @config['credentials'])
179
+ MU::Cloud.resourceClass("Google", "Role").bindFromConfig("serviceAccount", @cloud_id.gsub(/.*?\/([^\/]+)$/, '\1'), @config['roles'], credentials: @config['credentials'])
174
180
  if @config['create_api_key']
175
181
  resp = MU::Cloud::Google.iam(credentials: @config['credentials']).list_project_service_account_keys(
176
182
  cloud_desc.name
@@ -195,6 +201,7 @@ module MU
195
201
  if @config['type'] == "interactive" or !@config['type']
196
202
  @config['type'] ||= "interactive"
197
203
  if !@config['external']
204
+ @cloud_id ||= @config['email']
198
205
  @cloud_desc_cache = MU::Cloud::Google.admin_directory(credentials: @config['credentials']).get_user(@cloud_id)
199
206
  else
200
207
  return nil
@@ -226,7 +233,7 @@ module MU
226
233
  else
227
234
  {}
228
235
  end
229
- description.delete(:etag)
236
+ description.delete(:etag) if description
230
237
  description
231
238
  end
232
239
 
@@ -247,7 +254,7 @@ module MU
247
254
  # @param noop [Boolean]: If true, will only print what would be done
248
255
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
249
256
  # @return [void]
250
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
257
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
251
258
  MU::Cloud::Google.getDomains(credentials)
252
259
  my_org = MU::Cloud::Google.getOrg(credentials)
253
260
 
@@ -275,15 +282,15 @@ module MU
275
282
  next if user_email.nil?
276
283
  next if !user_email.match(/^[^\/]+@[^\/]+$/)
277
284
 
278
- MU::Cloud::Google::Role.removeBindings("user", user_email, credentials: credentials, noop: noop)
285
+ MU::Cloud.resourceClass("Google", "Role").removeBindings("user", user_email, credentials: credentials, noop: noop)
279
286
  }
280
287
 
281
288
  end
282
289
  end
283
290
 
284
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
291
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
285
292
  resp = MU::Cloud::Google.iam(credentials: credentials).list_project_service_accounts(
286
- "projects/"+flags["project"]
293
+ "projects/"+flags["habitat"]
287
294
  )
288
295
 
289
296
  if resp and resp.accounts and MU.deploy_id
@@ -356,8 +363,10 @@ module MU
356
363
  else
357
364
  if cred_cfg['masquerade_as']
358
365
  resp = MU::Cloud::Google.admin_directory(credentials: args[:credentials]).list_users(customer: MU::Cloud::Google.customerID(args[:credentials]), show_deleted: false)
366
+ # XXX this ain't exactly performant, do some caching or something
359
367
  if resp and resp.users
360
368
  resp.users.each { |u|
369
+ next if args[:cloud_id] and !args[:cloud_id] != u.primary_email
361
370
  found[u.primary_email] = u
362
371
  }
363
372
  end
@@ -374,6 +383,7 @@ module MU
374
383
  name.match(/\b\d+\-compute@developer\.gserviceaccount\.com$/) or
375
384
  name.match(/\bproject-\d+@storage-transfer-service\.iam\.gserviceaccount\.com$/) or
376
385
  name.match(/\b\d+@cloudbuild\.gserviceaccount\.com$/) or
386
+ name.match(/\b\d+@cloudservices\.gserviceaccount\.com$/) or
377
387
  name.match(/\bservice-\d+@containerregistry\.iam\.gserviceaccount\.com$/) or
378
388
  name.match(/\bservice-\d+@container-analysis\.iam\.gserviceaccount\.com$/) or
379
389
  name.match(/\bservice-\d+@compute-system\.iam\.gserviceaccount\.com$/) or
@@ -416,7 +426,7 @@ module MU
416
426
  return nil
417
427
  end
418
428
 
419
- user_roles = MU::Cloud::Google::Role.getAllBindings(@config['credentials'])["by_entity"]
429
+ user_roles = MU::Cloud.resourceClass("Google", "Role").getAllBindings(@config['credentials'])["by_entity"]
420
430
 
421
431
  if cloud_desc.nil?
422
432
  MU.log "FAILED TO FIND CLOUD DESCRIPTOR FOR #{self}", MU::ERR, details: @config
@@ -429,6 +439,10 @@ module MU
429
439
 
430
440
  if bok['type'] == "service"
431
441
  bok['name'].gsub!(/@.*/, '')
442
+ if cloud_desc.description and !cloud_desc.description.empty? and
443
+ !cloud_desc.description.match(/^[A-Z0-9_-]+-[A-Z0-9_-]+-\d{10}-[A-Z]{2}$/)
444
+ bok['description'] = cloud_desc.description
445
+ end
432
446
  bok['project'] = @project_id
433
447
  keys = MU::Cloud::Google.iam(credentials: @config['credentials']).list_project_service_account_keys(@cloud_id)
434
448
 
@@ -439,13 +453,13 @@ module MU
439
453
  if user_roles["serviceAccount"] and
440
454
  user_roles["serviceAccount"][bok['cloud_id']] and
441
455
  user_roles["serviceAccount"][bok['cloud_id']].size > 0
442
- bok['roles'] = MU::Cloud::Google::Role.entityBindingsToSchema(user_roles["serviceAccount"][bok['cloud_id']])
456
+ bok['roles'] = MU::Cloud.resourceClass("Google", "Role").entityBindingsToSchema(user_roles["serviceAccount"][bok['cloud_id']])
443
457
  end
444
458
  else
445
459
  if user_roles["user"] and
446
460
  user_roles["user"][bok['cloud_id']] and
447
461
  user_roles["user"][bok['cloud_id']].size > 0
448
- bok['roles'] = MU::Cloud::Google::Role.entityBindingsToSchema(user_roles["user"][bok['cloud_id']], credentials: @config['credentials'])
462
+ bok['roles'] = MU::Cloud.resourceClass("Google", "Role").entityBindingsToSchema(user_roles["user"][bok['cloud_id']], credentials: @config['credentials'])
449
463
  end
450
464
  bok['given_name'] = cloud_desc.name.given_name if cloud_desc.name.given_name and !cloud_desc.name.given_name.empty?
451
465
  bok['family_name'] = cloud_desc.name.family_name if cloud_desc.name.family_name and !cloud_desc.name.family_name.empty?
@@ -501,6 +515,10 @@ If we are binding (rather than creating) a user and no roles are specified, we w
501
515
  "type" => "string",
502
516
  "description" => "Alias for +family_name+"
503
517
  },
518
+ "description" => {
519
+ "type" => "string",
520
+ "description" => "Comment field for service accounts, which we normally use to store the originating deploy's deploy id, since GCP service accounts do not have labels. This field is only honored if +scrub_mu_isms+ is set."
521
+ },
504
522
  "email" => {
505
523
  "type" => "string",
506
524
  "description" => "Canonical email address for a +directory+ user. If not specified, will be set to +name@domain+."
@@ -528,7 +546,7 @@ If we are binding (rather than creating) a user and no roles are specified, we w
528
546
  "roles" => {
529
547
  "type" => "array",
530
548
  "description" => "One or more Google IAM roles to associate with this user.",
531
- "items" => MU::Cloud::Google::Role.ref_schema
549
+ "items" => MU::Cloud.resourceClass("Google", "Role").ref_schema
532
550
  }
533
551
  }
534
552
  [toplevel_required, schema]
@@ -614,15 +632,11 @@ If we are binding (rather than creating) a user and no roles are specified, we w
614
632
  ok = false
615
633
  end
616
634
 
617
- user['dependencies'] ||= []
618
635
  if user['roles']
619
636
  user['roles'].each { |r|
620
637
  if r['role'] and r['role']['name'] and
621
638
  (!r['role']['deploy_id'] and !r['role']['id'])
622
- user['dependencies'] << {
623
- "type" => "role",
624
- "name" => r['role']['name']
625
- }
639
+ MU::Config.addDependency(user, r['role']['name'], "role")
626
640
  end
627
641
 
628
642
  if !r["projects"] and !r["organizations"] and !r["folders"]
@@ -661,7 +675,6 @@ If we are binding (rather than creating) a user and no roles are specified, we w
661
675
  user['roles'] = parent['roles'].dup
662
676
  end
663
677
  configurator.insertKitten(user, "users", true)
664
- parent['dependencies'] ||= []
665
678
  parent['service_account'] = MU::Config::Ref.get(
666
679
  type: "users",
667
680
  cloud: "Google",
@@ -669,10 +682,7 @@ If we are binding (rather than creating) a user and no roles are specified, we w
669
682
  project: user["project"],
670
683
  credentials: user["credentials"]
671
684
  )
672
- parent['dependencies'] << {
673
- "type" => "user",
674
- "name" => user["name"]
675
- }
685
+ MU::Config.addDependency(parent, user['name'], "user")
676
686
 
677
687
  parent
678
688
  end
@@ -113,7 +113,7 @@ module MU
113
113
  # Describe this VPC
114
114
  # @return [Hash]
115
115
  def notify
116
- base = MU.structToHash(cloud_desc)
116
+ base = MU.structToHash(cloud_desc, stringify_keys: true)
117
117
  base["cloud_id"] = @cloud_id
118
118
  base["project_id"] = habitat_id
119
119
  base.merge!(@config.to_h)
@@ -301,14 +301,10 @@ end
301
301
  @deploy.deployment["vpcs"][@config['name']]["subnets"] and
302
302
  @deploy.deployment["vpcs"][@config['name']]["subnets"].size > 0
303
303
  @deploy.deployment["vpcs"][@config['name']]["subnets"].each { |desc|
304
- subnet = {}
305
- subnet["ip_block"] = desc['ip_block']
306
- subnet["name"] = desc["name"]
304
+ subnet = desc.clone
307
305
  subnet['mu_name'] = @config['scrub_mu_isms'] ? @cloud_id+subnet['name'].downcase : MU::Cloud::Google.nameStr(@deploy.getResourceName(subnet['name'], max_length: 61))
308
- subnet["cloud_id"] = desc['cloud_id']
309
306
  subnet["cloud_id"] ||= desc['self_link'].gsub(/.*?\/([^\/]+)$/, '\1')
310
307
  subnet["cloud_id"] ||= subnet['mu_name']
311
- subnet['az'] = desc["az"]
312
308
  subnet['az'] ||= desc["region"].gsub(/.*?\/([^\/]+)$/, '\1')
313
309
  @subnets << MU::Cloud::Google::VPC::Subnet.new(self, subnet, precache_description: false)
314
310
  }
@@ -513,7 +509,7 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
513
509
  # @param target_subnets_key [String]: The subnet/subnets on the other side of the peered VPC.
514
510
  # @param instance_id [String]: The instance ID in the target subnet/subnets.
515
511
  # @return [Boolean]
516
- def self.have_route_peered_vpc?(source_subnets_key, target_subnets_key, instance_id)
512
+ def self.can_route_to_master_peer?(source_subnets_key, target_subnets_key, instance_id)
517
513
  end
518
514
 
519
515
  # Retrieves the route tables of used by subnets
@@ -541,16 +537,16 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
541
537
  # @param noop [Boolean]: If true, will only print what would be done
542
538
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
543
539
  # @return [void]
544
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
545
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
546
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
540
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
541
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
542
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
547
543
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
548
544
  if !ignoremaster and MU.mu_public_ip
549
545
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
550
546
  end
551
547
  MU.log "Placeholder: Google VPC artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
552
548
 
553
- purge_subnets(noop, project: flags['project'], credentials: credentials)
549
+ purge_subnets(noop, project: flags['habitat'], credentials: credentials)
554
550
  ["route", "network"].each { |type|
555
551
  # XXX tagged routes aren't showing up in list, and the networks that own them
556
552
  # fail to delete silently
@@ -559,7 +555,7 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
559
555
  begin
560
556
  MU::Cloud::Google.compute(credentials: credentials).delete(
561
557
  type,
562
- flags["project"],
558
+ flags["habitat"],
563
559
  nil,
564
560
  noop
565
561
  )
@@ -569,13 +565,13 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
569
565
  MU.log e.message, MU::WARN
570
566
  if e.message.match(/Failed to delete network (.+)/)
571
567
  network_name = Regexp.last_match[1]
572
- fwrules = MU::Cloud::Google::FirewallRule.find(project: flags['project'], credentials: credentials)
568
+ fwrules = MU::Cloud.resourceClass("Google", "FirewallRule").find(project: flags['habitat'], credentials: credentials)
573
569
  fwrules.reject! { |_name, desc|
574
570
  !desc.network.match(/.*?\/#{Regexp.quote(network_name)}$/)
575
571
  }
576
572
  fwrules.keys.each { |name|
577
573
  MU.log "Attempting to delete firewall rule #{name} so that VPC #{network_name} can be removed", MU::NOTICE
578
- MU::Cloud::Google.compute(credentials: credentials).delete_firewall(flags['project'], name)
574
+ MU::Cloud::Google.compute(credentials: credentials).delete_firewall(flags['habitat'], name)
579
575
  }
580
576
  end
581
577
  end
@@ -950,6 +946,41 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
950
946
  createRoute(route, network: @url, tags: [MU::Cloud::Google.nameStr(server.mu_name)])
951
947
  end
952
948
 
949
+ # Looks at existing subnets, and attempts to find the next available
950
+ # IP block that's roughly similar to the ones we already have. This
951
+ # checks against secondary IP ranges, as well as each subnet's primary
952
+ # CIDR block.
953
+ # @param exclude [Array<String>]: One or more CIDRs to treat as unavailable, in addition to those allocated to existing subnets
954
+ # @return [String]
955
+ def getUnusedAddressBlock(exclude: [], max_bits: 28)
956
+ used_ranges = exclude.map { |cidr| NetAddr::IPv4Net.parse(cidr) }
957
+ subnets.each { |s|
958
+ used_ranges << NetAddr::IPv4Net.parse(s.cloud_desc.ip_cidr_range)
959
+ if s.cloud_desc.secondary_ip_ranges
960
+ used_ranges.concat(s.cloud_desc.secondary_ip_ranges.map { |r| NetAddr::IPv4Net.parse(r.ip_cidr_range) })
961
+ end
962
+ }
963
+ # XXX sort used_ranges
964
+ candidate = used_ranges.first.next_sib
965
+
966
+ begin
967
+ if candidate.netmask.prefix_len > max_bits
968
+ candidate = candidate.resize(max_bits)
969
+ end
970
+ try_again = false
971
+ used_ranges.each { |cidr|
972
+ if !cidr.rel(candidate).nil?
973
+ candidate = candidate.next_sib
974
+ try_again = true
975
+ break
976
+ end
977
+ }
978
+ try_again = false if candidate.nil?
979
+ end while try_again
980
+
981
+ candidate.to_s
982
+ end
983
+
953
984
  private
954
985
 
955
986
  def self.genStandardSubnetACLs(vpc_cidr, vpc_name, configurator, project, _publicroute = true, credentials: nil)
@@ -1120,7 +1151,7 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
1120
1151
  # Describe this VPC Subnet
1121
1152
  # @return [Hash]
1122
1153
  def notify
1123
- MU.structToHash(cloud_desc)
1154
+ MU.structToHash(cloud_desc, stringify_keys: true)
1124
1155
  end
1125
1156
 
1126
1157
  # Return the +self_link+ to this subnet
@@ -0,0 +1,46 @@
1
+ # clouds: AWS
2
+ ---
3
+ appname: smoketest
4
+ jobs:
5
+ - name: event1
6
+ schedule:
7
+ minute: '0'
8
+ hour: '1'
9
+ day_of_month: '1'
10
+ month: "*"
11
+ day_of_week: "?"
12
+ year: "*"
13
+ targets:
14
+ - type: functions
15
+ name: python-function
16
+ - name: event2
17
+ disabled: true
18
+ schedule:
19
+ minute: '0'
20
+ hour: '2'
21
+ day_of_month: '1'
22
+ month: "*"
23
+ day_of_week: "?"
24
+ year: "*"
25
+ targets:
26
+ - type: functions
27
+ name: node-function
28
+
29
+ functions:
30
+ - name: python-function
31
+ handler: lambda_function.lambda_handler
32
+ memory: 128
33
+ runtime: python3.6
34
+ timeout: 300
35
+ code:
36
+ path: functions/python-function
37
+ environment_variable:
38
+ - key: foo
39
+ value: bar
40
+ - name: node-function
41
+ runtime: nodejs12.x
42
+ handler: lambda_function.lambda_handler
43
+ memory: 256
44
+ timeout: 60
45
+ code:
46
+ path: functions/node-function