cloud-mu 2.0.0.pre.beta2 → 2.0.0.pre.beta3

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile.lock +1 -1
  3. data/cloud-mu.gemspec +4 -3
  4. data/cookbooks/mu-master/templates/default/mu.rc.erb +2 -2
  5. data/cookbooks/mu-tools/files/default/Mu_CA.pem +18 -19
  6. data/cookbooks/mu-tools/recipes/rsyslog.rb +1 -1
  7. data/modules/mu/cleanup.rb +14 -1
  8. data/modules/mu/cloud.rb +40 -22
  9. data/modules/mu/clouds/aws/alarm.rb +6 -0
  10. data/modules/mu/clouds/aws/bucket.rb +29 -0
  11. data/modules/mu/clouds/aws/cache_cluster.rb +6 -0
  12. data/modules/mu/clouds/aws/container_cluster.rb +6 -0
  13. data/modules/mu/clouds/aws/database.rb +6 -0
  14. data/modules/mu/clouds/aws/dnszone.rb +6 -0
  15. data/modules/mu/clouds/aws/endpoint.rb +6 -0
  16. data/modules/mu/clouds/aws/firewall_rule.rb +6 -0
  17. data/modules/mu/clouds/aws/folder.rb +6 -0
  18. data/modules/mu/clouds/aws/function.rb +6 -0
  19. data/modules/mu/clouds/aws/group.rb +6 -0
  20. data/modules/mu/clouds/aws/loadbalancer.rb +6 -0
  21. data/modules/mu/clouds/aws/log.rb +6 -0
  22. data/modules/mu/clouds/aws/msg_queue.rb +6 -0
  23. data/modules/mu/clouds/aws/nosqldb.rb +6 -0
  24. data/modules/mu/clouds/aws/notifier.rb +6 -0
  25. data/modules/mu/clouds/aws/role.rb +97 -11
  26. data/modules/mu/clouds/aws/search_domain.rb +6 -0
  27. data/modules/mu/clouds/aws/server.rb +6 -0
  28. data/modules/mu/clouds/aws/server_pool.rb +6 -0
  29. data/modules/mu/clouds/aws/storage_pool.rb +6 -0
  30. data/modules/mu/clouds/aws/user.rb +6 -0
  31. data/modules/mu/clouds/aws/vpc.rb +25 -1
  32. data/modules/mu/clouds/google.rb +86 -16
  33. data/modules/mu/clouds/google/bucket.rb +78 -3
  34. data/modules/mu/clouds/google/container_cluster.rb +12 -0
  35. data/modules/mu/clouds/google/database.rb +15 -1
  36. data/modules/mu/clouds/google/firewall_rule.rb +18 -2
  37. data/modules/mu/clouds/google/folder.rb +183 -16
  38. data/modules/mu/clouds/google/group.rb +7 -1
  39. data/modules/mu/clouds/google/habitat.rb +139 -24
  40. data/modules/mu/clouds/google/loadbalancer.rb +26 -12
  41. data/modules/mu/clouds/google/server.rb +25 -10
  42. data/modules/mu/clouds/google/server_pool.rb +16 -3
  43. data/modules/mu/clouds/google/user.rb +7 -1
  44. data/modules/mu/clouds/google/vpc.rb +87 -76
  45. data/modules/mu/config.rb +12 -0
  46. data/modules/mu/config/bucket.rb +4 -0
  47. data/modules/mu/config/folder.rb +1 -0
  48. data/modules/mu/config/habitat.rb +1 -1
  49. data/modules/mu/config/role.rb +78 -34
  50. data/modules/mu/config/vpc.rb +1 -0
  51. data/modules/mu/groomers/chef.rb +1 -1
  52. data/modules/mu/kittens.rb +689 -283
  53. metadata +5 -4
@@ -56,6 +56,12 @@ module MU
56
56
  true
57
57
  end
58
58
 
