mirror of
https://github.com/puppetlabs/vmpooler.git
synced 2026-01-26 10:08:40 -05:00
Merge pull request #223 from glennsarti/pooler-83-specify-datacenter
(POOLER-83) Add ability to specify a datacenter for vsphere
This commit is contained in:
commit
e5d2844fcc
4 changed files with 489 additions and 175 deletions
|
|
@ -45,7 +45,7 @@ module Vmpooler
|
||||||
@connection_pool.with_metrics do |pool_object|
|
@connection_pool.with_metrics do |pool_object|
|
||||||
connection = ensured_vsphere_connection(pool_object)
|
connection = ensured_vsphere_connection(pool_object)
|
||||||
foldername = pool_config(pool_name)['folder']
|
foldername = pool_config(pool_name)['folder']
|
||||||
folder_object = find_folder(foldername, connection)
|
folder_object = find_folder(foldername, connection, get_target_datacenter_from_config(pool_name))
|
||||||
|
|
||||||
return vms if folder_object.nil?
|
return vms if folder_object.nil?
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ module Vmpooler
|
||||||
raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
|
raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
|
||||||
|
|
||||||
target_cluster_name = get_target_cluster_from_config(pool_name)
|
target_cluster_name = get_target_cluster_from_config(pool_name)
|
||||||
cluster = find_cluster(target_cluster_name, connection)
|
cluster = find_cluster(target_cluster_name, connection, get_target_datacenter_from_config(pool_name))
|
||||||
raise("Pool #{pool_name} specifies cluster #{target_cluster_name} which does not exist for the provider #{name}") if cluster.nil?
|
raise("Pool #{pool_name} specifies cluster #{target_cluster_name} which does not exist for the provider #{name}") if cluster.nil?
|
||||||
|
|
||||||
# Go through each host and initiate a migration when the correct host name is found
|
# Go through each host and initiate a migration when the correct host name is found
|
||||||
|
|
@ -142,6 +142,7 @@ module Vmpooler
|
||||||
target_folder_path = pool['folder']
|
target_folder_path = pool['folder']
|
||||||
target_datastore = pool['datastore']
|
target_datastore = pool['datastore']
|
||||||
target_cluster_name = get_target_cluster_from_config(pool_name)
|
target_cluster_name = get_target_cluster_from_config(pool_name)
|
||||||
|
target_datacenter_name = get_target_datacenter_from_config(pool_name)
|
||||||
|
|
||||||
# Extract the template VM name from the full path
|
# Extract the template VM name from the full path
|
||||||
raise("Pool #{pool_name} did specify a full path for the template for the provider #{name}") unless template_path =~ /\//
|
raise("Pool #{pool_name} did specify a full path for the template for the provider #{name}") unless template_path =~ /\//
|
||||||
|
|
@ -149,7 +150,7 @@ module Vmpooler
|
||||||
template_name = templatefolders.pop
|
template_name = templatefolders.pop
|
||||||
|
|
||||||
# Get the actual objects from vSphere
|
# Get the actual objects from vSphere
|
||||||
template_folder_object = find_folder(templatefolders.join('/'), connection)
|
template_folder_object = find_folder(templatefolders.join('/'), connection, target_datacenter_name)
|
||||||
raise("Pool #{pool_name} specifies a template folder of #{templatefolders.join('/')} which does not exist for the provider #{name}") if template_folder_object.nil?
|
raise("Pool #{pool_name} specifies a template folder of #{templatefolders.join('/')} which does not exist for the provider #{name}") if template_folder_object.nil?
|
||||||
|
|
||||||
template_vm_object = template_folder_object.find(template_name)
|
template_vm_object = template_folder_object.find(template_name)
|
||||||
|
|
@ -170,11 +171,11 @@ module Vmpooler
|
||||||
)
|
)
|
||||||
|
|
||||||
# Choose a cluster/host to place the new VM on
|
# Choose a cluster/host to place the new VM on
|
||||||
target_host_object = find_least_used_host(target_cluster_name, connection)
|
target_host_object = find_least_used_host(target_cluster_name, connection, target_datacenter_name)
|
||||||
|
|
||||||
# Put the VM in the specified folder and resource pool
|
# Put the VM in the specified folder and resource pool
|
||||||
relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(
|
relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(
|
||||||
datastore: find_datastore(target_datastore, connection),
|
datastore: find_datastore(target_datastore, connection, target_datacenter_name),
|
||||||
host: target_host_object,
|
host: target_host_object,
|
||||||
diskMoveType: :moveChildMostDiskBacking
|
diskMoveType: :moveChildMostDiskBacking
|
||||||
)
|
)
|
||||||
|
|
@ -189,7 +190,7 @@ module Vmpooler
|
||||||
|
|
||||||
# Create the new VM
|
# Create the new VM
|
||||||
new_vm_object = template_vm_object.CloneVM_Task(
|
new_vm_object = template_vm_object.CloneVM_Task(
|
||||||
folder: find_folder(target_folder_path, connection),
|
folder: find_folder(target_folder_path, connection, target_datacenter_name),
|
||||||
name: new_vmname,
|
name: new_vmname,
|
||||||
spec: clone_spec
|
spec: clone_spec
|
||||||
).wait_for_completion
|
).wait_for_completion
|
||||||
|
|
@ -211,7 +212,7 @@ module Vmpooler
|
||||||
vm_object = find_vm(vm_name, connection)
|
vm_object = find_vm(vm_name, connection)
|
||||||
raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil?
|
raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil?
|
||||||
|
|
||||||
add_disk(vm_object, disk_size, datastore_name, connection)
|
add_disk(vm_object, disk_size, datastore_name, connection, get_target_datacenter_from_config(pool_name))
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
@ -287,6 +288,16 @@ module Vmpooler
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_target_datacenter_from_config(pool_name)
|
||||||
|
pool = pool_config(pool_name)
|
||||||
|
return nil if pool.nil?
|
||||||
|
|
||||||
|
return pool['datacenter'] unless pool['datacenter'].nil?
|
||||||
|
return provider_config['datacenter'] unless provider_config['datacenter'].nil?
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
def generate_vm_hash(vm_object, template_name, pool_name)
|
def generate_vm_hash(vm_object, template_name, pool_name)
|
||||||
hash = { 'name' => nil, 'hostname' => nil, 'template' => nil, 'poolname' => nil, 'boottime' => nil, 'powerstate' => nil }
|
hash = { 'name' => nil, 'hostname' => nil, 'template' => nil, 'poolname' => nil, 'boottime' => nil, 'powerstate' => nil }
|
||||||
|
|
||||||
|
|
@ -375,11 +386,12 @@ module Vmpooler
|
||||||
(full_path.reverse.map { |p| p[1] }).join('/')
|
(full_path.reverse.map { |p| p[1] }).join('/')
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_disk(vm, size, datastore, connection)
|
def add_disk(vm, size, datastore, connection, datacentername)
|
||||||
return false unless size.to_i > 0
|
return false unless size.to_i > 0
|
||||||
|
|
||||||
vmdk_datastore = find_datastore(datastore, connection)
|
vmdk_datastore = find_datastore(datastore, connection, datacentername)
|
||||||
vmdk_file_name = "#{vm['name']}/#{vm['name']}_#{find_vmdks(vm['name'], datastore, connection).length + 1}.vmdk"
|
raise("Datastore '#{datastore}' does not exist in datacenter '#{datacentername}'") if vmdk_datastore.nil?
|
||||||
|
vmdk_file_name = "#{vm['name']}/#{vm['name']}_#{find_vmdks(vm['name'], datastore, connection, datacentername).length + 1}.vmdk"
|
||||||
|
|
||||||
controller = find_disk_controller(vm)
|
controller = find_disk_controller(vm)
|
||||||
|
|
||||||
|
|
@ -413,7 +425,7 @@ module Vmpooler
|
||||||
)
|
)
|
||||||
|
|
||||||
connection.serviceContent.virtualDiskManager.CreateVirtualDisk_Task(
|
connection.serviceContent.virtualDiskManager.CreateVirtualDisk_Task(
|
||||||
datacenter: connection.serviceInstance.find_datacenter,
|
datacenter: connection.serviceInstance.find_datacenter(datacentername),
|
||||||
name: "[#{vmdk_datastore.name}] #{vmdk_file_name}",
|
name: "[#{vmdk_datastore.name}] #{vmdk_file_name}",
|
||||||
spec: vmdk_spec
|
spec: vmdk_spec
|
||||||
).wait_for_completion
|
).wait_for_completion
|
||||||
|
|
@ -423,8 +435,9 @@ module Vmpooler
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_datastore(datastorename, connection)
|
def find_datastore(datastorename, connection, datacentername)
|
||||||
datacenter = connection.serviceInstance.find_datacenter
|
datacenter = connection.serviceInstance.find_datacenter(datacentername)
|
||||||
|
raise("Datacenter #{datacentername} does not exist") if datacenter.nil?
|
||||||
datacenter.find_datastore(datastorename)
|
datacenter.find_datastore(datastorename)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -497,8 +510,15 @@ module Vmpooler
|
||||||
available_unit_numbers.sort[0]
|
available_unit_numbers.sort[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_folder(foldername, connection)
|
# Finds the first reference to and returns the folder object for a foldername and an optional datacenter
|
||||||
datacenter = connection.serviceInstance.find_datacenter
|
# Params:
|
||||||
|
# +foldername+:: the folder to find (optionally with / in which case the foldername will be split and each element searched for)
|
||||||
|
# +connection+:: the vsphere connection object
|
||||||
|
# +datacentername+:: the datacenter where the folder resides, or nil to return the first datacenter found
|
||||||
|
# returns a ManagedObjectReference for the first folder found or nil if none found
|
||||||
|
def find_folder(foldername, connection, datacentername)
|
||||||
|
datacenter = connection.serviceInstance.find_datacenter(datacentername)
|
||||||
|
raise("Datacenter #{datacentername} does not exist") if datacenter.nil?
|
||||||
base = datacenter.vmFolder
|
base = datacenter.vmFolder
|
||||||
|
|
||||||
folders = foldername.split('/')
|
folders = foldername.split('/')
|
||||||
|
|
@ -558,16 +578,17 @@ module Vmpooler
|
||||||
(memory_usage.to_f / memory_size.to_f) * 100
|
(memory_usage.to_f / memory_size.to_f) * 100
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_least_used_host(cluster, connection)
|
def find_least_used_host(cluster, connection, datacentername)
|
||||||
cluster_object = find_cluster(cluster, connection)
|
cluster_object = find_cluster(cluster, connection, datacentername)
|
||||||
target_hosts = get_cluster_host_utilization(cluster_object)
|
target_hosts = get_cluster_host_utilization(cluster_object)
|
||||||
raise("There is no host candidate in vcenter that meets all the required conditions, check that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory'") if target_hosts.empty?
|
raise("There is no host candidate in vcenter that meets all the required conditions, check that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory'") if target_hosts.empty?
|
||||||
least_used_host = target_hosts.sort[0][1]
|
least_used_host = target_hosts.sort[0][1]
|
||||||
least_used_host
|
least_used_host
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_cluster(cluster, connection)
|
def find_cluster(cluster, connection, datacentername)
|
||||||
datacenter = connection.serviceInstance.find_datacenter
|
datacenter = connection.serviceInstance.find_datacenter(datacentername)
|
||||||
|
raise("Datacenter #{datacentername} does not exist") if datacenter.nil?
|
||||||
datacenter.hostFolder.children.find { |cluster_object| cluster_object.name == cluster }
|
datacenter.hostFolder.children.find { |cluster_object| cluster_object.name == cluster }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -590,8 +611,9 @@ module Vmpooler
|
||||||
[target_host, target_host.name]
|
[target_host, target_host.name]
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_pool(poolname, connection)
|
def find_pool(poolname, connection, datacentername)
|
||||||
datacenter = connection.serviceInstance.find_datacenter
|
datacenter = connection.serviceInstance.find_datacenter(datacentername)
|
||||||
|
raise("Datacenter #{datacentername} does not exist") if datacenter.nil?
|
||||||
base = datacenter.hostFolder
|
base = datacenter.hostFolder
|
||||||
pools = poolname.split('/')
|
pools = poolname.split('/')
|
||||||
pools.each do |pool|
|
pools.each do |pool|
|
||||||
|
|
@ -670,10 +692,10 @@ module Vmpooler
|
||||||
vms
|
vms
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_vmdks(vmname, datastore, connection)
|
def find_vmdks(vmname, datastore, connection, datacentername)
|
||||||
disks = []
|
disks = []
|
||||||
|
|
||||||
vmdk_datastore = find_datastore(datastore, connection)
|
vmdk_datastore = find_datastore(datastore, connection,datacentername)
|
||||||
|
|
||||||
vm_files = connection.serviceContent.propertyCollector.collectMultiple vmdk_datastore.vm, 'layoutEx.file'
|
vm_files = connection.serviceContent.propertyCollector.collectMultiple vmdk_datastore.vm, 'layoutEx.file'
|
||||||
vm_files.keys.each do |f|
|
vm_files.keys.each do |f|
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,7 @@ MockServiceInstance = Struct.new(
|
||||||
return child if path.nil? || child.name == path
|
return child if path.nil? || child.name == path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ describe 'Vmpooler::PoolManager::Provider::VSphere' do
|
||||||
let(:metrics) { Vmpooler::DummyStatsd.new }
|
let(:metrics) { Vmpooler::DummyStatsd.new }
|
||||||
let(:poolname) { 'pool1'}
|
let(:poolname) { 'pool1'}
|
||||||
let(:provider_options) { { 'param' => 'value' } }
|
let(:provider_options) { { 'param' => 'value' } }
|
||||||
|
let(:datacenter_name) { 'MockDC' }
|
||||||
let(:config) { YAML.load(<<-EOT
|
let(:config) { YAML.load(<<-EOT
|
||||||
---
|
---
|
||||||
:config:
|
:config:
|
||||||
|
|
@ -55,6 +56,7 @@ describe 'Vmpooler::PoolManager::Provider::VSphere' do
|
||||||
insecure: true
|
insecure: true
|
||||||
# Drop the connection pool timeout way down for spec tests so they fail fast
|
# Drop the connection pool timeout way down for spec tests so they fail fast
|
||||||
connection_pool_timeout: 1
|
connection_pool_timeout: 1
|
||||||
|
datacenter: MockDC
|
||||||
:pools:
|
:pools:
|
||||||
- name: '#{poolname}'
|
- name: '#{poolname}'
|
||||||
alias: [ 'mockpool' ]
|
alias: [ 'mockpool' ]
|
||||||
|
|
@ -95,7 +97,7 @@ EOT
|
||||||
|
|
||||||
context 'Given a pool folder that is missing' do
|
context 'Given a pool folder that is missing' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
expect(subject).to receive(:find_folder).with(pool_config['folder'],connection).and_return(nil)
|
expect(subject).to receive(:find_folder).with(pool_config['folder'],connection,datacenter_name).and_return(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should get a connection' do
|
it 'should get a connection' do
|
||||||
|
|
@ -113,7 +115,7 @@ EOT
|
||||||
|
|
||||||
context 'Given an empty pool folder' do
|
context 'Given an empty pool folder' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
expect(subject).to receive(:find_folder).with(pool_config['folder'],connection).and_return(folder_object)
|
expect(subject).to receive(:find_folder).with(pool_config['folder'],connection,datacenter_name).and_return(folder_object)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should get a connection' do
|
it 'should get a connection' do
|
||||||
|
|
@ -142,7 +144,7 @@ EOT
|
||||||
folder_object.childEntity << mock_vm
|
folder_object.childEntity << mock_vm
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(subject).to receive(:find_folder).with(pool_config['folder'],connection).and_return(folder_object)
|
expect(subject).to receive(:find_folder).with(pool_config['folder'],connection,datacenter_name).and_return(folder_object)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should get a connection' do
|
it 'should get a connection' do
|
||||||
|
|
@ -324,7 +326,7 @@ EOT
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
config[:pools][0]['clone_target'] = cluster_name
|
config[:pools][0]['clone_target'] = cluster_name
|
||||||
expect(subject).to receive(:find_cluster).with(cluster_name,connection).and_return(nil)
|
expect(subject).to receive(:find_cluster).with(cluster_name,connection,datacenter_name).and_return(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
|
|
@ -338,7 +340,7 @@ EOT
|
||||||
before(:each) do
|
before(:each) do
|
||||||
config[:pools][0]['clone_target'] = nil
|
config[:pools][0]['clone_target'] = nil
|
||||||
config[:config]['clone_target'] = cluster_name
|
config[:config]['clone_target'] = cluster_name
|
||||||
expect(subject).to receive(:find_cluster).with(cluster_name,connection).and_return(nil)
|
expect(subject).to receive(:find_cluster).with(cluster_name,connection,datacenter_name).and_return(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
|
|
@ -352,7 +354,7 @@ EOT
|
||||||
mock_cluster = mock_RbVmomi_VIM_ComputeResource({
|
mock_cluster = mock_RbVmomi_VIM_ComputeResource({
|
||||||
:hosts => [ { :name => 'HOST001' },{ :name => dest_host_name} ]
|
:hosts => [ { :name => 'HOST001' },{ :name => dest_host_name} ]
|
||||||
})
|
})
|
||||||
expect(subject).to receive(:find_cluster).with(cluster_name,connection).and_return(mock_cluster)
|
expect(subject).to receive(:find_cluster).with(cluster_name,connection,datacenter_name).and_return(mock_cluster)
|
||||||
expect(subject).to receive(:migrate_vm_host).exactly(0).times
|
expect(subject).to receive(:migrate_vm_host).exactly(0).times
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -367,7 +369,7 @@ EOT
|
||||||
mock_cluster = mock_RbVmomi_VIM_ComputeResource({
|
mock_cluster = mock_RbVmomi_VIM_ComputeResource({
|
||||||
:hosts => [ { :name => 'HOST001' },{ :name => dest_host_name} ]
|
:hosts => [ { :name => 'HOST001' },{ :name => dest_host_name} ]
|
||||||
})
|
})
|
||||||
expect(subject).to receive(:find_cluster).with(cluster_name,connection).and_return(mock_cluster)
|
expect(subject).to receive(:find_cluster).with(cluster_name,connection,datacenter_name).and_return(mock_cluster)
|
||||||
expect(subject).to receive(:migrate_vm_host).with(Object,Object).and_raise(RuntimeError,'MockMigrationError')
|
expect(subject).to receive(:migrate_vm_host).with(Object,Object).and_raise(RuntimeError,'MockMigrationError')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -382,7 +384,7 @@ EOT
|
||||||
mock_cluster = mock_RbVmomi_VIM_ComputeResource({
|
mock_cluster = mock_RbVmomi_VIM_ComputeResource({
|
||||||
:hosts => [ { :name => 'HOST001' },{ :name => dest_host_name} ]
|
:hosts => [ { :name => 'HOST001' },{ :name => dest_host_name} ]
|
||||||
})
|
})
|
||||||
expect(subject).to receive(:find_cluster).with(cluster_name,connection).and_return(mock_cluster)
|
expect(subject).to receive(:find_cluster).with(cluster_name,connection,datacenter_name).and_return(mock_cluster)
|
||||||
expect(subject).to receive(:migrate_vm_host).with(Object,Object).and_return(nil)
|
expect(subject).to receive(:migrate_vm_host).with(Object,Object).and_return(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -558,7 +560,7 @@ EOT
|
||||||
|
|
||||||
context 'Given a successful creation' do
|
context 'Given a successful creation' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
template_vm = subject.find_folder('Templates',connection).find('pool1')
|
template_vm = subject.find_folder('Templates',connection,datacenter_name).find('pool1')
|
||||||
allow(template_vm).to receive(:CloneVM_Task).and_return(clone_vm_task)
|
allow(template_vm).to receive(:CloneVM_Task).and_return(clone_vm_task)
|
||||||
allow(clone_vm_task).to receive(:wait_for_completion).and_return(new_vm_object)
|
allow(clone_vm_task).to receive(:wait_for_completion).and_return(new_vm_object)
|
||||||
end
|
end
|
||||||
|
|
@ -570,7 +572,7 @@ EOT
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should use the appropriate Create_VM spec' do
|
it 'should use the appropriate Create_VM spec' do
|
||||||
template_vm = subject.find_folder('Templates',connection).find('pool1')
|
template_vm = subject.find_folder('Templates',connection,datacenter_name).find('pool1')
|
||||||
expect(template_vm).to receive(:CloneVM_Task)
|
expect(template_vm).to receive(:CloneVM_Task)
|
||||||
.with(create_vm_spec(vmname,'pool1','datastore0'))
|
.with(create_vm_spec(vmname,'pool1','datastore0'))
|
||||||
.and_return(clone_vm_task)
|
.and_return(clone_vm_task)
|
||||||
|
|
@ -633,7 +635,7 @@ EOT
|
||||||
|
|
||||||
context 'when adding the disk succeeds' do
|
context 'when adding the disk succeeds' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
expect(subject).to receive(:add_disk).with(vm_object, disk_size, datastorename, connection)
|
expect(subject).to receive(:add_disk).with(vm_object, disk_size, datastorename, connection, datacenter_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return true' do
|
it 'should return true' do
|
||||||
|
|
@ -881,6 +883,92 @@ EOT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# vSphere helper methods
|
||||||
|
describe '#get_target_datacenter_from_config' do
|
||||||
|
let(:pool_dc) { 'PoolDC'}
|
||||||
|
let(:provider_dc) { 'ProvDC'}
|
||||||
|
|
||||||
|
context 'when not specified' do
|
||||||
|
let(:config) { YAML.load(<<-EOT
|
||||||
|
---
|
||||||
|
:config:
|
||||||
|
:providers:
|
||||||
|
:vsphere:
|
||||||
|
server: "vcenter.domain.local"
|
||||||
|
username: "vcenter_user"
|
||||||
|
password: "vcenter_password"
|
||||||
|
:pools:
|
||||||
|
- name: '#{poolname}'
|
||||||
|
EOT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(subject.get_target_datacenter_from_config(poolname)).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when specified only in the pool' do
|
||||||
|
let(:config) { YAML.load(<<-EOT
|
||||||
|
---
|
||||||
|
:config:
|
||||||
|
:providers:
|
||||||
|
:vsphere:
|
||||||
|
server: "vcenter.domain.local"
|
||||||
|
username: "vcenter_user"
|
||||||
|
password: "vcenter_password"
|
||||||
|
:pools:
|
||||||
|
- name: '#{poolname}'
|
||||||
|
datacenter: '#{pool_dc}'
|
||||||
|
EOT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
it 'returns the pool datacenter' do
|
||||||
|
expect(subject.get_target_datacenter_from_config(poolname)).to eq(pool_dc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when specified only in the provider' do
|
||||||
|
let(:config) { YAML.load(<<-EOT
|
||||||
|
---
|
||||||
|
:config:
|
||||||
|
:providers:
|
||||||
|
:vsphere:
|
||||||
|
server: "vcenter.domain.local"
|
||||||
|
username: "vcenter_user"
|
||||||
|
password: "vcenter_password"
|
||||||
|
datacenter: '#{provider_dc}'
|
||||||
|
:pools:
|
||||||
|
- name: '#{poolname}'
|
||||||
|
EOT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
it 'returns the provider datacenter' do
|
||||||
|
expect(subject.get_target_datacenter_from_config(poolname)).to eq(provider_dc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when specified in the provider and pool' do
|
||||||
|
let(:config) { YAML.load(<<-EOT
|
||||||
|
---
|
||||||
|
:config:
|
||||||
|
:providers:
|
||||||
|
:vsphere:
|
||||||
|
server: "vcenter.domain.local"
|
||||||
|
username: "vcenter_user"
|
||||||
|
password: "vcenter_password"
|
||||||
|
datacenter: '#{provider_dc}'
|
||||||
|
:pools:
|
||||||
|
- name: '#{poolname}'
|
||||||
|
datacenter: '#{pool_dc}'
|
||||||
|
EOT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
it 'returns the pool datacenter' do
|
||||||
|
expect(subject.get_target_datacenter_from_config(poolname)).to eq(pool_dc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# vSphere helper methods
|
# vSphere helper methods
|
||||||
describe '#ensured_vsphere_connection' do
|
describe '#ensured_vsphere_connection' do
|
||||||
let(:config) { YAML.load(<<-EOT
|
let(:config) { YAML.load(<<-EOT
|
||||||
|
|
@ -1227,7 +1315,7 @@ EOT
|
||||||
let(:connection_options) {{
|
let(:connection_options) {{
|
||||||
:serviceContent => {
|
:serviceContent => {
|
||||||
:datacenters => [
|
:datacenters => [
|
||||||
{ :name => 'MockDC', :datastores => [datastorename] }
|
{ :name => datacenter_name, :datastores => [datastorename] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
@ -1240,7 +1328,11 @@ EOT
|
||||||
allow(connection.serviceContent.propertyCollector).to receive(:collectMultiple).and_return(collectMultiple_response)
|
allow(connection.serviceContent.propertyCollector).to receive(:collectMultiple).and_return(collectMultiple_response)
|
||||||
|
|
||||||
# Mocking for creating the disk
|
# Mocking for creating the disk
|
||||||
allow(connection.serviceContent.virtualDiskManager).to receive(:CreateVirtualDisk_Task).and_return(create_virtual_disk_task)
|
allow(connection.serviceContent.virtualDiskManager).to receive(:CreateVirtualDisk_Task) do |options|
|
||||||
|
if options[:datacenter][:name] == datacenter_name
|
||||||
|
create_virtual_disk_task
|
||||||
|
end
|
||||||
|
end
|
||||||
allow(create_virtual_disk_task).to receive(:wait_for_completion).and_return(true)
|
allow(create_virtual_disk_task).to receive(:wait_for_completion).and_return(true)
|
||||||
|
|
||||||
# Mocking for adding disk to the VM
|
# Mocking for adding disk to the VM
|
||||||
|
|
@ -1250,7 +1342,7 @@ EOT
|
||||||
|
|
||||||
context 'Succesfully addding disk' do
|
context 'Succesfully addding disk' do
|
||||||
it 'should return true' do
|
it 'should return true' do
|
||||||
expect(subject.add_disk(vm_object,disk_size,datastorename,connection)).to be true
|
expect(subject.add_disk(vm_object,disk_size,datastorename,connection,datacenter_name)).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should request a disk of appropriate size' do
|
it 'should request a disk of appropriate size' do
|
||||||
|
|
@ -1259,13 +1351,13 @@ EOT
|
||||||
.and_return(create_virtual_disk_task)
|
.and_return(create_virtual_disk_task)
|
||||||
|
|
||||||
|
|
||||||
subject.add_disk(vm_object,disk_size,datastorename,connection)
|
subject.add_disk(vm_object,disk_size,datastorename,connection,datacenter_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'Requested disk size is 0' do
|
context 'Requested disk size is 0' do
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
expect(subject.add_disk(vm_object,0,datastorename,connection)).to be false
|
expect(subject.add_disk(vm_object,0,datastorename,connection,datacenter_name)).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1273,13 +1365,28 @@ EOT
|
||||||
let(:connection_options) {{
|
let(:connection_options) {{
|
||||||
:serviceContent => {
|
:serviceContent => {
|
||||||
:datacenters => [
|
:datacenters => [
|
||||||
{ :name => 'MockDC', :datastores => ['missing_datastore'] }
|
{ :name => datacenter_name, :datastores => ['missing_datastore'] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should raise error' do
|
||||||
expect{ subject.add_disk(vm_object,disk_size,datastorename,connection) }.to raise_error(NoMethodError)
|
expect{ subject.add_disk(vm_object,disk_size,datastorename,connection,datacenter_name) }.to raise_error(/does not exist/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'Multiple datacenters with multiple datastores' do
|
||||||
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => 'AnotherDC', :datastores => ['dc1','dc2'] },
|
||||||
|
{ :name => datacenter_name, :datastores => ['dc3',datastorename,'dc4'] },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
it 'should return true' do
|
||||||
|
expect(subject.add_disk(vm_object,disk_size,datastorename,connection,datacenter_name)).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1293,7 +1400,7 @@ EOT
|
||||||
}
|
}
|
||||||
|
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
expect{ subject.add_disk(vm_object,disk_size,datastorename,connection) }.to raise_error(NoMethodError)
|
expect{ subject.add_disk(vm_object,disk_size,datastorename,connection,datacenter_name) }.to raise_error(NoMethodError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1306,13 +1413,13 @@ EOT
|
||||||
let(:connection_options) {{
|
let(:connection_options) {{
|
||||||
:serviceContent => {
|
:serviceContent => {
|
||||||
:datacenters => [
|
:datacenters => [
|
||||||
{ :name => 'MockDC', :datastores => [] }
|
{ :name => datacenter_name, :datastores => [] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
it 'should return nil if the datastore is not found' do
|
it 'should return nil if the datastore is not found' do
|
||||||
result = subject.find_datastore(datastorename,connection)
|
result = subject.find_datastore(datastorename,connection,datacenter_name)
|
||||||
expect(result).to be_nil
|
expect(result).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1321,18 +1428,42 @@ EOT
|
||||||
let(:connection_options) {{
|
let(:connection_options) {{
|
||||||
:serviceContent => {
|
:serviceContent => {
|
||||||
:datacenters => [
|
:datacenters => [
|
||||||
{ :name => 'MockDC', :datastores => ['ds1','ds2',datastorename,'ds3'] }
|
{ :name => datacenter_name, :datastores => ['ds1','ds2',datastorename,'ds3'] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
it 'should return nil if the datastore is not found' do
|
it 'should return nil if the datastore is not found' do
|
||||||
result = subject.find_datastore('missing_datastore',connection)
|
result = subject.find_datastore('missing_datastore',connection,datacenter_name)
|
||||||
expect(result).to be_nil
|
expect(result).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should find the datastore in the datacenter' do
|
it 'should find the datastore in the datacenter' do
|
||||||
result = subject.find_datastore(datastorename,connection)
|
result = subject.find_datastore(datastorename,connection,datacenter_name)
|
||||||
|
|
||||||
|
expect(result).to_not be_nil
|
||||||
|
expect(result.is_a?(RbVmomi::VIM::Datastore)).to be true
|
||||||
|
expect(result.name).to eq(datastorename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'Many datastores in many datacenters' do
|
||||||
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => 'AnotherDC', :datastores => ['ds1','ds2','ds3'] },
|
||||||
|
{ :name => datacenter_name, :datastores => ['ds3','ds4',datastorename,'ds5'] },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
it 'should return nil if the datastore is not found' do
|
||||||
|
result = subject.find_datastore(datastorename,connection,'AnotherDC')
|
||||||
|
expect(result).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should find the datastore in the datacenter' do
|
||||||
|
result = subject.find_datastore(datastorename,connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.is_a?(RbVmomi::VIM::Datastore)).to be true
|
expect(result.is_a?(RbVmomi::VIM::Datastore)).to be true
|
||||||
|
|
@ -1558,54 +1689,102 @@ EOT
|
||||||
let(:foldername) { 'folder'}
|
let(:foldername) { 'folder'}
|
||||||
let(:missing_foldername) { 'missing_folder'}
|
let(:missing_foldername) { 'missing_folder'}
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
allow(connection.serviceInstance).to receive(:find_datacenter).and_return(datacenter_object)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with no folder hierarchy' do
|
context 'with no folder hierarchy' do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter() }
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should return nil if the folder is not found' do
|
it 'should return nil if the folder is not found' do
|
||||||
expect(subject.find_folder(missing_foldername,connection)).to be_nil
|
expect(subject.find_folder(missing_foldername,connection,datacenter_name)).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a single layer folder hierarchy' do
|
context 'with a single layer folder hierarchy' do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
:vmfolder_tree => {
|
:vmfolder_tree => {
|
||||||
'folder1' => nil,
|
'folder1' => nil,
|
||||||
'folder2' => nil,
|
'folder2' => nil,
|
||||||
foldername => nil,
|
foldername => nil,
|
||||||
'folder3' => nil,
|
'folder3' => nil,
|
||||||
}
|
}
|
||||||
}) }
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should return the folder when found' do
|
it 'should return the folder when found' do
|
||||||
result = subject.find_folder(foldername,connection)
|
result = subject.find_folder(foldername,connection,datacenter_name)
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(foldername)
|
expect(result.name).to eq(foldername)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return nil if the folder is not found' do
|
it 'should return nil if the folder is not found' do
|
||||||
expect(subject.find_folder(missing_foldername,connection)).to be_nil
|
expect(subject.find_folder(missing_foldername,connection,datacenter_name)).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a single layer folder hierarchy in many datacenters' do
|
||||||
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => 'AnotherDC',
|
||||||
|
:vmfolder_tree => {
|
||||||
|
'folder1' => nil,
|
||||||
|
'folder2' => nil,
|
||||||
|
'folder3' => nil,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ :name => datacenter_name,
|
||||||
|
:vmfolder_tree => {
|
||||||
|
'folder4' => nil,
|
||||||
|
'folder5' => nil,
|
||||||
|
foldername => nil,
|
||||||
|
'folder6' => nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
it 'should return the folder when found' do
|
||||||
|
result = subject.find_folder(foldername,connection,datacenter_name)
|
||||||
|
expect(result).to_not be_nil
|
||||||
|
expect(result.name).to eq(foldername)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return nil if the folder is not found' do
|
||||||
|
expect(subject.find_folder(missing_foldername,connection,'AnotherDC')).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a VM with the same name as a folder in a single layer folder hierarchy' do
|
context 'with a VM with the same name as a folder in a single layer folder hierarchy' do
|
||||||
# The folder hierarchy should include a VM with same name as folder, and appear BEFORE the
|
# The folder hierarchy should include a VM with same name as folder, and appear BEFORE the
|
||||||
# folder in the child list.
|
# folder in the child list.
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
:vmfolder_tree => {
|
:vmfolder_tree => {
|
||||||
'folder1' => nil,
|
'folder1' => nil,
|
||||||
'vm1' => { :object_type => 'vm', :name => foldername },
|
'vm1' => { :object_type => 'vm', :name => foldername },
|
||||||
foldername => nil,
|
foldername => nil,
|
||||||
'folder3' => nil,
|
'folder3' => nil,
|
||||||
}
|
}
|
||||||
}) }
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should not return a VM' do
|
it 'should not return a VM' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/204')
|
pending('https://github.com/puppetlabs/vmpooler/issues/204')
|
||||||
result = subject.find_folder(foldername,connection)
|
result = subject.find_folder(foldername,connection,datacenter_name)
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(foldername)
|
expect(result.name).to eq(foldername)
|
||||||
expect(result.is_a? RbVmomi::VIM::VirtualMachine).to be false
|
expect(result.is_a? RbVmomi::VIM::VirtualMachine).to be false
|
||||||
|
|
@ -1615,7 +1794,10 @@ EOT
|
||||||
context 'with a multi layer folder hierarchy' do
|
context 'with a multi layer folder hierarchy' do
|
||||||
let(:end_folder_name) { 'folder'}
|
let(:end_folder_name) { 'folder'}
|
||||||
let(:foldername) { 'folder2/folder4/' + end_folder_name}
|
let(:foldername) { 'folder2/folder4/' + end_folder_name}
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
:vmfolder_tree => {
|
:vmfolder_tree => {
|
||||||
'folder1' => nil,
|
'folder1' => nil,
|
||||||
'folder2' => {
|
'folder2' => {
|
||||||
|
|
@ -1630,16 +1812,19 @@ EOT
|
||||||
},
|
},
|
||||||
'folder5' => nil,
|
'folder5' => nil,
|
||||||
}
|
}
|
||||||
}) }
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should return the folder when found' do
|
it 'should return the folder when found' do
|
||||||
result = subject.find_folder(foldername,connection)
|
result = subject.find_folder(foldername,connection,datacenter_name)
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(end_folder_name)
|
expect(result.name).to eq(end_folder_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return nil if the folder is not found' do
|
it 'should return nil if the folder is not found' do
|
||||||
expect(subject.find_folder(missing_foldername,connection)).to be_nil
|
expect(subject.find_folder(missing_foldername,connection,datacenter_name)).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1648,7 +1833,10 @@ EOT
|
||||||
# and appear BEFORE the folder in the child list.
|
# and appear BEFORE the folder in the child list.
|
||||||
let(:end_folder_name) { 'folder'}
|
let(:end_folder_name) { 'folder'}
|
||||||
let(:foldername) { 'folder2/folder4/' + end_folder_name}
|
let(:foldername) { 'folder2/folder4/' + end_folder_name}
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
:vmfolder_tree => {
|
:vmfolder_tree => {
|
||||||
'folder1' => nil,
|
'folder1' => nil,
|
||||||
'folder2' => {
|
'folder2' => {
|
||||||
|
|
@ -1664,14 +1852,17 @@ EOT
|
||||||
},
|
},
|
||||||
'folder5' => nil,
|
'folder5' => nil,
|
||||||
}
|
}
|
||||||
}) }
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should not return a VM' do
|
it 'should not return a VM' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/204')
|
pending('https://github.com/puppetlabs/vmpooler/issues/204')
|
||||||
result = subject.find_folder(foldername,connection)
|
result = subject.find_folder(foldername,connection,datacenter_name)
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(foldername)
|
expect(result.name).to eq(foldername)
|
||||||
expect(result.is_a? RbVmomi::VIM::VirtualMachine).to be false
|
expect(result.is_a? RbVmomi::VIM::VirtualMachine,datacenter_name).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1920,9 +2111,9 @@ EOT
|
||||||
:name => cluster_name,
|
:name => cluster_name,
|
||||||
}]})}
|
}]})}
|
||||||
let(:expected_host) { cluster_object.host[0] }
|
let(:expected_host) { cluster_object.host[0] }
|
||||||
|
#,datacenter_name
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
expect{subject.find_least_used_host(missing_cluster_name,connection)}.to raise_error(NoMethodError,/undefined method/)
|
expect{subject.find_least_used_host(missing_cluster_name,connection,datacenter_name)}.to raise_error(NoMethodError,/undefined method/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1935,7 +2126,7 @@ EOT
|
||||||
let(:expected_host) { cluster_object.host[0] }
|
let(:expected_host) { cluster_object.host[0] }
|
||||||
|
|
||||||
it 'should return the standalone host' do
|
it 'should return the standalone host' do
|
||||||
result = subject.find_least_used_host(cluster_name,connection)
|
result = subject.find_least_used_host(cluster_name,connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to be(expected_host)
|
expect(result).to be(expected_host)
|
||||||
end
|
end
|
||||||
|
|
@ -1951,7 +2142,7 @@ EOT
|
||||||
let(:expected_host) { cluster_object.host[0] }
|
let(:expected_host) { cluster_object.host[0] }
|
||||||
|
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
expect{subject.find_least_used_host(missing_cluster_name,connection)}.to raise_error(NoMethodError,/undefined method/)
|
expect{subject.find_least_used_host(missing_cluster_name,connection,datacenter_name)}.to raise_error(NoMethodError,/undefined method/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1966,7 +2157,7 @@ EOT
|
||||||
let(:expected_host) { cluster_object.host[1] }
|
let(:expected_host) { cluster_object.host[1] }
|
||||||
|
|
||||||
it 'should return the standalone host' do
|
it 'should return the standalone host' do
|
||||||
result = subject.find_least_used_host(cluster_name,connection)
|
result = subject.find_least_used_host(cluster_name,connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to be(expected_host)
|
expect(result).to be(expected_host)
|
||||||
end
|
end
|
||||||
|
|
@ -1983,7 +2174,7 @@ EOT
|
||||||
let(:expected_host) { cluster_object.host[1] }
|
let(:expected_host) { cluster_object.host[1] }
|
||||||
|
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
expect{subject.find_least_used_host(missing_cluster_name,connection)}.to raise_error(NoMethodError,/undefined method/)
|
expect{subject.find_least_used_host(missing_cluster_name,connection,datacenter_name)}.to raise_error(NoMethodError,/undefined method/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -2000,7 +2191,7 @@ EOT
|
||||||
let(:expected_host) { cluster_object.host[1] }
|
let(:expected_host) { cluster_object.host[1] }
|
||||||
|
|
||||||
it 'should return the standalone host' do
|
it 'should return the standalone host' do
|
||||||
result = subject.find_least_used_host(cluster_name,connection)
|
result = subject.find_least_used_host(cluster_name,connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to be(expected_host)
|
expect(result).to be(expected_host)
|
||||||
end
|
end
|
||||||
|
|
@ -2018,7 +2209,7 @@ EOT
|
||||||
|
|
||||||
it 'should return a host' do
|
it 'should return a host' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/206')
|
pending('https://github.com/puppetlabs/vmpooler/issues/206')
|
||||||
result = subject.find_least_used_host(missing_cluster_name,connection)
|
result = subject.find_least_used_host(missing_cluster_name,connection,datacenter_name)
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -2028,45 +2219,85 @@ EOT
|
||||||
let(:cluster) {'cluster'}
|
let(:cluster) {'cluster'}
|
||||||
let(:missing_cluster) {'missing_cluster'}
|
let(:missing_cluster) {'missing_cluster'}
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
allow(connection.serviceInstance).to receive(:find_datacenter).and_return(datacenter_object)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'no clusters in the datacenter' do
|
context 'no clusters in the datacenter' do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter() }
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
before(:each) do
|
:datacenters => [
|
||||||
end
|
{ :name => datacenter_name }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should return nil if the cluster is not found' do
|
it 'should return nil if the cluster is not found' do
|
||||||
expect(subject.find_cluster(missing_cluster,connection)).to be_nil
|
expect(subject.find_cluster(missing_cluster,connection,datacenter_name)).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a single layer folder hierarchy' do
|
context 'with a single layer folder hierarchy' do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
:hostfolder_tree => {
|
:hostfolder_tree => {
|
||||||
'cluster1' => {:object_type => 'compute_resource'},
|
'cluster1' => {:object_type => 'compute_resource'},
|
||||||
'cluster2' => {:object_type => 'compute_resource'},
|
'cluster2' => {:object_type => 'compute_resource'},
|
||||||
cluster => {:object_type => 'compute_resource'},
|
cluster => {:object_type => 'compute_resource'},
|
||||||
'cluster3' => {:object_type => 'compute_resource'},
|
'cluster3' => {:object_type => 'compute_resource'},
|
||||||
}
|
}
|
||||||
}) }
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should return the cluster when found' do
|
it 'should return the cluster when found' do
|
||||||
result = subject.find_cluster(cluster,connection)
|
result = subject.find_cluster(cluster,connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(cluster)
|
expect(result.name).to eq(cluster)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return nil if the cluster is not found' do
|
it 'should return nil if the cluster is not found' do
|
||||||
expect(subject.find_cluster(missing_cluster,connection)).to be_nil
|
expect(subject.find_cluster(missing_cluster,connection,datacenter_name)).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a single layer folder hierarchy with multiple datacenters' do
|
||||||
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => 'AnotherDC',
|
||||||
|
:hostfolder_tree => {
|
||||||
|
'cluster1' => {:object_type => 'compute_resource'},
|
||||||
|
'cluster2' => {:object_type => 'compute_resource'},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ :name => datacenter_name,
|
||||||
|
:hostfolder_tree => {
|
||||||
|
cluster => {:object_type => 'compute_resource'},
|
||||||
|
'cluster3' => {:object_type => 'compute_resource'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
it 'should return the cluster when found' do
|
||||||
|
result = subject.find_cluster(cluster,connection,datacenter_name)
|
||||||
|
|
||||||
|
expect(result).to_not be_nil
|
||||||
|
expect(result.name).to eq(cluster)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return nil if the cluster is not found' do
|
||||||
|
expect(subject.find_cluster(missing_cluster,connection,'AnotherDC')).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a multi layer folder hierarchy' do
|
context 'with a multi layer folder hierarchy' do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
:hostfolder_tree => {
|
:hostfolder_tree => {
|
||||||
'cluster1' => {:object_type => 'compute_resource'},
|
'cluster1' => {:object_type => 'compute_resource'},
|
||||||
'folder2' => {
|
'folder2' => {
|
||||||
|
|
@ -2076,18 +2307,21 @@ EOT
|
||||||
},
|
},
|
||||||
'cluster3' => {:object_type => 'compute_resource'},
|
'cluster3' => {:object_type => 'compute_resource'},
|
||||||
}
|
}
|
||||||
}) }
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should return the cluster when found' do
|
it 'should return the cluster when found' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/205')
|
pending('https://github.com/puppetlabs/vmpooler/issues/205')
|
||||||
result = subject.find_cluster(cluster,connection)
|
result = subject.find_cluster(cluster,connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(cluster)
|
expect(result.name).to eq(cluster)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return nil if the cluster is not found' do
|
it 'should return nil if the cluster is not found' do
|
||||||
expect(subject.find_cluster(missing_cluster,connection)).to be_nil
|
expect(subject.find_cluster(missing_cluster,connection,datacenter_name)).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -2287,23 +2521,56 @@ EOT
|
||||||
let(:poolname) { 'pool'}
|
let(:poolname) { 'pool'}
|
||||||
let(:missing_poolname) { 'missing_pool'}
|
let(:missing_poolname) { 'missing_pool'}
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
allow(connection.serviceInstance).to receive(:find_datacenter).and_return(datacenter_object)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with empty folder hierarchy' do
|
context 'with empty folder hierarchy' do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter() }
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should ensure the connection' do
|
it 'should ensure the connection' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/209')
|
pending('https://github.com/puppetlabs/vmpooler/issues/209')
|
||||||
expect(subject).to receive(:ensure_connected)
|
expect(subject).to receive(:ensure_connected)
|
||||||
|
|
||||||
subject.find_pool(poolname,connection)
|
subject.find_pool(poolname,connection,datacenter_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return nil if the pool is not found' do
|
it 'should return nil if the pool is not found' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/209')
|
pending('https://github.com/puppetlabs/vmpooler/issues/209')
|
||||||
expect(subject.find_pool(missing_poolname,connection)).to be_nil
|
expect(subject.find_pool(missing_poolname,connection,datacenter_name)).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with multiple datacenters' do
|
||||||
|
let(:poolpath) { 'pool' }
|
||||||
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => 'AnotherDC',
|
||||||
|
:hostfolder_tree => {
|
||||||
|
'folder1' => nil,
|
||||||
|
'folder2' => nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ :name => datacenter_name,
|
||||||
|
:hostfolder_tree => {
|
||||||
|
'folder3' => nil,
|
||||||
|
'pool' => {:object_type => 'resource_pool'},
|
||||||
|
'folder4' => nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
it 'should return the pool when found' do
|
||||||
|
result = subject.find_pool(poolpath,connection, datacenter_name)
|
||||||
|
|
||||||
|
expect(result).to_not be_nil
|
||||||
|
expect(result.name).to eq('pool')
|
||||||
|
expect(result.is_a?(RbVmomi::VIM::ResourcePool)).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -2398,10 +2665,18 @@ EOT
|
||||||
},
|
},
|
||||||
].each do |testcase|
|
].each do |testcase|
|
||||||
context testcase[:context] do
|
context testcase[:context] do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({ :hostfolder_tree => testcase[:hostfolder_tree]}) }
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
|
:hostfolder_tree => testcase[:hostfolder_tree],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should return the pool when found' do
|
it 'should return the pool when found' do
|
||||||
result = subject.find_pool(testcase[:poolpath],connection)
|
result = subject.find_pool(testcase[:poolpath],connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(testcase[:poolname])
|
expect(result.name).to eq(testcase[:poolname])
|
||||||
|
|
@ -2410,7 +2685,7 @@ EOT
|
||||||
|
|
||||||
it 'should return nil if the poolname is not found' do
|
it 'should return nil if the poolname is not found' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/209')
|
pending('https://github.com/puppetlabs/vmpooler/issues/209')
|
||||||
expect(subject.find_pool(missing_poolname,connection)).to be_nil
|
expect(subject.find_pool(missing_poolname,connection,datacenter_name)).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -2455,18 +2730,26 @@ EOT
|
||||||
},
|
},
|
||||||
].each do |testcase|
|
].each do |testcase|
|
||||||
context testcase[:context] do
|
context testcase[:context] do
|
||||||
let(:datacenter_object) { mock_RbVmomi_VIM_Datacenter({ :hostfolder_tree => testcase[:hostfolder_tree]}) }
|
let(:connection_options) {{
|
||||||
|
:serviceContent => {
|
||||||
|
:datacenters => [
|
||||||
|
{ :name => datacenter_name,
|
||||||
|
:hostfolder_tree => testcase[:hostfolder_tree],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
it 'should ensure the connection' do
|
it 'should ensure the connection' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/210')
|
pending('https://github.com/puppetlabs/vmpooler/issues/210')
|
||||||
expect(subject).to receive(:ensure_connected)
|
expect(subject).to receive(:ensure_connected)
|
||||||
|
|
||||||
subject.find_pool(testcase[:poolpath])
|
subject.find_pool(testcase[:poolpath],connection,datacenter_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return the pool when found' do
|
it 'should return the pool when found' do
|
||||||
pending('https://github.com/puppetlabs/vmpooler/issues/210')
|
pending('https://github.com/puppetlabs/vmpooler/issues/210')
|
||||||
result = subject.find_pool(testcase[:poolpath])
|
result = subject.find_pool(testcase[:poolpath],connection,datacenter_name)
|
||||||
|
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.name).to eq(testcase[:poolname])
|
expect(result.name).to eq(testcase[:poolname])
|
||||||
|
|
@ -2688,7 +2971,7 @@ EOT
|
||||||
let(:connection_options) {{
|
let(:connection_options) {{
|
||||||
:serviceContent => {
|
:serviceContent => {
|
||||||
:datacenters => [
|
:datacenters => [
|
||||||
{ :name => 'MockDC', :datastores => [datastorename] }
|
{ :name => datacenter_name, :datastores => [datastorename] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
@ -2719,11 +3002,11 @@ EOT
|
||||||
} }
|
} }
|
||||||
|
|
||||||
it 'should return empty array if no VMDKs match the VM name' do
|
it 'should return empty array if no VMDKs match the VM name' do
|
||||||
expect(subject.find_vmdks('missing_vm_name',datastorename,connection)).to eq([])
|
expect(subject.find_vmdks('missing_vm_name',datastorename,connection,datacenter_name)).to eq([])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return matching VMDKs for the VM' do
|
it 'should return matching VMDKs for the VM' do
|
||||||
result = subject.find_vmdks(vmname,datastorename,connection)
|
result = subject.find_vmdks(vmname,datastorename,connection,datacenter_name)
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result.count).to eq(2)
|
expect(result.count).to eq(2)
|
||||||
# The keys for each VMDK should be less that 100 as per the mocks
|
# The keys for each VMDK should be less that 100 as per the mocks
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,27 @@
|
||||||
# The currently supported backing services are:
|
# The currently supported backing services are:
|
||||||
# - vsphere
|
# - vsphere
|
||||||
# - dummy
|
# - dummy
|
||||||
|
#
|
||||||
|
# - provider_class
|
||||||
|
# For multiple providers, specify one of the supported backing services (vsphere or dummy)
|
||||||
|
# (optional: will default to it's parent :key: name eg. 'vsphere')
|
||||||
|
#
|
||||||
|
# If you want to support more than one provider with different parameters (server, username or passwords) you have to specify the
|
||||||
|
# backing service in the provider_class configuration parameter for example 'vsphere' or 'dummy'. Each pool can specify
|
||||||
|
# the provider to use.
|
||||||
|
#
|
||||||
|
# Multiple providers example:
|
||||||
|
|
||||||
|
:vsphere-pdx:
|
||||||
|
server: 'vsphere.pdx.company.com'
|
||||||
|
username: 'vmpooler-pdx'
|
||||||
|
password: 'swimsw1msw!m'
|
||||||
|
provider_class: 'vsphere'
|
||||||
|
:vsphere-bfs:
|
||||||
|
server: 'vsphere.bfs.company.com'
|
||||||
|
username: 'vmpooler-bfs'
|
||||||
|
password: 'swimsw1msw!m'
|
||||||
|
provider_class: 'vsphere'
|
||||||
|
|
||||||
# :vsphere:
|
# :vsphere:
|
||||||
#
|
#
|
||||||
|
|
@ -33,9 +54,9 @@
|
||||||
# Whether to ignore any HTTPS negotiation errors (e.g. untrusted self-signed certificates)
|
# Whether to ignore any HTTPS negotiation errors (e.g. untrusted self-signed certificates)
|
||||||
# (optional: default true)
|
# (optional: default true)
|
||||||
#
|
#
|
||||||
# - provider_class
|
# - datacenter
|
||||||
# For multiple providers, specify one of the supported backing services (vsphere or dummy)
|
# The datacenter within vCenter to manage VMs. This can be overridden in the pool configuration
|
||||||
# (optional: will default to it's parent :key: name eg. 'vsphere')
|
# (optional: default is the first datacenter in vSphere)
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
|
|
||||||
|
|
@ -44,23 +65,6 @@
|
||||||
username: 'vmpooler'
|
username: 'vmpooler'
|
||||||
password: 'swimsw1msw!m'
|
password: 'swimsw1msw!m'
|
||||||
|
|
||||||
# If you want to support more than one provider with different parameters (server, username or passwords) you have to specify the
|
|
||||||
# backing service in the provider_class configuration parameter for example 'vsphere' or 'dummy'. Each pool can specify
|
|
||||||
# the provider to use.
|
|
||||||
#
|
|
||||||
# Multiple providers example:
|
|
||||||
|
|
||||||
:vsphere-pdx:
|
|
||||||
server: 'vsphere.pdx.company.com'
|
|
||||||
username: 'vmpooler-pdx'
|
|
||||||
password: 'swimsw1msw!m'
|
|
||||||
provider_class: 'vsphere'
|
|
||||||
:vsphere-bfs:
|
|
||||||
server: 'vsphere.bfs.company.com'
|
|
||||||
username: 'vmpooler-bfs'
|
|
||||||
password: 'swimsw1msw!m'
|
|
||||||
provider_class: 'vsphere'
|
|
||||||
|
|
||||||
# :dummy:
|
# :dummy:
|
||||||
#
|
#
|
||||||
# The dummy backing service is a simple text file service that can be used
|
# The dummy backing service is a simple text file service that can be used
|
||||||
|
|
@ -465,6 +469,10 @@
|
||||||
# The vSphere 'datastore' destination for spawned clones.
|
# The vSphere 'datastore' destination for spawned clones.
|
||||||
# (required)
|
# (required)
|
||||||
#
|
#
|
||||||
|
# - datacenter
|
||||||
|
# The datacenter within vCenter to manage VMs.
|
||||||
|
# (optional: default is the first datacenter in vSphere)
|
||||||
|
#
|
||||||
# Example:
|
# Example:
|
||||||
|
|
||||||
:pools:
|
:pools:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue