test-kitchen 1.7.3 → 1.8.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.
- checksums.yaml +4 -4
- data/.kitchen.ci.yml +3 -0
- data/CHANGELOG.md +8 -0
- data/lib/kitchen/data_munger.rb +4 -1
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +46 -2
- data/lib/kitchen/provisioner/chef/policyfile.rb +107 -0
- data/lib/kitchen/provisioner/chef_base.rb +38 -1
- data/lib/kitchen/provisioner/chef_zero.rb +10 -0
- data/lib/kitchen/transport/winrm.rb +55 -7
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/data_munger_spec.rb +68 -0
- data/spec/kitchen/provisioner/chef_base_spec.rb +164 -0
- data/spec/kitchen/transport/winrm_spec.rb +153 -0
- data/test-kitchen.gemspec +1 -0
- data/testing_windows.md +1 -0
- metadata +18 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 2ad48e5953da8eb9d58bd3a8e2933450d669caa8
         | 
| 4 | 
            +
              data.tar.gz: 9d661157b18854c43bb1ce3094cb95888b9e0f95
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 61f25a72986488f05691bbbcb1189e08bac9a6953c52bbc93980c0f7caa283ac80a197da1a296e273217d99f43115f1cecfc136ccc43804eefc985a97e170894
         | 
| 7 | 
            +
              data.tar.gz: 344538d21ba1ce73e9c892bb895ad59f31a078eb661552ef8661d6c878f5d4f187eee6eb5f13756eb81fd894f2ee632a1a360fa87a9452fb8f06f3a4bb5ba3dd
         | 
    
        data/.kitchen.ci.yml
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,13 @@ | |
| 1 1 | 
             
            # Change Log
         | 
| 2 2 |  | 
| 3 | 
            +
            ## [1.8.0](https://github.com/test-kitchen/test-kitchen/tree/1.8.0) (2016-05-05)
         | 
