vagrant-unbundled 2.2.6.0 → 2.2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/.hashibot.hcl +14 -0
  3. data/CHANGELOG.md +93 -2
  4. data/README.md +1 -3
  5. data/bin/vagrant +23 -0
  6. data/contrib/bash/completion.sh +13 -1
  7. data/lib/vagrant.rb +25 -0
  8. data/lib/vagrant/action.rb +5 -0
  9. data/lib/vagrant/action/builder.rb +145 -24
  10. data/lib/vagrant/action/builtin/box_add.rb +11 -4
  11. data/lib/vagrant/action/builtin/box_check_outdated.rb +12 -15
  12. data/lib/vagrant/action/builtin/cleanup_disks.rb +56 -0
  13. data/lib/vagrant/action/builtin/delayed.rb +26 -0
  14. data/lib/vagrant/action/builtin/disk.rb +52 -0
  15. data/lib/vagrant/action/builtin/handle_box.rb +2 -0
  16. data/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb +28 -9
  17. data/lib/vagrant/action/builtin/mixin_provisioners.rb +19 -1
  18. data/lib/vagrant/action/builtin/ssh_run.rb +21 -3
  19. data/lib/vagrant/action/builtin/trigger.rb +36 -0
  20. data/lib/vagrant/action/hook.rb +20 -2
  21. data/lib/vagrant/action/runner.rb +11 -26
  22. data/lib/vagrant/action/warden.rb +4 -18
  23. data/lib/vagrant/box_metadata.rb +17 -3
  24. data/lib/vagrant/bundler.rb +260 -53
  25. data/lib/vagrant/cli.rb +4 -2
  26. data/lib/vagrant/errors.rb +24 -0
  27. data/lib/vagrant/machine.rb +9 -6
  28. data/lib/vagrant/plugin/manager.rb +25 -14
  29. data/lib/vagrant/plugin/v2/command.rb +1 -1
  30. data/lib/vagrant/plugin/v2/manager.rb +53 -0
  31. data/lib/vagrant/plugin/v2/plugin.rb +1 -0
  32. data/lib/vagrant/plugin/v2/trigger.rb +64 -26
  33. data/lib/vagrant/shared_helpers.rb +28 -0
  34. data/lib/vagrant/ui.rb +50 -4
  35. data/lib/vagrant/util.rb +1 -0
  36. data/lib/vagrant/util/curl_helper.rb +8 -5
  37. data/lib/vagrant/util/downloader.rb +5 -1
  38. data/lib/vagrant/util/file_checksum.rb +6 -2
  39. data/lib/vagrant/util/guest_inspection.rb +9 -1
  40. data/lib/vagrant/util/io.rb +7 -27
  41. data/lib/vagrant/util/is_port_open.rb +1 -2
  42. data/lib/vagrant/util/map_command_options.rb +33 -0
  43. data/lib/vagrant/util/numeric.rb +69 -0
  44. data/lib/vagrant/util/platform.rb +8 -1
  45. data/plugins/commands/box/command/outdated.rb +14 -2
  46. data/plugins/commands/cloud/locales/en.yml +1 -1
  47. data/plugins/commands/cloud/publish.rb +1 -1
  48. data/plugins/commands/snapshot/command/save.rb +13 -8
  49. data/plugins/commands/ssh_config/command.rb +1 -1
  50. data/plugins/communicators/ssh/communicator.rb +18 -23
  51. data/plugins/communicators/winrm/config.rb +1 -1
  52. data/plugins/communicators/winrm/shell.rb +1 -1
  53. data/plugins/communicators/winssh/communicator.rb +126 -38
  54. data/plugins/communicators/winssh/config.rb +3 -7
  55. data/plugins/guests/alpine/cap/rsync.rb +1 -1
  56. data/plugins/guests/alpine/plugin.rb +16 -0
  57. data/plugins/guests/centos/cap/flavor.rb +24 -0
  58. data/plugins/guests/centos/guest.rb +9 -0
  59. data/plugins/guests/centos/plugin.rb +20 -0
  60. data/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb +99 -13
  61. data/plugins/guests/darwin/plugin.rb +5 -0
  62. data/plugins/guests/debian/cap/configure_networks.rb +14 -6
  63. data/plugins/guests/linux/cap/halt.rb +9 -1
  64. data/plugins/guests/linux/cap/mount_smb_shared_folder.rb +16 -0
  65. data/plugins/guests/linux/cap/reboot.rb +48 -0
  66. data/plugins/guests/linux/plugin.rb +10 -0
  67. data/plugins/guests/redhat/cap/flavor.rb +3 -1
  68. data/plugins/guests/redhat/cap/nfs_client.rb +2 -2
  69. data/plugins/guests/redhat/cap/smb.rb +20 -0
  70. data/plugins/guests/redhat/plugin.rb +5 -0
  71. data/plugins/guests/suse/cap/change_host_name.rb +2 -2
  72. data/plugins/guests/windows/cap/public_key.rb +3 -3
  73. data/plugins/guests/windows/cap/reboot.rb +2 -1
  74. data/plugins/hosts/darwin/cap/nfs.rb +11 -0
  75. data/plugins/hosts/darwin/plugin.rb +5 -0
  76. data/plugins/hosts/linux/cap/nfs.rb +21 -2
  77. data/plugins/kernel_v2/config/disk.rb +199 -0
  78. data/plugins/kernel_v2/config/ssh_connect.rb +24 -0
  79. data/plugins/kernel_v2/config/vm.rb +109 -4
  80. data/plugins/kernel_v2/config/vm_provisioner.rb +4 -1
  81. data/plugins/kernel_v2/config/vm_trigger.rb +2 -5
  82. data/plugins/providers/docker/driver.rb +38 -10
  83. data/plugins/providers/docker/errors.rb +4 -0
  84. data/plugins/providers/docker/executor/local.rb +7 -1
  85. data/plugins/providers/hyperv/action/export.rb +4 -2
  86. data/plugins/providers/hyperv/driver.rb +10 -9
  87. data/plugins/providers/hyperv/scripts/set_vm_integration_services.ps1 +3 -3
  88. data/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 +6 -6
  89. data/plugins/providers/virtualbox/action.rb +2 -0
  90. data/plugins/providers/virtualbox/action/clean_machine_folder.rb +10 -1
  91. data/plugins/providers/virtualbox/action/export.rb +4 -2
  92. data/plugins/providers/virtualbox/action/import.rb +8 -4
  93. data/plugins/providers/virtualbox/action/prepare_clone_snapshot.rb +4 -2
  94. data/plugins/providers/virtualbox/action/snapshot_delete.rb +4 -2
  95. data/plugins/providers/virtualbox/action/snapshot_restore.rb +4 -2
  96. data/plugins/providers/virtualbox/cap/cleanup_disks.rb +54 -0
  97. data/plugins/providers/virtualbox/cap/configure_disks.rb +287 -0
  98. data/plugins/providers/virtualbox/cap/validate_disk_ext.rb +27 -0
  99. data/plugins/providers/virtualbox/driver/base.rb +15 -0
  100. data/plugins/providers/virtualbox/driver/meta.rb +14 -2
  101. data/plugins/providers/virtualbox/driver/version_5_0.rb +142 -2
  102. data/plugins/providers/virtualbox/driver/version_6_1.rb +39 -0
  103. data/plugins/providers/virtualbox/plugin.rb +21 -0
  104. data/plugins/provisioners/ansible/cap/guest/alpine/ansible_install.rb +44 -0
  105. data/plugins/provisioners/ansible/cap/guest/arch/ansible_install.rb +20 -3
  106. data/plugins/provisioners/ansible/cap/guest/debian/ansible_install.rb +4 -5
  107. data/plugins/provisioners/ansible/cap/guest/fedora/ansible_install.rb +2 -2
  108. data/plugins/provisioners/ansible/cap/guest/freebsd/ansible_install.rb +2 -2
  109. data/plugins/provisioners/ansible/cap/guest/pip/pip.rb +8 -4
  110. data/plugins/provisioners/ansible/cap/guest/redhat/ansible_install.rb +2 -2
  111. data/plugins/provisioners/ansible/cap/guest/suse/ansible_install.rb +2 -1
  112. data/plugins/provisioners/ansible/cap/guest/ubuntu/ansible_install.rb +3 -3
  113. data/plugins/provisioners/ansible/plugin.rb +5 -0
  114. data/plugins/provisioners/ansible/provisioner/base.rb +1 -1
  115. data/plugins/provisioners/container/client.rb +203 -0
  116. data/plugins/provisioners/container/config.rb +83 -0
  117. data/plugins/provisioners/container/installer.rb +13 -0
  118. data/plugins/provisioners/container/plugin.rb +23 -0
  119. data/plugins/provisioners/container/provisioner.rb +28 -0
  120. data/plugins/provisioners/docker/cap/{redhat → centos}/docker_install.rb +10 -7
  121. data/plugins/provisioners/docker/cap/centos/docker_start_service.rb +24 -0
  122. data/plugins/provisioners/docker/client.rb +4 -175
  123. data/plugins/provisioners/docker/config.rb +2 -72
  124. data/plugins/provisioners/docker/installer.rb +3 -5
  125. data/plugins/provisioners/docker/plugin.rb +6 -6
  126. data/plugins/provisioners/docker/provisioner.rb +4 -10
  127. data/plugins/provisioners/podman/cap/centos/podman_install.rb +35 -0
  128. data/plugins/provisioners/podman/cap/linux/podman_installed.rb +13 -0
  129. data/plugins/provisioners/podman/cap/redhat/podman_install.rb +26 -0
  130. data/plugins/provisioners/podman/client.rb +12 -0
  131. data/plugins/provisioners/podman/config.rb +28 -0
  132. data/plugins/provisioners/podman/installer.rb +33 -0
  133. data/plugins/provisioners/podman/plugin.rb +38 -0
  134. data/plugins/provisioners/podman/provisioner.rb +52 -0
  135. data/plugins/provisioners/salt/provisioner.rb +4 -0
  136. data/plugins/provisioners/shell/config.rb +1 -6
  137. data/plugins/provisioners/shell/provisioner.rb +54 -25
  138. data/plugins/synced_folders/smb/synced_folder.rb +1 -1
  139. data/templates/commands/init/Vagrantfile.erb +1 -1
  140. data/templates/locales/en.yml +123 -4
  141. data/templates/locales/providers_docker.yml +2 -0
  142. data/templates/nfs/exports_darwin.erb +7 -0
  143. data/vagrant.gemspec +8 -9
  144. data/version.txt +1 -1
  145. metadata +3731 -3663
  146. data/lib/vagrant/action/builtin/after_trigger.rb +0 -31
  147. data/lib/vagrant/action/builtin/before_trigger.rb +0 -28
  148. data/plugins/provisioners/docker/cap/redhat/docker_start_service.rb +0 -16
