beaker 1.16.0 → 1.17.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 (51) hide show
  1. checksums.yaml +8 -8
  2. data/CONTRIBUTING.md +90 -0
  3. data/HISTORY.md +654 -2
  4. data/beaker.gemspec +1 -0
  5. data/lib/beaker/answers/version34.rb +4 -0
  6. data/lib/beaker/cli.rb +49 -2
  7. data/lib/beaker/dsl/helpers.rb +356 -196
  8. data/lib/beaker/dsl/install_utils.rb +135 -16
  9. data/lib/beaker/dsl/patterns.rb +37 -0
  10. data/lib/beaker/dsl/roles.rb +29 -0
  11. data/lib/beaker/dsl.rb +2 -1
  12. data/lib/beaker/host/unix.rb +14 -10
  13. data/lib/beaker/host/windows.rb +2 -0
  14. data/lib/beaker/host.rb +96 -1
  15. data/lib/beaker/host_prebuilt_steps.rb +41 -51
  16. data/lib/beaker/hypervisor/aws_sdk.rb +80 -16
  17. data/lib/beaker/hypervisor/ec2_helper.rb +1 -1
  18. data/lib/beaker/logger.rb +17 -0
  19. data/lib/beaker/options/command_line_parser.rb +3 -0
  20. data/lib/beaker/options/hosts_file_parser.rb +7 -4
  21. data/lib/beaker/options/options_hash.rb +2 -2
  22. data/lib/beaker/options/parser.rb +1 -1
  23. data/lib/beaker/options/presets.rb +128 -83
  24. data/lib/beaker/perf.rb +58 -0
  25. data/lib/beaker/shared/host_manager.rb +81 -0
  26. data/lib/beaker/shared.rb +2 -2
  27. data/lib/beaker/ssh_connection.rb +14 -7
  28. data/lib/beaker/test_case.rb +13 -0
  29. data/lib/beaker/test_suite.rb +23 -5
  30. data/lib/beaker/version.rb +1 -1
  31. data/lib/beaker.rb +1 -1
  32. data/spec/beaker/answers_spec.rb +13 -8
  33. data/spec/beaker/dsl/ezbake_utils_spec.rb +8 -9
  34. data/spec/beaker/dsl/helpers_spec.rb +299 -51
  35. data/spec/beaker/dsl/install_utils_spec.rb +75 -10
  36. data/spec/beaker/dsl/roles_spec.rb +36 -1
  37. data/spec/beaker/host_prebuilt_steps_spec.rb +21 -5
  38. data/spec/beaker/host_spec.rb +187 -23
  39. data/spec/beaker/hypervisor/ec2_helper_spec.rb +4 -4
  40. data/spec/beaker/hypervisor/vagrant_spec.rb +1 -1
  41. data/spec/beaker/options/hosts_file_parser_spec.rb +5 -0
  42. data/spec/beaker/options/options_hash_spec.rb +2 -2
  43. data/spec/beaker/options/parser_spec.rb +6 -0
  44. data/spec/beaker/options/presets_spec.rb +18 -2
  45. data/spec/beaker/perf_spec.rb +87 -0
  46. data/spec/beaker/shared/{host_role_parser_spec.rb → host_manager_spec.rb} +36 -5
  47. data/spec/beaker/test_suite_spec.rb +4 -3
  48. data/spec/matchers.rb +31 -3
  49. data/spec/mocks.rb +31 -25
  50. metadata +24 -5
  51. data/lib/beaker/shared/host_role_parser.rb +0 -36
@@ -172,6 +172,17 @@ module Beaker
172
172
  end
173
173
  end
174
174
 
175
+ #Create the Higgs install command string based upon the host and options settings. Installation command will be run as a
176
+ #background process. The output of the command will be stored in the provided host['higgs_file'].
177
+ # @param [Host] host The host that Higgs is to be installed on
178
+ # The host object must have the 'working_dir', 'dist' and 'pe_installer' field set correctly.
179
+ # @api private
180
+ def higgs_installer_cmd host
181
+
182
+ "cd #{host['working_dir']}/#{host['dist']} ; nohup ./#{host['pe_installer']} <<<Y > #{host['higgs_file']} 2>&1 &"
183
+
184
+ end
185
+
175
186
  #Determine is a given URL is accessible
176
187
  #@param [String] link The URL to examine
177
188
  #@return [Boolean] true if the URL has a '200' HTTP response code, false otherwise
