cloud-mu 3.1.6 → 3.4.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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/bin/mu-adopt +15 -12
  4. data/bin/mu-azure-tests +57 -0
  5. data/bin/mu-cleanup +2 -4
  6. data/bin/mu-configure +37 -1
  7. data/bin/mu-deploy +3 -3
  8. data/bin/mu-findstray-tests +25 -0
  9. data/bin/mu-gen-docs +2 -4
  10. data/bin/mu-load-config.rb +2 -1
  11. data/bin/mu-run-tests +37 -12
  12. data/cloud-mu.gemspec +4 -4
  13. data/cookbooks/mu-tools/attributes/default.rb +7 -0
  14. data/cookbooks/mu-tools/libraries/helper.rb +87 -3
  15. data/cookbooks/mu-tools/recipes/apply_security.rb +39 -23
  16. data/cookbooks/mu-tools/recipes/aws_api.rb +13 -0
  17. data/cookbooks/mu-tools/recipes/google_api.rb +4 -0
  18. data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
  19. data/cookbooks/mu-tools/resources/disk.rb +33 -12
  20. data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
  21. data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
  22. data/extras/clean-stock-amis +10 -2
  23. data/extras/generate-stock-images +7 -3
  24. data/extras/image-generators/AWS/centos7.yaml +19 -16
  25. data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
  26. data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
  27. data/modules/mommacat.ru +2 -2
  28. data/modules/mu.rb +84 -97
  29. data/modules/mu/adoption.rb +359 -59
  30. data/modules/mu/cleanup.rb +67 -44
  31. data/modules/mu/cloud.rb +108 -1754
  32. data/modules/mu/cloud/database.rb +49 -0
  33. data/modules/mu/cloud/dnszone.rb +44 -0
  34. data/modules/mu/cloud/machine_images.rb +212 -0
  35. data/modules/mu/cloud/providers.rb +81 -0
  36. data/modules/mu/cloud/resource_base.rb +929 -0
  37. data/modules/mu/cloud/server.rb +40 -0
  38. data/modules/mu/cloud/server_pool.rb +1 -0
  39. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  40. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  41. data/modules/mu/cloud/wrappers.rb +178 -0
  42. data/modules/mu/config.rb +122 -80
  43. data/modules/mu/config/alarm.rb +2 -6
  44. data/modules/mu/config/bucket.rb +32 -3
  45. data/modules/mu/config/cache_cluster.rb +2 -2
  46. data/modules/mu/config/cdn.rb +100 -0
  47. data/modules/mu/config/collection.rb +1 -1
  48. data/modules/mu/config/container_cluster.rb +2 -2
  49. data/modules/mu/config/database.rb +84 -105
  50. data/modules/mu/config/database.yml +1 -2
  51. data/modules/mu/config/dnszone.rb +5 -4
  52. data/modules/mu/config/doc_helpers.rb +4 -5
  53. data/modules/mu/config/endpoint.rb +2 -1
  54. data/modules/mu/config/firewall_rule.rb +3 -19
  55. data/modules/mu/config/folder.rb +1 -1
  56. data/modules/mu/config/function.rb +17 -8
  57. data/modules/mu/config/group.rb +1 -1
  58. data/modules/mu/config/habitat.rb +1 -1
  59. data/modules/mu/config/job.rb +89 -0
  60. data/modules/mu/config/loadbalancer.rb +57 -11
  61. data/modules/mu/config/log.rb +1 -1
  62. data/modules/mu/config/msg_queue.rb +1 -1
  63. data/modules/mu/config/nosqldb.rb +1 -1
  64. data/modules/mu/config/notifier.rb +8 -19
  65. data/modules/mu/config/ref.rb +81 -9
  66. data/modules/mu/config/role.rb +1 -1
  67. data/modules/mu/config/schema_helpers.rb +30 -34
  68. data/modules/mu/config/search_domain.rb +1 -1
  69. data/modules/mu/config/server.rb +5 -13
  70. data/modules/mu/config/server_pool.rb +3 -7
  71. data/modules/mu/config/storage_pool.rb +1 -1
  72. data/modules/mu/config/tail.rb +10 -0
  73. data/modules/mu/config/user.rb +1 -1
  74. data/modules/mu/config/vpc.rb +13 -17
  75. data/modules/mu/defaults/AWS.yaml +106 -106
  76. data/modules/mu/defaults/Azure.yaml +1 -0
  77. data/modules/mu/defaults/Google.yaml +1 -0
  78. data/modules/mu/deploy.rb +33 -19
  79. data/modules/mu/groomer.rb +15 -0
  80. data/modules/mu/groomers/chef.rb +3 -0
  81. data/modules/mu/logger.rb +120 -144
  82. data/modules/mu/master.rb +22 -1
  83. data/modules/mu/mommacat.rb +71 -26
  84. data/modules/mu/mommacat/daemon.rb +23 -14
  85. data/modules/mu/mommacat/naming.rb +82 -3
  86. data/modules/mu/mommacat/search.rb +59 -16
  87. data/modules/mu/mommacat/storage.rb +119 -48
  88. data/modules/mu/{clouds → providers}/README.md +1 -1
  89. data/modules/mu/{clouds → providers}/aws.rb +248 -62
  90. data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
  91. data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
  92. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
  93. data/modules/mu/providers/aws/cdn.rb +782 -0
  94. data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
  95. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +65 -63
  96. data/modules/mu/providers/aws/database.rb +1747 -0
  97. data/modules/mu/{clouds → providers}/aws/dnszone.rb +26 -12
  98. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  99. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +39 -32
  100. data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
  101. data/modules/mu/{clouds → providers}/aws/function.rb +291 -133
  102. data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
  103. data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
  104. data/modules/mu/providers/aws/job.rb +469 -0
  105. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +77 -47
  106. data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
  107. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
  108. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
  109. data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
  110. data/modules/mu/{clouds → providers}/aws/role.rb +112 -78
  111. data/modules/mu/{clouds → providers}/aws/search_domain.rb +172 -41
  112. data/modules/mu/{clouds → providers}/aws/server.rb +120 -145
  113. data/modules/mu/{clouds → providers}/aws/server_pool.rb +42 -60
  114. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
  115. data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
  116. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  117. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  118. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
  119. data/modules/mu/{clouds → providers}/aws/vpc.rb +141 -73
  120. data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
  121. data/modules/mu/{clouds → providers}/azure.rb +4 -1
  122. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
  123. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
  124. data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
  125. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
  126. data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
  127. data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
  128. data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
  129. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  130. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  131. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  132. data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
  133. data/modules/mu/{clouds → providers}/cloudformation.rb +1 -1
  134. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  135. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  136. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  137. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  138. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  139. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  140. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  141. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  142. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  143. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  144. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
  145. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  146. data/modules/mu/{clouds → providers}/google.rb +15 -6
  147. data/modules/mu/{clouds → providers}/google/bucket.rb +2 -2
  148. data/modules/mu/{clouds → providers}/google/container_cluster.rb +29 -14
  149. data/modules/mu/{clouds → providers}/google/database.rb +2 -9
  150. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +3 -3
  151. data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
  152. data/modules/mu/{clouds → providers}/google/function.rb +4 -4
  153. data/modules/mu/{clouds → providers}/google/group.rb +9 -17
  154. data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
  155. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +2 -2
  156. data/modules/mu/{clouds → providers}/google/role.rb +46 -35
  157. data/modules/mu/{clouds → providers}/google/server.rb +26 -11
  158. data/modules/mu/{clouds → providers}/google/server_pool.rb +11 -11
  159. data/modules/mu/{clouds → providers}/google/user.rb +32 -22
  160. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  161. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  162. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  163. data/modules/mu/{clouds → providers}/google/vpc.rb +38 -3
  164. data/modules/tests/aws-jobs-functions.yaml +46 -0
  165. data/modules/tests/centos6.yaml +15 -0
  166. data/modules/tests/centos7.yaml +15 -0
  167. data/modules/tests/centos8.yaml +12 -0
  168. data/modules/tests/ecs.yaml +2 -2
  169. data/modules/tests/eks.yaml +1 -1
  170. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  171. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  172. data/modules/tests/microservice_app.yaml +288 -0
  173. data/modules/tests/rds.yaml +108 -0
  174. data/modules/tests/regrooms/rds.yaml +123 -0
  175. data/modules/tests/server-with-scrub-muisms.yaml +1 -1
  176. data/modules/tests/super_complex_bok.yml +2 -2
  177. data/modules/tests/super_simple_bok.yml +2 -2
  178. data/spec/mu/clouds/azure_spec.rb +2 -2
  179. metadata +126 -98
  180. data/modules/mu/clouds/aws/database.rb +0 -1974
  181. data/modules/mu/clouds/aws/endpoint.rb +0 -596