@@ -614,15 +614,15 @@ function Set-VagrantVMService {
614
614
  [parameter (Mandatory=$true)]
615
615
  [Microsoft.HyperV.PowerShell.VirtualMachine] $VM,
616
616
  [parameter (Mandatory=$true)]
617
- [string] $Name,
617
+ [string] $Id,
618
618
  [parameter (Mandatory=$true)]
619
619
  [bool] $Enable
620
620
  )
621
621
 
622
622
  if($Enable) {
623
- Hyper-V\Enable-VMIntegrationService -VM $VM -Name $Name
623
+ Hyper-V\Get-VMIntegrationService -VM $VM | ?{$_.Id -match $Id} | Hyper-V\Enable-VMIntegrationService
624
624
  } else {
625
- Hyper-V\Disable-VMIntegrationService -VM $VM -Name $Name
625
+ Hyper-V\Get-VMIntegrationService -VM $VM | ?{$_.Id -match $Id} | Hyper-V\Disable-VMIntegrationService
626
626
  }
627
627
  return $VM
628
628
  <#
@@ -634,9 +634,9 @@ Enable or disable Hyper-V VM integration services.
634
634
 
635
635
  Hyper-V VM for modification.
636
636
 
637
- .PARAMETER Name
637
+ .PARAMETER Id
638
638
 
