lib/beaker/dsl/helpers.rb in beaker-1.10.0 vs lib/beaker/dsl/helpers.rb in beaker-1.11.0

- old
+ new

@@ -11,10 +11,11 @@ # prepare the state of a test case. # # To mix this is into a class you need the following: # * a method *hosts* that yields any hosts implementing # {Beaker::Host}'s interface to act upon. + # * a method *options* that provides an options hash, see {Beaker::Options::OptionsHash} # * a method *logger* that yields a logger implementing # {Beaker::Logger}'s interface. # * the module {Beaker::DSL::Roles} that provides access to the various hosts implementing # {Beaker::Host}'s interface to act upon # * the module {Beaker::DSL::Wrappers} the provides convenience methods for {Beaker::DSL::Command} creation @@ -243,11 +244,11 @@ # # @param [Host] host # @param [String] path The path to the generated repository config # files. ex: /myproject/pkg/repo_configs # @param [String] name A human-readable name for the repository - # @param [String[ version The version of the project, as used by the + # @param [String] version The version of the project, as used by the # packaging tools. This can be determined with # `rake pl:print_build_params` from the packaging # repo. def deploy_package_repo host, path, name, version host.deploy_package_repo path, name, version @@ -665,11 +666,11 @@ # command completion. If provided, these values will # be combined with those used in :catch_failures and # :expect_failures to create the full list of # passing exit codes. # - # @options opts [Hash] :environment Additional environment variables to be + # @option opts [Hash] :environment Additional environment variables to be # passed to the 'puppet apply' command # # @option opts [Boolean] :catch_failures (false) By default `puppet # --apply` will exit with 0, which does not count # as a test failure, even if there were errors or @@ -696,10 +697,15 @@ # @option opts [Boolean] :future_parser (false) This option enables # the future parser option that is available # from Puppet verion 3.2 # By default it will use the 'current' parser. # + # @option opts [String] :modulepath The search path for modules, as + # a list of directories separated by the system + # path separator character. (The POSIX path separator + # is ‘:’, and the Windows path separator is ‘;’.) + # # @param [Block] block This method will yield to a block of code passed # by the caller; this can be used for additional # validation, etc. # def apply_manifest_on(host, manifest, opts = {}, &block) @@ -714,10 +720,11 @@ args = ["--verbose"] args << "--parseonly" if opts[:parseonly] args << "--trace" if opts[:trace] args << "--parser future" if opts[:future_parser] + args << "--modulepath #{opts[:modulepath]}" if opts[:modulepath] # From puppet help: # "... an exit code of '2' means there were changes, an exit code of # '4' means there were failures during the transaction, and an exit # code of '6' means there were both changes and failures." @@ -858,22 +865,28 @@ # # forge api v1 canonical source is forge.puppetlabs.com # forge api v3 canonical source is forgeapi.puppetlabs.com # # @param machine [String] the host to perform the stub on - def stub_forge_on(machine) - @forge_ip ||= Resolv.getaddress(forge) + # @param forge_host [String] The URL to use as the forge alias, will default to using :forge_host in the + # global options hash + def stub_forge_on(machine, forge_host = nil) + #use global options hash + forge_host ||= options[:forge_host] + @forge_ip ||= Resolv.getaddress(forge_host) stub_hosts_on(machine, 'forge.puppetlabs.com' => @forge_ip) stub_hosts_on(machine, 'forgeapi.puppetlabs.com' => @forge_ip) end # This wraps the method `stub_hosts` and makes the stub specific to # the forge alias. # # @see #stub_forge_on - def stub_forge - stub_forge_on(default) + def stub_forge(forge_host = nil) + #use global options hash + forge_host ||= options[:forge_host] + stub_forge_on(default, forge_host) end def sleep_until_puppetdb_started(host) curl_with_retries("start puppetdb", host, "http://localhost:8080", 0, 120) curl_with_retries("start puppetdb (ssl)", @@ -1006,9 +1019,127 @@ else on host, "curl %s" % cmd, opts, &block end end + + #Install local module for acceptance testing + # should be used as a presuite to ensure local module is copied to the hosts you want, particularly masters + # @api dsl + # @param [Host, Array<Host>, String, Symbol] host + # One or more hosts to act upon, + # or a role (String or Symbol) that identifies one or more hosts. + # @option opts [String] :source ('./') + # The current directory where the module sits, otherwise will try + # and walk the tree to figure out + # @option opts [String] :module_name (nil) + # Name which the module should be installed under, please do not include author, + # if none is provided it will attempt to parse the metadata.json and then the Modulefile to determine + # the name of the module + # @option opts [String] :target_module_path (host['puppetpath']/modules) + # Location where the module should be installed, will default + # to host['puppetpath']/modules + # @raise [ArgumentError] if not host is provided or module_name is not provided and can not be found in Modulefile + # + def copy_root_module_to(host, opts = {}) + if !host + raise(ArgumentError, "Host must be defined") + end + source = opts[:source] || parse_for_moduleroot(Dir.getwd) + target_module_path = opts[:target_module_path] || "#{host['puppetpath']}/modules" + + module_name = opts[:module_name] || parse_for_modulename(source) + if !module_name + logger.debug('Still unable to determine the modulename') + raise(ArgumentError, "Unable to determine the module name, please update your call of puppet_module_install") + end + + module_dir = File.join(target_module_path, module_name) + on host, "mkdir -p #{target_module_path}" + ['manifests', 'lib', 'templates', 'metadata.json', 'Modulefile', 'files', 'Gemfile'].each do |item| + item_source = File.join(source, item) + if File.exists? item_source + options = {} + if File.directory? item_source + on host, "mkdir -p #{File.join(module_dir, item)}" + options = { :mkdir => true } + end + host.do_scp_to(item_source, module_dir, options) + end + end + end + + + #Recursive method for finding the module root + # Assumes that a Modulefile exists + # @param [String] possible_module_directory + # will look for Modulefile and if none found go up one level and try again until root is reached + # + # @return [String,nil] + def parse_for_moduleroot(possible_module_directory) + if File.exists?("#{possible_module_directory}/Modulefile") + possible_module_directory + elsif possible_module_directory === '/' + logger.error "At root, can't parse for another directory" + nil + else + logger.debug "No Modulefile found at #{possible_module_directory}, moving up" + parse_for_moduleroot File.expand_path(File.join(possible_module_directory,'..')) + end + end + + + #Parse root directory of a module for module name + # Searches for metadata.json and then if none found, Modulefile and parses for the Name attribute + # @param [String] root_module_dir + # @return [String] module name + def parse_for_modulename(root_module_dir) + module_name = nil + if File.exists?("#{root_module_dir}/metadata.json") + logger.debug "Attempting to parse Modulename from metadata.json" + module_json = JSON.parse (File.read "#{root_module_dir}/metadata.json") + if(module_json.has_key?('name')) + module_name = get_module_name(module_json['name']) + end + end + if !module_name && File.exists?("#{root_module_dir}/Modulefile") + logger.debug "Attempting to parse Modulename from Modulefile" + if /^name\s+'?(\w+-\w+)'?\s*$/i.match(File.read("#{root_module_dir}/Modulefile")) + module_name = get_module_name(Regexp.last_match[1]) + end + end + if !module_name + logger.debug "Unable to determine name, returning null" + end + module_name + end + + #Parse modulename from the pattern 'Auther-ModuleName' + # + # @param [String] author_module_name <Author>-<ModuleName> pattern + # + # @return [String,nil] + # + def get_module_name(author_module_name) + split_name = split_author_modulename(author_module_name) + if split_name + split_name[:module] + end + end + + #Split the Author-Name into a hash + # @param [String] author_module_attr + # + # @return [Hash<Symbol,String>,nil] :author and :module symbols will be returned + # + def split_author_modulename(author_module_attr) + result = /(\w+)-(\w+)/.match(author_module_attr) + if result + {:author => result[1], :module => result[2]} + else + nil + end + end end end end