@@ -492,7 +492,7 @@ next if !create
492
492
  return nil if @config.nil? or @deploy.nil?
493
493
 
494
494
  nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
495
- if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, credentials: @config['credentials'])
495
+ if !@config["vpc"].nil? and !MU::Cloud.resourceClass("Google", "VPC").haveRouteToInstance?(cloud_desc, credentials: @config['credentials'])
496
496
 
497
497
  if !@nat.nil?
498
498
  if @nat.cloud_desc.nil?
@@ -623,7 +623,7 @@ next if !create
623
623
  end
624
624
 
625
625
  _nat_ssh_key, _nat_ssh_user, nat_ssh_host, _canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
626
- if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, credentials: @config['credentials'])
626
+ if !nat_ssh_host and !MU::Cloud.resourceClass("Google", "VPC").haveRouteToInstance?(cloud_desc, credentials: @config['credentials'])
627
627
  # XXX check if canonical_ip is in the private ranges
628
628
  # raise MuError, "#{node} has no NAT host configured, and I have no other route to it"
629
629
  end
@@ -992,7 +992,7 @@ next if !create
992
992
  # Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
993
993
  # which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
994
994
  # The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
995
- if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, credentials: @config['credentials']) or public_ips.size == 0
995
+ if MU::Cloud.resourceClass("Google", "VPC").haveRouteToInstance?(cloud_desc, credentials: @config['credentials']) or public_ips.size == 0
996
996
  @config['canonical_ip'] = private_ips.first