639
- Name of the integration service.
639
+ Id of the integration service.
640
640
 
641
641
  .PARAMETER Enable
642
642
 
@@ -722,7 +722,7 @@ function Check-VagrantHyperVAccess {
722
722
  )
723
723
  $acl = Get-ACL -Path $Path
724
724
  $systemACL = $acl.Access | where {
725
- $_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value -eq "S-1-5-18" -and
725
+ try { return $_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value -eq "S-1-5-18" } catch { return $false } -and
726
726
  $_.FileSystemRights -eq "FullControl" -and
727
727
  $_.AccessControlType -eq "Allow" -and
728
728
  $_.IsInherited -eq $true}
@@ -79,6 +79,8 @@ module VagrantPlugins
79
79
  b.use ForwardPorts
80
80
  b.use SetHostname
81
81
  b.use SaneDefaults
82
+ b.use CleanupDisks
83
+ b.use Disk
82
84
  b.use Customize, "pre-boot"
83
85
  b.use Boot
84
86
  b.use Customize, "post-boot"
@@ -13,7 +13,16 @@ module VagrantPlugins
13
13
  end
14
14
 
15
15
  def call(env)
16
- clean_machine_folder(env[:machine].provider.driver.read_machine_folder)
16
+ machine_folder = env[:machine].provider.driver.read_machine_folder
17
+
18
+ begin
19
+ clean_machine_folder(machine_folder)
20
+ rescue Errno::EPERM
21
+ raise Vagrant::Errors::MachineFolderNotAccessible,
22
+ name: env[:machine].name,
23
+ path: machine_folder
24
+ end
25
+
17
26
  @app.call(env)
