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.
- 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"
|