cloud-mu 3.1.3 → 3.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +10 -2
- data/bin/mu-adopt +5 -1
- data/bin/mu-load-config.rb +2 -3
- data/bin/mu-run-tests +112 -27
- data/cloud-mu.gemspec +20 -20
- data/cookbooks/mu-tools/libraries/helper.rb +2 -1
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +5 -15
- data/modules/mu.rb +10 -14
- data/modules/mu/adoption.rb +20 -14
- data/modules/mu/cleanup.rb +13 -9
- data/modules/mu/cloud.rb +26 -26
- data/modules/mu/clouds/aws.rb +100 -59
- data/modules/mu/clouds/aws/alarm.rb +4 -2
- data/modules/mu/clouds/aws/bucket.rb +25 -21
- data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
- data/modules/mu/clouds/aws/collection.rb +21 -20
- data/modules/mu/clouds/aws/container_cluster.rb +47 -26
- data/modules/mu/clouds/aws/database.rb +57 -68
- data/modules/mu/clouds/aws/dnszone.rb +14 -14
- data/modules/mu/clouds/aws/endpoint.rb +20 -16
- data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
- data/modules/mu/clouds/aws/folder.rb +7 -7
- data/modules/mu/clouds/aws/function.rb +15 -12
- data/modules/mu/clouds/aws/group.rb +14 -10
- data/modules/mu/clouds/aws/habitat.rb +16 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
- data/modules/mu/clouds/aws/log.rb +13 -10
- data/modules/mu/clouds/aws/msg_queue.rb +15 -8
- data/modules/mu/clouds/aws/nosqldb.rb +18 -11
- data/modules/mu/clouds/aws/notifier.rb +11 -6
- data/modules/mu/clouds/aws/role.rb +87 -70
- data/modules/mu/clouds/aws/search_domain.rb +30 -19
- data/modules/mu/clouds/aws/server.rb +102 -72
- data/modules/mu/clouds/aws/server_pool.rb +47 -28
- data/modules/mu/clouds/aws/storage_pool.rb +5 -6
- data/modules/mu/clouds/aws/user.rb +13 -10
- data/modules/mu/clouds/aws/vpc.rb +135 -121
- data/modules/mu/clouds/azure.rb +16 -9
- data/modules/mu/clouds/azure/container_cluster.rb +2 -3
- data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
- data/modules/mu/clouds/azure/habitat.rb +8 -6
- data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
- data/modules/mu/clouds/azure/role.rb +8 -10
- data/modules/mu/clouds/azure/server.rb +65 -25
- data/modules/mu/clouds/azure/user.rb +5 -7
- data/modules/mu/clouds/azure/vpc.rb +12 -15
- data/modules/mu/clouds/cloudformation.rb +8 -7
- data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
- data/modules/mu/clouds/google.rb +39 -24
- data/modules/mu/clouds/google/bucket.rb +9 -11
- data/modules/mu/clouds/google/container_cluster.rb +27 -42
- data/modules/mu/clouds/google/database.rb +6 -9
- data/modules/mu/clouds/google/firewall_rule.rb +11 -10
- data/modules/mu/clouds/google/folder.rb +16 -9
- data/modules/mu/clouds/google/function.rb +127 -161
- data/modules/mu/clouds/google/group.rb +21 -18
- data/modules/mu/clouds/google/habitat.rb +18 -15
- data/modules/mu/clouds/google/loadbalancer.rb +14 -16
- data/modules/mu/clouds/google/role.rb +48 -31
- data/modules/mu/clouds/google/server.rb +105 -105
- data/modules/mu/clouds/google/server_pool.rb +12 -31
- data/modules/mu/clouds/google/user.rb +67 -13
- data/modules/mu/clouds/google/vpc.rb +58 -65
- data/modules/mu/config.rb +89 -1738
- data/modules/mu/config/bucket.rb +3 -3
- data/modules/mu/config/collection.rb +3 -3
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/dnszone.rb +5 -5
- data/modules/mu/config/doc_helpers.rb +517 -0
- data/modules/mu/config/endpoint.rb +3 -3
- data/modules/mu/config/firewall_rule.rb +118 -3
- data/modules/mu/config/folder.rb +3 -3
- data/modules/mu/config/function.rb +2 -2
- data/modules/mu/config/group.rb +3 -3
- data/modules/mu/config/habitat.rb +3 -3
- data/modules/mu/config/loadbalancer.rb +3 -3
- data/modules/mu/config/log.rb +3 -3
- data/modules/mu/config/msg_queue.rb +3 -3
- data/modules/mu/config/nosqldb.rb +3 -3
- data/modules/mu/config/notifier.rb +2 -2
- data/modules/mu/config/ref.rb +333 -0
- data/modules/mu/config/role.rb +3 -3
- data/modules/mu/config/schema_helpers.rb +508 -0
- data/modules/mu/config/search_domain.rb +3 -3
- data/modules/mu/config/server.rb +86 -58
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/tail.rb +189 -0
- data/modules/mu/config/user.rb +3 -3
- data/modules/mu/config/vpc.rb +44 -4
- data/modules/mu/defaults/Google.yaml +2 -2
- data/modules/mu/deploy.rb +13 -10
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -24
- data/modules/mu/groomers/chef.rb +52 -44
- data/modules/mu/logger.rb +17 -14
- data/modules/mu/master.rb +317 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -2
- data/modules/mu/mommacat.rb +85 -1766
- data/modules/mu/mommacat/daemon.rb +394 -0
- data/modules/mu/mommacat/naming.rb +366 -0
- data/modules/mu/mommacat/storage.rb +689 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- metadata +112 -102
data/modules/mu/logger.rb
CHANGED
@@ -66,13 +66,16 @@ module MU
|
|
66
66
|
def log(msg,
|
67
67
|
level=INFO,
|
68
68
|
details: nil,
|
69
|
-
html:
|
70
|
-
verbosity:
|
71
|
-
handle:
|
72
|
-
color:
|
69
|
+
html: nil,
|
70
|
+
verbosity: nil,
|
71
|
+
handle: nil,
|
72
|
+
color: nil,
|
73
73
|
deploy: MU.mommacat
|
74
74
|
)
|
75
75
|
verbosity ||= @verbosity
|
76
|
+
html ||= @html
|
77
|
+
handle ||= @handle
|
78
|
+
color ||= @color
|
76
79
|
return if verbosity == MU::Logger::SILENT
|
77
80
|
return if verbosity < MU::Logger::LOUD and level == DEBUG
|
78
81
|
return if verbosity < MU::Logger::NORMAL and level == INFO
|
@@ -101,7 +104,7 @@ module MU
|
|
101
104
|
end
|
102
105
|
details = PP.pp(details, '') if !details.is_a?(String)
|
103
106
|
end
|
104
|
-
details = "<pre>"+details+"</pre>" if
|
107
|
+
details = "<pre>"+details+"</pre>" if html
|
105
108
|
# We get passed literal quoted newlines sometimes, fix 'em. Get Windows'
|
106
109
|
# ugly line feeds too.
|
107
110
|
if !details.nil?
|
@@ -139,7 +142,7 @@ module MU
|
|
139
142
|
@summary << msg
|
140
143
|
when DEBUG
|
141
144
|
if verbosity >= MU::Logger::LOUD
|
142
|
-
if
|
145
|
+
if html
|
143
146
|
html_out "#{time} - #{caller_name} - #{msg}", "orange"
|
144
147
|
html_out " #{details}" if details
|
145
148
|
elsif color
|
@@ -154,7 +157,7 @@ module MU
|
|
154
157
|
end
|
155
158
|
when INFO
|
156
159
|
if verbosity >= MU::Logger::NORMAL
|
157
|
-
if
|
160
|
+
if html
|
158
161
|
html_out "#{time} - #{caller_name} - #{msg}", "green"
|
159
162
|
elsif color
|
160
163
|
msgs << "#{time} - #{caller_name} - #{msg}".green.on_black
|
@@ -162,7 +165,7 @@ module MU
|
|
162
165
|
msgs << "#{time} - #{caller_name} - #{msg}"
|
163
166
|
end
|
164
167
|
if verbosity >= MU::Logger::LOUD
|
165
|
-
if
|
168
|
+
if html
|
166
169
|
html_out " #{details}"
|
167
170
|
elsif color
|
168
171
|
msgs << "#{details}".white.on_black if details
|
@@ -174,7 +177,7 @@ module MU
|
|
174
177
|
Syslog.log(Syslog::LOG_NOTICE, details.gsub(/%/, '')) if details
|
175
178
|
end
|
176
179
|
when NOTICE
|
177
|
-
if
|
180
|
+
if html
|
178
181
|
html_out "#{time} - #{caller_name} - #{msg}", "yellow"
|
179
182
|
elsif color
|
180
183
|
msgs << "#{time} - #{caller_name} - #{msg}".yellow.on_black
|
@@ -182,7 +185,7 @@ module MU
|
|
182
185
|
msgs << "#{time} - #{caller_name} - #{msg}"
|
183
186
|
end
|
184
187
|
if verbosity >= MU::Logger::QUIET
|
185
|
-
if
|
188
|
+
if html
|
186
189
|
html_out "#{caller_name} - #{msg}"
|
187
190
|
elsif color
|
188
191
|
msgs << "#{details}".white.on_black if details
|
@@ -193,7 +196,7 @@ module MU
|
|
193
196
|
Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
194
197
|
Syslog.log(Syslog::LOG_NOTICE, details.gsub(/%/, '')) if details
|
195
198
|
when WARN
|
196
|
-
if
|
199
|
+
if html
|
197
200
|
html_out "#{time} - #{caller_name} - #{msg}", "orange"
|
198
201
|
elsif color
|
199
202
|
msgs << "#{time} - #{caller_name} - #{msg}".light_red.on_black
|
@@ -201,7 +204,7 @@ module MU
|
|
201
204
|
msgs << "#{time} - #{caller_name} - #{msg}"
|
202
205
|
end
|
203
206
|
if verbosity >= MU::Logger::SILENT
|
204
|
-
if
|
207
|
+
if html
|
205
208
|
html_out "#{caller_name} - #{msg}"
|
206
209
|
elsif color
|
207
210
|
msgs << "#{details}".white.on_black if details
|
@@ -212,7 +215,7 @@ module MU
|
|
212
215
|
Syslog.log(Syslog::LOG_WARNING, msg.gsub(/%/, ''))
|
213
216
|
Syslog.log(Syslog::LOG_WARNING, details.gsub(/%/, '')) if details
|
214
217
|
when ERR
|
215
|
-
if
|
218
|
+
if html
|
216
219
|
html_out "#{time} - #{caller_name} - #{msg}", "red"
|
217
220
|
html_out " #{details}" if details
|
218
221
|
elsif color
|
@@ -225,7 +228,7 @@ module MU
|
|
225
228
|
Syslog.log(Syslog::LOG_ERR, msg.gsub(/%/, ''))
|
226
229
|
Syslog.log(Syslog::LOG_ERR, details.gsub(/%/, '')) if details
|
227
230
|
else
|
228
|
-
if
|
231
|
+
if html
|
229
232
|
html_out "#{time} - #{caller_name} - #{msg}"
|
230
233
|
html_out " #{details}" if details
|
231
234
|
elsif color
|
data/modules/mu/master.rb
CHANGED
@@ -24,6 +24,12 @@ module MU
|
|
24
24
|
autoload :LDAP, 'mu/master/ldap'
|
25
25
|
autoload :SSL, 'mu/master/ssl'
|
26
26
|
|
27
|
+
# Home directory of the invoking user
|
28
|
+
MY_HOME = Etc.getpwuid(Process.uid).dir
|
29
|
+
|
30
|
+
# Home directory of the Nagios user, if we're in a non-gem context
|
31
|
+
NAGIOS_HOME = "/opt/mu/var/nagios_user_home" # XXX gross
|
32
|
+
|
27
33
|
# @param users [Hash]: User metadata of the type returned by listUsers
|
28
34
|
def self.printUsersToTerminal(users = MU::Master.listUsers)
|
29
35
|
labeled = false
|
@@ -228,7 +234,7 @@ module MU
|
|
228
234
|
begin
|
229
235
|
resp = MU::Cloud::AWS.s3.get_object(bucket: MU.adminBucketName, key: cryptfile)
|
230
236
|
body = resp.body
|
231
|
-
rescue
|
237
|
+
rescue StandardError => e
|
232
238
|
MU.log "Failed to fetch #{cryptfile} from S3 bucket #{MU.adminBucketName}", MU::ERR, details: e.inspect
|
233
239
|
%x{/bin/dd if=/dev/urandom of=#{temp_dev} bs=1M count=1 > /dev/null 2>&1}
|
234
240
|
raise e
|
@@ -236,7 +242,7 @@ module MU
|
|
236
242
|
elsif MU::Cloud::Google.hosted?
|
237
243
|
begin
|
238
244
|
body = MU::Cloud::Google.storage.get_object(MU.adminBucketName, cryptfile)
|
239
|
-
rescue
|
245
|
+
rescue StandardError => e
|
240
246
|
MU.log "Failed to fetch #{cryptfile} from Cloud Storage bucket #{MU.adminBucketName}", MU::ERR, details: e.inspect
|
241
247
|
%x{/bin/dd if=/dev/urandom of=#{temp_dev} bs=1M count=1 > /dev/null 2>&1}
|
242
248
|
raise e
|
@@ -493,5 +499,314 @@ module MU
|
|
493
499
|
end
|
494
500
|
end
|
495
501
|
|
502
|
+
# Clean a node's entries out of /etc/hosts
|
503
|
+
# @param node [String]: The node's name
|
504
|
+
# @return [void]
|
505
|
+
def self.removeInstanceFromEtcHosts(node)
|
506
|
+
return if MU.mu_user != "mu"
|
507
|
+
hostsfile = "/etc/hosts"
|
508
|
+
FileUtils.copy(hostsfile, "#{hostsfile}.bak-#{MU.deploy_id}")
|
509
|
+
File.open(hostsfile, File::CREAT|File::RDWR, 0644) { |f|
|
510
|
+
f.flock(File::LOCK_EX)
|
511
|
+
newlines = Array.new
|
512
|
+
f.readlines.each { |line|
|
513
|
+
newlines << line if !line.match(/ #{node}(\s|$)/)
|
514
|
+
}
|
515
|
+
f.rewind
|
516
|
+
f.truncate(0)
|
517
|
+
f.puts(newlines)
|
518
|
+
f.flush
|
519
|
+
|
520
|
+
f.flock(File::LOCK_UN)
|
521
|
+
}
|
522
|
+
end
|
523
|
+
|
524
|
+
|
525
|
+
# Insert node names associated with a new instance into /etc/hosts so we
|
526
|
+
# can treat them as if they were real DNS entries. Especially helpful when
|
527
|
+
# Chef/Ohai mistake the proper hostname, e.g. when bootstrapping Windows.
|
528
|
+
# @param public_ip [String]: The node's IP address
|
529
|
+
# @param chef_name [String]: The node's Chef node name
|
530
|
+
# @param system_name [String]: The node's local system name
|
531
|
+
# @return [void]
|
532
|
+
def self.addInstanceToEtcHosts(public_ip, chef_name = nil, system_name = nil)
|
533
|
+
|
534
|
+
# XXX cover ipv6 case
|
535
|
+
if public_ip.nil? or !public_ip.match(/^\d+\.\d+\.\d+\.\d+$/) or (chef_name.nil? and system_name.nil?)
|
536
|
+
raise MuError, "addInstanceToEtcHosts requires public_ip and one or both of chef_name and system_name!"
|
537
|
+
end
|
538
|
+
if chef_name == "localhost" or system_name == "localhost"
|
539
|
+
raise MuError, "Can't set localhost as a name in addInstanceToEtcHosts"
|
540
|
+
end
|
541
|
+
|
542
|
+
if !["mu", "root"].include?(MU.mu_user)
|
543
|
+
response = nil
|
544
|
+
begin
|
545
|
+
response = open("https://127.0.0.1:#{MU.mommaCatPort.to_s}/rest/hosts_add/#{chef_name}/#{public_ip}").read
|
546
|
+
rescue Errno::ECONNRESET, Errno::ECONNREFUSED
|
547
|
+
end
|
548
|
+
if response != "ok"
|
549
|
+
MU.log "Error adding #{public_ip} to /etc/hosts via MommaCat request", MU::ERR
|
550
|
+
end
|
551
|
+
return
|
552
|
+
end
|
553
|
+
|
554
|
+
File.readlines("/etc/hosts").each { |line|
|
555
|
+
if line.match(/^#{public_ip} /) or (chef_name != nil and line.match(/ #{chef_name}(\s|$)/)) or (system_name != nil and line.match(/ #{system_name}(\s|$)/))
|
556
|
+
MU.log "Ignoring attempt to add duplicate /etc/hosts entry: #{public_ip} #{chef_name} #{system_name}", MU::DEBUG
|
557
|
+
return
|
558
|
+
end
|
559
|
+
}
|
560
|
+
File.open("/etc/hosts", 'a') { |etc_hosts|
|
561
|
+
etc_hosts.flock(File::LOCK_EX)
|
562
|
+
etc_hosts.puts("#{public_ip} #{chef_name} #{system_name}")
|
563
|
+
etc_hosts.flock(File::LOCK_UN)
|
564
|
+
}
|
565
|
+
MU.log("Added to /etc/hosts: #{public_ip} #{chef_name} #{system_name}")
|
566
|
+
end
|
567
|
+
|
568
|
+
@ssh_semaphore = Mutex.new
|
569
|
+
# Insert a definition for a node into our SSH config.
|
570
|
+
# @param server [MU::Cloud::Server]: The name of the node.
|
571
|
+
# @param names [Array<String>]: Other names that we'd like this host to be known by for SSH purposes
|
572
|
+
# @param ssh_dir [String]: The configuration directory of the SSH config to emit.
|
573
|
+
# @param ssh_conf [String]: A specific SSH configuration file to write entries into.
|
574
|
+
# @param ssh_owner [String]: The preferred owner of the SSH configuration files.
|
575
|
+
# @param timeout [Integer]: An alternate timeout value for connections to this server.
|
576
|
+
# @return [void]
|
577
|
+
def self.addHostToSSHConfig(server,
|
578
|
+
ssh_dir: "#{Etc.getpwuid(Process.uid).dir}/.ssh",
|
579
|
+
ssh_conf: "#{Etc.getpwuid(Process.uid).dir}/.ssh/config",
|
580
|
+
ssh_owner: Etc.getpwuid(Process.uid).name,
|
581
|
+
names: [],
|
582
|
+
timeout: 0
|
583
|
+
)
|
584
|
+
if server.nil?
|
585
|
+
MU.log "Called addHostToSSHConfig without a MU::Cloud::Server object", MU::ERR, details: caller
|
586
|
+
return nil
|
587
|
+
end
|
588
|
+
|
589
|
+
_nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = begin
|
590
|
+
server.getSSHConfig
|
591
|
+
rescue MU::MuError
|
592
|
+
return
|
593
|
+
end
|
594
|
+
|
595
|
+
if ssh_user.nil? or ssh_user.empty?
|
596
|
+
MU.log "Failed to extract ssh_user for #{server.mu_name} addHostToSSHConfig", MU::ERR
|
597
|
+
return
|
598
|
+
end
|
599
|
+
if canonical_ip.nil? or canonical_ip.empty?
|
600
|
+
MU.log "Failed to extract canonical_ip for #{server.mu_name} addHostToSSHConfig", MU::ERR
|
601
|
+
return
|
602
|
+
end
|
603
|
+
if ssh_key_name.nil? or ssh_key_name.empty?
|
604
|
+
MU.log "Failed to extract ssh_key_name for #{ssh_key_name.mu_name} in addHostToSSHConfig", MU::ERR
|
605
|
+
return
|
606
|
+
end
|
607
|
+
|
608
|
+
@ssh_semaphore.synchronize {
|
609
|
+
|
610
|
+
if File.exist?(ssh_conf)
|
611
|
+
File.readlines(ssh_conf).each { |line|
|
612
|
+
if line.match(/^Host #{server.mu_name} /)
|
613
|
+
MU.log("Attempt to add duplicate #{ssh_conf} entry for #{server.mu_name}", MU::WARN)
|
614
|
+
return
|
615
|
+
end
|
616
|
+
}
|
617
|
+
end
|
618
|
+
|
619
|
+
File.open(ssh_conf, 'a', 0600) { |ssh_config|
|
620
|
+
ssh_config.flock(File::LOCK_EX)
|
621
|
+
host_str = "Host #{server.mu_name} #{server.canonicalIP}"
|
622
|
+
if !names.nil? and names.size > 0
|
623
|
+
host_str = host_str+" "+names.join(" ")
|
624
|
+
end
|
625
|
+
ssh_config.puts host_str
|
626
|
+
ssh_config.puts " Hostname #{server.canonicalIP}"
|
627
|
+
if !nat_ssh_host.nil? and server.canonicalIP != nat_ssh_host
|
628
|
+
ssh_config.puts " ProxyCommand ssh -W %h:%p #{nat_ssh_user}@#{nat_ssh_host}"
|
629
|
+
end
|
630
|
+
if timeout > 0
|
631
|
+
ssh_config.puts " ConnectTimeout #{timeout}"
|
632
|
+
end
|
633
|
+
|
634
|
+
ssh_config.puts " User #{ssh_user}"
|
635
|
+
# XXX I'd rather add the host key to known_hosts, but Net::SSH is a little dumb
|
636
|
+
ssh_config.puts " StrictHostKeyChecking no"
|
637
|
+
ssh_config.puts " ServerAliveInterval 60"
|
638
|
+
|
639
|
+
ssh_config.puts " IdentityFile #{ssh_dir}/#{ssh_key_name}"
|
640
|
+
if !File.exist?("#{ssh_dir}/#{ssh_key_name}")
|
641
|
+
MU.log "#{server.mu_name} - ssh private key #{ssh_dir}/#{ssh_key_name} does not exist", MU::WARN
|
642
|
+
end
|
643
|
+
|
644
|
+
ssh_config.flock(File::LOCK_UN)
|
645
|
+
ssh_config.chown(Etc.getpwnam(ssh_owner).uid, Etc.getpwnam(ssh_owner).gid)
|
646
|
+
}
|
647
|
+
MU.log "Wrote #{server.mu_name} ssh key to #{ssh_dir}/config", MU::DEBUG
|
648
|
+
return "#{ssh_dir}/#{ssh_key_name}"
|
649
|
+
}
|
650
|
+
end
|
651
|
+
|
652
|
+
# Clean an IP address out of ~/.ssh/known hosts
|
653
|
+
# @param ip [String]: The IP to remove
|
654
|
+
# @return [void]
|
655
|
+
def self.removeIPFromSSHKnownHosts(ip, noop: false)
|
656
|
+
return if ip.nil?
|
657
|
+
sshdir = "#{MY_HOME}/.ssh"
|
658
|
+
knownhosts = "#{sshdir}/known_hosts"
|
659
|
+
|
660
|
+
if File.exist?(knownhosts) and File.open(knownhosts).read.match(/^#{Regexp.quote(ip)} /)
|
661
|
+
MU.log "Expunging old #{ip} entry from #{knownhosts}", MU::NOTICE
|
662
|
+
if !noop
|
663
|
+
File.open(knownhosts, File::CREAT|File::RDWR, 0600) { |f|
|
664
|
+
f.flock(File::LOCK_EX)
|
665
|
+
newlines = Array.new
|
666
|
+
f.readlines.each { |line|
|
667
|
+
next if line.match(/^#{Regexp.quote(ip)} /)
|
668
|
+
newlines << line
|
669
|
+
}
|
670
|
+
f.rewind
|
671
|
+
f.truncate(0)
|
672
|
+
f.puts(newlines)
|
673
|
+
f.flush
|
674
|
+
f.flock(File::LOCK_UN)
|
675
|
+
}
|
676
|
+
end
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
# Clean a node's entries out of ~/.ssh/config
|
681
|
+
# @param nodename [String]: The node's name
|
682
|
+
# @return [void]
|
683
|
+
def self.removeHostFromSSHConfig(nodename, noop: false)
|
684
|
+
sshdir = "#{MY_HOME}/.ssh"
|
685
|
+
sshconf = "#{sshdir}/config"
|
686
|
+
|
687
|
+
if File.exist?(sshconf) and File.open(sshconf).read.match(/ #{nodename} /)
|
688
|
+
MU.log "Expunging old #{nodename} entry from #{sshconf}", MU::DEBUG
|
689
|
+
if !noop
|
690
|
+
File.open(sshconf, File::CREAT|File::RDWR, 0600) { |f|
|
691
|
+
f.flock(File::LOCK_EX)
|
692
|
+
newlines = Array.new
|
693
|
+
delete_block = false
|
694
|
+
f.readlines.each { |line|
|
695
|
+
if line.match(/^Host #{nodename}(\s|$)/)
|
696
|
+
delete_block = true
|
697
|
+
elsif line.match(/^Host /)
|
698
|
+
delete_block = false
|
699
|
+
end
|
700
|
+
newlines << line if !delete_block
|
701
|
+
}
|
702
|
+
f.rewind
|
703
|
+
f.truncate(0)
|
704
|
+
f.puts(newlines)
|
705
|
+
f.flush
|
706
|
+
f.flock(File::LOCK_UN)
|
707
|
+
}
|
708
|
+
end
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
# Ensure that the Nagios configuration local to the MU master has been
|
713
|
+
# updated, and make sure Nagios has all of the ssh keys it needs to tunnel
|
714
|
+
# to client nodes.
|
715
|
+
# @return [void]
|
716
|
+
def self.syncMonitoringConfig(blocking = true)
|
717
|
+
return if Etc.getpwuid(Process.uid).name != "root" or (MU.mu_user != "mu" and MU.mu_user != "root")
|
718
|
+
parent_thread_id = Thread.current.object_id
|
719
|
+
nagios_threads = []
|
720
|
+
nagios_threads << Thread.new {
|
721
|
+
MU.dupGlobals(parent_thread_id)
|
722
|
+
realhome = Etc.getpwnam("nagios").dir
|
723
|
+
[NAGIOS_HOME, "#{NAGIOS_HOME}/.ssh"].each { |dir|
|
724
|
+
Dir.mkdir(dir, 0711) if !Dir.exist?(dir)
|
725
|
+
File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, dir)
|
726
|
+
}
|
727
|
+
if realhome != NAGIOS_HOME and Dir.exist?(realhome) and !File.symlink?("#{realhome}/.ssh")
|
728
|
+
File.rename("#{realhome}/.ssh", "#{realhome}/.ssh.#{$$}") if Dir.exist?("#{realhome}/.ssh")
|
729
|
+
File.symlink("#{NAGIOS_HOME}/.ssh", Etc.getpwnam("nagios").dir+"/.ssh")
|
730
|
+
end
|
731
|
+
MU.log "Updating #{NAGIOS_HOME}/.ssh/config..."
|
732
|
+
ssh_lock = File.new("#{NAGIOS_HOME}/.ssh/config.mu.lock", File::CREAT|File::TRUNC|File::RDWR, 0600)
|
733
|
+
ssh_lock.flock(File::LOCK_EX)
|
734
|
+
ssh_conf = File.new("#{NAGIOS_HOME}/.ssh/config.tmp", File::CREAT|File::TRUNC|File::RDWR, 0600)
|
735
|
+
ssh_conf.puts "Host MU-MASTER localhost"
|
736
|
+
ssh_conf.puts " Hostname localhost"
|
737
|
+
ssh_conf.puts " User root"
|
738
|
+
ssh_conf.puts " IdentityFile #{NAGIOS_HOME}/.ssh/id_rsa"
|
739
|
+
ssh_conf.puts " StrictHostKeyChecking no"
|
740
|
+
ssh_conf.close
|
741
|
+
FileUtils.cp("#{@myhome}/.ssh/id_rsa", "#{NAGIOS_HOME}/.ssh/id_rsa")
|
742
|
+
File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/id_rsa")
|
743
|
+
threads = []
|
744
|
+
|
745
|
+
parent_thread_id = Thread.current.object_id
|
746
|
+
MU::MommaCat.listDeploys.sort.each { |deploy_id|
|
747
|
+
begin
|
748
|
+
# We don't want to use cached litter information here because this is also called by cleanTerminatedInstances.
|
749
|
+
deploy = MU::MommaCat.getLitter(deploy_id)
|
750
|
+
if deploy.ssh_key_name.nil? or deploy.ssh_key_name.empty?
|
751
|
+
MU.log "Failed to extract ssh key name from #{deploy_id} in syncMonitoringConfig", MU::ERR if deploy.kittens.has_key?("servers")
|
752
|
+
next
|
753
|
+
end
|
754
|
+
FileUtils.cp("#{@myhome}/.ssh/#{deploy.ssh_key_name}", "#{NAGIOS_HOME}/.ssh/#{deploy.ssh_key_name}")
|
755
|
+
File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/#{deploy.ssh_key_name}")
|
756
|
+
if deploy.kittens.has_key?("servers")
|
757
|
+
deploy.kittens["servers"].values.each { |nodeclasses|
|
758
|
+
nodeclasses.values.each { |nodes|
|
759
|
+
nodes.values.each { |server|
|
760
|
+
next if !server.cloud_desc
|
761
|
+
MU.dupGlobals(parent_thread_id)
|
762
|
+
threads << Thread.new {
|
763
|
+
MU::MommaCat.setThreadContext(deploy)
|
764
|
+
MU.log "Adding #{server.mu_name} to #{NAGIOS_HOME}/.ssh/config", MU::DEBUG
|
765
|
+
MU::Master.addHostToSSHConfig(
|
766
|
+
server,
|
767
|
+
ssh_dir: "#{NAGIOS_HOME}/.ssh",
|
768
|
+
ssh_conf: "#{NAGIOS_HOME}/.ssh/config.tmp",
|
769
|
+
ssh_owner: "nagios"
|
770
|
+
)
|
771
|
+
MU.purgeGlobals
|
772
|
+
}
|
773
|
+
}
|
774
|
+
}
|
775
|
+
}
|
776
|
+
end
|
777
|
+
rescue StandardError => e
|
778
|
+
MU.log "#{e.inspect} while generating Nagios SSH config in #{deploy_id}", MU::ERR, details: e.backtrace
|
779
|
+
end
|
780
|
+
}
|
781
|
+
threads.each { |t|
|
782
|
+
t.join
|
783
|
+
}
|
784
|
+
ssh_lock.flock(File::LOCK_UN)
|
785
|
+
ssh_lock.close
|
786
|
+
File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/config.tmp")
|
787
|
+
File.rename("#{NAGIOS_HOME}/.ssh/config.tmp", "#{NAGIOS_HOME}/.ssh/config")
|
788
|
+
|
789
|
+
MU.log "Updating Nagios monitoring config, this may take a while..."
|
790
|
+
output = nil
|
791
|
+
if $MU_CFG and !$MU_CFG['master_runlist_extras'].nil?
|
792
|
+
output = %x{#{MU::Groomer::Chef.chefclient} -o 'role[mu-master-nagios-only],#{$MU_CFG['master_runlist_extras'].join(",")}' 2>&1}
|
793
|
+
else
|
794
|
+
output = %x{#{MU::Groomer::Chef.chefclient} -o 'role[mu-master-nagios-only]' 2>&1}
|
795
|
+
end
|
796
|
+
|
797
|
+
if $?.exitstatus != 0
|
798
|
+
MU.log "Nagios monitoring config update returned a non-zero exit code!", MU::ERR, details: output
|
799
|
+
else
|
800
|
+
MU.log "Nagios monitoring config update complete."
|
801
|
+
end
|
802
|
+
}
|
803
|
+
|
804
|
+
if blocking
|
805
|
+
nagios_threads.each { |t|
|
806
|
+
t.join
|
807
|
+
}
|
808
|
+
end
|
809
|
+
end
|
810
|
+
|
496
811
|
end
|
497
812
|
end
|
data/modules/mu/master/chef.rb
CHANGED
@@ -48,7 +48,7 @@ module MU
|
|
48
48
|
def self.deleteOrg(org)
|
49
49
|
begin
|
50
50
|
Timeout::timeout(45) {
|
51
|
-
|
51
|
+
chefAPI.delete("organizations/#{org}")
|
52
52
|
}
|
53
53
|
MU.log "Removed Chef organization #{org}", MU::NOTICE
|
54
54
|
return true
|
@@ -82,7 +82,7 @@ module MU
|
|
82
82
|
|
83
83
|
begin
|
84
84
|
Timeout::timeout(45) {
|
85
|
-
|
85
|
+
chefAPI.delete("users/#{chef_user}")
|
86
86
|
}
|
87
87
|
MU.log "Removed Chef user #{chef_user}", MU::NOTICE
|
88
88
|
return true
|
@@ -200,7 +200,6 @@ module MU
|
|
200
200
|
|
201
201
|
# This organization does not yet exist, create it
|
202
202
|
if !existing_org
|
203
|
-
name = org.dup if fullname.nil?
|
204
203
|
begin
|
205
204
|
org_data = {
|
206
205
|
:name => org.dup,
|
@@ -255,7 +254,7 @@ module MU
|
|
255
254
|
}
|
256
255
|
remove_users.each { |user|
|
257
256
|
begin
|
258
|
-
|
257
|
+
chefAPI.delete("organizations/#{org}/users/#{user}")
|
259
258
|
MU.log "Removed Chef user #{user} from organization #{org}", MU::NOTICE
|
260
259
|
rescue Net::HTTPServerException => e
|
261
260
|
end
|