59
+ # Denote whether this resource implementation is experiment, ready for
60
+ # testing, or ready for production use.
61
+ def self.quality
62
+ MU::Cloud::ALPHA
63
+ end
64
+
59
65
  # Remove all groups associated with the currently loaded deployment.
60
66
  # @param noop [Boolean]: If true, will only print what would be done
61
67
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
@@ -69,7 +75,7 @@ module MU
69
75
  # @param region [String]: The cloud provider region.
70
76
  # @param flags [Hash]: Optional flags
71
77
  # @return [OpenStruct]: The cloud provider's complete descriptions of matching group group.
72
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
78
+ def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {}, tag_key: nil, tag_value: nil)
73
79
  flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
74
80
  found = nil
75
81
  found
@@ -30,36 +30,112 @@ module MU
30
30
  @deploy = mommacat
31
31
  @config = MU::Config.manxify(kitten_cfg)
32
32
  @cloud_id ||= cloud_id
33
- @mu_name ||= @deploy.getResourceName(@config["name"])
33
+
34
+ if !mu_name.nil?
35
+ @mu_name = mu_name
36
+ elsif @config['scrub_mu_isms']
37
+ @mu_name = @config['name']
38
+ else
39
+ @mu_name = @deploy.getResourceName(@config['name'])
40
+ end
34
41
  end
35
42
 
36
43
  # Called automatically by {MU::Deploy#createResources}
37
44
  def create
38
45
  labels = {}
39
46
 
40
- name_string = @deploy.getResourceName(@config["name"], max_length: 30).downcase
47
+ name_string = if @config['scrub_mu_isms']
48
+ @config["name"]
49
+ else
50
+ @deploy.getResourceName(@config["name"], max_length: 30).downcase
51
+ end
52
+
53
+ params = {
54
+ name: name_string,
55
+ project_id: name_string,
56
+ }
41
57
 
42
58
  MU::MommaCat.listStandardTags.each_pair { |name, value|
43
59
  if !value.nil?
44
60
  labels[name.downcase] = value.downcase.gsub(/[^a-z0-9\-\_]/i, "_")
45
61
  end
46
62
  }
63
+
64
+ if !@config['scrub_mu_isms']
65
+ params[:labels] = labels
66
+ end
47
67
 
48
- desc = {
49
- name: name_string,
50
- project_id: name_string,
51
- labels: labels
52
- }
53
- if @config['folder'] and @config['folder']['id']
54
- desc["parent"] = @config['folder']['id']
68
+ parent = MU::Cloud::Google::Folder.resolveParent(@config['parent'], credentials: @config['credentials'])
69
+ if !parent
70
+ MU.log "Unable to resolve parent resource of Google Project #{@config['name']}", MU::ERR, details: @config['parent']
71
+ raise "Unable to resolve parent resource of Google Project #{@config['name']}"
55
72
  end
56
73
 