@@ -420,8 +431,7 @@ module Beaker
420
431
  version = host['pe_ver'] || opts[:pe_ver]
421
432
  host['dist'] = "puppet-enterprise-#{version}-#{host['platform']}"
422
433
  end
423
- host['working_dir'] = "/tmp/" + Time.new.strftime("%Y-%m-%d_%H.%M.%S") #unique working dirs make me happy
424
- on host, "mkdir #{host['working_dir']}"
434
+ host['working_dir'] = host.tmpdir(Time.new.strftime("%Y-%m-%d_%H.%M.%S"))
425
435
  end
426
436
 
427
437
  fetch_puppet(hosts, opts)
@@ -493,6 +503,57 @@ module Beaker
493
503
  on install_hosts, puppet_agent('-t'), :acceptable_exit_codes => [0,2]
494
504
  end
495
505
 
506
+ #Perform a Puppet Enterprise Higgs install up until web browser interaction is required, runs on linux hosts only.
507
+ # @param [Host] host The host to install higgs on
508
+ # @param [Hash{Symbol=>Symbol, String}] opts The options
509
+ # @option opts [String] :pe_dir Default directory or URL to pull PE package from
510
+ # (Otherwise uses individual hosts pe_dir)
511
+ # @option opts [String] :pe_ver Default PE version to install
512
+ # (Otherwise uses individual hosts pe_ver)
513
+ # @raise [StandardError] When installation times out
514
+ #
515
+ # @example
516
+ # do_higgs_install(master, {:pe_dir => path, :pe_ver => version})
517
+ #
518
+ # @api private
519
+ #
520
+ def do_higgs_install host, opts
521
+ use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
522
+ platform = use_all_tar ? 'all' : host['platform']
523
+ version = host['pe_ver'] || opts[:pe_ver]
524
+ host['dist'] = "puppet-enterprise-#{version}-#{platform}"
525
+
526
+ use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
527
+ host['pe_installer'] ||= 'puppet-enterprise-installer'
528
+ host['working_dir'] = host.tmpdir(Time.new.strftime("%Y-%m-%d_%H.%M.%S"))
529
+
530
+ fetch_puppet([host], opts)
531
+
532
+ host['higgs_file'] = "higgs_#{File.basename(host['working_dir'])}.log"
533
+ on host, higgs_installer_cmd(host), opts
534
+
535
+ #wait for output to host['higgs_file']
536
+ #we're all done when we find this line in the PE installation log
537
+ higgs_re = /Please\s+go\s+to\s+https:\/\/.*\s+in\s+your\s+browser\s+to\s+continue\s+installation/m
538
+ res = Result.new(host, 'tmp cmd')
539
+ tries = 10
540
+ attempts = 0
541
+ prev_sleep = 0
542
+ cur_sleep = 1
543
+ while (res.stdout !~ higgs_re) and (attempts < tries)
544
+ res = on host, "cd #{host['working_dir']}/#{host['dist']} && cat #{host['higgs_file']}", :acceptable_exit_codes => (0..255)
545
+ attempts += 1
546
+ sleep( cur_sleep )
547
+ prev_sleep = cur_sleep
548
+ cur_sleep = cur_sleep + prev_sleep
549
+ end
550
+
551
+ if attempts >= tries
552
+ raise "Failed to kick off PE (Higgs) web installation"
553
+ end
554
+
555
+ end
556
+
496
557
  #Sort array of hosts so that it has the correct order for PE installation based upon each host's role
497
558
  # @example
498
559
  # h = sorted_hosts
@@ -551,6 +612,10 @@ module Beaker
551
612
  raise "install_puppet() called for unsupported platform '#{host['platform']}' on '#{host.name}'"
552
613
  end
553
614
  end
615
+
616
+ # Certain install paths may not create the config dirs/files needed
617
+ on host, "mkdir -p #{host['puppetpath']}"
618
+ on host, "echo '' >> #{host['hieraconf']}"
554
619
  end
555
620
  nil
556
621
  end
@@ -688,20 +753,51 @@ module Beaker
688
753
  # @raise [StandardError] if gem does not exist on target host
689
754
  # @api private
690
755
  def install_puppet_from_gem( host, opts )