| 4 | 
            +
            [Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.7.3...1.8.0)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            **Implemented enhancements:**
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            - Add native policyfile resolution support [\#1014](https://github.com/test-kitchen/test-kitchen/pull/1014) ([danielsdeleo](https://github.com/danielsdeleo))
         | 
| 9 | 
            +
            - Provide the option to run all winrm commands through a scheduled task [\#1012](https://github.com/test-kitchen/test-kitchen/pull/1012) ([mwrock](https://github.com/mwrock))
         | 
| 10 | 
            +
             | 
| 3 11 | 
             
            ## [1.7.3](https://github.com/test-kitchen/test-kitchen/tree/1.7.3) (2016-04-13)
         | 
| 4 12 | 
             
            [Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.7.2...1.7.3)
         | 
| 5 13 |  | 
    
        data/lib/kitchen/data_munger.rb
    CHANGED
    
    | @@ -624,10 +624,11 @@ module Kitchen | |
| 624 624 | 
             
                # Destructively moves key Chef configuration key/value pairs from being
         | 
| 625 625 | 
             
                # directly under a suite or platform into a `:provisioner` sub-hash.
         | 
| 626 626 | 
             
                #
         | 
| 627 | 
            -
                # There are  | 
| 627 | 
            +
                # There are three key Chef configuration key/value pairs:
         | 
| 628 628 | 
             
                #
         | 
| 629 629 | 
             
                # 1. `:attributes`
         | 
| 630 630 | 
             
                # 2. `:run_list`
         | 
| 631 | 
            +
                # 3. `:named_run_list`
         | 
| 631 632 | 
             
                #
         | 
| 632 633 | 
             
                # This method converts the following:
         | 
| 633 634 | 
             
                #
         | 
| @@ -678,11 +679,13 @@ module Kitchen | |
| 678 679 | 
             
                  data.fetch(:suites, []).each do |suite|
         | 
| 679 680 | 
             
                    move_chef_data_to_provisioner_at!(suite, :attributes)
         | 
| 680 681 | 
             
                    move_chef_data_to_provisioner_at!(suite, :run_list)
         | 
| 682 | 
            +
                    move_chef_data_to_provisioner_at!(suite, :named_run_list)
         | 
| 681 683 | 
             
                  end
         | 
| 682 684 |  | 
| 683 685 | 
             
                  data.fetch(:platforms, []).each do |platform|
         | 
| 684 686 | 
             
                    move_chef_data_to_provisioner_at!(platform, :attributes)
         | 
| 685 687 | 
             
                    move_chef_data_to_provisioner_at!(platform, :run_list)
         | 
| 688 | 
            +
                    move_chef_data_to_provisioner_at!(platform, :named_run_list)
         | 
| 686 689 | 
             
                  end
         | 
| 687 690 | 
             
                end
         | 
| 688 691 |  | 
| @@ -16,6 +16,8 @@ | |
| 16 16 | 
             
            # See the License for the specific language governing permissions and
         | 
| 17 17 | 
             
            # limitations under the License.
         | 
| 18 18 |  | 
| 19 | 
            +
            require "json"
         | 
| 20 | 
            +
             | 
| 19 21 | 
             
            module Kitchen
         | 
| 20 22 |  | 
| 21 23 | 
             
              module Provisioner
         | 
| @@ -86,6 +88,14 @@ module Kitchen | |
| 86 88 | 
             
                        select { |fn| File.file?(fn) && ! %w[. ..].include?(fn) }
         | 
| 87 89 | 
             
                    end
         | 
| 88 90 |  | 
| 91 | 
            +
                    # @return [String] an absolute path to a Policyfile, relative to the
         | 
| 92 | 
            +
                    #   kitchen root
         | 
| 93 | 
            +
                    # @api private
         | 
| 94 | 
            +
                    def policyfile
         | 
| 95 | 
            +
                      basename = config[:policyfile_path] || "Policyfile.rb"
         | 
| 96 | 
            +
                      File.join(config[:kitchen_root], basename)
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
             | 
| 89 99 | 
             
                    # @return [String] an absolute path to a Berksfile, relative to the
         | 
| 90 100 | 
             
                    #   kitchen root
         | 
| 91 101 | 
             
                    # @api private
         | 
| @@ -246,8 +256,11 @@ module Kitchen | |
| 246 256 | 
             
                    # Prepares Chef cookbooks for inclusion in the sandbox path.
         | 
| 247 257 | 
             
                    #
         | 
| 248 258 | 
             
                    # @api private
         | 
| 259 | 
            +
                    # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
         | 
| 249 260 | 
             
                    def prepare_cookbooks
         | 
| 250 | 
            -
                      if File.exist?( | 
| 261 | 
            +
                      if File.exist?(policyfile)
         | 
| 262 | 
            +
                        resolve_with_policyfile
         | 
| 263 | 
            +
                      elsif File.exist?(berksfile)
         | 
| 251 264 | 
             
                        resolve_with_berkshelf
         | 
| 252 265 | 
             
                      elsif File.exist?(cheffile)
         | 
| 253 266 | 
             
                        resolve_with_librarian
         | 
| @@ -268,7 +281,11 @@ module Kitchen | |
| 268 281 | 
             
                    #
         | 
| 269 282 | 
             
                    # @api private
         | 
| 270 283 | 
             
                    def prepare_json
         | 
| 271 | 
            -
                      dna =  | 
| 284 | 
            +
                      dna = if File.exist?(policyfile)
         | 
| 285 | 
            +
                        update_dna_for_policyfile
         | 
| 286 | 
            +
                      else
         | 
| 287 | 
            +
                        config[:attributes].merge(:run_list => config[:run_list])
         | 
| 288 | 
            +
                      end
         | 
| 272 289 |  | 
| 273 290 | 
             
                      info("Preparing dna.json")
         | 
| 274 291 | 
             
                      debug("Creating dna.json from #{dna.inspect}")
         | 
| @@ -278,6 +295,32 @@ module Kitchen | |
| 278 295 | 
             
                      end
         | 
| 279 296 | 
             
                    end
         | 
| 280 297 |  | 
| 298 | 
            +
                    def update_dna_for_policyfile
         | 
| 299 | 
            +
                      if !config[:run_list].nil? && !config[:run_list].empty?
         | 
| 300 | 
            +
                        warn("You must set your run_list in your policyfile instead of "\
         | 
| 301 | 
            +
                             "kitchen config. The run_list your config will be ignored.")
         | 
| 302 | 
            +
                        warn("Ignored run_list: #{config[:run_list].inspect}")
         | 
| 303 | 
            +
                      end
         | 
| 304 | 
            +
                      policylock = policyfile.gsub(/\.rb\Z/, ".lock.json")
         | 
| 305 | 
            +
                      unless File.exist?(policylock)
         | 
| 306 | 
            +
                        Kitchen.mutex.synchronize do
         | 
| 307 | 
            +
                          Chef::Policyfile.new(policyfile, sandbox_path, logger).compile
         | 
| 308 | 
            +
                        end
         | 
| 309 | 
            +
                      end
         | 
| 310 | 
            +
                      policy_name = JSON.parse(IO.read(policylock))["name"]
         | 
| 311 | 
            +
                      policy_group = "local"
         | 
| 312 | 
            +
                      config[:attributes].merge(:policy_name => policy_name, :policy_group => policy_group)
         | 
| 313 | 
            +
                    end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                    # Performs a Policyfile cookbook resolution inside a common mutex.
         | 
| 316 | 
            +
                    #
         | 
| 317 | 
            +
                    # @api private
         | 
| 318 | 
            +
                    def resolve_with_policyfile
         | 
| 319 | 
            +
                      Kitchen.mutex.synchronize do
         | 
| 320 | 
            +
                        Chef::Policyfile.new(policyfile, sandbox_path, logger).resolve
         | 
| 321 | 
            +
                      end
         | 
| 322 | 
            +
                    end
         | 
| 323 | 
            +
             | 
| 281 324 | 
             
                    # Performs a Berkshelf cookbook resolution inside a common mutex.
         | 
| 282 325 | 
             
                    #
         | 
| 283 326 | 
             
                    # @api private
         | 
| @@ -316,6 +359,7 @@ module Kitchen | |
| 316 359 | 
             
                    def tmpsitebooks_dir
         | 
| 317 360 | 
             
                      File.join(sandbox_path, "cookbooks")
         | 
| 318 361 | 
             
                    end
         | 
| 362 | 
            +
             | 
| 319 363 | 
             
                  end
         | 
| 320 364 | 
             
                end
         | 
| 321 365 | 
             
              end
         | 
| @@ -0,0 +1,107 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            # Copyright (C) 2013, Fletcher Nichol
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            # Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 8 | 
            +
            # you may not use this file except in compliance with the License.
         | 
| 9 | 
            +
            # You may obtain a copy of the License at
         | 
| 10 | 
            +
            #
         | 
| 11 | 
            +
            #    http://www.apache.org/licenses/LICENSE-2.0
         | 
| 12 | 
            +
            #
         | 
| 13 | 
            +
            # Unless required by applicable law or agreed to in writing, software
         | 
| 14 | 
            +
            # distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 15 | 
            +
            # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 16 | 
            +
            # See the License for the specific language governing permissions and
         | 
| 17 | 
            +
            # limitations under the License.
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            require "kitchen/errors"
         | 
| 20 | 
            +
            require "kitchen/logging"
         | 
| 21 | 
            +
            require "kitchen/shell_out"
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            module Kitchen
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              module Provisioner
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                module Chef
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  # Chef cookbook resolver that uses Policyfiles to calculate dependencies.
         | 
| 30 | 
            +
                  #
         | 
| 31 | 
            +
                  # @author Fletcher Nichol <fnichol@nichol.ca>
         | 
| 32 | 
            +
                  class Policyfile
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    include Logging
         | 
| 35 | 
            +
                    include ShellOut
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    # Creates a new cookbook resolver.
         | 
| 38 | 
            +
                    #
         | 
| 39 | 
            +
                    # @param berksfile [String] path to a Berksfile
         | 
| 40 | 
            +
                    # @param path [String] path in which to vendor the resulting
         | 
| 41 | 
            +
                    #   cookbooks
         | 
| 42 | 
            +
                    # @param logger [Kitchen::Logger] a logger to use for output, defaults
         | 
| 43 | 
            +
                    #   to `Kitchen.logger`
         | 
| 44 | 
            +
                    def initialize(policyfile, path, logger = Kitchen.logger)
         | 
| 45 | 
            +
                      @policyfile = policyfile
         | 
| 46 | 
            +
                      @path       = path
         | 
| 47 | 
            +
                      @logger     = logger
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    # Loads the library code required to use the resolver.
         | 
| 51 | 
            +
                    #
         | 
| 52 | 
            +
                    # @param logger [Kitchen::Logger] a logger to use for output, defaults
         | 
| 53 | 
            +
                    #   to `Kitchen.logger`
         | 
| 54 | 
            +
                    def self.load!(logger = Kitchen.logger)
         | 
| 55 | 
            +
                      detect_chef_command!(logger)
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    # Performs the cookbook resolution and vendors the resulting cookbooks
         | 
| 59 | 
            +
                    # in the desired path.
         | 
| 60 | 
            +
                    def resolve
         | 
| 61 | 
            +
                      info("Exporting cookbook dependencies from Policyfile #{path}...")
         | 
| 62 | 
            +
                      run_command("chef export #{policyfile} #{path} --force")
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    # Runs `chef install` to determine the correct cookbook set and
         | 
| 66 | 
            +
                    # generate the policyfile lock.
         | 
| 67 | 
            +
                    def compile
         | 
| 68 | 
            +
                      info("Policy lock file doesn't exist, running `chef install` for "\
         | 
| 69 | 
            +
                           "Policyfile #{policyfile}...")
         | 
| 70 | 
            +
                      run_command("chef install #{policyfile}")
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    private
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    # @return [String] path to a Berksfile
         | 
| 76 | 
            +
                    # @api private
         | 
| 77 | 
            +
                    attr_reader :policyfile
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    # @return [String] path in which to vendor the resulting cookbooks
         | 
| 80 | 
            +
                    # @api private
         | 
| 81 | 
            +
                    attr_reader :path
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    # @return [Kitchen::Logger] a logger to use for output
         | 
| 84 | 
            +
                    # @api private
         | 
| 85 | 
            +
                    attr_reader :logger
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    # Ensure the `chef` command is in the path.
         | 
| 88 | 
            +
                    #
         | 
| 89 | 
            +
                    # @param logger [Kitchen::Logger] the logger to use
         | 
| 90 | 
            +
                    # @raise [UserError] if the `chef` command is not in the PATH
         | 
| 91 | 
            +
                    # @api private
         | 
| 92 | 
            +
                    def self.detect_chef_command!(logger)
         | 
| 93 | 
            +
                      unless ENV["PATH"].split(File::PATH_SEPARATOR).any? { |p|
         | 
| 94 | 
            +
                        File.exist?(File.join(p, "chef"))
         | 
| 95 | 
            +
                      }
         | 
| 96 | 
            +
                        logger.fatal("The `chef` executable cannot be found in your " \
         | 
| 97 | 
            +
                                     "PATH. Ensure you have installed ChefDK from " \
         | 
| 98 | 
            +
                                     "https://downloads.chef.io and that your PATH " \
         | 
| 99 | 
            +
                                     "setting includes the path to the `chef` comand.")
         | 
| 100 | 
            +
                        raise UserError,
         | 
| 101 | 
            +
                          "Could not find the chef executable in your PATH."
         | 
| 102 | 
            +
                      end
         | 
| 103 | 
            +
                    end
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
            end
         | 
| @@ -21,6 +21,7 @@ require "pathname" | |
| 21 21 | 
             
            require "json"
         | 
| 22 22 | 
             
            require "cgi"
         | 
| 23 23 |  | 
| 24 | 
            +
            require "kitchen/provisioner/chef/policyfile"
         | 
| 24 25 | 
             
            require "kitchen/provisioner/chef/berkshelf"
         | 
| 25 26 | 
             
            require "kitchen/provisioner/chef/common_sandbox"
         | 
| 26 27 | 
             
            require "kitchen/provisioner/chef/librarian"
         | 
| @@ -53,6 +54,9 @@ module Kitchen | |
| 53 54 | 
             
                  default_config :log_file, nil
         | 
| 54 55 | 
             
                  default_config :log_level, "auto"
         | 
| 55 56 | 
             
                  default_config :profile_ruby, false
         | 
| 57 | 
            +
                  # Will try to autodetect by searching for `Policyfile.rb` if not set.
         | 
| 58 | 
            +
                  # If set, will error if the file doesn't exist.
         | 
| 59 | 
            +
                  default_config :policyfile_path, nil
         | 
| 56 60 | 
             
                  default_config :cookbook_files_glob, %w[
         | 
| 57 61 | 
             
                    README.* metadata.{json,rb}
         | 
| 58 62 | 
             
                    attributes/**/* definitions/**/* files/**/* libraries/**/*
         | 
| @@ -114,6 +118,7 @@ module Kitchen | |
| 114 118 | 
             
                  # (see Base#create_sandbox)
         | 
| 115 119 | 
             
                  def create_sandbox
         | 
| 116 120 | 
             
                    super
         | 
| 121 | 
            +
                    sanity_check_sandbox_options!
         | 
| 117 122 | 
             
                    Chef::CommonSandbox.new(config, sandbox_path, instance).populate
         | 
| 118 123 | 
             
                  end
         | 
| 119 124 |  | 
| @@ -158,6 +163,14 @@ module Kitchen | |
| 158 163 | 
             
                    end
         | 
| 159 164 | 
             
                  end
         | 
| 160 165 |  | 
| 166 | 
            +
                  # @return [String] an absolute path to a Policyfile, relative to the
         | 
| 167 | 
            +
                  #   kitchen root
         | 
| 168 | 
            +
                  # @api private
         | 
| 169 | 
            +
                  def policyfile
         | 
| 170 | 
            +
                    policyfile_basename = config[:policyfile_path] || "Policyfile.rb"
         | 
| 171 | 
            +
                    File.join(config[:kitchen_root], policyfile_basename)
         | 
| 172 | 
            +
                  end
         | 
| 173 | 
            +
             | 
| 161 174 | 
             
                  # @return [String] an absolute path to a Berksfile, relative to the
         | 
| 162 175 | 
             
                  #   kitchen root
         | 
| 163 176 | 
             
                  # @api private
         | 
| @@ -264,7 +277,10 @@ module Kitchen | |
| 264 277 | 
             
                  # (see Base#load_needed_dependencies!)
         | 
| 265 278 | 
             
                  def load_needed_dependencies!
         | 
| 266 279 | 
             
                    super
         | 
| 267 | 
            -
                    if File.exist?( | 
| 280 | 
            +
                    if File.exist?(policyfile)
         | 
| 281 | 
            +
                      debug("Policyfile found at #{policyfile}, using Policyfile to resolve dependencies")
         | 
| 282 | 
            +
                      Chef::Policyfile.load!(logger)
         | 
| 283 | 
            +
                    elsif File.exist?(berksfile)
         | 
| 268 284 | 
             
                      debug("Berksfile found at #{berksfile}, loading Berkshelf")
         | 
| 269 285 | 
             
                      Chef::Berkshelf.load!(logger)
         | 
| 270 286 | 
             
                    elsif File.exist?(cheffile)
         | 
| @@ -325,6 +341,27 @@ module Kitchen | |
| 325 341 | 
             
                    config[:chef_omnibus_root] = installer.root
         | 
| 326 342 | 
             
                    installer.install_command
         | 
| 327 343 | 
             
                  end
         | 
| 344 | 
            +
             | 
| 345 | 
            +
                  def supports_policyfile?
         | 
| 346 | 
            +
                    false
         | 
| 347 | 
            +
                  end
         | 
| 348 | 
            +
             | 
| 349 | 
            +
                  # @return [void]
         | 
| 350 | 
            +
                  # @raise [UserError]
         | 
| 351 | 
            +
                  # @api private
         | 
| 352 | 
            +
                  def sanity_check_sandbox_options!
         | 
| 353 | 
            +
                    if config[:policyfile_path] && !File.exist?(policyfile)
         | 
| 354 | 
            +
                      raise UserError, "policyfile_path set in config "\
         | 
| 355 | 
            +
                        "(#{config[:policyfile_path]} could not be found. " \
         | 
| 356 | 
            +
                        "Expected to find it at full path #{policyfile} " \
         | 
| 357 | 
            +
                    end
         | 
| 358 | 
            +
                    if File.exist?(policyfile) && !supports_policyfile?
         | 
| 359 | 
            +
                      raise UserError, "policyfile detected, but provisioner " \
         | 
| 360 | 
            +
                        "#{self.class.name} doesn't support policyfiles. " \
         | 
| 361 | 
            +
                        "Either use a different provisioner, or delete/rename " \
         | 
| 362 | 
            +
                        "#{policyfile}"
         | 
| 363 | 
            +
                    end
         | 
| 364 | 
            +
                  end
         | 
| 328 365 | 
             
                end
         | 
| 329 366 | 
             
              end
         | 
| 330 367 | 
             
            end
         | 
| @@ -32,6 +32,7 @@ module Kitchen | |
| 32 32 | 
             
                  plugin_version Kitchen::VERSION
         | 
| 33 33 |  | 
| 34 34 | 
             
                  default_config :client_rb, {}
         | 
| 35 | 
            +
                  default_config :named_run_list, {}
         | 
| 35 36 | 
             
                  default_config :json_attributes, true
         | 
| 36 37 | 
             
                  default_config :chef_zero_host, nil
         | 
| 37 38 | 
             
                  default_config :chef_zero_port, 8889
         | 
| @@ -207,6 +208,7 @@ module Kitchen | |
| 207 208 | 
             
                  # @api private
         | 
| 208 209 | 
             
                  def prepare_client_rb
         | 
| 209 210 | 
             
                    data = default_config_rb.merge(config[:client_rb])
         | 
| 211 | 
            +
                    data = data.merge(:named_run_list => config[:named_run_list]) if config[:named_run_list]
         | 
| 210 212 |  | 
| 211 213 | 
             
                    info("Preparing client.rb")
         | 
| 212 214 | 
             
                    debug("Creating client.rb from #{data.inspect}")
         | 
| @@ -240,6 +242,14 @@ module Kitchen | |
| 240 242 |  | 
| 241 243 | 
             
                    "#{chef_client_zero_env}\n#{sudo(ruby)} #{shim}"
         | 
| 242 244 | 
             
                  end
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                  # This provisioner supports policyfiles, so override the default (which
         | 
| 247 | 
            +
                  # is false)
         | 
| 248 | 
            +
                  # @return [true] always returns true
         | 
| 249 | 
            +
                  # @api private
         | 
| 250 | 
            +
                  def supports_policyfile?
         | 
| 251 | 
            +
                    true
         | 
| 252 | 
            +
                  end
         | 
| 243 253 | 
             
                end
         | 
| 244 254 | 
             
              end
         | 
| 245 255 | 
             
            end
         | 
| @@ -42,6 +42,7 @@ module Kitchen | |
| 42 42 |  | 
| 43 43 | 
             
                  default_config :username, "administrator"
         | 
| 44 44 | 
             
                  default_config :password, nil
         | 
| 45 | 
            +
                  default_config :elevated, false
         | 
| 45 46 | 
             
                  default_config :rdp_port, 3389
         | 
| 46 47 | 
             
                  default_config :connection_retries, 5
         | 
| 47 48 | 
             
                  default_config :connection_retry_sleep, 1
         | 
| @@ -185,6 +186,10 @@ module Kitchen | |
| 185 186 | 
             
                    # @api private
         | 
| 186 187 | 
             
                    attr_reader :winrm_transport
         | 
| 187 188 |  | 
| 189 | 
            +
                    # @return [Boolean] whether to use winrm-elevated for running commands
         | 
| 190 | 
            +
                    # @api private
         | 
| 191 | 
            +
                    attr_reader :elevated
         | 
| 192 | 
            +
             | 
| 188 193 | 
             
                    # Writes an RDP document to the local file system.
         | 
| 189 194 | 
             
                    #
         | 
| 190 195 | 
             
                    # @param opts [Hash] file options
         | 
| @@ -217,13 +222,30 @@ module Kitchen | |
| 217 222 | 
             
                    #   script and the standard error stream
         | 
| 218 223 | 
             
                    # @api private
         | 
| 219 224 | 
             
                    def execute_with_exit_code(command)
         | 
| 220 | 
            -
                       | 
| 221 | 
            -
                         | 
| 225 | 
            +
                      if elevated
         | 
| 226 | 
            +
                        unless options[:elevated_username] == options[:user]
         | 
| 227 | 
            +
                          command = "$env:temp='#{unelevated_temp_dir}';#{command}"
         | 
| 228 | 
            +
                        end
         | 
| 229 | 
            +
                        response = elevated_runner.powershell_elevated(
         | 
| 230 | 
            +
                          command,
         | 
| 231 | 
            +
                          options[:elevated_username],
         | 
| 232 | 
            +
                          options[:elevated_password]
         | 
| 233 | 
            +
                        ) do |stdout, _|
         | 
| 234 | 
            +
                          logger << stdout if stdout
         | 
| 235 | 
            +
                        end
         | 
| 236 | 
            +
                      else
         | 
| 237 | 
            +
                        response = session.run_powershell_script(command) do |stdout, _|
         | 
| 238 | 
            +
                          logger << stdout if stdout
         | 
| 239 | 
            +
                        end
         | 
| 222 240 | 
             
                      end
         | 
| 223 241 |  | 
| 224 242 | 
             
                      [response[:exitcode], response.stderr]
         | 
| 225 243 | 
             
                    end
         | 
| 226 244 |  | 
| 245 | 
            +
                    def unelevated_temp_dir
         | 
| 246 | 
            +
                      @unelevated_temp_dir ||= session.run_powershell_script("$env:temp").stdout.chomp
         | 
| 247 | 
            +
                    end
         | 
| 248 | 
            +
             | 
| 227 249 | 
             
                    # @return [Winrm::FileTransporter] a file transporter
         | 
| 228 250 | 
             
                    # @api private
         | 
| 229 251 | 
             
                    def file_transporter
         | 
| @@ -241,6 +263,7 @@ module Kitchen | |
| 241 263 | 
             
                      @connection_retries = @options.delete(:connection_retries)
         | 
| 242 264 | 
             
                      @connection_retry_sleep = @options.delete(:connection_retry_sleep)
         | 
| 243 265 | 
             
                      @max_wait_until_ready   = @options.delete(:max_wait_until_ready)
         | 
| 266 | 
            +
                      @elevated           = @options.delete(:elevated)
         | 
| 244 267 | 
             
                    end
         | 
| 245 268 |  | 
| 246 269 | 
             
                    # Logs formatted standard error output at the warning level.
         | 
| @@ -309,16 +332,33 @@ module Kitchen | |
| 309 332 | 
             
                    # @return [Winrm::CommandExecutor] the command executor session
         | 
| 310 333 | 
             
                    # @api private
         | 
| 311 334 | 
             
                    def session(retry_options = {})
         | 
| 312 | 
            -
                      @session ||=  | 
| 335 | 
            +
                      @session ||= service(retry_options).create_executor
         | 
| 336 | 
            +
                    end
         | 
| 337 | 
            +
             | 
| 338 | 
            +
                    # Creates the elevated runner for running elevated commands
         | 
| 339 | 
            +
                    #
         | 
| 340 | 
            +
                    # @return [Winrm::Elevated::Runner] the elevated runner
         | 
| 341 | 
            +
                    # @api private
         | 
| 342 | 
            +
                    def elevated_runner
         | 
| 343 | 
            +
                      @elevated_runner ||= WinRM::Elevated::Runner.new(session)
         | 
| 344 | 
            +
                    end
         | 
| 345 | 
            +
             | 
| 346 | 
            +
                    # Creates a winrm web service instance
         | 
| 347 | 
            +
                    #
         | 
| 348 | 
            +
                    # @param retry_options [Hash] retry options for the initial connection
         | 
| 349 | 
            +
                    # @return [Winrm::WinRMWebService] the winrm web service
         | 
| 350 | 
            +
                    # @api private
         | 
| 351 | 
            +
                    def service(retry_options = {})
         | 
| 352 | 
            +
                      @service ||= begin
         | 
| 313 353 | 
             
                        opts = {
         | 
| 314 354 | 
             
                          :retry_limit => connection_retries.to_i,
         | 
| 315 355 | 
             
                          :retry_delay   => connection_retry_sleep.to_i
         | 
| 316 356 | 
             
                        }.merge(retry_options)
         | 
| 317 357 |  | 
| 318 358 | 
             
                        service_args = [endpoint, winrm_transport, options.merge(opts)]
         | 
| 319 | 
            -
                         | 
| 320 | 
            -
                         | 
| 321 | 
            -
                         | 
| 359 | 
            +
                        svc = ::WinRM::WinRMWebService.new(*service_args)
         | 
| 360 | 
            +
                        svc.logger = logger
         | 
| 361 | 
            +
                        svc
         | 
| 322 362 | 
             
                      end
         | 
| 323 363 | 
             
                    end
         | 
| 324 364 |  | 
| @@ -360,6 +400,7 @@ module Kitchen | |
| 360 400 |  | 
| 361 401 | 
             
                  WINRM_SPEC_VERSION = ["~> 1.6"].freeze
         | 
| 362 402 | 
             
                  WINRM_FS_SPEC_VERSION = ["~> 0.4.1"].freeze
         | 
| 403 | 
            +
                  WINRM_ELEVATED_SPEC_VERSION = ["~> 0.4.0"].freeze
         | 
| 363 404 |  | 
| 364 405 | 
             
                  # Builds the hash of options needed by the Connection object on
         | 
| 365 406 | 
             
                  # construction.
         | 
| @@ -368,6 +409,9 @@ module Kitchen | |
| 368 409 | 
             
                  # @return [Hash] hash of connection options
         | 
| 369 410 | 
             
                  # @api private
         | 
| 370 411 | 
             
                  def connection_options(data)
         | 
| 412 | 
            +
                    elevated_password = data[:password]
         | 
| 413 | 
            +
                    elevated_password = data[:elevated_password] if data.key?(:elevated_password)
         | 
| 414 | 
            +
             | 
| 371 415 | 
             
                    opts = {
         | 
| 372 416 | 
             
                      :instance_name => instance.name,
         | 
| 373 417 | 
             
                      :kitchen_root => data[:kitchen_root],
         | 
| @@ -379,7 +423,10 @@ module Kitchen | |
| 379 423 | 
             
                      :connection_retries => data[:connection_retries],
         | 
| 380 424 | 
             
                      :connection_retry_sleep => data[:connection_retry_sleep],
         | 
| 381 425 | 
             
                      :max_wait_until_ready => data[:max_wait_until_ready],
         | 
| 382 | 
            -
                      :winrm_transport => data[:winrm_transport]
         | 
| 426 | 
            +
                      :winrm_transport => data[:winrm_transport],
         | 
| 427 | 
            +
                      :elevated => data[:elevated],
         | 
| 428 | 
            +
                      :elevated_username => data[:elevated_username] || data[:username],
         | 
| 429 | 
            +
                      :elevated_password => elevated_password
         | 
| 383 430 | 
             
                    }
         | 
| 384 431 | 
             
                    opts.merge!(additional_transport_args(opts[:winrm_transport]))
         | 
| 385 432 | 
             
                    opts
         | 
| @@ -424,6 +471,7 @@ module Kitchen | |
| 424 471 | 
             
                    super
         | 
| 425 472 | 
             
                    load_with_rescue!("winrm", WINRM_SPEC_VERSION.dup)
         | 
| 426 473 | 
             
                    load_with_rescue!("winrm-fs", WINRM_FS_SPEC_VERSION.dup)
         | 
| 474 | 
            +
                    load_with_rescue!("winrm-elevated", WINRM_ELEVATED_SPEC_VERSION.dup) if config[:elevated]
         | 
| 427 475 | 
             
                  end
         | 
| 428 476 |  | 
| 429 477 | 
             
                  def load_with_rescue!(gem_name, spec_version)
         | 
    
        data/lib/kitchen/version.rb
    CHANGED
    
    
| @@ -480,6 +480,23 @@ module Kitchen # rubocop:disable Metrics/ModuleLength | |
| 480 480 | 
             
                      )
         | 
| 481 481 | 
             
                    end
         | 
| 482 482 |  | 
| 483 | 
            +
                    it "moves named_run_list into provisioner" do
         | 
| 484 | 
            +
                      DataMunger.new(
         | 
| 485 | 
            +
                        {
         | 
| 486 | 
            +
                          :provisioner => "chefy",
         | 
| 487 | 
            +
                          :suites => [
         | 
| 488 | 
            +
                            {
         | 
| 489 | 
            +
                              :name => "sweet",
         | 
| 490 | 
            +
                              :named_run_list => "other_run_list"
         | 
| 491 | 
            +
                            }
         | 
| 492 | 
            +
                          ]
         | 
| 493 | 
            +
                        },
         | 
| 494 | 
            +
                        {}
         | 
| 495 | 
            +
                      ).provisioner_data_for("sweet", "plat").must_equal(
         | 
| 496 | 
            +
                        :name => "chefy",
         | 
| 497 | 
            +
                        :named_run_list => "other_run_list"
         | 
| 498 | 
            +
                      )
         | 
| 499 | 
            +
                    end
         | 
| 483 500 | 
             
                    it "maintains run_list in provisioner" do
         | 
| 484 501 | 
             
                      DataMunger.new(
         | 
| 485 502 | 
             
                        {
         | 
| @@ -536,6 +553,23 @@ module Kitchen # rubocop:disable Metrics/ModuleLength | |
| 536 553 | 
             
                      )
         | 
| 537 554 | 
             
                    end
         | 
| 538 555 |  | 
| 556 | 
            +
                    it "merge provisioner into named_run_list if provisioner exists" do
         | 
| 557 | 
            +
                      DataMunger.new(
         | 
| 558 | 
            +
                        {
         | 
| 559 | 
            +
                          :suites => [
         | 
| 560 | 
            +
                            {
         | 
| 561 | 
            +
                              :name => "sweet",
         | 
| 562 | 
            +
                              :named_run_list => "other_run_list",
         | 
| 563 | 
            +
                              :provisioner => "chefy"
         | 
| 564 | 
            +
                            }
         | 
| 565 | 
            +
                          ]
         | 
| 566 | 
            +
                        },
         | 
| 567 | 
            +
                        {}
         | 
| 568 | 
            +
                      ).provisioner_data_for("sweet", "plat").must_equal(
         | 
| 569 | 
            +
                        :name => "chefy",
         | 
| 570 | 
            +
                        :named_run_list => "other_run_list"
         | 
| 571 | 
            +
                      )
         | 
| 572 | 
            +
                    end
         | 
| 539 573 | 
             
                    it "drops nil run_list" do
         | 
| 540 574 | 
             
                      DataMunger.new(
         | 
| 541 575 | 
             
                        {
         | 
| @@ -609,6 +643,23 @@ module Kitchen # rubocop:disable Metrics/ModuleLength | |
| 609 643 | 
             
                      )
         | 
| 610 644 | 
             
                    end
         | 
| 611 645 |  | 
| 646 | 
            +
                    it "moves named_run_list into provisioner" do
         | 
| 647 | 
            +
                      DataMunger.new(
         | 
| 648 | 
            +
                        {
         | 
| 649 | 
            +
                          :provisioner => "chefy",
         | 
| 650 | 
            +
                          :platforms => [
         | 
| 651 | 
            +
                            {
         | 
| 652 | 
            +
                              :name => "plat",
         | 
| 653 | 
            +
                              :named_run_list => "other_run_list"
         | 
| 654 | 
            +
                            }
         | 
| 655 | 
            +
                          ]
         | 
| 656 | 
            +
                        },
         | 
| 657 | 
            +
                        {}
         | 
| 658 | 
            +
                      ).provisioner_data_for("sweet", "plat").must_equal(
         | 
| 659 | 
            +
                        :name => "chefy",
         | 
| 660 | 
            +
                        :named_run_list => "other_run_list"
         | 
| 661 | 
            +
                      )
         | 
| 662 | 
            +
                    end
         | 
| 612 663 | 
             
                    it "maintains run_list in provisioner" do
         | 
| 613 664 | 
             
                      DataMunger.new(
         | 
| 614 665 | 
             
                        {
         | 
| @@ -665,6 +716,23 @@ module Kitchen # rubocop:disable Metrics/ModuleLength | |
| 665 716 | 
             
                      )
         | 
| 666 717 | 
             
                    end
         | 
| 667 718 |  | 
| 719 | 
            +
                    it "merge provisioner into named_run_list if provisioner exists" do
         | 
| 720 | 
            +
                      DataMunger.new(
         | 
| 721 | 
            +
                        {
         | 
| 722 | 
            +
                          :platforms => [
         | 
| 723 | 
            +
                            {
         | 
| 724 | 
            +
                              :name => "plat",
         | 
| 725 | 
            +
                              :named_run_list => "other_run_list",
         | 
| 726 | 
            +
                              :provisioner => "chefy"
         | 
| 727 | 
            +
                            }
         | 
| 728 | 
            +
                          ]
         | 
| 729 | 
            +
                        },
         | 
| 730 | 
            +
                        {}
         | 
| 731 | 
            +
                      ).provisioner_data_for("sweet", "plat").must_equal(
         | 
| 732 | 
            +
                        :name => "chefy",
         | 
| 733 | 
            +
                        :named_run_list => "other_run_list"
         | 
| 734 | 
            +
                      )
         | 
| 735 | 
            +
                    end
         | 
| 668 736 | 
             
                    it "drops nil run_list" do
         | 
| 669 737 | 
             
                      DataMunger.new(
         | 
| 670 738 | 
             
                        {
         | 
| @@ -893,6 +893,170 @@ describe Kitchen::Provisioner::ChefBase do | |
| 893 893 | 
             
                    end
         | 
| 894 894 | 
             
                  end
         | 
| 895 895 |  | 
| 896 | 
            +
                  describe "with a Policyfile under kitchen_root" do
         | 
| 897 | 
            +
             | 
| 898 | 
            +
                    let(:resolver) { stub(:resolve => true) }
         | 
| 899 | 
            +
             | 
| 900 | 
            +
                    describe "with the default name `Policyfile.rb`" do
         | 
| 901 | 
            +
                      before do
         | 
| 902 | 
            +
                        File.open("#{kitchen_root}/Policyfile.rb", "wb") do |file|
         | 
| 903 | 
            +
                          file.write(<<-POLICYFILE)
         | 
| 904 | 
            +
            name 'wat'
         | 
| 905 | 
            +
            run_list 'wat'
         | 
| 906 | 
            +
            cookbook 'wat'
         | 
| 907 | 
            +
            POLICYFILE
         | 
| 908 | 
            +
                        end
         | 
| 909 | 
            +
                        File.open("#{kitchen_root}/Policyfile.lock.json", "wb") do |file|
         | 
| 910 | 
            +
                          file.write(<<-POLICYFILE)
         | 
| 911 | 
            +
            {
         | 
| 912 | 
            +
              "name": "wat"
         | 
| 913 | 
            +
            }
         | 
| 914 | 
            +
            POLICYFILE
         | 
| 915 | 
            +
                        end
         | 
| 916 | 
            +
                        Kitchen::Provisioner::Chef::Policyfile.stubs(:new).returns(resolver)
         | 
| 917 | 
            +
                      end
         | 
| 918 | 
            +
             | 
| 919 | 
            +
                      describe "when the chef executable is not in the PATH" do
         | 
| 920 | 
            +
                        it "raises a UserError" do
         | 
| 921 | 
            +
                          Kitchen::Provisioner::Chef::Policyfile.stubs(:detect_chef_command!).with do
         | 
| 922 | 
            +
                            raise Kitchen::UserError, "Load failed"
         | 
| 923 | 
            +
                          end
         | 
| 924 | 
            +
                          proc { provisioner }.must_raise Kitchen::UserError
         | 
| 925 | 
            +
                        end
         | 
| 926 | 
            +
                      end
         | 
| 927 | 
            +
             | 
| 928 | 
            +
                      describe "when using a provisoner that doesn't support policyfiles" do
         | 
| 929 | 
            +
                        # This is be the default, provisioners must opt-in.
         | 
| 930 | 
            +
                        it "raises a UserError" do
         | 
| 931 | 
            +
                          proc { provisioner.create_sandbox }.must_raise Kitchen::UserError
         | 
| 932 | 
            +
                        end
         | 
| 933 | 
            +
                      end
         | 
| 934 | 
            +
             | 
| 935 | 
            +
                      describe "when the chef executable is in the PATH" do
         | 
| 936 | 
            +
             | 
| 937 | 
            +
                        before do
         | 
| 938 | 
            +
                          Kitchen::Provisioner::Chef::Policyfile.stubs(:load!)
         | 
| 939 | 
            +
                          provisioner.stubs(:supports_policyfile?).returns(true)
         | 
| 940 | 
            +
                        end
         | 
| 941 | 
            +
             | 
| 942 | 
            +
                        it "logs on debug that it autodetected the policyfile" do
         | 
| 943 | 
            +
                          provisioner
         | 
| 944 | 
            +
             | 
| 945 | 
            +
                          logged_output.string.must_match debug_line(
         | 
| 946 | 
            +
                            "Policyfile found at #{kitchen_root}/Policyfile.rb, "\
         | 
| 947 | 
            +
                            "using Policyfile to resolve dependencies")
         | 
| 948 | 
            +
                        end
         | 
| 949 | 
            +
             | 
| 950 | 
            +
                        it "uses uses the policyfile to resolve dependencies" do
         | 
| 951 | 
            +
                          resolver.expects(:resolve)
         | 
| 952 | 
            +
             | 
| 953 | 
            +
                          provisioner.create_sandbox
         | 
| 954 | 
            +
                        end
         | 
| 955 | 
            +
             | 
| 956 | 
            +
                        it "uses Kitchen.mutex for resolving" do
         | 
| 957 | 
            +
                          Kitchen.mutex.expects(:synchronize)
         | 
| 958 | 
            +
             | 
| 959 | 
            +
                          provisioner.create_sandbox
         | 
| 960 | 
            +
                        end
         | 
| 961 | 
            +
             | 
| 962 | 
            +
                        it "injects policyfile configuration into the dna.json" do
         | 
| 963 | 
            +
                          provisioner.create_sandbox
         | 
| 964 | 
            +
             | 
| 965 | 
            +
                          dna_json_file = File.join(provisioner.sandbox_path, "dna.json")
         | 
| 966 | 
            +
                          dna_json_data = JSON.parse(IO.read(dna_json_file))
         | 
| 967 | 
            +
             | 
| 968 | 
            +
                          expected = {
         | 
| 969 | 
            +
                            "policy_name" => "wat",
         | 
| 970 | 
            +
                            "policy_group" => "local"
         | 
| 971 | 
            +
                          }
         | 
| 972 | 
            +
             | 
| 973 | 
            +
                          dna_json_data.must_equal(expected)
         | 
| 974 | 
            +
                        end
         | 
| 975 | 
            +
                      end
         | 
| 976 | 
            +
                    end
         | 
| 977 | 
            +
                    describe "with a custom policyfile_path" do
         | 
| 978 | 
            +
             | 
| 979 | 
            +
                      let(:config) do
         | 
| 980 | 
            +
                        {
         | 
| 981 | 
            +
                          :policyfile_path => "foo-policy.rb",
         | 
| 982 | 
            +
                          :test_base_path => "/basist",
         | 
| 983 | 
            +
                          :kitchen_root => "/rooty"
         | 
| 984 | 
            +
                        }
         | 
| 985 | 
            +
                      end
         | 
| 986 | 
            +
             | 
| 987 | 
            +
                      before do
         | 
| 988 | 
            +
                        Kitchen::Provisioner::Chef::Policyfile.stubs(:load!)
         | 
| 989 | 
            +
                        Kitchen::Provisioner::Chef::Policyfile.stubs(:new).returns(resolver)
         | 
| 990 | 
            +
                        provisioner.stubs(:supports_policyfile?).returns(true)
         | 
| 991 | 
            +
                      end
         | 
| 992 | 
            +
             | 
| 993 | 
            +
                      describe "when the policyfile exists" do
         | 
| 994 | 
            +
             | 
| 995 | 
            +
                        let(:policyfile_path) { "#{kitchen_root}/foo-policy.rb" }
         | 
| 996 | 
            +
                        let(:policyfile_lock_path) { "#{kitchen_root}/foo-policy.lock.json" }
         | 
| 997 | 
            +
             | 
| 998 | 
            +
                        before do
         | 
| 999 | 
            +
                          File.open(policyfile_path, "wb") do |file|
         | 
| 1000 | 
            +
                            file.write(<<-POLICYFILE)
         | 
| 1001 | 
            +
            name 'wat'
         | 
| 1002 | 
            +
            run_list 'wat'
         | 
| 1003 | 
            +
            cookbook 'wat'
         | 
| 1004 | 
            +
            POLICYFILE
         | 
| 1005 | 
            +
                          end
         | 
| 1006 | 
            +
                          File.open(policyfile_lock_path, "wb") do |file|
         | 
| 1007 | 
            +
                            file.write(<<-POLICYFILE)
         | 
| 1008 | 
            +
            {
         | 
| 1009 | 
            +
              "name": "wat"
         | 
| 1010 | 
            +
            }
         | 
| 1011 | 
            +
            POLICYFILE
         | 
| 1012 | 
            +
                          end
         | 
| 1013 | 
            +
                        end
         | 
| 1014 | 
            +
             | 
| 1015 | 
            +
                        it "uses uses the policyfile to resolve dependencies" do
         | 
| 1016 | 
            +
                          Kitchen::Provisioner::Chef::Policyfile.stubs(:load!)
         | 
| 1017 | 
            +
                          resolver.expects(:resolve)
         | 
| 1018 | 
            +
             | 
| 1019 | 
            +
                          provisioner.create_sandbox
         | 
| 1020 | 
            +
                        end
         | 
| 1021 | 
            +
             | 
| 1022 | 
            +
                        it "passes the correct path to the policyfile resolver" do
         | 
| 1023 | 
            +
                          Kitchen::Provisioner::Chef::Policyfile.
         | 
| 1024 | 
            +
                            expects(:new).
         | 
| 1025 | 
            +
                            with(policyfile_path, instance_of(String), anything).
         | 
| 1026 | 
            +
                            returns(resolver)
         | 
| 1027 | 
            +
             | 
| 1028 | 
            +
                          Kitchen::Provisioner::Chef::Policyfile.stubs(:load!)
         | 
| 1029 | 
            +
                          resolver.expects(:resolve)
         | 
| 1030 | 
            +
             | 
| 1031 | 
            +
                          provisioner.create_sandbox
         | 
| 1032 | 
            +
                        end
         | 
| 1033 | 
            +
                      end
         | 
| 1034 | 
            +
                      describe "when the policyfile doesn't exist" do
         | 
| 1035 | 
            +
             | 
| 1036 | 
            +
                        it "raises a UserError" do
         | 
| 1037 | 
            +
                          proc { provisioner.create_sandbox }.must_raise Kitchen::UserError
         | 
| 1038 | 
            +
                        end
         | 
| 1039 | 
            +
             | 
| 1040 | 
            +
                      end
         | 
| 1041 | 
            +
                      describe "when the policyfile lock doesn't exist" do
         | 
| 1042 | 
            +
                        before do
         | 
| 1043 | 
            +
                          File.open("#{kitchen_root}/Policyfile.rb", "wb") do |file|
         | 
| 1044 | 
            +
                            file.write(<<-POLICYFILE)
         | 
| 1045 | 
            +
              name 'wat'
         | 
| 1046 | 
            +
              run_list 'wat'
         | 
| 1047 | 
            +
              cookbook 'wat'
         | 
| 1048 | 
            +
              POLICYFILE
         | 
| 1049 | 
            +
                          end
         | 
| 1050 | 
            +
             | 
| 1051 | 
            +
                          it "runs `chef install` to generate the lock" do
         | 
| 1052 | 
            +
                            resolver.expects(:compile)
         | 
| 1053 | 
            +
                            provisioner.create_sandbox
         | 
| 1054 | 
            +
                          end
         | 
| 1055 | 
            +
                        end
         | 
| 1056 | 
            +
                      end
         | 
| 1057 | 
            +
                    end
         | 
| 1058 | 
            +
                  end
         | 
| 1059 | 
            +
             | 
| 896 1060 | 
             
                  describe "with a Berksfile under kitchen_root" do
         | 
| 897 1061 |  | 
| 898 1062 | 
             
                    let(:resolver) { stub(:resolve => true) }
         | 
| @@ -21,6 +21,7 @@ require_relative "../../spec_helper" | |
| 21 21 | 
             
            require "kitchen/transport/winrm"
         | 
| 22 22 | 
             
            require "winrm"
         | 
| 23 23 | 
             
            require "winrm-fs"
         | 
| 24 | 
            +
            require "winrm-elevated"
         | 
| 24 25 |  | 
| 25 26 | 
             
            module Kitchen
         | 
| 26 27 |  | 
| @@ -108,6 +109,10 @@ describe Kitchen::Transport::Winrm do | |
| 108 109 | 
             
                it "sets :winrm_transport to :negotiate" do
         | 
| 109 110 | 
             
                  transport[:winrm_transport].must_equal :negotiate
         | 
| 110 111 | 
             
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                it "sets :elevated to false" do
         | 
| 114 | 
            +
                  transport[:elevated].must_equal false
         | 
| 115 | 
            +
                end
         | 
| 111 116 | 
             
              end
         | 
| 112 117 |  | 
| 113 118 | 
             
              describe "#connection" do
         | 
| @@ -326,6 +331,59 @@ describe Kitchen::Transport::Winrm do | |
| 326 331 | 
             
                    make_connection
         | 
| 327 332 | 
             
                  end
         | 
| 328 333 |  | 
| 334 | 
            +
                  it "sets elevated_username from user by default" do
         | 
| 335 | 
            +
                    config[:username] = "user"
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                    klass.expects(:new).with do |hash|
         | 
| 338 | 
            +
                      hash[:elevated_username] == "user"
         | 
| 339 | 
            +
                    end
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                    make_connection
         | 
| 342 | 
            +
                  end
         | 
| 343 | 
            +
             | 
| 344 | 
            +
                  it "sets elevated_username from overriden elevated_username" do
         | 
| 345 | 
            +
                    config[:username] = "user"
         | 
| 346 | 
            +
                    config[:elevated_username] = "elevated_user"
         | 
| 347 | 
            +
             | 
| 348 | 
            +
                    klass.expects(:new).with do |hash|
         | 
| 349 | 
            +
                      hash[:elevated_username] == "elevated_user"
         | 
| 350 | 
            +
                    end
         | 
| 351 | 
            +
             | 
| 352 | 
            +
                    make_connection
         | 
| 353 | 
            +
                  end
         | 
| 354 | 
            +
             | 
| 355 | 
            +
                  it "sets elevated_password from user by default" do
         | 
| 356 | 
            +
                    config[:password] = "pass"
         | 
| 357 | 
            +
             | 
| 358 | 
            +
                    klass.expects(:new).with do |hash|
         | 
| 359 | 
            +
                      hash[:elevated_password] == "pass"
         | 
| 360 | 
            +
                    end
         | 
| 361 | 
            +
             | 
| 362 | 
            +
                    make_connection
         | 
| 363 | 
            +
                  end
         | 
| 364 | 
            +
             | 
| 365 | 
            +
                  it "sets elevated_password from overriden elevated_password" do
         | 
| 366 | 
            +
                    config[:password] = "pass"
         | 
| 367 | 
            +
                    config[:elevated_password] = "elevated_pass"
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                    klass.expects(:new).with do |hash|
         | 
| 370 | 
            +
                      hash[:elevated_password] == "elevated_pass"
         | 
| 371 | 
            +
                    end
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                    make_connection
         | 
| 374 | 
            +
                  end
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                  it "sets elevated_password to nil if overriden elevated_password is nil" do
         | 
| 377 | 
            +
                    config[:password] = "pass"
         | 
| 378 | 
            +
                    config[:elevated_password] = nil
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                    klass.expects(:new).with do |hash|
         | 
| 381 | 
            +
                      hash[:elevated_password].nil?
         | 
| 382 | 
            +
                    end
         | 
| 383 | 
            +
             | 
| 384 | 
            +
                    make_connection
         | 
| 385 | 
            +
                  end
         | 
| 386 | 
            +
             | 
| 329 387 | 
             
                  describe "when negotiate is set in config" do
         | 
| 330 388 | 
             
                    before do
         | 
| 331 389 | 
             
                      config[:winrm_transport] = "negotiate"
         | 
| @@ -406,6 +464,31 @@ describe Kitchen::Transport::Winrm do | |
| 406 464 | 
             
              end
         | 
| 407 465 |  | 
| 408 466 | 
             
              describe "#load_needed_dependencies" do
         | 
| 467 | 
            +
                describe "winrm-elevated" do
         | 
| 468 | 
            +
                  let(:transport) { Kitchen::Transport::Winrm.new(config) }
         | 
| 469 | 
            +
             | 
| 470 | 
            +
                  before do
         | 
| 471 | 
            +
                    transport.stubs(:require).with("winrm")
         | 
| 472 | 
            +
                    transport.stubs(:require).with("winrm-fs")
         | 
| 473 | 
            +
                  end
         | 
| 474 | 
            +
             | 
| 475 | 
            +
                  describe "elevated is false" do
         | 
| 476 | 
            +
                    it "does not require winrm-elevated" do
         | 
| 477 | 
            +
                      transport.expects(:require).with("winrm-elevated").never
         | 
| 478 | 
            +
                      transport.finalize_config!(instance)
         | 
| 479 | 
            +
                    end
         | 
| 480 | 
            +
                  end
         | 
| 481 | 
            +
             | 
| 482 | 
            +
                  describe "elevated is true" do
         | 
| 483 | 
            +
                    before { config[:elevated] = true }
         | 
| 484 | 
            +
             | 
| 485 | 
            +
                    it "does requires winrm-elevated" do
         | 
| 486 | 
            +
                      transport.expects(:require).with("winrm-elevated")
         | 
| 487 | 
            +
                      transport.finalize_config!(instance)
         | 
| 488 | 
            +
                    end
         | 
| 489 | 
            +
                  end
         | 
| 490 | 
            +
                end
         | 
| 491 | 
            +
             | 
| 409 492 | 
             
                describe "winrm-fs" do
         | 
| 410 493 | 
             
                  before do
         | 
| 411 494 | 
             
                    # force loading of winrm-fs to get the version constant
         | 
| @@ -656,6 +739,76 @@ describe Kitchen::Transport::Winrm::Connection do | |
| 656 739 | 
             
                  end
         | 
| 657 740 | 
             
                end
         | 
| 658 741 |  | 
| 742 | 
            +
                describe "elevated command" do
         | 
| 743 | 
            +
                  let(:response) do
         | 
| 744 | 
            +
                    o = WinRM::Output.new
         | 
| 745 | 
            +
                    o[:exitcode] = 0
         | 
| 746 | 
            +
                    o[:data].concat([
         | 
| 747 | 
            +
                      { :stdout => "ok\r\n" },
         | 
| 748 | 
            +
                      { :stderr => "congrats\r\n" }
         | 
| 749 | 
            +
                    ])
         | 
| 750 | 
            +
                    o
         | 
| 751 | 
            +
                  end
         | 
| 752 | 
            +
                  let(:env_temp_response) do
         | 
| 753 | 
            +
                    o = WinRM::Output.new
         | 
| 754 | 
            +
                    o[:exitcode] = 0
         | 
| 755 | 
            +
                    o[:data].concat([
         | 
| 756 | 
            +
                      { :stdout => "temp_dir" }
         | 
| 757 | 
            +
                    ])
         | 
| 758 | 
            +
                    o
         | 
| 759 | 
            +
                  end
         | 
| 760 | 
            +
                  let(:elevated_runner) do
         | 
| 761 | 
            +
                    r = mock("elevated_runner")
         | 
| 762 | 
            +
                    r.responds_like_instance_of(WinRM::Elevated::Runner)
         | 
| 763 | 
            +
                    r
         | 
| 764 | 
            +
                  end
         | 
| 765 | 
            +
             | 
| 766 | 
            +
                  before do
         | 
| 767 | 
            +
                    options[:elevated] = true
         | 
| 768 | 
            +
                    WinRM::Elevated::Runner.stubs(:new).with(executor).returns(elevated_runner)
         | 
| 769 | 
            +
                  end
         | 
| 770 | 
            +
             | 
| 771 | 
            +
                  describe "elevated user is not login user" do
         | 
| 772 | 
            +
                    before do
         | 
| 773 | 
            +
                      options[:elevated_username] = "username"
         | 
| 774 | 
            +
                      options[:elevated_password] = "password"
         | 
| 775 | 
            +
                      executor.expects(:run_powershell_script).
         | 
| 776 | 
            +
                        with("$env:temp").returns(env_temp_response)
         | 
| 777 | 
            +
                      elevated_runner.expects(:powershell_elevated).
         | 
| 778 | 
            +
                        with(
         | 
| 779 | 
            +
                          "$env:temp='temp_dir';doit",
         | 
| 780 | 
            +
                          options[:elevated_username],
         | 
| 781 | 
            +
                          options[:elevated_password]
         | 
| 782 | 
            +
                        ).yields("ok\n", nil).returns(response)
         | 
| 783 | 
            +
                    end
         | 
| 784 | 
            +
             | 
| 785 | 
            +
                    it "logger captures stdout" do
         | 
| 786 | 
            +
                      connection.execute("doit")
         | 
| 787 | 
            +
             | 
| 788 | 
            +
                      logged_output.string.must_match(/^ok$/)
         | 
| 789 | 
            +
                    end
         | 
| 790 | 
            +
                  end
         | 
| 791 | 
            +
             | 
| 792 | 
            +
                  describe "elevator user is login user" do
         | 
| 793 | 
            +
                    before do
         | 
| 794 | 
            +
                      options[:elevated_username] = options[:user]
         | 
| 795 | 
            +
                      options[:elevated_password] = options[:pass]
         | 
| 796 | 
            +
                      elevated_runner.expects(:powershell_elevated).
         | 
| 797 | 
            +
                        with(
         | 
| 798 | 
            +
                          "doit",
         | 
| 799 | 
            +
                          options[:elevated_username],
         | 
| 800 | 
            +
                          options[:elevated_password]
         | 
| 801 | 
            +
                        ).yields("ok\n", nil).returns(response)
         | 
| 802 | 
            +
                    end
         | 
| 803 | 
            +
             | 
| 804 | 
            +
                    it "logger captures stdout" do
         | 
| 805 | 
            +
                      connection.execute("doit")
         | 
| 806 | 
            +
             | 
| 807 | 
            +
                      logged_output.string.must_match(/^ok$/)
         | 
| 808 | 
            +
                    end
         | 
| 809 | 
            +
                  end
         | 
| 810 | 
            +
                end
         | 
| 811 | 
            +
             | 
| 659 812 | 
             
                describe "long command" do
         | 
| 660 813 | 
             
                  let(:command) { %{Write-Host "#{"a" * 4000}"} }
         | 
| 661 814 |  | 
    
        data/test-kitchen.gemspec
    CHANGED
    
    | @@ -34,6 +34,7 @@ Gem::Specification.new do |gem| | |
| 34 34 | 
             
              gem.add_development_dependency "pry-byebug"
         | 
| 35 35 | 
             
              gem.add_development_dependency "pry-stack_explorer"
         | 
| 36 36 | 
             
              gem.add_development_dependency "winrm", "~> 1.6"
         | 
| 37 | 
            +
              gem.add_development_dependency "winrm-elevated", "~> 0.4.0"
         | 
| 37 38 | 
             
              gem.add_development_dependency "winrm-fs", "~> 0.4.1"
         | 
| 38 39 |  | 
| 39 40 | 
             
              gem.add_development_dependency "bundler",   "~> 1.3"
         | 
    
        data/testing_windows.md
    CHANGED
    
    | @@ -9,6 +9,7 @@ Ensure that the cookbook's root directory includes a `Gemfile` that includes you | |
| 9 9 | 
             
            gem 'test-kitchen', git: 'https://github.com/mwrock/test-kitchen', branch: 'winrm-fs'
         | 
| 10 10 | 
             
            gem 'winrm', '~> 1.6'
         | 
| 11 11 | 
             
            gem 'winrm-fs', '~> 0.4.1'
         | 
| 12 | 
            +
            gem 'winrm-elevated', '~> 0.4.0'
         | 
| 12 13 | 
             
            ```
         | 
| 13 14 | 
             
            The above would target the `winrm-fs` branch in mwrock's test-kitchen repo.
         | 
| 14 15 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: test-kitchen
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.8.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Fletcher Nichol
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2016- | 
| 11 | 
            +
            date: 2016-05-06 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: mixlib-shellout
         | 
| @@ -168,6 +168,20 @@ dependencies: | |
| 168 168 | 
             
                - - "~>"
         | 
| 169 169 | 
             
                  - !ruby/object:Gem::Version
         | 
| 170 170 | 
             
                    version: '1.6'
         | 
| 171 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 172 | 
            +
              name: winrm-elevated
         | 
| 173 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 174 | 
            +
                requirements:
         | 
| 175 | 
            +
                - - "~>"
         | 
| 176 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 177 | 
            +
                    version: 0.4.0
         | 
| 178 | 
            +
              type: :development
         | 
| 179 | 
            +
              prerelease: false
         | 
| 180 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 181 | 
            +
                requirements:
         | 
| 182 | 
            +
                - - "~>"
         | 
| 183 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 184 | 
            +
                    version: 0.4.0
         | 
| 171 185 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 172 186 | 
             
              name: winrm-fs
         | 
| 173 187 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -465,6 +479,7 @@ files: | |
| 465 479 | 
             
            - lib/kitchen/provisioner/chef/berkshelf.rb
         | 
| 466 480 | 
             
            - lib/kitchen/provisioner/chef/common_sandbox.rb
         | 
| 467 481 | 
             
            - lib/kitchen/provisioner/chef/librarian.rb
         | 
| 482 | 
            +
            - lib/kitchen/provisioner/chef/policyfile.rb
         | 
| 468 483 | 
             
            - lib/kitchen/provisioner/chef_apply.rb
         | 
| 469 484 | 
             
            - lib/kitchen/provisioner/chef_base.rb
         | 
| 470 485 | 
             
            - lib/kitchen/provisioner/chef_solo.rb
         | 
| @@ -587,7 +602,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 587 602 | 
             
                  version: '0'
         | 
| 588 603 | 
             
            requirements: []
         | 
| 589 604 | 
             
            rubyforge_project: 
         | 
| 590 | 
            -
            rubygems_version: 2. | 
| 605 | 
            +
            rubygems_version: 2.6.3
         | 
| 591 606 | 
             
            signing_key: 
         | 
| 592 607 | 
             
            specification_version: 4
         | 
| 593 608 | 
             
            summary: Test Kitchen is an integration tool for developing and testing infrastructure
         |