57
- project_obj = MU::Cloud::Google.resource_manager(:Project).new(desc)
58
- pp project_obj
59
- MU.log "Creating project #{@mu_name}", details: project_obj
60
- resp = MU::Cloud::Google.resource_manager(credentials: @config['credentials']).create_project(project_obj)
74
+ type, parent_id = parent.split(/\//)
75
+ params[:parent] = MU::Cloud::Google.resource_manager(:ResourceId).new(
76
+ id: parent_id,
77
+ type: type.sub(/s$/, "") # I wish these engineering teams would talk to each other
78
+ )
79
+
80
+ project_obj = MU::Cloud::Google.resource_manager(:Project).new(params)
81
+
82
+ MU.log "Creating project #{name_string} under #{parent}", details: project_obj
83
+ MU::Cloud::Google.resource_manager(credentials: @config['credentials']).create_project(project_obj)
84
+
85
+
86
+ found = false
87
+ retries = 0
88
+ begin
89
+ resp = MU::Cloud::Google.resource_manager(credentials: credentials).list_projects
90
+ if resp and resp.projects
91
+ resp.projects.each { |p|
92
+ if p.name == name_string.downcase
93
+ found = true
94
+ end
95
+ }
96
+ end
97
+ if !found
98
+ if retries > 0 and (retries % 3) == 0
99
+ MU.log "Waiting for Google Cloud project #{name_string} to appear in list_projects results...", MU::NOTICE
100
+ end
101
+ retries += 1
102
+ sleep 15
103
+ end
104
+ end while !found
105
+
61
106
 
62
107
  @cloud_id = name_string.downcase
108
+ setProjectBilling
109
+ end
110
+
111
+ # Called automatically by {MU::Deploy#createResources}
112
+ def groom
113
+ setProjectBilling
114
+ end
115
+
116
+ # Associate a billing account with this project. If none is specified in
117
+ # our configuration, use the billing account tied the the default
118
+ # project of our credential set.
119
+ def setProjectBilling
120
+ cur_billing = MU::Cloud::Google.billing(credentials: @config['credentials']).get_project_billing_info("projects/"+@cloud_id)
121
+
122
+ if !cur_billing or
123
+ cur_billing.billing_account_name != "billingAccounts/"+@config['billing_acct'] or
124
+ !cur_billing.billing_enabled
125
+
126
+ billing_obj = MU::Cloud::Google.billing(:ProjectBillingInfo).new(
127
+ billing_account_name: "billingAccounts/"+@config['billing_acct'],
128
+ billing_enabled: true,
129
+ name: "projects/"+@cloud_id+"/billingInfo",
130
+ project_id: @cloud_id
131
+ )
132
+ MU.log "Associating project #{@cloud_id} with billing account #{@config['billing_acct']}"
133
+ MU::Cloud::Google.billing(credentials: credentials).update_project_billing_info(
134
+ "projects/"+@cloud_id,
135
+ billing_obj
136
+ )
137
+
138
+ end
63
139
  end
64
140
 
65
141
  # Return the cloud descriptor for the Habitat
@@ -70,12 +146,7 @@ pp project_obj
70
146
  # Return the metadata for this project's configuration
71
147
  # @return [Hash]
72
148
  def notify
73
- desc = MU.structToHash(MU::Cloud::Google.resource_manager(credentials: credentials).list_projects(
74
- filter: "name:#{cloud_id}"
75
- ).projects.first)
76
- desc["mu_name"] = @mu_name
77
- desc["cloud_id"] = @cloud_id
78
- desc
149
+ MU.structToHash(MU::Cloud::Google.resource_manager(credentials: @config['credentials']).get_project(@cloud_id))
79
150
  end
80
151
 
81
152
  # Does this resource type exist as a global (cloud-wide) artifact, or
@@ -85,12 +156,38 @@ pp project_obj
85
156
  true
86
157
  end
87
158
 
159
+ # Denote whether this resource implementation is experiment, ready for
160
+ # testing, or ready for production use.
161
+ def self.quality
162
+ MU::Cloud::BETA
163
+ end
164
+
88
165
  # Remove all Google projects associated with the currently loaded deployment. Try to, anyway.
89
166
  # @param noop [Boolean]: If true, will only print what would be done
90
167
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
91
168
  # @param region [String]: The cloud provider region
92
169
  # @return [void]
93
170
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
171
+ resp = MU::Cloud::Google.resource_manager(credentials: credentials).list_projects
172
+ if resp and resp.projects
173
+ resp.projects.each { |p|
174
+ if p.labels and p.labels["mu-id"] == MU.deploy_id.downcase and
175
+ p.lifecycle_state == "ACTIVE"
176
+ MU.log "Deleting project #{p.name}", details: p
177
+ if !noop
178
+ begin
179
+ MU::Cloud::Google.resource_manager(credentials: credentials).delete_project(p.name)
180
+ rescue ::Google::Apis::ClientError => e
181
+ if e.message.match(/Cannot delete an inactive project/)
182
+ # this is fine
183
+ else
184
+ raise e
185
+ end
186
+ end
187
+ end
188
+ end
189
+ }
190
+ end
94
191
  end
95
192
 
96
193
  # Locate an existing project
@@ -98,13 +195,13 @@ pp project_obj
98
195
  # @param region [String]: The cloud provider region.
99
196
  # @param flags [Hash]: Optional flags
100
197
  # @return [OpenStruct]: The cloud provider's complete descriptions of matching project
101
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
198
+ def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {}, tag_key: nil, tag_value: nil)
102
199
  found = {}
