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.
- checksums.yaml +4 -4
- data/README.md +17 -8
- data/ansible/roles/mu-nat/README.md +33 -0
- data/ansible/roles/mu-nat/defaults/main.yml +3 -0
- data/ansible/roles/mu-nat/handlers/main.yml +2 -0
- data/ansible/roles/mu-nat/meta/main.yml +60 -0
- data/ansible/roles/mu-nat/tasks/main.yml +65 -0
- data/ansible/roles/mu-nat/tests/inventory +2 -0
- data/ansible/roles/mu-nat/tests/test.yml +5 -0
- data/ansible/roles/mu-nat/vars/main.yml +2 -0
- data/bin/mu-cleanup +2 -1
- data/bin/mu-configure +950 -948
- data/bin/mu-gen-docs +6 -0
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/mu-tools/recipes/gcloud.rb +8 -1
- data/modules/mommacat.ru +1 -1
- data/modules/mu.rb +31 -39
- data/modules/mu/cloud.rb +11 -1
- data/modules/mu/clouds/aws.rb +8 -3
- data/modules/mu/clouds/aws/alarm.rb +5 -8
- data/modules/mu/clouds/aws/bucket.rb +15 -9
- data/modules/mu/clouds/aws/cache_cluster.rb +60 -26
- data/modules/mu/clouds/aws/collection.rb +4 -4
- data/modules/mu/clouds/aws/container_cluster.rb +50 -33
- data/modules/mu/clouds/aws/database.rb +25 -21
- data/modules/mu/clouds/aws/dnszone.rb +12 -14
- data/modules/mu/clouds/aws/endpoint.rb +5 -8
- data/modules/mu/clouds/aws/firewall_rule.rb +9 -4
- data/modules/mu/clouds/aws/folder.rb +4 -7
- data/modules/mu/clouds/aws/function.rb +5 -8
- data/modules/mu/clouds/aws/group.rb +5 -8
- data/modules/mu/clouds/aws/habitat.rb +2 -5
- data/modules/mu/clouds/aws/loadbalancer.rb +12 -16
- data/modules/mu/clouds/aws/log.rb +6 -9
- data/modules/mu/clouds/aws/msg_queue.rb +16 -19
- data/modules/mu/clouds/aws/nosqldb.rb +27 -18
- data/modules/mu/clouds/aws/notifier.rb +6 -9
- data/modules/mu/clouds/aws/role.rb +4 -7
- data/modules/mu/clouds/aws/search_domain.rb +50 -23
- data/modules/mu/clouds/aws/server.rb +20 -14
- data/modules/mu/clouds/aws/server_pool.rb +22 -12
- data/modules/mu/clouds/aws/storage_pool.rb +9 -14
- data/modules/mu/clouds/aws/user.rb +5 -8
- data/modules/mu/clouds/aws/userdata/linux.erb +7 -1
- data/modules/mu/clouds/aws/vpc.rb +16 -14
- data/modules/mu/clouds/azure.rb +1 -1
- data/modules/mu/clouds/azure/container_cluster.rb +1 -1
- data/modules/mu/clouds/azure/server.rb +16 -2
- data/modules/mu/clouds/azure/user.rb +1 -1
- data/modules/mu/clouds/azure/userdata/linux.erb +84 -80
- data/modules/mu/clouds/azure/vpc.rb +32 -13
- data/modules/mu/clouds/cloudformation/server.rb +1 -1
- data/modules/mu/clouds/google.rb +2 -3
- data/modules/mu/clouds/google/container_cluster.rb +9 -1
- data/modules/mu/clouds/google/firewall_rule.rb +6 -0
- data/modules/mu/clouds/google/role.rb +1 -3
- data/modules/mu/clouds/google/server.rb +25 -4
- data/modules/mu/clouds/google/user.rb +1 -1
- data/modules/mu/clouds/google/userdata/linux.erb +9 -5
- data/modules/mu/clouds/google/vpc.rb +102 -21
- data/modules/mu/config.rb +250 -49
- data/modules/mu/config/alarm.rb +1 -0
- data/modules/mu/config/container_cluster.yml +0 -1
- data/modules/mu/config/database.yml +4 -1
- data/modules/mu/config/search_domain.yml +4 -3
- data/modules/mu/config/server.rb +7 -3
- data/modules/mu/config/server.yml +4 -1
- data/modules/mu/config/server_pool.yml +2 -0
- data/modules/mu/config/vpc.rb +42 -29
- data/modules/mu/deploy.rb +12 -5
- data/modules/mu/groomers/ansible.rb +4 -1
- data/modules/mu/groomers/chef.rb +5 -1
- data/modules/mu/kittens.rb +60 -11
- data/modules/mu/logger.rb +6 -4
- data/modules/mu/mommacat.rb +39 -19
- data/modules/mu/mu.yaml.rb +276 -0
- metadata +13 -4
data/bin/mu-gen-docs
CHANGED
@@ -47,6 +47,7 @@ if !Dir.exist?(docdir)
|
|
47
47
|
FileUtils.mkdir_p(docdir, mode: 0755)
|
48
48
|
end
|
49
49
|
|
50
|
+
MU::Config.emitConfigAsRuby
|
50
51
|
MU::Config.emitSchemaAsRuby
|
51
52
|
if Process.uid == 0
|
52
53
|
MU.log "Generating YARD documentation in #{docdir} (see http://#{$MU_CFG['public_address']}/docs/frames.html)"
|
@@ -68,6 +69,7 @@ Dir.chdir(MU.myRoot) do
|
|
68
69
|
EOF
|
69
70
|
|
70
71
|
impl_counts = {}
|
72
|
+
cloud_is_useful = {}
|
71
73
|
cloudlist = MU::Cloud.supportedClouds.sort { |a, b|
|
72
74
|
counts = {
|
73
75
|
a => 0,
|
@@ -80,9 +82,11 @@ EOF
|
|
80
82
|
myclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(type)
|
81
83
|
case myclass.quality
|
82
84
|
when MU::Cloud::RELEASE
|
85
|
+
cloud_is_useful[cloud] = true
|
83
86
|
counts[cloud] += 4
|
84
87
|
impl_counts[type] += 4
|
85
88
|
when MU::Cloud::BETA
|
89
|
+
cloud_is_useful[cloud] = true
|
86
90
|
counts[cloud] += 2
|
87
91
|
impl_counts[type] += 2
|
88
92
|
when MU::Cloud::ALPHA
|
@@ -96,6 +100,8 @@ EOF
|
|
96
100
|
counts[b] <=> counts[a]
|
97
101
|
}
|
98
102
|
|
103
|
+
cloudlist.reject! { |c| !cloud_is_useful[c] }
|
104
|
+
|
99
105
|
readme += "\n\n<table><tr><th></th>"
|
100
106
|
cloudlist.each { |cloud|
|
101
107
|
readme += "<th>"+cloud+"</th>"
|
data/cloud-mu.gemspec
CHANGED
@@ -17,8 +17,8 @@ end
|
|
17
17
|
|
18
18
|
Gem::Specification.new do |s|
|
19
19
|
s.name = 'cloud-mu'
|
20
|
-
s.version = '3.0.
|
21
|
-
s.date = '2019-11-
|
20
|
+
s.version = '3.0.0'
|
21
|
+
s.date = '2019-11-11'
|
22
22
|
s.require_paths = ['modules']
|
23
23
|
s.required_ruby_version = '>= 2.4'
|
24
24
|
s.summary = "The eGTLabs Mu toolkit for unified cloud deployments"
|
@@ -41,7 +41,14 @@ if platform_family?("rhel") or platform_family?("amazon")
|
|
41
41
|
cwd "/opt"
|
42
42
|
code <<-EOH
|
43
43
|
tar -xzf #{Chef::Config[:file_cache_path]}/gcloud-cli.tar.gz
|
44
|
-
|
44
|
+
if [ -f /opt/rh/python27/root/usr/bin/python ];then
|
45
|
+
if [ ! -f /etc/ld.so.conf.d/python27.conf ];then
|
46
|
+
echo "/opt/rh/python27/root/usr/lib64" > /etc/ld.so.conf.d/python27.conf
|
47
|
+
echo "/opt/rh/python27/root/usr/lib" >> /etc/ld.so.conf.d/python27.conf
|
48
|
+
/sbin/ldconfig
|
49
|
+
fi
|
50
|
+
fi
|
51
|
+
CLOUDSDK_PYTHON="`/bin/rpm -ql muthon python27-python | grep '/bin/python$'`" ./google-cloud-sdk/install.sh -q
|
45
52
|
EOH
|
46
53
|
notifies :create, "remote_file[#{Chef::Config[:file_cache_path]}/gcloud-cli.sh]", :before
|
47
54
|
notifies :create, "remote_file[#{Chef::Config[:file_cache_path]}/gcloud-cli.tar.gz]", :before
|
data/modules/mommacat.ru
CHANGED
data/modules/mu.rb
CHANGED
@@ -404,41 +404,49 @@ module MU
|
|
404
404
|
|
405
405
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
406
406
|
def self.mommacat;
|
407
|
+
@@globals[Thread.current.object_id] ||= {}
|
407
408
|
@@globals[Thread.current.object_id]['mommacat']
|
408
409
|
end
|
409
410
|
|
410
411
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
411
412
|
def self.deploy_id;
|
413
|
+
@@globals[Thread.current.object_id] ||= {}
|
412
414
|
@@globals[Thread.current.object_id]['deploy_id']
|
413
415
|
end
|
414
416
|
|
415
417
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
416
418
|
def self.appname;
|
419
|
+
@@globals[Thread.current.object_id] ||= {}
|
417
420
|
@@globals[Thread.current.object_id]['appname']
|
418
421
|
end
|
419
422
|
|
420
423
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
421
424
|
def self.environment;
|
425
|
+
@@globals[Thread.current.object_id] ||= {}
|
422
426
|
@@globals[Thread.current.object_id]['environment']
|
423
427
|
end
|
424
428
|
|
425
429
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
426
430
|
def self.timestamp;
|
431
|
+
@@globals[Thread.current.object_id] ||= {}
|
427
432
|
@@globals[Thread.current.object_id]['timestamp']
|
428
433
|
end
|
429
434
|
|
430
435
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
431
436
|
def self.seed;
|
437
|
+
@@globals[Thread.current.object_id] ||= {}
|
432
438
|
@@globals[Thread.current.object_id]['seed']
|
433
439
|
end
|
434
440
|
|
435
441
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
436
442
|
def self.handle;
|
443
|
+
@@globals[Thread.current.object_id] ||= {}
|
437
444
|
@@globals[Thread.current.object_id]['handle']
|
438
445
|
end
|
439
446
|
|
440
447
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
441
448
|
def self.chef_user;
|
449
|
+
@@globals[Thread.current.object_id] ||= {}
|
442
450
|
if @@globals.has_key?(Thread.current.object_id) and @@globals[Thread.current.object_id].has_key?('chef_user')
|
443
451
|
@@globals[Thread.current.object_id]['chef_user']
|
444
452
|
elsif Etc.getpwuid(Process.uid).name == "root"
|
@@ -450,6 +458,7 @@ module MU
|
|
450
458
|
|
451
459
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
452
460
|
def self.mu_user
|
461
|
+
@@globals[Thread.current.object_id] ||= {}
|
453
462
|
if @@globals.has_key?(Thread.current.object_id) and @@globals[Thread.current.object_id].has_key?('mu_user')
|
454
463
|
return @@globals[Thread.current.object_id]['mu_user']
|
455
464
|
elsif Etc.getpwuid(Process.uid).name == "root"
|
@@ -461,11 +470,13 @@ module MU
|
|
461
470
|
|
462
471
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
463
472
|
def self.curRegion
|
473
|
+
@@globals[Thread.current.object_id] ||= {}
|
464
474
|
@@globals[Thread.current.object_id]['curRegion'] ||= myRegion || ENV['EC2_REGION']
|
465
475
|
end
|
466
476
|
|
467
477
|
# Accessor for per-thread global variable. There is probably a Ruby-clever way to define this.
|
468
478
|
def self.syncLitterThread;
|
479
|
+
@@globals[Thread.current.object_id] ||= {}
|
469
480
|
@@globals[Thread.current.object_id]['syncLitterThread']
|
470
481
|
end
|
471
482
|
|
@@ -487,26 +498,13 @@ module MU
|
|
487
498
|
end
|
488
499
|
end
|
489
500
|
|
490
|
-
#
|
501
|
+
# Return the verbosity setting of the default @@logger object
|
491
502
|
def self.verbosity
|
492
|
-
|
493
|
-
MU.setVar("verbosity", MU::Logger::NORMAL)
|
494
|
-
end
|
495
|
-
@@globals[Thread.current.object_id]['verbosity']
|
496
|
-
end
|
497
|
-
|
498
|
-
# The color logging flag merits a default value.
|
499
|
-
def self.color
|
500
|
-
if @@globals[Thread.current.object_id].nil? or @@globals[Thread.current.object_id]['color'].nil?
|
501
|
-
MU.setVar("color", true)
|
502
|
-
end
|
503
|
-
@@globals[Thread.current.object_id]['color']
|
503
|
+
@@logger ? @@logger.verbosity : MU::Logger::NORMAL
|
504
504
|
end
|
505
505
|
|
506
506
|
# Set parameters parameters for calls to {MU#log}
|
507
507
|
def self.setLogging(verbosity, webify_logs = false, handle = STDOUT, color = true)
|
508
|
-
MU.setVar("verbosity", verbosity)
|
509
|
-
MU.setVar("color", color)
|
510
508
|
@@logger ||= MU::Logger.new(verbosity, webify_logs, handle, color)
|
511
509
|
@@logger.html = webify_logs
|
512
510
|
@@logger.verbosity = verbosity
|
@@ -523,33 +521,25 @@ module MU
|
|
523
521
|
end
|
524
522
|
|
525
523
|
# Shortcut to invoke {MU::Logger#log}
|
526
|
-
def self.log(msg, level = MU::INFO, details: nil, html: false, verbosity:
|
527
|
-
return if (level == MU::DEBUG and verbosity <= MU::Logger::LOUD)
|
528
|
-
return if verbosity == MU::Logger::SILENT
|
524
|
+
def self.log(msg, level = MU::INFO, details: nil, html: false, verbosity: nil, color: true)
|
525
|
+
return if (level == MU::DEBUG and verbosity and verbosity <= MU::Logger::LOUD)
|
526
|
+
return if verbosity and verbosity == MU::Logger::SILENT
|
529
527
|
|
530
528
|
if (level == MU::ERR or
|
531
529
|
level == MU::WARN or
|
532
530
|
level == MU::DEBUG or
|
533
|
-
verbosity >= MU::Logger::LOUD or
|
534
|
-
(level == MU::NOTICE and !details.nil?)
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
:name => Thread.current.thread_variable_get("name")
|
543
|
-
}
|
544
|
-
end
|
545
|
-
if !details.nil?
|
546
|
-
extra = Hash.new if extra.nil?
|
547
|
-
extra[:details] = details
|
548
|
-
end
|
549
|
-
@@logger.log(msg, level, details: extra, verbosity: MU::Logger::LOUD, html: html, color: color)
|
550
|
-
else
|
551
|
-
@@logger.log(msg, level, html: html, verbosity: verbosity, color: color)
|
531
|
+
(verbosity and verbosity >= MU::Logger::LOUD) or
|
532
|
+
(level == MU::NOTICE and !details.nil?)) and
|
533
|
+
Thread.current.thread_variable_get("name")
|
534
|
+
newdetails = {
|
535
|
+
:thread => Thread.current.object_id,
|
536
|
+
:name => Thread.current.thread_variable_get("name")
|
537
|
+
}
|
538
|
+
newdetails[:details] = details.dup if details
|
539
|
+
details = newdetails
|
552
540
|
end
|
541
|
+
|
542
|
+
@@logger.log(msg, level, details: details, html: html, verbosity: verbosity, color: color)
|
553
543
|
end
|
554
544
|
|
555
545
|
# For log entries that should only be logged when we're in verbose mode
|
@@ -894,9 +884,11 @@ module MU
|
|
894
884
|
|
895
885
|
@@myCloudDescriptor = nil
|
896
886
|
if MU.myCloud
|
897
|
-
|
887
|
+
svrclass = const_get("MU").const_get("Cloud").const_get(MU.myCloud).const_get("Server")
|
888
|
+
found = svrclass.find(cloud_id: @@myInstanceId, region: MU.myRegion) # XXX need habitat arg for google et al
|
889
|
+
# found = MU::MommaCat.findStray(MU.myCloud, "server", cloud_id: @@myInstanceId, dummy_ok: true, region: MU.myRegion)
|
898
890
|
if !found.nil? and found.size == 1
|
899
|
-
@@myCloudDescriptor = found.first
|
891
|
+
@@myCloudDescriptor = found.values.first
|
900
892
|
end
|
901
893
|
end
|
902
894
|
|
data/modules/mu/cloud.rb
CHANGED
@@ -1351,6 +1351,8 @@ module MU
|
|
1351
1351
|
|
1352
1352
|
# Special dependencies: my containing VPC
|
1353
1353
|
if self.class.can_live_in_vpc and !@config['vpc'].nil?
|
1354
|
+
@config['vpc']["id"] ||= @config['vpc']["vpc_id"] # old deploys
|
1355
|
+
@config['vpc']["name"] ||= @config['vpc']["vpc_name"] # old deploys
|
1354
1356
|
# If something hash-ified a MU::Config::Ref here, fix it
|
1355
1357
|
if !@config['vpc']["id"].nil? and @config['vpc']["id"].is_a?(Hash)
|
1356
1358
|
@config['vpc']["id"] = MU::Config::Ref.new(@config['vpc']["id"])
|
@@ -1930,6 +1932,8 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1930
1932
|
session = nil
|
1931
1933
|
retries = 0
|
1932
1934
|
|
1935
|
+
vpc_class = Object.const_get("MU").const_get("Cloud").const_get(@cloud).const_get("VPC")
|
1936
|
+
|
1933
1937
|
# XXX WHY is this a thing
|
1934
1938
|
Thread.handle_interrupt(Errno::ECONNREFUSED => :never) {
|
1935
1939
|
}
|
@@ -1953,6 +1957,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1953
1957
|
:proxy => proxy
|
1954
1958
|
)
|
1955
1959
|
else
|
1960
|
+
|
1956
1961
|
MU.log "Attempting SSH to #{canonical_ip} (#{@mu_name}) as #{ssh_user} with key #{ssh_keydir}/#{@deploy.ssh_key_name}" if retries == 0
|
1957
1962
|
session = Net::SSH.start(
|
1958
1963
|
canonical_ip,
|
@@ -1986,9 +1991,14 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1986
1991
|
|
1987
1992
|
if retries < max_retries
|
1988
1993
|
retries = retries + 1
|
1989
|
-
msg = "ssh #{ssh_user}@#{@mu_name}: #{e.message}, waiting #{retry_interval}s (attempt #{retries}/#{max_retries})"
|
1994
|
+
msg = "ssh #{ssh_user}@#{@mu_name}: #{e.message}, waiting #{retry_interval}s (attempt #{retries}/#{max_retries})"
|
1990
1995
|
if retries == 1 or (retries/max_retries <= 0.5 and (retries % 3) == 0)
|
1991
1996
|
MU.log msg, MU::NOTICE
|
1997
|
+
if !vpc_class.haveRouteToInstance?(cloud_desc, credentials: @credentials) and
|
1998
|
+
canonical_ip.match(/(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])/) and
|
1999
|
+
!nat_ssh_host
|
2000
|
+
MU.log "Node #{@mu_name} at #{canonical_ip} looks like it's in a private address space, and I don't appear to have a direct route to it. It may not be possible to connect with this routing!", MU::WARN
|
2001
|
+
end
|
1992
2002
|
elsif retries/max_retries > 0.5
|
1993
2003
|
MU.log msg, MU::WARN, details: e.inspect
|
1994
2004
|
end
|
data/modules/mu/clouds/aws.rb
CHANGED
@@ -164,6 +164,7 @@ module MU
|
|
164
164
|
# @param r [String]
|
165
165
|
# @return [String]
|
166
166
|
def self.validate_region(r, credentials: nil)
|
167
|
+
require "aws-sdk-core"
|
167
168
|
begin
|
168
169
|
MU::Cloud::AWS.ec2(region: r, credentials: credentials).describe_availability_zones.availability_zones.first.region_name
|
169
170
|
rescue ::Aws::EC2::Errors::UnauthorizedOperation => e
|
@@ -207,15 +208,19 @@ module MU
|
|
207
208
|
MU.log "Created standard tags for resource #{resource}", MU::DEBUG, details: caller
|
208
209
|
end
|
209
210
|
|
211
|
+
@@myVPCObj = nil
|
212
|
+
|
210
213
|
# If we reside in this cloud, return the VPC in which we, the Mu Master, reside.
|
211
214
|
# @return [MU::Cloud::VPC]
|
212
215
|
def self.myVPCObj
|
216
|
+
return @@myVPCObj if @@myVPCObj
|
213
217
|
return nil if !hosted?
|
214
218
|
instance = MU.myCloudDescriptor
|
215
219
|
return nil if !instance or !instance.vpc_id
|
216
|
-
vpc = MU::MommaCat.findStray("AWS", "vpc", cloud_id: instance.vpc_id, dummy_ok: true)
|
220
|
+
vpc = MU::MommaCat.findStray("AWS", "vpc", cloud_id: instance.vpc_id, dummy_ok: true, no_deploy_search: true)
|
217
221
|
return nil if vpc.nil? or vpc.size == 0
|
218
|
-
vpc.first
|
222
|
+
@@myVPCObj = vpc.first
|
223
|
+
@@myVPCObj
|
219
224
|
end
|
220
225
|
|
221
226
|
# If we've configured AWS as a provider, or are simply hosted in AWS,
|
@@ -1334,8 +1339,8 @@ module MU
|
|
1334
1339
|
# @param region [String]: Amazon region so we know what endpoint to use
|
1335
1340
|
# @param api [String]: Which API are we wrapping?
|
1336
1341
|
def initialize(region: MU.curRegion, api: "EC2", credentials: nil)
|
1337
|
-
@cred_obj = MU::Cloud::AWS.loadCredentials(credentials)
|
1338
1342
|
@credentials = MU::Cloud::AWS.credConfig(credentials, name_only: true)
|
1343
|
+
@cred_obj = MU::Cloud::AWS.loadCredentials(credentials)
|
1339
1344
|
|
1340
1345
|
if !@cred_obj
|
1341
1346
|
raise MuError, "Unable to locate valid AWS credentials for #{api} API. #{credentials ? "Credentials requested were '#{credentials}'": ""}"
|
@@ -147,12 +147,9 @@ module MU
|
|
147
147
|
end
|
148
148
|
|
149
149
|
# Locate an existing alarm.
|
150
|
-
# @param cloud_id [String]: The cloud provider's identifier for this resource.
|
151
|
-
# @param region [String]: The cloud provider region.
|
152
|
-
# @param flags [Hash]: Optional flags
|
153
150
|
# @return [OpenStruct]: The cloud provider's complete descriptions of matching alarm.
|
154
|
-
def self.find(
|
155
|
-
MU::Cloud::AWS::Alarm.getAlarmByName(cloud_id, region: region, credentials: credentials)
|
151
|
+
def self.find(**args)
|
152
|
+
MU::Cloud::AWS::Alarm.getAlarmByName(args[:cloud_id], region: args[:region], credentials: args[:credentials])
|
156
153
|
end
|
157
154
|
|
158
155
|
# Create an alarm.
|
@@ -260,13 +257,13 @@ module MU
|
|
260
257
|
alarm["dimensions"] ||= []
|
261
258
|
|
262
259
|
if alarm["#TARGETCLASS"] == "cache_cluster"
|
263
|
-
alarm['dimensions'] << { "name" => alarm["#
|
260
|
+
alarm['dimensions'] << { "name" => alarm["#TARGETNAME"], "cloud_class" => "CacheClusterId" }
|
264
261
|
alarm["namespace"] = "AWS/ElastiCache" if alarm["namespace"].nil?
|
265
262
|
elsif alarm["#TARGETCLASS"] == "server"
|
266
|
-
alarm['dimensions'] << { "name" => alarm["#
|
263
|
+
alarm['dimensions'] << { "name" => alarm["#TARGETNAME"], "cloud_class" => "InstanceId" }
|
267
264
|
alarm["namespace"] = "AWS/EC2" if alarm["namespace"].nil?
|
268
265
|
elsif alarm["#TARGETCLASS"] == "database"
|
269
|
-
alarm['dimensions'] << { "name" => alarm["#
|
266
|
+
alarm['dimensions'] << { "name" => alarm["#TARGETNAME"], "cloud_class" => "DBInstanceIdentifier" }
|
270
267
|
alarm["namespace"] = "AWS/RDS" if alarm["namespace"].nil?
|
271
268
|
end
|
272
269
|
|
@@ -33,11 +33,17 @@ module MU
|
|
33
33
|
bucket_name = @deploy.getResourceName(@config["name"], max_length: 63).downcase
|
34
34
|
|
35
35
|
MU.log "Creating S3 bucket #{bucket_name}"
|
36
|
-
MU::Cloud::AWS.s3(credentials: @config['credentials'], region: @config['region']).create_bucket(
|
36
|
+
resp = MU::Cloud::AWS.s3(credentials: @config['credentials'], region: @config['region']).create_bucket(
|
37
37
|
acl: @config['acl'],
|
38
38
|
bucket: bucket_name
|
39
39
|
)
|
40
|
+
|
40
41
|
@cloud_id = bucket_name
|
42
|
+
is_live = MU::Cloud::AWS::Bucket.find(cloud_id: @cloud_id, region: @config['region'], credentials: @credentials).values.first
|
43
|
+
begin
|
44
|
+
is_live = MU::Cloud::AWS::Bucket.find(cloud_id: @cloud_id, region: @config['region'], credentials: @credentials).values.first
|
45
|
+
sleep 3
|
46
|
+
end while !is_live
|
41
47
|
|
42
48
|
@@region_cache_semaphore.synchronize {
|
43
49
|
@@region_cache[@cloud_id] ||= @config['region']
|
@@ -216,7 +222,7 @@ puts path
|
|
216
222
|
else
|
217
223
|
@@region_cache[bucket.name] = location
|
218
224
|
end
|
219
|
-
rescue Aws::S3::Errors::AccessDenied
|
225
|
+
rescue Aws::S3::Errors::NoSuchBucket, Aws::S3::Errors::AccessDenied
|
220
226
|
# this is routine- we saw a bucket that's not our business
|
221
227
|
next
|
222
228
|
end
|
@@ -261,14 +267,14 @@ puts path
|
|
261
267
|
end
|
262
268
|
|
263
269
|
# Locate an existing bucket.
|
264
|
-
# @
|
265
|
-
|
266
|
-
# @param flags [Hash]: Optional flags
|
267
|
-
# @return [OpenStruct]: The cloud provider's complete descriptions of matching bucket.
|
268
|
-
def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
|
270
|
+
# @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching bucket.
|
271
|
+
def self.find(**args)
|
269
272
|
found = {}
|
270
|
-
if cloud_id
|
271
|
-
|
273
|
+
if args[:cloud_id]
|
274
|
+
begin
|
275
|
+
found[args[:cloud_id]] = describe_bucket(args[:cloud_id], minimal: true, credentials: args[:credentials], region: args[:region])
|
276
|
+
rescue ::Aws::S3::Errors::NoSuchBucket
|
277
|
+
end
|
272
278
|
end
|
273
279
|
found
|
274
280
|
end
|
@@ -39,27 +39,22 @@ module MU
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# Locate an existing Cache Cluster or Cache Clusters and return an array containing matching AWS resource descriptors for those that match.
|
42
|
-
# @
|
43
|
-
|
44
|
-
# @param tag_key [String]: A tag key to search.
|
45
|
-
# @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
|
46
|
-
# @param flags [Hash]: Optional flags
|
47
|
-
# @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching Cache Clusters.
|
48
|
-
def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
|
42
|
+
# @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching Cache Clusters.
|
43
|
+
def self.find(**args)
|
49
44
|
map = {}
|
50
|
-
if cloud_id
|
51
|
-
cache_cluster = MU::Cloud::AWS::CacheCluster.getCacheClusterById(cloud_id, region: region)
|
52
|
-
map[cloud_id] = cache_cluster if cache_cluster
|
45
|
+
if args[:cloud_id]
|
46
|
+
cache_cluster = MU::Cloud::AWS::CacheCluster.getCacheClusterById(args[:cloud_id], region: args[:region], credentials: args[:credentials])
|
47
|
+
map[args[:cloud_id]] = cache_cluster if cache_cluster
|
53
48
|
end
|
54
49
|
|
55
|
-
if tag_value
|
56
|
-
MU::Cloud::AWS.elasticache(region: region, credentials: credentials).describe_cache_clusters.cache_clusters.each { |cc|
|
57
|
-
resp = MU::Cloud::AWS.elasticache(region: region, credentials: credentials).list_tags_for_resource(
|
58
|
-
resource_name: MU::Cloud::AWS::CacheCluster.getARN(cc.cache_cluster_id, "cluster", "elasticache", region: region, credentials: credentials)
|
50
|
+
if args[:tag_value]
|
51
|
+
MU::Cloud::AWS.elasticache(region: args[:region], credentials: args[:credentials]).describe_cache_clusters.cache_clusters.each { |cc|
|
52
|
+
resp = MU::Cloud::AWS.elasticache(region: args[:region], credentials: args[:credentials]).list_tags_for_resource(
|
53
|
+
resource_name: MU::Cloud::AWS::CacheCluster.getARN(cc.cache_cluster_id, "cluster", "elasticache", region: args[:region], credentials: args[:credentials])
|
59
54
|
)
|
60
55
|
if resp && resp.tag_list && !resp.tag_list.empty?
|
61
56
|
resp.tag_list.each { |tag|
|
62
|
-
map[cc.cache_cluster_id] = cc if tag.key == tag_key and tag.value == tag_value
|
57
|
+
map[cc.cache_cluster_id] = cc if tag.key == args[:tag_key] and tag.value == args[:tag_value]
|
63
58
|
}
|
64
59
|
end
|
65
60
|
}
|
@@ -222,14 +217,25 @@ module MU
|
|
222
217
|
@cloud_id = resp.replication_group_id
|
223
218
|
else
|
224
219
|
config_struct[:cache_cluster_id] = @config['identifier']
|
225
|
-
config_struct[:az_mode] = @config["
|
220
|
+
config_struct[:az_mode] = @config["multi_az"] ? "cross-az" : "single-az"
|
226
221
|
config_struct[:num_cache_nodes] = @config["node_count"]
|
227
222
|
# config_struct[:replication_group_id] = @config["replication_group_id"] if @config["replication_group_id"]
|
228
223
|
# config_struct[:preferred_availability_zone] = @config["preferred_availability_zone"] if @config["preferred_availability_zone"] && @config["az_mode"] == "single-az"
|
229
224
|
# config_struct[:preferred_availability_zones] = @config["preferred_availability_zones"] if @config["preferred_availability_zones"] && @config["az_mode"] == "cross-az"
|
230
225
|
|
231
226
|
MU.log "Creating cache cluster #{@config['identifier']}"
|
232
|
-
|
227
|
+
begin
|
228
|
+
resp = MU::Cloud::AWS.elasticache(region: @config['region'], credentials: @config['credentials']).create_cache_cluster(config_struct).cache_cluster
|
229
|
+
rescue ::Aws::ElastiCache::Errors::InvalidParameterValue => e
|
230
|
+
if e.message.match(/security group (sg-[^\s]+)/)
|
231
|
+
bad_sg = Regexp.last_match[1]
|
232
|
+
MU.log "Removing invalid security group #{bad_sg} from Cache Cluster #{@mu_name}", MU::WARN, details: e.message
|
233
|
+
config_struct[:security_group_ids].delete(bad_sg)
|
234
|
+
retry
|
235
|
+
else
|
236
|
+
raise e
|
237
|
+
end
|
238
|
+
end
|
233
239
|
|
234
240
|
wait_start_time = Time.now
|
235
241
|
retries = 0
|
@@ -260,7 +266,6 @@ module MU
|
|
260
266
|
# Create a subnet group for a Cache Cluster with the given config.
|
261
267
|
def createSubnetGroup
|
262
268
|
subnet_ids = []
|
263
|
-
|
264
269
|
if @config["vpc"] && !@config["vpc"].empty?
|
265
270
|
raise MuError, "Didn't find the VPC specified in #{@config["vpc"]}" unless @vpc
|
266
271
|
|
@@ -306,8 +311,8 @@ module MU
|
|
306
311
|
}
|
307
312
|
|
308
313
|
@config['vpc'] = {
|
309
|
-
|
310
|
-
|
314
|
+
"vpc_id" => vpc_id,
|
315
|
+
"subnets" => mu_subnets
|
311
316
|
}
|
312
317
|
using_default_vpc = true
|
313
318
|
MU.log "Using default VPC for cache cluster #{@config['identifier']}"
|
@@ -346,8 +351,8 @@ module MU
|
|
346
351
|
|
347
352
|
if @dependencies.has_key?('firewall_rule')
|
348
353
|
@config["security_group_ids"] = []
|
349
|
-
|
350
|
-
|
354
|
+
@dependencies['firewall_rule'].values.each { |sg|
|
355
|
+
@config["security_group_ids"] << sg.cloud_id
|
351
356
|
}
|
352
357
|
end
|
353
358
|
end
|
@@ -691,6 +696,10 @@ module MU
|
|
691
696
|
def self.schema(config)
|
692
697
|
toplevel_required = []
|
693
698
|
schema = {
|
699
|
+
"create_replication_group" => {
|
700
|
+
"type" => "boolean",
|
701
|
+
"description" => "Create a replication group; will be set automatically if +engine+ is +redis+ and +node_count+ is greated than one."
|
702
|
+
},
|
694
703
|
"ingress_rules" => {
|
695
704
|
"items" => {
|
696
705
|
"properties" => {
|
@@ -722,6 +731,32 @@ module MU
|
|
722
731
|
def self.validateConfig(cache, configurator)
|
723
732
|
ok = true
|
724
733
|
|
734
|
+
if !cache['vpc']
|
735
|
+
siblings = configurator.haveLitterMate?(nil, "vpcs", has_multiple: true)
|
736
|
+
if siblings.size == 1
|
737
|
+
MU.log "CacheCluster #{cache['name']} did not declare a VPC. Inserting into sibling VPC #{siblings[0]['name']}.", MU::WARN
|
738
|
+
cache["vpc"] = {
|
739
|
+
"name" => siblings[0]['name'],
|
740
|
+
"subnet_pref" => "all_private"
|
741
|
+
}
|
742
|
+
elsif MU::Cloud::AWS.hosted? and MU::Cloud::AWS.myVPCObj
|
743
|
+
cache["vpc"] = {
|
744
|
+
"id" => MU.myVPC,
|
745
|
+
"subnet_pref" => "all_private"
|
746
|
+
}
|
747
|
+
else
|
748
|
+
MU.log "CacheCluster #{cache['name']} must declare a VPC", MU::ERR
|
749
|
+
ok = false
|
750
|
+
end
|
751
|
+
|
752
|
+
# Re-insert ourselves with this modification so that our child
|
753
|
+
# resources get this VPC we just shoved in
|
754
|
+
if ok and cache['vpc']
|
755
|
+
cache.delete("#MU_VALIDATED")
|
756
|
+
return configurator.insertKitten(cache, "cache_clusters", overwrite: true)
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
725
760
|
if cache.has_key?("parameter_group_parameters") && cache["parameter_group_family"].nil?
|
726
761
|
MU.log "parameter_group_family must be set when setting parameter_group_parameters", MU::ERR
|
727
762
|
ok = false
|
@@ -743,7 +778,6 @@ module MU
|
|
743
778
|
end
|
744
779
|
elsif cache["engine"] == "memcached"
|
745
780
|
cache["create_replication_group"] = false
|
746
|
-
cache["az_mode"] = cache["multi_az"] ? "cross-az" : "single-az"
|
747
781
|
|
748
782
|
if cache["node_count"] > 20
|
749
783
|
MU.log "#{cache['engine']} supports up to 20 nodes per cache cluster", MU::ERR
|
@@ -868,7 +902,7 @@ module MU
|
|
868
902
|
# @param region [String]: The cloud provider's region in which to operate.
|
869
903
|
# @param cloud_id [String]: The cloud provider's identifier for this resource.
|
870
904
|
# @return [void]
|
871
|
-
def self.terminate_replication_group(repl_group, noop: false, skipsnapshots: false, region: MU.curRegion, deploy_id: MU.deploy_id, mu_name: nil, cloud_id: nil)
|
905
|
+
def self.terminate_replication_group(repl_group, noop: false, skipsnapshots: false, region: MU.curRegion, deploy_id: MU.deploy_id, mu_name: nil, cloud_id: nil, credentials: nil)
|
872
906
|
raise MuError, "terminate_replication_group requires a non-nil cache replication group descriptor" if repl_group.nil? || repl_group.empty?
|
873
907
|
|
874
908
|
repl_group_id = repl_group.replication_group_id
|
@@ -908,9 +942,9 @@ module MU
|
|
908
942
|
)
|
909
943
|
end
|
910
944
|
|
911
|
-
def self.createSnap(repl_group_id, region)
|
945
|
+
def self.createSnap(repl_group_id, region, credentials)
|
912
946
|
MU.log "Terminating #{repl_group_id}. Final snapshot name: #{repl_group_id}-mufinal"
|
913
|
-
MU::Cloud::AWS.elasticache(region: region).delete_replication_group(
|
947
|
+
MU::Cloud::AWS.elasticache(region: region, credentials: credentials).delete_replication_group(
|
914
948
|
replication_group_id: repl_group_id,
|
915
949
|
retain_primary_cluster: false,
|
916
950
|
final_snapshot_identifier: "#{repl_group_id}-mufinal"
|