cloud-mu 3.1.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +15 -3
  3. data/ansible/roles/mu-windows/README.md +33 -0
  4. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  5. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  6. data/ansible/roles/mu-windows/files/config.xml +76 -0
  7. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  8. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  9. data/ansible/roles/mu-windows/tasks/main.yml +36 -0
  10. data/ansible/roles/mu-windows/tests/inventory +2 -0
  11. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  12. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  13. data/bin/mu-adopt +10 -13
  14. data/bin/mu-azure-tests +57 -0
  15. data/bin/mu-cleanup +2 -4
  16. data/bin/mu-configure +52 -0
  17. data/bin/mu-deploy +3 -3
  18. data/bin/mu-findstray-tests +25 -0
  19. data/bin/mu-gen-docs +2 -4
  20. data/bin/mu-load-config.rb +2 -3
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +135 -37
  23. data/cloud-mu.gemspec +22 -20
  24. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  25. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  26. data/cookbooks/mu-tools/libraries/helper.rb +3 -2
  27. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  28. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  29. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  30. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  31. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  32. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  33. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  34. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  35. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  36. data/extras/clean-stock-amis +25 -19
  37. data/extras/generate-stock-images +1 -0
  38. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  39. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  40. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  41. data/extras/image-generators/Google/centos6.yaml +1 -0
  42. data/extras/image-generators/Google/centos7.yaml +1 -1
  43. data/modules/mommacat.ru +6 -16
  44. data/modules/mu.rb +165 -111
  45. data/modules/mu/adoption.rb +401 -68
  46. data/modules/mu/cleanup.rb +199 -306
  47. data/modules/mu/cloud.rb +100 -1632
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +46 -0
  50. data/modules/mu/cloud/machine_images.rb +212 -0
  51. data/modules/mu/cloud/providers.rb +81 -0
  52. data/modules/mu/cloud/resource_base.rb +920 -0
  53. data/modules/mu/cloud/server.rb +40 -0
  54. data/modules/mu/cloud/server_pool.rb +1 -0
  55. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  56. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  57. data/modules/mu/cloud/wrappers.rb +165 -0
  58. data/modules/mu/config.rb +171 -1767
  59. data/modules/mu/config/alarm.rb +2 -6
  60. data/modules/mu/config/bucket.rb +4 -4
  61. data/modules/mu/config/cache_cluster.rb +1 -1
  62. data/modules/mu/config/collection.rb +4 -4
  63. data/modules/mu/config/container_cluster.rb +9 -4
  64. data/modules/mu/config/database.rb +83 -104
  65. data/modules/mu/config/database.yml +1 -2
  66. data/modules/mu/config/dnszone.rb +6 -6
  67. data/modules/mu/config/doc_helpers.rb +516 -0
  68. data/modules/mu/config/endpoint.rb +4 -4
  69. data/modules/mu/config/firewall_rule.rb +103 -4
  70. data/modules/mu/config/folder.rb +4 -4
  71. data/modules/mu/config/function.rb +3 -3
  72. data/modules/mu/config/group.rb +4 -4
  73. data/modules/mu/config/habitat.rb +4 -4
  74. data/modules/mu/config/loadbalancer.rb +60 -14
  75. data/modules/mu/config/log.rb +4 -4
  76. data/modules/mu/config/msg_queue.rb +4 -4
  77. data/modules/mu/config/nosqldb.rb +4 -4
  78. data/modules/mu/config/notifier.rb +3 -3
  79. data/modules/mu/config/ref.rb +365 -0
  80. data/modules/mu/config/role.rb +4 -4
  81. data/modules/mu/config/schema_helpers.rb +509 -0
  82. data/modules/mu/config/search_domain.rb +4 -4
  83. data/modules/mu/config/server.rb +97 -70
  84. data/modules/mu/config/server.yml +1 -0
  85. data/modules/mu/config/server_pool.rb +5 -9
  86. data/modules/mu/config/storage_pool.rb +1 -1
  87. data/modules/mu/config/tail.rb +200 -0
  88. data/modules/mu/config/user.rb +4 -4
  89. data/modules/mu/config/vpc.rb +70 -27
  90. data/modules/mu/config/vpc.yml +0 -1
  91. data/modules/mu/defaults/AWS.yaml +83 -60
  92. data/modules/mu/defaults/Azure.yaml +1 -0
  93. data/modules/mu/defaults/Google.yaml +3 -2
  94. data/modules/mu/deploy.rb +30 -26
  95. data/modules/mu/groomer.rb +17 -2
  96. data/modules/mu/groomers/ansible.rb +188 -41
  97. data/modules/mu/groomers/chef.rb +116 -55
  98. data/modules/mu/logger.rb +127 -148
  99. data/modules/mu/master.rb +389 -2
  100. data/modules/mu/master/chef.rb +3 -4
  101. data/modules/mu/master/ldap.rb +3 -3
  102. data/modules/mu/master/ssl.rb +12 -3
  103. data/modules/mu/mommacat.rb +217 -2612
  104. data/modules/mu/mommacat/daemon.rb +397 -0
  105. data/modules/mu/mommacat/naming.rb +473 -0
  106. data/modules/mu/mommacat/search.rb +495 -0
  107. data/modules/mu/mommacat/storage.rb +722 -0
  108. data/modules/mu/{clouds → providers}/README.md +1 -1
  109. data/modules/mu/{clouds → providers}/aws.rb +271 -112
  110. data/modules/mu/{clouds → providers}/aws/alarm.rb +5 -3
  111. data/modules/mu/{clouds → providers}/aws/bucket.rb +26 -22
  112. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +33 -67
  113. data/modules/mu/{clouds → providers}/aws/collection.rb +24 -23
  114. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +681 -721
  115. data/modules/mu/providers/aws/database.rb +1744 -0
  116. data/modules/mu/{clouds → providers}/aws/dnszone.rb +64 -63
  117. data/modules/mu/{clouds → providers}/aws/endpoint.rb +22 -27
  118. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +214 -244
  119. data/modules/mu/{clouds → providers}/aws/folder.rb +7 -7
  120. data/modules/mu/{clouds → providers}/aws/function.rb +17 -22
  121. data/modules/mu/{clouds → providers}/aws/group.rb +23 -23
  122. data/modules/mu/{clouds → providers}/aws/habitat.rb +17 -14
  123. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +57 -48
  124. data/modules/mu/{clouds → providers}/aws/log.rb +15 -12
  125. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +17 -16
  126. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +18 -11
  127. data/modules/mu/{clouds → providers}/aws/notifier.rb +11 -6
  128. data/modules/mu/{clouds → providers}/aws/role.rb +112 -86
  129. data/modules/mu/{clouds → providers}/aws/search_domain.rb +39 -33
  130. data/modules/mu/{clouds → providers}/aws/server.rb +835 -1133
  131. data/modules/mu/{clouds → providers}/aws/server_pool.rb +56 -60
  132. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +24 -42
  133. data/modules/mu/{clouds → providers}/aws/user.rb +21 -22
  134. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  135. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
  136. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  137. data/modules/mu/{clouds → providers}/aws/vpc.rb +523 -929
  138. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  139. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  140. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  141. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  142. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  143. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  144. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  145. data/modules/mu/{clouds → providers}/azure/server.rb +95 -48
  146. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  147. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  148. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  149. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  150. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  151. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  152. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  153. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  154. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  155. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  156. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  160. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  161. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  162. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  163. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  164. data/modules/mu/{clouds → providers}/google.rb +67 -30
  165. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  166. data/modules/mu/{clouds → providers}/google/container_cluster.rb +84 -77
  167. data/modules/mu/{clouds → providers}/google/database.rb +10 -20
  168. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  169. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  170. data/modules/mu/{clouds → providers}/google/function.rb +139 -167
  171. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  172. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  173. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +18 -20
  174. data/modules/mu/{clouds → providers}/google/role.rb +92 -58
  175. data/modules/mu/{clouds → providers}/google/server.rb +242 -155
  176. data/modules/mu/{clouds → providers}/google/server_pool.rb +25 -44
  177. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  178. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  179. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  180. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  181. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  182. data/modules/tests/bucket.yml +4 -0
  183. data/modules/tests/centos6.yaml +11 -0
  184. data/modules/tests/centos7.yaml +11 -0
  185. data/modules/tests/centos8.yaml +12 -0
  186. data/modules/tests/ecs.yaml +23 -0
  187. data/modules/tests/includes-and-params.yaml +2 -1
  188. data/modules/tests/rds.yaml +108 -0
  189. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  190. data/modules/tests/regrooms/bucket.yml +19 -0
  191. data/modules/tests/regrooms/rds.yaml +123 -0
  192. data/modules/tests/server-with-scrub-muisms.yaml +1 -0
  193. data/modules/tests/super_simple_bok.yml +1 -3
  194. data/modules/tests/win2k12.yaml +17 -5
  195. data/modules/tests/win2k16.yaml +25 -0
  196. data/modules/tests/win2k19.yaml +25 -0
  197. data/requirements.txt +1 -0
  198. data/spec/mu/clouds/azure_spec.rb +2 -2
  199. metadata +232 -154
  200. data/extras/image-generators/AWS/windows.yaml +0 -18
  201. data/modules/mu/clouds/aws/database.rb +0 -1985
