├── .rspec ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── publish.yml │ └── lint.yml ├── .release-please-manifest.json ├── .yamllint.yml ├── .markdownlint.yaml ├── CODE_OF_CONDUCT.md ├── .rubocop.yml ├── renovate.json ├── .gitignore ├── Gemfile ├── test └── integration │ └── default │ └── default_test.rb ├── release-please-config.json ├── kitchen.yml ├── Rakefile ├── LICENSE ├── lib └── kitchen │ └── driver │ ├── vagrant_version.rb │ ├── helpers.rb │ └── vagrant.rb ├── support └── hyperv.ps1 ├── kitchen-vagrant.gemspec ├── spec ├── spec_helper.rb └── kitchen │ └── driver │ └── vagrant_spec.rb ├── README.md ├── example └── kitchen.vagrant.yml ├── templates └── Vagrantfile.erb └── CHANGELOG.md /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -fd 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @test-kitchen/maintainers 2 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "2.2.0" 3 | } 4 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | rules: 4 | line-length: disable -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | default: true 3 | MD004: false 4 | MD012: false 5 | MD013: false 6 | MD024: false 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Please refer to the Chef Community Code of Conduct at 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | require: 3 | - cookstyle 4 | 5 | AllCops: 6 | Include: 7 | - "**/*.rb" 8 | Exclude: 9 | - "vendor/**/*" 10 | - "spec/**/*" 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: bundler 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | ":disableDependencyDashboard", 6 | "schedule:automergeEarlyMondays" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | vendor 19 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem"s dependencies in kitchen-vagrant.gemspec 4 | gemspec 5 | 6 | group :test do 7 | gem "rake" 8 | gem "kitchen-inspec" 9 | gem "rspec", "~> 3.2" 10 | end 11 | 12 | group :debug do 13 | gem "pry" 14 | end 15 | 16 | group :cookstyle do 17 | gem "cookstyle" 18 | end 19 | -------------------------------------------------------------------------------- /test/integration/default/default_test.rb: -------------------------------------------------------------------------------- 1 | # Chef InSpec test for kitchen-vagrant 2 | 3 | # The Chef InSpec reference, with examples and extensive documentation, can be 4 | # found at https://docs.chef.io/inspec/resources/ 5 | 6 | user_name = os.windows? ? "Administrator" : "root" 7 | describe user(user_name) do 8 | it { should exist } 9 | end 10 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | ".": { 4 | "package-name": "kitchen-vagrant", 5 | "changelog-path": "CHANGELOG.md", 6 | "release-type": "ruby", 7 | "include-component-in-tag": false, 8 | "version-file": "lib/kitchen/driver/vagrant_version.rb" 9 | } 10 | }, 11 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" 12 | } 13 | -------------------------------------------------------------------------------- /kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | provisioner: 6 | name: shell 7 | command: 'echo "Hello, World!"' 8 | 9 | verifier: 10 | name: inspec 11 | 12 | platforms: 13 | - name: almalinux-9 14 | - name: ubuntu-24.04 15 | - name: windows-2022 16 | driver: 17 | box: stromweld/windows-2022 18 | customize: 19 | memory: 4096 20 | 21 | suites: 22 | - name: default 23 | verifier: 24 | inspec_tests: 25 | - test/integration/default 26 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | require "rspec/core/rake_task" 4 | desc "Run all specs in spec directory" 5 | RSpec::Core::RakeTask.new(:test) do |t| 6 | t.pattern = "spec/**/*_spec.rb" 7 | end 8 | 9 | begin 10 | require "cookstyle" 11 | require "rubocop/rake_task" 12 | RuboCop::RakeTask.new(:style) do |task| 13 | task.options += ["--chefstyle", "--display-cop-names", "--no-color"] 14 | end 15 | rescue LoadError 16 | puts "cookstyle is not available. (sudo) gem install cookstyle to do style checking." 17 | end 18 | 19 | task default: %i{test style} 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Author:: Fletcher Nichol () 2 | 3 | Copyright (C) 2012, Fletcher Nichol 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | -------------------------------------------------------------------------------- /lib/kitchen/driver/vagrant_version.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Fletcher Nichol () 3 | # 4 | # Copyright (C) 2012, Fletcher Nichol 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | module Kitchen 19 | 20 | module Driver 21 | 22 | # Version string for Vagrant Kitchen driver 23 | VAGRANT_VERSION = "2.2.0".freeze 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /support/hyperv.ps1: -------------------------------------------------------------------------------- 1 | #requires -Version 2 -Modules Hyper-V 2 | 3 | #implicitly import hyperv module to avoid powercli cmdlets 4 | if ((Get-Module -Name 'hyper-v') -ne $null) { 5 | Remove-Module -Name hyper-v 6 | Import-Module -Name hyper-v 7 | } 8 | else { 9 | Import-Module -Name hyper-v 10 | } 11 | 12 | $ProgressPreference = 'SilentlyContinue' 13 | 14 | function Get-DefaultVMSwitch { 15 | [CmdletBinding()] 16 | param ($Name) 17 | 18 | $switches = Get-VMSwitch @PSBoundParameters 19 | 20 | if (-not $PSBoundParameters.ContainsKey('Name') -and (($switches.Name) -contains 'Default Switch') ) { 21 | # Looking for 'Default Switch' on Fall Creators Update or newer 22 | $switches = $switches | 23 | Where-Object {$_.Name -like 'Default Switch'} 24 | } 25 | 26 | $switches | 27 | Select-Object -first 1 | 28 | Select-Object Name, ID 29 | } -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: release-please 3 | 4 | "on": 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | release-please: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: googleapis/release-please-action@v4 13 | id: release 14 | with: 15 | token: ${{ secrets.PORTER_GITHUB_TOKEN }} 16 | 17 | - name: Checkout 18 | uses: actions/checkout@v5 19 | if: ${{ steps.release.outputs.release_created }} 20 | 21 | - name: Build and publish to GitHub Package 22 | uses: actionshub/publish-gem-to-github@main 23 | if: ${{ steps.release.outputs.release_created }} 24 | with: 25 | token: ${{ secrets.GITHUB_TOKEN }} 26 | owner: ${{ secrets.OWNER }} 27 | 28 | - name: Build and publish to RubyGems 29 | uses: actionshub/publish-gem-to-rubygems@main 30 | if: ${{ steps.release.outputs.release_created }} 31 | with: 32 | token: ${{ secrets.RUBYGEMS_API_KEY }} 33 | -------------------------------------------------------------------------------- /kitchen-vagrant.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path("lib", __dir__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require "kitchen/driver/vagrant_version" 4 | 5 | Gem::Specification.new do |gem| 6 | gem.name = "kitchen-vagrant" 7 | gem.version = Kitchen::Driver::VAGRANT_VERSION 8 | gem.license = "Apache-2.0" 9 | gem.authors = ["Fletcher Nichol"] 10 | gem.email = ["fnichol@nichol.ca"] 11 | gem.description = "Kitchen::Driver::Vagrant - A HashiCorp Vagrant Driver for Test Kitchen." 12 | gem.summary = gem.description 13 | gem.homepage = "https://github.com/test-kitchen/kitchen-vagrant/" 14 | 15 | gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).grep(/LICENSE|^lib|^support|^templates/) 16 | gem.require_paths = ["lib"] 17 | 18 | gem.required_ruby_version = ">= 3.0" 19 | 20 | if ENV['CHEF_TEST_KITCHEN_ENTERPRISE'] 21 | gem.add_dependency "chef-test-kitchen-enterprise", ">= 1.1.4", "< 4" 22 | else 23 | gem.add_dependency "test-kitchen", ">= 1.4", "< 4" 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Lint, Unit & Integration Tests' 3 | 4 | 'on': 5 | pull_request: 6 | 7 | jobs: 8 | lint-unit: 9 | uses: test-kitchen/.github/.github/workflows/lint-unit.yml@main 10 | 11 | integration: 12 | runs-on: ubuntu-latest 13 | needs: lint-unit 14 | name: Kitchen Verify 15 | strategy: 16 | matrix: 17 | ruby: ["3.4"] 18 | os: ["almalinux-9"] 19 | steps: 20 | - name: Install VirtualBox 21 | run: | 22 | sudo apt-get update 23 | sudo apt-get install -y software-properties-common libarchive-tools virtualbox 24 | - uses: actions/checkout@v5 25 | - uses: ruby/setup-ruby@v1 26 | with: 27 | ruby-version: ${{ matrix.ruby }} 28 | bundler-cache: true 29 | - name: Install Vagrant 30 | run: | 31 | bundle add vagrant --version ">= 2.4.4" 32 | bundle binstubs vagrant 33 | export PATH="$(pwd)/bin:$PATH" 34 | vagrant -v 35 | - name: Kitchen Verify 36 | run: | 37 | export PATH="$(pwd)/bin:$PATH" 38 | bundle exec kitchen verify default-${{ matrix.os}} 39 | env: 40 | CHEF_LICENSE: "accept-no-persist" 41 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Fletcher Nichol () 3 | # 4 | # Copyright (C) 2015, Fletcher Nichol 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | RSpec.configure do |config| 18 | 19 | # Run specs in random order to surface order dependencies. If you find an 20 | # order dependency and want to debug it, you can fix the order by providing 21 | # the seed, which is printed after each run. 22 | # --seed 1234 23 | config.order = :random 24 | 25 | # Seed global randomization in this process using the `--seed` CLI option. 26 | # Setting this allows you to use `--seed` to deterministically reproduce 27 | # test failures related to randomization by passing the same `--seed` value 28 | # as the one that triggered the failure. 29 | Kernel.srand config.seed 30 | 31 | config.expose_dsl_globally = true 32 | 33 | end 34 | require "securerandom" 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kitchen::Vagrant 2 | 3 | [![Gem Version](https://badge.fury.io/rb/kitchen-vagrant.svg)](http://badge.fury.io/rb/kitchen-vagrant) 4 | [![CI](https://github.com/test-kitchen/kitchen-vagrant/actions/workflows/lint.yml/badge.svg)](https://github.com/test-kitchen/kitchen-vagrant/actions/workflows/lint.yml) 5 | 6 | A Test Kitchen Driver for HashiCorp Vagrant. 7 | 8 | This driver works by generating a single Vagrantfile for each instance in a 9 | sandboxed directory. Since the Vagrantfile is written out on disk, Vagrant 10 | needs absolutely no knowledge of Test Kitchen. So no Vagrant plugins are 11 | required. 12 | 13 | ## Requirements 14 | 15 | ### Vagrant 16 | 17 | Vagrant version of 2.4 or later. 18 | 19 | ## Installation 20 | 21 | The kitchen-vagrant driver ships as part of Chef Workstation. The easiest way to use this driver is to use it with Chef Workstation. 22 | 23 | If you want to install the driver directly into a Ruby installation: 24 | 25 | ```sh 26 | gem install kitchen-vagrant 27 | ``` 28 | 29 | If you're using Bundler, simply add it to your Gemfile: 30 | 31 | ```ruby 32 | gem "kitchen-vagrant" 33 | ``` 34 | 35 | ... and then run `bundle install`. 36 | 37 | ## Configuration and Usage 38 | 39 | See the [kitchen.ci Vagrant Driver Page](https://kitchen.ci/docs/drivers/vagrant/) for documentation on configuring this driver. 40 | 41 | ### Custom SSH Port Configuration 42 | 43 | If your VM's SSH daemon listens on a non-standard port (other than port 22), you can configure Test Kitchen to use the custom port: 44 | 45 | ```yaml 46 | driver: 47 | name: vagrant 48 | ssh: 49 | guest_port: 444 # SSH daemon listens on port 444 inside the VM 50 | network: 51 | - ["forwarded_port", {guest: 444, host: 2222, auto_correct: true}] 52 | ``` 53 | 54 | This configuration tells Vagrant that the SSH daemon inside the guest VM is listening on port 444 instead of the default port 22. Vagrant will handle the port forwarding appropriately. 55 | 56 | ## Development 57 | 58 | * Source hosted at [GitHub][repo] 59 | * Report issues/questions/feature requests on [GitHub Issues][issues] 60 | 61 | Pull requests are very welcome! Make sure your patches are well tested. 62 | Ideally create a topic branch for every separate change you make. For 63 | example: 64 | 65 | 1. Fork the repo 66 | 2. Create your feature branch (`git checkout -b my-new-feature`) 67 | 3. Commit your changes (`git commit -am 'Added some feature'`) 68 | 4. Push to the branch (`git push origin my-new-feature`) 69 | 5. Create new Pull Request 70 | 71 | ## Authors 72 | 73 | Created by [Fletcher Nichol][author] () 74 | 75 | ## License 76 | 77 | Apache 2.0 (see [LICENSE][license]) 78 | 79 | [author]: https://github.com/test-kitchen 80 | [issues]: https://github.com/test-kitchen/kitchen-vagrant/issues 81 | [license]: https://github.com/test-kitchen/kitchen-vagrant/blob/master/LICENSE 82 | [repo]: https://github.com/test-kitchen/kitchen-vagrant 83 | -------------------------------------------------------------------------------- /lib/kitchen/driver/helpers.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Steven Murawski 3 | # Copyright:: Copyright (c) 2015 Chef Software, Inc. 4 | # License:: Apache License, Version 2.0 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | require "mixlib/shellout" unless defined?(Mixlib::ShellOut) 19 | require "fileutils" unless defined?(FileUtils) 20 | require "json" unless defined?(JSON) 21 | 22 | module Kitchen 23 | module Driver 24 | module HypervHelpers 25 | def encode_command(script) 26 | encoded_script = script.encode("UTF-16LE", "UTF-8") 27 | Base64.strict_encode64(encoded_script) 28 | end 29 | 30 | def is_64bit? 31 | os_arch = ENV["PROCESSOR_ARCHITEW6432"] || ENV["PROCESSOR_ARCHITECTURE"] 32 | ruby_arch = ["foo"].pack("p").size == 4 ? 32 : 64 33 | os_arch == "AMD64" && ruby_arch == 64 34 | end 35 | 36 | def is_32bit? 37 | os_arch = ENV["PROCESSOR_ARCHITEW6432"] || ENV["PROCESSOR_ARCHITECTURE"] 38 | ruby_arch = ["foo"].pack("p").size == 4 ? 32 : 64 39 | os_arch != "AMD64" && ruby_arch == 32 40 | end 41 | 42 | def powershell_64_bit 43 | if is_64bit? || is_32bit? 44 | 'c:\windows\system32\windowspowershell\v1.0\powershell.exe' 45 | else 46 | 'c:\windows\sysnative\windowspowershell\v1.0\powershell.exe' 47 | end 48 | end 49 | 50 | def wrap_command(script) 51 | base_script_path = File.join(File.dirname(__FILE__), "/../../../support/hyperv.ps1") 52 | debug("Loading functions from #{base_script_path}") 53 | new_script = [ ". #{base_script_path}", "#{script}" ].join(";\n") 54 | debug("Wrapped script: #{new_script}") 55 | "#{powershell_64_bit} -noprofile -executionpolicy bypass" \ 56 | " -encodedcommand #{encode_command new_script} -outputformat Text" 57 | end 58 | 59 | # Convenience method to run a powershell command locally. 60 | # 61 | # @param cmd [String] command to run locally 62 | # @param options [Hash] options hash 63 | # @see Kitchen::ShellOut.run_command 64 | # @api private 65 | def run_ps(cmd, options = {}) 66 | cmd = "echo #{cmd}" if config[:dry_run] 67 | debug("Preparing to run: ") 68 | debug(" #{cmd}") 69 | wrapped_command = wrap_command cmd 70 | execute_command wrapped_command, options 71 | end 72 | 73 | def execute_command(cmd, options = {}) 74 | debug("#Local Command BEGIN (#{cmd})") 75 | sh = Mixlib::ShellOut.new(cmd, options) 76 | sh.run_command 77 | debug("Local Command END #{Util.duration(sh.execution_time)}") 78 | raise "Failed: #{sh.stderr}" if sh.error? 79 | 80 | stdout = sanitize_stdout(sh.stdout) 81 | JSON.parse(stdout) if stdout.length > 2 82 | end 83 | 84 | def sanitize_stdout(stdout) 85 | stdout.split("\n").select { |s| !s.start_with?("PS") }.join("\n") 86 | end 87 | 88 | def hyperv_switch 89 | default_switch_object = run_ps hyperv_default_switch_ps 90 | if default_switch_object.nil? || 91 | !default_switch_object.key?("Name") || 92 | default_switch_object["Name"].empty? 93 | raise "Failed to find a default VM Switch." 94 | end 95 | 96 | default_switch_object["Name"] 97 | end 98 | 99 | def hyperv_default_switch_ps 100 | <<-VMSWITCH 101 | Get-DefaultVMSwitch #{ENV["KITCHEN_HYPERV_SWITCH"]} | ConvertTo-Json 102 | VMSWITCH 103 | end 104 | 105 | private 106 | 107 | def ruby_array_to_ps_array(list) 108 | return "@()" if list.nil? || list.empty? 109 | 110 | list.to_s.tr("[]", "()").prepend("@") 111 | end 112 | end 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /example/kitchen.vagrant.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # All the options for kitchen-vagrant enumerated and annotated 3 | # options are illustrated where they most commonly would be set 4 | driver: 5 | name: vagrant 6 | 7 | # If not set, check for the environment variable `VAGRANT_DEFAULT_PROVIDER` 8 | # If that is unset, default to `virtualbox` 9 | # provider: virtualbox 10 | 11 | # If `true` check if the box is up-to-date 12 | # box_check_update: nil 13 | 14 | # If `true`, then SSL certificates from the server will not be verified. 15 | # box_download_insecure: nil 16 | 17 | # A relative path to a CA certificate bundle 18 | # for verifying endpoints with custom certificates 19 | # box_download_ca_cert: nil 20 | 21 | # Integer for setting custom boot timeout 22 | # boot_timeout: nil 23 | # Hash for passing k/v options to specific 24 | # providers for customization 25 | # emtpy by default 26 | # customize: 27 | # memory: 1024 28 | # cpuexecutioncap: 50 29 | # If `true`, allows GUI mode for Vagrant providers 30 | # that support this feature 31 | # gui: nil 32 | 33 | # If `true`, use "Linked Clones" or "Differencing Disk" 34 | # options for providers that support this feature 35 | # This can reduce disk usage and offer performance benefits. 36 | # linked_clone: nil 37 | 38 | # An Array of network customizations for the virtual machine. 39 | # Each Array element is itself an Array of arguments to be passed to the 40 | # config.vm.network method 41 | # network: [] 42 | 43 | # An optional hook to run a command immediately prior to 44 | # the `vagrant up --no-provisioner` command being executed. 45 | # **CAUTION** 46 | # pre_create_command: nil 47 | 48 | # Enables Vagrant built-in provisioning 49 | # Useful in conjunction with `vagrantfiles` 50 | # provision: false 51 | 52 | # Hash for passing k/v options to Vagrant's SSH 53 | # configuration. Only needed for advanced/custom 54 | # configuration. **CAUTION** 55 | # ssh: {} 56 | # 57 | # Example: To use a custom SSH port inside the guest VM 58 | # (useful when SSH daemon is configured to listen on a non-standard port): 59 | # ssh: 60 | # guest_port: 444 61 | # 62 | # This tells Vagrant that SSH is listening on port 444 inside the VM 63 | # instead of the default port 22. Vagrant will still forward this to 64 | # a high port on the host (e.g., 2222), but will connect to port 444 65 | # inside the guest. 66 | 67 | # An array of arrays that configure a synced folder 68 | # This value is automatically configured if using 69 | # the `cache_directory` option. Otherwise, empty. 70 | # Options can be specified as a String (backward compatible) or Hash 71 | # synced_folders: 72 | # - ["data/%{instance_name}", "/opt/instance_data"] 73 | # - ["/host_path", "/vm_path", "create: true, type: :nfs"] 74 | # # For SMB shares (useful with Hyper-V), use Hash format: 75 | # - ["C:\\local\\path", "C:\\remote\\path", {type: "smb", smb_username: "user", smb_password: "pass"}] 76 | 77 | # This should only need to get set if the Vagrant binary 78 | # isn't in the PATH or there is a specific location desired 79 | # vagrant_binary: "vagrant" 80 | 81 | # By default, use the Vagrantfile.erb that is part of the gem 82 | # otherwise use whatever the user provides here. **CAUTION** 83 | # vagrantfile_erb: Alt_Vagrantfile.erb 84 | 85 | # An array of paths to Vagrantfiles 86 | # Empty by default 87 | # vagrantfiles: [] 88 | 89 | # An array of environment variables to set in the VM 90 | # These are written to /etc/profile.d/kitchen.sh and are available 91 | # to all users and processes including Chef runs 92 | # Empty by default 93 | # env: 94 | # - AWS_REGION=<%= ENV['AWS_REGION'] %> 95 | # - AWS_ACCESS_KEY_ID=<%= ENV['AWS_ACCESS_KEY_ID'] %> 96 | # - AWS_SECRET_ACCESS_KEY=<%= ENV['AWS_SECRET_ACCESS_KEY'] %> 97 | 98 | # We only set this to a path for a subset of known bento boxes 99 | # driver.windows_os? ? "/omnibus/cache" : "/tmp/omnibus/cache" 100 | # if set to `false` this will disable caching entirely 101 | # cache_directory: /tmp/omnibus/cache 102 | 103 | # Path to kitchen's global cache directory, primarily for caching 104 | # chef-client downlaods 105 | # Default is File.expand_path("~/.kitchen/cache") 106 | # kitchen_cache_directory: /Users/cheeseplus/.kitchen/cache 107 | 108 | # If `box` or `machine`, sets the respective value for 109 | # config.cache.scope. Any other truthy value yields `box` 110 | # cachier: nil 111 | 112 | provisioner: 113 | name: chef_zero 114 | 115 | verifier: 116 | name: inspec 117 | 118 | platforms: 119 | # We will grab boxes from bento on Vagrant Cloud 120 | # for a set of common platforms 121 | - name: ubuntu-20.04 122 | - name: centos-8 123 | # Otherwise for platforms we don't know, the box needs to exist locally 124 | # and be known to Vagrant, otherwise provide `box` or `box_url` 125 | - name: openbsd-5.6 126 | driver: 127 | # Versioned boxes from Vagrant Cloud can be utilized 128 | # `box_version` only works when `box` uses the Vagrant Cloud syntax 129 | # box: organization/openbsd-56 130 | # box_version: 1.2.3 131 | # If not using Vagrant Cloud, the box can be fetched 132 | # remotely via `http(s)://` or locally via `file://` 133 | # `box` requires a value 134 | box: openbsd-5.6 135 | box_url: http://url.tld/openbsd-5.6.box 136 | 137 | suites: 138 | - name: default 139 | driver: 140 | # If Windows, this is nil otherwise it's set to 141 | # "#{driver.instance.name}.vagrantup.com" 142 | # vm_hostname: "custom.tld" 143 | run_list: 144 | - recipe[cookbook::default] 145 | -------------------------------------------------------------------------------- /templates/Vagrantfile.erb: -------------------------------------------------------------------------------- 1 | <% config[:vagrantfiles].each do |vagrantfile| %> 2 | load "<%= vagrantfile %>" 3 | <% end %> 4 | 5 | Vagrant.configure("2") do |c| 6 | c.berkshelf.enabled = false if Vagrant.has_plugin?("vagrant-berkshelf") 7 | <% if config[:cachier] %> 8 | if Vagrant.has_plugin?("vagrant-cachier") 9 | c.cache.scope = <%= [':box', ':machine'].include?(config[:cachier]) ? config[:cachier] : ':box' %> 10 | end 11 | <% end %> 12 | 13 | c.vm.box = "<%= config[:box] %>" 14 | 15 | <% if config[:box_url] %> 16 | c.vm.box_url = "<%= config[:box_url] %>" 17 | <% end %> 18 | 19 | <% if config[:box_version] %> 20 | c.vm.box_version = "<%= config[:box_version] %>" 21 | <% end %> 22 | 23 | <% if config[:box_arch] %> 24 | c.vm.box_architecture = "<%= config[:box_arch] %>" 25 | <% end %> 26 | 27 | <% if !config[:box_check_update].nil? %> 28 | c.vm.box_check_update = <%= config[:box_check_update] %> 29 | <% end %> 30 | 31 | <% if !config[:box_download_ca_cert].nil? %> 32 | c.vm.box_download_ca_cert = "<%= config[:box_download_ca_cert] %>" 33 | <% end %> 34 | 35 | <% if !config[:box_download_insecure].nil? %> 36 | c.vm.box_download_insecure = "<%= config[:box_download_insecure] %>" 37 | <% end %> 38 | 39 | <% if config[:vm_hostname] %> 40 | c.vm.hostname = "<%= config[:vm_hostname] %>" 41 | <% end %> 42 | 43 | <% if config[:communicator] %> 44 | c.vm.communicator = "<%= config[:communicator] %>" 45 | <% end %> 46 | 47 | <% if config[:guest] %> 48 | c.vm.guest = "<%= config[:guest] %>" 49 | <% end %> 50 | 51 | <% if config[:communicator] %> 52 | <% if config[:username] %> 53 | c.<%= config[:communicator] %>.username = "<%= config[:username] %>" 54 | <% end %> 55 | <% if config[:password] %> 56 | c.<%= config[:communicator] %>.password = "<%= config[:password] %>" 57 | <% end %> 58 | <% else %> 59 | <% if config[:username] %> 60 | c.ssh.username = "<%= config[:username] %>" 61 | <% end %> 62 | <% if config[:password] %> 63 | c.ssh.password = "<%= config[:password] %>" 64 | <% end %> 65 | <% end %> 66 | 67 | <% if config[:ssh_key] %> 68 | c.ssh.private_key_path = "<%= config[:ssh_key] %>" 69 | <% end %> 70 | <% config[:ssh].each do |key, value| %> 71 | c.ssh.<%= key %> = <%= [true, false].include?(value) ? value : value.inspect %> 72 | <% end %> 73 | <% if config[:winrm] %> 74 | <% config[:winrm].each do |key, value| %> 75 | <% if value.is_a? String %> 76 | c.winrm.<%= key %> = "<%= value%>" 77 | <% else %> 78 | c.winrm.<%= key %> = <%= value%> 79 | <% end %> 80 | <% end %> 81 | <% end %> 82 | 83 | <% if config[:boot_timeout] %> 84 | c.vm.boot_timeout = <%= config[:boot_timeout] %> 85 | <% end %> 86 | 87 | <% Array(config[:network]).each do |opts| %> 88 | c.vm.network(:<%= opts[0] %>, <%= opts[1].map { |k, v| "#{k}: #{v.inspect}" }.join(', ') %>) 89 | <% end %> 90 | 91 | c.vm.synced_folder ".", "/vagrant", disabled: true 92 | <% config[:synced_folders].each do |source, destination, options| %> 93 | c.vm.synced_folder <%= source.inspect %>, <%= destination.inspect %>, <%= options %> 94 | <% end %> 95 | 96 | c.vm.provider :<%= config[:provider] %> do |p| 97 | <% case config[:provider] 98 | when "virtualbox" %> 99 | p.name = "kitchen-<%= File.basename(config[:kitchen_root]) %>-<%= instance.name %>-<%= SecureRandom.uuid %>" 100 | <% end %> 101 | 102 | <% case config[:provider] 103 | when "virtualbox", /^vmware_/ 104 | if config[:gui] == true || config[:gui] == false %> 105 | p.gui = <%= config[:gui] %> 106 | <% end 107 | end 108 | 109 | case config[:provider] 110 | when "virtualbox", /^vmware_/, "parallels" 111 | if config[:linked_clone] == true || config[:linked_clone] == false %> 112 | p.linked_clone = <%= config[:linked_clone] %> 113 | <% end 114 | when "hyperv" %> 115 | p.vmname = "<%="kitchen-#{File.basename(config[:kitchen_root])}-#{instance.name}-#{SecureRandom.uuid}"[0..99].chomp('-') %>" 116 | <% if config[:linked_clone] == true || config[:linked_clone] == false %> 117 | p.linked_clone = <%= config[:linked_clone] %> 118 | <% end 119 | end %> 120 | 121 | <% if config[:provider] == "virtualbox" && 122 | !config[:customize].has_key?(:audio) %> 123 | p.customize ["modifyvm", :id, "--audio", "none"] 124 | <% end %> 125 | 126 | <% config[:customize].each do |key, value| %> 127 | <% case config[:provider] 128 | when "libvirt" %> 129 | <% if key == :storage %> 130 | <% if value.is_a? String %> 131 | p.storage <%= value %> 132 | <% elsif value.is_a? Array %> 133 | <% value.each do |v| %> 134 | p.storage <%= v %> 135 | <% end %> 136 | <% end %> 137 | <% else %> 138 | <% if value.is_a? String %> 139 | p.<%= key %> = "<%= value%>" 140 | <% else %> 141 | p.<%= key %> = <%= value%> 142 | <% end %> 143 | <% end %> 144 | <% when "lxc" %> 145 | <% if key == :container_name %> 146 | p.container_name = <%= value == ":machine" ? value : "\"#{value}\"" %> 147 | <% elsif key == :backingstore %> 148 | p.backingstore = "<%= value %>" 149 | <% elsif key == :backingstore_options %> 150 | <% config[:customize][:backingstore_options].each do |opt, opt_val| %> 151 | p.backingstore_option "--<%= opt %>", "<%= opt_val %>" 152 | <% end %> 153 | <% elsif key == :include %> 154 | <% Array(value).each do |include| %> 155 | p.customize "<%= key %>", "<%= include %>" 156 | <% end %> 157 | <% else %> 158 | p.customize "<%= key %>", "<%= value %>" 159 | <% end %> 160 | <% when "managed" %> 161 | <% if key == :server %> 162 | p.server = "<%= value %>" 163 | <% end %> 164 | <% when "parallels" %> 165 | <% if key == :memory || key == :cpus %> 166 | p.<%= key %> = <%= value %> 167 | <% else %> 168 | p.customize ["set", :id, "--<%= key.to_s.gsub('_', '-') %>", "<%= value %>"] 169 | <% end %> 170 | <% when "softlayer" %> 171 | <% if key == :disk_capacity %> 172 | <% if value.is_a? Hash %> 173 | p.<%= key %> = {<%= value.map { |k, v| "\"#{k}\": #{v}" }.join(', ') %>} 174 | <% else %> 175 | p.<%= key %> = <%= value %> 176 | <% end %> 177 | <% else %> 178 | p.<%= key %> = "<%= value %>" 179 | <% end %> 180 | <% when "virtualbox" %> 181 | <% if key == :createhd %> 182 | <% value = [value] unless value.instance_of?(Array) %> 183 | <% value.each do |item| %> 184 | unless File.file?("<%= item[:filename] %>") 185 | p.customize ["createhd", "--filename", "<%= item[:filename] %>", "--size", <%= item[:size] %>] 186 | end 187 | <% end %> 188 | <% elsif key == :storageattach || key == :storagectl %> 189 | <% value = [value] unless value.instance_of?(Array) %> 190 | <% value.each do |item| %> 191 | <% options = [] %> 192 | <% item.each do |storage_option_key, storage_option_value| 193 | options << "\"--#{storage_option_key}\"" 194 | if storage_option_value.kind_of? Integer 195 | options << storage_option_value 196 | else 197 | options << "\"#{storage_option_value}\"" 198 | end 199 | end %> 200 | p.customize ["<%= key.to_s %>", :id, <%= options.join(', ') %>] 201 | <% end %> 202 | <% elsif key == :cpuidset %> 203 | <% ids = [] %> 204 | <% value.each do | id | 205 | ids << "\"#{id}\"" 206 | end %> 207 | p.customize ["modifyvm", :id, "--cpuidset", <%= ids.join(', ') %>] 208 | <% elsif key == :setextradata %> 209 | <% value.each do | data_key, data_value | %> 210 | <% data_value = "\"#{data_value}\"" if data_value.is_a? String %> 211 | p.customize ["setextradata", :id, "<%= data_key %>", <%= data_value %>] 212 | <% end %> 213 | <% else %> 214 | p.customize ["modifyvm", :id, "--<%= key %>", "<%= value %>"] 215 | <% end %> 216 | <% when /^vmware_/ %> 217 | <% if key == :memory %> 218 | <% unless config[:customize].include?(:memsize) %> 219 | p.vmx["memsize"] = "<%= value %>" 220 | <% end %> 221 | <% elsif key == :cpus %> 222 | <% unless config[:customize].include?(:numvcpus) %> 223 | p.vmx["numvcpus"] = "<%= value %>" 224 | <% end %> 225 | <% else %> 226 | p.vmx["<%= key %>"] = "<%= value %>" 227 | <% end %> 228 | <% else %> 229 | <% if value.is_a? String %> 230 | p.<%= key %> = "<%= value%>" 231 | <% elsif value.is_a? Array %> 232 | <% if value.all? { |item| item.is_a? Hash } %> 233 | <% 234 | def format_hash_recursively(hash) 235 | hash.map do |k, v| 236 | if v.is_a?(Array) && v.all? { |item| item.is_a? Hash } 237 | # Handle nested array of hashes 238 | formatted_array = v.map { |nested_hash| "{" + format_hash_recursively(nested_hash) + "}" }.join(", ") 239 | "#{k}: [#{formatted_array}]" 240 | else 241 | "#{k}: #{v.inspect}" 242 | end 243 | end.join(", ") 244 | end 245 | %> 246 | p.<%= key %> = [<%= value.map { |hash| "{" + format_hash_recursively(hash) + "}" }.join(", ") %>] 247 | <% else %> 248 | p.<%= key %> = <%= value%> 249 | <% end %> 250 | <% else %> 251 | p.<%= key %> = <%= value%> 252 | <% end %> 253 | <% end %> 254 | <% end %> 255 | end 256 | 257 | <% if config[:env] && !config[:env].empty? %> 258 | # Set environment variables 259 | <% config[:env].each do |env_var| %> 260 | c.vm.provision "shell", inline: <<-SHELL 261 | echo 'export <%= env_var.gsub("'", "'\\\\''") %>' >> /etc/profile.d/kitchen.sh 262 | SHELL 263 | <% end %> 264 | c.vm.provision "shell", inline: "chmod +x /etc/profile.d/kitchen.sh", run: "once" 265 | <% end %> 266 | end 267 | -------------------------------------------------------------------------------- /lib/kitchen/driver/vagrant.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Fletcher Nichol () 3 | # 4 | # Copyright (C) 2012, Fletcher Nichol 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | require "erb" unless defined?(Erb) 19 | require "fileutils" unless defined?(FileUtils) 20 | require "rubygems/version" 21 | 22 | require "kitchen" 23 | require_relative "vagrant_version" 24 | require_relative "helpers" 25 | 26 | module Kitchen 27 | 28 | module Driver 29 | 30 | # Vagrant driver for Kitchen. It communicates to Vagrant via the CLI. 31 | # 32 | # @author Fletcher Nichol 33 | class Vagrant < Kitchen::Driver::Base 34 | 35 | include ShellOut 36 | include Kitchen::Driver::HypervHelpers 37 | 38 | kitchen_driver_api_version 2 39 | 40 | plugin_version Kitchen::Driver::VAGRANT_VERSION 41 | 42 | default_config(:box, &:default_box) 43 | required_config :box 44 | 45 | default_config :box_check_update, nil 46 | 47 | default_config :box_auto_update, nil 48 | 49 | default_config :box_auto_prune, nil 50 | 51 | default_config :box_download_insecure, nil 52 | 53 | default_config :box_download_ca_cert, nil 54 | 55 | default_config(:box_url, &:default_box_url) 56 | 57 | default_config :box_version, nil 58 | 59 | default_config :box_arch, nil 60 | 61 | default_config :boot_timeout, nil 62 | 63 | default_config :customize, {} 64 | 65 | default_config :gui, nil 66 | 67 | default_config :linked_clone, nil 68 | 69 | default_config :network, [] 70 | 71 | default_config :pre_create_command, nil 72 | 73 | default_config :provision, false 74 | 75 | default_config :provider do |_| 76 | ENV.fetch("VAGRANT_DEFAULT_PROVIDER", "virtualbox") 77 | end 78 | 79 | default_config :ssh, {} 80 | 81 | default_config :synced_folders, [] 82 | 83 | default_config :env, [] 84 | 85 | default_config :use_cached_chef_client, false 86 | 87 | default_config :vagrant_binary, "vagrant" 88 | 89 | default_config :vagrantfile_erb, 90 | File.join(File.dirname(__FILE__), "../../../templates/Vagrantfile.erb") 91 | expand_path_for :vagrantfile_erb 92 | 93 | default_config :vagrantfiles, [] 94 | expand_path_for :vagrantfiles 95 | 96 | default_config(:vm_hostname) do |driver| 97 | driver.windows_os? ? nil : "#{driver.instance.name}.vagrantup.com" 98 | end 99 | 100 | default_config(:cache_directory) do |driver| 101 | driver.windows_os? ? "/omnibus/cache" : "/tmp/omnibus/cache" 102 | end 103 | 104 | # for use with vagrant on WSL 105 | user_home = ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH"].nil? ? "~" : ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH"] 106 | 107 | default_config :kitchen_cache_directory, 108 | File.expand_path("#{user_home}/.kitchen/cache") 109 | 110 | default_config :cachier, nil 111 | 112 | no_parallel_for :create, :destroy 113 | 114 | # Creates a Vagrant VM instance. 115 | # 116 | # @param state [Hash] mutable instance state 117 | # @raise [ActionFailed] if the action could not be completed 118 | def create(state) 119 | create_vagrantfile 120 | run_pre_create_command 121 | check_box_outdated 122 | run_box_auto_update 123 | run_box_auto_prune 124 | run_vagrant_up 125 | update_state(state) 126 | instance.transport.connection(state).wait_until_ready 127 | info("Vagrant instance #{instance.to_str} created.") 128 | end 129 | 130 | # @return [String,nil] the Vagrant box for this Instance 131 | def default_box 132 | if bento_box?(instance.platform.name) 133 | "bento/#{instance.platform.name}" 134 | else 135 | instance.platform.name 136 | end 137 | end 138 | 139 | # @return [String,nil] the Vagrant box URL for this Instance 140 | def default_box_url 141 | nil 142 | end 143 | 144 | # Destroys an instance. 145 | # 146 | # @param state [Hash] mutable instance state 147 | # @raise [ActionFailed] if the action could not be completed 148 | def destroy(state) 149 | return if state[:hostname].nil? 150 | 151 | create_vagrantfile 152 | @vagrantfile_created = false 153 | instance.transport.connection(state).close 154 | run("#{config[:vagrant_binary]} destroy -f") 155 | FileUtils.rm_rf(vagrant_root) 156 | info("Vagrant instance #{instance.to_str} destroyed.") 157 | state.delete(:hostname) 158 | end 159 | 160 | def package(state) 161 | if state[:hostname].nil? 162 | raise UserError, "Vagrant instance not created!" 163 | end 164 | 165 | unless config[:ssh] && config[:ssh][:insert_key] == false 166 | m = "Disable vagrant ssh key replacement to preserve the default key!" 167 | warn(m) 168 | end 169 | instance.transport.connection(state).close 170 | box_name = File.join(Dir.pwd, instance.name + ".box") 171 | run("#{config[:vagrant_binary]} package --output #{box_name}") 172 | destroy(state) 173 | end 174 | 175 | # A lifecycle method that should be invoked when the object is about 176 | # ready to be used. A reference to an Instance is required as 177 | # configuration dependant data may be access through an Instance. This 178 | # also acts as a hook point where the object may wish to perform other 179 | # last minute checks, validations, or configuration expansions. 180 | # 181 | # @param instance [Instance] an associated instance 182 | # @return [self] itself, for use in chaining 183 | # @raise [ClientError] if instance parameter is nil 184 | def finalize_config!(instance) 185 | super 186 | finalize_vm_hostname! 187 | finalize_box_auto_update! 188 | finalize_box_auto_prune! 189 | finalize_pre_create_command! 190 | finalize_synced_folders! 191 | finalize_ca_cert! 192 | finalize_network! 193 | self 194 | end 195 | 196 | # Performs whatever tests that may be required to ensure that this driver 197 | # will be able to function in the current environment. This may involve 198 | # checking for the presence of certain directories, software installed, 199 | # etc. 200 | # 201 | # @raise [UserError] if the driver will not be able to perform or if a 202 | # documented dependency is missing from the system 203 | def verify_dependencies 204 | super 205 | if Gem::Version.new(vagrant_version) < Gem::Version.new(MIN_VER.dup) 206 | raise UserError, "Detected an old version of Vagrant " \ 207 | "(#{vagrant_version})." \ 208 | " Please upgrade to version #{MIN_VER} or higher from #{WEBSITE}." 209 | end 210 | end 211 | 212 | # @return [TrueClass,FalseClass] whether or not the transport's name 213 | # implies a WinRM-based transport 214 | # @api private 215 | def winrm_transport? 216 | instance.transport.name.downcase =~ /win_?rm/ 217 | end 218 | 219 | # Setting up the `cache_directory` to store omnibus packages in cache 220 | # and share a local folder to that directory so that we don't pull them 221 | # down every single time 222 | def cache_directory 223 | if enable_cache? 224 | config[:cache_directory] 225 | else 226 | false 227 | end 228 | end 229 | 230 | protected 231 | 232 | WEBSITE = "https://developer.hashicorp.com/vagrant/install".freeze 233 | MIN_VER = "2.4.0".freeze 234 | 235 | class << self 236 | # @return [String] the version of Vagrant installed on the workstation 237 | # @api private 238 | attr_accessor :vagrant_version 239 | end 240 | 241 | # Retuns whether or not a platform name could have a correcponding Bento 242 | # box produced by the Bento project. 243 | # (https://github.com/chef/bento). 244 | # 245 | # @return [TrueClass,FalseClass] whether or not the name could be a Bento 246 | # box 247 | # @api private 248 | def bento_box?(name) 249 | name =~ /^(centos|debian|fedora|freebsd|opensuse|ubuntu|oracle|oraclelinux|hardenedbsd|amazonlinux|almalinux|rockylinux|springdalelinux)-/ 250 | end 251 | 252 | # Returns whether or not the we expect the box to work with shared folders 253 | # by matching against a whitelist of bento boxes 254 | # @return [TrueClass,FalseClass] whether or not the box shoud work with 255 | # shared folders 256 | # @api private 257 | def safe_share?(box) 258 | return false if /(hyperv|libvirt|qemu|utm)/.match?(config[:provider]) 259 | 260 | box =~ %r{^bento/(centos|debian|fedora|opensuse|ubuntu|oracle|oraclelinux|amazonlinux|almalinux|rockylinux|springdalelinux)-} 261 | end 262 | 263 | # Return true if we found the criteria to enable the cache_directory 264 | # functionality 265 | def enable_cache? 266 | return false unless config[:cache_directory] 267 | return true if safe_share?(config[:box]) 268 | return true if config[:use_cached_chef_client] 269 | 270 | # Otherwise 271 | false 272 | end 273 | 274 | # Renders and writes out a Vagrantfile dedicated to this instance. 275 | # 276 | # @api private 277 | def create_vagrantfile 278 | return if @vagrantfile_created 279 | 280 | vagrantfile = File.join(vagrant_root, "Vagrantfile") 281 | debug("Creating Vagrantfile for #{instance.to_str} (#{vagrantfile})") 282 | FileUtils.mkdir_p(vagrant_root) 283 | File.open(vagrantfile, "wb") { |f| f.write(render_template) } 284 | debug_vagrantfile(vagrantfile) 285 | @vagrantfile_created = true 286 | end 287 | 288 | # Logs the Vagrantfile's contents to the debug log level. 289 | # 290 | # @param vagrantfile [String] path to the Vagrantfile 291 | # @api private 292 | def debug_vagrantfile(vagrantfile) 293 | return unless logger.debug? 294 | 295 | debug("------------") 296 | IO.read(vagrantfile).each_line { |l| debug("#{l.chomp}") } 297 | debug("------------") 298 | end 299 | 300 | # Setup path for CA cert 301 | # 302 | # @api private 303 | def finalize_ca_cert! 304 | unless config[:box_download_ca_cert].nil? 305 | config[:box_download_ca_cert] = File.expand_path( 306 | config[:box_download_ca_cert], config[:kitchen_root] 307 | ) 308 | end 309 | end 310 | 311 | # Create vagrant command to update box to the latest version 312 | def finalize_box_auto_update! 313 | return if config[:box_auto_update].nil? 314 | 315 | cmd = "#{config[:vagrant_binary]} box update --box #{config[:box]}" 316 | cmd += " --architecture #{config[:box_arch]}" if config[:box_arch] 317 | cmd += " --provider #{config[:provider]}" if config[:provider] 318 | cmd += " --insecure" if config[:box_download_insecure] 319 | config[:box_auto_update] = cmd 320 | end 321 | 322 | # Create vagrant command to remove older versions of the box 323 | def finalize_box_auto_prune! 324 | return if config[:box_auto_prune].nil? 325 | 326 | cmd = "#{config[:vagrant_binary]} box prune --force --keep-active-boxes --name #{config[:box]}" 327 | cmd += " --provider #{config[:provider]}" if config[:provider] 328 | config[:box_auto_prune] = cmd 329 | end 330 | 331 | # Replaces any `{{vagrant_root}}` tokens in the pre create command. 332 | # 333 | # @api private 334 | def finalize_pre_create_command! 335 | return if config[:pre_create_command].nil? 336 | 337 | config[:pre_create_command] = config[:pre_create_command] 338 | .gsub("{{vagrant_root}}", vagrant_root) 339 | end 340 | 341 | # Formats synced folder options for use in the Vagrantfile. 342 | # Accepts either a Hash (converts to Ruby hash syntax) or a String (returns as-is). 343 | # Supports SMB options like smb_username, smb_password, etc. 344 | # 345 | # @param options [Hash, String, nil] synced folder options 346 | # @return [String] formatted options string for Vagrantfile 347 | # @api private 348 | def format_synced_folder_options(options) 349 | return "nil" if options.nil? 350 | return options if options.is_a?(String) 351 | 352 | # Convert Hash to Ruby hash literal syntax 353 | if options.is_a?(Hash) 354 | options.map { |k, v| "#{k}: #{v.inspect}" }.join(", ") 355 | else 356 | options.to_s 357 | end 358 | end 359 | 360 | # Replaces an `%{instance_name}` tokens in the synced folder items. 361 | # 362 | # @api private 363 | def finalize_synced_folders! 364 | config[:synced_folders] = config[:synced_folders] 365 | .map do |source, destination, options| 366 | [ 367 | File.expand_path( 368 | source.gsub("%{instance_name}", instance.name), 369 | config[:kitchen_root] 370 | ), 371 | destination.gsub("%{instance_name}", instance.name), 372 | format_synced_folder_options(options), 373 | ] 374 | end 375 | add_extra_synced_folders! 376 | end 377 | 378 | # We would like to sync a local folder to the instance so we can 379 | # take advantage of the packages that we might have in cache, 380 | # therefore we wont download a package we already have 381 | def add_extra_synced_folders! 382 | if cache_directory 383 | FileUtils.mkdir_p(local_kitchen_cache) 384 | config[:synced_folders].push([ 385 | local_kitchen_cache, 386 | cache_directory, 387 | "create: true", 388 | ]) 389 | end 390 | end 391 | 392 | # Truncates the length of `:vm_hostname` to 12 characters for 393 | # Windows-based operating systems. 394 | # 395 | # @api private 396 | def finalize_vm_hostname! 397 | string = config[:vm_hostname] 398 | 399 | if windows_os? && string.is_a?(String) && string.size > 15 400 | config[:vm_hostname] = "#{string[0...12]}-#{string[-1]}" 401 | end 402 | end 403 | 404 | # If Hyper-V and no network configuration 405 | # check KITCHEN_HYPERV_SWITCH and fallback to helper method 406 | # to select the best switch 407 | # @api private 408 | def finalize_network! 409 | if config[:provider] == "hyperv" && config[:network].empty? 410 | config[:network].push([ 411 | "public_network", 412 | "bridge: \"#{hyperv_switch}\"", 413 | ]) 414 | end 415 | end 416 | 417 | # Renders the Vagrantfile ERb template. 418 | # 419 | # @return [String] the contents for a Vagrantfile 420 | # @raise [ActionFailed] if the Vagrantfile template was not found 421 | # @api private 422 | def render_template 423 | template = File.expand_path( 424 | config[:vagrantfile_erb], config[:kitchen_root] 425 | ) 426 | 427 | if File.exist?(template) 428 | ERB.new(IO.read(template)).result(binding).gsub(/^\s*$\n/, "") 429 | else 430 | raise ActionFailed, "Could not find Vagrantfile template #{template}" 431 | end 432 | end 433 | 434 | # Convenience method to run a command locally. 435 | # 436 | # @param cmd [String] command to run locally 437 | # @param options [Hash] options hash 438 | # @see Kitchen::ShellOut.run_command 439 | # @api private 440 | def run(cmd, options = {}) 441 | cmd = "echo #{cmd}" if config[:dry_run] 442 | run_command(cmd, { cwd: vagrant_root }.merge(options)) 443 | end 444 | 445 | # Delegates to Kitchen::ShellOut.run_command, overriding some default 446 | # options: 447 | # 448 | # * `:use_sudo` defaults to the value of `config[:use_sudo]` in the 449 | # Driver object 450 | # * `:log_subject` defaults to a String representation of the Driver's 451 | # class name 452 | # 453 | # Since vagrant does not support being run through bundler, we escape 454 | # any bundler environment should we detect one. Otherwise, subcommands 455 | # will inherit our bundled environment. 456 | # @see https://github.com/test-kitchen/kitchen-vagrant/issues/190 457 | # @see Kitchen::ShellOut#run_command 458 | # rubocop:disable Metrics/CyclomaticComplexity 459 | def run_command(cmd, options = {}) 460 | merged = { 461 | use_sudo: config[:use_sudo], 462 | log_subject: name, 463 | environment: {}, 464 | }.merge(options) 465 | 466 | # Attempt to extract bundler and associated GEM related values. 467 | # TODO: To this accurately, we'd need to create a test-kitchen 468 | # launch wrapper that serializes the existing environment before 469 | # bundler touches it so that we can go back to it. Since that is 470 | # "A Hard Problem"(TM), we simply blow away all known bundler 471 | # related changes. 472 | env = merged[:environment] 473 | %w{BUNDLE_BIN_PATH BUNDLE_GEMFILE GEM_HOME GEM_PATH GEM_ROOT RUBYLIB 474 | RUBYOPT _ORIGINAL_GEM_PATH}.each do |var| 475 | env[var] = nil 476 | end 477 | 478 | # Altering the path seems to break vagrant. When the :environment 479 | # is passed to a windows process with a PATH, Vagrant's batch installer 480 | # (https://github.com/mitchellh/vagrant-installers/blob/master/substrate 481 | # /modules/vagrant_installer/templates/windows_vagrant.bat.erb) 482 | # does not efectively prepend the vagrant ruby path in a persistent 483 | # manner which causes vagrant to use the same ruby as test-kitchen and 484 | # then the environment is essentially corrupted leading to many errors 485 | # and dispair 486 | unless windows_host? 487 | gem_home = ENV["GEM_HOME"] 488 | if gem_home && (env["PATH"] || ENV["PATH"]) 489 | env["PATH"] ||= ENV["PATH"].dup if ENV["PATH"] 490 | gem_bin = File.join(gem_home, "bin") + File::PATH_SEPARATOR 491 | env["PATH"][gem_bin] = "" if env["PATH"].include?(gem_bin) 492 | end 493 | end 494 | 495 | super(cmd, merged) 496 | end 497 | # rubocop:enable Metrics/CyclomaticComplexity 498 | 499 | # Check if a newer version of the vagrant box is available and warn the user 500 | # 501 | # @api private 502 | def check_box_outdated 503 | # Skip if box_auto_update is enabled (they'll get the update anyway) 504 | return if config[:box_auto_update] 505 | 506 | cmd = "#{config[:vagrant_binary]} box outdated --box #{config[:box]}" 507 | cmd += " --provider #{config[:provider]}" if config[:provider] 508 | 509 | begin 510 | output = run_silently(cmd) 511 | warn_if_outdated(output) 512 | rescue Kitchen::ShellOut::ShellCommandFailed => e 513 | # If the box isn't installed yet or there's an error checking, silently continue 514 | # This can happen on first run before the box is downloaded 515 | debug("Unable to check if box is outdated: #{e.message}") 516 | end 517 | end 518 | 519 | # Parse vagrant box outdated output and warn if a new version is available 520 | # 521 | # @param output [String] output from vagrant box outdated command 522 | # @api private 523 | def warn_if_outdated(output) 524 | return unless box_is_outdated?(output) 525 | 526 | current_version = extract_current_version(output) 527 | latest_version = extract_latest_version(output) 528 | 529 | warning_msg = "A new version of the '#{config[:box]}' box is available!" 530 | if current_version && latest_version 531 | warning_msg += " Current: #{current_version}, Latest: #{latest_version}." 532 | end 533 | warning_msg += " Run `vagrant box update --box #{config[:box]}` to update." 534 | 535 | warn(warning_msg) 536 | end 537 | 538 | # Check if the vagrant box outdated output indicates an outdated box 539 | # 540 | # @param output [String] output from vagrant box outdated command 541 | # @return [Boolean] true if box is outdated 542 | # @api private 543 | def box_is_outdated?(output) 544 | # Check for various output patterns indicating an outdated box 545 | # Use include? instead of complex regexes to avoid ReDoS vulnerabilities 546 | output_downcase = output.downcase 547 | output_downcase.include?("is outdated") || 548 | output_downcase.include?("newer version") && output_downcase.include?("available") || 549 | output_downcase.include?("newer version of the box") 550 | end 551 | 552 | # Extract current version from vagrant box outdated output 553 | # 554 | # @param output [String] output from vagrant box outdated command 555 | # @return [String, nil] current version or nil if not found 556 | # @api private 557 | def extract_current_version(output) 558 | match = output.match(/Current:\s+v?(\S+)/i) || 559 | output.match(/currently have version\s+'?v?([^'.\s]+)/i) 560 | match ? match[1] : nil 561 | end 562 | 563 | # Extract latest version from vagrant box outdated output 564 | # 565 | # @param output [String] output from vagrant box outdated command 566 | # @return [String, nil] latest version or nil if not found 567 | # @api private 568 | def extract_latest_version(output) 569 | match = output.match(/Latest:\s+v?(\S+)/i) || 570 | output.match(/latest is version\s+'?v?([^'.\s]+)/i) 571 | match ? match[1] : nil 572 | end 573 | 574 | # Tell vagrant to update vagrant box to latest version 575 | def run_box_auto_update 576 | if config[:box_auto_update] 577 | begin 578 | run(config[:box_auto_update]) 579 | rescue Kitchen::ShellOut::ShellCommandFailed => e 580 | # If the box has never been downloaded, the update command will fail with this message. 581 | # Just ignore it and move on. Re-raise all other errors. 582 | raise e unless e.message.match?(/The box '.*' does not exist/m) 583 | end 584 | end 585 | end 586 | 587 | # Tell vagrant to remove older vagrant boxes 588 | def run_box_auto_prune 589 | if config[:box_auto_prune] 590 | run(config[:box_auto_prune]) 591 | end 592 | end 593 | 594 | # Runs a local command before `vagrant up` has been called. 595 | # 596 | # @api private 597 | def run_pre_create_command 598 | if config[:pre_create_command] 599 | run(config[:pre_create_command], cwd: config[:kitchen_root]) 600 | end 601 | end 602 | 603 | # Runs a local command without streaming the stdout to the logger. 604 | # 605 | # @param cmd [String] command to run locally 606 | # @api private 607 | def run_silently(cmd, options = {}) 608 | merged = { 609 | live_stream: nil, quiet: (logger.debug? ? false : true) 610 | }.merge(options) 611 | run(cmd, merged) 612 | end 613 | 614 | # Runs the `vagrant up` command locally. 615 | # 616 | # @api private 617 | def run_vagrant_up 618 | cmd = "#{config[:vagrant_binary]} up" 619 | cmd += " --no-provision" unless config[:provision] 620 | cmd += " --provider #{config[:provider]}" if config[:provider] 621 | run(cmd) 622 | end 623 | 624 | # Updates any state after creation. 625 | # 626 | # @param state [Hash] mutable instance state 627 | # @api private 628 | def update_state(state) 629 | hash = winrm_transport? ? vagrant_config(:winrm) : vagrant_config(:ssh) 630 | 631 | state[:hostname] = hash["HostName"] 632 | state[:port] = hash["Port"] 633 | state[:username] = hash["User"] 634 | state[:password] = hash["Password"] if hash["Password"] 635 | state[:ssh_key] = hash["IdentityFile"] if hash["IdentityFile"] 636 | state[:proxy_command] = hash["ProxyCommand"] if hash["ProxyCommand"] 637 | state[:rdp_port] = hash["RDPPort"] if hash["RDPPort"] 638 | end 639 | 640 | # @return [String] full absolute path to the kitchen cache directory 641 | # @api private 642 | def local_kitchen_cache 643 | @local_kitchen_cache ||= config[:kitchen_cache_directory] 644 | end 645 | 646 | # @return [String] full local path to the directory containing the 647 | # instance's Vagrantfile 648 | # @api private 649 | def vagrant_root 650 | if !@vagrant_root && !instance.nil? 651 | @vagrant_root = File.join( 652 | config[:kitchen_root], %w{.kitchen kitchen-vagrant}, 653 | "#{instance.name}" 654 | ) 655 | end 656 | @vagrant_root 657 | end 658 | 659 | # @return [true,false] whether or not we're running in WSL 660 | # @api private 661 | def wsl? 662 | # Check for WSL via environment variables 663 | return true if ENV["WSL_DISTRO_NAME"] 664 | return true if ENV["VAGRANT_WSL_ENABLE_WINDOWS_ACCESS"] 665 | 666 | # Check for WSL via /proc/version 667 | if File.exist?("/proc/version") 668 | version_content = File.read("/proc/version") 669 | return true if version_content.match?(/microsoft|wsl/i) 670 | end 671 | 672 | false 673 | rescue 674 | false 675 | end 676 | 677 | # Converts a Windows path to a WSL path 678 | # @param path [String] Windows path (e.g., "C:/Users/...") 679 | # @return [String] WSL path (e.g., "/mnt/c/users/...") 680 | # @api private 681 | def windows_to_wsl_path(path) 682 | # Only convert if it looks like a Windows path 683 | if path.match?(%r{^[A-Za-z]:/}) 684 | # Convert C:/path to /mnt/c/path 685 | path.gsub(/^([A-Za-z]):/, '/mnt/\1').downcase 686 | else 687 | path 688 | end 689 | end 690 | 691 | # @param type [Symbol] either `:ssh` or `:winrm` 692 | # @return [Hash] key/value pairs resulting from parsing a 693 | # `vagrant ssh-config` or `vagrant winrm-config` local command 694 | # invocation 695 | # @api private 696 | def vagrant_config(type) 697 | lines = run_silently("#{config[:vagrant_binary]} #{type}-config") 698 | .split("\n").map do |line| 699 | tokens = line.strip.partition(" ") 700 | value = tokens.last.delete('"') 701 | # Convert Windows paths to WSL paths when running in WSL 702 | value = windows_to_wsl_path(value) if wsl? && tokens.first == "IdentityFile" 703 | [tokens.first, value] 704 | end 705 | Hash[lines] 706 | end 707 | 708 | # @return [String] version of Vagrant 709 | # @raise [UserError] if the `vagrant` command can not be found locally 710 | # @api private 711 | def vagrant_version 712 | self.class.vagrant_version ||= run_silently( 713 | "#{config[:vagrant_binary]} --version", cwd: Dir.pwd 714 | ) 715 | .chomp.split(" ").last 716 | rescue Errno::ENOENT 717 | raise UserError, "Vagrant #{MIN_VER} or higher is not installed." \ 718 | " Please download a package from #{WEBSITE}." 719 | end 720 | 721 | # @return [true,false] whether or not the host is windows 722 | # 723 | # @api private 724 | def windows_host? 725 | RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ 726 | end 727 | end 728 | end 729 | end 730 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [2.2.0](https://github.com/test-kitchen/kitchen-vagrant/compare/v2.1.3...v2.2.0) (2025-11-09) 4 | 5 | 6 | ### Features 7 | 8 | * Warn users when new Vagrant box version is available ([#517](https://github.com/test-kitchen/kitchen-vagrant/issues/517)) ([8c05a0e](https://github.com/test-kitchen/kitchen-vagrant/commit/8c05a0ebd35b8570ce25e9578804c99ea14dd4dc)) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * SSH key path resolution in WSL2 environments ([#516](https://github.com/test-kitchen/kitchen-vagrant/issues/516)) ([69b942c](https://github.com/test-kitchen/kitchen-vagrant/commit/69b942c2579e8996f8faee143e84e82c2bed0786)) 14 | 15 | ## [2.1.3](https://github.com/test-kitchen/kitchen-vagrant/compare/v2.1.2...v2.1.3) (2025-09-29) 16 | 17 | 18 | ### Bug Fixes 19 | 20 | * add oracle linux to bento box list ([#513](https://github.com/test-kitchen/kitchen-vagrant/issues/513)) ([9b466ae](https://github.com/test-kitchen/kitchen-vagrant/commit/9b466ae759c5932b6515d2632adea59ba7ee6521)) 21 | 22 | ## [2.1.2](https://github.com/test-kitchen/kitchen-vagrant/compare/v2.1.1...v2.1.2) (2025-09-22) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * update test-kitchen dependency to support test-kitchen and chef-test-kitchen-enterprise ([#502](https://github.com/test-kitchen/kitchen-vagrant/issues/502)) ([55be0e9](https://github.com/test-kitchen/kitchen-vagrant/commit/55be0e90f6d53d13a5c401726e9f61c734372af7)) 28 | 29 | ## [2.1.1](https://github.com/test-kitchen/kitchen-vagrant/compare/v2.1.0...v2.1.1) (2025-09-22) 30 | 31 | 32 | ### Bug Fixes 33 | 34 | * update hash syntax for Ruby 3.4 compatibility ([#508](https://github.com/test-kitchen/kitchen-vagrant/issues/508)) ([091cdb7](https://github.com/test-kitchen/kitchen-vagrant/commit/091cdb766d1b0ac89d5d5460d05452b46d383e38)) 35 | 36 | ## [2.1.0](https://github.com/test-kitchen/kitchen-vagrant/compare/v2.0.2...v2.1.0) (2025-09-02) 37 | 38 | 39 | ### Features 40 | 41 | * support setting extra data for VirtualBox ([#493](https://github.com/test-kitchen/kitchen-vagrant/issues/493)) ([46c9606](https://github.com/test-kitchen/kitchen-vagrant/commit/46c9606a8b08d738953e1e6c08bca848ad2b1e04)) 42 | 43 | ## [2.0.2](https://github.com/test-kitchen/kitchen-vagrant/compare/v2.0.1...v2.0.2) (2025-09-02) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * Add utm provider to list of not safe providers for omnibus cache ([#505](https://github.com/test-kitchen/kitchen-vagrant/issues/505)) ([b8b3c44](https://github.com/test-kitchen/kitchen-vagrant/commit/b8b3c44de7e9b803c0edc7fc26832d4d048f115e)) 49 | 50 | ## [1.14.3](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.14.2...v1.14.3) (2024-06-19) 51 | 52 | 53 | ### Bug Fixes 54 | 55 | * update release please configs ([#498](https://github.com/test-kitchen/kitchen-vagrant/issues/498)) ([823b495](https://github.com/test-kitchen/kitchen-vagrant/commit/823b49527ee8ddb69cdd52ca77a4cb3dc7946382)) 56 | 57 | ## [2.0.0](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.14.2...v2.0.0) (2024-02-14) 58 | 59 | - Require Vagrant 2.4 or later 60 | - Drop support for EOL Ruby 2.7 release 61 | - Add a new `box_arch` configuration option for defining the architecture to use 62 | - Eliminate the need for the vagrant-winrm plugin on Windows boxes 63 | 64 | ## [1.14.2](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.14.1...v1.14.2) (2023-11-27) 65 | 66 | ### Bug Fixes 67 | 68 | * Add New lint and publish workflows ([#488](https://github.com/test-kitchen/kitchen-vagrant/issues/488)) ([744fdc9](https://github.com/test-kitchen/kitchen-vagrant/commit/744fdc93d006ad32f80994b371c198e5a2a9deb6)) 69 | 70 | ## [1.14.1](https://github.com/test-kitchen/kitchen-vagrant/tree/1.14.1) (2023-02-21) 71 | 72 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.14.0...v1.14.1) 73 | 74 | - Fix failures auto pruning box images that are in use elsewhere [#485](https://github.com/test-kitchen/kitchen-vagrant/pull/485) ([@Stromweld](https://github.com/Stromweld)) 75 | 76 | ## [1.14.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.14.0) (2023-02-09) 77 | 78 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.13.0...v1.14.0) 79 | 80 | - Add arm64 to bento box name [#483](https://github.com/test-kitchen/kitchen-vagrant/pull/483) ([@Stromweld](https://github.com/Stromweld)) 81 | 82 | ## [1.13.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.13.0) (2022-12-13) 83 | 84 | - Drop support for EOL Ruby 2.6 ([@tas50](https://github.com/tas50)) 85 | - Avoid failures when the system has the same boxes for multiple providers on disk [#481](https://github.com/test-kitchen/kitchen-vagrant/pull/481) ([@Stromweld](https://github.com/Stromweld)) 86 | 87 | ## [1.12.1](https://github.com/test-kitchen/kitchen-vagrant/tree/1.12.1) (2022-07-11) 88 | 89 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.12.0...v1.12.1) 90 | 91 | - Fix for Ruby 3.0 compatibility when specifying Vagrantfile network configuration [#477](https://github.com/test-kitchen/kitchen-vagrant/pull/477) ([@PowerKiki](https://github.com/PowerKiKi)) 92 | 93 | ## [1.12.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.12.0) (2022-06-09) 94 | 95 | - Support for Ruby 3.1 96 | - Using chefstyle linting 97 | 98 | ## [1.11.0] 99 | 100 | - Adds `use_cached_chef_client` option to enable using the cached Chef Infra Client installers on non-Bento Vagrant boxes that have `Guest Additions` installed. 101 | 102 | ## [1.10.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.10.0) (2021-08-25) 103 | 104 | - Only create the virtual drive if it doesn't already exist locally 105 | 106 | ## [1.9.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.9.0) (2021-07-02) 107 | 108 | - Support Test Kitchen 3.0 109 | 110 | ## [1.8.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.8.0) (2021-02-02) 111 | 112 | - Require Ruby 2.5 or later (2.3/2.4 are EOL) ([@tas50](https://github.com/tas50)) 113 | - Add support for our new Bento `almalinux` boxes [#444](https://github.com/test-kitchen/kitchen-vagrant/pull/444) ([@tas50](https://github.com/tas50)) 114 | - Switch all testing to GitHub Actions [#430](https://github.com/test-kitchen/kitchen-vagrant/pull/430) ([@tas50](https://github.com/tas50)) 115 | - Remove github changelog generator & countloc development dependencies [#431](https://github.com/test-kitchen/kitchen-vagrant/pull/431) ([@tas50](https://github.com/tas50)) 116 | - Remove the Guardfile [#432](https://github.com/test-kitchen/kitchen-vagrant/pull/432) ([@tas50](https://github.com/tas50)) 117 | - Add Ruby 3.0 testing [#440](https://github.com/test-kitchen/kitchen-vagrant/pull/440) ([@tas50](https://github.com/tas50)) 118 | - Remove guard dev deps / move dev deps to the gemfile [#441](https://github.com/test-kitchen/kitchen-vagrant/pull/441) ([@tas50](https://github.com/tas50)) 119 | - Add a Code of Conduct file + misc testing updates [#442](https://github.com/test-kitchen/kitchen-vagrant/pull/442) ([@tas50](https://github.com/tas50)) 120 | 121 | ## [1.7.2](https://github.com/test-kitchen/kitchen-vagrant/tree/1.7.2) (2020-11-10) 122 | 123 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.7.1...v1.7.2) 124 | 125 | - Ignore error if box not found when updating [#428](https://github.com/test-kitchen/kitchen-vagrant/pull/428) ([@clintoncwolfe](https://github.com/clintoncwolfe)) 126 | 127 | ## [1.7.1](https://github.com/test-kitchen/kitchen-vagrant/tree/1.7.1) (2020-11-03) 128 | 129 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.7.0...v1.7.1) 130 | 131 | - Don't fail if active boxes can't be pruned [#427](https://github.com/test-kitchen/kitchen-vagrant/pull/427) ([@tas50](https://github.com/tas50)) 132 | - Remove redundant encoding comments [#426](https://github.com/test-kitchen/kitchen-vagrant/pull/426) ([@tas50](https://github.com/tas50)) 133 | - Use match? when we don't need the match data [#424](https://github.com/test-kitchen/kitchen-vagrant/pull/424) ([@tas50](https://github.com/tas50)) 134 | - Optimize our requires to improve performance [#423](https://github.com/test-kitchen/kitchen-vagrant/pull/423) ([@tas50](https://github.com/tas50)) 135 | 136 | ## [1.7.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.7.0) (2020-07-04) 137 | 138 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.6.1...v1.7.0) 139 | 140 | - Add new `box_auto_update` and `box_auto_prune` options to pull newer Vagrant base boxes [#421](https://github.com/test-kitchen/kitchen-vagrant/pull/421) ([@Stromweld](https://github.com/Stromweld)) 141 | 142 | ## [1.6.1](https://github.com/test-kitchen/kitchen-vagrant/tree/1.6.1) (2020-01-14) 143 | 144 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.6.0...v1.6.1) 145 | 146 | - \[README\] fix openstack link [#409](https://github.com/test-kitchen/kitchen-vagrant/pull/409) ([@arthurlogilab](https://github.com/arthurlogilab)) 147 | - Use require_relative instead of require [#414](https://github.com/test-kitchen/kitchen-vagrant/pull/414) ([@tas50](https://github.com/tas50)) 148 | 149 | ## [1.6.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.6.0) (2019-08-05) 150 | 151 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.5.2...v1.6.0) 152 | 153 | - Don't fail when instance names become too long for Hyper-V [#404](https://github.com/test-kitchen/kitchen-vagrant/pull/404) ([@Xorima](https://github.com/Xorima)) 154 | - Require Ruby 2.3 or later (Ruby < 2.3 are no longer supported Ruby releases) 155 | 156 | ## [1.5.2](https://github.com/test-kitchen/kitchen-vagrant/tree/1.5.2) (2019-05-02) 157 | 158 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.5.1...v1.5.2) 159 | 160 | - Restores vm name uniqueness [#399](https://github.com/test-kitchen/kitchen-vagrant/pull/399) ([@fretb](https://github.com/fretb)) 161 | 162 | ## [1.5.1](https://github.com/test-kitchen/kitchen-vagrant/tree/1.5.1) (2019-03-19) 163 | 164 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.5.0...v1.5.1) 165 | 166 | - Loosen the Test Kitchen dep to allow 2.0 [#398](https://github.com/test-kitchen/kitchen-vagrant/pull/398) ([@tas50](https://github.com/tas50)) 167 | 168 | ## [1.5.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.5.0) (2019-03-14) 169 | 170 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.4.0...v1.5.0) 171 | 172 | - Support using bento/amazonlinux-2 when specifying just amazonlinux-2 platform [#397](https://github.com/test-kitchen/kitchen-vagrant/pull/397) ([@tas50](https://github.com/tas50)) 173 | 174 | ## [1.4.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.4.0) (2019-01-28) 175 | 176 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.3.6...v1.4.0) 177 | 178 | - Add usage of vm_hostname to Readme.md [#386](https://github.com/test-kitchen/kitchen-vagrant/pull/386) ([@f9n](https://github.com/f9n)) 179 | - Disable audio in virtualbox by default to prevent interupting host Bluetooth audio [#392](https://github.com/test-kitchen/kitchen-vagrant/pull/392) ([@robbkidd](https://github.com/robbkidd)) 180 | - Added WSL support [#384](https://github.com/test-kitchen/kitchen-vagrant/pull/384) ([@BCarley](https://github.com/BCarley)) 181 | 182 | ## [1.3.6](https://github.com/test-kitchen/kitchen-vagrant/tree/1.3.6) (2018-10-26) 183 | 184 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.3.5...v1.3.6) 185 | 186 | **Merged pull requests:** 187 | 188 | - Updating for new Chefstyle rules [\#382](https://github.com/test-kitchen/kitchen-vagrant/pull/382) ([tyler-ball](https://github.com/tyler-ball)) 189 | - Newest vagrant no long requires vagrant-winrm plugin [\#379](https://github.com/test-kitchen/kitchen-vagrant/pull/379) ([tyler-ball](https://github.com/tyler-ball)) 190 | 191 | ## [v1.3.5](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.3.5) (2018-10-23) 192 | 193 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.3.4...v1.3.5) 194 | 195 | **Closed issues:** 196 | 197 | - vagrant winrm-config doesn't detect auto-assigned forwarding for RDP [\#224](https://github.com/test-kitchen/kitchen-vagrant/issues/224) 198 | 199 | **Merged pull requests:** 200 | 201 | - Slim the size of the gem by removing spec files [\#377](https://github.com/test-kitchen/kitchen-vagrant/pull/377) ([tas50](https://github.com/tas50)) 202 | 203 | ## [v1.3.4](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.3.4) (2018-09-15) 204 | 205 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.3.3...v1.3.4) 206 | 207 | **Merged pull requests:** 208 | 209 | - Fix \#371, change require =\> load [\#373](https://github.com/test-kitchen/kitchen-vagrant/pull/373) ([cheeseplus](https://github.com/cheeseplus)) 210 | - Vagrantfile Template: Hyper-v Differencing\_disk deprecation [\#370](https://github.com/test-kitchen/kitchen-vagrant/pull/370) ([cocazoulou](https://github.com/cocazoulou)) 211 | 212 | ## [v1.3.3](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.3.3) (2018-08-13) 213 | 214 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.3.2...v1.3.3) 215 | 216 | **Closed issues:** 217 | 218 | - Hard to identify running VM instance from Hyper-V Manager or PowerShell [\#367](https://github.com/test-kitchen/kitchen-vagrant/issues/367) 219 | - \[Feature\] Add support for vm.name for virtualbox [\#365](https://github.com/test-kitchen/kitchen-vagrant/issues/365) 220 | 221 | **Merged pull requests:** 222 | 223 | - Adding a per-instance generated vmname for Hyper-V [\#368](https://github.com/test-kitchen/kitchen-vagrant/pull/368) ([stuartpreston](https://github.com/stuartpreston)) 224 | - Fix \#365 - add name for virtualbox instances [\#366](https://github.com/test-kitchen/kitchen-vagrant/pull/366) ([cheeseplus](https://github.com/cheeseplus)) 225 | - Adding the lifecycle hooks stub to fix tests [\#364](https://github.com/test-kitchen/kitchen-vagrant/pull/364) ([cheeseplus](https://github.com/cheeseplus)) 226 | - Add an example for vagrantfile\_erb [\#363](https://github.com/test-kitchen/kitchen-vagrant/pull/363) ([jkugler](https://github.com/jkugler)) 227 | - Move github changelog generator to the gemfile and skip install in testing [\#362](https://github.com/test-kitchen/kitchen-vagrant/pull/362) ([tas50](https://github.com/tas50)) 228 | - Fix disk examples [\#360](https://github.com/test-kitchen/kitchen-vagrant/pull/360) ([espoelstra](https://github.com/espoelstra)) 229 | 230 | ## [v1.3.2](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.3.2) (2018-04-23) 231 | 232 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.3.1...v1.3.2) 233 | 234 | **Merged pull requests:** 235 | 236 | - Fixing \#349 - allow bento/hardenedbsd [\#355](https://github.com/test-kitchen/kitchen-vagrant/pull/355) ([cheeseplus](https://github.com/cheeseplus)) 237 | - Updating travis config [\#354](https://github.com/test-kitchen/kitchen-vagrant/pull/354) ([cheeseplus](https://github.com/cheeseplus)) 238 | - Hyper-V: Ensure default switch name is always wrapped in quotes [\#345](https://github.com/test-kitchen/kitchen-vagrant/pull/345) ([stuartpreston](https://github.com/stuartpreston)) 239 | 240 | ## [v1.3.1](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.3.1) (2018-02-20) 241 | 242 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.3.0...v1.3.1) 243 | 244 | **Merged pull requests:** 245 | 246 | - Adding support for HyperV Differencing\_disk [\#342](https://github.com/test-kitchen/kitchen-vagrant/pull/342) ([cocazoulou](https://github.com/cocazoulou)) 247 | 248 | ## [1.3.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.3.0) (2018-01-17) 249 | 250 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.2.2...1.3.0) 251 | 252 | - Improve Hyper-V defaults and support [\#338](https://github.com/test-kitchen/kitchen-vagrant/pull/338) 253 | 254 | ## [1.2.2](https://github.com/test-kitchen/kitchen-vagrant/tree/1.2.2) (2017-11-07) 255 | 256 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.2.1...1.2.2) 257 | 258 | - For WinRM options, only treat strings as strings. [\#330](https://github.com/test-kitchen/kitchen-vagrant/pull/330) 259 | 260 | ## [1.2.1](https://github.com/test-kitchen/kitchen-vagrant/tree/1.2.1) (2017-08-22) 261 | 262 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.2.0...1.2.1) 263 | 264 | - Revert parallel virtualbox [\#325](https://github.com/test-kitchen/kitchen-vagrant/pull/325) 265 | - Shorten directory name for `vagrant_root` [\#323](https://github.com/test-kitchen/kitchen-vagrant/pull/323) 266 | 267 | ## [1.2.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.2.0) (2017-08-11) 268 | 269 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.1.1...1.2.0) 270 | 271 | **Implemented enhancements:** 272 | 273 | - Support to create/attach multiple additional VirtualBox disks [\#312](https://github.com/test-kitchen/kitchen-vagrant/pull/312) ([stissot](https://github.com/stissot)) 274 | - Parallel virtualbox [\#202](https://github.com/test-kitchen/kitchen-vagrant/pull/202) ([rveznaver](https://github.com/rveznaver)) 275 | 276 | ## [v1.1.1](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.1.1) (2017-07-26) 277 | 278 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.1.0...v1.1.1) 279 | 280 | ### Fixed Bugs 281 | 282 | - Fix detection of vagrant-winrm plugin. [\#309](https://github.com/test-kitchen/kitchen-vagrant/pull/309) ([silverl](https://github.com/silverl)) 283 | - Fix bug in Vagrantfile template related to WinRM options. [\#306](https://github.com/test-kitchen/kitchen-vagrant/pull/306) ([aleksey-hariton](https://github.com/aleksey-hariton)) 284 | - Disable caching, even for bento boxes. [\#313](https://github.com/test-kitchen/kitchen-vagrant/pull/313) ([robbkidd](https://github.com/robbkidd)) 285 | 286 | ## [v1.1.0](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.1.0) (2017-03-31) 287 | 288 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.0.2...v1.1.0) 289 | 290 | **New Features:** 291 | 292 | - Make kitchen package work [\#275](https://github.com/test-kitchen/kitchen-vagrant/pull/275) ([ccope](https://github.com/ccope)) 293 | 294 | **Improvements:** 295 | 296 | - Only enable the cache when using known bento boxes. Fix \#296 [\#303](https://github.com/test-kitchen/kitchen-vagrant/pull/303) ([cheeseplus](https://github.com/cheeseplus)) 297 | - README: add info about cache\_directory disabling [\#299](https://github.com/test-kitchen/kitchen-vagrant/pull/299) ([jugatsu](https://github.com/jugatsu)) 298 | - Add ability to override Kitchen cache directory [\#292](https://github.com/test-kitchen/kitchen-vagrant/pull/292) ([Jakauppila](https://github.com/Jakauppila)) 299 | - Add support for all misc vagrant providers [\#290](https://github.com/test-kitchen/kitchen-vagrant/pull/290) ([myoung34](https://github.com/myoung34)) 300 | 301 | ## [v1.0.2](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.0.2) (2017-02-13) 302 | 303 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.0.1...v1.0.2) 304 | 305 | **Fixed bugs:** 306 | 307 | - Fixed a bug that can occur when `instance` returns `nil` [\#285](https://github.com/test-kitchen/kitchen-vagrant/pull/285) ([Kuniwak](https://github.com/Kuniwak)) 308 | 309 | ## [v1.0.1](https://github.com/test-kitchen/kitchen-vagrant/tree/v1.0.1) (2017-02-10) 310 | 311 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v1.0.0...v1.0.1) 312 | 313 | **Fixed bugs:** 314 | 315 | - Fixed cache folder disable for FreeBSD and MacOS/OSX [\#281](https://github.com/test-kitchen/kitchen-vagrant/pull/281) ([brentm5](https://github.com/brentm5)) [\#283](https://github.com/test-kitchen/kitchen-vagrant/pull/283) ([cheeseplus](https://github.com/cheeseplus)) 316 | 317 | ## [1.0.0](https://github.com/test-kitchen/kitchen-vagrant/tree/1.0.0) (2017-01-10) 318 | 319 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v0.21.1...v1.0.0) 320 | 321 | **Implemented enhancements:** 322 | 323 | - Add vagrant-cachier support to default Vagrantfile.erb [\#186](https://github.com/test-kitchen/kitchen-vagrant/issues/186) 324 | - Allow customization of cpuidset for VirtualBox VMs [\#175](https://github.com/test-kitchen/kitchen-vagrant/issues/175) 325 | - Add KVM/libvirt storage support to Vagrantfile.erb [\#271](https://github.com/test-kitchen/kitchen-vagrant/pull/271) ([dprts](https://github.com/dprts)) 326 | - Move to chefstyle [\#264](https://github.com/test-kitchen/kitchen-vagrant/pull/264) ([shortdudey123](https://github.com/shortdudey123)) 327 | - Allow multiple "include" statements in LXC configuration [\#230](https://github.com/test-kitchen/kitchen-vagrant/pull/230) ([alexmv](https://github.com/alexmv)) 328 | - Set FQDN to include vagrantup.com again for non-windows operating sys… [\#168](https://github.com/test-kitchen/kitchen-vagrant/pull/168) ([spion06](https://github.com/spion06)) 329 | - Virtualbox storage via createhd and storageattach [\#246](https://github.com/test-kitchen/kitchen-vagrant/pull/246) ([shortdudey123](https://github.com/shortdudey123)) 330 | - Add support for box\_download\_ca\_cert [\#274](https://github.com/test-kitchen/kitchen-vagrant/pull/274) ([cheeseplus](https://github.com/cheeseplus)) 331 | 332 | **Fixed bugs:** 333 | 334 | - Bug in box\_check\_update code [\#237](https://github.com/test-kitchen/kitchen-vagrant/issues/237) 335 | - Fix quoting for cloud providers \(redux \#179\) [\#268](https://github.com/test-kitchen/kitchen-vagrant/pull/268) ([cheeseplus](https://github.com/cheeseplus)) 336 | 337 | ## [0.21.1](https://github.com/test-kitchen/kitchen-vagrant/tree/0.21.1) (2016-12-05) 338 | 339 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v0.21.0...v0.21.1) 340 | 341 | **Implemented enhancements:** 342 | 343 | - add oracle as supported bento-box type [\#258](https://github.com/test-kitchen/kitchen-vagrant/pull/258) ([lamont-granquist](https://github.com/lamont-granquist)) 344 | 345 | **Fixed bugs:** 346 | 347 | - Change default cache dir for Windows [\#259](https://github.com/test-kitchen/kitchen-vagrant/pull/259) ([afiune](https://github.com/afiune)) 348 | - Vagrant requires also to scape slashes [\#253](https://github.com/test-kitchen/kitchen-vagrant/pull/253) ([afiune](https://github.com/afiune)) 349 | - Fix cache directory on windows [\#251](https://github.com/test-kitchen/kitchen-vagrant/pull/251) ([afiune](https://github.com/afiune)) 350 | - Exclude freebsd and ability to disable cache dir [\#262](https://github.com/test-kitchen/kitchen-vagrant/pull/262) ([afiune](https://github.com/afiune)) 351 | - Don't alter the path during the bundler cleanup on windows [\#241](https://github.com/test-kitchen/kitchen-vagrant/pull/241) ([mwrock](https://github.com/mwrock)) 352 | - do not map the extra cache drive on non virtualbox windows [\#255](https://github.com/test-kitchen/kitchen-vagrant/pull/255) ([mwrock](https://github.com/mwrock)) 353 | 354 | ## [0.21.0](https://github.com/test-kitchen/kitchen-vagrant/tree/0.21.0) (2016-11-29) 355 | 356 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v0.20.0...v0.21.0) 357 | 358 | **Fixed bugs:** 359 | 360 | - Generated Vagrantfile has type issues [\#236](https://github.com/test-kitchen/kitchen-vagrant/issues/236) 361 | - Fix ssh boolean values in Vagrantfile template [\#231](https://github.com/test-kitchen/kitchen-vagrant/pull/231) ([zuazo](https://github.com/zuazo)) 362 | 363 | **Merged pull requests:** 364 | 365 | - Add a synced folder to persist chef omnibus packages [\#248](https://github.com/test-kitchen/kitchen-vagrant/pull/248) ([afiune](https://github.com/afiune)) 366 | - Fix generated Vagrantfile type issues [\#243](https://github.com/test-kitchen/kitchen-vagrant/pull/243) ([OBrienCommaJosh](https://github.com/OBrienCommaJosh)) 367 | - Bump travis rubies to the modern age [\#242](https://github.com/test-kitchen/kitchen-vagrant/pull/242) ([mwrock](https://github.com/mwrock)) 368 | - Fix the name of "Parallels Desktop for Mac" [\#233](https://github.com/test-kitchen/kitchen-vagrant/pull/233) ([legal90](https://github.com/legal90)) 369 | - Add support for ovirt3 vagrant provider [\#223](https://github.com/test-kitchen/kitchen-vagrant/pull/223) ([xiboy](https://github.com/xiboy)) 370 | 371 | ## [0.20.0](https://github.com/test-kitchen/kitchen-vagrant/tree/v0.20.0) (2016-04-07) 372 | 373 | [Full Changelog](https://github.com/test-kitchen/kitchen-vagrant/compare/v0.19.0...v0.20.0) 374 | 375 | **Implemented enhancements:** 376 | 377 | - Make Vagrant binary a parameter [\#218](https://github.com/test-kitchen/kitchen-vagrant/issues/218) 378 | - WARN: Child with name 'dna.json' found in multiple directories: /tmp/kitchen/dna.json and /tmp/kitchen/dna.json [\#198](https://github.com/test-kitchen/kitchen-vagrant/issues/198) 379 | - Default bento boxes should be pulled from Atlas [\#193](https://github.com/test-kitchen/kitchen-vagrant/issues/193) 380 | - Easily override instance name [\#169](https://github.com/test-kitchen/kitchen-vagrant/issues/169) 381 | - Easily override instance name [\#169](https://github.com/test-kitchen/kitchen-vagrant/issues/169) 382 | - Make vagrant binary a parameter [\#219](https://github.com/test-kitchen/kitchen-vagrant/pull/219) ([bheuvel](https://github.com/bheuvel)) 383 | - HyperV acts as OpenStack, CloudStack [\#217](https://github.com/test-kitchen/kitchen-vagrant/pull/217) ([bheuvel](https://github.com/bheuvel)) 384 | - Add support for hyperv customize [\#212](https://github.com/test-kitchen/kitchen-vagrant/pull/212) ([giseongeom](https://github.com/giseongeom)) 385 | - Add option for box\_download\_insecure to be passed to Vagrantfile [\#208](https://github.com/test-kitchen/kitchen-vagrant/pull/208) ([drrk](https://github.com/drrk)) 386 | - fix libvirt customize [\#204](https://github.com/test-kitchen/kitchen-vagrant/pull/204) ([akissa](https://github.com/akissa)) 387 | - Add linked\_clone config option [\#203](https://github.com/test-kitchen/kitchen-vagrant/pull/203) ([bborysenko](https://github.com/bborysenko)) 388 | - Use Bento's Atlas boxes by default if detected [\#195](https://github.com/test-kitchen/kitchen-vagrant/pull/195) ([andytson](https://github.com/andytson)) 389 | - Parallels: Use "memory" and "cpus" customization shortcuts [\#194](https://github.com/test-kitchen/kitchen-vagrant/pull/194) ([legal90](https://github.com/legal90)) 390 | - Add support for boot\_timeout driver setting [\#184](https://github.com/test-kitchen/kitchen-vagrant/pull/184) ([gh2k](https://github.com/gh2k)) 391 | - Fixes box check update bug [\#182](https://github.com/test-kitchen/kitchen-vagrant/pull/182) ([roderickrandolph](https://github.com/roderickrandolph)) 392 | - Add cloudstack support [\#167](https://github.com/test-kitchen/kitchen-vagrant/pull/167) ([miguelaferreira](https://github.com/miguelaferreira)) 393 | 394 | **Fixed bugs:** 395 | 396 | - setting box\_check\_update to false does not disable box update checking [\#181](https://github.com/test-kitchen/kitchen-vagrant/issues/181) 397 | 398 | **Merged pull requests:** 399 | 400 | - Updating readme for Parallels [\#221](https://github.com/test-kitchen/kitchen-vagrant/pull/221) ([cheeseplus](https://github.com/cheeseplus)) 401 | - Adding changelog generator [\#220](https://github.com/test-kitchen/kitchen-vagrant/pull/220) ([cheeseplus](https://github.com/cheeseplus)) 402 | - Updating Readme to reflect changes to default boxes [\#215](https://github.com/test-kitchen/kitchen-vagrant/pull/215) ([cheeseplus](https://github.com/cheeseplus)) 403 | - Ruby 1.9.3 is no longer supported [\#209](https://github.com/test-kitchen/kitchen-vagrant/pull/209) ([drrk](https://github.com/drrk)) 404 | 405 | 406 | ## 0.19.0 / 2015-09-18 407 | 408 | ### Bug fixes 409 | 410 | * Pull request [#163][]: Properly quote `config[:ssh]` values. ([@zuazo][]) 411 | * Pull request [#191][], pull request [#197][], issue [#190][]: Escape Bundler environment when shelling out to `vagrant` command. ([@ksubrama][], [@tknerr][]) 412 | 413 | ### New features 414 | 415 | * Pull request 172, issue [#171][]: Add support for OpenStack provider. ([@xmik][]) 416 | 417 | ### Improvements 418 | 419 | * Pull request [#174][]: Correct grammar error in README. ([@albsOps][]) 420 | * Support running unit test suite on Windows ([@ksubrama][]) 421 | 422 | 423 | ## 0.18.0 / 2015-05-07 424 | 425 | ### Bug fixes 426 | 427 | * Pull request [#161][]: Add handling for winrm communicator in username & password handling. ([@atiniir][]) 428 | 429 | ### Improvements 430 | 431 | * Pull request [#166][]: Allow a fuzzier match for known Bento box names. ([@fnichol][]) 432 | 433 | 434 | ## 0.17.0 / 2015-04-28 435 | 436 | (*A selected roll-up of 0.17.0 pre-release changelogs*) 437 | 438 | ### Bug fixes 439 | 440 | * Pull request [#156][]: Use RDPPort value from `vagrant winrm-config` for WinRM Transports. ([@fnichol][]) 441 | 442 | ### New features 443 | 444 | * Pull request [#154][]: Support for WinRM Transport and Windows-based instances. ([@fnichol][]) 445 | 446 | ### Improvements 447 | 448 | * Pull request [#152][]: Translate CPU count for VMWare provider. ([@whiteley][]) 449 | * Pull request [#157][]: Close Transport connection in #destroy. ([@fnichol][]) 450 | * Pull request [#158][]: Add plugin metadata to the Driver. ([@fnichol][]) 451 | 452 | 453 | ## 0.17.0.rc.1 / 2015-03-29 454 | 455 | ### Improvements 456 | 457 | * Pull request [#157][]: Close Transport connection in #destroy. ([@fnichol][]) 458 | * Pull request [#158][]: Add plugin metadata to the Driver. ([@fnichol][]) 459 | 460 | 461 | ## 0.17.0.beta.4 / 2015-03-26 462 | 463 | ### Bug fixes 464 | 465 | * Pull request [#156][]: Use RDPPort value from `vagrant winrm-config` for WinRM Transports. ([@fnichol][]) 466 | 467 | ### Improvements 468 | 469 | * Pull request [#152][]: Translate CPU count for VMWare provider. ([@whiteley][]) 470 | 471 | 472 | ## 0.17.0.beta.3 / 2015-03-25 473 | 474 | ### Bug fixes 475 | 476 | * Pull request [#155][]: Use the vagrant-winrm Vagrant plugin to resolve VM IP address. See PR for details. ([@fnichol][]) 477 | 478 | 479 | ## 0.17.0.beta.2 / 2015-03-25 480 | 481 | * Relax version constraint on Test Kitchen. ([@fnichol][]) 482 | 483 | 484 | ## 0.17.0.beta.1 / 2015-03-24 485 | 486 | * Pull request [#154][]: Support for WinRM Transport and Windows-based instances. ([@fnichol][]) 487 | 488 | 489 | ## 0.16.0 / 2015-03-23 490 | 491 | ### Bug fixes 492 | 493 | * Pull request [#122][], pull request [#151][]: Only set custom `:box` & `:box_url` values for known Bento boxes. ([@ashb][], [@fnichol][]) 494 | 495 | ### New features 496 | 497 | * Pull request [#84][]: Add support for Parallels provider. ([@jhx][]) 498 | * Pull request [#107][]: Add support for libvirt provider. ([@bradleyd][]) 499 | * Pull request [#128][]: Add support for LXC provider. ([@tknerr][]) 500 | * Pull request [#142][]: Add support for managed-servers provider. ([@kbruner][]) 501 | * Add `:gui` configuration attribute to override default GUI mode with VirtualBox and VMware-based providers. ([@fnichol][]) 502 | * Pull request [#137][]: Support SoftLayer `:disk_capacity` configuration. ([@hugespoon][]) 503 | * Pull request [#102][]: Add `:box_version` & `:box_check_update` configuration options to support box versioning. ([@mconigliaro][]) 504 | * Pull request [#129][]: Add `:provision` configuration option. ([@gouketsu][]) 505 | * Pull request [#112][]: Add configuration option for user Vagrantfiles with `:vagrantfiles` configuration option. ([@byggztryng][]) 506 | * Pull request [#95][]: Add SSH ProxyCommand to state if present. ([@bdclark][]) 507 | * Pull request [#121][]: Add `:ssh` configuration hash. ([@Igorshp][]) 508 | * Pull request [#104][]: Add `:communicator` configuration option to support overriding underlying base box's communicator setting. ([@RobertRehberg][]) 509 | * Pull request [#118][]: Vagrant config password (Not Vagrant recommended). ([@philcallister][]) 510 | 511 | ### Improvements 512 | 513 | * Pull request [#148][]: Add full test coverage to the codebase. ([@fnichol][]) 514 | * Pull request [#126][]: Disable vagrant-berkshelf plugin by default (this Driver does not need it and can cause confusing errors). ([@tknerr][]) 515 | * Pull request [#101][]: Qualify VM names with project name. ([@petere][]) 516 | * Pull request [#117][]: Change default hostname to be shorter and friendlier for Windows hosts. ([@Annih][]) 517 | * Pull request [#106][], Use correct URLs to download vagrant in README. ([@alex-slynko-wonga][]) 518 | * Pull request [#146][]: Freshen project quality (TravisCI, Tailor-for-Rubocop, Guard support, etc). ([@fnichol][]) 519 | * Pull request [#147][]: Tidy default configuration attributes. ([@fnichol][]) 520 | * Pull request [#134][]: CHANGELOG Champion, Mr. [@miketheman][]. ([@miketheman][]) 521 | * Pull request [#127][]: README updates. ([@vinyar][], fnichol) 522 | 523 | 524 | ## 0.15.0 / 2014-04-28 525 | 526 | ### New features 527 | 528 | * Support vagrant-softlayer plugin 529 | 530 | ### Improvements 531 | 532 | * Improved/updated README documentation + typos 533 | * Remove default memory setting 534 | * Fix relative paths in synced folders 535 | 536 | ## 0.14.0 / 2013-12-09 537 | 538 | ### New features 539 | 540 | * Add `config[:vm_hostname]` to set config.vm.hostname in Vagrantfile. ([@fnichol][]) 541 | 542 | ### Improvements 543 | 544 | * Add `config[:guest]` documentation in README. ([@fnichol][]) 545 | 546 | 547 | ## 0.13.0 / 2013-12-04 548 | 549 | ### New features 550 | 551 | * Use Opscode's new buckets for Virtual machines, allowing for downloads of VirtualBox and VMware Fusion/Workstation Bento boxes (Vagrant minimal base boxes). ([@sethvargo][]) 552 | 553 | 554 | ## 0.12.0 / 2013-11-29 555 | 556 | ### Breaking changes 557 | 558 | * Remove `use_vagrant_provision` configuration option. 559 | 560 | ### New features 561 | 562 | * Major refactor of Vagrantfile generation, to use an ERB template. For more details please consult the `vagrantfile_erb` section of the README. ([@fnichol][]) 563 | * Add `pre_create_command` option to run optional setup such as Bindler. ([@fnichol][]) 564 | 565 | ### Improvements 566 | 567 | * Pull request [#56][]: Enabled passing options to the synced folders. ([@antonio-osorio][]) 568 | * Pull request [#55][]: Fix README badges. ([@arangamani][]) 569 | 570 | 571 | ## 0.11.3 / 2013-11-09 572 | 573 | ### Bug fixes 574 | 575 | * Revert `quiet` option used for Vagrant version checking. ([@fnichol][]) 576 | 577 | 578 | ## 0.11.2 / 2013-11-05 579 | 580 | ### Bug fixes 581 | 582 | * Remove misleading `quiet` option ([@sethvargo][]) 583 | * Relax dependency on Test Kitchen ([@sethvargo][]) 584 | * Remove deprecated references to `vagrant-berkshelf` ([@sethvargo][]) 585 | 586 | ### Improvements 587 | 588 | * Allow users to specify custom SSH private key ([@manul][]) 589 | * Use platform to determine which vagrant box to download (assume Opscode) ([@sethvargo][]) 590 | 591 | 592 | ## 0.11.1 / 2013-08-29 593 | 594 | ### Bug fixes 595 | 596 | * Pull request [#36][]: README fix for synched_folders. ([@mattray][]) 597 | 598 | ### Improvements 599 | 600 | * Pull request [#34][]: Disable synced folders by default. ([@dje][]) 601 | 602 | 603 | ## 0.11.0 / 2013-07-23 604 | 605 | ### New features 606 | 607 | * Pull request [#30][]: Support computed defaults for a select list of pre-determined platforms (see pull request and readme for quick example). ([@fnichol][]) 608 | * Pull request [#25][]: Add rackspace support. ([@josephholsten][]) 609 | 610 | ### Improvements 611 | 612 | * Pull request [#20][]: Respect `VAGRANT_DEFAULT_PROVIDER` environment variable. ([@tmatilai][]) 613 | * Pull request [#24][]: Allow to override Vagrant default SSH username. ([@gildegoma][]) 614 | * Pull request [#21][]: Configure tailor to actually check the code style. ([@tmatilai][]) 615 | 616 | ### Bug fixes 617 | 618 | * Pull request [#29][], issue [#28][]: Allow the vagrant guest setting to be set in the generated Vagrantfile via the kitchen.yml. ([@keiths-osc][]) 619 | * Pull request [#31][]: Add some quotes around Vagrantfile value. ([@albertsj1][]) 620 | 621 | 622 | ## 0.10.0 / 2013-05-08 623 | 624 | ### New features 625 | 626 | * Pull request [#12][]: Use SSHBase functionality (using ChefDataUploader) to manage Chef provisioning in the converge action and make Vagrant's built in provisioning an optional mode by setting `use_vagrant_provision: true` in the `driver_config` section of the .kitchen.yml. As a consequence, the vagrant-berkshelf middleware is now also optional and off by default (can be re-enabled by setting `use_vagrant_berkshelf_plugin: true`). ([@fujin][]) 627 | * Pull request [#18][]: Add VMware Fusion/Workstation support. ([@TheDude05][]) 628 | 629 | ### Improvements 630 | 631 | * Issue [#19][]: Recommend the vagrant-wrapper gem in README. ([@fnichol][]) 632 | 633 | 634 | ## 0.9.0 / 2013-04-19 635 | 636 | ### Upstream changes 637 | 638 | * Pull request [#16][]: Update Vagrant Berkshelf plugin detection for the vagrant-berkshelf and drop detection for berkshelf-vagrant. ([@martinisoft][]) 639 | 640 | 641 | ## 0.8.0 / 2013-04-16 642 | 643 | ### Improvements 644 | 645 | * Pull request [#15][]: Support berkshelf-vagrant 1.1.0+ in Vagrantfiles. ([@petejkim][], [@fnichol][]) 646 | * Add an explanation of how this driver works in the README. ([@fnichol][]) 647 | 648 | 649 | ## 0.7.4 / 2013-03-28 650 | 651 | ### Improvements 652 | 653 | * Drop `vagrant ssh -c` & communicate directly via SSH. ([@fnichol][]) 654 | 655 | 656 | ## 0.7.3 / 2013-03-28 657 | 658 | ### Bug fixes 659 | 660 | * Calling #destroy should not memoize #create_vagrantfile. ([@fnichol][], [@sandfish8][]) 661 | 662 | 663 | ## 0.7.2 / 2013-03-23 664 | 665 | ### Bug fixes 666 | 667 | * Wrap strings for data_bags_path and roles_path in Vagrantfiles. ([@fnichol][]) 668 | 669 | 670 | ## 0.7.1 / 2013-03-23 671 | 672 | ### Bug fixes 673 | 674 | * Depend on test-kitchen ~> 1.0.0.alpha.1 to get API updates. ([@fnichol][]) 675 | 676 | 677 | ## 0.7.0 / 2013-03-22 678 | 679 | ### New features 680 | 681 | * Pull request [#7][]: [Breaking] Support Vagrant 1.1+ and remove vagrant gem dependency. ([@fnichol][]) 682 | * Pull request [#8][]: Add dependency checks for Vagrant and berkshelf-vagrant plugin (if necessary). ([@fnichol][]) 683 | 684 | 685 | ## 0.6.0 / 2013-03-02 686 | 687 | The initial release. 688 | 689 | 690 | [#7]: https://github.com/test-kitchen/kitchen-vagrant/issues/7 691 | [#8]: https://github.com/test-kitchen/kitchen-vagrant/issues/8 692 | [#12]: https://github.com/test-kitchen/kitchen-vagrant/issues/12 693 | [#15]: https://github.com/test-kitchen/kitchen-vagrant/issues/15 694 | [#16]: https://github.com/test-kitchen/kitchen-vagrant/issues/16 695 | [#18]: https://github.com/test-kitchen/kitchen-vagrant/issues/18 696 | [#19]: https://github.com/test-kitchen/kitchen-vagrant/issues/19 697 | [#20]: https://github.com/test-kitchen/kitchen-vagrant/issues/20 698 | [#21]: https://github.com/test-kitchen/kitchen-vagrant/issues/21 699 | [#24]: https://github.com/test-kitchen/kitchen-vagrant/issues/24 700 | [#25]: https://github.com/test-kitchen/kitchen-vagrant/issues/25 701 | [#28]: https://github.com/test-kitchen/kitchen-vagrant/issues/28 702 | [#29]: https://github.com/test-kitchen/kitchen-vagrant/issues/29 703 | [#30]: https://github.com/test-kitchen/kitchen-vagrant/issues/30 704 | [#31]: https://github.com/test-kitchen/kitchen-vagrant/issues/31 705 | [#34]: https://github.com/test-kitchen/kitchen-vagrant/issues/34 706 | [#36]: https://github.com/test-kitchen/kitchen-vagrant/issues/36 707 | [#55]: https://github.com/test-kitchen/kitchen-vagrant/issues/55 708 | [#56]: https://github.com/test-kitchen/kitchen-vagrant/issues/56 709 | [#84]: https://github.com/test-kitchen/kitchen-vagrant/issues/84 710 | [#95]: https://github.com/test-kitchen/kitchen-vagrant/issues/95 711 | [#101]: https://github.com/test-kitchen/kitchen-vagrant/issues/101 712 | [#102]: https://github.com/test-kitchen/kitchen-vagrant/issues/102 713 | [#104]: https://github.com/test-kitchen/kitchen-vagrant/issues/104 714 | [#106]: https://github.com/test-kitchen/kitchen-vagrant/issues/106 715 | [#107]: https://github.com/test-kitchen/kitchen-vagrant/issues/107 716 | [#112]: https://github.com/test-kitchen/kitchen-vagrant/issues/112 717 | [#117]: https://github.com/test-kitchen/kitchen-vagrant/issues/117 718 | [#118]: https://github.com/test-kitchen/kitchen-vagrant/issues/118 719 | [#121]: https://github.com/test-kitchen/kitchen-vagrant/issues/121 720 | [#122]: https://github.com/test-kitchen/kitchen-vagrant/issues/122 721 | [#126]: https://github.com/test-kitchen/kitchen-vagrant/issues/126 722 | [#127]: https://github.com/test-kitchen/kitchen-vagrant/issues/127 723 | [#128]: https://github.com/test-kitchen/kitchen-vagrant/issues/128 724 | [#129]: https://github.com/test-kitchen/kitchen-vagrant/issues/129 725 | [#134]: https://github.com/test-kitchen/kitchen-vagrant/issues/134 726 | [#137]: https://github.com/test-kitchen/kitchen-vagrant/issues/137 727 | [#142]: https://github.com/test-kitchen/kitchen-vagrant/issues/142 728 | [#146]: https://github.com/test-kitchen/kitchen-vagrant/issues/146 729 | [#147]: https://github.com/test-kitchen/kitchen-vagrant/issues/147 730 | [#148]: https://github.com/test-kitchen/kitchen-vagrant/issues/148 731 | [#151]: https://github.com/test-kitchen/kitchen-vagrant/issues/151 732 | [#152]: https://github.com/test-kitchen/kitchen-vagrant/issues/152 733 | [#154]: https://github.com/test-kitchen/kitchen-vagrant/issues/154 734 | [#155]: https://github.com/test-kitchen/kitchen-vagrant/issues/155 735 | [#156]: https://github.com/test-kitchen/kitchen-vagrant/issues/156 736 | [#157]: https://github.com/test-kitchen/kitchen-vagrant/issues/157 737 | [#158]: https://github.com/test-kitchen/kitchen-vagrant/issues/158 738 | [#161]: https://github.com/test-kitchen/kitchen-vagrant/issues/161 739 | [#163]: https://github.com/test-kitchen/kitchen-vagrant/issues/163 740 | [#166]: https://github.com/test-kitchen/kitchen-vagrant/issues/166 741 | [#171]: https://github.com/test-kitchen/kitchen-vagrant/issues/171 742 | [#174]: https://github.com/test-kitchen/kitchen-vagrant/issues/174 743 | [#190]: https://github.com/test-kitchen/kitchen-vagrant/issues/190 744 | [#191]: https://github.com/test-kitchen/kitchen-vagrant/issues/191 745 | [#197]: https://github.com/test-kitchen/kitchen-vagrant/issues/197 746 | [@Annih]: https://github.com/Annih 747 | [@Igorshp]: https://github.com/Igorshp 748 | [@RobertRehberg]: https://github.com/RobertRehberg 749 | [@TheDude05]: https://github.com/TheDude05 750 | [@albertsj1]: https://github.com/albertsj1 751 | [@albsOps]: https://github.com/albsOps 752 | [@alex-slynko-wonga]: https://github.com/alex-slynko-wonga 753 | [@antonio-osorio]: https://github.com/antonio-osorio 754 | [@arangamani]: https://github.com/arangamani 755 | [@ashb]: https://github.com/ashb 756 | [@atiniir]: https://github.com/atiniir 757 | [@bdclark]: https://github.com/bdclark 758 | [@bradleyd]: https://github.com/bradleyd 759 | [@byggztryng]: https://github.com/byggztryng 760 | [@dje]: https://github.com/dje 761 | [@fnichol]: https://github.com/fnichol 762 | [@fujin]: https://github.com/fujin 763 | [@gildegoma]: https://github.com/gildegoma 764 | [@gouketsu]: https://github.com/gouketsu 765 | [@hugespoon]: https://github.com/hugespoon 766 | [@jhx]: https://github.com/jhx 767 | [@josephholsten]: https://github.com/josephholsten 768 | [@kbruner]: https://github.com/kbruner 769 | [@keiths-osc]: https://github.com/keiths-osc 770 | [@ksubrama]: https://github.com/ksubrama 771 | [@manul]: https://github.com/manul 772 | [@martinisoft]: https://github.com/martinisoft 773 | [@mattray]: https://github.com/mattray 774 | [@mconigliaro]: https://github.com/mconigliaro 775 | [@miketheman]: https://github.com/miketheman 776 | [@petejkim]: https://github.com/petejkim 777 | [@petere]: https://github.com/petere 778 | [@philcallister]: https://github.com/philcallister 779 | [@sandfish8]: https://github.com/sandfish8 780 | [@sethvargo]: https://github.com/sethvargo 781 | [@tknerr]: https://github.com/tknerr 782 | [@tmatilai]: https://github.com/tmatilai 783 | [@vinyar]: https://github.com/vinyar 784 | [@whiteley]: https://github.com/whiteley 785 | [@xmik]: https://github.com/xmik 786 | [@zuazo]: https://github.com/zuazo 787 | -------------------------------------------------------------------------------- /spec/kitchen/driver/vagrant_spec.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Fletcher Nichol () 3 | # 4 | # Copyright (C) 2015, Fletcher Nichol 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | require_relative "../../spec_helper" 19 | 20 | require "logger" 21 | require "stringio" unless defined?(StringIO) 22 | 23 | require "kitchen/driver/vagrant" 24 | require "kitchen/provisioner/dummy" 25 | require "kitchen/transport/dummy" 26 | require "kitchen/verifier/dummy" 27 | 28 | describe Kitchen::Driver::Vagrant do 29 | 30 | let(:logged_output) { StringIO.new } 31 | let(:logger) { Logger.new(logged_output) } 32 | let(:config) { { kitchen_root: "/kroot" } } 33 | let(:platform) { Kitchen::Platform.new(name: "fooos-99") } 34 | let(:suite) { Kitchen::Suite.new(name: "suitey") } 35 | let(:verifier) { Kitchen::Verifier::Dummy.new } 36 | let(:provisioner) { Kitchen::Provisioner::Dummy.new } 37 | let(:state) { {} } 38 | let(:lifecycle_hooks) { Kitchen::LifecycleHooks.new(config, state) } 39 | let(:transport) { Kitchen::Transport::Dummy.new } 40 | let(:state_file) { double("state_file") } 41 | let(:env) { {} } 42 | 43 | let(:driver_object) { Kitchen::Driver::Vagrant.new(config) } 44 | 45 | let(:driver) do 46 | d = driver_object 47 | instance 48 | d 49 | end 50 | 51 | let(:driver_with_no_instance) do 52 | driver_object 53 | end 54 | 55 | let(:instance) do 56 | Kitchen::Instance.new( 57 | verifier: verifier, 58 | driver: driver_object, 59 | logger: logger, 60 | suite: suite, 61 | platform: platform, 62 | provisioner: provisioner, 63 | lifecycle_hooks: lifecycle_hooks, 64 | transport: transport, 65 | state_file: state_file 66 | ) 67 | end 68 | 69 | module RunCommandStub 70 | def run_command(_cmd, options = {}) 71 | options 72 | end 73 | end 74 | 75 | before(:all) do 76 | Kitchen::Driver::Vagrant.instance_eval { include RunCommandStub } 77 | end 78 | 79 | before(:each) { stub_const("ENV", env) } 80 | 81 | after do 82 | driver_object.class.send(:vagrant_version=, nil) 83 | end 84 | 85 | it "driver api_version is 2" do 86 | expect(driver.diagnose_plugin[:api_version]).to eq(2) 87 | end 88 | 89 | it "plugin_version is set to Kitchen::Vagrant::VERSION" do 90 | expect(driver.diagnose_plugin[:version]).to eq( 91 | Kitchen::Driver::VAGRANT_VERSION 92 | ) 93 | end 94 | 95 | describe "#run_command" do 96 | 97 | context "when invoked from a clean environment" do 98 | 99 | it "passes through environment variables" do 100 | options = driver.send( 101 | :run_command, 102 | "cmd", 103 | environment: { "EV1" => "Val1", "EV2" => "Val2" } 104 | ) 105 | expect(options[:environment]["EV1"]).to eq("Val1") 106 | expect(options[:environment]["EV2"]).to eq("Val2") 107 | end 108 | 109 | it "leaves path alone" do 110 | path = "/foo/#{File::PATH_SEPARATOR}/bar" 111 | options = driver.send( 112 | :run_command, 113 | "cmd", 114 | environment: { "PATH" => path } 115 | ) 116 | expect(options[:environment]["PATH"]).to eq(path) 117 | end 118 | 119 | end 120 | 121 | context "when invoked from a bundler[:environment]" do 122 | 123 | let(:bundler_env) do 124 | { 125 | "BUNDLE_BIN_PATH" => "bundle_bin_path", 126 | "BUNDLE_GEMFILE" => "bundle_gem_file", 127 | "GEM_HOME" => "gem_home", 128 | "GEM_PATH" => "gem_path", 129 | "GEM_ROOT" => "gem_root", 130 | "RUBYLIB" => "ruby_lib", 131 | "RUBYOPT" => "ruby_opt", 132 | "_ORIGINAL_GEM_PATH" => "original_gem_path", 133 | } 134 | end 135 | 136 | it "removes all bundler related variables" do 137 | env.merge!(bundler_env) 138 | options = driver.send(:run_command, "cmd") 139 | bundler_env.each do |k, _v| 140 | expect(options[:environment]).to include(k) 141 | expect(options[:environment][k]).to eq(nil) 142 | end 143 | end 144 | 145 | it "fixes path if it notices gem_home in it" do 146 | allow(RbConfig::CONFIG).to receive(:[]).with("host_os") 147 | .and_return("linux") 148 | env.merge!(bundler_env) 149 | env["PATH"] = "gem_home/bin#{File::PATH_SEPARATOR}/something/else" 150 | options = driver.send(:run_command, "cmd") 151 | puts(options) 152 | expect(options[:environment]["PATH"]).to eq("/something/else") 153 | end 154 | end 155 | end 156 | 157 | describe "configuration" do 158 | 159 | let(:cache_directory_array) do 160 | [ 161 | File.expand_path("~/.kitchen/cache"), 162 | "/tmp/omnibus/cache", 163 | "create: true", 164 | ] 165 | end 166 | 167 | %w{centos debian fedora opensuse ubuntu oracle freebsd hardenedbsd}.each do |name| 168 | 169 | context "for known bento platform names starting with #{name}" do 170 | 171 | before { allow(platform).to receive(:name) { "#{name}-99.04" } } 172 | 173 | it "sets :box based on the platform name by default" do 174 | expect(driver[:box]).to eq("bento/#{name}-99.04") 175 | end 176 | 177 | it "sets :box to a custom value" do 178 | config[:box] = "booya" 179 | 180 | expect(driver[:box]).to eq("booya") 181 | end 182 | 183 | it "sets :box_url to nil" do 184 | config[:provider] = "the-next-coolness" 185 | 186 | expect(driver[:box_url]).to eq(nil) 187 | end 188 | end 189 | end 190 | 191 | context "for unknown bento platform names" do 192 | 193 | before { allow(platform).to receive(:name) { "slackware-14.1" } } 194 | 195 | it "sets :box based on the platform name by default" do 196 | expect(driver[:box]).to eq("slackware-14.1") 197 | end 198 | 199 | it "sets :box to a custom value" do 200 | config[:box] = "booya" 201 | 202 | expect(driver[:box]).to eq("booya") 203 | end 204 | 205 | it "sets :box_url to nil" do 206 | expect(driver[:box_url]).to eq(nil) 207 | end 208 | end 209 | 210 | it "sets :box_check_update to nil by default" do 211 | expect(driver[:box_check_update]).to eq(nil) 212 | end 213 | 214 | it "sets :box_check_update to a custom value" do 215 | config[:box_check_update] = true 216 | 217 | expect(driver[:box_check_update]).to eq(true) 218 | end 219 | 220 | it "sets :box_download_ca_cert to nil by default" do 221 | expect(driver[:box_download_ca_cert]).to eq(nil) 222 | end 223 | 224 | it "sets :box_download_ca_cert to a custom value" do 225 | config[:box_download_ca_cert] = "cacert.pem" 226 | 227 | expect(driver[:box_download_ca_cert]).to eq("/kroot/cacert.pem") 228 | end 229 | 230 | it "sets :box_download_insecure to nil by default" do 231 | expect(driver[:box_download_insecure]).to eq(nil) 232 | end 233 | 234 | it "sets :box_download_insecure to a custom value" do 235 | config[:box_download_insecure] = true 236 | 237 | expect(driver[:box_download_insecure]).to eq(true) 238 | end 239 | 240 | it "sets :box_version to nil by default" do 241 | expect(driver[:box_version]).to eq(nil) 242 | end 243 | 244 | it "sets :box_version to a custom value" do 245 | config[:box_version] = "1.2.3" 246 | 247 | expect(driver[:box_version]).to eq("1.2.3") 248 | end 249 | 250 | it "sets :boot_timeout to nil by default" do 251 | expect(driver[:boot_timeout]).to eq(nil) 252 | end 253 | 254 | it "sets :boot_timeout to a custom value" do 255 | config[:boot_timeout] = 600 256 | 257 | expect(driver[:boot_timeout]).to eq(600) 258 | end 259 | 260 | it "sets :customize to an empty hash by default" do 261 | expect(driver[:customize]).to eq({}) 262 | end 263 | 264 | it "sets :customize to a custom value" do 265 | config[:customize] = { a: "b", c: { d: "e" } } 266 | 267 | expect(driver[:customize]).to eq(a: "b", c: { d: "e" }) 268 | end 269 | 270 | it "sets :gui to nil by default" do 271 | expect(driver[:gui]).to eq(nil) 272 | end 273 | 274 | it "sets :linked_clone to nil by default" do 275 | expect(driver[:linked_clone]).to eq(nil) 276 | end 277 | 278 | it "sets :network to an empty array by default" do 279 | expect(driver[:network]).to eq([]) 280 | end 281 | 282 | it "sets :network to a custom value" do 283 | config[:network] = [ 284 | ["forwarded_port", guest: 80, host: 8080], 285 | ] 286 | 287 | expect(driver[:network]).to eq([ 288 | ["forwarded_port", guest: 80, host: 8080], 289 | ]) 290 | end 291 | 292 | it "sets :pre_create_command to nil by default" do 293 | expect(driver[:pre_create_command]).to eq(nil) 294 | end 295 | 296 | it "sets :pre_create_command to a custom value" do 297 | config[:pre_create_command] = "execute yo" 298 | 299 | expect(driver[:pre_create_command]).to eq("execute yo") 300 | end 301 | 302 | it "replaces {{vagrant_root}} in :pre_create_command" do 303 | config[:pre_create_command] = "{{vagrant_root}}/candy" 304 | 305 | expect(driver[:pre_create_command]).to eq( 306 | "/kroot/.kitchen/kitchen-vagrant/suitey-fooos-99/candy" 307 | ) 308 | end 309 | 310 | it "sets :provision to false by default" do 311 | expect(driver[:provision]).to eq(false) 312 | end 313 | 314 | it "sets :provision to a custom value" do 315 | config[:provision] = true 316 | 317 | expect(driver[:provision]).to eq(true) 318 | end 319 | 320 | it "sets :provider to virtualbox by default" do 321 | expect(driver[:provider]).to eq("virtualbox") 322 | end 323 | 324 | it "sets :provider to the value of VAGRANT_DEFAULT_PROVIDER from ENV" do 325 | env["VAGRANT_DEFAULT_PROVIDER"] = "vcool" 326 | 327 | expect(driver[:provider]).to eq("vcool") 328 | end 329 | 330 | it "sets :provider to a custom value" do 331 | config[:provider] = "mything" 332 | 333 | expect(driver[:provider]).to eq("mything") 334 | end 335 | 336 | it "sets :ssh to an empty hash by default" do 337 | expect(driver[:ssh]).to eq({}) 338 | end 339 | 340 | it "sets :ssh to a custom value" do 341 | config[:ssh] = { a: "b", c: { d: "e" } } 342 | 343 | expect(driver[:ssh]).to eq(a: "b", c: { d: "e" }) 344 | end 345 | 346 | it "sets :synced_folders with the cache_directory for select bento boxes" do 347 | config[:box] = "bento/centos-99" 348 | expect(driver[:synced_folders]).to eq([cache_directory_array]) 349 | end 350 | 351 | it "does not set :synced_folders when cache_directory is false" do 352 | config[:box] = "bento/centos-99" 353 | config[:cache_directory] = false 354 | expect(driver[:synced_folders]).to eq([]) 355 | end 356 | 357 | it "sets :synced_folders with the cache_directory when :use_cached_chef_client is `true`" do 358 | config[:box] = "some_owner/centos-99" 359 | config[:use_cached_chef_client] = true 360 | expect(driver[:synced_folders]).to eq([cache_directory_array]) 361 | end 362 | 363 | it "does not set :synced_folders to cache_directory on freebsd systems" do 364 | allow(platform).to receive(:name).and_return("freebsd-99") 365 | expect(driver[:synced_folders]).to eq([]) 366 | end 367 | 368 | it "sets :synced_folders to a custom value" do 369 | config[:synced_folders] = [ 370 | ["/host_path", "/vm_path", "create: true, type: :nfs"], 371 | ] 372 | 373 | expect(driver[:synced_folders]).to eq([ 374 | [ 375 | File.expand_path("/host_path"), 376 | "/vm_path", "create: true, type: :nfs" 377 | ], 378 | ]) 379 | end 380 | 381 | it "replaces %{instance_name} with instance name in :synced_folders" do 382 | config[:synced_folders] = [ 383 | ["/root/%{instance_name}", "/vm_path", "stuff"], 384 | ] 385 | 386 | expect(driver[:synced_folders]).to eq([ 387 | [File.expand_path("/root/suitey-fooos-99"), "/vm_path", "stuff"], 388 | ]) 389 | end 390 | 391 | it "expands source paths relative to :kitchen_root in :synced_folders" do 392 | config[:synced_folders] = [ 393 | ["./a", "/vm_path", "stuff"], 394 | ] 395 | 396 | expect(driver[:synced_folders]).to eq([ 397 | [File.expand_path("/kroot/a"), "/vm_path", "stuff"], 398 | ]) 399 | end 400 | 401 | it "sets options to 'nil' if not set in :synced_folders entry" do 402 | config[:synced_folders] = [ 403 | ["/host_path", "/vm_path", nil], 404 | ] 405 | 406 | expect(driver[:synced_folders]).to eq([ 407 | [File.expand_path("/host_path"), "/vm_path", "nil"], 408 | ]) 409 | end 410 | 411 | it 'sets :env to an empty array by default' do 412 | expect(driver[:env]).to eq([]) 413 | end 414 | 415 | it 'sets :env to a custom value' do 416 | config[:env] = ['AWS_REGION=us-east-1', 'AWS_ACCESS_KEY_ID=test123'] 417 | 418 | expect(driver[:env]).to eq(['AWS_REGION=us-east-1', 'AWS_ACCESS_KEY_ID=test123']) 419 | end 420 | 421 | it "converts Hash options to Ruby hash syntax in :synced_folders" do 422 | config[:synced_folders] = [ 423 | ["/host_path", "/vm_path", { type: "smb", smb_username: "testuser", smb_password: "testpass" }], 424 | ] 425 | 426 | expect(driver[:synced_folders]).to eq([ 427 | [File.expand_path("/host_path"), "/vm_path", 'type: "smb", smb_username: "testuser", smb_password: "testpass"'], 428 | ]) 429 | end 430 | 431 | it "handles Hash options with symbol keys in :synced_folders" do 432 | config[:synced_folders] = [ 433 | ["/host_path", "/vm_path", { type: "smb", create: true }], 434 | ] 435 | 436 | expect(driver[:synced_folders]).to eq([ 437 | [File.expand_path("/host_path"), "/vm_path", 'type: "smb", create: true'], 438 | ]) 439 | end 440 | 441 | it "preserves String options for backward compatibility in :synced_folders" do 442 | config[:synced_folders] = [ 443 | ["/host_path", "/vm_path", "type: :nfs, create: true"], 444 | ] 445 | 446 | expect(driver[:synced_folders]).to eq([ 447 | [File.expand_path("/host_path"), "/vm_path", "type: :nfs, create: true"], 448 | ]) 449 | end 450 | 451 | it "sets :vagrant_binary to 'vagrant' by default" do 452 | expect(driver[:vagrant_binary]).to eq("vagrant") 453 | end 454 | 455 | it "sets :vagrant_binary to a custom value" do 456 | config[:vagrant_binary] = "vagrant.cmd" 457 | expect(driver[:vagrant_binary]).to eq("vagrant.cmd") 458 | end 459 | 460 | it "sets :vagrantfile_erb to a default" do 461 | expect(driver[:vagrantfile_erb]).to match( 462 | %r{/kitchen-vagrant/templates/Vagrantfile\.erb$} 463 | ) 464 | end 465 | 466 | it "sets :vagrantfile_erb to a default value" do 467 | config[:vagrantfile_erb] = "/a/Vagrantfile.erb" 468 | 469 | expect(driver[:vagrantfile_erb]).to eq( 470 | File.expand_path("/a/Vagrantfile.erb") 471 | ) 472 | end 473 | 474 | it "expands path for :vagrantfile_erb" do 475 | config[:vagrantfile_erb] = "Yep.erb" 476 | 477 | expect(driver[:vagrantfile_erb]).to eq( 478 | File.expand_path("/kroot/Yep.erb") 479 | ) 480 | end 481 | 482 | it "sets :vagrantfiles to an empty array by default" do 483 | expect(driver[:vagrantfiles]).to eq([]) 484 | end 485 | 486 | it "sets and expands paths in :vagrantfiles" do 487 | config[:vagrantfiles] = %w{one two three} 488 | 489 | expect(driver[:vagrantfiles]).to eq( 490 | %w{/kroot/one /kroot/two /kroot/three}.map { |f| File.expand_path(f) } 491 | ) 492 | end 493 | 494 | context "for unix os_types" do 495 | 496 | before { allow(platform).to receive(:os_type).and_return("unix") } 497 | 498 | it "sets :vm_hostname to the instance name by default" do 499 | expect(driver[:vm_hostname]).to eq("suitey-fooos-99.vagrantup.com") 500 | end 501 | 502 | it "sets :vm_hostname to a custom value" do 503 | config[:vm_hostname] = "okay" 504 | 505 | expect(driver[:vm_hostname]).to eq("okay") 506 | end 507 | end 508 | 509 | context "for windows os_types" do 510 | 511 | before { allow(platform).to receive(:os_type).and_return("windows") } 512 | 513 | it "sets :vm_hostname to nil by default" do 514 | expect(driver[:vm_hostname]).to eq(nil) 515 | end 516 | 517 | it "sets :vm_hostname to a custom value, truncated to 15 chars" do 518 | config[:vm_hostname] = "this-is-a-pretty-long-name-ya-think" 519 | 520 | expect(driver[:vm_hostname]).to eq("this-is-a-pr-k") 521 | end 522 | 523 | it "replaces %{instance_name} with instance name in :synced_folders" do 524 | config[:synced_folders] = [ 525 | ["/root/%{instance_name}", "/vm_path", "stuff"], 526 | ] 527 | 528 | expect(driver[:synced_folders]).to eq([ 529 | [File.expand_path("/root/suitey-fooos-99"), "/vm_path", "stuff"], 530 | ]) 531 | end 532 | end 533 | 534 | context "when cache_directory is customized" do 535 | 536 | let(:custom_cache_directory_array) do 537 | [ 538 | File.expand_path("~/.kitchen/cache"), 539 | "Z:\\awesome\\cache", 540 | "create: true", 541 | ] 542 | end 543 | 544 | before do 545 | config[:box] = "bento/centos-99" 546 | config[:cache_directory] = "Z:\\awesome\\cache" 547 | end 548 | 549 | it "sets :synced_folders with the custom cache_directory" do 550 | expect(driver[:synced_folders]).to eq([custom_cache_directory_array]) 551 | end 552 | 553 | it "replaces %{instance_name} with instance name in :synced_folders" do 554 | config[:synced_folders] = [ 555 | ["/root/%{instance_name}", "/vm_path", "stuff"], 556 | ] 557 | 558 | expect(driver[:synced_folders]).to eq([ 559 | [File.expand_path("/root/suitey-fooos-99"), "/vm_path", "stuff"], 560 | custom_cache_directory_array, 561 | ]) 562 | end 563 | end 564 | end 565 | 566 | describe '#wsl?' do 567 | it 'returns true when WSL_DISTRO_NAME is set' do 568 | stub_const('ENV', { 'WSL_DISTRO_NAME' => 'Ubuntu' }) 569 | expect(driver.send(:wsl?)).to eq(true) 570 | end 571 | 572 | it 'returns true when VAGRANT_WSL_ENABLE_WINDOWS_ACCESS is set' do 573 | stub_const('ENV', { 'VAGRANT_WSL_ENABLE_WINDOWS_ACCESS' => '1' }) 574 | expect(driver.send(:wsl?)).to eq(true) 575 | end 576 | 577 | it 'returns true when /proc/version contains Microsoft' do 578 | stub_const('ENV', {}) 579 | allow(File).to receive(:exist?).with('/proc/version').and_return(true) 580 | allow(File).to receive(:read).with('/proc/version') 581 | .and_return('Linux version 4.4.0-19041-Microsoft') 582 | expect(driver.send(:wsl?)).to eq(true) 583 | end 584 | 585 | it 'returns true when /proc/version contains WSL' do 586 | stub_const('ENV', {}) 587 | allow(File).to receive(:exist?).with('/proc/version').and_return(true) 588 | allow(File).to receive(:read).with('/proc/version') 589 | .and_return('Linux version 5.10.16.3-microsoft-standard-WSL2') 590 | expect(driver.send(:wsl?)).to eq(true) 591 | end 592 | 593 | it 'returns false when not in WSL' do 594 | stub_const('ENV', {}) 595 | allow(File).to receive(:exist?).with('/proc/version').and_return(false) 596 | expect(driver.send(:wsl?)).to eq(false) 597 | end 598 | 599 | it "returns false when /proc/version exists but doesn't contain WSL markers" do 600 | stub_const('ENV', {}) 601 | allow(File).to receive(:exist?).with('/proc/version').and_return(true) 602 | allow(File).to receive(:read).with('/proc/version') 603 | .and_return('Linux version 5.4.0-42-generic') 604 | expect(driver.send(:wsl?)).to eq(false) 605 | end 606 | 607 | it 'returns false when an error occurs' do 608 | stub_const('ENV', {}) 609 | allow(File).to receive(:exist?).and_raise(StandardError) 610 | expect(driver.send(:wsl?)).to eq(false) 611 | end 612 | end 613 | 614 | describe '#windows_to_wsl_path' do 615 | it 'converts C: drive path to /mnt/c' do 616 | path = 'C:/Users/username/.vagrant.d/insecure_private_key' 617 | expected = '/mnt/c/users/username/.vagrant.d/insecure_private_key' 618 | expect(driver.send(:windows_to_wsl_path, path)).to eq(expected) 619 | end 620 | 621 | it 'converts D: drive path to /mnt/d' do 622 | path = 'D:/Projects/vagrant/.vagrant/machines/default/virtualbox/private_key' 623 | expected = '/mnt/d/projects/vagrant/.vagrant/machines/default/virtualbox/private_key' 624 | expect(driver.send(:windows_to_wsl_path, path)).to eq(expected) 625 | end 626 | 627 | it 'handles lowercase drive letters' do 628 | path = 'c:/path/to/key' 629 | expected = '/mnt/c/path/to/key' 630 | expect(driver.send(:windows_to_wsl_path, path)).to eq(expected) 631 | end 632 | 633 | it 'leaves Unix paths unchanged' do 634 | path = '/home/user/.vagrant.d/insecure_private_key' 635 | expect(driver.send(:windows_to_wsl_path, path)).to eq(path) 636 | end 637 | 638 | it 'leaves relative paths unchanged' do 639 | path = '.vagrant/machines/default/virtualbox/private_key' 640 | expect(driver.send(:windows_to_wsl_path, path)).to eq(path) 641 | end 642 | end 643 | 644 | describe "#verify_dependencies" do 645 | 646 | it "passes for supported versions of Vagrant" do 647 | with_modern_vagrant 648 | 649 | driver.verify_dependencies 650 | end 651 | 652 | it "passes for supported versions of Vagrant when it has no instances" do 653 | with_modern_vagrant 654 | 655 | driver_with_no_instance.verify_dependencies 656 | end 657 | 658 | it "raises a UserError for unsupported versions of Vagrant" do 659 | with_unsupported_vagrant 660 | 661 | expect { driver.verify_dependencies }.to raise_error( 662 | Kitchen::UserError, /Please upgrade to version 2.4.0 or higher/ 663 | ) 664 | end 665 | 666 | it "raises a UserError for a missing Vagrant command" do 667 | allow(driver_object).to receive(:run_command) 668 | .with("vagrant --version", any_args).and_raise(Errno::ENOENT) 669 | 670 | expect { driver.verify_dependencies }.to raise_error( 671 | Kitchen::UserError, /Vagrant 2.4.0 or higher is not installed/ 672 | ) 673 | end 674 | end 675 | 676 | describe "#create" do 677 | 678 | let(:cmd) { driver.create(state) } 679 | 680 | let(:vagrant_root) do 681 | File.join(%W{ 682 | #{@dir} .kitchen kitchen-vagrant suitey-fooos-99 683 | }) 684 | end 685 | 686 | before do 687 | @dir = Dir.mktmpdir("kitchen_root") 688 | config[:kitchen_root] = @dir 689 | 690 | allow(driver).to receive(:run_command).and_return("") 691 | with_modern_vagrant 692 | end 693 | 694 | after do 695 | FileUtils.remove_entry_secure(@dir) 696 | end 697 | 698 | it "logs a message on debug level for creating the Vagrantfile" do 699 | cmd 700 | 701 | expect(logged_output.string).to match( 702 | /^D, .+ DEBUG -- : Creating Vagrantfile for \ / 703 | ) 704 | end 705 | 706 | it "creates a Vagrantfile in the vagrant root directory" do 707 | cmd 708 | 709 | expect(File.exist?(File.join(vagrant_root, "Vagrantfile"))).to eq(true) 710 | end 711 | 712 | it "calls Transport's #wait_until_ready" do 713 | conn = double("connection") 714 | allow(transport).to receive(:connection).with(state).and_return(conn) 715 | expect(conn).to receive(:wait_until_ready) 716 | 717 | cmd 718 | end 719 | 720 | it "logs the Vagrantfile contents on debug level" do 721 | cmd 722 | 723 | expect(debug_lines).to match(Regexp.new(<<-REGEXP.gsub(/^ {8}/, ""))) 724 | ------------ 725 | Vagrant.configure\("2"\) do \|c\| 726 | .* 727 | end 728 | ------------ 729 | REGEXP 730 | end 731 | 732 | it "raises ActionFailed if a custom Vagrantfile template was not found" do 733 | config[:vagrantfile_erb] = "/a/bunch/of/nope" 734 | 735 | expect { cmd }.to raise_error( 736 | Kitchen::ActionFailed, /^Could not find Vagrantfile template/ 737 | ) 738 | end 739 | 740 | it "runs the pre create command, if set" do 741 | config[:pre_create_command] = "echo heya" 742 | expect(driver).to receive(:run_command).with("echo heya", any_args) 743 | 744 | cmd 745 | end 746 | 747 | it "runs vagrant up with --no-provision if :provision is falsey" do 748 | config[:provision] = false 749 | expect(driver).to receive(:run_command) 750 | .with("vagrant up --no-provision --provider virtualbox", any_args) 751 | 752 | cmd 753 | end 754 | 755 | it "runs vagrant up without --no-provision if :provision is truthy" do 756 | config[:provision] = true 757 | expect(driver).to receive(:run_command) 758 | .with("vagrant up --provider virtualbox", any_args) 759 | 760 | cmd 761 | end 762 | 763 | it "runs vagrant up with a custom provider if :provider is set" do 764 | config[:provider] = "bananas" 765 | expect(driver).to receive(:run_command) 766 | .with("vagrant up --no-provision --provider bananas", any_args) 767 | 768 | cmd 769 | end 770 | 771 | describe "for state" do 772 | 773 | context "for non-WinRM-based transports" do 774 | 775 | let(:output) do 776 | <<-OUTPUT.gsub(/^ {10}/, "") 777 | Host hehe 778 | HostName 192.168.32.64 779 | User vagrant 780 | Port 2022 781 | UserKnownHostsFile /dev/null 782 | StrictHostKeyChecking no 783 | PasswordAuthentication no 784 | IdentityFile /path/to/private_key 785 | IdentitiesOnly yes 786 | LogLevel FATAL 787 | OUTPUT 788 | end 789 | 790 | before do 791 | allow(transport).to receive(:name).and_return("Coolness") 792 | allow(driver).to receive(:run_command) 793 | .with("vagrant ssh-config", any_args).and_return(output) 794 | end 795 | 796 | it "sets :hostname from ssh-config" do 797 | cmd 798 | 799 | expect(state).to include(hostname: "192.168.32.64") 800 | end 801 | 802 | it "sets :port from ssh-config" do 803 | cmd 804 | 805 | expect(state).to include(port: "2022") 806 | end 807 | 808 | it "sets :username from ssh-config" do 809 | cmd 810 | 811 | expect(state).to include(username: "vagrant") 812 | end 813 | 814 | it "does not set :password by default" do 815 | cmd 816 | 817 | expect(state.keys).to_not include(:password) 818 | end 819 | 820 | it "sets :password if Password is in ssh-config" do 821 | output.concat(" Password yep\n") 822 | cmd 823 | 824 | expect(state).to include(password: "yep") 825 | end 826 | 827 | it "sets :ssh_key from ssh-config" do 828 | cmd 829 | 830 | expect(state).to include(ssh_key: "/path/to/private_key") 831 | end 832 | 833 | it "does not set :proxy_command by default" do 834 | cmd 835 | 836 | expect(state.keys).to_not include(:proxy_command) 837 | end 838 | 839 | it "sets :proxy_command if ProxyCommand is in ssh-config" do 840 | output.concat(" ProxyCommand echo proxy\n") 841 | cmd 842 | 843 | expect(state).to include(proxy_command: "echo proxy") 844 | end 845 | end 846 | 847 | context "for WinRM-based transports" do 848 | 849 | let(:output) do 850 | <<-OUTPUT.gsub(/^ {10}/, "") 851 | Host hehe 852 | HostName 192.168.32.64 853 | User vagrant 854 | Password yep 855 | Port 9999 856 | RDPPort 5555 857 | OUTPUT 858 | end 859 | 860 | before do 861 | allow(transport).to receive(:name).and_return("WinRM") 862 | allow(driver).to receive(:run_command) 863 | .with("vagrant winrm-config", any_args).and_return(output) 864 | end 865 | 866 | it "sets :hostname from winrm-config" do 867 | cmd 868 | 869 | expect(state).to include(hostname: "192.168.32.64") 870 | end 871 | 872 | it "sets :port from winrm-config" do 873 | cmd 874 | 875 | expect(state).to include(port: "9999") 876 | end 877 | 878 | it "sets :username from winrm-config" do 879 | cmd 880 | 881 | expect(state).to include(username: "vagrant") 882 | end 883 | 884 | it "sets :password from winrm-config" do 885 | cmd 886 | 887 | expect(state).to include(password: "yep") 888 | end 889 | 890 | it "sets :rdp_port from winrm-config" do 891 | cmd 892 | 893 | expect(state).to include(rdp_port: "5555") 894 | end 895 | end 896 | end 897 | 898 | it "logs a message on info level" do 899 | cmd 900 | 901 | expect(logged_output.string).to match( 902 | /I, .+ INFO -- : Vagrant instance \ created\.$/ 903 | ) 904 | end 905 | 906 | describe "box outdated check" do 907 | it "warns when a newer box version is available" do 908 | outdated_output = <<-OUTPUT 909 | Checking if box 'bento/ubuntu-20.04' version '202112.19.0' is up to date... 910 | A newer version of the box 'bento/ubuntu-20.04' for provider 'virtualbox' is 911 | available! You currently have version '202112.19.0'. The latest is version 912 | '202401.31.0'. 913 | OUTPUT 914 | 915 | # Stub the run_command to return different outputs for different commands 916 | allow(driver).to receive(:run_command) do |cmd, options| 917 | case cmd 918 | when /vagrant box outdated/ 919 | outdated_output 920 | else 921 | "" 922 | end 923 | end 924 | 925 | cmd 926 | 927 | expect(logged_output.string).to match( 928 | /WARN -- : A new version of the 'fooos-99' box is available!/ 929 | ) 930 | expect(logged_output.string).to match( 931 | /Run `vagrant box update --box fooos-99` to update\./ 932 | ) 933 | end 934 | 935 | it "does not warn when box is up to date" do 936 | uptodate_output = <<-OUTPUT 937 | Checking if box 'bento/ubuntu-20.04' version '202401.31.0' is up to date... 938 | You're running the latest version of this box. 939 | OUTPUT 940 | 941 | # Stub the run_command to return different outputs for different commands 942 | allow(driver).to receive(:run_command) do |cmd, options| 943 | case cmd 944 | when /vagrant box outdated/ 945 | uptodate_output 946 | else 947 | "" 948 | end 949 | end 950 | 951 | cmd 952 | 953 | expect(logged_output.string).to_not match( 954 | /A new version of the 'fooos-99' box is available!/ 955 | ) 956 | end 957 | 958 | it "does not check when box_auto_update is enabled" do 959 | config[:box_auto_update] = "vagrant box update --box fooos-99" 960 | 961 | # Verify that outdated check is not called 962 | allow(driver).to receive(:run_command) do |cmd, options| 963 | if cmd.is_a?(String) && cmd.include?("vagrant box outdated") 964 | raise "Should not call vagrant box outdated when box_auto_update is enabled" 965 | end 966 | "" 967 | end 968 | 969 | # Should not raise an error 970 | expect { cmd }.to_not raise_error 971 | end 972 | 973 | it "handles errors gracefully when box is not yet installed" do 974 | # Stub the run_command to raise an error for outdated check 975 | allow(driver).to receive(:run_command) do |cmd, options| 976 | if cmd.include?("vagrant box outdated") 977 | raise Kitchen::ShellOut::ShellCommandFailed.new("Box not found") 978 | end 979 | "" 980 | end 981 | 982 | # Should not raise an error 983 | expect { cmd }.to_not raise_error 984 | 985 | expect(logged_output.string).to match( 986 | /DEBUG -- : Unable to check if box is outdated/ 987 | ) 988 | end 989 | end 990 | end 991 | 992 | describe "#destroy" do 993 | 994 | let(:cmd) { driver.destroy(state) } 995 | 996 | let(:vagrant_root) do 997 | File.join(%W{ 998 | #{@dir} .kitchen kitchen-vagrant suitey-fooos-99 999 | }) 1000 | end 1001 | 1002 | before do 1003 | @dir = Dir.mktmpdir("kitchen_root") 1004 | config[:kitchen_root] = @dir 1005 | 1006 | allow(driver).to receive(:run_command).and_return("") 1007 | with_modern_vagrant 1008 | 1009 | FileUtils.mkdir_p(vagrant_root) 1010 | state[:hostname] = "hosta" 1011 | end 1012 | 1013 | after do 1014 | FileUtils.remove_entry_secure(@dir) 1015 | end 1016 | 1017 | it "logs a message on debug level for creating the Vagrantfile" do 1018 | cmd 1019 | 1020 | expect(logged_output.string).to match( 1021 | /^D, .+ DEBUG -- : Creating Vagrantfile for \ / 1022 | ) 1023 | end 1024 | 1025 | it "logs the Vagrantfile contents on debug level" do 1026 | cmd 1027 | 1028 | expect(debug_lines).to match(Regexp.new(<<-REGEXP.gsub(/^ {8}/, ""))) 1029 | ------------ 1030 | Vagrant.configure\("2"\) do \|c\| 1031 | .* 1032 | end 1033 | ------------ 1034 | REGEXP 1035 | end 1036 | 1037 | it "does not run vagrant destroy if :hostname is not present in state" do 1038 | state.delete(:hostname) 1039 | expect(driver).to_not receive(:run_command) 1040 | .with("vagrant destroy -f", any_args) 1041 | 1042 | cmd 1043 | end 1044 | 1045 | it "closes the transport connection" do 1046 | connection = double(Kitchen::Transport::Base::Connection) 1047 | allow(transport).to receive(:connection).with(state) { connection } 1048 | expect(connection).to receive(:close) 1049 | 1050 | cmd 1051 | end 1052 | 1053 | it "runs vagrant destroy" do 1054 | expect(driver).to receive(:run_command) 1055 | .with("vagrant destroy -f", any_args) 1056 | 1057 | cmd 1058 | end 1059 | 1060 | it "deletes the vagrant root directory" do 1061 | expect(File.directory?(vagrant_root)).to eq(true) 1062 | cmd 1063 | expect(File.directory?(vagrant_root)).to eq(false) 1064 | end 1065 | 1066 | it "logs a message on info level" do 1067 | cmd 1068 | 1069 | expect(logged_output.string).to match( 1070 | /I, .+ INFO -- : Vagrant instance \ destroyed\.$/ 1071 | ) 1072 | end 1073 | 1074 | it "deletes :hostname from state" do 1075 | cmd 1076 | 1077 | expect(state.keys).to_not include(:hostname) 1078 | end 1079 | end 1080 | 1081 | describe "Vagrantfile" do 1082 | 1083 | let(:cmd) { driver.create(state) } 1084 | 1085 | let(:vagrant_root) do 1086 | File.join(%W{ 1087 | #{@dir} .kitchen kitchen-vagrant suitey-fooos-99 1088 | }) 1089 | end 1090 | 1091 | before do 1092 | @dir = Dir.mktmpdir("kitchen_root") 1093 | config[:kitchen_root] = @dir 1094 | 1095 | allow(driver).to receive(:run_command).and_return("") 1096 | with_modern_vagrant 1097 | end 1098 | 1099 | after do 1100 | FileUtils.remove_entry_secure(@dir) 1101 | end 1102 | 1103 | it "disables the vagrant-berkshelf plugin is present" do 1104 | cmd 1105 | 1106 | expect(vagrantfile).to match(regexify( 1107 | "c.berkshelf.enabled = false " \ 1108 | "if Vagrant.has_plugin?(\"vagrant-berkshelf\")" 1109 | )) 1110 | end 1111 | 1112 | it "sets no cache.scope if missing" do 1113 | config[:cachier] = nil 1114 | cmd 1115 | 1116 | expect(vagrantfile).to_not match(regexify(%{c.cache.scope}, :partial)) 1117 | end 1118 | 1119 | it "sets cache.scope to :box if :cachier is set" do 1120 | config[:cachier] = true 1121 | cmd 1122 | 1123 | expect(vagrantfile).to match(regexify(%{c.cache.scope = :box})) 1124 | end 1125 | 1126 | it "sets cache.scope if :cachier is set to a custom value" do 1127 | config[:cachier] = ":machine" 1128 | cmd 1129 | 1130 | expect(vagrantfile).to match(regexify(%{c.cache.scope = :machine})) 1131 | end 1132 | 1133 | it "sets the vm.box" do 1134 | cmd 1135 | 1136 | expect(vagrantfile).to match(regexify(%{c.vm.box = "fooos-99"})) 1137 | end 1138 | 1139 | it "sets the vm.hostname" do 1140 | config[:vm_hostname] = "charlie" 1141 | cmd 1142 | 1143 | expect(vagrantfile).to match(regexify(%{c.vm.hostname = "charlie"})) 1144 | end 1145 | 1146 | it "disables the /vagrant synced folder by default" do 1147 | cmd 1148 | 1149 | expect(vagrantfile).to match(regexify( 1150 | %{c.vm.synced_folder ".", "/vagrant", disabled: true} 1151 | )) 1152 | end 1153 | 1154 | it "creates an empty provider block by default" do 1155 | config[:provider] = "wowza" 1156 | cmd 1157 | 1158 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {6}/, "").chomp)) 1159 | c.vm.provider :wowza do |p| 1160 | end 1161 | RUBY 1162 | end 1163 | 1164 | it "requires no Vagrantfiles by default" do 1165 | cmd 1166 | 1167 | expect(vagrantfile).to_not match(regexify("require")) 1168 | end 1169 | 1170 | it "requires each entry in :vagranfiles" do 1171 | config[:vagrantfiles] = %w{/a /b /c} 1172 | cmd 1173 | 1174 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1175 | load "/a" 1176 | load "/b" 1177 | load "/c" 1178 | RUBY 1179 | end 1180 | 1181 | it "sets no vm.box_url if missing" do 1182 | config[:box_url] = nil 1183 | cmd 1184 | 1185 | expect(vagrantfile).to_not match(regexify(%{c.vm.box_url}, :partial)) 1186 | end 1187 | 1188 | it "sets vm.box_url if :box_url is set" do 1189 | config[:box_url] = "dat.url" 1190 | cmd 1191 | 1192 | expect(vagrantfile).to match(regexify(%{c.vm.box_url = "dat.url"})) 1193 | end 1194 | 1195 | it "sets no vm.box_version if missing" do 1196 | config[:box_version] = nil 1197 | cmd 1198 | 1199 | expect(vagrantfile).to_not match(regexify(%{c.vm.box_version}, :partial)) 1200 | end 1201 | 1202 | it "sets vm.box_version if :box_version is set" do 1203 | config[:box_version] = "a.b.c" 1204 | cmd 1205 | 1206 | expect(vagrantfile).to match(regexify(%{c.vm.box_version = "a.b.c"})) 1207 | end 1208 | 1209 | it "sets no vm.boot_timeout if missing" do 1210 | config[:boot_timeout] = nil 1211 | cmd 1212 | 1213 | expect(vagrantfile).to_not match(regexify(%{c.vm.boot_timeout}, :partial)) 1214 | end 1215 | 1216 | it "sets no vm.boot_timeout if :boot_timeout is set" do 1217 | config[:boot_timeout] = 600 1218 | cmd 1219 | 1220 | expect(vagrantfile).to match( 1221 | regexify(%{c.vm.boot_timeout = 600}, :partial) 1222 | ) 1223 | end 1224 | 1225 | it "sets no vm.box_check_update if missing" do 1226 | config[:box_check_update] = nil 1227 | cmd 1228 | 1229 | expect(vagrantfile).to_not match( 1230 | regexify(%{c.vm.box_check_update}, :partial) 1231 | ) 1232 | end 1233 | 1234 | it "sets vm.box_check_update to false if :box_check_update is false" do 1235 | config[:box_check_update] = false 1236 | cmd 1237 | 1238 | expect(vagrantfile).to match(regexify(%{c.vm.box_check_update = false})) 1239 | end 1240 | 1241 | it "sets no vm.box_download_insecure if missing" do 1242 | config[:box_download_insecure] = nil 1243 | cmd 1244 | 1245 | expect(vagrantfile).to_not match( 1246 | regexify(%{c.vm.box_download_insecure}, :partial) 1247 | ) 1248 | end 1249 | 1250 | it "sets vm.box_download_insecure to false if :box_download_insecure is false" do 1251 | config[:box_download_insecure] = false 1252 | cmd 1253 | 1254 | expect(vagrantfile).to match(regexify(%{c.vm.box_download_insecure = "false"})) 1255 | end 1256 | 1257 | it "sets vm.box_download_insecure if :box_download_insecure is set" do 1258 | config[:box_download_insecure] = "um" 1259 | cmd 1260 | 1261 | expect( 1262 | vagrantfile 1263 | ).to match(regexify(%{c.vm.box_download_insecure = "um"})) 1264 | end 1265 | 1266 | it "sets no vm.communicator if missing" do 1267 | config[:communicator] = nil 1268 | cmd 1269 | 1270 | expect(vagrantfile).to_not match(regexify(%{c.vm.communicator}, :partial)) 1271 | end 1272 | 1273 | it "sets vm.communicator if :communicator is set" do 1274 | config[:communicator] = "wat" 1275 | cmd 1276 | 1277 | expect(vagrantfile).to match(regexify(%{c.vm.communicator = "wat"})) 1278 | end 1279 | 1280 | it "sets no vm.guest if missing" do 1281 | config[:guest] = nil 1282 | cmd 1283 | 1284 | expect(vagrantfile).to_not match(regexify(%{c.vm.guest}, :partial)) 1285 | end 1286 | 1287 | it "sets vm.guest if :guest is set" do 1288 | config[:guest] = "mac" 1289 | cmd 1290 | 1291 | expect(vagrantfile).to match(regexify(%{c.vm.guest = "mac"})) 1292 | end 1293 | 1294 | it "sets no ssh.username if missing" do 1295 | config[:username] = nil 1296 | cmd 1297 | 1298 | expect(vagrantfile).to_not match(regexify(%{c.ssh.username}, :partial)) 1299 | end 1300 | 1301 | it "sets ssh.username if :username is set" do 1302 | config[:username] = "jdoe" 1303 | cmd 1304 | 1305 | expect(vagrantfile).to match(regexify(%{c.ssh.username = "jdoe"})) 1306 | end 1307 | 1308 | it "sets no ssh.password if missing" do 1309 | config[:password] = nil 1310 | cmd 1311 | 1312 | expect(vagrantfile).to_not match(regexify(%{c.ssh.password}, :partial)) 1313 | end 1314 | 1315 | it "sets ssh.password if :password is set" do 1316 | config[:password] = "okay" 1317 | cmd 1318 | 1319 | expect(vagrantfile).to match(regexify(%{c.ssh.password = "okay"})) 1320 | end 1321 | 1322 | it "sets communicator.username if :communicator and :username are set" do 1323 | config[:communicator] = "wat" 1324 | config[:username] = "jdoe" 1325 | cmd 1326 | 1327 | expect(vagrantfile).to match(regexify(%{c.wat.username = "jdoe"})) 1328 | end 1329 | 1330 | it "sets communicator.password if :communicator and :password are set" do 1331 | config[:communicator] = "wat" 1332 | config[:password] = "okay" 1333 | cmd 1334 | 1335 | expect(vagrantfile).to match(regexify(%{c.wat.password = "okay"})) 1336 | end 1337 | 1338 | it "sets no ssh.private_key_path if missing" do 1339 | config[:ssh_key] = nil 1340 | cmd 1341 | 1342 | expect(vagrantfile).to_not match( 1343 | regexify(%{c.ssh.private_key_path}, :partial) 1344 | ) 1345 | end 1346 | 1347 | it "sets ssh.private_key_path if :ssh_key is set" do 1348 | config[:ssh_key] = "okay" 1349 | cmd 1350 | 1351 | expect(vagrantfile).to match(regexify(%{c.ssh.private_key_path = "okay"})) 1352 | end 1353 | 1354 | it "adds a vm.ssh line for each key/value pair in :ssh" do 1355 | config[:ssh] = { 1356 | username: %{jdoe}, 1357 | password: %{secret}, 1358 | private_key_path: %{/key}, 1359 | insert_key: false, 1360 | } 1361 | cmd 1362 | 1363 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {6}/, "").chomp)) 1364 | c.ssh.username = "jdoe" 1365 | c.ssh.password = "secret" 1366 | c.ssh.private_key_path = "/key" 1367 | c.ssh.insert_key = false 1368 | RUBY 1369 | end 1370 | 1371 | it "sets ssh.guest_port if specified in :ssh config" do 1372 | config[:ssh] = { guest_port: 444 } 1373 | cmd 1374 | 1375 | expect(vagrantfile).to match(regexify(%{c.ssh.guest_port = 444})) 1376 | end 1377 | 1378 | it "adds a vm.network line for each element in :network" do 1379 | config[:network] = [ 1380 | ["forwarded_port", { guest: 80, host: 8080 }], 1381 | ["private_network", { ip: "192.168.33.33" }], 1382 | ] 1383 | cmd 1384 | 1385 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {6}/, "").chomp)) 1386 | c.vm.network(:forwarded_port, guest: 80, host: 8080) 1387 | c.vm.network(:private_network, ip: "192.168.33.33") 1388 | RUBY 1389 | end 1390 | 1391 | it "adds a vm.synced_folder line for each element in :synced_folders" do 1392 | config[:synced_folders] = [ 1393 | ["/a/b", "/opt/instance_data", "nil"], 1394 | ["/host_path", "/vm_path", "create: true, type: :nfs"], 1395 | ] 1396 | cmd 1397 | 1398 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {6}/, "").chomp)) 1399 | c.vm.synced_folder "/a/b", "/opt/instance_data", nil 1400 | c.vm.synced_folder "/host_path", "/vm_path", create: true, type: :nfs 1401 | RUBY 1402 | end 1403 | 1404 | it "vm.synced_folder scapes the back slashes for Windows paths" do 1405 | config[:synced_folders] = [ 1406 | ["/a/b", "C:\\opt\\instance_data", "nil"], 1407 | ["Z:\\host_path", "/vm_path", "create: true"], 1408 | ] 1409 | cmd 1410 | 1411 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {6}/, "").chomp)) 1412 | c.vm.synced_folder "/a/b", "C:\\\\opt\\\\instance_data", nil 1413 | c.vm.synced_folder "Z:\\\\host_path", "/vm_path", create: true 1414 | RUBY 1415 | end 1416 | 1417 | context "for virtualbox provider" do 1418 | 1419 | before { config[:provider] = "virtualbox" } 1420 | 1421 | it "sets :name for virtualbox GUI" do 1422 | cmd 1423 | 1424 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1425 | c.vm.provider :virtualbox do |p| 1426 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1427 | p.customize ["modifyvm", :id, "--audio", "none"] 1428 | end 1429 | RUBY 1430 | end 1431 | 1432 | it "disables audio by default" do 1433 | cmd 1434 | 1435 | expect(vagrantfile).to include(%{p.customize ["modifyvm", :id, "--audio", "none"]}) 1436 | end 1437 | 1438 | it "allows audio to be enabled with :customize" do 1439 | config[:customize] = { 1440 | audio: "pulse", 1441 | } 1442 | cmd 1443 | 1444 | expect(vagrantfile).to include(%{p.customize ["modifyvm", :id, "--audio", "pulse"]}) 1445 | expect(vagrantfile).not_to include(%{p.customize ["modifyvm", :id, "--audio", "none"]}) 1446 | end 1447 | 1448 | it "adds a line for each element in :customize" do 1449 | config[:customize] = { 1450 | a_key: "some value", 1451 | something: "else", 1452 | } 1453 | cmd 1454 | 1455 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1456 | c.vm.provider :virtualbox do |p| 1457 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1458 | p.customize ["modifyvm", :id, "--audio", "none"] 1459 | p.customize ["modifyvm", :id, "--a_key", "some value"] 1460 | p.customize ["modifyvm", :id, "--something", "else"] 1461 | end 1462 | RUBY 1463 | end 1464 | 1465 | it "does not set :gui to nil" do 1466 | config[:gui] = nil 1467 | cmd 1468 | 1469 | expect(vagrantfile).to_not match(regexify(%{p.gui = }, :partial)) 1470 | end 1471 | 1472 | it "sets :gui to false if set" do 1473 | config[:gui] = false 1474 | cmd 1475 | 1476 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1477 | c.vm.provider :virtualbox do |p| 1478 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1479 | p.gui = false 1480 | p.customize ["modifyvm", :id, "--audio", "none"] 1481 | end 1482 | RUBY 1483 | end 1484 | 1485 | it "sets :gui to true if set" do 1486 | config[:gui] = true 1487 | cmd 1488 | 1489 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1490 | c.vm.provider :virtualbox do |p| 1491 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1492 | p.gui = true 1493 | p.customize ["modifyvm", :id, "--audio", "none"] 1494 | end 1495 | RUBY 1496 | end 1497 | 1498 | it "does not set :linked_clone to nil" do 1499 | config[:linked_clone] = nil 1500 | cmd 1501 | 1502 | expect(vagrantfile).to_not match( 1503 | regexify(%{p.linked_clone = }, :partial) 1504 | ) 1505 | end 1506 | 1507 | it "sets :linked_clone to false if set" do 1508 | config[:linked_clone] = false 1509 | cmd 1510 | 1511 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1512 | c.vm.provider :virtualbox do |p| 1513 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1514 | p.linked_clone = false 1515 | p.customize ["modifyvm", :id, "--audio", "none"] 1516 | end 1517 | RUBY 1518 | end 1519 | 1520 | it "sets :linked_clone to true if set" do 1521 | config[:linked_clone] = true 1522 | cmd 1523 | 1524 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1525 | c.vm.provider :virtualbox do |p| 1526 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1527 | p.linked_clone = true 1528 | p.customize ["modifyvm", :id, "--audio", "none"] 1529 | end 1530 | RUBY 1531 | end 1532 | 1533 | it "add line for single createhd in :customize" do 1534 | config[:customize] = { 1535 | createhd: { 1536 | filename: "./d1.vmdk", 1537 | size: 10 * 1024, 1538 | }, 1539 | } 1540 | cmd 1541 | 1542 | expect(vagrantfile).to include(<<-RUBY.gsub(/^ {8}/, "").chomp) 1543 | unless File.file?("./d1.vmdk") 1544 | RUBY 1545 | 1546 | expect(vagrantfile).to include(<<-RUBY.gsub(/^ {8}/, "").chomp) 1547 | p.customize ["createhd", "--filename", "./d1.vmdk", "--size", 10240] 1548 | RUBY 1549 | end 1550 | 1551 | it "adds lines for multiple createhd in :customize" do 1552 | config[:customize] = { 1553 | createhd: [ 1554 | { 1555 | filename: "./d1.vmdk", 1556 | size: 10 * 1024, 1557 | }, 1558 | { 1559 | filename: "./d2.vmdk", 1560 | size: 20 * 1024, 1561 | }, 1562 | ], 1563 | } 1564 | cmd 1565 | 1566 | expect(vagrantfile).to include(<<-RUBY.gsub(/^ {8}/, "").chomp) 1567 | unless File.file?("./d1.vmdk") 1568 | RUBY 1569 | 1570 | expect(vagrantfile).to include(<<-RUBY.gsub(/^ {8}/, "").chomp) 1571 | p.customize ["createhd", "--filename", "./d1.vmdk", "--size", 10240] 1572 | RUBY 1573 | 1574 | expect(vagrantfile).to include(<<-RUBY.gsub(/^ {8}/, "").chomp) 1575 | unless File.file?("./d2.vmdk") 1576 | RUBY 1577 | 1578 | expect(vagrantfile).to include(<<-RUBY.gsub(/^ {8}/, "").chomp) 1579 | p.customize ["createhd", "--filename", "./d2.vmdk", "--size", 20480] 1580 | RUBY 1581 | end 1582 | 1583 | it "adds lines for single storagectl in :customize" do 1584 | config[:customize] = { 1585 | storagectl: { 1586 | name: "Custom SATA Controller", 1587 | add: "sata", 1588 | controller: "IntelAHCI", 1589 | portcount: 4, 1590 | }, 1591 | } 1592 | cmd 1593 | 1594 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1595 | c.vm.provider :virtualbox do |p| 1596 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1597 | p.customize ["modifyvm", :id, "--audio", "none"] 1598 | p.customize ["storagectl", :id, "--name", "Custom SATA Controller", "--add", "sata", "--controller", "IntelAHCI", "--portcount", 4] 1599 | end 1600 | RUBY 1601 | end 1602 | 1603 | it "adds lines for multiple storagectl in :customize" do 1604 | config[:customize] = { 1605 | storagectl: [ 1606 | { 1607 | name: "Custom SATA Controller", 1608 | add: "sata", 1609 | controller: "IntelAHCI", 1610 | }, 1611 | { 1612 | name: "Custom SATA Controller", 1613 | portcount: 4, 1614 | }, 1615 | ], 1616 | } 1617 | cmd 1618 | 1619 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1620 | c.vm.provider :virtualbox do |p| 1621 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1622 | p.customize ["modifyvm", :id, "--audio", "none"] 1623 | p.customize ["storagectl", :id, "--name", "Custom SATA Controller", "--add", "sata", "--controller", "IntelAHCI"] 1624 | p.customize ["storagectl", :id, "--name", "Custom SATA Controller", "--portcount", 4] 1625 | end 1626 | RUBY 1627 | end 1628 | 1629 | it "adds lines for single storageattach in :customize" do 1630 | config[:customize] = { 1631 | storageattach: { 1632 | type: "hdd", 1633 | port: 1, 1634 | }, 1635 | } 1636 | cmd 1637 | 1638 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1639 | c.vm.provider :virtualbox do |p| 1640 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1641 | p.customize ["modifyvm", :id, "--audio", "none"] 1642 | p.customize ["storageattach", :id, "--type", "hdd", "--port", 1] 1643 | end 1644 | RUBY 1645 | end 1646 | 1647 | it "adds lines for multiple storageattach in :customize" do 1648 | config[:customize] = { 1649 | storageattach: [ 1650 | { 1651 | storagectl: "SATA Controller", 1652 | port: 1, 1653 | device: 0, 1654 | type: "hdd", 1655 | medium: "./d1.vmdk", 1656 | }, 1657 | { 1658 | storagectl: "SATA Controller", 1659 | port: 1, 1660 | device: 1, 1661 | type: "hdd", 1662 | medium: "./d2.vmdk", 1663 | }, 1664 | ], 1665 | } 1666 | cmd 1667 | 1668 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1669 | c.vm.provider :virtualbox do |p| 1670 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1671 | p.customize ["modifyvm", :id, "--audio", "none"] 1672 | p.customize ["storageattach", :id, "--storagectl", "SATA Controller", "--port", 1, "--device", 0, "--type", "hdd", "--medium", "./d1.vmdk"] 1673 | p.customize ["storageattach", :id, "--storagectl", "SATA Controller", "--port", 1, "--device", 1, "--type", "hdd", "--medium", "./d2.vmdk"] 1674 | end 1675 | RUBY 1676 | end 1677 | 1678 | it "adds a line for cpuidset in :customize" do 1679 | config[:customize] = { 1680 | cpuidset: %w{00000001 00000002}, 1681 | } 1682 | cmd 1683 | 1684 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1685 | c.vm.provider :virtualbox do |p| 1686 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1687 | p.customize ["modifyvm", :id, "--audio", "none"] 1688 | p.customize ["modifyvm", :id, "--cpuidset", "00000001", "00000002"] 1689 | end 1690 | RUBY 1691 | end 1692 | 1693 | it "adds lines for multiple setextradata in :customize and quotes only string values" do 1694 | config[:customize] = { 1695 | setextradata: { 1696 | "VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC": 0, 1697 | "VBoxInternal/Devices/efi/0/Config/DmiSystemVersion": "1.0" 1698 | }, 1699 | } 1700 | cmd 1701 | 1702 | expect(vagrantfile).to match(Regexp.new(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1703 | c.vm.provider :virtualbox do |p| 1704 | p.name = "kitchen-#{File.basename(config[:kitchen_root])}-suitey-fooos-99-.*" 1705 | p.customize ["modifyvm", :id, "--audio", "none"] 1706 | p.customize ["setextradata", :id, "VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC", 0] 1707 | p.customize ["setextradata", :id, "VBoxInternal/Devices/efi/0/Config/DmiSystemVersion", "1.0"] 1708 | end 1709 | RUBY 1710 | end 1711 | 1712 | end 1713 | 1714 | context "for parallels provider" do 1715 | 1716 | before { config[:provider] = "parallels" } 1717 | 1718 | it "adds a line for each element in :customize" do 1719 | config[:customize] = { 1720 | a_key: "some value", 1721 | something: "else", 1722 | } 1723 | cmd 1724 | 1725 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1726 | c.vm.provider :parallels do |p| 1727 | p.customize ["set", :id, "--a-key", "some value"] 1728 | p.customize ["set", :id, "--something", "else"] 1729 | end 1730 | RUBY 1731 | end 1732 | 1733 | it "adds a short form of :memory and :cpus elements in :customize" do 1734 | config[:customize] = { 1735 | memory: 2048, 1736 | cpus: 4, 1737 | } 1738 | cmd 1739 | 1740 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1741 | c.vm.provider :parallels do |p| 1742 | p.memory = 2048 1743 | p.cpus = 4 1744 | end 1745 | RUBY 1746 | end 1747 | 1748 | it "does not set :linked_clone to nil" do 1749 | config[:linked_clone] = nil 1750 | cmd 1751 | 1752 | expect(vagrantfile).to_not match( 1753 | regexify(%{p.linked_clone = }, :partial) 1754 | ) 1755 | end 1756 | 1757 | it "sets :linked_clone to false if set" do 1758 | config[:linked_clone] = false 1759 | cmd 1760 | 1761 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1762 | c.vm.provider :parallels do |p| 1763 | p.linked_clone = false 1764 | end 1765 | RUBY 1766 | end 1767 | 1768 | it "sets :linked_clone to true if set" do 1769 | config[:linked_clone] = true 1770 | cmd 1771 | 1772 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1773 | c.vm.provider :parallels do |p| 1774 | p.linked_clone = true 1775 | end 1776 | RUBY 1777 | end 1778 | end 1779 | 1780 | context "for rackspace provider" do 1781 | 1782 | before { config[:provider] = "rackspace" } 1783 | 1784 | it "adds a line for each element in :customize" do 1785 | config[:customize] = { 1786 | a_key: "some value", 1787 | something: "else", 1788 | } 1789 | cmd 1790 | 1791 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1792 | c.vm.provider :rackspace do |p| 1793 | p.a_key = "some value" 1794 | p.something = "else" 1795 | end 1796 | RUBY 1797 | end 1798 | end 1799 | 1800 | context "for softlayer provider" do 1801 | 1802 | before { config[:provider] = "softlayer" } 1803 | 1804 | it "adds a line for disk_capacity" do 1805 | config[:customize] = { 1806 | disk_capacity: { 1807 | "0": 25, 1808 | "2": 100, 1809 | }, 1810 | } 1811 | cmd 1812 | 1813 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1814 | c.vm.provider :softlayer do |p| 1815 | p.disk_capacity = {"0": 25, "2": 100} 1816 | end 1817 | RUBY 1818 | end 1819 | 1820 | it "adds a line for each element in :customize" do 1821 | config[:customize] = { 1822 | a_key: "some value", 1823 | something: "else", 1824 | } 1825 | cmd 1826 | 1827 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1828 | c.vm.provider :softlayer do |p| 1829 | p.a_key = "some value" 1830 | p.something = "else" 1831 | end 1832 | RUBY 1833 | end 1834 | end 1835 | 1836 | context "for libvirt provider" do 1837 | 1838 | before { config[:provider] = "libvirt" } 1839 | 1840 | it "adds a line for each element in :customize" do 1841 | config[:customize] = { 1842 | a_key: "some value", 1843 | something: "else", 1844 | a_number_key: 1024, 1845 | } 1846 | cmd 1847 | 1848 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1849 | c.vm.provider :libvirt do |p| 1850 | p.a_key = "some value" 1851 | p.something = "else" 1852 | p.a_number_key = 1024 1853 | end 1854 | RUBY 1855 | end 1856 | 1857 | it "adds a single storage definition in :customize" do 1858 | config[:customize] = { 1859 | storage: ":file, :size => '32G'", 1860 | } 1861 | cmd 1862 | 1863 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1864 | c.vm.provider :libvirt do |p| 1865 | p.storage :file, :size => '32G' 1866 | end 1867 | RUBY 1868 | end 1869 | 1870 | it "adds a line for each additional storage definition in :customize" do 1871 | config[:customize] = { 1872 | storage: [ 1873 | ":file, :size => '1G'", 1874 | ":file, :size => '128G', :bus => 'sata'", 1875 | ":file, :size => '64G', :bus => 'sata'", 1876 | ], 1877 | } 1878 | cmd 1879 | 1880 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1881 | c.vm.provider :libvirt do |p| 1882 | p.storage :file, :size => '1G' 1883 | p.storage :file, :size => '128G', :bus => 'sata' 1884 | p.storage :file, :size => '64G', :bus => 'sata' 1885 | end 1886 | RUBY 1887 | end 1888 | end 1889 | 1890 | context "for lxc provider" do 1891 | 1892 | before { config[:provider] = "lxc" } 1893 | 1894 | it "sets container_name to :machine if set" do 1895 | config[:customize] = { 1896 | container_name: ":machine", 1897 | } 1898 | cmd 1899 | 1900 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1901 | c.vm.provider :lxc do |p| 1902 | p.container_name = :machine 1903 | end 1904 | RUBY 1905 | end 1906 | 1907 | it "sets container_name to another value in quotes if set" do 1908 | config[:customize] = { 1909 | container_name: "beans", 1910 | } 1911 | cmd 1912 | 1913 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1914 | c.vm.provider :lxc do |p| 1915 | p.container_name = "beans" 1916 | end 1917 | RUBY 1918 | end 1919 | 1920 | it "sets backingstore if set" do 1921 | config[:customize] = { 1922 | backingstore: "lvm", 1923 | } 1924 | cmd 1925 | 1926 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1927 | c.vm.provider :lxc do |p| 1928 | p.backingstore = "lvm" 1929 | end 1930 | RUBY 1931 | end 1932 | 1933 | it "sets backingstore_option line for each backingstore_options" do 1934 | config[:customize] = { 1935 | backingstore_options: { 1936 | vgname: "schroots", 1937 | fstype: "xfs", 1938 | }, 1939 | } 1940 | cmd 1941 | 1942 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1943 | c.vm.provider :lxc do |p| 1944 | p.backingstore_option "--vgname", "schroots" 1945 | p.backingstore_option "--fstype", "xfs" 1946 | end 1947 | RUBY 1948 | end 1949 | 1950 | it "sets all other options to customize lines" do 1951 | config[:customize] = { 1952 | cookies: "cream", 1953 | salt: "vinegar", 1954 | } 1955 | cmd 1956 | 1957 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1958 | c.vm.provider :lxc do |p| 1959 | p.customize "cookies", "cream" 1960 | p.customize "salt", "vinegar" 1961 | end 1962 | RUBY 1963 | end 1964 | end 1965 | 1966 | context "for vmware_* providers" do 1967 | 1968 | before { config[:provider] = "vmware_desktop" } 1969 | 1970 | it "does not set :gui to nil" do 1971 | config[:gui] = nil 1972 | cmd 1973 | 1974 | expect(vagrantfile).to_not match(regexify(%{p.gui = }, :partial)) 1975 | end 1976 | 1977 | it "sets :gui to false if set" do 1978 | config[:gui] = false 1979 | cmd 1980 | 1981 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1982 | c.vm.provider :vmware_desktop do |p| 1983 | p.gui = false 1984 | end 1985 | RUBY 1986 | end 1987 | 1988 | it "sets :gui to true if set" do 1989 | config[:gui] = true 1990 | cmd 1991 | 1992 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 1993 | c.vm.provider :vmware_desktop do |p| 1994 | p.gui = true 1995 | end 1996 | RUBY 1997 | end 1998 | 1999 | it "adds a line for each element in :customize" do 2000 | config[:customize] = { 2001 | a_key: "some value", 2002 | something: "else", 2003 | } 2004 | cmd 2005 | 2006 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2007 | c.vm.provider :vmware_desktop do |p| 2008 | p.vmx["a_key"] = "some value" 2009 | p.vmx["something"] = "else" 2010 | end 2011 | RUBY 2012 | end 2013 | 2014 | it "converts :memory into :memsize" do 2015 | config[:customize] = { 2016 | memory: "222", 2017 | } 2018 | cmd 2019 | 2020 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2021 | c.vm.provider :vmware_desktop do |p| 2022 | p.vmx["memsize"] = "222" 2023 | end 2024 | RUBY 2025 | end 2026 | 2027 | it "skips :memory if key :memsize exists" do 2028 | config[:customize] = { 2029 | memory: "222", 2030 | memsize: "444", 2031 | } 2032 | cmd 2033 | 2034 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2035 | c.vm.provider :vmware_desktop do |p| 2036 | p.vmx["memsize"] = "444" 2037 | end 2038 | RUBY 2039 | end 2040 | 2041 | it "converts :cpus into :numvcpus" do 2042 | config[:customize] = { 2043 | cpus: "2", 2044 | } 2045 | cmd 2046 | 2047 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2048 | c.vm.provider :vmware_desktop do |p| 2049 | p.vmx["numvcpus"] = "2" 2050 | end 2051 | RUBY 2052 | end 2053 | 2054 | it "skips :cpus if key :numvcpus exists" do 2055 | config[:customize] = { 2056 | cpus: "2", 2057 | numvcpus: "4", 2058 | } 2059 | cmd 2060 | 2061 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2062 | c.vm.provider :vmware_desktop do |p| 2063 | p.vmx["numvcpus"] = "4" 2064 | end 2065 | RUBY 2066 | end 2067 | end 2068 | 2069 | context "for managed provider" do 2070 | 2071 | before { config[:provider] = "managed" } 2072 | 2073 | it "adds a line a server" do 2074 | config[:customize] = { 2075 | server: "my_server", 2076 | } 2077 | cmd 2078 | 2079 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2080 | c.vm.provider :managed do |p| 2081 | p.server = "my_server" 2082 | end 2083 | RUBY 2084 | end 2085 | 2086 | it "ignores all other key types than server" do 2087 | config[:customize] = { 2088 | other: "stuff", 2089 | is: "ignored", 2090 | } 2091 | cmd 2092 | 2093 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2094 | c.vm.provider :managed do |p| 2095 | end 2096 | RUBY 2097 | end 2098 | end 2099 | 2100 | context "for openstack provider" do 2101 | 2102 | before { config[:provider] = "openstack" } 2103 | 2104 | it "adds a line for each element in :customize" do 2105 | config[:customize] = { 2106 | key1: "some string value", 2107 | key2: 22, 2108 | key3: false, 2109 | } 2110 | cmd 2111 | 2112 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2113 | c.vm.provider :openstack do |p| 2114 | p.key1 = "some string value" 2115 | p.key2 = 22 2116 | p.key3 = false 2117 | end 2118 | RUBY 2119 | end 2120 | end 2121 | 2122 | context "for cloudstack provider" do 2123 | 2124 | before { config[:provider] = "cloudstack" } 2125 | 2126 | it "adds a line for each element in :customize" do 2127 | config[:customize] = { 2128 | a_key: "some value", 2129 | something: "else", 2130 | } 2131 | cmd 2132 | 2133 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2134 | c.vm.provider :cloudstack do |p| 2135 | p.a_key = "some value" 2136 | p.something = "else" 2137 | end 2138 | RUBY 2139 | end 2140 | 2141 | it "builds an array of hashes for firewall rules in :customize" do 2142 | config[:customize] = { 2143 | firewall_rules: [ 2144 | { 2145 | ipaddress: "A.A.A.A", 2146 | cidrlist: "B.B.B.B/24", 2147 | protocol: "tcp", 2148 | startport: 2222, 2149 | endport: 2222, 2150 | }, 2151 | { 2152 | ipaddress: "C.C.C.C", 2153 | cidrlist: "D.D.D.D/32", 2154 | protocol: "tcp", 2155 | startport: 80, 2156 | endport: 81, 2157 | }, 2158 | ], 2159 | } 2160 | cmd 2161 | 2162 | expectation = <<-RUBY.gsub(/^ {8}/, "").gsub(/,\n /, ",").chomp 2163 | c.vm.provider :cloudstack do |p| 2164 | p.firewall_rules = [{ipaddress: "A.A.A.A", cidrlist: "B.B.B.B/24", 2165 | protocol: "tcp", startport: 2222, 2166 | endport: 2222}, {ipaddress: "C.C.C.C", cidrlist: "D.D.D.D/32", 2167 | protocol: "tcp", startport: 80, endport: 81}] 2168 | end 2169 | RUBY 2170 | 2171 | expect(vagrantfile).to match(regexify(expectation)) 2172 | end 2173 | 2174 | it "builds an array for security group ids in :customize" do 2175 | config[:customize] = { 2176 | security_group_ids: %w{aaaa-bbbb-cccc-dddd 2177 | 1111-2222-3333-4444}, 2178 | } 2179 | cmd 2180 | 2181 | expectation = <<-RUBY.gsub(/^ {8}/, "").gsub(/,\n /, ",").chomp 2182 | c.vm.provider :cloudstack do |p| 2183 | p.security_group_ids = ["aaaa-bbbb-cccc-dddd", 2184 | "1111-2222-3333-4444"] 2185 | end 2186 | RUBY 2187 | 2188 | expect(vagrantfile).to match(regexify(expectation)) 2189 | end 2190 | 2191 | it "builds an array for security group names in :customize" do 2192 | config[:customize] = { 2193 | security_group_names: %w{min_fantastiska_security_group 2194 | another_security_group}, 2195 | } 2196 | cmd 2197 | 2198 | expectation = <<-RUBY.gsub(/^ {8}/, "").gsub(/,\n /, ",").chomp 2199 | c.vm.provider :cloudstack do |p| 2200 | p.security_group_names = ["min_fantastiska_security_group", 2201 | "another_security_group"] 2202 | end 2203 | RUBY 2204 | 2205 | expect(vagrantfile).to match(regexify(expectation)) 2206 | end 2207 | 2208 | it "builds an array of hashes for security groups in :customize" do 2209 | config[:customize] = { 2210 | security_groups: [ 2211 | { 2212 | name: "Awesome_security_group", 2213 | description: "Created from the Vagrantfile", 2214 | rules: [ 2215 | { 2216 | type: "ingress", 2217 | protocol: "TCP", 2218 | startport: 22, 2219 | endport: 22, 2220 | cidrlist: "0.0.0.0/0", 2221 | }, 2222 | { 2223 | type: "egress", 2224 | protocol: "TCP", 2225 | startport: 81, 2226 | endport: 82, 2227 | cidrlist: "1.2.3.4/24", 2228 | }, 2229 | ], 2230 | }, 2231 | ], 2232 | } 2233 | cmd 2234 | 2235 | expectation = <<-RUBY.gsub(/^ {8}/, "").gsub(/,\n /, ",").chomp 2236 | c.vm.provider :cloudstack do |p| 2237 | p.security_groups = [{name: "Awesome_security_group", 2238 | description: "Created from the Vagrantfile", 2239 | rules: [{type: "ingress", protocol: "TCP", startport: 22, 2240 | endport: 22, cidrlist: "0.0.0.0/0"}, {type: "egress", 2241 | protocol: "TCP", startport: 81, endport: 82, 2242 | cidrlist: "1.2.3.4/24"}]}] 2243 | end 2244 | RUBY 2245 | 2246 | expect(vagrantfile).to match(regexify(expectation)) 2247 | end 2248 | 2249 | it "builds an array of hashes for static nat in :customize" do 2250 | config[:customize] = { 2251 | static_nat: [{ idaddress: "A.A.A.A" }], 2252 | } 2253 | cmd 2254 | 2255 | expect(vagrantfile).to match(regexify(<<-RUBY.gsub(/^ {8}/, "").chomp)) 2256 | c.vm.provider :cloudstack do |p| 2257 | p.static_nat = [{idaddress: "A.A.A.A"}] 2258 | end 2259 | RUBY 2260 | end 2261 | 2262 | it "builds an array of hashes for port forwarding rules in :customize" do 2263 | config[:customize] = { 2264 | port_forwarding_rules: [ 2265 | { 2266 | ipaddress: "X.X.X.X", 2267 | protocol: "tcp", 2268 | publicport: 22, 2269 | privateport: 22, 2270 | openfirewall: false, 2271 | }, 2272 | { 2273 | ipaddress: "X.X.X.X", 2274 | protocol: "tcp", 2275 | publicport: 80, 2276 | privateport: 80, 2277 | openfirewall: false, 2278 | }, 2279 | ], 2280 | } 2281 | cmd 2282 | 2283 | expectation = <<-RUBY.gsub(/^ {8}/, "").gsub(/,\n /, ",").chomp 2284 | c.vm.provider :cloudstack do |p| 2285 | p.port_forwarding_rules = [{ipaddress: "X.X.X.X", 2286 | protocol: "tcp", publicport: 22, privateport: 22, 2287 | openfirewall: false}, {ipaddress: "X.X.X.X", protocol: "tcp", 2288 | publicport: 80, privateport: 80, openfirewall: false}] 2289 | end 2290 | RUBY 2291 | 2292 | expect(vagrantfile).to match(regexify(expectation)) 2293 | end 2294 | end 2295 | 2296 | it 'sets no environment variables by default' do 2297 | cmd 2298 | 2299 | expect(vagrantfile).to_not match(regexify(%(c.vm.provision "shell"), :partial)) 2300 | end 2301 | 2302 | it 'sets environment variables when :env is configured' do 2303 | config[:env] = ['AWS_REGION=us-east-1', 'AWS_ACCESS_KEY_ID=test123'] 2304 | cmd 2305 | 2306 | expect(vagrantfile).to match(/c\.vm\.provision "shell", inline: <<-SHELL/) 2307 | expect(vagrantfile).to match(/echo 'export AWS_REGION=us-east-1' >> \/etc\/profile\.d\/kitchen\.sh/) 2308 | expect(vagrantfile).to match(/echo 'export AWS_ACCESS_KEY_ID=test123' >> \/etc\/profile\.d\/kitchen\.sh/) 2309 | expect(vagrantfile).to match(regexify( 2310 | %(c.vm.provision "shell", inline: "chmod +x /etc/profile.d/kitchen.sh", run: "once") 2311 | )) 2312 | end 2313 | 2314 | it 'properly escapes single quotes in environment variable values' do 2315 | config[:env] = ["TEST_VAR=value'with'quotes"] 2316 | cmd 2317 | 2318 | expect(vagrantfile).to match(/echo 'export TEST_VAR=value'\\''with'\\''quotes' >> \/etc\/profile\.d\/kitchen\.sh/) 2319 | end 2320 | end 2321 | 2322 | def debug_lines 2323 | regex = /^D, .* : / 2324 | logged_output.string.lines 2325 | .select { |l| l =~ regex }.map { |l| l.sub(regex, "") }.join 2326 | end 2327 | 2328 | def with_modern_vagrant 2329 | with_vagrant("2.4.1") 2330 | end 2331 | 2332 | def with_unsupported_vagrant 2333 | with_vagrant("1.0.5") 2334 | end 2335 | 2336 | def with_vagrant(version) 2337 | allow(driver_object).to receive(:run_command) 2338 | .with("vagrant --version", any_args).and_return("Vagrant #{version}") 2339 | end 2340 | 2341 | def regexify(str, line = :whole_line) 2342 | r = Regexp.escape(str) 2343 | r = "^\s*#{r}$" if line == :whole_line 2344 | Regexp.new(r) 2345 | end 2346 | 2347 | def vagrantfile 2348 | IO.read(File.join(vagrant_root, "Vagrantfile")) 2349 | end 2350 | end 2351 | --------------------------------------------------------------------------------