Class: Beaker::Options::Parser
- Inherits:
-
Object
- Object
- Beaker::Options::Parser
- Defined in:
- lib/beaker/options/parser.rb
Overview
An Object that parses, merges and normalizes all supported Beaker options and arguments
Constant Summary collapse
- GITREPO =
'git://github.com/puppetlabs'
- LONG_OPTS =
These options can have the form of arg1,arg2 or [arg] or just arg, should default to []
[:helper, :load_path, :tests, :pre_suite, :post_suite, :install, :modules]
- RB_FILE_OPTS =
These options expand out into an array of .rb files
[:tests, :pre_suite, :post_suite]
- PARSE_ERROR =
Psych::SyntaxError
Instance Attribute Summary collapse
-
#options ⇒ Object
The OptionsHash of all parsed options.
Instance Method Summary collapse
-
#check_yaml_file(f, msg = "") ⇒ Object
Determine is a given file exists and is a valid YAML file.
-
#file_list(paths) ⇒ Array
Generates a list of files based upon a given path or list of paths.
-
#initialize ⇒ Parser
constructor
Constructor for Parser.
-
#normalize_and_validate_tags ⇒ Object
Takes tag arguments given at this point, which are strings, converts them into the proper format (an array of strings) for Beaker use, and lastly, validates them.
-
#normalize_args ⇒ Object
Validate all merged options values for correctness.
-
#parse_args(args = ARGV) ⇒ Object
Parses ARGV or provided arguments array, file options, hosts options and combines with environment variables and preset defaults to generate a Hash representing the Beaker options for a given test run.
-
#parse_git_repos(git_opts) ⇒ Array
Converts array of paths into array of fully qualified git repo URLS with expanded keywords.
-
#parser_error(msg = "") ⇒ Object
Raises an ArgumentError with associated message.
-
#repo ⇒ String
Returns the git repository used for git installations.
-
#resolve_symlinks ⇒ Object
resolves all file symlinks that require it.
-
#set_default_host!(hosts) ⇒ Object
Add the ‘default’ role to the host determined to be the default.
-
#split_arg(arg) ⇒ Array
Normalizes argument into an Array.
-
#usage ⇒ String
Returns a description of Beaker’s supported arguments.
Constructor Details
Instance Attribute Details
#options ⇒ Object
The OptionsHash of all parsed options
17 18 19 |
# File 'lib/beaker/options/parser.rb', line 17 def @options end |
Instance Method Details
#check_yaml_file(f, msg = "") ⇒ Object
Determine is a given file exists and is a valid YAML file
221 222 223 224 225 226 227 228 229 230 |
# File 'lib/beaker/options/parser.rb', line 221 def check_yaml_file(f, msg = "") if not File.file?(f) parser_error "#{f} does not exist (#{msg})" end begin YAML.load_file(f) rescue PARSE_ERROR => e parser_error "#{f} is not a valid YAML file (#{msg})\n\t#{e}" end end |
#file_list(paths) ⇒ Array
Generates a list of files based upon a given path or list of paths.
Looks recursively for .rb files in paths.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/beaker/options/parser.rb', line 68 def file_list(paths) files = [] if not paths.empty? paths.each do |root| if File.file?(root) files << root elsif File.directory?(root) #expand and explore discover_files = Dir.glob( File.join(root, "**/*.rb") ).select { |f| File.file?(f) } if discover_files.empty? parser_error "empty directory used as an option (#{root})!" end files += discover_files.sort_by {|file| [file.count("/"), file]} else #not a file, not a directory, not nothin' parser_error "#{root} used as a file option but is not a file or directory!" end end end if files.empty? parser_error "no .rb files found in #{paths.to_s}" end files end |
#normalize_and_validate_tags ⇒ Object
Takes tag arguments given at this point, which are strings, converts them into the proper format (an array of strings) for Beaker use, and lastly, validates them.
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/beaker/options/parser.rb', line 352 def () @options[:tag_includes] ||= '' @options[:tag_excludes] ||= '' @options[:tag_includes] = @options[:tag_includes].split(',') if @options[:tag_includes].respond_to?(:split) @options[:tag_excludes] = @options[:tag_excludes].split(',') if @options[:tag_excludes].respond_to?(:split) @options[:tag_includes].map!(&:downcase) @options[:tag_excludes].map!(&:downcase) #check that a tag is not both included & excluded sets @options[:tag_includes].each do |included_tag| @options[:tag_excludes].each do |excluded_tag| parser_error "tag '#{included_tag}' cannot be in both the included and excluded tag sets" \ if included_tag == excluded_tag end end end |
#normalize_args ⇒ Object
Validate all merged options values for correctness
Currently checks:
- each host has a valid platform
- if a keyfile is provided then use it
- paths provided to --test, --pre-suite, --post-suite provided lists of .rb files for testing
- --fail-mode is one of 'fast', 'stop' or nil
- if using blimpy hypervisor an EC2 YAML file exists
- if using the aix, solaris, or vcloud hypervisors a .fog file exists
- that one and only one master is defined per set of hosts
- that solaris/windows/aix hosts are agent only for PE tests OR
- sets the default host based upon machine definitions
- if an ssh user has been defined make it the host user
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/beaker/options/parser.rb', line 247 def normalize_args @options['HOSTS'].each_key do |name| if not @options['HOSTS'][name]['platform'] parser_error "Host #{name} does not have a platform specified" else @options['HOSTS'][name]['platform'] = Platform.new(@options['HOSTS'][name]['platform']) end end #use the keyfile if present if @options.has_key?(:keyfile) @options[:ssh][:keys] = [@options[:keyfile]] end #split out arguments - these arguments can have the form of arg1,arg2 or [arg] or just arg #will end up being normalized into an array LONG_OPTS.each do |opt| if @options.has_key?(opt) @options[opt] = split_arg(@options[opt]) if RB_FILE_OPTS.include?(opt) && (not @options[opt] == []) @options[opt] = file_list(@options[opt]) end if opt == :install @options[:install] = parse_git_repos(@options[:install]) end else @options[opt] = [] end end #check for valid fail mode if @options[:fail_mode] !~ /stop|fast|slow/ parser_error "--fail-mode must be one of fast or slow, not '#{@options[:fail_mode]}'" end #check for valid preserve_hosts option if @options[:preserve_hosts] !~ /always|onfail|onpass|never/ parser_error "--preserve_hosts must be one of always, onfail, onpass or never, not '#{@options[:preserve_hosts]}'" end #check for config files necessary for different hypervisors hypervisors = [] @options[:HOSTS].each_key do |name| hypervisors << @options[:HOSTS][name][:hypervisor].to_s end hypervisors.uniq! hypervisors.each do |visor| if ['blimpy'].include?(visor) check_yaml_file(@options[:ec2_yaml], "required by #{visor}") end if ['aix', 'solaris', 'vcloud'].include?(visor) check_yaml_file(@options[:dot_fog], "required by #{visor}") end end #check that roles of hosts make sense # - must be one and only one master roles = [] @options[:HOSTS].each_key do |name| roles << @options[:HOSTS][name][:roles] end master = 0 roles.each do |role_array| if role_array.include?('master') master += 1 end if role_array.include?('frictionless') and !(role_array & ['master', 'database', 'dashboard', 'console']).empty? parser_error "Only agent nodes may have the role 'frictionless', fix #{@options[:hosts_file]}" end end if master > 1 parser_error "Only one host/node may have the role 'master', fix #{@options[:hosts_file]}" end #check that windows/el-4 boxes are only agents (solaris can be a master in foss cases) @options[:HOSTS].each_key do |name| host = @options[:HOSTS][name] if host[:platform] =~ /windows|el-4/ test_host_roles(name, host) end #check to see if a custom user account has been provided, if so use it if host[:ssh] && host[:ssh][:user] host[:user] = host[:ssh][:user] end # merge host tags for this host with the global/preset host tags host[:host_tags] = @options[:host_tags].merge(host[:host_tags] || {}) end () resolve_symlinks() #set the default role set_default_host!(@options[:HOSTS]) end |
#parse_args(args = ARGV) ⇒ Object
Parses ARGV or provided arguments array, file options, hosts options and combines with environment variables and preset defaults to generate a Hash representing the Beaker options for a given test run
Order of priority is as follows:
1. environment variables are given top priority
2. ARGV or provided arguments array
3. the 'CONFIG' section of the hosts file
4. options file values
5. default or preset values are given the lowest priority
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/beaker/options/parser.rb', line 179 def parse_args(args = ARGV) @options = @presets.presets = @command_line_parser.parse(args) [:command_line] = ([$0] + args).join(' ') = Beaker::Options::OptionsFileParser.([:options_file]) # merge together command line and file_options # overwrite file options with command line options = .merge() # merge command line and file options with defaults # overwrite defaults with command line and file options @options = @options.merge() if not @options[:help] and not @options[:beaker_version_print] #read the hosts file that contains the node configuration and hypervisor info = Beaker::Options::HostsFileParser.parse_hosts_file(@options[:hosts_file]) # merge in host file vars # overwrite options (default, file options, command line) with host file options @options = @options.merge() # re-merge the command line options # overwrite options (default, file options, hosts file ) with command line arguments @options = @options.merge() # merge in env vars # overwrite options (default, file options, command line, hosts file) with env env_vars = @presets.env_vars @options = @options.merge(env_vars) normalize_args end @options end |
#parse_git_repos(git_opts) ⇒ Array
Converts array of paths into array of fully qualified git repo URLS with expanded keywords
Supports the following keywords
PUPPET
FACTER
HIERA
HIERA-PUPPET
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/beaker/options/parser.rb', line 105 def parse_git_repos(git_opts) git_opts.map! { |opt| case opt when /^PUPPET\// opt = "#{GITREPO}/puppet.git##{opt.split('/', 2)[1]}" when /^FACTER\// opt = "#{GITREPO}/facter.git##{opt.split('/', 2)[1]}" when /^HIERA\// opt = "#{GITREPO}/hiera.git##{opt.split('/', 2)[1]}" when /^HIERA-PUPPET\// opt = "#{GITREPO}/hiera-puppet.git##{opt.split('/', 2)[1]}" end opt } git_opts end |
#parser_error(msg = "") ⇒ Object
Raises an ArgumentError with associated message
22 23 24 |
# File 'lib/beaker/options/parser.rb', line 22 def parser_error msg = "" raise ArgumentError, msg.to_s end |
#repo ⇒ String
Returns the git repository used for git installations
28 29 30 |
# File 'lib/beaker/options/parser.rb', line 28 def repo GITREPO end |
#resolve_symlinks ⇒ Object
doing it here allows us to not need duplicate logic, which we would need if we were doing it in the parser (–hosts & –config)
resolves all file symlinks that require it.
376 377 378 |
# File 'lib/beaker/options/parser.rb', line 376 def resolve_symlinks() @options[:hosts_file] = File.realpath(@options[:hosts_file]) if @options[:hosts_file] end |
#set_default_host!(hosts) ⇒ Object
Add the ‘default’ role to the host determined to be the default. If a host already has the role default then do nothing. If more than a single host has the role ‘default’, raise error. Default host determined to be 1) the only host in a single host configuration, 2) the host with the role ‘master’ defined.
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/beaker/options/parser.rb', line 127 def set_default_host!(hosts) default = [] master = [] default_host_name = nil #look through the hosts and find any hosts with role 'default' and any hosts with role 'master' hosts.each_key do |name| host = hosts[name] if host[:roles].include?('default') default << name elsif host[:roles].include?('master') master << name end end if not default.empty? #we already have a default set, do nothing if default.length > 1 parser_error "Only one host may have the role 'default', default roles assigned to #{default}" end else #no default set, let's make one if not master.empty? and master.length == 1 default_host_name = master[0] elsif hosts.length == 1 default_host_name = hosts.keys[0] end if default_host_name hosts[default_host_name][:roles] << 'default' end end end |
#split_arg(arg) ⇒ Array
Normalizes argument into an Array. Argument can either be converted into an array of a single value, or can become an array of multiple values by splitting arg over ‘,’. If argument is already an array that array is returned untouched.
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/beaker/options/parser.rb', line 48 def split_arg arg arry = [] if arg.is_a?(Array) arry += arg elsif arg =~ /,/ arry += arg.split(',') else arry << arg end arry end |
#usage ⇒ String
Returns a description of Beaker’s supported arguments
34 35 36 |
# File 'lib/beaker/options/parser.rb', line 34 def usage @command_line_parser.usage end |