691
- if host.check_for_command( 'gem' )
692
- if opts[:facter_version]
693
- on host, "gem install facter -v#{opts[:facter_version]}"
694
- end
695
- if opts[:hiera_version]
696
- on host, "gem install hiera -v#{opts[:hiera_version]}"
697
- end
698
- ver_cmd = opts[:version] ? "-v#{opts[:version]}" : ''
699
- on host, "gem install puppet #{ver_cmd}"
700
- else
701
- raise "install_puppet() called with default_action 'gem_install' but program `gem' not installed on #{host.name}"
756
+ # Hosts may be provisioned with csw but pkgutil won't be in the
757
+ # PATH by default to avoid changing the behavior for Puppet's tests
758
+ if host['platform'] =~ /solaris-10/
759
+ on host, 'ln -s /opt/csw/bin/pkgutil /usr/bin/pkgutil'
760
+ end
761
+
762
+ # Solaris doesn't necessarily have this, but gem needs it
763
+ if host['platform'] =~ /solaris/
764
+ on host, 'mkdir -p /var/lib'
765
+ end
766
+
767
+ unless host.check_for_command( 'gem' )
768
+ gempkg = case host['platform']
769
+ when /solaris-11/ then 'ruby-18'
770
+ when /ubuntu-14/ then 'ruby'
771
+ when /solaris-10|ubuntu|debian|el-/ then 'rubygems'
772
+ else
773
+ raise "install_puppet() called with default_action " +
774
+ "'gem_install' but program `gem' is " +
775
+ "not installed on #{host.name}"
776
+ end
777
+
778
+ host.install_package gempkg
779
+ end
780
+
781
+ if host['platform'] =~ /debian|ubuntu|solaris/
782
+ gem_env = YAML.load( on( host, 'gem environment' ).stdout )
783
+ gem_paths_array = gem_env['RubyGems Environment'].find {|h| h['GEM PATHS'] != nil }['GEM PATHS']
784
+ path_with_gem = 'export PATH=' + gem_paths_array.join(':') + ':${PATH}'
785
+ on host, "echo '#{path_with_gem}' >> ~/.bashrc"
786
+ end
787
+
788
+ if opts[:facter_version]
789
+ on host, "gem install facter -v#{opts[:facter_version]} --no-ri --no-rdoc"
790
+ end
791
+
792
+ if opts[:hiera_version]
793
+ on host, "gem install hiera -v#{opts[:hiera_version]} --no-ri --no-rdoc"
702
794
  end
795
+
796
+ ver_cmd = opts[:version] ? "-v#{opts[:version]}" : ''
797
+ on host, "gem install puppet #{ver_cmd} --no-ri --no-rdoc"
703
798
  end
704
799
 
800
+
705
801
  #Install PE based upon host configuration and options
706
802
  # @example
707
803
  # install_pe
@@ -777,7 +873,7 @@ module Beaker
777
873
  on host, "rpm -ivh --force #{rpm}"
778
874
 
779
875
  when /^(debian|ubuntu)$/
780
- deb = options[:release_apt_repo_url] + "puppetlabs-release-%s.deb" % codename
876
+ deb = URI.join(options[:release_apt_repo_url], "puppetlabs-release-%s.deb" % codename)
781
877
 
782
878
  on host, "wget -O /tmp/puppet.deb #{deb}"
783
879
  on host, "dpkg -i --force-all /tmp/puppet.deb"
@@ -888,8 +984,8 @@ module Beaker
888
984
  scp_to host, list, config_dir
889
985
  scp_to host, repo_dir, "/root/#{package_name}"
890
986
 
891
- search = "'deb\\s\\+http:\\/\\/#{hostname}.*$"
892
- replace = "'deb file:\\/\\/\\/root\\/#{package_name}\\/#{codename} #{codename} main'"
987
+ search = "deb\\s\\+http:\\/\\/#{hostname}.*$"
988
+ replace = "deb file:\\/\\/\\/root\\/#{package_name}\\/#{codename} #{codename} main"
893
989
  sed_command = "sed -i 's/#{search}/#{replace}/'"
894
990
  find_and_sed = "find #{config_dir} -name \"*.list\" -exec #{sed_command} {} \\;"
895
991
 
@@ -900,6 +996,29 @@ module Beaker
900
996
  raise "No repository installation step for #{variant} yet..."
901
997
  end
902
998
  end