103
200
  if cloud_id
104
201
  resp = MU::Cloud::Google.resource_manager(credentials: credentials).list_projects(
105
202
  filter: "name:#{cloud_id}"
106
- ).projects.first
107
- found[resp.name] = resp
203
+ )
204
+ found[resp.name] = resp.projects.first if resp and resp.projects
108
205
  else
109
206
  resp = MU::Cloud::Google.resource_manager(credentials: credentials).list_projects().projects
110
207
  resp.each { |p|
@@ -121,6 +218,10 @@ pp project_obj
121
218
  def self.schema(config)
122
219
  toplevel_required = []
123
220
  schema = {
221
+ "billing_acct" => {
222
+ "type" => "string",
223
+ "description" => "Billing account ID to associate with a newly-created Google Project. If not specified, will attempt to locate a billing account associated with the default project for our credentials."
224
+ }
124
225
  }
125
226
  [toplevel_required, schema]
126
227
  end
@@ -132,11 +233,25 @@ pp project_obj
132
233
  def self.validateConfig(habitat, configurator)
133
234
  ok = true
134
235
 
135
- if habitat['folder'] and habitat['folder']['name'] and !habitat['folder']['deploy_id']
236
+ if !MU::Cloud::Google.getOrg(habitat['credentials'])
237
+ MU.log "Cannot manage Google Cloud projects in environments without an organization. See also: https://cloud.google.com/resource-manager/docs/creating-managing-organization", MU::ERR
238
+ ok = false
239
+ end
240
+
241
+ if !habitat['billing_acct']
242
+ default_billing = MU::Cloud::Google.billing(credentials: habitat['credentials']).get_project_billing_info("projects/"+MU::Cloud::Google.defaultProject(habitat['credentials']))
243
+ if !default_billing or !default_billing.billing_account_name
244
+ MU.log "Google project #{habitat['name']} does not specify 'billing_acct' and I'm unable to locate a default", MU::ERR
245
+ ok = false
246
+ end
247
+ habitat['billing_acct'] = default_billing.billing_account_name.sub(/^billingAccounts\//, "")
248
+ end
249
+
250
+ if habitat['parent'] and habitat['parent']['name'] and !habitat['parent']['deploy_id'] and configurator.haveLitterMate?(habitat['parent']['name'], "folders")
136
251
  habitat["dependencies"] ||= []
137
252
  habitat["dependencies"] << {
138
253
  "type" => "folder",
139
- "name" => habitat['folder']['name']
254
+ "name" => habitat['parent']['name']
140
255
  }
141
256
  end
142
257
 
@@ -18,6 +18,7 @@ module MU
18
18
  # A load balancer as configured in {MU::Config::BasketofKittens::loadbalancers}
19
19
  class LoadBalancer < MU::Cloud::LoadBalancer
20
20
 
21
+ @project_id = nil
21
22
  @deploy = nil
22
23
  @lb = nil
23
24
  attr_reader :mu_name
@@ -36,6 +37,11 @@ module MU
36
37
  @cloud_id ||= cloud_id
37
38
  if !mu_name.nil?
38
39
  @mu_name = mu_name
40
+ @config['project'] ||= MU::Cloud::Google.defaultProject(@config['credentials'])
41
+ if !@project_id
42
+ project = MU::Cloud::Google.projectLookup(@config['project'], @deploy, sibling_only: true, raise_on_fail: false)
43
+ @project_id = project.nil? ? @config['project'] : project.cloudobj.cloud_id
44
+ end
39
45
  elsif @config['scrub_mu_isms']
40
46
  @mu_name = @config['name']
41
47
  else
@@ -45,6 +51,7 @@ module MU
45
51
 
46
52
  # Called automatically by {MU::Deploy#createResources}
47
53
  def create
54
+ @project_id = MU::Cloud::Google.projectLookup(@config['project'], @deploy).cloudobj.cloud_id
48
55
 
49
56
  parent_thread_id = Thread.current.object_id
50
57
 
@@ -96,13 +103,13 @@ module MU
96
103
  if @config['global']
97
104
  MU.log "Creating Global Forwarding Rule #{@mu_name}", MU::NOTICE, details: ruleobj
98
105
  resp = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_global_forwarding_rule(
99
- @config['project'],
106
+ @project_id,
100
107
  ruleobj
101
108
  )
102
109
  else
103
110
  MU.log "Creating regional Forwarding Rule #{@mu_name} in #{@config['region']}", MU::NOTICE, details: ruleobj
104
111
  resp = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_forwarding_rule(
105
- @config['project'],
112
+ @project_id,
106
113
  @config['region'],
107
114
  ruleobj
108
115
  )
@@ -120,12 +127,12 @@ module MU
120
127
  def notify
121
128
  rules = {}
122
129
  resp = MU::Cloud::Google.compute(credentials: @config['credentials']).list_global_forwarding_rules(
123
- @config["project"],
130
+ @project_id,
124
131
  filter: "description eq #{@deploy.deploy_id}"
125
132
  )
126
133
  if resp.nil? or resp.items.nil? or resp.items.size == 0
127
134
  resp = MU::Cloud::Google.compute(credentials: @config['credentials']).list_forwarding_rules(
128
- @config["project"],
135
+ @project_id,
129
136
  @config['region'],
130
137
  filter: "description eq #{@deploy.deploy_id}"
131
138
  )
@@ -136,6 +143,7 @@ module MU
136
143
  rules[rule.name].delete(:label_fingerprint)
137
144
  }
138
145
  end
146
+ rules["project_id"] = @project_id
139
147
 
140
148
  rules
141
149
  end
@@ -154,6 +162,12 @@ module MU
154
162
  true
155
163
  end
156
164
 
165
+ # Denote whether this resource implementation is experiment, ready for
166
+ # testing, or ready for production use.
167
+ def self.quality
168
+ MU::Cloud::RELEASE
169
+ end
170
+
157
171
  # Remove all load balancers associated with the currently loaded deployment.
158
172
  # @param noop [Boolean]: If true, will only print what would be done
159
173
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
@@ -321,7 +335,7 @@ module MU
321
335
  )
