require 'spec_helper' describe Beaker do let( :options ) { make_opts.merge({ 'logger' => double().as_null_object }) } let( :ntpserver_set ) { "ntp_server_set" } let( :options_ntp ) { make_opts.merge({ 'ntp_server' => ntpserver_set }) } let( :ntpserver ) { Beaker::HostPrebuiltSteps::NTPSERVER } let( :apt_cfg ) { Beaker::HostPrebuiltSteps::APT_CFG } let( :ips_pkg_repo ) { Beaker::HostPrebuiltSteps::IPS_PKG_REPO } let( :sync_cmd ) { Beaker::HostPrebuiltSteps::ROOT_KEYS_SYNC_CMD } let( :windows_pkgs ) { Beaker::HostPrebuiltSteps::WINDOWS_PACKAGES } let( :unix_only_pkgs ) { Beaker::HostPrebuiltSteps::UNIX_PACKAGES } let( :sles_only_pkgs ) { Beaker::HostPrebuiltSteps::SLES_PACKAGES } let( :platform ) { @platform || 'unix' } let( :ip ) { "ip.address.0.0" } let( :stdout) { @stdout || ip } let( :hosts ) { hosts = make_hosts( { :stdout => stdout, :platform => platform } ) hosts[0][:roles] = ['agent'] hosts[1][:roles] = ['master', 'dashboard', 'agent', 'database'] hosts[2][:roles] = ['agent'] hosts } let( :dummy_class ) { Class.new { include Beaker::HostPrebuiltSteps } } shared_examples 'enables_root_login' do |platform, commands, non_cygwin| subject { dummy_class.new } it "can enable root login on #{platform}" do hosts = make_hosts( { :platform => platform, :is_cygwin => non_cygwin} ) if commands.empty? expect( Beaker::Command ).to receive( :new ).exactly( 0 ).times end commands.each do | command | expect( Beaker::Command ).to receive( :new ).with(command).exactly( 3 ).times end subject.enable_root_login( hosts, options ) end end # Non-cygwin Windows it_should_behave_like 'enables_root_login', 'pswindows', [], false # Non-cygwin Windows it_should_behave_like 'enables_root_login', 'windows', [ "sudo su -c \"sed -ri 's/^#?PermitRootLogin no|^#?PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config\"" ], true # FreeBSD it_should_behave_like 'enables_root_login', 'freesbd', [ "sudo su -c \"sed -ri 's/^#?PermitRootLogin no|^#?PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config\"" ], true it_should_behave_like 'enables_root_login', 'osx', [ "sudo sed -i '' 's/#PermitRootLogin yes/PermitRootLogin Yes/g' /etc/sshd_config", "sudo sed -i '' 's/#PermitRootLogin no/PermitRootLogin Yes/g' /etc/sshd_config" ] ['debian','ubuntu','cumulus'].each do | deb_like | it_should_behave_like 'enables_root_login', deb_like, [ "sudo su -c \"sed -ri 's/^#?PermitRootLogin no|^#?PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config\"", "sudo su -c \"service ssh restart\"" ] end ['centos','el-','redhat','fedora','eos'].each do | rhel_like | it_should_behave_like 'enables_root_login', rhel_like, [ "sudo su -c \"sed -ri 's/^#?PermitRootLogin no|^#?PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config\"", "sudo -E /sbin/service sshd reload" ] end context 'timesync' do subject { dummy_class.new } it "can sync time on unix hosts" do hosts = make_hosts( { :platform => 'unix' } ) expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 3 ).times subject.timesync( hosts, options ) end it "can retry on failure on unix hosts" do hosts = make_hosts( { :platform => 'unix', :exit_code => [1, 0] } ) allow( subject ).to receive( :sleep ).and_return(true) expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 6 ).times subject.timesync( hosts, options ) end it "eventually gives up and raises an error when unix hosts can't be synched" do hosts = make_hosts( { :platform => 'unix', :exit_code => 1 } ) allow( subject ).to receive( :sleep ).and_return(true) expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 5 ).times expect{ subject.timesync( hosts, options ) }.to raise_error(/NTP date was not successful after/) end it "can sync time on windows hosts" do hosts = make_hosts( { :platform => 'windows' } ) expect( Beaker::Command ).to receive( :new ).with("w32tm /register").exactly( 3 ).times expect( Beaker::Command ).to receive( :new ).with("net start w32time").exactly( 3 ).times expect( Beaker::Command ).to receive( :new ).with("w32tm /config /manualpeerlist:#{ntpserver} /syncfromflags:manual /update").exactly( 3 ).times expect( Beaker::Command ).to receive( :new ).with("w32tm /resync").exactly( 3 ).times subject.timesync( hosts, options ) end it "can sync time on Sles hosts" do hosts = make_hosts( { :platform => 'sles-13.1-x64' } ) expect( Beaker::Command ).to receive( :new ).with("sntp #{ntpserver}").exactly( 3 ).times subject.timesync( hosts, options ) end it "can set time server on unix hosts" do hosts = make_hosts( { :platform => 'unix' } ) expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver_set}").exactly( 3 ).times subject.timesync( hosts, options_ntp ) end it "can set time server on windows hosts" do hosts = make_hosts( { :platform => 'windows' } ) expect( Beaker::Command ).to receive( :new ).with("w32tm /register").exactly( 3 ).times expect( Beaker::Command ).to receive( :new ).with("net start w32time").exactly( 3 ).times expect( Beaker::Command ).to receive( :new ).with("w32tm /config /manualpeerlist:#{ntpserver_set} /syncfromflags:manual /update").exactly( 3 ).times expect( Beaker::Command ).to receive( :new ).with("w32tm /resync").exactly( 3 ).times subject.timesync( hosts, options_ntp ) end it "can set time server on Sles hosts" do hosts = make_hosts( { :platform => 'sles-13.1-x64' } ) expect( Beaker::Command ).to receive( :new ).with("sntp #{ntpserver_set}").exactly( 3 ).times subject.timesync( hosts, options_ntp ) end end context "epel_info_for!" do subject { dummy_class.new } it "can return the correct url for an el-6 host" do host = make_host( 'testhost', { :platform => Beaker::Platform.new('el-6-platform') } ) expect( subject.epel_info_for( host, options )).to be === ["http://mirrors.kernel.org/fedora-epel/6", "i386", "epel-release-6-8.noarch.rpm"] end it "can return the correct url for an el-5 host" do host = make_host( 'testhost', { :platform => Beaker::Platform.new('el-5-platform') } ) expect( subject.epel_info_for( host, options )).to be === ["http://mirrors.kernel.org/fedora-epel/5", "i386", "epel-release-5-4.noarch.rpm"] end it "raises an error on non el-5/6 host" do host = make_host( 'testhost', { :platform => Beaker::Platform.new('el-4-platform') } ) expect{ subject.epel_info_for( host, options )}.to raise_error(RuntimeError, /epel_info_for does not support el version/) end end context "apt_get_update" do subject { dummy_class.new } it "can perform apt-get on ubuntu hosts" do host = make_host( 'testhost', { :platform => 'ubuntu' } ) expect( Beaker::Command ).to receive( :new ).with("apt-get update").once subject.apt_get_update( host ) end it "can perform apt-get on debian hosts" do host = make_host( 'testhost', { :platform => 'debian' } ) expect( Beaker::Command ).to receive( :new ).with("apt-get update").once subject.apt_get_update( host ) end it "can perform apt-get on cumulus hosts" do host = make_host( 'testhost', { :platform => 'cumulus' } ) expect( Beaker::Command ).to receive( :new ).with("apt-get update").once subject.apt_get_update( host ) end it "does nothing on non debian/ubuntu/cumulus hosts" do host = make_host( 'testhost', { :platform => 'windows' } ) expect( Beaker::Command ).to receive( :new ).never subject.apt_get_update( host ) end end context "copy_file_to_remote" do subject { dummy_class.new } it "can copy a file to a remote host" do content = "this is the content" tempfilepath = "/path/to/tempfile" filepath = "/path/to/file" host = make_host( 'testhost', { :platform => 'windows' }) tempfile = double( 'tempfile' ) allow( tempfile ).to receive( :path ).and_return( tempfilepath ) allow( Tempfile ).to receive( :open ).and_yield( tempfile ) file = double( 'file' ) allow( File ).to receive( :open ).and_yield( file ) expect( file ).to receive( :puts ).with( content ).once expect( host ).to receive( :do_scp_to ).with( tempfilepath, filepath, subject.instance_variable_get( :@options ) ).once subject.copy_file_to_remote(host, filepath, content) end end context "proxy_config" do subject { dummy_class.new } it "correctly configures ubuntu hosts" do hosts = make_hosts( { :platform => 'ubuntu', :exit_code => 1 } ) expect( Beaker::Command ).to receive( :new ).with( "if test -f /etc/apt/apt.conf; then mv /etc/apt/apt.conf /etc/apt/apt.conf.bk; fi" ).exactly( 3 ) hosts.each do |host| expect( subject ).to receive( :copy_file_to_remote ).with( host, '/etc/apt/apt.conf', apt_cfg ).once expect( subject ).to receive( :apt_get_update ).with( host ).once end subject.proxy_config( hosts, options ) end it "correctly configures debian hosts" do hosts = make_hosts( { :platform => 'debian' } ) expect( Beaker::Command ).to receive( :new ).with( "if test -f /etc/apt/apt.conf; then mv /etc/apt/apt.conf /etc/apt/apt.conf.bk; fi" ).exactly( 3 ).times hosts.each do |host| expect( subject ).to receive( :copy_file_to_remote ).with( host, '/etc/apt/apt.conf', apt_cfg ).once expect( subject ).to receive( :apt_get_update ).with( host ).once end subject.proxy_config( hosts, options ) end it "correctly configures cumulus hosts" do hosts = make_hosts( { :platform => 'cumulus' } ) expect( Beaker::Command ).to receive( :new ).with( "if test -f /etc/apt/apt.conf; then mv /etc/apt/apt.conf /etc/apt/apt.conf.bk; fi" ).exactly( 3 ).times hosts.each do |host| expect( subject ).to receive( :copy_file_to_remote ).with( host, '/etc/apt/apt.conf', apt_cfg ).once expect( subject ).to receive( :apt_get_update ).with( host ).once end subject.proxy_config( hosts, options ) end it "correctly configures solaris-11 hosts" do hosts = make_hosts( { :platform => 'solaris-11' } ) expect( Beaker::Command ).to receive( :new ).with( "/usr/bin/pkg unset-publisher solaris || :" ).exactly( 3 ).times hosts.each do |host| expect( Beaker::Command ).to receive( :new ).with( "/usr/bin/pkg set-publisher -g %s solaris" % ips_pkg_repo ).once end subject.proxy_config( hosts, options ) end it "does nothing for non ubuntu/debian/cumulus/solaris-11 hosts" do hosts = make_hosts( { :platform => 'windows' } ) expect( Beaker::Command ).to receive( :new ).never subject.proxy_config( hosts, options ) end end context "add_el_extras" do subject { dummy_class.new } it "add extras for el-5/6 hosts" do hosts = make_hosts( { :platform => Beaker::Platform.new('el-5-arch'), :exit_code => 1 }, 6 ) hosts[0][:platform] = Beaker::Platform.new('el-6-arch') hosts[1][:platform] = Beaker::Platform.new('centos-6-arch') hosts[2][:platform] = Beaker::Platform.new('scientific-6-arch') hosts[3][:platform] = Beaker::Platform.new('redhat-6-arch') hosts[4][:platform] = Beaker::Platform.new('oracle-5-arch') expect( Beaker::Command ).to receive( :new ).with("rpm -qa | grep epel-release").exactly( 6 ).times expect( Beaker::Command ).to receive( :new ).with("rpm -i http://mirrors.kernel.org/fedora-epel/6/i386/epel-release-6-8.noarch.rpm").exactly( 4 ).times expect( Beaker::Command ).to receive( :new ).with("rpm -i http://mirrors.kernel.org/fedora-epel/5/i386/epel-release-5-4.noarch.rpm").exactly( 2 ).times expect( Beaker::Command ).to receive( :new ).with("sed -i -e 's;#baseurl.*$;baseurl=http://mirrors\\.kernel\\.org/fedora\\-epel/6/$basearch;' /etc/yum.repos.d/epel.repo").exactly( 4 ).times expect( Beaker::Command ).to receive( :new ).with("sed -i -e 's;#baseurl.*$;baseurl=http://mirrors\\.kernel\\.org/fedora\\-epel/5/$basearch;' /etc/yum.repos.d/epel.repo").exactly( 2 ).times expect( Beaker::Command ).to receive( :new ).with("sed -i -e '/mirrorlist/d' /etc/yum.repos.d/epel.repo").exactly( 6 ).times expect( Beaker::Command ).to receive( :new ).with("yum clean all && yum makecache").exactly( 6 ).times subject.add_el_extras( hosts, options ) end it "should do nothing for non el-5/6 hosts" do hosts = make_hosts( { :platform => Beaker::Platform.new('windows-version-arch') } ) expect( Beaker::Command ).to receive( :new ).never subject.add_el_extras( hosts, options ) end end context "sync_root_keys" do subject { dummy_class.new } it "can sync keys on a solaris/eos host" do @platform = 'solaris' expect( Beaker::Command ).to receive( :new ).with( sync_cmd % "bash" ).exactly( 3 ).times subject.sync_root_keys( hosts, options ) end it "can sync keys on a non-solaris host" do expect( Beaker::Command ).to receive( :new ).with( sync_cmd % "env PATH=/usr/gnu/bin:$PATH bash" ).exactly( 3 ).times subject.sync_root_keys( hosts, options ) end end context "validate_host" do subject { dummy_class.new } it "can validate unix hosts" do hosts.each do |host| unix_only_pkgs.each do |pkg| expect( host ).to receive( :check_for_package ).with( pkg ).once.and_return( false ) expect( host ).to receive( :install_package ).with( pkg ).once end end subject.validate_host(hosts, options) end it "can validate windows hosts" do @platform = 'windows' hosts.each do |host| windows_pkgs.each do |pkg| allow( host ).to receive( :is_cygwin? ).and_return( true ) expect( host ).to receive( :check_for_package ).with( pkg ).once.and_return( false ) expect( host ).to receive( :install_package ).with( pkg ).once end end subject.validate_host(hosts, options) end it "can validate SLES hosts" do @platform = 'sles-13.1-x64' hosts.each do |host| sles_only_pkgs.each do |pkg| expect( host ).to receive( :check_for_package).with( pkg ).once.and_return( false ) expect( host ).to receive( :install_package ).with( pkg ).once end end subject.validate_host(hosts, options) end end context 'get_domain_name' do subject { dummy_class.new } it "can find the domain for a host" do host = make_host('name', { :stdout => "domain labs.lan d.labs.net dc1.labs.net labs.com\nnameserver 10.16.22.10\nnameserver 10.16.22.11" } ) expect( Beaker::Command ).to receive( :new ).with( "cat /etc/resolv.conf" ).once expect( subject.get_domain_name( host ) ).to be === "labs.lan" end it "can find the search for a host" do host = make_host('name', { :stdout => "search labs.lan d.labs.net dc1.labs.net labs.com\nnameserver 10.16.22.10\nnameserver 10.16.22.11" } ) expect( Beaker::Command ).to receive( :new ).with( "cat /etc/resolv.conf" ).once expect( subject.get_domain_name( host ) ).to be === "labs.lan" end end context "get_ip" do subject { dummy_class.new } it "can exec the get_ip command" do host = make_host('name', { :stdout => "192.168.2.130\n" } ) expect( Beaker::Command ).to receive( :new ).with( "ip a|awk '/global/{print$2}' | cut -d/ -f1 | head -1", [], {:prepend_cmds=>nil, :cmdexe=>false} ).once expect( subject.get_ip( host ) ).to be === "192.168.2.130" end end context "set_etc_hosts" do subject { dummy_class.new } it "can set the /etc/hosts string on a host" do host = make_host('name', {}) etc_hosts = "127.0.0.1 localhost\n192.168.2.130 pe-ubuntu-lucid\n192.168.2.128 pe-centos6\n192.168.2.131 pe-debian6" expect( Beaker::Command ).to receive( :new ).with( "echo '#{etc_hosts}' > /etc/hosts" ).once expect( host ).to receive( :exec ).once subject.set_etc_hosts(host, etc_hosts) end end context "package_proxy" do subject { dummy_class.new } proxyurl = "http://192.168.2.100:3128" it "can set proxy config on a debian/ubuntu/cumulus host" do host = make_host('name', { :platform => 'cumulus' } ) expect( Beaker::Command ).to receive( :new ).with( "echo 'Acquire::http::Proxy \"#{proxyurl}/\";' >> /etc/apt/apt.conf.d/10proxy" ).once expect( host ).to receive( :exec ).once subject.package_proxy(host, options.merge( {'package_proxy' => proxyurl}) ) end it "can set proxy config on a centos host" do host = make_host('name', { :platform => 'centos' } ) expect( Beaker::Command ).to receive( :new ).with( "echo 'proxy=#{proxyurl}/' >> /etc/yum.conf" ).once expect( host ).to receive( :exec ).once subject.package_proxy(host, options.merge( {'package_proxy' => proxyurl}) ) end end context "set_env" do subject { dummy_class.new } it "can set the environment on a windows host" do commands = [ "echo '\nPermitUserEnvironment yes' >> /etc/sshd_config", "cygrunsrv -E sshd", "cygrunsrv -S sshd" ] set_env_helper('windows', commands) end it "can set the environment on an OS X host" do commands = [ "echo '\nPermitUserEnvironment yes' >> /etc/sshd_config", "launchctl unload /System/Library/LaunchDaemons/ssh.plist", "launchctl load /System/Library/LaunchDaemons/ssh.plist" ] set_env_helper('osx', commands) end it "can set the environment on an ssh-based linux host" do commands = [ "echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config", "service ssh restart" ] set_env_helper('ubuntu', commands) end it "can set the environment on an sshd-based linux host" do commands = [ "echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config", "/sbin/service sshd restart" ] set_env_helper('eos', commands) end it "can set the environment on an sles host" do commands = [ "echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config", "rcsshd restart" ] set_env_helper('sles', commands) end it "can set the environment on a solaris host" do commands = [ "echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config", "svcadm restart svc:/network/ssh:default" ] set_env_helper('solaris', commands) end it "can set the environment on an aix host" do commands = [ "echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config", "stopsrc -g ssh", "startsrc -g ssh" ] set_env_helper('aix', commands) end it "can set the environment on a FreeBSD host" do commands = [ "sudo perl -pi -e 's/^#?PermitUserEnvironment no/PermitUserEnvironment yes/' /etc/ssh/sshd_config", "sudo /etc/rc.d/sshd restart", ] set_env_helper('freebsd', commands) end def set_env_helper(platform_name, host_specific_commands_array) host = make_host('name', { :platform => platform_name, :ssh_env_file => 'ssh_env_file', :is_cygwin => true, } ) opts = { :env1_key => :env1_value, :env2_key => :env2_value } expect( subject ).to receive( :construct_env ).and_return( opts ) host_specific_commands_array.each do |command| expect( Beaker::Command ).to receive( :new ).with( command ).once end expect( Beaker::Command ).to receive( :new ).with( "mkdir -p #{Pathname.new(host[:ssh_env_file]).dirname}" ).once expect( Beaker::Command ).to receive( :new ).with( "chmod 0600 #{Pathname.new(host[:ssh_env_file]).dirname}" ).once expect( Beaker::Command ).to receive( :new ).with( "touch #{host[:ssh_env_file]}" ).once expect_any_instance_of( Class ).to receive( :extend ).and_return( double( 'class' ).as_null_object ) expect( Beaker::Command ).to receive( :new ).with( "cat #{host[:ssh_env_file]}" ).once expect( host ).to receive( :add_env_var ).with( 'PATH', '$PATH' ).once opts.each_pair do |key, value| expect( host ).to receive( :add_env_var ).with( key, value ).once end expect( host ).to receive( :add_env_var ).with( 'CYGWIN', 'nodosfilewarning' ).once if platform_name =~ /windows/ expect( host ).to receive( :exec ).exactly( host_specific_commands_array.length + 4 ).times subject.set_env(host, options.merge( opts )) end end end