cloud-mu 3.1.3 → 3.1.4

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +10 -2
  3. data/bin/mu-adopt +5 -1
  4. data/bin/mu-load-config.rb +2 -3
  5. data/bin/mu-run-tests +112 -27
  6. data/cloud-mu.gemspec +20 -20
  7. data/cookbooks/mu-tools/libraries/helper.rb +2 -1
  8. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  9. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  10. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  11. data/extras/image-generators/Google/centos6.yaml +1 -0
  12. data/extras/image-generators/Google/centos7.yaml +1 -1
  13. data/modules/mommacat.ru +5 -15
  14. data/modules/mu.rb +10 -14
  15. data/modules/mu/adoption.rb +20 -14
  16. data/modules/mu/cleanup.rb +13 -9
  17. data/modules/mu/cloud.rb +26 -26
  18. data/modules/mu/clouds/aws.rb +100 -59
  19. data/modules/mu/clouds/aws/alarm.rb +4 -2
  20. data/modules/mu/clouds/aws/bucket.rb +25 -21
  21. data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
  22. data/modules/mu/clouds/aws/collection.rb +21 -20
  23. data/modules/mu/clouds/aws/container_cluster.rb +47 -26
  24. data/modules/mu/clouds/aws/database.rb +57 -68
  25. data/modules/mu/clouds/aws/dnszone.rb +14 -14
  26. data/modules/mu/clouds/aws/endpoint.rb +20 -16
  27. data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
  28. data/modules/mu/clouds/aws/folder.rb +7 -7
  29. data/modules/mu/clouds/aws/function.rb +15 -12
  30. data/modules/mu/clouds/aws/group.rb +14 -10
  31. data/modules/mu/clouds/aws/habitat.rb +16 -13
  32. data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
  33. data/modules/mu/clouds/aws/log.rb +13 -10
  34. data/modules/mu/clouds/aws/msg_queue.rb +15 -8
  35. data/modules/mu/clouds/aws/nosqldb.rb +18 -11
  36. data/modules/mu/clouds/aws/notifier.rb +11 -6
  37. data/modules/mu/clouds/aws/role.rb +87 -70
  38. data/modules/mu/clouds/aws/search_domain.rb +30 -19
  39. data/modules/mu/clouds/aws/server.rb +102 -72
  40. data/modules/mu/clouds/aws/server_pool.rb +47 -28
  41. data/modules/mu/clouds/aws/storage_pool.rb +5 -6
  42. data/modules/mu/clouds/aws/user.rb +13 -10
  43. data/modules/mu/clouds/aws/vpc.rb +135 -121
  44. data/modules/mu/clouds/azure.rb +16 -9
  45. data/modules/mu/clouds/azure/container_cluster.rb +2 -3
  46. data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
  47. data/modules/mu/clouds/azure/habitat.rb +8 -6
  48. data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
  49. data/modules/mu/clouds/azure/role.rb +8 -10
  50. data/modules/mu/clouds/azure/server.rb +65 -25
  51. data/modules/mu/clouds/azure/user.rb +5 -7
  52. data/modules/mu/clouds/azure/vpc.rb +12 -15
  53. data/modules/mu/clouds/cloudformation.rb +8 -7
  54. data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
  55. data/modules/mu/clouds/google.rb +39 -24
  56. data/modules/mu/clouds/google/bucket.rb +9 -11
  57. data/modules/mu/clouds/google/container_cluster.rb +27 -42
  58. data/modules/mu/clouds/google/database.rb +6 -9
  59. data/modules/mu/clouds/google/firewall_rule.rb +11 -10
  60. data/modules/mu/clouds/google/folder.rb +16 -9
  61. data/modules/mu/clouds/google/function.rb +127 -161
  62. data/modules/mu/clouds/google/group.rb +21 -18
  63. data/modules/mu/clouds/google/habitat.rb +18 -15
  64. data/modules/mu/clouds/google/loadbalancer.rb +14 -16
  65. data/modules/mu/clouds/google/role.rb +48 -31
  66. data/modules/mu/clouds/google/server.rb +105 -105
  67. data/modules/mu/clouds/google/server_pool.rb +12 -31
  68. data/modules/mu/clouds/google/user.rb +67 -13
  69. data/modules/mu/clouds/google/vpc.rb +58 -65
  70. data/modules/mu/config.rb +89 -1738
  71. data/modules/mu/config/bucket.rb +3 -3
  72. data/modules/mu/config/collection.rb +3 -3
  73. data/modules/mu/config/container_cluster.rb +2 -2
  74. data/modules/mu/config/dnszone.rb +5 -5
  75. data/modules/mu/config/doc_helpers.rb +517 -0
  76. data/modules/mu/config/endpoint.rb +3 -3
  77. data/modules/mu/config/firewall_rule.rb +118 -3
  78. data/modules/mu/config/folder.rb +3 -3
  79. data/modules/mu/config/function.rb +2 -2
  80. data/modules/mu/config/group.rb +3 -3
  81. data/modules/mu/config/habitat.rb +3 -3
  82. data/modules/mu/config/loadbalancer.rb +3 -3
  83. data/modules/mu/config/log.rb +3 -3
  84. data/modules/mu/config/msg_queue.rb +3 -3
  85. data/modules/mu/config/nosqldb.rb +3 -3
  86. data/modules/mu/config/notifier.rb +2 -2
  87. data/modules/mu/config/ref.rb +333 -0
  88. data/modules/mu/config/role.rb +3 -3
  89. data/modules/mu/config/schema_helpers.rb +508 -0
  90. data/modules/mu/config/search_domain.rb +3 -3
  91. data/modules/mu/config/server.rb +86 -58
  92. data/modules/mu/config/server_pool.rb +2 -2
  93. data/modules/mu/config/tail.rb +189 -0
  94. data/modules/mu/config/user.rb +3 -3
  95. data/modules/mu/config/vpc.rb +44 -4
  96. data/modules/mu/defaults/Google.yaml +2 -2
  97. data/modules/mu/deploy.rb +13 -10
  98. data/modules/mu/groomer.rb +1 -1
  99. data/modules/mu/groomers/ansible.rb +69 -24
  100. data/modules/mu/groomers/chef.rb +52 -44
  101. data/modules/mu/logger.rb +17 -14
  102. data/modules/mu/master.rb +317 -2
  103. data/modules/mu/master/chef.rb +3 -4
  104. data/modules/mu/master/ldap.rb +3 -3
  105. data/modules/mu/master/ssl.rb +12 -2
  106. data/modules/mu/mommacat.rb +85 -1766
  107. data/modules/mu/mommacat/daemon.rb +394 -0
  108. data/modules/mu/mommacat/naming.rb +366 -0
  109. data/modules/mu/mommacat/storage.rb +689 -0
  110. data/modules/tests/bucket.yml +4 -0
  111. data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
  112. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  113. data/modules/tests/regrooms/bucket.yml +19 -0
  114. metadata +112 -102