322
336
  MU.log "Creating url map #{tg['name']}", details: urlmap_obj
323
337
  urlmap = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_url_map(
324
- @config['project'],
338
+ @project_id,
325
339
  urlmap_obj
326
340
  )
327
341
 
@@ -335,7 +349,7 @@ module MU
335
349
  target_obj = MU::Cloud::Google.compute(:TargetHttpProxy).new(desc)
336
350
  MU.log "Creating http target proxy #{tg['name']}", details: target_obj
337
351
  MU::Cloud::Google.compute(credentials: @config['credentials']).insert_target_http_proxy(
338
- @config['project'],
352
+ @project_id,
339
353
  target_obj
340
354
  )
341
355
  else
@@ -348,7 +362,7 @@ module MU
348
362
  target_obj = MU::Cloud::Google.compute(:TargetHttpsProxy).new(desc)
349
363
  MU.log "Creating https target proxy #{tg['name']}", details: target_obj
350
364
  MU::Cloud::Google.compute(credentials: @config['credentials']).insert_target_https_proxy(
351
- @config['project'],
365
+ @project_id,
352
366
  target_obj
353
367
  )
354
368
  end
@@ -394,13 +408,13 @@ module MU
394
408
  MU.log "Creating backend service #{MU::Cloud::Google.nameStr(@deploy.getResourceName(tg["name"]))}", details: backend_obj
