cloud-mu 3.1.2 → 3.2.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.
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