cloud-mu 3.0.0beta → 3.0.0

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