395
409
  if @config['private'] and !@config['global']
396
410
  return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_region_backend_service(
397
- @config['project'],
411
+ @project_id,
398
412
  @config['region'],
399
413
  backend_obj
400
414
  )
401
415
  else
402
416
  return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_backend_service(
403
- @config['project'],
417
+ @project_id,
404
418
  backend_obj
405
419
  )
406
420
  end
@@ -430,12 +444,12 @@ module MU
430
444
  MU.log "Creating #{proto} health check #{name}", details: hc_obj
431
445
  if proto == "HTTP"
432
446
  return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_http_health_check(
433
- @config['project'],
447
+ @project_id,
434
448
  hc_obj
435
449
  )
436
450
  else
437
451
  return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_https_health_check(
438
- @config['project'],
452
+ @project_id,
439
453
  hc_obj
440
454
  )
441
455
  end
@@ -475,7 +489,7 @@ module MU
475
489
  hc_obj = MU::Cloud::Google.compute(:HealthCheck).new(desc)
476
490
  MU.log "INSERTING HEALTH CHECK", MU::NOTICE, details: hc_obj
477
491
  return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_health_check(
478
- @config['project'],
492
+ @project_id,
479
493
  hc_obj
480
494
  )
481
495
  end
@@ -28,6 +28,7 @@ module MU
28
28
  # Google Cloud, this amounts to a single Instance in an Unmanaged
29
29
  # Instance Group.
30
30
  class Server < MU::Cloud::Server
31
+ @project_id = nil
31
32
 
32
33
  attr_reader :mu_name
33
34
  attr_reader :config
@@ -69,6 +70,11 @@ module MU
69
70
  @config['mu_name'] = @mu_name
70
71
  # describe
71
72
  @mu_windows_name = @deploydata['mu_windows_name'] if @mu_windows_name.nil? and @deploydata
73
+ @config['project'] ||= MU::Cloud::Google.defaultProject(@config['credentials'])
74
+ if !@project_id
75
+ project = MU::Cloud::Google.projectLookup(@config['project'], @deploy, sibling_only: true, raise_on_fail: false)
76
+ @project_id = project.nil? ? @config['project'] : project.cloudobj.cloud_id
77
+ end
72
78
  else
73
79
  if kitten_cfg.has_key?("basis")
74
80
  @mu_name = @deploy.getResourceName(@config['name'], need_unique_string: true)
@@ -243,11 +249,12 @@ next if !create
243
249
 
244
250
  # Called automatically by {MU::Deploy#createResources}
245
251
  def create
252
+ @project_id = MU::Cloud::Google.projectLookup(@config['project_id'], @deploy).cloudobj.cloud_id
246
253
 
247
254
  service_acct = MU::Cloud::Google::Server.createServiceAccount(
248
255
  @mu_name.downcase,
249
256
  @deploy,
250
- project: @config['project'],
257
+ project: @project_id,
251
258
  credentials: @config['credentials']
252
259
  )
253
260
  MU::Cloud::Google.grantDeploySecretAccess(service_acct.email, credentials: @config['credentials'])
@@ -301,7 +308,7 @@ next if !create
301
308
  MU.log "Creating instance #{@mu_name}"
302
309
  begin
303
310
  instance = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_instance(
304
- @config['project'],
311
+ @project_id,
305
312
  @config['availability_zone'],
306
313
  instanceobj
307
314
  )
@@ -379,7 +386,7 @@ next if !create
379
386
  def stop
380
387
  MU.log "Stopping #{@cloud_id}"
381
388
  MU::Cloud::Google.compute(credentials: @config['credentials']).stop_instance(
382
- @config['project'],
389
+ @project_id,
383
390
  @config['availability_zone'],
384
391
  @cloud_id
385
392
  )
@@ -392,7 +399,7 @@ next if !create
392
399
  def start
393
400
  MU.log "Starting #{@cloud_id}"
