├── .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 | [](http://badge.fury.io/rb/kitchen-vagrant)
4 | [](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 |
--------------------------------------------------------------------------------