@@ -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 Exception => e
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 Exception => e
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
@@ -380,6 +386,7 @@ module MU
380
386
  best = nil
381
387
  best_version = nil
382
388
  paths.uniq.each { |path|
389
+ path.sub!(/^~/, MY_HOME)
383
390
  if File.exist?(path+"/kubectl")
384
391
  version = %x{#{path}/kubectl version --short --client}.chomp.sub(/.*Client version:\s+v/i, '')
385
392
  next if !$?.success?
@@ -493,5 +500,385 @@ module MU
493
500
  end
494
501
  end
495
502
 
503
+ # Clean a node's entries out of /etc/hosts
504
+ # @param node [String]: The node's name
505
+ # @return [void]
506
+ def self.removeInstanceFromEtcHosts(node)
507
+ return if MU.mu_user != "mu"
508
+ hostsfile = "/etc/hosts"
509
+ FileUtils.copy(hostsfile, "#{hostsfile}.bak-#{MU.deploy_id}")
510
+ File.open(hostsfile, File::CREAT|File::RDWR, 0644) { |f|
511
+ f.flock(File::LOCK_EX)
512
+ newlines = Array.new
513
+ f.readlines.each { |line|
514
+ newlines << line if !line.match(/ #{node}(\s|$)/)
515
+ }
516
+ f.rewind
517
+ f.truncate(0)
518
+ f.puts(newlines)
519
+ f.flush
520
+
521
+ f.flock(File::LOCK_UN)
522
+ }
523
+ end
524
+
525
+
526
+ # Insert node names associated with a new instance into /etc/hosts so we
527
+ # can treat them as if they were real DNS entries. Especially helpful when
528
+ # Chef/Ohai mistake the proper hostname, e.g. when bootstrapping Windows.
529
+ # @param public_ip [String]: The node's IP address
530
+ # @param chef_name [String]: The node's Chef node name
531
+ # @param system_name [String]: The node's local system name
532
+ # @return [void]
533
+ def self.addInstanceToEtcHosts(public_ip, chef_name = nil, system_name = nil)
534
+
535
+ # XXX cover ipv6 case
536
+ if public_ip.nil? or !public_ip.match(/^\d+\.\d+\.\d+\.\d+$/) or (chef_name.nil? and system_name.nil?)
537
+ raise MuError, "addInstanceToEtcHosts requires public_ip and one or both of chef_name and system_name!"
538
+ end
539
+ if chef_name == "localhost" or system_name == "localhost"
540
+ raise MuError, "Can't set localhost as a name in addInstanceToEtcHosts"
541
+ end
542
+
543
+ if !["mu", "root"].include?(MU.mu_user)
544
+ response = nil
545
+ begin
546
+ response = open("https://127.0.0.1:#{MU.mommaCatPort.to_s}/rest/hosts_add/#{chef_name}/#{public_ip}").read
547
+ rescue Errno::ECONNRESET, Errno::ECONNREFUSED
548
+ end
549
+ if response != "ok"
550
+ MU.log "Unable to add #{public_ip} to /etc/hosts via MommaCat request", MU::WARN
551
+ end
552
+ return
553
+ end
554
+
555
+ File.readlines("/etc/hosts").each { |line|
556
+ 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|$)/))
557
+ MU.log "Ignoring attempt to add duplicate /etc/hosts entry: #{public_ip} #{chef_name} #{system_name}", MU::DEBUG
558
+ return
559
+ end
560
+ }
561
+ File.open("/etc/hosts", 'a') { |etc_hosts|
562
+ etc_hosts.flock(File::LOCK_EX)
563
+ etc_hosts.puts("#{public_ip} #{chef_name} #{system_name}")
564
+ etc_hosts.flock(File::LOCK_UN)
565
+ }
566
+ MU.log("Added to /etc/hosts: #{public_ip} #{chef_name} #{system_name}")
567
+ end
568
+
569
+ @ssh_semaphore = Mutex.new
570
+ # Insert a definition for a node into our SSH config.
571
+ # @param server [MU::Cloud::Server]: The name of the node.
572
+ # @param names [Array<String>]: Other names that we'd like this host to be known by for SSH purposes
573
+ # @param ssh_dir [String]: The configuration directory of the SSH config to emit.
574
+ # @param ssh_conf [String]: A specific SSH configuration file to write entries into.
575
+ # @param ssh_owner [String]: The preferred owner of the SSH configuration files.
576
+ # @param timeout [Integer]: An alternate timeout value for connections to this server.
577
+ # @return [void]
578
+ def self.addHostToSSHConfig(server,
579
+ ssh_dir: "#{Etc.getpwuid(Process.uid).dir}/.ssh",
580
+ ssh_conf: "#{Etc.getpwuid(Process.uid).dir}/.ssh/config",
581
+ ssh_owner: Etc.getpwuid(Process.uid).name,
582
+ names: [],
583
+ timeout: 0
584
+ )
585
+ if server.nil?
586
+ MU.log "Called addHostToSSHConfig without a MU::Cloud::Server object", MU::ERR, details: caller
587
+ return nil
588
+ end
589
+
590
+ _nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = begin
591
+ server.getSSHConfig
592
+ rescue MU::MuError
593
+ return
594
+ end
595
+
596
+ if ssh_user.nil? or ssh_user.empty?
597
+ MU.log "Failed to extract ssh_user for #{server.mu_name} addHostToSSHConfig", MU::ERR
598
+ return
599
+ end
600
+ if canonical_ip.nil? or canonical_ip.empty?
601
+ MU.log "Failed to extract canonical_ip for #{server.mu_name} addHostToSSHConfig", MU::ERR
602
+ return
603
+ end
604
+ if ssh_key_name.nil? or ssh_key_name.empty?
605
+ MU.log "Failed to extract ssh_key_name for #{server.mu_name} in addHostToSSHConfig", MU::ERR
606
+ return
607
+ end
608
+
609
+ @ssh_semaphore.synchronize {
610
+
611
+ if File.exist?(ssh_conf)
612
+ File.readlines(ssh_conf).each { |line|
613
+ if line.match(/^Host #{server.mu_name} /)
614
+ MU.log("Attempt to add duplicate #{ssh_conf} entry for #{server.mu_name}", MU::WARN)
615
+ return
616
+ end
617
+ }
618
+ end
619
+
620
+ File.open(ssh_conf, 'a', 0600) { |ssh_config|
621
+ ssh_config.flock(File::LOCK_EX)
622
+ host_str = "Host #{server.mu_name} #{server.canonicalIP}"
623
+ if !names.nil? and names.size > 0
624
+ host_str = host_str+" "+names.join(" ")
625
+ end
626
+ ssh_config.puts host_str
627
+ ssh_config.puts " Hostname #{server.canonicalIP}"
628
+ if !nat_ssh_host.nil? and server.canonicalIP != nat_ssh_host
629
+ ssh_config.puts " ProxyCommand ssh -W %h:%p #{nat_ssh_user}@#{nat_ssh_host}"
630
+ end
631
+ if timeout > 0
632
+ ssh_config.puts " ConnectTimeout #{timeout}"
633
+ end
634
+
635
+ ssh_config.puts " User #{ssh_user}"
636
+ # XXX I'd rather add the host key to known_hosts, but Net::SSH is a little dumb
637
+ ssh_config.puts " StrictHostKeyChecking no"
638
+ ssh_config.puts " ServerAliveInterval 60"
639
+
640
+ ssh_config.puts " IdentityFile #{ssh_dir}/#{ssh_key_name}"
641
+ if !File.exist?("#{ssh_dir}/#{ssh_key_name}")
642
+ MU.log "#{server.mu_name} - ssh private key #{ssh_dir}/#{ssh_key_name} does not exist", MU::WARN
643
+ end
644
+
645
+ ssh_config.flock(File::LOCK_UN)
646
+ ssh_config.chown(Etc.getpwnam(ssh_owner).uid, Etc.getpwnam(ssh_owner).gid)
647
+ }
648
+ MU.log "Wrote #{server.mu_name} ssh key to #{ssh_dir}/config", MU::DEBUG
649
+ return "#{ssh_dir}/#{ssh_key_name}"
650
+ }
651
+ end
652
+
653
+ # Clean an IP address out of ~/.ssh/known hosts
654
+ # @param ip [String]: The IP to remove
655
+ # @return [void]
656
+ def self.removeIPFromSSHKnownHosts(ip, noop: false)
657
+ return if ip.nil?
658
+ sshdir = "#{MY_HOME}/.ssh"
659
+ knownhosts = "#{sshdir}/known_hosts"
660
+
661
+ if File.exist?(knownhosts) and File.open(knownhosts).read.match(/^#{Regexp.quote(ip)} /)
662
+ MU.log "Expunging old #{ip} entry from #{knownhosts}", MU::NOTICE
663
+ if !noop
664
+ File.open(knownhosts, File::CREAT|File::RDWR, 0600) { |f|
665
+ f.flock(File::LOCK_EX)
666
+ newlines = Array.new
667
+ f.readlines.each { |line|
668
+ next if line.match(/^#{Regexp.quote(ip)} /)
669
+ newlines << line
670
+ }
671
+ f.rewind
672
+ f.truncate(0)
673
+ f.puts(newlines)
674
+ f.flush
675
+ f.flock(File::LOCK_UN)
676
+ }
677
+ end
678
+ end
679
+ end
680
+
681
+ # Clean a node's entries out of ~/.ssh/config
682
+ # @param nodename [String]: The node's name
683
+ # @return [void]
684
+ def self.removeHostFromSSHConfig(nodename, noop: false)
685
+ sshdir = "#{MY_HOME}/.ssh"
686
+ sshconf = "#{sshdir}/config"
687
+
688
+ if File.exist?(sshconf) and File.open(sshconf).read.match(/ #{nodename} /)
689
+ MU.log "Expunging old #{nodename} entry from #{sshconf}", MU::DEBUG
690
+ if !noop
691
+ File.open(sshconf, File::CREAT|File::RDWR, 0600) { |f|
692
+ f.flock(File::LOCK_EX)
693
+ newlines = Array.new
694
+ delete_block = false
695
+ f.readlines.each { |line|
696
+ if line.match(/^Host #{nodename}(\s|$)/)
697
+ delete_block = true
698
+ elsif line.match(/^Host /)
699
+ delete_block = false
700
+ end
701
+ newlines << line if !delete_block
702
+ }
703
+ f.rewind
704
+ f.truncate(0)
705
+ f.puts(newlines)
706
+ f.flush
707
+ f.flock(File::LOCK_UN)
708
+ }
709
+ end
710
+ end
711
+ end
712
+
713
+ # Evict ssh keys associated with a particular deploy from our ssh config
714
+ # and key directory.
715
+ # @param deploy_id [String]
716
+ # @param noop [Boolean]
717
+ def self.purgeDeployFromSSH(deploy_id, noop: false)
718
+ myhome = Etc.getpwuid(Process.uid).dir
719
+ sshdir = "#{myhome}/.ssh"
720
+ sshconf = "#{sshdir}/config"
721
+ ssharchive = "#{sshdir}/archive"
722
+
723
+ Dir.mkdir(sshdir, 0700) if !Dir.exist?(sshdir) and !noop
724
+ Dir.mkdir(ssharchive, 0700) if !Dir.exist?(ssharchive) and !noop
725
+
726
+ keyname = "deploy-#{deploy_id}"
727
+ if File.exist?("#{sshdir}/#{keyname}")
728
+ MU.log "Moving #{sshdir}/#{keyname} to #{ssharchive}/#{keyname}"
729
+ if !noop
730
+ File.rename("#{sshdir}/#{keyname}", "#{ssharchive}/#{keyname}")
731
+ end
732
+ end
733
+ if File.exist?(sshconf) and File.open(sshconf).read.match(/\/deploy\-#{deploy_id}$/)
734
+ MU.log "Expunging #{deploy_id} from #{sshconf}"
735
+ if !noop
736
+ FileUtils.copy(sshconf, "#{ssharchive}/config-#{deploy_id}")
737
+ File.open(sshconf, File::CREAT|File::RDWR, 0600) { |f|
738
+ f.flock(File::LOCK_EX)
739
+ newlines = Array.new
740
+ delete_block = false
741
+ f.readlines.each { |line|
742
+ if line.match(/^Host #{deploy_id}\-/)
743
+ delete_block = true
744
+ elsif line.match(/^Host /)
745
+ delete_block = false
746
+ end
747
+ newlines << line if !delete_block
748
+ }
749
+ f.rewind
750
+ f.truncate(0)
751
+ f.puts(newlines)
752
+ f.flush
753
+ f.flock(File::LOCK_UN)
754
+ }
755
+ end
756
+ end
757
+ # XXX refactor with above? They're similar, ish.
758
+ hostsfile = "/etc/hosts"
759
+ if File.open(hostsfile).read.match(/ #{deploy_id}\-/)
760
+ if Process.uid == 0
761
+ MU.log "Expunging traces of #{deploy_id} from #{hostsfile}"
762
+ if !noop
763
+ FileUtils.copy(hostsfile, "#{hostsfile}.cleanup-#{deploy_id}")
764
+ File.open(hostsfile, File::CREAT|File::RDWR, 0644) { |f|
765
+ f.flock(File::LOCK_EX)
766
+ newlines = Array.new
767
+ f.readlines.each { |line|
768
+ newlines << line if !line.match(/ #{deploy_id}\-/)
769
+ }
770
+ f.rewind
771
+ f.truncate(0)
772
+ f.puts(newlines)
773
+ f.flush
774
+ f.flock(File::LOCK_UN)
775
+ }
776
+ end
777
+ else
778
+ MU.log "Residual /etc/hosts entries for #{deploy_id} must be removed by root user", MU::WARN
779
+ end
780
+ end
781
+
782
+ end
783
+
784
+ # Ensure that the Nagios configuration local to the MU master has been
785
+ # updated, and make sure Nagios has all of the ssh keys it needs to tunnel
786
+ # to client nodes.
787
+ # @return [void]
788
+ def self.syncMonitoringConfig(blocking = true)
789
+ return if Etc.getpwuid(Process.uid).name != "root" or (MU.mu_user != "mu" and MU.mu_user != "root")
790
+ parent_thread_id = Thread.current.object_id
791
+ nagios_threads = []
792
+ nagios_threads << Thread.new {
793
+ MU.dupGlobals(parent_thread_id)
794
+ realhome = Etc.getpwnam("nagios").dir
795
+ [NAGIOS_HOME, "#{NAGIOS_HOME}/.ssh"].each { |dir|
796
+ Dir.mkdir(dir, 0711) if !Dir.exist?(dir)
797
+ File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, dir)
798
+ }
799
+ if realhome != NAGIOS_HOME and Dir.exist?(realhome) and !File.symlink?("#{realhome}/.ssh")
800
+ File.rename("#{realhome}/.ssh", "#{realhome}/.ssh.#{$$}") if Dir.exist?("#{realhome}/.ssh")
801
+ File.symlink("#{NAGIOS_HOME}/.ssh", Etc.getpwnam("nagios").dir+"/.ssh")
802
+ end
803
+ MU.log "Updating #{NAGIOS_HOME}/.ssh/config..."
804
+ ssh_lock = File.new("#{NAGIOS_HOME}/.ssh/config.mu.lock", File::CREAT|File::TRUNC|File::RDWR, 0600)
805
+ ssh_lock.flock(File::LOCK_EX)
806
+ ssh_conf = File.new("#{NAGIOS_HOME}/.ssh/config.tmp", File::CREAT|File::TRUNC|File::RDWR, 0600)
807
+ ssh_conf.puts "Host MU-MASTER localhost"
808
+ ssh_conf.puts " Hostname localhost"
809
+ ssh_conf.puts " User root"
810
+ ssh_conf.puts " IdentityFile #{NAGIOS_HOME}/.ssh/id_rsa"
811
+ ssh_conf.puts " StrictHostKeyChecking no"
812
+ ssh_conf.close
813
+ FileUtils.cp("#{Etc.getpwuid(Process.uid).dir}/.ssh/id_rsa", "#{NAGIOS_HOME}/.ssh/id_rsa")
814
+ File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/id_rsa")
815
+ threads = []
816
+
817
+ parent_thread_id = Thread.current.object_id
818
+ MU::MommaCat.listDeploys.sort.each { |deploy_id|
819
+ begin
820
+ # We don't want to use cached litter information here because this is also called by cleanTerminatedInstances.
821
+ deploy = MU::MommaCat.getLitter(deploy_id)
822
+ if deploy.ssh_key_name.nil? or deploy.ssh_key_name.empty?
823
+ MU.log "Failed to extract ssh key name from #{deploy_id} in syncMonitoringConfig", MU::ERR if deploy.kittens.has_key?("servers")
824
+ next
825
+ end
826
+ FileUtils.cp("#{Etc.getpwuid(Process.uid).dir}/.ssh/#{deploy.ssh_key_name}", "#{NAGIOS_HOME}/.ssh/#{deploy.ssh_key_name}")
827
+ File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/#{deploy.ssh_key_name}")
828
+ if deploy.kittens.has_key?("servers")
829
+ deploy.kittens["servers"].values.each { |nodeclasses|
830
+ nodeclasses.values.each { |nodes|
831
+ nodes.values.each { |server|
832
+ next if !server.cloud_desc
833
+ MU.dupGlobals(parent_thread_id)
834
+ threads << Thread.new {
835
+ MU::MommaCat.setThreadContext(deploy)
836
+ MU.log "Adding #{server.mu_name} to #{NAGIOS_HOME}/.ssh/config", MU::DEBUG
837
+ MU::Master.addHostToSSHConfig(
838
+ server,
839
+ ssh_dir: "#{NAGIOS_HOME}/.ssh",
840
+ ssh_conf: "#{NAGIOS_HOME}/.ssh/config.tmp",
841
+ ssh_owner: "nagios"
842
+ )
843
+ MU.purgeGlobals
844
+ }
845
+ }
846
+ }
847
+ }
848
+ end
849
+ rescue StandardError => e
850
+ MU.log "#{e.inspect} while generating Nagios SSH config in #{deploy_id}", MU::ERR, details: e.backtrace
851
+ end
852
+ }
853
+ threads.each { |t|
854
+ t.join
855
+ }
856
+ ssh_lock.flock(File::LOCK_UN)
857
+ ssh_lock.close
858
+ File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/config.tmp")
859
+ File.rename("#{NAGIOS_HOME}/.ssh/config.tmp", "#{NAGIOS_HOME}/.ssh/config")
860
+
861
+ MU.log "Updating Nagios monitoring config, this may take a while..."
862
+ output = nil
863
+ if $MU_CFG and !$MU_CFG['master_runlist_extras'].nil?
864
+ output = %x{#{MU::Groomer::Chef.chefclient} -o 'role[mu-master-nagios-only],#{$MU_CFG['master_runlist_extras'].join(",")}' 2>&1}
865
+ else
866
+ output = %x{#{MU::Groomer::Chef.chefclient} -o 'role[mu-master-nagios-only]' 2>&1}
867
+ end
868
+
869
+ if $?.exitstatus != 0
870
+ MU.log "Nagios monitoring config update returned a non-zero exit code!", MU::ERR, details: output
871
+ else
872
+ MU.log "Nagios monitoring config update complete."
873
+ end
874
+ }
875
+
876
+ if blocking
877
+ nagios_threads.each { |t|
878
+ t.join
879
+ }
880
+ end
881
+ end
882
+
496
883
  end
497
884
  end
@@ -48,7 +48,7 @@ module MU
48
48
  def self.deleteOrg(org)
49
49
  begin
50
50
  Timeout::timeout(45) {
51
- response = chefAPI.delete("organizations/#{org}")
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
- response = chefAPI.delete("users/#{chef_user}")
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
- response = chefAPI.delete("organizations/#{org}/users/#{user}")
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