diff --git a/acceptance/lib/puppet/acceptance/module_utils.rb b/acceptance/lib/puppet/acceptance/module_utils.rb index cc009e050..5b6124998 100644 --- a/acceptance/lib/puppet/acceptance/module_utils.rb +++ b/acceptance/lib/puppet/acceptance/module_utils.rb @@ -1,279 +1,282 @@ module Puppet module Acceptance module ModuleUtils # Return an array of module paths for a given host. # # Example return value: # # [ # "/etc/puppetlabs/puppet/environments/production/modules", # "/etc/puppetlabs/puppet/modules", # "/opt/puppet/share/puppet/modules", # ] # # @param host [String] hostname # @return [Array] paths for found modulepath def get_modulepaths_for_host (host) separator = ':' if host['platform'] =~ /windows/ separator = ';' end environment = on(host, puppet("config print environment")).stdout.chomp on(host, puppet("config print modulepath --environment #{environment}")).stdout.chomp.split(separator) end # Return a string of the default (first) path in modulepath for a given host. # # Example return value: # # "/etc/puppetlabs/puppet/environments/production/modules" # # @param host [String] hostname # @return [String] first path for found modulepath def get_default_modulepath_for_host (host) get_modulepaths_for_host(host)[0] end # Return an array of paths to installed modules for a given host. # # Example return value: # # [ # "/opt/puppet/share/puppet/modules/apt", # "/opt/puppet/share/puppet/modules/auth_conf", # "/opt/puppet/share/puppet/modules/concat", # ] # # @param host [String] hostname # @return [Array] paths for found modules def get_installed_modules_for_host (host) on host, puppet("module list --render-as pson") str = stdout.lines.to_a.last pat = /\(([^()]+)\)/ mods = str.scan(pat).flatten return mods end # Return a hash of array of paths to installed modules for a hosts. # The individual hostnames are the keys of the hash. The only value # for a given key is an array of paths for the found modules. # # Example return value: # # { # "my_master" => # [ # "/opt/puppet/share/puppet/modules/apt", # "/opt/puppet/share/puppet/modules/auth_conf", # "/opt/puppet/share/puppet/modules/concat", # ], # "my_agent01" => # [ # "/opt/puppet/share/puppet/modules/apt", # "/opt/puppet/share/puppet/modules/auth_conf", # "/opt/puppet/share/puppet/modules/concat", # ], # } # # @param hosts [Array] hostnames # @return [Hash] paths for found modules indexed by hostname def get_installed_modules_for_hosts (hosts) mods = {} hosts.each do |host| mods[host] = get_installed_modules_for_host host end return mods end # Compare the module paths in given hashes and remove paths that # are were not present in the first hash. The use case for this # method is to remove any modules that were installed during the # course of a test run. # # Installed module hashes would be gathered using the # `get_+installed_module_for_hosts` command in the setup stage # and teardown stages of a test. These hashes would be passed into # this method in order to find modules installed during the test # and delete them in order to return the SUT environments to their # initial state. # # TODO: Enhance to take versions into account, so that upgrade/ # downgrade events during a test does not persist in the SUT # environment. # # @param beginning_hash [Hash] paths for found modules indexed # by hostname. Taken in the setup stage of a test. # @param ending_hash [Hash] paths for found modules indexed # by hostname. Taken in the teardown stage of a test. def rm_installed_modules_from_hosts (beginning_hash, ending_hash) ending_hash.each do |host, mod_array| mod_array.each do |mod| if ! beginning_hash[host].include? mod on host, "rm -rf '#{mod}'" end end end end # Convert a semantic version number string to an integer. # # Example return value given an input of '1.2.42': # # 10242 # # @param semver [String] semantic version number def semver_to_i ( semver ) # semver assumed to be in format .. # calculation assumes that each segment is < 100 tmp = semver.split('.') tmp[0].to_i * 10000 + tmp[1].to_i * 100 + tmp[2].to_i end # Compare two given semantic version numbers. # # Returns an integer indicating the relationship between the two: # 0 indicates that both are equal # a value greater than 0 indicates that the semver1 is greater than semver2 # a value less than 0 indicates that the semver1 is less than semver2 # def semver_cmp ( semver1, semver2 ) semver_to_i(semver1) - semver_to_i(semver2) end # Assert that a module was installed according to the UI.. # # This is a wrapper to centralize the validation about how # the UI responded that a module was installed. # It is called after a call # to `on ( host )` and inspects # STDOUT for specific content. # # @param stdout [String] # @param module_author [String] the author portion of a module name # @param module_name [String] the name portion of a module name # @param module_verion [String] the version of the module to compare to # installed version # @param compare_op [String] the operator for comparing the verions of # the installed module def assert_module_installed_ui ( stdout, module_author, module_name, module_version = nil, compare_op = nil ) valid_compare_ops = {'==' => 'equal to', '>' => 'greater than', '<' => 'less than'} assert_match(/#{module_author}-#{module_name}/, stdout, "Notice that module '#{module_author}-#{module_name}' was installed was not displayed") if version /#{module_author}-#{module_name} \(.*v(\d+\.\d+\.\d+)/ =~ stdout installed_version = Regexp.last_match[1] if valid_compare_ops.include? compare_op assert_equal( true, semver_cmp(installed_version, module_version).send(compare_op, 0), "Installed version '#{installed_version}' of '#{module_name}' was not #{valid_compare_ops[compare_op]} '#{module_version}'") end end end # Assert that a module is installed on disk. # # @param host [HOST] the host object to make the remote call on # @param module_name [String] the name portion of a module name # @param optional moduledir [String, Array] the path where the module should be, will # iterate over components of the modulepath by default. def assert_module_installed_on_disk (host, module_name, moduledir=nil) moduledir ||= get_modulepaths_for_host(host) modulepath = moduledir.is_a?(Array) ? moduledir : [moduledir] moduledir= nil modulepath.each do |i| # module directory should exist if on(host, %Q{[ -d "#{i}/#{module_name}" ]}, :acceptable_exit_codes => (0..255)).exit_code == 0 moduledir = i end end fail_test('module directory not found') unless moduledir owner = '' group = '' on host, %Q{ls -ld "#{moduledir}"} do listing = stdout.split(' ') owner = listing[2] group = listing[3] end # A module's files should have: # * a mode of 444 (755, if they're a directory) # * owner == owner of moduledir # * group == group of moduledir on host, %Q{ls -alR "#{moduledir}/#{module_name}"} do listings = stdout.split("\n") listings = listings.grep(/^[bcdlsp-]/) listings = listings.reject { |l| l =~ /\.\.$/ } listings.each do |line| assert_match /(drwxr-xr-x|[^d]r--r--r--)[^\d]+\d+\s+#{owner}\s+#{group}/, line, "bad permissions for '#{line[/\S+$/]}' - expected 444/755, #{owner}, #{group}" end end end # Assert that a module is not installed on disk. # # @param host [HOST] the host object to make the remote call on # @param module_name [String] the name portion of a module name # @param optional moduledir [String, Array] the path where the module should be, will # iterate over components of the modulepath by default. def assert_module_not_installed_on_disk (host, module_name, moduledir=nil) moduledir ||= get_modulepaths_for_host(host) modulepath = moduledir.is_a?(Array) ? moduledir : [moduledir] moduledir= nil modulepath.each do |i| # module directory should not exist on host, %Q{[ ! -d "#{i}/#{module_name}" ]} end end # Create a simple legacy and directory environment at :path_to_environments. # # @note Also registers a teardown block to remove generated files. # # @param path_to_environments [String] directory to contain all the # generated environment files # @return [String] path to the new puppet configuration file defining the # environments def generate_base_legacy_and_directory_environments(path_to_environments) puppet_conf = "#{path_to_environments}/puppet2.conf" legacy_env = "#{path_to_environments}/legacyenv" dir_envs = "#{path_to_environments}/environments" step "ensure we don't have left over bad state from another, possibly failed run" on master, "rm -rf #{legacy_env} #{dir_envs} #{puppet_conf}" # and register to clean up afterwords teardown do on master, "rm -rf #{legacy_env} #{dir_envs} #{puppet_conf}" end step 'Configure a non-default legacy and directory environment' apply_manifest_on master, %Q{ file { [ '#{legacy_env}', '#{legacy_env}/modules', '#{dir_envs}', '#{dir_envs}/direnv', ]: ensure => directory, } file { '#{puppet_conf}': source => $settings::config, } } + # remove environmentpath entry from config + on master, "sed '/environmentpath/d' #{puppet_conf} > #{path_to_environments}/tmp && mv #{path_to_environments}/tmp #{puppet_conf}" + on master, puppet("config", "set", "modulepath", "#{legacy_env}/modules", "--section", "legacyenv", "--config", puppet_conf) return puppet_conf end end end end diff --git a/acceptance/tests/modules/install/with_environment.rb b/acceptance/tests/modules/install/with_environment.rb index dcba46e45..fa608f230 100644 --- a/acceptance/tests/modules/install/with_environment.rb +++ b/acceptance/tests/modules/install/with_environment.rb @@ -1,74 +1,72 @@ test_name 'puppet module install (with environment)' require 'puppet/acceptance/module_utils' extend Puppet::Acceptance::ModuleUtils -if master.is_pe? - skip_test -end +tmpdir = master.tmpdir('environmentpath') module_author = "pmtacceptance" module_name = "nginx" orig_installed_modules = get_installed_modules_for_hosts hosts teardown do rm_installed_modules_from_hosts orig_installed_modules, (get_installed_modules_for_hosts hosts) end step 'Setup' stub_forge_on(master) -puppet_conf = generate_base_legacy_and_directory_environments(master['puppetpath']) +puppet_conf = generate_base_legacy_and_directory_environments(tmpdir) check_module_install_in = lambda do |environment_path, module_install_args| on master, "puppet module install #{module_author}-#{module_name} --config=#{puppet_conf} #{module_install_args}" do assert_module_installed_ui(stdout, module_author, module_name) assert_match(/#{environment_path}/, stdout, "Notice of non default install path was not displayed") end assert_module_installed_on_disk(master, module_name, environment_path) end step 'Install a module into a non default legacy environment' do - check_module_install_in.call("#{master['puppetpath']}/legacyenv/modules", + check_module_install_in.call("#{tmpdir}/legacyenv/modules", "--environment=legacyenv") end step 'Enable directory environments' do on master, puppet("config", "set", - "environmentpath", "#{master['puppetpath']}/environments", + "environmentpath", "#{tmpdir}/environments", "--section", "main", "--config", puppet_conf) end step 'Install a module into a non default directory environment' do - check_module_install_in.call("#{master['puppetpath']}/environments/direnv/modules", + check_module_install_in.call("#{tmpdir}/environments/direnv/modules", "--environment=direnv") end step 'Prepare a separate modulepath' modulepath_dir = master.tmpdir("modulepath") apply_manifest_on(master, <<-MANIFEST , :catch_failures => true) file { [ - '#{master['puppetpath']}/environments/production', + '#{tmpdir}/environments/production', '#{modulepath_dir}', ]: ensure => directory, owner => #{master['user']}, } MANIFEST step "Install a module into --modulepath #{modulepath_dir} despite the implicit production directory env existing" do check_module_install_in.call(modulepath_dir, "--modulepath=#{modulepath_dir}") end step "Uninstall so we can try a different scenario" do on master, "puppet module uninstall #{module_author}-#{module_name} --config=#{puppet_conf} --modulepath=#{modulepath_dir}" end step "Install a module into --modulepath #{modulepath_dir} with a directory env specified" do check_module_install_in.call(modulepath_dir, "--modulepath=#{modulepath_dir} --environment=direnv") end diff --git a/acceptance/tests/modules/list/with_environment.rb b/acceptance/tests/modules/list/with_environment.rb index fd6515c9d..e57138150 100644 --- a/acceptance/tests/modules/list/with_environment.rb +++ b/acceptance/tests/modules/list/with_environment.rb @@ -1,47 +1,45 @@ test_name 'puppet module list (with environment)' require 'puppet/acceptance/module_utils' extend Puppet::Acceptance::ModuleUtils -if master.is_pe? - skip_test -end +tmpdir = master.tmpdir('environmentpath') step 'Setup' stub_forge_on(master) -puppet_conf = generate_base_legacy_and_directory_environments(master['puppetpath']) +puppet_conf = generate_base_legacy_and_directory_environments(tmpdir) install_test_module_in = lambda do |environment| on master, puppet("module", "install", "pmtacceptance-nginx", "--config", puppet_conf, "--environment", environment) end check_module_list_in = lambda do |environment, environment_path| on master, puppet("module", "list", "--config", puppet_conf, "--environment", environment) do assert_match(/#{environment_path}/, stdout) assert_match(/pmtacceptance-nginx/, stdout) end end step 'List modules in a non default legacy environment' do install_test_module_in.call('legacyenv') - check_module_list_in.call('legacyenv', "#{master['puppetpath']}/legacyenv/modules") + check_module_list_in.call('legacyenv', "#{tmpdir}/legacyenv/modules") end step 'Enable directory environments' do on master, puppet("config", "set", - "environmentpath", "#{master['puppetpath']}/environments", + "environmentpath", "#{tmpdir}/environments", "--section", "main", "--config", puppet_conf) end step 'List modules in a non default directory environment' do install_test_module_in.call('direnv') - check_module_list_in.call('direnv', "#{master['puppetpath']}/environments/direnv/modules") + check_module_list_in.call('direnv', "#{tmpdir}/environments/direnv/modules") end diff --git a/acceptance/tests/modules/uninstall/with_environment.rb b/acceptance/tests/modules/uninstall/with_environment.rb index c8a438da0..77a682f14 100644 --- a/acceptance/tests/modules/uninstall/with_environment.rb +++ b/acceptance/tests/modules/uninstall/with_environment.rb @@ -1,69 +1,67 @@ test_name 'puppet module uninstall (with environment)' require 'puppet/acceptance/module_utils' extend Puppet::Acceptance::ModuleUtils -if master.is_pe? - skip_test -end +tmpdir = master.tmpdir('environmentpath') step 'Setup' stub_forge_on(master) -puppet_conf = generate_base_legacy_and_directory_environments(master['puppetpath']) +puppet_conf = generate_base_legacy_and_directory_environments(tmpdir) crakorn_metadata = <<-EOS { "name": "jimmy/crakorn", "version": "0.4.0", "source": "", "author": "jimmy", "license": "MIT", "dependencies": [] } EOS # Configure a non-default environment apply_manifest_on master, %Q{ file { [ - '#{master['puppetpath']}/legacyenv/modules/crakorn', - '#{master['puppetpath']}/environments/direnv/modules', - '#{master['puppetpath']}/environments/direnv/modules/crakorn', + '#{tmpdir}/legacyenv/modules/crakorn', + '#{tmpdir}/environments/direnv/modules', + '#{tmpdir}/environments/direnv/modules/crakorn', ]: ensure => directory, } file { - '#{master['puppetpath']}/legacyenv/modules/crakorn/metadata.json': + '#{tmpdir}/legacyenv/modules/crakorn/metadata.json': content => '#{crakorn_metadata}', } file { - '#{master['puppetpath']}/environments/direnv/modules/crakorn/metadata.json': + '#{tmpdir}/environments/direnv/modules/crakorn/metadata.json': content => '#{crakorn_metadata}', } } check_module_uninstall_in = lambda do |environment, environment_path| on master, "puppet module uninstall jimmy-crakorn --config=#{puppet_conf} --environment=#{environment}" do assert_equal <<-OUTPUT, stdout \e[mNotice: Preparing to uninstall 'jimmy-crakorn' ...\e[0m Removed 'jimmy-crakorn' (\e[0;36mv0.4.0\e[0m) from #{environment_path} OUTPUT end on master, "[ ! -d #{environment_path}/crakorn ]" end step 'Uninstall a module from a non default legacy environment' do - check_module_uninstall_in.call('legacyenv', "#{master['puppetpath']}/legacyenv/modules") + check_module_uninstall_in.call('legacyenv', "#{tmpdir}/legacyenv/modules") end step 'Enable directory environments' do on master, puppet("config", "set", - "environmentpath", "#{master['puppetpath']}/environments", + "environmentpath", "#{tmpdir}/environments", "--section", "main", "--config", puppet_conf) end step 'Uninstall a module from a non default directory environment' do - check_module_uninstall_in.call('direnv', "#{master['puppetpath']}/environments/direnv/modules") + check_module_uninstall_in.call('direnv', "#{tmpdir}/environments/direnv/modules") end diff --git a/acceptance/tests/modules/upgrade/with_environment.rb b/acceptance/tests/modules/upgrade/with_environment.rb index de8077486..3a4aa8c72 100644 --- a/acceptance/tests/modules/upgrade/with_environment.rb +++ b/acceptance/tests/modules/upgrade/with_environment.rb @@ -1,53 +1,51 @@ test_name "puppet module upgrade (with environment)" require 'puppet/acceptance/module_utils' extend Puppet::Acceptance::ModuleUtils -if master.is_pe? - skip_test -end +tmpdir = master.tmpdir('environmentpath') module_author = "pmtacceptance" module_name = "java" module_dependencies = ["stdlub"] orig_installed_modules = get_installed_modules_for_hosts hosts teardown do rm_installed_modules_from_hosts orig_installed_modules, (get_installed_modules_for_hosts hosts) end step 'Setup' stub_forge_on(master) -puppet_conf = generate_base_legacy_and_directory_environments(master['puppetpath']) +puppet_conf = generate_base_legacy_and_directory_environments(tmpdir) install_test_module_in = lambda do |environment| on master, puppet("module install #{module_author}-#{module_name} --config=#{puppet_conf} --version 1.6.0 --environment=#{environment}") do assert_module_installed_ui(stdout, module_author, module_name) end end check_module_upgrade_in = lambda do |environment, environment_path| on master, puppet("module upgrade #{module_author}-#{module_name} --config=#{puppet_conf} --environment=#{environment}") do assert_module_installed_ui(stdout, module_author, module_name) on master, "[ -f #{environment_path}/#{module_name}/Modulefile ]" on master, "grep 1.7.1 #{environment_path}/#{module_name}/Modulefile" end end step "Upgrade a module that has a more recent version published in a legacy environment" do install_test_module_in.call('legacyenv') - check_module_upgrade_in.call('legacyenv', "#{master['puppetpath']}/legacyenv/modules") + check_module_upgrade_in.call('legacyenv', "#{tmpdir}/legacyenv/modules") end step 'Enable directory environments' do on master, puppet("config", "set", - "environmentpath", "#{master['puppetpath']}/environments", + "environmentpath", "#{tmpdir}/environments", "--section", "main", "--config", puppet_conf) end step "Upgrade a module that has a more recent version published in a directory environment" do install_test_module_in.call('direnv') - check_module_upgrade_in.call('direnv', "#{master['puppetpath']}/environments/direnv/modules") + check_module_upgrade_in.call('direnv', "#{tmpdir}/environments/direnv/modules") end