cloud-mu 3.0.0beta → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -8
  3. data/ansible/roles/mu-nat/README.md +33 -0
  4. data/ansible/roles/mu-nat/defaults/main.yml +3 -0
  5. data/ansible/roles/mu-nat/handlers/main.yml +2 -0
  6. data/ansible/roles/mu-nat/meta/main.yml +60 -0
  7. data/ansible/roles/mu-nat/tasks/main.yml +65 -0
  8. data/ansible/roles/mu-nat/tests/inventory +2 -0
  9. data/ansible/roles/mu-nat/tests/test.yml +5 -0
  10. data/ansible/roles/mu-nat/vars/main.yml +2 -0
  11. data/bin/mu-cleanup +2 -1
  12. data/bin/mu-configure +950 -948
  13. data/bin/mu-gen-docs +6 -0
  14. data/cloud-mu.gemspec +2 -2
  15. data/cookbooks/mu-tools/recipes/gcloud.rb +8 -1
  16. data/modules/mommacat.ru +1 -1
  17. data/modules/mu.rb +31 -39
  18. data/modules/mu/cloud.rb +11 -1
  19. data/modules/mu/clouds/aws.rb +8 -3
  20. data/modules/mu/clouds/aws/alarm.rb +5 -8
  21. data/modules/mu/clouds/aws/bucket.rb +15 -9
  22. data/modules/mu/clouds/aws/cache_cluster.rb +60 -26
  23. data/modules/mu/clouds/aws/collection.rb +4 -4
  24. data/modules/mu/clouds/aws/container_cluster.rb +50 -33
  25. data/modules/mu/clouds/aws/database.rb +25 -21
  26. data/modules/mu/clouds/aws/dnszone.rb +12 -14
  27. data/modules/mu/clouds/aws/endpoint.rb +5 -8
  28. data/modules/mu/clouds/aws/firewall_rule.rb +9 -4
  29. data/modules/mu/clouds/aws/folder.rb +4 -7
  30. data/modules/mu/clouds/aws/function.rb +5 -8
  31. data/modules/mu/clouds/aws/group.rb +5 -8
  32. data/modules/mu/clouds/aws/habitat.rb +2 -5
  33. data/modules/mu/clouds/aws/loadbalancer.rb +12 -16
  34. data/modules/mu/clouds/aws/log.rb +6 -9
  35. data/modules/mu/clouds/aws/msg_queue.rb +16 -19
  36. data/modules/mu/clouds/aws/nosqldb.rb +27 -18
  37. data/modules/mu/clouds/aws/notifier.rb +6 -9
  38. data/modules/mu/clouds/aws/role.rb +4 -7
  39. data/modules/mu/clouds/aws/search_domain.rb +50 -23
  40. data/modules/mu/clouds/aws/server.rb +20 -14
  41. data/modules/mu/clouds/aws/server_pool.rb +22 -12
  42. data/modules/mu/clouds/aws/storage_pool.rb +9 -14
  43. data/modules/mu/clouds/aws/user.rb +5 -8
  44. data/modules/mu/clouds/aws/userdata/linux.erb +7 -1
  45. data/modules/mu/clouds/aws/vpc.rb +16 -14
  46. data/modules/mu/clouds/azure.rb +1 -1
  47. data/modules/mu/clouds/azure/container_cluster.rb +1 -1
  48. data/modules/mu/clouds/azure/server.rb +16 -2
  49. data/modules/mu/clouds/azure/user.rb +1 -1
  50. data/modules/mu/clouds/azure/userdata/linux.erb +84 -80
  51. data/modules/mu/clouds/azure/vpc.rb +32 -13
  52. data/modules/mu/clouds/cloudformation/server.rb +1 -1
  53. data/modules/mu/clouds/google.rb +2 -3
  54. data/modules/mu/clouds/google/container_cluster.rb +9 -1
  55. data/modules/mu/clouds/google/firewall_rule.rb +6 -0
  56. data/modules/mu/clouds/google/role.rb +1 -3
  57. data/modules/mu/clouds/google/server.rb +25 -4
  58. data/modules/mu/clouds/google/user.rb +1 -1
  59. data/modules/mu/clouds/google/userdata/linux.erb +9 -5
  60. data/modules/mu/clouds/google/vpc.rb +102 -21
  61. data/modules/mu/config.rb +250 -49
  62. data/modules/mu/config/alarm.rb +1 -0
  63. data/modules/mu/config/container_cluster.yml +0 -1
  64. data/modules/mu/config/database.yml +4 -1
  65. data/modules/mu/config/search_domain.yml +4 -3
  66. data/modules/mu/config/server.rb +7 -3
  67. data/modules/mu/config/server.yml +4 -1
  68. data/modules/mu/config/server_pool.yml +2 -0
  69. data/modules/mu/config/vpc.rb +42 -29
  70. data/modules/mu/deploy.rb +12 -5
  71. data/modules/mu/groomers/ansible.rb +4 -1
  72. data/modules/mu/groomers/chef.rb +5 -1
  73. data/modules/mu/kittens.rb +60 -11
  74. data/modules/mu/logger.rb +6 -4
  75. data/modules/mu/mommacat.rb +39 -19
  76. data/modules/mu/mu.yaml.rb +276 -0
  77. metadata +13 -4