999
+
1000
+ #Install Higgs up till the point where you need to continue installation in a web browser, defaults to execution
1001
+ #on the master node.
1002
+ #@param [Host] higgs_host The host to install Higgs on (supported on linux platform only)
1003
+ # @example
1004
+ # install_higgs
1005
+ #
1006
+ # @note Either pe_ver and pe_dir should be set in the ENV or each host should have pe_ver and pe_dir set individually.
1007
+ # Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz).
1008
+ #
1009
+ # @api dsl
1010
+ def install_higgs( higgs_host = master )
1011
+ #process the version files if necessary
1012
+ master['pe_dir'] ||= options[:pe_dir]
1013
+ master['pe_ver'] = master['pe_ver'] || options['pe_ver'] ||
1014
+ Beaker::Options::PEVersionScraper.load_pe_version(master[:pe_dir] || options[:pe_dir], options[:pe_version_file])
1015
+ if higgs_host['platform'] =~ /osx|windows/
1016
+ raise "Attempting higgs installation on host #{higgs_host.name} with unsupported platform #{higgs_host['platform']}"
1017
+ end
1018
+ #send in the global options hash
1019
+ do_higgs_install higgs_host, options
1020
+ end
1021
+
903
1022
  end
904
1023
  end
905
1024
  end
@@ -0,0 +1,37 @@
1
+ module Beaker
2
+ module DSL
3
+ # These are simple patterns that appear frequently in beaker test
4
+ # code, and are provided to simplify test construction.
5
+ #
6
+ #
7
+ # It requires the class it is mixed into to provide the attribute
8
+ # `hosts` which contain the hosts to search, these should implement
9
+ # {Beaker::Host}'s interface. They, at least, must have #[]
10
+ # and #to_s available and provide an array when #[]('roles') is called.
11
+ #
12
+ module Patterns
13
+
14
+ #Execute a block selecting the hosts that match with the provided criteria
15
+ #@param [Array<Host>, Host, String, Symbol] hosts_or_filter A host role as a String or Symbol that can be
16
+ # used to search for a set of Hosts, a host name
17
+ # as a String that can be used to search for
18
+ # a set of Hosts, or a {Host}
19
+ # or Array<{Host}> to run the block against
20
+ #@param [Block] block This method will yield to a block of code passed by the caller
21
+ def block_on hosts_or_filter, &block
22
+ block_hosts = nil
23
+ if defined? hosts
24
+ block_hosts = hosts
25
+ end
26
+ filter = nil
27
+ if hosts_or_filter.is_a? String or hosts_or_filter.is_a? Symbol
28
+ filter = hosts_or_filter
29
+ else
30
+ block_hosts = hosts_or_filter
31
+ end
32
+ run_block_on block_hosts, filter, &block
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -88,6 +88,35 @@ module Beaker
88
88
  find_only_one :default
89
89
  end
90
90
 
91
+ #Create a new role method for a given arbitrary role name. Makes it possible to be able to run
92
+ #commands without having to refer to role by String or Symbol. Will not add a new method
93
+ #definition if the name is already in use.
94
+ # @param [String, Symbol, Array[String,Symbol]] role The role that you wish to create a definition for, either a String
95
+ # Symbol or an Array of Strings or Symbols.
96
+ # @example Basic usage
97
+ # add_role_def('myrole')
98
+ # on myrole, "run command"
99
+ def add_role_def role
100
+ if role.kind_of?(Array)
101
+ role.each do |r|
102
+ add_role_def r
103
+ end
104
+ else
105
+ if not respond_to? role
106
+ if role !~ /\A[[:alpha:]]+[a-zA-Z0-9_]*[!?=]?\Z/
107
+ raise "Role name format error for '#{role}'. Allowed characters are: \na-Z\n0-9 (as long as not at the beginning of name)\n'_'\n'?', '!' and '=' (only as individual last character at end of name)"
108
+ end
109
+ self.class.send :define_method, role.to_s do
110
+ hosts_with_role = hosts_as role.to_sym
111
+ if hosts_with_role.length == 1
112
+ hosts_with_role = hosts_with_role.pop
113
+ end
114
+ hosts_with_role
115
+ end
116
+ end
117
+ end
118
+ end
119
+
91
120
  # Determine if there is a host or hosts with the given role defined
92
121
  # @return [Boolean] True if there is a host with role, false otherwise
93
122
  #
