Merge pull request #44827 from mz-bmcqueen/2017.7

add more clone options to virtualbox and add better dhcp handling
This commit is contained in:
Nicole Thomas 2017-12-06 10:02:22 -05:00 committed by GitHub
commit d6c37ea19c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 21 deletions

View file

@ -48,6 +48,10 @@ log = logging.getLogger(__name__)
# The name salt will identify the lib by
__virtualname__ = 'virtualbox'
#if no clone mode is specified in the virtualbox profile
#then default to 0 which was the old default value
DEFAULT_CLONE_MODE = 0
def __virtual__():
'''
@ -85,6 +89,30 @@ def get_configured_provider():
return configured
def map_clonemode(vm_info):
"""
Convert the virtualbox config file values for clone_mode into the integers the API requires
"""
mode_map = {
'state': 0,
'child': 1,
'all': 2
}
if not vm_info:
return DEFAULT_CLONE_MODE
if 'clonemode' not in vm_info:
return DEFAULT_CLONE_MODE
if vm_info['clonemode'] in mode_map:
return mode_map[vm_info['clonemode']]
else:
raise SaltCloudSystemExit(
"Illegal clonemode for virtualbox profile. Legal values are: {}".format(','.join(mode_map.keys()))
)
def create(vm_info):
"""
Creates a virtual machine from the given VM information.
@ -102,6 +130,7 @@ def create(vm_info):
profile: <dict>
driver: <provider>:<profile>
clonefrom: <vm_name>
clonemode: <mode> (default: state, choices: state, child, all)
}
@type vm_info dict
@return dict of resulting vm. !!!Passwords can and should be included!!!
@ -133,6 +162,9 @@ def create(vm_info):
key_filename = config.get_cloud_config_value(
'private_key', vm_info, __opts__, search_global=False, default=None
)
clone_mode = map_clonemode(vm_info)
wait_for_pattern = vm_info['waitforpattern'] if 'waitforpattern' in vm_info.keys() else None
interface_index = vm_info['interfaceindex'] if 'interfaceindex' in vm_info.keys() else 0
log.debug("Going to fire event: starting create")
__utils__['cloud.fire_event'](
@ -147,7 +179,8 @@ def create(vm_info):
# to create the virtual machine.
request_kwargs = {
'name': vm_info['name'],
'clone_from': vm_info['clonefrom']
'clone_from': vm_info['clonefrom'],
'clone_mode': clone_mode
}
__utils__['cloud.fire_event'](
@ -163,17 +196,17 @@ def create(vm_info):
# Booting and deploying if needed
if power:
vb_start_vm(vm_name, timeout=boot_timeout)
ips = vb_wait_for_network_address(wait_for_ip_timeout, machine_name=vm_name)
ips = vb_wait_for_network_address(wait_for_ip_timeout, machine_name=vm_name, wait_for_pattern=wait_for_pattern)
if len(ips):
ip = ips[0]
ip = ips[interface_index]
log.info("[ {0} ] IPv4 is: {1}".format(vm_name, ip))
# ssh or smb using ip and install salt only if deploy is True
if deploy:
vm_info['key_filename'] = key_filename
vm_info['ssh_host'] = ip
res = __utils__['cloud.bootstrap'](vm_info)
res = __utils__['cloud.bootstrap'](vm_info, __opts__)
vm_result.update(res)
__utils__['cloud.fire_event'](

View file

@ -197,7 +197,7 @@ def vb_get_network_adapters(machine_name=None, machine=None):
return network_adapters
def vb_wait_for_network_address(timeout, step=None, machine_name=None, machine=None):
def vb_wait_for_network_address(timeout, step=None, machine_name=None, machine=None, wait_for_pattern=None):
'''
Wait until a machine has a network address to return or quit after the timeout
@ -209,12 +209,16 @@ def vb_wait_for_network_address(timeout, step=None, machine_name=None, machine=N
@type machine_name: str
@param machine:
@type machine: IMachine
@type wait_for_pattern: str
@param wait_for_pattern:
@type machine: str
@return:
@rtype: list
'''
kwargs = {
'machine_name': machine_name,
'machine': machine
'machine': machine,
'wait_for_pattern': wait_for_pattern
}
return wait_for(vb_get_network_addresses, timeout=timeout, step=step, default=[], func_kwargs=kwargs)
@ -251,7 +255,7 @@ def vb_wait_for_session_state(xp_session, state='Unlocked', timeout=10, step=Non
wait_for(_check_session_state, timeout=timeout, step=step, default=False, func_args=args)
def vb_get_network_addresses(machine_name=None, machine=None):
def vb_get_network_addresses(machine_name=None, machine=None, wait_for_pattern=None):
'''
TODO distinguish between private and public addresses
@ -276,21 +280,38 @@ def vb_get_network_addresses(machine_name=None, machine=None):
machine = vb_get_box().findMachine(machine_name)
ip_addresses = []
# We can't trust virtualbox to give us up to date guest properties if the machine isn't running
# For some reason it may give us outdated (cached?) values
log.debug("checking for power on:")
if machine.state == _virtualboxManager.constants.MachineState_Running:
try:
total_slots = int(machine.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/Count'))
except ValueError:
total_slots = 0
for i in range(total_slots):
try:
address = machine.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/{0}/V4/IP'.format(i))
if address:
ip_addresses.append(address)
except Exception as e:
log.debug(e.message)
log.debug("got power on:")
#wait on an arbitrary named property
#for instance use a dhcp client script to set a property via VBoxControl guestproperty set dhcp_done 1
if wait_for_pattern and not machine.getGuestPropertyValue(wait_for_pattern):
log.debug("waiting for pattern:{}:".format(wait_for_pattern))
return None
_total_slots = machine.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/Count')
#upon dhcp the net count drops to 0 and it takes some seconds for it to be set again
if not _total_slots:
log.debug("waiting for net count:{}:".format(wait_for_pattern))
return None
try:
total_slots = int(_total_slots)
for i in range(total_slots):
try:
address = machine.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/{0}/V4/IP'.format(i))
if address:
ip_addresses.append(address)
except Exception as e:
log.debug(e.message)
except ValueError as e:
log.debug(e.message)
return None
log.debug("returning ip_addresses:{}:".format(ip_addresses))
return ip_addresses
@ -339,6 +360,7 @@ def vb_create_machine(name=None):
def vb_clone_vm(
name=None,
clone_from=None,
clone_mode=0,
timeout=10000,
**kwargs
):
@ -370,7 +392,7 @@ def vb_clone_vm(
progress = source_machine.cloneTo(
new_machine,
0, # CloneMode
clone_mode, # CloneMode
None # CloneOptions : None = Full?
)