@@ -263,18 +263,15 @@ module MU
263
263
  end
264
264
 
265
265
  # Locate an existing log group.
266
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
267
- # @param region [String]: The cloud provider region.
268
- # @param flags [Hash]: Optional flags
269
- # @return [OpenStruct]: The cloud provider's complete descriptions of matching log group.
270
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
266
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching log group.
267
+ def self.find(**args)
271
268
  found = nil
272
- if !cloud_id.nil? and !cloud_id.match(/^arn:/i)
269
+ if !args[:cloud_id].nil? and !args[:cloud_id].match(/^arn:/i)
273
270
  found ||= {}
274
- found[cloud_id] = MU::Cloud::AWS::Log.getLogGroupByName(cloud_id, region: region, credentials: nil)
271
+ found[args[:cloud_id]] = MU::Cloud::AWS::Log.getLogGroupByName(args[:cloud_id], region: args[:region], credentials: args[:credentials])
275
272
  else
276
- resp = MU::Cloud::AWS.cloudwatchlogs(region: region, credentials: credentials).describe_log_groups.log_groups.each { |group|
277
- if group.arn == cloud_id or group.arn.sub(/:\*$/, "") == cloud_id
273
+ resp = MU::Cloud::AWS.cloudwatchlogs(region: args[:region], credentials: args[:credentials]).describe_log_groups.log_groups.each { |group|
274
+ if group.arn == args[:cloud_id] or group.arn.sub(/:\*$/, "") == args[:cloud_id]
278
275
  found ||= {}
279
276
  found[group.log_group_name] = group
280
277
  break
@@ -153,47 +153,44 @@ module MU
153
153
  end
154
154
 
155
155
  # Locate an existing msg_queue.
156
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
157
- # @param region [String]: The cloud provider region.
158
- # @param flags [Hash]: Optional flags
159
156
  # @return [Hash]: AWS doesn't return anything but the SQS URL, so supplement with attributes
160
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
161
- flags['account'] ||= MU.account_number
162
- return nil if !cloud_id
157
+ def self.find(**args)
158
+ args[:flags] ||= {}
159
+ args[:flags]['account'] ||= MU.account_number
160
+ return nil if !args[:cloud_id]
163
161
 
164
162
  # If it's a URL, make sure it's good
165
163
  begin
166
- if cloud_id.match(/^https?:/i)
167
- resp = MU::Cloud::AWS.sqs(region: region, credentials: credentials).get_queue_attributes(
168
- queue_url: cloud_id,
164
+ if args[:cloud_id].match(/^https?:/i)
165
+ resp = MU::Cloud::AWS.sqs(region: args[:region], credentials: args[:credentials]).get_queue_attributes(
166
+ queue_url: args[:cloud_id],
169
167
  attribute_names: ["All"]
170
168
  )
171
169
  if resp and resp.attributes
172
170
  desc = resp.attributes.dup
173
- desc["Url"] = cloud_id
171
+ desc["Url"] = args[:cloud_id]
174
172
  return desc
175
173
  end
176
174
  else
177
175
  # If it's a plain queue name, resolve it to a URL
178
- resp = MU::Cloud::AWS.sqs(region: region, credentials: credentials).get_queue_url(
179
- queue_name: cloud_id,
180
- queue_owner_aws_account_id: flags['account']
176
+ resp = MU::Cloud::AWS.sqs(region: args[:region], credentials: args[:credentials]).get_queue_url(
177
+ queue_name: args[:cloud_id],
178
+ queue_owner_aws_account_id: args[:flags]['account']
181
179
  )
182
- cloud_id = resp.queue_url if resp and resp.queue_url
180
+ args[:cloud_id] = resp.queue_url if resp and resp.queue_url
183
181
  end
184
182
  rescue ::Aws::SQS::Errors::NonExistentQueue => e
185
183
  end
186
184
 
187
185
  # Go fetch its attributes
188
- if cloud_id
189
- resp = MU::Cloud::AWS.sqs(region: region, credentials: credentials).get_queue_attributes(
190
- queue_url: cloud_id,
186
+ if args[:cloud_id]
187
+ resp = MU::Cloud::AWS.sqs(region: args[:region], credentials: args[:credentials]).get_queue_attributes(
188
+ queue_url: args[:cloud_id],
191
189
  attribute_names: ["All"]
192
190
  )
193
191
  if resp and resp.attributes
194
192
  desc = resp.attributes.dup
195
- desc["Url"] = cloud_id
196
- MU.log "RETURNING FROM FIND ON #{cloud_id}", MU::WARN, details: caller
193
+ desc["Url"] = args[:cloud_id]
197
194
  return desc
198
195
  end
199
196
  end
@@ -98,7 +98,7 @@ module MU
98
98
  end
99
99
  }
100
100
  end
101
- pp params
101
+
102
102
  MU.log "Creating DynamoDB table #{@mu_name}", details: params
103
103
 
104
104
  resp = MU::Cloud::AWS.dynamo(credentials: @config['credentials'], region: @config['region']).create_table(params)
@@ -169,16 +169,25 @@ pp params
169
169
  resp.table_names.each { |table|
170
170
  desc = MU::Cloud::AWS.dynamo(credentials: credentials, region: region).describe_table(table_name: table).table
171
171
  next if desc.table_status == "DELETING"
172
- tags = MU::Cloud::AWS.dynamo(credentials: credentials, region: region).list_tags_of_resource(resource_arn: desc.table_arn)
173
- if tags and tags.tags
174
- tags.tags.each { |tag|
175
- if tag.key == "MU-ID" and tag.value == MU.deploy_id
176
- MU.log "Deleting DynamoDB table #{desc.table_name}"
177
- if !noop
178
- MU::Cloud::AWS.dynamo(credentials: credentials, region: region).delete_table(table_name: desc.table_name)
172
+ if desc.table_status == "CREATING"
173
+ begin
174
+ desc = MU::Cloud::AWS.dynamo(credentials: credentials, region: region).describe_table(table_name: table).table
175
+ sleep 1
176
+ end while desc.table_status == "CREATING"
177
+ end
178
+ begin
179
+ tags = MU::Cloud::AWS.dynamo(credentials: credentials, region: region).list_tags_of_resource(resource_arn: desc.table_arn)
180
+ if tags and tags.tags
181
+ tags.tags.each { |tag|
182
+ if tag.key == "MU-ID" and tag.value == MU.deploy_id
183
+ MU.log "Deleting DynamoDB table #{desc.table_name}"
184
+ if !noop
185
+ MU::Cloud::AWS.dynamo(credentials: credentials, region: region).delete_table(table_name: desc.table_name)
186
+ end
179
187
  end
180
- end
181
- }
188
+ }
189
+ end
190
+ rescue Aws::DynamoDB::Errors::ResourceNotFoundException => e
182
191
  end
183
192
 
184
193
  }
@@ -200,15 +209,15 @@ pp params
200
209
  end
201
210
 
202
211
  # Locate an existing DynamoDB table
203
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
204
- # @param region [String]: The cloud provider region.
205
- # @param flags [Hash]: Optional flags
206
- # @return [OpenStruct]: The cloud provider's complete descriptions of matching bucket.
207
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
212
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching bucket.
213
+ def self.find(**args)
208
214
  found = {}
209
- if cloud_id
210
- resp = MU::Cloud::AWS.dynamo(credentials: credentials, region: region).describe_table(table_name: cloud_id)
211
- found[cloud_id] = resp.table if resp and resp.table
215
+ if args[:cloud_id]
216
+ begin
217
+ resp = MU::Cloud::AWS.dynamo(credentials: args[:credentials], region: args[:region]).describe_table(table_name: args[:cloud_id])
218
+ rescue ::Aws::DynamoDB::Errors::ResourceNotFoundException
219
+ end
220
+ found[args[:cloud_id]] = resp.table if resp and resp.table
212
221
  end
213
222
  found
214
223
  end
@@ -91,16 +91,13 @@ module MU
91
91
  end
92
92
 
93
93
  # Locate an existing notifier.
94
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
95
- # @param region [String]: The cloud provider region.
96
- # @param flags [Hash]: Optional flags
97
- # @return [OpenStruct]: The cloud provider's complete descriptions of matching notifier.
98
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
94
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching notifier.
95
+ def self.find(**args)
99
96
  found = {}
100
- if cloud_id
101
- arn = "arn:"+(MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws")+":sns:"+region+":"+MU::Cloud::AWS.credToAcct(credentials)+":"+cloud_id
102
- desc = MU::Cloud::AWS.sns(region: region, credentials: credentials).get_topic_attributes(topic_arn: arn).attributes
103
- found[cloud_id] = desc if desc
97
+ if args[:cloud_id]
98
+ arn = "arn:"+(MU::Cloud::AWS.isGovCloud?(args[:region]) ? "aws-us-gov" : "aws")+":sns:"+args[:region]+":"+MU::Cloud::AWS.credToAcct(args[:credentials])+":"+args[:cloud_id]
99
+ desc = MU::Cloud::AWS.sns(region: args[:region], credentials: args[:credentials]).get_topic_attributes(topic_arn: arn).attributes
100
+ found[args[:cloud_id]] = desc if desc
104
101
  end
105
102
  found
106
103
  end
@@ -123,12 +123,12 @@ module MU
123
123
  version_id: desc.policy.default_version_id
124
124
  )
125
125
 
126
- if version.policy_version.document != URI.encode_www_form(JSON.generate(policy.values.first), /[^a-z0-9\-]/i)
126
+ if version.policy_version.document != URI.encode(JSON.generate(policy.values.first))#, /[^a-z0-9\-]/i)
127
127
  # Special exception- we don't want to overwrite extra rules
128
128
  # in MuSecrets policies, because our siblings might have
129
129
  # (will have) injected those and they should stay.
130
130
  if policy.size == 1 and policy["MuSecrets"]
131
- ext = JSON.parse(URI.decode_www_form(version.policy_version.document))
131
+ ext = JSON.parse(URI.decode(version.policy_version.document))
132
132
  if (ext["Statement"][0]["Resource"] & policy["MuSecrets"]["Statement"][0]["Resource"]).sort == policy["MuSecrets"]["Statement"][0]["Resource"].sort
133
133
  next
134
134
  end
@@ -409,11 +409,8 @@ module MU
409
409
  end
410
410
 
411
411
  # Locate an existing user group.
412
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
413
- # @param region [String]: The cloud provider region.
414
- # @param flags [Hash]: Optional flags
415
- # @return [OpenStruct]: The cloud provider's complete descriptions of matching user group.
416
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
412
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching user group.
413
+ def self.find(**args)
417
414
  found = nil
418
415
 
419
416
  found
@@ -32,7 +32,6 @@ module MU
32
32
  params = genParams
33
33
 
34
34
  MU.log "Creating ElasticSearch domain #{@config['domain_name']}", details: params
35
- pp params
36
35
  resp = MU::Cloud::AWS.elasticsearch(region: @config['region'], credentials: @config['credentials']).create_elasticsearch_domain(params).domain_status
37
36
 
38
37
  tagDomain
@@ -86,6 +85,11 @@ module MU
86
85
  deploy_struct['tags'] = tags.map { |t| { t.key => t.value } }
87
86
  if deploy_struct['endpoint']
88
87
  deploy_struct['kibana'] = deploy_struct['endpoint']+"/_plugin/kibana/"
88
+ elsif deploy_struct['endpoints']
89
+ deploy_struct['kibana'] = {}
90
+ deploy_struct['endpoints'].each_pair { |k, v|
91
+ deploy_struct['kibana'][k] = v+"/_plugin/kibana/"
92
+ }
89
93
  end
90
94
  deploy_struct['domain_name'] ||= @config['domain_name'] if @config['domain_name']
91
95
  deploy_struct
@@ -112,20 +116,25 @@ module MU
112
116
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
113
117
  list = MU::Cloud::AWS.elasticsearch(region: region).list_domain_names
114
118
  if list and list.domain_names and list.domain_names.size > 0
115
- descs = MU::Cloud::AWS.elasticsearch(region: region).describe_elasticsearch_domains(domain_names: list.domain_names.map { |d| d.domain_name } )
116
-
117
- descs.domain_status_list.each { |domain|
118
- tags = MU::Cloud::AWS.elasticsearch(region: region).list_tags(arn: domain.arn)
119
- tags.tag_list.each { |tag|
120
- if tag.key == "MU-ID" and tag.value == MU.deploy_id
121
- MU.log "Deleting ElasticSearch Domain #{domain.domain_name}"
122
- if !noop
123
- MU::Cloud::AWS.elasticsearch(region: region).delete_elasticsearch_domain(domain_name: domain.domain_name)
119
+ names = list.domain_names.map { |d| d.domain_name }
120
+ begin
121
+ # why is this API so obnoxious?
122
+ sample = names.slice!(0, (names.length >= 5 ? 5 : names.length))
123
+ descs = MU::Cloud::AWS.elasticsearch(region: region).describe_elasticsearch_domains(domain_names: sample)
124
+
125
+ descs.domain_status_list.each { |domain|
126
+ tags = MU::Cloud::AWS.elasticsearch(region: region).list_tags(arn: domain.arn)
127
+ tags.tag_list.each { |tag|
128
+ if tag.key == "MU-ID" and tag.value == MU.deploy_id
129
+ MU.log "Deleting ElasticSearch Domain #{domain.domain_name}"
130
+ if !noop
131
+ MU::Cloud::AWS.elasticsearch(region: region).delete_elasticsearch_domain(domain_name: domain.domain_name)
132
+ end
133
+ break
124
134
  end
125
- break
126
- end
135
+ }
127
136
  }
128
- }
137
+ end while names.size > 0
129
138
  end
130
139
 
131
140
  unless noop
@@ -142,18 +151,15 @@ module MU
142
151
  end
143
152
 
144
153
  # Locate an existing search_domain.
145
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
146
- # @param region [String]: The cloud provider region.
147
- # @param flags [Hash]: Optional flags
148
- # @return [OpenStruct]: The cloud provider's complete descriptions of matching search_domain.
149
- def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
150
- if cloud_id
154
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching search_domain.
155
+ def self.find(**args)
156
+ if args[:cloud_id]
151
157
  # Annoyingly, we might expect one of several possible artifacts,
152
158
  # since AWS couldn't decide what the real identifier of these
153
159
  # things should be
154
- list = MU::Cloud::AWS.elasticsearch(region: region, credentials: credentials).list_domain_names
160
+ list = MU::Cloud::AWS.elasticsearch(region: args[:region], credentials: args[:credentials]).list_domain_names
155
161
  if list and list.domain_names and list.domain_names.size > 0
156
- descs = MU::Cloud::AWS.elasticsearch(region: region, credentials: credentials).describe_elasticsearch_domains(domain_names: list.domain_names.map { |d| d.domain_name } )
162
+ descs = MU::Cloud::AWS.elasticsearch(region: args[:region], credentials: args[:credentials]).describe_elasticsearch_domains(domain_names: list.domain_names.map { |d| d.domain_name } )
157
163
  descs.domain_status_list.each { |domain|
158
164
  return domain if domain.arn == cloud_id
159
165
  return domain if domain.domain_name == cloud_id
@@ -305,6 +311,10 @@ module MU
305
311
 
306
312
  if dom["dedicated_masters"] > 0 and dom["master_instance_type"].nil?
307
313
  dom["master_instance_type"] = dom["instance_type"]
314
+ if dom["dedicated_masters"] != 3 and dom["dedicated_masters"] != 5
315
+ MU.log "SearchDomain #{dom['name']}: You must choose either three or five dedicated master nodes", MU::ERR
316
+ ok = false
317
+ end
308
318
  end
309
319
 
310
320
  if dom["instance_count"] < 1
@@ -312,6 +322,11 @@ module MU
312
322
  ok = false
313
323
  end
314
324
 
325
+ if dom["ebs_iops"]
326
+ MU.log "SearchDomain #{dom['name']} declared ebs_iops, setting volume type to io1", MU::NOTICE
327
+ dom["ebs_type"] = "io1"
328
+ end
329
+
315
330
  if dom["zone_aware"] and (dom["instance_count"] % 2) != 0
316
331
  MU.log "Must set an even number for instance_count when enabling Zone Awareness in SearchDomain '#{dom['name']}'", MU::ERR
317
332
  ok = false
@@ -554,6 +569,10 @@ module MU
554
569
  }
555
570
  end
556
571
 
572
+ # XXX this will break on regroom, revisit and make deterministic
573
+ # or remembered
574
+ subnet_ids = subnet_ids.sample(3) if subnet_ids.size > 3
575
+
557
576
  if ext.nil? or
558
577
  ext.vpc_options.subnet_ids != subnet_ids or
559
578
  ext.vpc_options.security_group_ids != sgs
@@ -561,6 +580,11 @@ module MU
561
580
  params[:vpc_options][:subnet_ids] = subnet_ids
562
581
  params[:vpc_options][:security_group_ids] = sgs
563
582
  end
583
+ if @config['zone_aware'] and params[:elasticsearch_cluster_config]
584
+ params[:elasticsearch_cluster_config][:zone_awareness_config] = {
585
+ :availability_zone_count => subnet_ids.size
586
+ }
587
+ end
564
588
  end
565
589
 
566
590
  if @config['ebs_type']
@@ -650,13 +674,16 @@ module MU
650
674
 
651
675
  begin
652
676
  resp = cloud_desc
653
- if (resp.endpoint.nil? or resp.endpoint.empty?) and !resp.deleted
677
+
678
+ if (resp.endpoint.nil? or resp.endpoint.empty?) and
679
+ (resp.endpoints.nil? or resp.endpoints.empty?) and
680
+ !resp.deleted
654
681
  loglevel = (retries > 0 and retries % 3 == 0) ? MU::NOTICE : MU::DEBUG
655
682
  MU.log "Waiting for Elasticsearch domain #{@mu_name} (#{@config['domain_name']}) to finish creating", loglevel
656
683
  sleep interval
657
684
  end
658
685
  retries += 1
659
- end while (resp.endpoint.nil? or resp.endpoint.empty?) and !resp.deleted
686
+ end while (resp.endpoint.nil? or resp.endpoint.empty?) and (resp.endpoints.nil? or resp.endpoints.empty?) and !resp.deleted
660
687
  end
661
688
 
662
689
  end
@@ -391,8 +391,13 @@ module MU
391
391
  # end
392
392
 
393
393
  retries = 0
394
- begin
394
+ instance = begin
395
395
  response = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).run_instances(instance_descriptor)
396
+ if response and response.instances and response.instances.size > 0
397
+ instance = response.instances.first
398
+ else
399
+ MU.log "halp", MU::ERR, details: response
400
+ end
396
401
  rescue Aws::EC2::Errors::InvalidRequest => e
397
402
  MU.log e.message, MU::ERR, details: instance_descriptor
398
403
  raise e
@@ -409,11 +414,9 @@ module MU
409
414
  end
410
415
  end
411
416
 
412
- instance = response.instances.first
413
417
  MU.log "#{node} (#{instance.instance_id}) coming online"
414
418
 
415
- return instance
416
-
419
+ instance
417
420
  end
418
421
 
419
422
  # Ask the Amazon API to restart this node
@@ -967,13 +970,7 @@ module MU
967
970
  # postBoot
968
971
 
969
972
  # Locate an existing instance or instances and return an array containing matching AWS resource descriptors for those that match.
970
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
971
- # @param region [String]: The cloud provider region
972
- # @param tag_key [String]: A tag key to search.
973
- # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
974
- # @param flags [Hash]: Optional flags
975
- # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
976
- # def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
973
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching instances
977
974
  def self.find(**args)
978
975
  ip ||= args[:flags]['ip'] if args[:flags] and args[:flags]['ip']
979
976
 
@@ -1278,7 +1275,12 @@ module MU
1278
1275
  retries = 0
1279
1276
  if !@cloud_id.nil?
1280
1277
  begin
1281
- return MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_instances(instance_ids: [@cloud_id]).reservations.first.instances.first
1278
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_instances(instance_ids: [@cloud_id])
1279
+ if resp and resp.reservations and resp.reservations.first and
1280
+ resp.reservations.first.instances and
1281
+ resp.reservations.first.instances.first
1282
+ return resp.reservations.first.instances.first
1283
+ end
1282
1284
  rescue Aws::EC2::Errors::InvalidInstanceIDNotFound
1283
1285
  return nil
1284
1286
  rescue NoMethodError => e
@@ -2126,7 +2128,8 @@ module MU
2126
2128
  "cloud" => "AWS",
2127
2129
  "bastion" => true,
2128
2130
  "size" => "t2.small",
2129
- "run_list" => [ "mu-utility::nat" ],
2131
+ "run_list" => [ "mu-nat" ],
2132
+ "groomer" => "Ansible",
2130
2133
  "platform" => "centos7",
2131
2134
  "ssh_user" => "centos",
2132
2135
  "associate_public_ip" => true,
@@ -2214,7 +2217,10 @@ module MU
2214
2217
  MU::Cloud.availableClouds.each { |cloud|
2215
2218
  next if cloud == "AWS"
2216
2219
  cloudbase = Object.const_get("MU").const_get("Cloud").const_get(cloud)
2217
- foreign_types = (cloudbase.listInstanceTypes)[cloudbase.myRegion]
2220
+ foreign_types = (cloudbase.listInstanceTypes).values.first
2221
+ if foreign_types.size == 1
2222
+ foreign_types = foreign_types.values.first
2223
+ end
2218
2224
  if foreign_types and foreign_types.size > 0 and foreign_types.has_key?(size)
2219
2225
  vcpu = foreign_types[size]["vcpu"]
2220
2226
  mem = foreign_types[size]["memory"]
@@ -89,11 +89,20 @@ module MU
89
89
  desc.instances.each { |member|
90
90
  begin
91
91
  groomthreads << Thread.new {
92
- Thread.abort_on_exception = false
93
92
  MU.dupGlobals(parent_thread_id)
94
93
  MU.log "Initializing #{member.instance_id} in ServerPool #{@mu_name}"
95
94
  MU::MommaCat.lock(member.instance_id+"-mommagroom")
96
- kitten = MU::Cloud::Server.new(mommacat: @deploy, kitten_cfg: @config, cloud_id: member.instance_id)
95
+ begin
96
+ kitten = MU::Cloud::Server.new(mommacat: @deploy, kitten_cfg: @config, cloud_id: member.instance_id)
97
+ rescue RuntimeError => e
98
+ if e.message.match(/can't add a new key into hash during iteration/)
99
+ MU.log e.message+", retrying", MU::WARN
100
+ sleep 3
101
+ retry
102
+ else
103
+ raise e
104
+ end
105
+ end
97
106
  MU::MommaCat.lock("#{kitten.cloudclass.name}_#{kitten.config["name"]}-dependencies")
98
107
  MU::MommaCat.unlock("#{kitten.cloudclass.name}_#{kitten.config["name"]}-dependencies")
99
108
  if !kitten.postBoot(member.instance_id)
@@ -435,18 +444,13 @@ module MU
435
444
  end
436
445
 
437
446
  # Locate an existing ServerPool or ServerPools and return an array containing matching AWS resource descriptors for those that match.
438
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
439
- # @param region [String]: The cloud provider region
440
- # @param tag_key [String]: A tag key to search.
441
- # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
442
- # @param flags [Hash]: Optional flags
443
- # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching ServerPools
444
- def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
447
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching ServerPools
448
+ def self.find(**args)
445
449
  found = []
446
- if cloud_id
447
- resp = MU::Cloud::AWS.autoscale(region: region, credentials: credentials).describe_auto_scaling_groups({
450
+ if args[:cloud_id]
451
+ resp = MU::Cloud::AWS.autoscale(region: args[:region], credentials: args[:credentials]).describe_auto_scaling_groups({
448
452
  auto_scaling_group_names: [
449
- cloud_id
453
+ args[:cloud_id]
450
454
  ],
451
455
  })
452
456
  return resp.auto_scaling_groups
@@ -1361,9 +1365,15 @@ module MU
1361
1365
  if @config["vpc_zone_identifier"]
1362
1366
  asg_options[:vpc_zone_identifier] = @config["vpc_zone_identifier"]
1363
1367
  elsif @config["vpc"]
1368
+ if !@vpc and @config['vpc'].is_a?(MU::Config::Ref)
1369
+ @vpc = @config['vpc'].kitten
1370
+ end
1364
1371
 
1365
1372
  subnet_ids = []
1366
1373
 
1374
+ if !@vpc
1375
+ raise MuError, "Failed to load vpc for Autoscale Group #{@mu_name}"
1376
+ end
1367
1377
  if !@config["vpc"]["subnets"].nil? and @config["vpc"]["subnets"].size > 0
1368
1378
  @config["vpc"]["subnets"].each { |subnet|
1369
1379
  subnet_obj = @vpc.getSubnet(cloud_id: subnet["subnet_id"], name: subnet["subnet_name"])