18
27
  end
19
28
 
@@ -23,8 +23,10 @@ module VagrantPlugins
23
23
  def export
24
24
  @env[:ui].info I18n.t("vagrant.actions.vm.export.exporting")
25
25
  @env[:machine].provider.driver.export(ovf_path) do |progress|
26
- @env[:ui].clear_line
27
- @env[:ui].report_progress(progress.percent, 100, false)
26
+ @env[:ui].rewriting do |ui|
27
+ ui.clear_line
28
+ ui.report_progress(progress.percent, 100, false)
29
+ end
28
30
  end
29
31
 
30
32
  # Clear the line a final time so the next data can appear
@@ -19,8 +19,10 @@ module VagrantPlugins
19
19
  env[:ui].info I18n.t("vagrant.actions.vm.clone.creating")
20
20
  env[:machine].id = env[:machine].provider.driver.clonevm(
21
21
  env[:clone_id], env[:clone_snapshot]) do |progress|
22
- env[:ui].clear_line
23
- env[:ui].report_progress(progress, 100, false)
22
+ env[:ui].rewriting do |ui|
23
+ ui.clear_line
24
+ ui.report_progress(progress, 100, false)
25
+ end
24
26
  end
25
27
 
26
28
  # Clear the line one last time since the progress meter doesn't
@@ -51,8 +53,10 @@ module VagrantPlugins
51
53
  # Import the virtual machine
52
54
  ovf_file = env[:machine].box.directory.join("box.ovf").to_s
53
55
  id = env[:machine].provider.driver.import(ovf_file) do |progress|
54
- env[:ui].clear_line
55
- env[:ui].report_progress(progress, 100, false)
56
+ env[:ui].rewriting do |ui|
57
+ ui.clear_line
58
+ ui.report_progress(progress, 100, false)
59
+ end
56
60
  end
57
61
 
58
62
  # Set the machine ID
@@ -55,8 +55,10 @@ module VagrantPlugins
55
55
  @logger.info("Creating base snapshot for master VM.")
56
56
  env[:machine].provider.driver.create_snapshot(
57
57
  env[:clone_id], name) do |progress|
58
- env[:ui].clear_line
59
- env[:ui].report_progress(progress, 100, false)
58
+ env[:ui].rewriting do |ui|
59
+ ui.clear_line
60
+ ui.report_progress(progress, 100, false)
61
+ end
60
62
  end
61
63
  end
62
64
  end
@@ -12,8 +12,10 @@ module VagrantPlugins
12
12
  name: env[:snapshot_name]))
13
13
  env[:machine].provider.driver.delete_snapshot(
14
14
  env[:machine].id, env[:snapshot_name]) do |progress|
15
- env[:ui].clear_line
16
- env[:ui].report_progress(progress, 100, false)
15
+ env[:ui].rewriting do |ui|
16
+ ui.clear_line
17
+ ui.report_progress(progress, 100, false)
18
+ end
17
19
  end
18
20
 
19
21
  # Clear the line one last time since the progress meter doesn't disappear