data/lib/beaker/dsl.rb CHANGED
@@ -1,4 +1,4 @@
1
- [ 'install_utils', 'roles', 'outcomes', 'assertions',
1
+ [ 'install_utils', 'roles', 'outcomes', 'assertions', 'patterns',
2
2
  'structure', 'helpers', 'ezbake_utils', 'wrappers' ].each do |lib|
3
3
  require "beaker/dsl/#{lib}"
4
4
  end
@@ -78,5 +78,6 @@ module Beaker
78
78
  include Beaker::DSL::Helpers
79
79
  include Beaker::DSL::EZBakeUtils
80
80
  include Beaker::DSL::InstallUtils
81
+ include Beaker::DSL::Patterns
81
82
  end
82
83
  end
@@ -20,16 +20,18 @@ module Unix
20
20
  'user' => 'root',
21
21
  'group' => 'pe-puppet',
22
22
  'master-start-curl-retries' => 120,
23
- 'puppetservice' => 'pe-httpd',
24
- 'puppetpath' => '/etc/puppetlabs/puppet',
25
- 'puppetbin' => '/opt/puppet/bin/puppet',
26
- 'puppetbindir' => '/opt/puppet/bin',
27
- 'puppetvardir' => '/var/opt/lib/pe-puppet',
28
- 'hieradatadir' => '/var/lib/hiera',
29
- 'hieraconf' => '/etc/puppetlabs/puppet/hiera.yaml',
30
- 'distmoduledir' => '/etc/puppetlabs/puppet/modules',
31
- 'sitemoduledir' => '/opt/puppet/share/puppet/modules',
32
- 'pathseparator' => ':',
23
+ 'jvm-puppet-confdir' => '/etc/puppetlabs/jvm-puppet/conf.d',
24
+ 'puppetservice' => 'pe-httpd',
25
+ 'puppetpath' => '/etc/puppetlabs/puppet',
26
+ 'puppetbin' => '/opt/puppet/bin/puppet',
27
+ 'puppetbindir' => '/opt/puppet/bin',
28
+ 'puppetsbindir' => '/opt/puppet/sbin',
29
+ 'puppetvardir' => '/var/opt/lib/pe-puppet',
30
+ 'hieradatadir' => '/var/lib/hiera',
31
+ 'hieraconf' => '/etc/puppetlabs/puppet/hiera.yaml',
32
+ 'distmoduledir' => '/etc/puppetlabs/puppet/modules',
33
+ 'sitemoduledir' => '/opt/puppet/share/puppet/modules',
34
+ 'pathseparator' => ':',
33
35
  })
34
36
  end
35
37
 
@@ -39,6 +41,8 @@ module Unix
39
41
  'user' => 'root',
40
42
  'group' => 'puppet',
41
43
  'master-start-curl-retries' => 120,
44
+ 'jvm-puppet-confdir' => '/etc/jvm-puppet/conf.d',
45
+ 'puppetservice' => 'puppetmaster',
42
46
  'puppetpath' => '/etc/puppet',
43
47
  'puppetvardir' => '/var/lib/puppet',
44
48
  'puppetbin' => '/usr/bin/puppet',
@@ -21,6 +21,7 @@ module Windows
21
21
  'group' => 'Administrators',
22
22
  'puppetservice' => 'pe-httpd',
23
23
  'puppetpath' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
24
+ 'hieraconf' => '`cygpath -smF 35`/Puppetlabs/puppet/etc/hiera.yaml',
24
25
  'puppetvardir' => '`cygpath -smF 35`/PuppetLabs/puppet/var',
25
26
  'distmoduledir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc/modules',
26
27
  'sitemoduledir' => 'C:/usr/share/puppet/modules',
@@ -36,6 +37,7 @@ module Windows
36
37
  'user' => 'Administrator',
37
38
  'group' => 'Administrators',
38
39
  'puppetpath' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
40
+ 'hieraconf' => '`cygpath -smF 35`/Puppetlabs/puppet/etc/hiera.yaml',
39
41
  'puppetvardir' => '`cygpath -smF 35`/PuppetLabs/puppet/var',
40
42
  'distmoduledir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc/modules',
41
43
  'sitemoduledir' => 'C:/usr/share/puppet/modules',
data/lib/beaker/host.rb CHANGED
@@ -137,6 +137,43 @@ module Beaker
137
137
  @options.is_pe?
138
138
  end
139
139
 