997
997
  return private_ips.first
998
998
  else
@@ -1001,6 +1001,22 @@ next if !create
1001
1001
  end
1002
1002
  end
1003
1003
 
1004
+ # Return all of the IP addresses, public and private, from all of our
1005
+ # network interfaces.
1006
+ # @return [Array<String>]
1007
+ def listIPs
1008
+ ips = []
1009
+ cloud_desc.network_interfaces.each { |iface|
1010
+ ips << iface.network_ip
1011
+ if iface.access_configs
1012
+ iface.access_configs.each { |acfg|
1013
+ ips << acfg.nat_ip if acfg.nat_ip
1014
+ }
1015
+ end
1016
+ }
1017
+ ips
1018
+ end
1019
+
1004
1020
  # return [String]: A password string.
1005
1021
  def getWindowsAdminPassword(use_cache: true)
1006
1022
  @config['windows_auth_vault'] ||= {
@@ -1274,9 +1290,9 @@ next if !create
1274
1290
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
1275
1291
  # @param region [String]: The cloud provider region
1276
1292
  # @return [void]
1277
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1293
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1278
1294
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
1279
- return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
1295
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
1280
1296
 
1281
1297
  # XXX make damn sure MU.deploy_id is set
1282
1298
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
@@ -1340,7 +1356,7 @@ next if !create
1340
1356
  def self.schema(config)
1341
1357
  toplevel_required = []
1342
1358
  schema = {
1343
- "roles" => MU::Cloud::Google::User.schema(config)[1]["roles"],
1359
+ "roles" => MU::Cloud.resourceClass("Google", "User").schema(config)[1]["roles"],
1344
1360
  "windows_admin_username" => {
1345
1361
  "type" => "string",
1346
1362
  "default" => "muadmin"
@@ -1451,8 +1467,7 @@ next if !create
1451
1467
  foundmatch = false
1452
1468
  MU::Cloud.availableClouds.each { |cloud|
1453
1469
  next if cloud == "Google"
1454
- cloudbase = Object.const_get("MU").const_get("Cloud").const_get(cloud)
1455
- foreign_types = (cloudbase.listInstanceTypes).values.first
1470
+ foreign_types = (MU::Cloud.cloudClass(cloud).listInstanceTypes).values.first
1456
1471
  if foreign_types.size == 1
1457
1472
  foreign_types = foreign_types.values.first
1458
1473
  end
@@ -1518,12 +1533,12 @@ next if !create
1518
1533
  ok = false
1519
1534
  end
1520
1535
  else
1521
- server = MU::Cloud::Google::User.genericServiceAccount(server, configurator)
1536
+ server = MU::Cloud.resourceClass("Google", "User").genericServiceAccount(server, configurator)
1522
1537
  end
1523
1538
 
1524
1539
  subnets = nil
1525
1540
  if !server['vpc']
1526
- vpcs = MU::Cloud::Google::VPC.find(credentials: server['credentials'])
1541
+ vpcs = MU::Cloud.resourceClass("Google", "VPC").find(credentials: server['credentials'])
1527
1542
  if vpcs["default"]
1528
1543
  server["vpc"] ||= {}
1529
1544
  server["vpc"]["vpc_id"] = vpcs["default"].self_link
@@ -1538,7 +1553,7 @@ next if !create
1538
1553
  if !server['vpc']['subnet_id'] and server['vpc']['subnet_name'].nil?
1539
1554
  if !subnets
1540
1555
  if server["vpc"]["vpc_id"]
1541
- vpcs = MU::Cloud::Google::VPC.find(cloud_id: server["vpc"]["vpc_id"])
1556
+ vpcs = MU::Cloud.resourceClass("Google", "VPC").find(cloud_id: server["vpc"]["vpc_id"])
1542
1557
  subnets = vpcs["default"].subnetworks.sample
1543
1558
  end
1544
1559
  end
@@ -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: {})
434
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
435
435
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
436
- return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], 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(/\./, "_")}")}
@@ -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,7 +282,7 @@ 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
@@ -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
@@ -537,9 +537,9 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
537
537
  # @param noop [Boolean]: If true, will only print what would be done
538
538
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
539
539
  # @return [void]
540
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
540
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
541
541
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
542
- return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
542
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
543
543
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
544
544
  if !ignoremaster and MU.mu_public_ip
545
545
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -565,7 +565,7 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
565
565
  MU.log e.message, MU::WARN
566
566
  if e.message.match(/Failed to delete network (.+)/)
567
567
  network_name = Regexp.last_match[1]
568
- fwrules = MU::Cloud::Google::FirewallRule.find(project: flags['habitat'], credentials: credentials)
568
+ fwrules = MU::Cloud.resourceClass("Google", "FirewallRule").find(project: flags['habitat'], credentials: credentials)
569
569
  fwrules.reject! { |_name, desc|
570
570
  !desc.network.match(/.*?\/#{Regexp.quote(network_name)}$/)
571
571
  }
@@ -946,6 +946,41 @@ MU.log "ROUTES TO #{target_instance.name}", MU::WARN, details: resp
946
946
  createRoute(route, network: @url, tags: [MU::Cloud::Google.nameStr(server.mu_name)])
947
947
  end
948
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
+
949
984
  private
950
985
 
951
986
  def self.genStandardSubnetACLs(vpc_cidr, vpc_name, configurator, project, _publicroute = true, credentials: nil)
@@ -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