@@ -12,8 +12,10 @@ module VagrantPlugins
12
12
  name: env[:snapshot_name]))
13
13
  env[:machine].provider.driver.restore_snapshot(
14
14
  env[:machine].id, env[:snapshot_name]) do |progress|
15
- env[:ui].clear_line
16
- env[:ui].report_progress(progress, 100, false)
15
+ env[:ui].rewriting do |ui|
16
+ ui.clear_line
17
+ ui.report_progress(progress, 100, false)
18
+ end
17
19
  end
18
20
 
19
21
  # Clear the line one last time since the progress meter doesn't disappear
@@ -0,0 +1,54 @@
1
+ require "log4r"
2
+ require "vagrant/util/experimental"
3
+
4
+ module VagrantPlugins
5
+ module ProviderVirtualBox
6
+ module Cap
7
+ module CleanupDisks
8
+ LOGGER = Log4r::Logger.new("vagrant::plugins::virtualbox::cleanup_disks")
9
+
10
+ # @param [Vagrant::Machine] machine
11
+ # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_disks
12
+ # @param [Hash] disk_meta_file - A hash of all the previously defined disks from the last configure_disk action
13
+ def self.cleanup_disks(machine, defined_disks, disk_meta_file)
14
+ return if disk_meta_file.values.flatten.empty?
15
+
16
+ return if !Vagrant::Util::Experimental.feature_enabled?("disks")
17
+
18
+ handle_cleanup_disk(machine, defined_disks, disk_meta_file["disk"])
19
+ # TODO: Floppy and DVD disks
20
+ end
21
+
22
+ protected
23
+
24
+ # @param [Vagrant::Machine] machine
25
+ # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_disks
26
+ # @param [Hash] disk_meta - A hash of all the previously defined disks from the last configure_disk action
27
+ def self.handle_cleanup_disk(machine, defined_disks, disk_meta)
28
+ vm_info = machine.provider.driver.show_vm_info
29
+ primary_disk = vm_info["SATA Controller-ImageUUID-0-0"]
30
+
31
+ disk_meta.each do |d|
32
+ dsk = defined_disks.select { |dk| dk.name == d["name"] }
33
+ if !dsk.empty? || d["uuid"] == primary_disk
34
+ next
35
+ else
36
+ LOGGER.warn("Found disk not in Vagrantfile config: '#{d["name"]}'. Removing disk from guest #{machine.name}")
37
+ disk_info = machine.provider.driver.get_port_and_device(d["uuid"])
38
+
39
+ machine.ui.warn("Disk '#{d["name"]}' no longer exists in Vagrant config. Removing and closing medium from guest...", prefix: true)
40
+
41
+ if disk_info.empty?
42
+ LOGGER.warn("Disk '#{d["name"]}' not attached to guest, but still exists.")
43
+ else
44
+ machine.provider.driver.remove_disk(disk_info[:port], disk_info[:device])
45
+ end
46
+
47
+ machine.provider.driver.close_medium(d["uuid"])
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,287 @@
1
+ require "log4r"
2
+ require "fileutils"
3
+ require "vagrant/util/numeric"
4
+ require "vagrant/util/experimental"
5
+
6
+ module VagrantPlugins
7
+ module ProviderVirtualBox
8
+ module Cap
9
+ module ConfigureDisks
10
+ LOGGER = Log4r::Logger.new("vagrant::plugins::virtualbox::configure_disks")
11
+
12
+ # The max amount of disks that can be attached to a single device in a controller
13
+ MAX_DISK_NUMBER = 30.freeze
14
+
15
+ # @param [Vagrant::Machine] machine
16
+ # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_disks
17
+ # @return [Hash] configured_disks - A hash of all the current configured disks
18
+ def self.configure_disks(machine, defined_disks)
19
+ return {} if defined_disks.empty?
20
+
21
+ return {} if !Vagrant::Util::Experimental.feature_enabled?("disks")
22
+
23
+ if defined_disks.size > MAX_DISK_NUMBER
24
+ # you can only attach up to 30 disks per controller, INCLUDING the primary disk
25
+ raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit
26
+ end
27
+
28
+ machine.ui.info(I18n.t("vagrant.cap.configure_disks.start"))
29
+
30
+ current_disks = machine.provider.driver.list_hdds
31
+
32
+ configured_disks = {disk: [], floppy: [], dvd: []}
33
+
34
+ defined_disks.each do |disk|
35
+ if disk.type == :disk
36
+ disk_data = handle_configure_disk(machine, disk, current_disks)
37
+ configured_disks[:disk] << disk_data unless disk_data.empty?
38
+ elsif disk.type == :floppy
39
+ # TODO: Write me
40
+ machine.ui.info(I18n.t("vagrant.cap.configure_disks.floppy_not_supported", name: disk.name))
41
+ elsif disk.type == :dvd
42
+ # TODO: Write me
43
+ machine.ui.info(I18n.t("vagrant.cap.configure_disks.dvd_not_supported", name: disk.name))
44
+ end
45
+ end
46
+
47
+ configured_disks
48
+ end
49
+
50
+ protected
51
+
52
+ # @param [Vagrant::Machine] machine - the current machine
53
+ # @param [Config::Disk] disk - the current disk to configure
54
+ # @param [Array] all_disks - A list of all currently defined disks in VirtualBox
55
+ # @return [Hash] current_disk - Returns the current disk. Returns nil if it doesn't exist
56
+ def self.get_current_disk(machine, disk, all_disks)
57
+ current_disk = nil
58
+ if disk.primary
59
+ # Ensure we grab the proper primary disk
60
+ # We can't rely on the order of `all_disks`, as they will not
61
+ # always come in port order, but primary is always Port 0 Device 0.
62
+ vm_info = machine.provider.driver.show_vm_info
63
+ primary_uuid = vm_info["SATA Controller-ImageUUID-0-0"]
64
+
65
+ current_disk = all_disks.select { |d| d["UUID"] == primary_uuid }.first
66
+ else
67
+ current_disk = all_disks.select { |d| d["Disk Name"] == disk.name}.first
68
+ end
69
+
70
+ current_disk
71
+ end
72
+
73
+ # Handles all disk configs of type `:disk`
74
+ #
75
+ # @param [Vagrant::Machine] machine - the current machine
76
+ # @param [Config::Disk] disk - the current disk to configure
77
+ # @param [Array] all_disks - A list of all currently defined disks in VirtualBox
78
+ # @return [Hash] - disk_metadata
79
+ def self.handle_configure_disk(machine, disk, all_disks)
80
+ disk_metadata = {}
81
+
82
+ # Grab the existing configured disk, if it exists
83
+ current_disk = get_current_disk(machine, disk, all_disks)
84
+
85
+ # Configure current disk
86
+ if !current_disk
87
+ # create new disk and attach
88
+ disk_metadata = create_disk(machine, disk)
89
+ elsif compare_disk_size(machine, disk, current_disk)
90
+ disk_metadata = resize_disk(machine, disk, current_disk)
91
+ else
92
+ # TODO: What if it needs to be resized?
93
+
94
+ disk_info = machine.provider.driver.get_port_and_device(current_disk["UUID"])
95
+ if disk_info.empty?
96
+ LOGGER.warn("Disk '#{disk.name}' is not connected to guest '#{machine.name}', Vagrant will attempt to connect disk to guest")
97
+ dsk_info = get_next_port(machine)
98
+ machine.provider.driver.attach_disk(dsk_info[:port],
99
+ dsk_info[:device],
100
+ current_disk["Location"])
101
+ else
102
+ LOGGER.info("No further configuration required for disk '#{disk.name}'")
103
+ end
104
+
105
+ disk_metadata = {uuid: current_disk["UUID"], name: disk.name}
106
+ end
107
+
108
+ disk_metadata
109
+ end
110
+
111
+ # Check to see if current disk is configured based on defined_disks
112
+ #
113
+ # @param [Kernel_V2::VagrantConfigDisk] disk_config
114
+ # @param [Hash] defined_disk
115
+ # @return [Boolean]
116
+ def self.compare_disk_size(machine, disk_config, defined_disk)
117
+ requested_disk_size = Vagrant::Util::Numeric.bytes_to_megabytes(disk_config.size)
118
+ defined_disk_size = defined_disk["Capacity"].split(" ").first.to_f
119
+
120
+ if defined_disk_size > requested_disk_size
121
+ machine.ui.warn(I18n.t("vagrant.cap.configure_disks.shrink_size_not_supported", name: disk_config.name))
122
+ return false
123
+ elsif defined_disk_size < requested_disk_size
124
+ return true
125
+ else
126
+ return false
127
+ end
128
+ end
129
+
130
+ # Creates and attaches a disk to a machine
131
+ #
132
+ # @param [Vagrant::Machine] machine
133
+ # @param [Kernel_V2::VagrantConfigDisk] disk_config
134
+ def self.create_disk(machine, disk_config)
135
+ machine.ui.detail(I18n.t("vagrant.cap.configure_disks.create_disk", name: disk_config.name))
136
+ # NOTE: At the moment, there are no provider specific configs for VirtualBox
137
+ # but we grab it anyway for future use.
138
+ disk_provider_config = disk_config.provider_config[:virtualbox] if disk_config.provider_config
139
+
140
+ guest_info = machine.provider.driver.show_vm_info
141
+ guest_folder = File.dirname(guest_info["CfgFile"])
142
+
143
+ disk_ext = disk_config.disk_ext
144
+ disk_file = File.join(guest_folder, disk_config.name) + ".#{disk_ext}"
145
+
146
+ LOGGER.info("Attempting to create a new disk file '#{disk_file}' of size '#{disk_config.size}' bytes")
147
+
148
+ disk_var = machine.provider.driver.create_disk(disk_file, disk_config.size, disk_ext.upcase)
149
+ disk_metadata = {uuid: disk_var.split(':').last.strip, name: disk_config.name}
150
+
151
+ dsk_controller_info = get_next_port(machine)
152
+ machine.provider.driver.attach_disk(dsk_controller_info[:port], dsk_controller_info[:device], disk_file)
153
+
154
+ disk_metadata
155
+ end
156
+
157
+ # Finds the next available port
158
+ #
159
+ # SATA Controller-ImageUUID-0-0 (sub out ImageUUID)
160
+ # - Controller: SATA Controller
161
+ # - Port: 0
162
+ # - Device: 0
163
+ #
164
+ # Note: Virtualbox returns the string above with the port and device info
165
+ # disk_info = key.split("-")
166
+ # port = disk_info[2]
167
+ # device = disk_info[3]
168
+ #
169
+ # @param [Vagrant::Machine] machine
170
+ # @return [Hash] dsk_info - The next available port and device on a given controller
171
+ def self.get_next_port(machine)
172
+ vm_info = machine.provider.driver.show_vm_info
173
+ dsk_info = {device: "0", port: "0"}
174
+
175
+ disk_images = vm_info.select { |v| v.include?("ImageUUID") && v.include?("SATA Controller") }
176
+ used_ports = disk_images.keys.map { |k| k.split('-') }.map {|v| v[2].to_i}
177
+ next_available_port = ((0..(MAX_DISK_NUMBER-1)).to_a - used_ports).first
178
+
179
+ dsk_info[:port] = next_available_port.to_s
180
+ if dsk_info[:port].empty?
181
+ # This likely only occurs if additional disks have been added outside of Vagrant configuration
182
+ LOGGER.warn("There are no more available ports to attach disks to for the SATA Controller. Clear up some space on the SATA controller to attach new disks.")
183
+ raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit
184
+ end
185
+
186
+ dsk_info
187
+ end
188
+
189
+ # @param [Vagrant::Machine] machine
190
+ # @param [Config::Disk] disk_config - the current disk to configure
191
+ # @param [Hash] defined_disk - current disk as represented by VirtualBox
192
+ # @return [Hash] - disk_metadata
193
+ def self.resize_disk(machine, disk_config, defined_disk)
194
+ machine.ui.detail(I18n.t("vagrant.cap.configure_disks.resize_disk", name: disk_config.name), prefix: true)
195
+
196
+ if defined_disk["Storage format"] == "VMDK"
197
+ LOGGER.warn("Disk type VMDK cannot be resized in VirtualBox. Vagrant will convert disk to VDI format to resize first, and then convert resized disk back to VMDK format")
198
+
199
+ # grab disk to be resized port and device number
200
+ disk_info = machine.provider.driver.get_port_and_device(defined_disk["UUID"])
201
+ # original disk information in case anything goes wrong during clone/resize
202
+ original_disk = defined_disk
203
+ backup_disk_location = "#{original_disk["Location"]}.backup"
204
+
205
+ # clone disk to vdi formatted disk
206
+ vdi_disk_file = machine.provider.driver.vmdk_to_vdi(defined_disk["Location"])
207
+ # resize vdi
208
+ machine.provider.driver.resize_disk(vdi_disk_file, disk_config.size.to_i)
209
+
210
+ begin
211
+ # Danger Zone
212
+
213
+ # remove and close original volume
214
+ machine.provider.driver.remove_disk(disk_info[:port], disk_info[:device])
215
+ # Create a backup of the original disk if something goes wrong
216
+ LOGGER.warn("Making a backup of the original disk at #{defined_disk["Location"]}")
217
+ FileUtils.mv(defined_disk["Location"], backup_disk_location)
218
+
219
+ # we have to close here, otherwise we can't re-clone after
220
+ # resizing the vdi disk
221
+ machine.provider.driver.close_medium(defined_disk["UUID"])
222
+
223
+ # clone back to original vmdk format and attach resized disk
224
+ vmdk_disk_file = machine.provider.driver.vdi_to_vmdk(vdi_disk_file)
225
+ machine.provider.driver.attach_disk(disk_info[:port], disk_info[:device], vmdk_disk_file, "hdd")
226
+ rescue ScriptError, SignalException, StandardError
227
+ LOGGER.warn("Vagrant encountered an error while trying to resize a disk. Vagrant will now attempt to reattach and preserve the original disk...")
228
+ machine.ui.error(I18n.t("vagrant.cap.configure_disks.recovery_from_resize",
229
+ location: original_disk["Location"],
230
+ name: machine.name))
231
+ recover_from_resize(machine, disk_info, backup_disk_location, original_disk, vdi_disk_file)
232
+
233
+ raise
234
+ ensure
235
+ # Remove backup disk file if all goes well
236
+ FileUtils.remove(backup_disk_location, force: true)
237
+ end
238
+
239
+ # Remove cloned resized volume format
240
+ machine.provider.driver.close_medium(vdi_disk_file)
241
+
242
+ # Get new updated disk UUID for vagrant disk_meta file
243
+ new_disk_info = machine.provider.driver.list_hdds.select { |h| h["Location"] == defined_disk["Location"] }.first
244
+ defined_disk = new_disk_info
245
+ else
246
+ machine.provider.driver.resize_disk(defined_disk["Location"], disk_config.size.to_i)
247
+ end
248
+
249
+ disk_metadata = {uuid: defined_disk["UUID"], name: disk_config.name}
250
+
251
+ disk_metadata
252
+ end
253
+
254
+ # Recovery method for when an exception occurs during the process of resizing disks
255
+ #
256
+ # It attempts to move back the backup disk into place, and reattach it to the guest before
257
+ # raising the original error
258
+ #
259
+ # @param [Vagrant::Machine] machine
260
+ # @param [Hash] disk_info - The disk device and port number to attach back to
261
+ # @param [String] backup_disk_location - The place on disk where vagrant made a backup of the original disk being resized
262
+ # @param [Hash] original_disk - The disk information from VirtualBox
263
+ # @param [String] vdi_disk_file - The place on disk where vagrant made a clone of the original disk being resized
264
+ def self.recover_from_resize(machine, disk_info, backup_disk_location, original_disk, vdi_disk_file)
265
+ begin
266
+ # move backup to original name
267
+ FileUtils.mv(backup_disk_location, original_disk["Location"], force: true)
268
+ # Attach disk
269
+ machine.provider.driver.
270
+ attach_disk(disk_info[:port], disk_info[:device], original_disk["Location"], "hdd")
271
+
272
+ # Remove cloned disk if still hanging around
273
+ if vdi_disk_file
274
+ machine.provider.driver.close_medium(vdi_disk_file)
275
+ end
276
+
277
+ # We recovered!
278
+ machine.ui.warn(I18n.t("vagrant.cap.configure_disks.recovery_attached_disks"))
279
+ rescue => e
280
+ LOGGER.error("Vagrant encountered an error while trying to recover. It will now show the original error and continue...")
281
+ LOGGER.error(e)
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end