Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ Install using standard Vagrant plugin method:
vagrant plugin install vagrant-vsphere
```

Install this **hacked** vagrant plugin:

```bash
./tools/reinstall.sh
```

This will install the plugin from RubyGems.org.

Alternatively, you can clone this repository and build the source with `gem
Expand Down Expand Up @@ -76,6 +82,10 @@ Vagrant.configure("2") do |config|
vsphere.name = 'NEW VM NAME'
vsphere.user = 'YOUR VMWARE USER'
vsphere.password = 'YOUR VMWARE PASSWORD'
vsphere.networks = [
{'network': 'VM Network'},
{'network': 'VM Network 2'}
]
end
end
```
Expand Down Expand Up @@ -120,21 +130,22 @@ This provider has the following settings, all are required unless noted:
not specified template's parent folder will be used
* `name` - _Optional_ name of the new VM, if missing the name will be auto
generated
* `disks` - _Optional_ Additional disks to attach to VM.
* `size` - _Required_ disk size in GB
* `type` - _Optional_ disk type in `thin`, `lazy`, `eager_zeroed`. Default is `lazy`
* `customization_spec_name` - _Optional_ customization spec for the new VM
* `data_store_name` - _Optional_ the datastore where the VM will be located
* `linked_clone` - _Optional_ link the cloned VM to the parent to share virtual
disks
* `proxy_host` - _Optional_ proxy host name for connecting to vSphere via proxy
* `proxy_port` - _Optional_ proxy port number for connecting to vSphere via
proxy
* `vlan` - _Optional_ vlan to connect the first NIC to
* `memory_mb` - _Optional_ Configure the amount of memory (in MB) for the new VM
* `cpu_count` - _Optional_ Configure the number of CPUs for the new VM
* `mac` - _Optional_ Used to set the mac address of the new VM
* `cpu_reservation` - _Optional_ Configure the CPU time (in MHz) to reserve for this VM
* `cpu_mmu_type` - _Optional_ Configure CPU and MMU virtualization support type
* `nested_hv` - _Optional_ Expose nested hardware virtualization to VM
* `mem_reservation` - _Optional_ Configure the memory (in MB) to reserve for this VM
* `addressType` - _Optional_ Configure the address type of the
[vSphere Virtual Ethernet Card](https://www.vmware.com/support/developer/vc-sdk/visdk2xpubs/ReferenceGuide/vim.vm.device.VirtualEthernetCard.html)
* `custom_attribute` - _Optional_ Add a
[custom attribute](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CB4QFjAAahUKEwiWwbWX59jHAhVBC5IKHa3HAEU&url=http%3A%2F%2Fpubs.vmware.com%2Fvsphere-51%2Ftopic%2Fcom.vmware.vsphere.vcenterhost.doc%2FGUID-25244732-D473-4857-A471-579257B6D95F.html&usg=AFQjCNGTSl4cauFrflUJpBeTBb0Yv7R13g&sig2=a9he6W2qVvBSZ5lCiXnENA)
to the VM upon creation. This method takes a key/value pair,
Expand All @@ -149,8 +160,17 @@ This provider has the following settings, all are required unless noted:
for a target VM to be retrieved from the list of vm adapters on the host and filtered for a single legitimate
adapter with a defined interface. An error will be raised if this filter is enabled and multiple valid
adapters exist on a host.
* `ssh_cidr` - _Optional_ This is a filter that vagrant will only use the ip address in this cidr to connect
* `ip_address_timeout` _ _Optional_ Maximum number of seconds to wait while an
IP address is obtained
* `networks` - _Optional_ List of networks attached to VM. This property will shadow `vlan`, `addressType`, `mac` properties
* `network` - _Required_ Network name
* `adaptertype` - _Optional_ Either `e1000` or `vmxnet3`
* `mac` - _Optional_ Mac address of this adapter
* `vlan` - (_Deprecated_ Please use `networks` instead)_Optional_ vlan to connect the first NIC to
* `mac` - (_Deprecated_ Please use `networks` instead)_Optional_ Used to set the mac address of the new VM
* `addressType` - (_Deprecated_ Please use `networks` instead)_Optional_ Configure the address type of the
[vSphere Virtual Ethernet Card](https://www.vmware.com/support/developer/vc-sdk/visdk2xpubs/ReferenceGuide/vim.vm.device.VirtualEthernetCard.html)

### Cloning from a VM rather than a template

Expand Down
5 changes: 5 additions & 0 deletions example_box/addbox.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

tar cvzf dummy.box ./metadata.json
vagrant box add ./dummy.box --name dummy

49 changes: 49 additions & 0 deletions lib/vSphere/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,52 @@ def self.action_halt
end
end

def self.action_suspend
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectVSphere
b.use Call, IsCreated do |env, b2|
unless env[:result]
b2.use MessageNotCreated
next
end

b2.use Call, IsRunning do |env2, b3|
unless env2[:result]
b3.use MessageNotRunning
next
end

b3.use Suspend
end
end
b.use CloseVSphere
end
end

def self.action_resume
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectVSphere
b.use Call, IsCreated do |env, b2|
unless env[:result]
b2.use MessageNotCreated
next
end

b2.use Call, IsSuspended do |env2, b3|
unless env2[:result]
b3.use MessageNotSuspended
next
end

b3.use PowerOn
end
end
b.use CloseVSphere
end
end

def self.action_reload
Vagrant::Action::Builder.new.tap do |b|
b.use ConnectVSphere
Expand Down Expand Up @@ -259,11 +305,14 @@ def self.action_snapshot_save
autoload :GetState, action_root.join('get_state')
autoload :IsCreated, action_root.join('is_created')
autoload :IsRunning, action_root.join('is_running')
autoload :IsSuspended, action_root.join('is_suspended')
autoload :MessageAlreadyCreated, action_root.join('message_already_created')
autoload :MessageNotCreated, action_root.join('message_not_created')
autoload :MessageNotRunning, action_root.join('message_not_running')
autoload :MessageNotSuspended, action_root.join('message_not_suspended')
autoload :PowerOff, action_root.join('power_off')
autoload :PowerOn, action_root.join('power_on')
autoload :Suspend, action_root.join('suspend')
autoload :WaitForIPAddress, action_root.join('wait_for_ip_address')

# TODO: Remove the if guard when Vagrant 1.8.0 is the minimum version.
Expand Down
163 changes: 154 additions & 9 deletions lib/vSphere/action/clone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,23 @@ def call(env)
fail Errors::VSphereError, :'invalid_configuration_linked_clone_with_sdrs' if config.linked_clone && ds.is_a?(RbVmomi::VIM::StoragePod)

location = get_location ds, dc, machine, template
spec = RbVmomi::VIM.VirtualMachineCloneSpec location: location, powerOn: true, template: false
spec = RbVmomi::VIM.VirtualMachineCloneSpec location: location, powerOn: false, template: false
spec[:config] = RbVmomi::VIM.VirtualMachineConfigSpec
customization_info = get_customization_spec_info_by_name connection, machine

spec[:customization] = get_customization_spec(machine, customization_info) unless customization_info.nil?

env[:ui].info "Setting custom address: #{config.addressType}" unless config.addressType.nil?
add_custom_address_type(template, spec, config.addressType) unless config.addressType.nil?
env[:ui].info "Setting custom address: #{config.addressType}" unless config.addressType.nil? || !config.networks.empty?
add_custom_address_type(template, spec, config.addressType) unless config.addressType.nil? || !config.networks.empty?

env[:ui].info "Setting custom mac: #{config.mac}" unless config.mac.nil?
add_custom_mac(template, spec, config.mac) unless config.mac.nil?
env[:ui].info "Setting custom mac: #{config.mac}" unless config.mac.nil? || !config.networks.empty?
add_custom_mac(template, spec, config.mac) unless config.mac.nil? || !config.networks.empty?

env[:ui].info "Setting custom vlan: #{config.vlan}" unless config.vlan.nil?
add_custom_vlan(template, dc, spec, config.vlan) unless config.vlan.nil?
env[:ui].info "Setting custom vlan: #{config.vlan}" unless config.vlan.nil? || !config.networks.empty?
add_custom_vlan(template, dc, spec, config.vlan) unless config.vlan.nil? || !config.networks.empty?

env[:ui].info "Setting custom networks: #{config.networks}" unless config.networks.empty?
add_custom_networks(template, spec, dc, config.networks) unless config.networks.empty?

env[:ui].info "Setting custom memory: #{config.memory_mb}" unless config.memory_mb.nil?
add_custom_memory(spec, config.memory_mb) unless config.memory_mb.nil?
Expand All @@ -58,6 +61,12 @@ def call(env)
add_custom_extra_config(spec, config.extra_config) unless config.extra_config.empty?
add_custom_notes(spec, config.notes) unless config.notes.nil?

env[:ui].info "Setting custom cpu_mmu_type: #{config.cpu_mmu_type}" unless config.cpu_mmu_type.nil?
add_custom_mmu(template, spec, config.cpu_mmu_type) unless config.cpu_mmu_type.nil?

env[:ui].info "Setting nested hardware virtualization to: #{config.nested_hv}" unless config.nested_hv.nil?
add_custom_nested_hv(template, spec, config.nested_hv) unless config.nested_hv.nil?

if !config.clone_from_vm && ds.is_a?(RbVmomi::VIM::StoragePod)

storage_mgr = connection.serviceContent.storageResourceManager
Expand Down Expand Up @@ -96,6 +105,14 @@ def call(env)
new_vm.setCustomValue(key: k, value: v)
end
end
machine.id = new_vm.config.uuid

env[:ui].info "Setting custom disks: #{config.disks}" unless config.disks.empty?
add_custom_disks(new_vm, config.disks) unless config.disks.empty?

env[:ui].info I18n.t('vsphere.power_on_vm')
new_vm.PowerOnVM_Task.wait_for_completion

rescue Errors::VSphereError
raise
rescue StandardError => e
Expand All @@ -104,8 +121,6 @@ def call(env)

# TODO: handle interrupted status in the environment, should the vm be destroyed?

machine.id = new_vm.config.uuid

wait_for_sysprep(env, new_vm, connection, 600, 10) if machine.config.vm.guest.eql?(:windows)

env[:ui].info I18n.t('vsphere.vm_clone_success')
Expand Down Expand Up @@ -225,6 +240,55 @@ def get_vm_base_folder(dc, template, config)
end
end

def add_custom_disks(vm, disks)
# Get necessary variables
unit_number = 0
controllerkey = 1000
datastore = ""
old_disks = vm.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
old_disks.each do |d|
unit_number = d.unitNumber if d.unitNumber > unit_number
controllerkey = d.controllerKey
datastore = d.backing.datastore.name
end
# Generate spec
disks.each do |disk|
unit_number += 1
# unit_number 7 reserved for scsi controller
unit_number += 1 if unit_number == 7
fail Errors::VSphereError, :'too_many_disks' if unit_number >= 16
size = disk[:size]
disk_types = ['thin', 'eager_zeroed', 'lazy']
disk_type = disk[:type] || 'lazy'
fail Errors::VSphereError, :disk_type_error if !disk_types.include?(disk_type)

thinProvisioned = false
eagerlyScrub = false
if disk_type == 'thin'
thinProvisioned = true
elsif disk_type == 'eager_zeroed'
eagerlyScrub = true
end

backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo(
diskMode: 'persistent',
thinProvisioned: thinProvisioned,
eagerlyScrub: eagerlyScrub,
fileName: "[#{datastore}]",
)
disk_device = RbVmomi::VIM::VirtualDisk(
key: -1,
backing: backing,
capacityInKB: 1024 * 1024 * Integer(size),
unitNumber: unit_number,
controllerKey: controllerkey,
)
dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(device: disk_device, operation: 'add', fileOperation: 'create')
disk_spec = RbVmomi::VIM::VirtualMachineConfigSpec(deviceChange: [dev_spec])
vm.ReconfigVM_Task(spec: disk_spec).wait_for_completion
end
end

def modify_network_card(template, spec)
spec[:config][:deviceChange] ||= []
@card ||= template.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).first
Expand Down Expand Up @@ -267,6 +331,60 @@ def add_custom_vlan(template, dc, spec, vlan)
end
end

def add_custom_networks(template, spec, dc, networks)
spec[:config][:deviceChange] ||= []
cards = template.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard)
cards.each do |card|
dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(device: card, operation: 'remove')
spec[:config][:deviceChange].push dev_spec
end

networks.each do |net|
network_label = net[:network] || ''
network = get_network_by_name(dc, network_label)
adaptertype = net[:adaptertype] || ''
mac = net[:mac] || ''
if mac == ''
addresstype = 'generated'
else
addresstype = 'manual'
end

begin
switch_port = RbVmomi::VIM.DistributedVirtualSwitchPortConnection(switchUuid: network.config.distributedVirtualSwitch.uuid, portgroupKey: network.key)
backing = RbVmomi::VIM::VirtualEthernetCardDistributedVirtualPortBackingInfo(port: switch_port)
rescue
# not connected to a distibuted switch?
backing = RbVmomi::VIM::VirtualEthernetCardNetworkBackingInfo(network: network, deviceName: network.name)
end
if adaptertype == 'e1000'
card_device = RbVmomi::VIM::VirtualE1000(
key: -1,
deviceInfo: {
label: '',
summary: network.name,
},
backing: backing,
addressType: addresstype,
macAddress: mac
)
else
card_device = RbVmomi::VIM::VirtualVmxnet3(
key: -1,
deviceInfo: {
label: '',
summary: network.name,
},
backing: backing,
addressType: addresstype,
macAddress: mac
)
end
dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(device: card_device, operation: 'add')
spec[:config][:deviceChange].push dev_spec
end
end

def add_custom_memory(spec, memory_mb)
spec[:config][:memoryMB] = Integer(memory_mb)
end
Expand Down Expand Up @@ -294,6 +412,33 @@ def add_custom_extra_config(spec, extra_config = {})
def add_custom_notes(spec, notes)
spec[:config][:annotation] = notes
end

def add_custom_mmu(template, spec, mmu)
flags = template.config.flags.dup
if mmu == 'software'
flags.virtualMmuUsage = 'off'
flags.virtualExecUsage = 'hvOff'
elsif mmu == 'hardware'
flags.virtualMmuUsage = 'on'
flags.virtualExecUsage = 'hvOn'
elsif mmu == 'half'
flags.virtualMmuUsage = 'off'
flags.virtualExecUsage = 'hvOn'
else
flags.virtualMmuUsage = 'automatic'
flags.virtualExecUsage = 'hvAuto'
end
spec[:config][:flags] = flags
end

def add_custom_nested_hv(template, spec, nested)
if nested == true
spec[:config][:nestedHVEnabled] = true
else
spec[:config][:nestedHVEnabled] = false
end
end

end
end
end
Expand Down
20 changes: 16 additions & 4 deletions lib/vSphere/action/get_ssh_info.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'rbvmomi'
require 'vSphere/util/vim_helpers'
require 'netaddr'

module VagrantPlugins
module VSphere
Expand All @@ -19,10 +20,21 @@ def call(env)
private

def filter_guest_nic(vm, machine)
return vm.guest.ipAddress unless machine.provider_config.real_nic_ip
ip_addresses = vm.guest.net.select { |g| g.deviceConfigId > 0 }.map { |g| g.ipAddress[0] }
fail Errors::VSphereError.new, :'multiple_interface_with_real_nic_ip_set' if ip_addresses.size > 1
ip_addresses.first
ssh_cidr = machine.provider_config.ssh_cidr
if ssh_cidr.nil?
return vm.guest.ipAddress unless machine.provider_config.real_nic_ip
ip_addresses = vm.guest.net.select { |g| g.deviceConfigId > 0 }.map { |g| g.ipAddress[0] }
fail Errors::VSphereError.new, :'multiple_interface_with_real_nic_ip_set' if ip_addresses.size > 1
return ip_addresses.first
else
ssh_ips = NetAddr::CIDR.create(ssh_cidr).enumerate
vm.guest.net.each do |nic_info|
nic_info.ipAddress.each do |ip|
return ip if ssh_ips.include?(ip)
end
end
end
return nil
end

def get_ssh_info(connection, machine)
Expand Down
Loading