@@ -121,22 +121,18 @@ class Hash
121
121
  # custom objects which we might find in here so that we can get away with
122
122
  # sorting arrays full of weird, non-primitive types.
123
123
  done = []
124
- # before_a = on.dup
125
- # after_a = on.dup.sort
126
- # before_b = with.dup
127
- # after_b = with.dup.sort
128
124
  on.sort.each { |elt|
129
125
  if elt.is_a?(Hash) and elt['name'] or elt['entity']# or elt['cloud_id']
130
126
  with.sort.each { |other_elt|
131
- if (elt['name'] and other_elt['name'] == elt['name']) or
132
- (elt['name'].nil? and !elt["id"].nil? and elt["id"] == other_elt["id"]) or
133
- (elt['name'].nil? and elt["id"].nil? and
134
- !elt["entity"].nil? and !other_elt["entity"].nil? and
135
- (
136
- (elt["entity"]["id"] and elt["entity"]["id"] == other_elt["entity"]["id"]) or
137
- (elt["entity"]["name"] and elt["entity"]["name"] == other_elt["entity"]["name"])
138
- )
139
- )
127
+ # Figure out what convention this thing is using for resource identification
128
+ compare_a, compare_b = if elt['name'].nil? and elt["id"].nil? and !elt["entity"].nil? and !other_elt["entity"].nil?
129
+ [elt["entity"], other_elt["entity"]]
130
+ else
131
+ [elt, other_elt]
132
+ end
133
+
134
+ if (compare_a['name'] and compare_b['name'] == compare_a['name']) or
135
+ (compare_a['name'].nil? and !compare_a["id"].nil? and compare_a["id"] == compare_b["id"])
140
136
  break if elt == other_elt
141
137
  done << elt
142
138
  done << other_elt
@@ -649,7 +645,7 @@ module MU
649
645
  !$MU_CFG['public_address'].empty? and @@my_public_ip != $MU_CFG['public_address']
650
646
  @@mu_public_addr = $MU_CFG['public_address']
651
647
  if !@@mu_public_addr.match(/^\d+\.\d+\.\d+\.\d+$/)
652
- hostname = IO.readlines("/etc/hostname")[0].gsub /\n/, ''
648
+ hostname = IO.readlines("/etc/hostname")[0].gsub(/\n/, '')
653
649
 
654
650
  hostlines = File.open('/etc/hosts').grep(/.*#{hostname}.*/)
655
651
  if hostlines and !hostlines.empty?
@@ -123,6 +123,8 @@ module MU
123
123
  MU.log "Failed to locate a folder that resembles #{@parent}", MU::ERR
124
124
  end
125
125
  MU.log "Scraping complete"
126
+
127
+ @scraped
126
128
  end
127
129
 
128
130
  # Given a list of BoK style tags, try to reverse-engineer the correct
@@ -130,8 +132,9 @@ module MU
130
132
  # this infers from Mu-style tagging, but we'll add a couple cases for
131
133
  # special cloud provider cases.
132
134
  # @param tags [Array<Hash>]
135
+ # @param basename [String]
133
136
  # return [String]
134
- def self.tagsToName(tags = [])
137
+ def self.tagsToName(tags = [], basename: nil)
135
138
  tags.each { |tag|
136
139
  if tag['key'] == "aws:cloudformation:logical-id"
137
140
  return tag['value']
@@ -144,6 +147,7 @@ module MU
144
147
  break
145
148
  end
146
149
  }
150
+
147
151
  tags.each { |tag|
148
152
  if tag['key'] == "Name"
149
153
  if muid and tag['value'].match(/^#{Regexp.quote(muid)}-(.*)/)
@@ -153,6 +157,11 @@ module MU
153
157
  end
154
158
  end
155
159
  }
160
+
161
+ if basename and muid and basename.match(/^#{Regexp.quote(muid)}-(.*)/)
162
+ return Regexp.last_match[1].downcase
163
+ end
164
+
156
165
  nil
157
166
  end
158
167
 
@@ -206,7 +215,7 @@ module MU
206
215
  @scraped.each_pair { |type, resources|
207
216
  res_class = begin
208
217
  MU::Cloud.loadCloudType(cloud, type)
209
- rescue MU::Cloud::MuCloudResourceNotImplemented => e
218
+ rescue MU::Cloud::MuCloudResourceNotImplemented
210
219
  # XXX I don't think this can actually happen
211
220
  next
212
221
  end
@@ -217,8 +226,8 @@ module MU
217
226
  class_semaphore = Mutex.new
218
227
 
219
228
  Thread.abort_on_exception = true
220
- resources.each_pair { |cloud_id_thr, obj_thr|
221
- threads << Thread.new(cloud_id_thr, obj_thr) { |cloud_id, obj|
229
+ resources.values.each { |obj_thr|
230
+ threads << Thread.new(obj_thr) { |obj|
222
231
 
223
232
  kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats)
224
233
  if kitten_cfg
@@ -307,14 +316,14 @@ module MU
307
316
 
308
317
  private
309
318
 
310
- def scrubSchemaDefaults(conf_chunk, schema_chunk, depth = 0, siblings = nil, type: nil)
319
+ def scrubSchemaDefaults(conf_chunk, schema_chunk, depth = 0, type: nil)
311
320
  return if schema_chunk.nil?
312
321
 
313
322
  if !conf_chunk.nil? and schema_chunk["properties"].kind_of?(Hash) and conf_chunk.is_a?(Hash)
314
323
  deletia = []
315
324
  schema_chunk["properties"].each_pair { |key, subschema|
316
325
  next if !conf_chunk[key]
317
- shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(key)
326
+ shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key)
318
327
 
319
328
  if subschema["default_if"]
320
329
  subschema["default_if"].each { |cond|
@@ -328,7 +337,7 @@ module MU
328
337
  if subschema["default"] and conf_chunk[key] == subschema["default"]
329
338
  deletia << key
330
339
  elsif ["array", "object"].include?(subschema["type"])
331
- scrubSchemaDefaults(conf_chunk[key], subschema, depth+1, conf_chunk, type: shortclass)
340
+ scrubSchemaDefaults(conf_chunk[key], subschema, depth+1, type: shortclass)
332
341
  end
333
342
  }
334
343
  deletia.each { |key| conf_chunk.delete(key) }
@@ -339,7 +348,7 @@ module MU
339
348
  realschema = if type and schema_chunk["items"] and schema_chunk["items"]["properties"] and item["cloud"] and MU::Cloud.supportedClouds.include?(item['cloud'])
340
349
 
341
350
  cloudclass = Object.const_get("MU").const_get("Cloud").const_get(item["cloud"]).const_get(type)
342
- toplevel_required, cloudschema = cloudclass.schema(self)
351
+ _toplevel_required, cloudschema = cloudclass.schema(self)
343
352
 
344
353
  newschema = schema_chunk["items"].dup
345
354
  newschema["properties"].merge!(cloudschema)
@@ -349,7 +358,7 @@ module MU
349
358
  end
350
359
  next if ["array", "object"].include?(realschema["type"])
351
360
 
352
- scrubSchemaDefaults(item, realschema, depth+1, conf_chunk, type: type)
361
+ scrubSchemaDefaults(item, realschema, depth+1, type: type)
353
362
  }
354
363
  end
355
364
 
@@ -373,10 +382,7 @@ module MU
373
382
  'billing_acct' => {},
374
383
  'us_only' => {},
375
384
  }
376
- clouds = {}
377
- credentials = {}
378
- regions = {}
379
- MU::Cloud.resource_types.each_pair { |typename, attrs|
385
+ MU::Cloud.resource_types.values.each { |attrs|
380
386
  if bok[attrs[:cfg_plural]]
381
387
  processed = []
382
388
  bok[attrs[:cfg_plural]].each { |resource|
@@ -434,7 +440,7 @@ module MU
434
440
  next if counts.size != 1
435
441
  bok[field] = counts.keys.first
436
442
  MU.log "Setting global default #{field} to #{bok[field]} (#{deploy.deploy_id})", MU::DEBUG
437
- MU::Cloud.resource_types.each_pair { |typename, attrs|
443
+ MU::Cloud.resource_types.values.each { |attrs|
438
444
  if bok[attrs[:cfg_plural]]
439
445
  new_resources = []
440
446
  bok[attrs[:cfg_plural]].each { |resource|
@@ -25,8 +25,6 @@ module MU
25
25
  # Routines for removing cloud resources.
26
26
  class Cleanup
27
27
 
28
- home = Etc.getpwuid(Process.uid).dir
29
-
30
28
  @deploy_id = nil
31
29
  @noop = false
32
30
  @onlycloud = false
@@ -81,7 +79,7 @@ module MU
81
79
  MU.log "Searching for remnants of #{deploy_id}, though this may be an invalid MU-ID.", MU::WARN
82
80
  end
83
81
  @mommacat = MU::MommaCat.new(deploy_id, mu_user: MU.mu_user, delay_descriptor_load: true)
84
- rescue Exception => e
82
+ rescue StandardError => e
85
83
  MU.log "Can't load a deploy record for #{deploy_id} (#{e.inspect}), cleaning up resources by guesswork", MU::WARN, details: e.backtrace
86
84
  MU.setVar("deploy_id", deploy_id)
87
85
 
@@ -90,6 +88,7 @@ module MU
90
88
 
91
89
  regionsused = @mommacat.regionsUsed if @mommacat
92
90
  credsused = @mommacat.credsUsed if @mommacat
91
+ habitatsused = @mommacat.habitatsUsed if @mommacat
93
92
 
94
93
  if !@skipcloud
95
94
  creds = {}
@@ -112,7 +111,6 @@ module MU
112
111
  }
113
112
 
114
113
  parent_thread_id = Thread.current.object_id
115
- deleted_nodes = 0
116
114
  cloudthreads = []
117
115
  keyname = "deploy-#{MU.deploy_id}"
118
116
  had_failures = false
@@ -127,7 +125,6 @@ module MU
127
125
  next if credsused and !credsused.include?(credset)
128
126
  global_vs_region_semaphore = Mutex.new
129
127
  global_done = {}
130
- habitats_done = {}
131
128
  regionthreads = []
132
129
  acct_regions.each { |r|
133
130
  if regionsused
@@ -172,10 +169,13 @@ module MU
172
169
  # CloudFormation sometimes fails internally.
173
170
  projectthreads = []
174
171
  projects.each { |project|
175
- next if !habitatclass.isLive?(project, credset)
176
172
  if habitats and !habitats.empty? and project != ""
177
173
  next if !habitats.include?(project)
178
174
  end
175
+ if habitatsused and !habitatsused.empty? and project != ""
176
+ next if !habitatsused.include?(project)
177
+ end
178
+ next if !habitatclass.isLive?(project, credset)
179
179
 
180
180
  projectthreads << Thread.new {
181
181
  MU.dupGlobals(parent_thread_id)
@@ -192,7 +192,6 @@ module MU
192
192
  "skipsnapshots" => @skipsnapshots,
193
193
  }
194
194
  types_in_order.each { |t|
195
- shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(t)
196
195
  begin
197
196
  skipme = false
198
197
  global_vs_region_semaphore.synchronize {
@@ -424,8 +423,12 @@ module MU
424
423
 
425
424
  end
426
425
 
427
- private
428
-
426
+ # Wrapper for dynamically invoking resource type cleanup methods.
427
+ # @param type [String]:
428
+ # @param credset [String]:
429
+ # @param provider [String]:
430
+ # @param flags [Hash]:
431
+ # @param region [String]:
429
432
  def self.call_cleanup(type, credset, provider, flags, region)
430
433
  if @mommacat.nil? or @mommacat.numKittens(types: [type]) > 0
431
434
  if @mommacat
@@ -458,6 +461,7 @@ module MU
458
461
  else
459
462
  true
460
463
  end
464
+
461
465
  end
462
466
  end #class
463
467
  end #module
@@ -479,7 +479,7 @@ module MU
479
479
  @@platform_cache = MU::Cloud.supportedClouds.map { |cloud|
480
480
  begin
481
481
  loadCloudType(cloud, :Server)
482
- rescue MU::Cloud::MuCloudResourceNotImplemented, MU::MuError => e
482
+ rescue MU::Cloud::MuCloudResourceNotImplemented, MU::MuError
483
483
  next
484
484
  end
485
485
 
@@ -529,7 +529,7 @@ module MU
529
529
  images.deep_merge!(YAML.load(response))
530
530
  break
531
531
  end
532
- rescue Exception => e
532
+ rescue StandardError
533
533
  if fail_hard
534
534
  raise MuError, "Failed to fetch stock images from #{base_url}/#{cloud}.yaml (#{e.message})"
535
535
  else
@@ -624,7 +624,7 @@ module MU
624
624
  end
625
625
  else
626
626
  if region
627
- images.each_pair { |p, regions|
627
+ images.values.each { |regions|
628
628
  # Filter to match our requested region, but for all the platforms,
629
629
  # since we didn't specify one.
630
630
  if regions.is_a?(Hash)
@@ -652,7 +652,6 @@ module MU
652
652
  cloudclass[:cfg_name] == type or
653
653
  cloudclass[:cfg_plural] == type or
654
654
  Object.const_get("MU").const_get("Cloud").const_get(name) == type
655
- cfg_name = cloudclass[:cfg_name]
656
655
  type = name
657
656
  return [type.to_sym, cloudclass[:cfg_name], cloudclass[:cfg_plural], Object.const_get("MU").const_get("Cloud").const_get(name), cloudclass]
658
657
  end
@@ -802,7 +801,7 @@ module MU
802
801
  # @return [Class]: The cloud-specific class implementing this resource
803
802
  def self.loadCloudType(cloud, type)
804
803
  raise MuError, "cloud argument to MU::Cloud.loadCloudType cannot be nil" if cloud.nil?
805
- shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(type)
804
+ shortclass, cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(type)
806
805
  if @cloud_class_cache.has_key?(cloud) and @cloud_class_cache[cloud].has_key?(type)
807
806
  if @cloud_class_cache[cloud][type].nil?
808
807
  raise MuError, "The '#{type}' resource is not supported in cloud #{cloud} (tried MU::#{cloud}::#{type})", caller
@@ -864,7 +863,7 @@ module MU
864
863
  }
865
864
  }
866
865
 
867
- @@resource_types.each_pair { |name, attrs|
866
+ @@resource_types.keys.each { |name|
868
867
  Object.const_get("MU").const_get("Cloud").const_get(name).class_eval {
869
868
  attr_reader :cloudclass
870
869
  attr_reader :cloudobj
@@ -1145,19 +1144,19 @@ module MU
1145
1144
  if self.class.cfg_name == "server"
1146
1145
  begin
1147
1146
  ip = canonicalIP
1148
- MU::MommaCat.removeIPFromSSHKnownHosts(ip) if ip
1147
+ MU::Master.removeIPFromSSHKnownHosts(ip) if ip
1149
1148
  if @deploy and @deploy.deployment and
1150
- @deploy.deployment['servers'] and @config['name'] and
1149
+ @deploy.deployment['servers'] and @config['name']
1151
1150
  me = @deploy.deployment['servers'][@config['name']][@mu_name]
1152
1151
  if me
1153
1152
  ["private_ip_address", "public_ip_address"].each { |field|
1154
1153
  if me[field]
1155
- MU::MommaCat.removeIPFromSSHKnownHosts(me[field])
1154
+ MU::Master.removeIPFromSSHKnownHosts(me[field])
1156
1155
  end
1157
1156
  }
1158
1157
  if me["private_ip_list"]
1159
- me["private_ip_list"].each { |ip|
1160
- MU::MommaCat.removeIPFromSSHKnownHosts(ip)
1158
+ me["private_ip_list"].each { |private_ip|
1159
+ MU::Master.removeIPFromSSHKnownHosts(private_ip)
1161
1160
  }
1162
1161
  end
1163
1162
  end
@@ -1286,7 +1285,7 @@ module MU
1286
1285
  if !@cloud_desc_cache
1287
1286
  MU.log "cloud_desc via #{self.class.name}.find() failed to locate a live object.\nWas called by #{caller[0]}", MU::WARN, details: args
1288
1287
  end
1289
- rescue Exception => e
1288
+ rescue StandardError => e
1290
1289
  MU.log "Got #{e.inspect} trying to find cloud handle for #{self.class.shortname} #{@mu_name} (#{@cloud_id})", MU::WARN
1291
1290
  raise e
1292
1291
  end
@@ -1297,9 +1296,8 @@ module MU
1297
1296
 
1298
1297
  # Retrieve all of the known metadata for this resource.
1299
1298
  # @param cloud_id [String]: The cloud platform's identifier for the resource we're describing. Makes lookups more efficient.
1300
- # @param update_cache [Boolean]: Ignore cached data if we have any, instead reconsituting from original sources.
1301
1299
  # @return [Array<Hash>]: mu_name, config, deploydata
1302
- def describe(cloud_id: nil, update_cache: false)
1300
+ def describe(cloud_id: nil)
1303
1301
  if cloud_id.nil? and !@cloudobj.nil?
1304
1302
  @cloud_id ||= @cloudobj.cloud_id
1305
1303
  end
@@ -1614,7 +1612,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1614
1612
  end
1615
1613
  begin
1616
1614
  cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
1617
- rescue MU::MuError => e
1615
+ rescue MU::MuError
1618
1616
  next
1619
1617
  end
1620
1618
 
@@ -1778,17 +1776,14 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1778
1776
  MU.log "Failed at installing Cygwin", MU::ERR, details: resp
1779
1777
  end
1780
1778
 
1781
- set_hostname = true
1782
1779
  hostname = nil
1783
1780
  if !@config['active_directory'].nil?
1784
1781
  if @config['active_directory']['node_type'] == "domain_controller" && @config['active_directory']['domain_controller_hostname']
1785
1782
  hostname = @config['active_directory']['domain_controller_hostname']
1786
1783
  @mu_windows_name = hostname
1787
- set_hostname = true
1788
1784
  else
1789
1785
  # Do we have an AD specific hostname?
1790
1786
  hostname = @mu_windows_name
1791
- set_hostname = true
1792
1787
  end
1793
1788
  else
1794
1789
  hostname = @mu_windows_name
@@ -1859,7 +1854,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1859
1854
  end
1860
1855
  if windows?
1861
1856
  output = ssh.exec!(win_env_fix)
1862
- output = ssh.exec!(win_installer_check)
1857
+ output += ssh.exec!(win_installer_check)
1863
1858
  raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
1864
1859
  if output.match(/InProgress/)
1865
1860
  raise MU::Cloud::BootstrapTempFail, "Windows Installer service is still doing something, need to wait"
@@ -1906,14 +1901,13 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1906
1901
  # @param winrm_retries [Integer]:
1907
1902
  # @param reboot_on_problems [Boolean]:
1908
1903
  def getWinRMSession(max_retries = 40, retry_interval = 60, timeout: 30, winrm_retries: 5, reboot_on_problems: false)
1909
- nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
1904
+ _nat_ssh_key, _nat_ssh_user, _nat_ssh_host, canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
1910
1905
  @mu_name ||= @config['mu_name']
1911
1906
 
1912
- conn = nil
1913
1907
  shell = nil
1914
1908
  opts = nil
1915
1909
  # and now, a thing I really don't want to do
1916
- MU::MommaCat.addInstanceToEtcHosts(canonical_ip, @mu_name)
1910
+ MU::Master.addInstanceToEtcHosts(canonical_ip, @mu_name)
1917
1911
 
1918
1912
  # catch exceptions that circumvent our regular call stack
1919
1913
  Thread.abort_on_exception = false
@@ -1949,7 +1943,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1949
1943
  retries, rebootable_fails = handleWindowsFail(e, retries, rebootable_fails, max_retries: max_retries, reboot_on_problems: reboot_on_problems, retry_interval: retry_interval)
1950
1944
  retry
1951
1945
  ensure
1952
- MU::MommaCat.removeInstanceFromEtcHosts(@mu_name)
1946
+ MU::Master.removeInstanceFromEtcHosts(@mu_name)
1953
1947
  end
1954
1948
 
1955
1949
  shell
@@ -1960,7 +1954,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1960
1954
  # @return [Net::SSH::Connection::Session]
1961
1955
  def getSSHSession(max_retries = 12, retry_interval = 30)
1962
1956
  ssh_keydir = Etc.getpwnam(@deploy.mu_user).dir+"/.ssh"
1963
- nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
1957
+ nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, _ssh_key_name = getSSHConfig
1964
1958
  session = nil
1965
1959
  retries = 0
1966
1960
 
@@ -2011,7 +2005,8 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
2011
2005
  e.remember_host!
2012
2006
  session.close
2013
2007
  retry
2014
- rescue SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, MU::Cloud::NetSSHFail => e
2008
+ # rescue SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, MU::Cloud::NetSSHFail => e
2009
+ rescue SystemExit, Timeout::Error, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, Net::SSH::Exception, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EPIPE, SocketError, IOError => e
2015
2010
  begin
2016
2011
  session.close if !session.nil?
2017
2012
  rescue Net::SSH::Disconnect, IOError => e
@@ -2059,12 +2054,17 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
2059
2054
  clouds.each { |cloud|
2060
2055
  begin
2061
2056
  cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
2057
+
2058
+ if cloudclass.isGlobal?
2059
+ params.delete(:region)
2060
+ end
2061
+
2062
2062
  raise MuCloudResourceNotImplemented if !cloudclass.respond_to?(:cleanup) or cloudclass.method(:cleanup).owner.to_s != "#<Class:#{cloudclass}>"
2063
2063
  MU.log "Invoking #{cloudclass}.cleanup from #{shortname}", MU::DEBUG, details: flags
2064
2064
  cloudclass.cleanup(params)
2065
2065
  rescue MuCloudResourceNotImplemented
2066
2066
  MU.log "No #{cloud} implementation of #{shortname}.cleanup, skipping", MU::DEBUG, details: flags
2067
- rescue Exception => e
2067
+ rescue StandardError => e
2068
2068
  in_msg = cloud
2069
2069
  if params and params[:region]
2070
2070
  in_msg += " "+params[:region]
@@ -38,8 +38,8 @@ module MU
38
38
  # repetitive setup tasks (like resolving +:resource_group+ for Azure
39
39
  # resources) have always been done.
40
40
  # @param cloudobj [MU::Cloud]
41
- # @param deploy [MU::MommaCat]
42
- def self.resourceInitHook(cloudobj, deploy)
41
+ # @param _deploy [MU::MommaCat]
42
+ def self.resourceInitHook(cloudobj, _deploy)
43
43
  class << self
44
44
  attr_reader :cloudformation_data
45
45
  end
@@ -63,7 +63,6 @@ module MU
63
63
  return nil
64
64
  end
65
65
 
66
- loaded = false
67
66
  cred_obj = nil
68
67
  if cred_cfg['access_key'] and cred_cfg['access_secret'] and
69
68
  # access key and secret just sitting in mu.yaml
@@ -137,11 +136,22 @@ module MU
137
136
  # assume we've got an IAM profile and hope for the best
138
137
  ENV.delete('AWS_ACCESS_KEY_ID')
139
138
  ENV.delete('AWS_SECRET_ACCESS_KEY')
140
- cred_obj = Aws::InstanceProfileCredentials.new
139
+ retries = 0
140
+ begin
141
+ cred_obj = Aws::InstanceProfileCredentials.new
142
+ if cred_obj.nil?
143
+ retries += 1
144
+ MU.log "Failed to fetch AWS instance profile credentials, attempt #{retries.to_s}/10", MU::WARN
145
+ sleep 3
146
+ end
147
+ end while cred_obj.nil? and retries < 10
141
148
  # if name.nil?
142
149
  # Aws.config = {region: ENV['EC2_REGION']}
143
150
  # end
144
151
  end
152
+ if cred_obj.nil?
153
+ MU.log "cred_obj is nil and hosted? says #{hosted?.to_s}", MU::WARN, details: name
154
+ end
145
155
 
146
156
  if name.nil?
147
157
  @@creds_loaded["#default"] = cred_obj
@@ -283,52 +293,13 @@ module MU
283
293
  )
284
294
  end
285
295
 
286
- # Tag EC2 resources.
287
- #
288
- # @param resources [Array<String>]: The cloud provider identifier of the resource to tag
289
- # @param key [String]: The name of the tag to create
290
- # @param value [String]: The value of the tag
291
- # @param region [String]: The cloud provider region
292
- # @return [void,<Hash>]
293
- def self.createTag(key, value, resources = [], region: myRegion, credentials: nil)
294
-
295
- if !MU::Cloud::CloudFormation.emitCloudFormation
296
- begin
297
- MU::Cloud::AWS.ec2(region: region, credentials: credentials).create_tags(
298
- resources: resources,
299
- tags: [
300
- {
301
- key: key,
302
- value: value
303
- }
304
- ]
305
- )
306
- rescue Aws::EC2::Errors::ServiceError => e
307
- MU.log "Got #{e.inspect} tagging #{resources.size.to_s} resources with #{key}=#{value}", MU::WARN, details: resources if attempts > 1
308
- if attempts < 5
309
- attempts = attempts + 1
310
- sleep 15
311
- retry
312
- else
313
- raise e
314
- end
315
- end
316
- MU.log "Created tag #{key} with value #{value}", MU::DEBUG, details: resources
317
- else
318
- return {
319
- "Key" => key,
320
- "Value" => value
321
- }
322
- end
323
- end
324
-
325
296
  @@azs = {}
326
297
  # List the Availability Zones associated with a given Amazon Web Services
327
298
  # region. If no region is given, search the one in which this MU master
328
299
  # server resides.
329
300
  # @param region [String]: The region to search.
330
301
  # @return [Array<String>]: The Availability Zones in this region.
331
- def self.listAZs(region: MU.curRegion, account: nil, credentials: nil)
302
+ def self.listAZs(region: MU.curRegion, credentials: nil)
332
303
  cfg = credConfig(credentials)
333
304
  return [] if !cfg
334
305
  if !region.nil? and @@azs[region]
@@ -491,7 +462,32 @@ module MU
491
462
  # @param cloudobj [MU::Cloud::AWS]: The resource from which to extract the habitat id
492
463
  # @return [String,nil]
493
464
  def self.habitat(cloudobj, nolookup: false, deploy: nil)
494
- cloudobj.respond_to?(:account_number) ? cloudobj.account_number : nil
465
+ @@habmap ||= {}
466
+ # XXX whaddabout config['habitat'] HNNNGH
467
+
468
+ if cloudobj.respond_to?(:account_number) and cloudobj.account_number and
469
+ !cloudobj.account_number.empty?
470
+ return cloudobj.account_number
471
+ elsif cloudobj.config and cloudobj.config['account']
472
+ if nolookup
473
+ return cloudobj.config['account']
474
+ end
475
+ if @@habmap[cloudobj.config['account']]
476
+ return @@habmap[cloudobj.config['account']]
477
+ end
478
+ deploy ||= cloudobj.deploy if cloudobj.respond_to?(:deploy)
479
+
480
+ MU.log "Incomplete implementation: MU::Cloud::AWS.habitat", MU::DEBUG, details: deploy
481
+
482
+ # accountobj = accountLookup(cloudobj.config['account'], deploy, raise_on_fail: false)
483
+
484
+ # if accountobj
485
+ # @@habmap[cloudobj.config['account']] = accountobj.cloud_id
486
+ # return accountobj.cloud_id
487
+ # end
488
+ end
489
+
490
+ nil
495
491
  end
496
492
 
497
493
 
@@ -506,7 +502,6 @@ module MU
506
502
 
507
503
  return creds['account_number'] if creds['account_number']
508
504
 
509
- user_list = MU::Cloud::AWS.iam(credentials: name).list_users.users
510
505
  acct_num = MU::Cloud::AWS.iam(credentials: name).list_users.users.first.arn.split(/:/)[4]
511
506
  acct_num.to_s
512
507
  end
@@ -543,8 +538,8 @@ module MU
543
538
  if !found
544
539
  MU.log "Attempting to create log bucket #{cfg['log_bucket_name']} for credentials #{credentials}", MU::WARN
545
540
  begin
546
- resp = MU::Cloud::AWS.s3(credentials: credentials).create_bucket(bucket: cfg['log_bucket_name'], acl: "private")
547
- rescue Aws::S3::Errors::BucketAlreadyExists => e
541
+ MU::Cloud::AWS.s3(credentials: credentials).create_bucket(bucket: cfg['log_bucket_name'], acl: "private")
542
+ rescue Aws::S3::Errors::BucketAlreadyExists
548
543
  raise MuError, "AWS credentials #{credentials} need a log bucket, and the name #{cfg['log_bucket_name']} is unavailable. Use mu-configure to edit credentials '#{credentials}' or 'hostname'"
549
544
  end
550
545
  end
@@ -620,9 +615,9 @@ module MU
620
615
  # Check each credential sets' resident account, then
621
616
  $MU_CFG['aws'].each_pair { |acctname, cfg|
622
617
  begin
623
- user_list = MU::Cloud::AWS.iam(credentials: acctname).list_users.users
618
+ MU::Cloud::AWS.iam(credentials: acctname).list_users.users
624
619
  # rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
625
- rescue Exception => e
620
+ rescue StandardError => e
626
621
  MU.log e.inspect, MU::WARN, details: cfg
627
622
  next
628
623
  end
@@ -653,7 +648,7 @@ module MU
653
648
  # begin
654
649
  # user_list = MU::Cloud::AWS.iam(region: credConfig['region']).list_users.users
655
650
  ## rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
656
- # rescue Exception => e
651
+ # rescue StandardError => e
657
652
  # MU.log "Got #{e.inspect} while trying to figure out our account number", MU::WARN, details: caller
658
653
  # end
659
654
  # if user_list.nil? or user_list.size == 0
@@ -682,7 +677,6 @@ module MU
682
677
  if @@regions.size == 0
683
678
  return [] if credConfig.nil?
684
679
  result = MU::Cloud::AWS.ec2(region: myRegion, credentials: credentials).describe_regions.regions
685
- regions = []
686
680
  @@regions_semaphore.synchronize {
687
681
  begin
688
682
  result.each { |r|
@@ -1154,6 +1148,55 @@ module MU
1154
1148
  end
1155
1149
  end
1156
1150
 
1151
+ # Tag a resource. Defaults to applying our MU deployment identifier, if no
1152
+ # arguments other than the resource identifier are given.
1153
+ # XXX this belongs in the cloud layer(s)
1154
+ #
1155
+ # @param resource [String]: The cloud provider identifier of the resource to tag
1156
+ # @param tag_name [String]: The name of the tag to create
1157
+ # @param tag_value [String]: The value of the tag
1158
+ # @param region [String]: The cloud provider region
1159
+ # @return [void]
1160
+ def self.createTag(resource = nil,
1161
+ tag_name="MU-ID",
1162
+ tag_value=MU.deploy_id,
1163
+ region: MU.curRegion,
1164
+ credentials: nil)
1165
+ attempts = 0
1166
+
1167
+ return nil if resource.nil?
1168
+ resource = [resource] if resource.is_a?(String)
1169
+
1170
+ if !MU::Cloud::CloudFormation.emitCloudFormation
1171
+ begin
1172
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).create_tags(
1173
+ resources: resource,
1174
+ tags: [
1175
+ {
1176
+ key: tag_name,
1177
+ value: tag_value
1178
+ }
1179
+ ]
1180
+ )
1181
+ rescue Aws::EC2::Errors::ServiceError => e
1182
+ MU.log "Got #{e.inspect} tagging #{resource} with #{tag_name}=#{tag_value}", MU::WARN if attempts > 1
1183
+ if attempts < 5
1184
+ attempts = attempts + 1
1185
+ sleep 15
1186
+ retry
1187
+ else
1188
+ raise e
1189
+ end
1190
+ end
1191
+ MU.log "Created tag #{tag_name} with value #{tag_value} for resource #{resource}", MU::DEBUG
1192
+ else
1193
+ return {
1194
+ "Key" => tag_name,
1195
+ "Value" => tag_value
1196
+ }
1197
+ end
1198
+ end
1199
+
1157
1200
  @syslog_port_semaphore = Mutex.new
1158
1201
  # Punch AWS security group holes for client nodes to talk back to us, the
1159
1202
  # Mu Master, if we're in AWS.
@@ -1205,8 +1248,8 @@ module MU
1205
1248
  )
1206
1249
  sg_id = group.group_id
1207
1250
  my_sgs << sg_id
1208
- MU::MommaCat.createTag sg_id, "Name", my_client_sg_name
1209
- MU::MommaCat.createTag sg_id, "MU-MASTER-IP", MU.mu_public_ip
1251
+ MU::Cloud::AWS.createTag sg_id, "Name", my_client_sg_name
1252
+ MU::Cloud::AWS.createTag sg_id, "MU-MASTER-IP", MU.mu_public_ip
1210
1253
  MU::Cloud::AWS.ec2.modify_instance_attribute(
1211
1254
  instance_id: my_instance_id,
1212
1255
  groups: my_sgs
@@ -1237,7 +1280,7 @@ module MU
1237
1280
  end
1238
1281
 
1239
1282
  allow_ips = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
1240
- MU::MommaCat.listAllNodes.each_pair { |node, data|
1283
+ MU::MommaCat.listAllNodes.values.each { |data|
1241
1284
  next if data.nil? or !data.is_a?(Hash)
1242
1285
  ["public_ip_address"].each { |key|
1243
1286
  if data.has_key?(key) and !data[key].nil? and !data[key].empty?
@@ -1266,7 +1309,7 @@ module MU
1266
1309
  }
1267
1310
  ]
1268
1311
  )
1269
- rescue Aws::EC2::Errors::InvalidPermissionNotFound => e
1312
+ rescue Aws::EC2::Errors::InvalidPermissionNotFound
1270
1313
  MU.log "Permission disappeared from #{sg_id} (port #{port.to_s}) before I could remove it", MU::WARN, details: MU.structToHash(rule.ip_ranges)
1271
1314
  end
1272
1315
  end
@@ -1300,8 +1343,6 @@ module MU
1300
1343
  }
1301
1344
  end
1302
1345
 
1303
- private
1304
-
1305
1346
  # XXX we shouldn't have to do this, but AWS does not provide a way to look
1306
1347
  # it up, and the pricing API only returns the human-readable strings.
1307
1348
  @@regionLookup = {
@@ -1397,7 +1438,7 @@ module MU
1397
1438
  MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}, waiting #{interval.to_s}s and retrying. Args were: #{arguments}", debuglevel, details: caller
1398
1439
  sleep interval
1399
1440
  retry
1400
- rescue Exception => e
1441
+ rescue StandardError => e
1401
1442
  MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}", MU::DEBUG, details: arguments
1402
1443
  raise e
1403
1444
  end