140
+ # True if this is a pe run, or if the host has had a 'use-service' property set.
141
+ def use_service_scripts?
142
+ is_pe? || self['use-service']
143
+ end
144
+
145
+ # Mirrors the true/false value of the host's 'graceful-restarts' property,
146
+ # or falls back to the value of +is_using_passenger?+ if
147
+ # 'graceful-restarts' is nil, but only if this is not a PE run (foss only).
148
+ def graceful_restarts?
149
+ graceful =
150
+ if !self['graceful-restarts'].nil?
151
+ self['graceful-restarts']
152
+ else
153
+ !is_pe? && is_using_passenger?
154
+ end
155
+ graceful
156
+ end
157
+
158
+ # Modifies the host settings to indicate that it will be using passenger service scripts,
159
+ # (apache2) by default. Does nothing if this is a PE host, since it is already using
160
+ # passenger.
161
+ # @param [String] puppetservice Name of the service script that should be
162
+ # called to stop/startPuppet on this host. Defaults to 'apache2'.
163
+ def uses_passenger!(puppetservice = 'apache2')
164
+ if !is_pe?
165
+ self['passenger'] = true
166
+ self['puppetservice'] = puppetservice
167
+ self['use-service'] = true
168
+ end
169
+ return true
170
+ end
171
+
172
+ # True if this is a PE run, or if the host's 'passenger' property has been set.
173
+ def is_using_passenger?
174
+ is_pe? || self['passenger']
175
+ end
176
+
140
177
  def log_prefix
141
178
  if @defaults['vmhostname']
142
179
  "#{self} (#{@name})"
@@ -206,9 +243,66 @@ module Beaker
206
243
  end
207
244
  end
208
245
 
246
+ # Create the provided directory structure on the host
247
+ # @param [String] dir The directory structure to create on the host
248
+ # @return [Boolean] True, if directory construction succeeded, otherwise False
249
+ def mkdir_p dir
250
+ result = exec(Beaker::Command.new("mkdir -p #{dir}"), :acceptable_exit_codes => [0, 1])
251
+ result.exit_code == 0
252
+ end
253
+
254
+ # scp files from the localhost to this test host
255
+ # @param source [String] The path to the file/dir to upload
256
+ # @param target [String] The destination path on the host
257
+ # @param [Hash{Symbol=>String}] options Options to alter execution
258
+ # @option options [Boolean] :recursive Should we copy recursively? Defaults to 'True' in case of a directory source.
259
+ # @option options [Array<String>] :ignore An array of file/dir paths that will not be copied to the host
209
260
  def do_scp_to source, target, options
210
261
  @logger.debug "localhost $ scp #{source} #{@name}:#{target}"
211
- result = connection.scp_to(source, target, options, $dry_run)
262
+
263
+ result = Result.new(@name, [source, target])
264
+ has_ignore = options[:ignore] and not options[:ignore].empty?
265
+ # construct the regex for matching ignored files/dirs
266
+ ignore_re = nil
267
+ if has_ignore
268
+ ignore_arr = Array(options[:ignore]).map do |entry|
269
+ "((\/|\\A)#{entry}(\/|\\z))".sub(/\./, "\.")
270
+ end
271
+ ignore_re = Regexp.new(ignore_arr.join('|'))
272
+ end
273
+
274
+ # either a single file, or a directory with no ignores
275
+ if File.file?(source) or (File.directory?(source) and not has_ignore)
276
+ source_file = source
277
+ if has_ignore and (source =~ ignore_re)
278
+ @logger.debug "After rejecting ignored files/dirs, there is no file to copy"
279
+ source_file = nil
280
+ result.stdout = "No files to copy"
281
+ result.exit_code = 1
282
+ end
283
+ if source_file
284
+ result = connection.scp_to(source_file, target, options, $dry_run)
285
+ end
286
+ else # a directory with ignores
287
+ dir_source = Dir.glob("#{source}/**/*").reject do |f|
288
+ f =~ ignore_re
289
+ end
290
+ @logger.debug "After rejecting ignored files/dirs, going to scp [#{dir_source.join(", ")}]"
291
+
292
+ # create necessary directory structure on host
293
+ required_dirs = (dir_source.map{ | dir | File.dirname(dir) }).uniq
294
+ required_dirs.each do |dir|
295
+ mkdir_p( File.join(target, dir) )
296
+ end
297
+
298
+ # copy each file to the host
299
+ dir_source.each do |s|
300
+ file_path = File.join(target, s)
301
+ result = connection.scp_to(s, file_path, options, $dry_run)
302
+ end
303
+ end
304
+
305
+ @logger.debug result.stdout
212
306
  return result
213
307
  end
214
308
 
@@ -216,6 +310,7 @@ module Beaker
216
310
 
217
311
  @logger.debug "localhost $ scp #{@name}:#{source} #{target}"
218
312
  result = connection.scp_from(source, target, options, $dry_run)
313
+ @logger.debug result.stdout
219
314
  return result
220
315
  end
221
316