394
401
  MU::Cloud::Google.compute(credentials: @config['credentials']).start_instance(
395
- @config['project'],
402
+ @project_id,
396
403
  @config['availability_zone'],
397
404
  @cloud_id
398
405
  )
@@ -687,6 +694,7 @@ next if !create
687
694
  "image_created" => @config['image_created'],
688
695
  # "iam_role" => @config['iam_role'],
689
696
  "cloud_desc_id" => @cloud_id,
697
+ "project_id" => @project_id,
690
698
  "private_ip_address" => private_ips.first,
691
699
  "public_ip_address" => public_ips.first,
692
700
  "private_ip_list" => private_ips,
@@ -714,6 +722,7 @@ next if !create
714
722
 
715
723
  # Called automatically by {MU::Deploy#createResources}
716
724
  def groom
725
+ @project_id = MU::Cloud::Google.projectLookup(@config['project_id'], @deploy).cloudobj.cloud_id
717
726
 
718
727
  MU::MommaCat.lock(@cloud_id+"-groom")
719
728
 
@@ -791,7 +800,7 @@ next if !create
791
800
  region: @config['region'],
792
801
  storage: @config['storage'],
793
802
  family: ("mu-"+@config['platform']+"-"+MU.environment).downcase,
794
- project: @config['project'],
803
+ project: @project_id,
795
804
  exclude_storage: img_cfg['image_exclude_storage'],
796
805
  make_public: img_cfg['public'],
797
806
  tags: @config['tags'],
@@ -803,7 +812,7 @@ next if !create
803
812
  if img_cfg['image_then_destroy']
804
813
  MU.log "Image #{image_id} ready, removing source node #{node}"
805
814
  MU::Cloud::Google.compute(credentials: @config['credentials']).delete_instance(
806
- @config['project'],
815
+ @project_id,
807
816
  @config['availability_zone'],
808
817
  @cloud_id
809
818
  )
@@ -901,7 +910,7 @@ next if !create
901
910
  # if !@cloud_id.nil?
902
911
  # begin
903
912
  # return MU::Cloud::Google.compute(credentials: @config['credentials']).get_instance(
904
- # @config['project'],
913
+ # @project_id,
905
914
  # @config['availability_zone'],
906
915
  # @cloud_id
907
916
  # )
@@ -975,14 +984,14 @@ next if !create
975
984
  description: description,
976
985
  zone: @config['availability_zone'],
977
986
  # type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-ssd",
978
- type: "projects/#{@config['project']}/zones/#{@config['availability_zone']}/diskTypes/pd-standard",
987
+ type: "projects/#{@project_id}/zones/#{@config['availability_zone']}/diskTypes/pd-standard",
979
988
  # Other values include pd-ssd and local-ssd
980
989
  name: resname
981
990
  )
982
991
 
983
992
  begin
984
993
  newdisk = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_disk(
985
- @config['project'],
994
+ @project_id,
986
995
  @config['availability_zone'],
987
996
  newdiskobj
988
997
  )
@@ -1002,7 +1011,7 @@ next if !create
1002
1011
  type: "PERSISTENT"
1003
1012
  )
1004
1013
  attachment = MU::Cloud::Google.compute(credentials: @config['credentials']).attach_disk(
1005
- @config['project'],
1014
+ @project_id,
1006
1015
  @config['availability_zone'],
1007
1016
  @cloud_id,
1008
1017
  attachobj
@@ -1024,6 +1033,12 @@ next if !create
1024
1033
  false
1025
1034
  end
1026
1035
 
1036
+ # Denote whether this resource implementation is experiment, ready for
1037
+ # testing, or ready for production use.
1038
+ def self.quality
1039
+ MU::Cloud::RELEASE
1040
+ end
1041
+
1027
1042
  # Remove all instances associated with the currently loaded deployment. Also cleans up associated volumes, droppings in the MU master's /etc/hosts and ~/.ssh, and in whatever Groomer was used.
1028
1043
  # @param noop [Boolean]: If true, will only print what would be done
1029
1044
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server