cloud-mu 3.1.3 → 3.1.4

Sign up to get free protection for your applications and to get access to all the features.
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