mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
commit
2eb5a3803d
4 changed files with 258 additions and 130 deletions
|
@ -10,10 +10,13 @@ from __future__ import absolute_import
|
|||
import os
|
||||
import tempfile
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
|
@ -35,26 +38,28 @@ def mount(location, access='rw'):
|
|||
salt '*' guest.mount /srv/images/fedora.qcow
|
||||
'''
|
||||
root = os.path.join(
|
||||
tempfile.gettempdir(),
|
||||
'guest',
|
||||
location.lstrip(os.sep).replace('/', '.')
|
||||
)
|
||||
tempfile.gettempdir(),
|
||||
'guest',
|
||||
location.lstrip(os.sep).replace('/', '.')
|
||||
)
|
||||
log.debug('Using root {0}'.format(root))
|
||||
if not os.path.isdir(root):
|
||||
try:
|
||||
os.makedirs(root)
|
||||
except OSError:
|
||||
# somehow the directory already exists
|
||||
# Somehow the path already exists
|
||||
pass
|
||||
while True:
|
||||
if os.listdir(root):
|
||||
# Stuf is in there, don't use it
|
||||
# Stuff is in there, don't use it
|
||||
hash_type = getattr(hashlib, __opts__.get('hash_type', 'md5'))
|
||||
rand = hash_type(os.urandom(32)).hexdigest()
|
||||
root = os.path.join(
|
||||
tempfile.gettempdir(),
|
||||
'guest',
|
||||
location.lstrip(os.sep).replace('/', '.') + rand
|
||||
)
|
||||
)
|
||||
log.debug('Establishing new root as {0}'.format(root))
|
||||
else:
|
||||
break
|
||||
cmd = 'guestmount -i -a {0} --{1} {2}'.format(location, access, root)
|
||||
|
|
|
@ -86,7 +86,7 @@ def _umount(mpt, ftype):
|
|||
|
||||
|
||||
def apply_(path, id_=None, config=None, approve_key=True, install=True,
|
||||
prep_install=False):
|
||||
prep_install=False, pub_key=None, priv_key=None):
|
||||
'''
|
||||
Seed a location (disk image, directory, or block device) with the
|
||||
minion config, approve the minion's key, and/or install salt-minion.
|
||||
|
@ -126,18 +126,27 @@ def apply_(path, id_=None, config=None, approve_key=True, install=True,
|
|||
return '{0} does not exist'.format(path)
|
||||
ftype = stats['type']
|
||||
path = stats['target']
|
||||
log.debug('Mounting {0} at {1}'.format(ftype, path))
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError:
|
||||
# The directory already exists
|
||||
pass
|
||||
|
||||
mpt = _mount(path, ftype)
|
||||
|
||||
if not mpt:
|
||||
return '{0} could not be mounted'.format(path)
|
||||
|
||||
tmp = os.path.join(mpt, 'tmp')
|
||||
log.debug('Attempting to create directory {0}'.format(tmp))
|
||||
try:
|
||||
os.makedirs(tmp)
|
||||
except OSError:
|
||||
if not os.path.isdir(tmp):
|
||||
raise
|
||||
cfg_files = mkconfig(config, tmp=tmp, id_=id_, approve_key=approve_key)
|
||||
cfg_files = mkconfig(config, tmp=tmp, id_=id_, approve_key=approve_key,
|
||||
pub_key=pub_key, priv_key=priv_key)
|
||||
|
||||
if _check_install(mpt):
|
||||
# salt-minion is already installed, just move the config and keys
|
||||
|
@ -157,8 +166,7 @@ def apply_(path, id_=None, config=None, approve_key=True, install=True,
|
|||
os.rename(cfg_files['config'], os.path.join(mpt, 'etc/salt/minion'))
|
||||
res = True
|
||||
elif install:
|
||||
log.info('attempting to install salt-minion to '
|
||||
'{0}'.format(mpt))
|
||||
log.info('Attempting to install salt-minion to {0}'.format(mpt))
|
||||
res = _install(mpt)
|
||||
elif prep_install:
|
||||
log.error('The prep_install option is no longer supported. Please use '
|
||||
|
@ -214,12 +222,16 @@ def mkconfig(config=None,
|
|||
privkeyfn = os.path.join(tmp, 'minion.pem')
|
||||
preseeded = pub_key and priv_key
|
||||
if preseeded:
|
||||
log.debug('Writing minion.pub to {0}'.format(pubkeyfn))
|
||||
log.debug('Writing minion.pem to {0}'.format(privkeyfn))
|
||||
with salt.utils.fopen(pubkeyfn, 'w') as fic:
|
||||
fic.write(_file_or_content(pub_key))
|
||||
with salt.utils.fopen(privkeyfn, 'w') as fic:
|
||||
fic.write(_file_or_content(priv_key))
|
||||
os.chmod(pubkeyfn, 0o600)
|
||||
os.chmod(privkeyfn, 0o600)
|
||||
with salt.utils.fopen(pubkeyfn, 'w') as fic:
|
||||
fic.write(_file_or_content(pub_key))
|
||||
else:
|
||||
salt.crypt.gen_keys(tmp, 'minion', 2048)
|
||||
if approve_key and not preseeded:
|
||||
|
@ -236,7 +248,6 @@ def _install(mpt):
|
|||
install it.
|
||||
Return True if install is successful or already installed.
|
||||
'''
|
||||
|
||||
_check_resolv(mpt)
|
||||
boot_, tmppath = (prep_bootstrap(mpt)
|
||||
or salt.syspaths.BOOTSTRAP)
|
||||
|
|
|
@ -27,6 +27,7 @@ from salt.ext.six.moves import StringIO as _StringIO # pylint: disable=import-e
|
|||
from xml.dom import minidom
|
||||
try:
|
||||
import libvirt # pylint: disable=import-error
|
||||
from libvirt import libvirtError
|
||||
HAS_LIBVIRT = True
|
||||
except ImportError:
|
||||
HAS_LIBVIRT = False
|
||||
|
@ -139,7 +140,7 @@ def __get_conn():
|
|||
__esxi_auth(),
|
||||
0]],
|
||||
'qemu': [libvirt.open, [conn_str]],
|
||||
}
|
||||
}
|
||||
|
||||
hypervisor = __salt__['config.get']('libvirt:hypervisor', 'qemu')
|
||||
|
||||
|
@ -214,7 +215,7 @@ def _gen_xml(name,
|
|||
hypervisor,
|
||||
**kwargs):
|
||||
'''
|
||||
Generate the XML string to define a libvirt vm
|
||||
Generate the XML string to define a libvirt VM
|
||||
'''
|
||||
hypervisor = 'vmware' if hypervisor == 'esxi' else hypervisor
|
||||
mem = mem * 1024 # MB
|
||||
|
@ -501,9 +502,9 @@ def _nic_profile(profile_name, hypervisor, **kwargs):
|
|||
attributes[key] = value
|
||||
|
||||
def _assign_mac(attributes):
|
||||
dmac = '{0}_mac'.format(attributes['name'])
|
||||
if dmac in kwargs:
|
||||
dmac = kwargs[dmac]
|
||||
dmac = kwargs.get('dmac', None)
|
||||
if dmac is not None:
|
||||
log.debug('DMAC address is {0}'.format(dmac))
|
||||
if salt.utils.validate.net.mac(dmac):
|
||||
attributes['mac'] = dmac
|
||||
else:
|
||||
|
@ -530,6 +531,11 @@ def init(name,
|
|||
start=True, # pylint: disable=redefined-outer-name
|
||||
disk='default',
|
||||
saltenv='base',
|
||||
seed=True,
|
||||
install=True,
|
||||
pub_key=None,
|
||||
priv_key=None,
|
||||
seed_cmd='seed.apply',
|
||||
**kwargs):
|
||||
'''
|
||||
Initialize a new vm
|
||||
|
@ -542,17 +548,21 @@ def init(name,
|
|||
salt 'hypervisor' virt.init vm_name 4 512 nic=profile disk=profile
|
||||
'''
|
||||
hypervisor = __salt__['config.get']('libvirt:hypervisor', hypervisor)
|
||||
log.debug('Using hyperisor {0}'.format(hypervisor))
|
||||
|
||||
nicp = _nic_profile(nic, hypervisor, **kwargs)
|
||||
log.debug('NIC profile is {0}'.format(nicp))
|
||||
|
||||
diskp = None
|
||||
seedable = False
|
||||
if image: # with disk template image
|
||||
log.debug('Image {0} will be used'.format(image))
|
||||
# if image was used, assume only one disk, i.e. the
|
||||
# 'default' disk profile
|
||||
# TODO: make it possible to use disk profiles and use the
|
||||
# template image as the system disk
|
||||
diskp = _disk_profile('default', hypervisor, **kwargs)
|
||||
log.debug('Disk profile is {0}'.format(diskp))
|
||||
|
||||
# When using a disk profile extract the sole dict key of the first
|
||||
# array element as the filename for disk
|
||||
|
@ -562,9 +572,10 @@ def init(name,
|
|||
|
||||
if hypervisor in ['esxi', 'vmware']:
|
||||
# TODO: we should be copying the image file onto the ESX host
|
||||
raise SaltInvocationError('virt.init does not support image '
|
||||
'template template in conjunction '
|
||||
'with esxi hypervisor')
|
||||
raise SaltInvocationError(
|
||||
'virt.init does not support image template template in '
|
||||
'conjunction with esxi hypervisor'
|
||||
)
|
||||
elif hypervisor in ['qemu', 'kvm']:
|
||||
img_dir = __salt__['config.option']('virt.images')
|
||||
img_dest = os.path.join(
|
||||
|
@ -574,55 +585,71 @@ def init(name,
|
|||
)
|
||||
img_dir = os.path.dirname(img_dest)
|
||||
sfn = __salt__['cp.cache_file'](image, saltenv)
|
||||
if not os.path.isdir(img_dir):
|
||||
os.makedirs(img_dir)
|
||||
log.debug('Image directory is {0}'.format(img_dir))
|
||||
|
||||
try:
|
||||
os.makedirs(img_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
log.debug('Copying {0} to {1}'.format(sfn, img_dest))
|
||||
salt.utils.files.copyfile(sfn, img_dest)
|
||||
mask = os.umask(0)
|
||||
os.umask(mask)
|
||||
# Apply umask and remove exec bit
|
||||
mode = (0o0777 ^ mask) & 0o0666
|
||||
os.chmod(img_dest, mode)
|
||||
|
||||
except (IOError, OSError) as e:
|
||||
raise CommandExecutionError('problem copying image. {0} - {1}'.format(image, e))
|
||||
|
||||
seedable = True
|
||||
else:
|
||||
log.error('unsupported hypervisor when handling disk image')
|
||||
|
||||
log.error('Unsupported hypervisor when handling disk image')
|
||||
else:
|
||||
# no disk template image specified, create disks based on disk profile
|
||||
diskp = _disk_profile(disk, hypervisor, **kwargs)
|
||||
log.debug('No image specified, disk profile will be used: {0}'.format(diskp))
|
||||
if hypervisor in ['qemu', 'kvm']:
|
||||
# TODO: we should be creating disks in the local filesystem with
|
||||
# qemu-img
|
||||
raise SaltInvocationError('virt.init does not support disk '
|
||||
'profiles in conjunction with '
|
||||
'qemu/kvm at this time, use image '
|
||||
'template instead')
|
||||
raise SaltInvocationError(
|
||||
'virt.init does not support disk profiles in conjunction with '
|
||||
'qemu/kvm at this time, use image template instead'
|
||||
)
|
||||
else:
|
||||
# assume libvirt manages disks for us
|
||||
for disk in diskp:
|
||||
for disk_name, args in six.iteritems(disk):
|
||||
xml = _gen_vol_xml(name,
|
||||
disk_name,
|
||||
args['size'],
|
||||
hypervisor)
|
||||
log.debug('Generating libvirt XML for {0}'.format(disk))
|
||||
xml = _gen_vol_xml(
|
||||
name,
|
||||
disk_name,
|
||||
args['size'],
|
||||
hypervisor,
|
||||
)
|
||||
define_vol_xml_str(xml)
|
||||
|
||||
log.debug('Generating VM XML')
|
||||
xml = _gen_xml(name, cpu, mem, diskp, nicp, hypervisor, **kwargs)
|
||||
define_xml_str(xml)
|
||||
try:
|
||||
define_xml_str(xml)
|
||||
except libvirtError:
|
||||
# This domain already exists
|
||||
pass
|
||||
|
||||
if kwargs.get('seed') and seedable:
|
||||
install = kwargs.get('install', True)
|
||||
seed_cmd = kwargs.get('seed_cmd', 'seed.apply')
|
||||
|
||||
__salt__[seed_cmd](img_dest,
|
||||
id_=name,
|
||||
config=kwargs.get('config'),
|
||||
install=install)
|
||||
if seed and seedable:
|
||||
log.debug('Seed command is {0}'.format(seed_cmd))
|
||||
__salt__[seed_cmd](
|
||||
img_dest,
|
||||
id_=name,
|
||||
config=kwargs.get('config'),
|
||||
install=install,
|
||||
pub_key=pub_key,
|
||||
priv_key=priv_key,
|
||||
)
|
||||
if start:
|
||||
log.debug('Creating {0}'.format(name))
|
||||
create(name)
|
||||
|
||||
return True
|
||||
|
|
|
@ -5,11 +5,13 @@ Control virtual machines via Salt
|
|||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import, print_function
|
||||
import os.path
|
||||
import logging
|
||||
|
||||
# Import Salt libs
|
||||
import salt.client
|
||||
import salt.utils.virt
|
||||
import salt.utils.cloud
|
||||
import salt.key
|
||||
from salt.exceptions import SaltClientError
|
||||
|
||||
|
@ -19,14 +21,13 @@ import salt.ext.six as six
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _determine_hyper(data, omit=''):
|
||||
def _determine_host(data, omit=''):
|
||||
'''
|
||||
Determine what the most resource free hypervisor is based on the given
|
||||
data
|
||||
Determine what the most resource free host is based on the given data
|
||||
'''
|
||||
# This is just checking for the hyper with the most free ram, this needs
|
||||
# This is just checking for the host with the most free ram, this needs
|
||||
# to be much more complicated.
|
||||
hyper = ''
|
||||
host = ''
|
||||
bestmem = 0
|
||||
for hv_, comps in six.iteritems(data):
|
||||
if hv_ == omit:
|
||||
|
@ -35,13 +36,13 @@ def _determine_hyper(data, omit=''):
|
|||
continue
|
||||
if comps.get('freemem', 0) > bestmem:
|
||||
bestmem = comps['freemem']
|
||||
hyper = hv_
|
||||
return hyper
|
||||
host = hv_
|
||||
return host
|
||||
|
||||
|
||||
def _find_vm(name, data, quiet=False):
|
||||
'''
|
||||
Scan the query data for the named vm
|
||||
Scan the query data for the named VM
|
||||
'''
|
||||
for hv_ in data:
|
||||
# Check if data is a dict, and not '"virt.full_info" is not available.'
|
||||
|
@ -55,12 +56,20 @@ def _find_vm(name, data, quiet=False):
|
|||
return {}
|
||||
|
||||
|
||||
def query(hyper=None, quiet=False):
|
||||
def query(host=None, quiet=False, hyper=None):
|
||||
'''
|
||||
Query the virtual machines. When called without options all hypervisors
|
||||
are detected and a full query is returned. A single hypervisor can be
|
||||
passed in to specify an individual hypervisor to query.
|
||||
Query the virtual machines. When called without options all hosts
|
||||
are detected and a full query is returned. A single host can be
|
||||
passed in to specify an individual host to query.
|
||||
'''
|
||||
if hyper is not None:
|
||||
salt.utils.warn_until(
|
||||
'Carbon',
|
||||
'Please use "host" instead of "hyper". The "hyper" argument will '
|
||||
'be removed in the Carbon release of Salt'
|
||||
)
|
||||
host = hyper
|
||||
|
||||
if quiet:
|
||||
log.warn('\'quiet\' is deprecated. Please migrate to --quiet')
|
||||
ret = {}
|
||||
|
@ -74,8 +83,8 @@ def query(hyper=None, quiet=False):
|
|||
continue
|
||||
chunk = {}
|
||||
id_ = next(info.iterkeys())
|
||||
if hyper:
|
||||
if hyper != id_:
|
||||
if host:
|
||||
if host != id_:
|
||||
continue
|
||||
if not isinstance(info[id_], dict):
|
||||
continue
|
||||
|
@ -92,13 +101,21 @@ def query(hyper=None, quiet=False):
|
|||
return ret
|
||||
|
||||
|
||||
def list(hyper=None, quiet=False): # pylint: disable=redefined-builtin
|
||||
def list(host=None, quiet=False, hyper=None): # pylint: disable=redefined-builtin
|
||||
'''
|
||||
List the virtual machines on each hyper, this is a simplified query,
|
||||
showing only the virtual machine names belonging to each hypervisor.
|
||||
A single hypervisor can be passed in to specify an individual hypervisor
|
||||
List the virtual machines on each host, this is a simplified query,
|
||||
showing only the virtual machine names belonging to each host.
|
||||
A single host can be passed in to specify an individual host
|
||||
to list.
|
||||
'''
|
||||
if hyper is not None:
|
||||
salt.utils.warn_until(
|
||||
'Carbon',
|
||||
'Please use "host" instead of "hyper". The "hyper" argument will '
|
||||
'be removed in the Carbon release of Salt'
|
||||
)
|
||||
host = hyper
|
||||
|
||||
if quiet:
|
||||
log.warn('\'quiet\' is deprecated. Please migrate to --quiet')
|
||||
ret = {}
|
||||
|
@ -111,8 +128,8 @@ def list(hyper=None, quiet=False): # pylint: disable=redefined-builtin
|
|||
continue
|
||||
chunk = {}
|
||||
id_ = next(six.iterkeys(info))
|
||||
if hyper:
|
||||
if hyper != id_:
|
||||
if host:
|
||||
if host != id_:
|
||||
continue
|
||||
if not isinstance(info[id_], dict):
|
||||
continue
|
||||
|
@ -134,22 +151,36 @@ def list(hyper=None, quiet=False): # pylint: disable=redefined-builtin
|
|||
return ret
|
||||
|
||||
|
||||
def next_host():
|
||||
'''
|
||||
Return the host to use for the next autodeployed VM. This queries
|
||||
the available host and executes some math the determine the most
|
||||
"available" next host.
|
||||
'''
|
||||
host = _determine_host(query(quiet=True))
|
||||
print(host)
|
||||
return host
|
||||
|
||||
|
||||
def next_hyper():
|
||||
'''
|
||||
Return the hypervisor to use for the next autodeployed vm. This queries
|
||||
the available hypervisors and executes some math the determine the most
|
||||
"available" next hypervisor.
|
||||
Return the host to use for the next autodeployed VM. This queries
|
||||
the available host and executes some math the determine the most
|
||||
"available" next host.
|
||||
'''
|
||||
hyper = _determine_hyper(query(quiet=True))
|
||||
print(hyper)
|
||||
return hyper
|
||||
salt.utils.warn_until(
|
||||
'Carbon',
|
||||
'Please use "host" instead of "hyper". The "hyper" argument will '
|
||||
'be removed in the Carbon release of Salt'
|
||||
)
|
||||
return next_host()
|
||||
|
||||
|
||||
def hyper_info(hyper=None):
|
||||
def host_info(host=None):
|
||||
'''
|
||||
Return information about the hypervisors connected to this master
|
||||
Return information about the host connected to this master
|
||||
'''
|
||||
data = query(hyper, quiet=True)
|
||||
data = query(host, quiet=True)
|
||||
for id_ in data:
|
||||
if 'vm_info' in data[id_]:
|
||||
data[id_].pop('vm_info')
|
||||
|
@ -157,15 +188,32 @@ def hyper_info(hyper=None):
|
|||
return data
|
||||
|
||||
|
||||
def hyper_info(hyper=None):
|
||||
'''
|
||||
Return information about the host connected to this master
|
||||
'''
|
||||
salt.utils.warn_until(
|
||||
'Carbon',
|
||||
'Please use "host" instead of "hyper". The "hyper" argument will '
|
||||
'be removed in the Carbon release of Salt'
|
||||
)
|
||||
return host_info(hyper)
|
||||
|
||||
|
||||
def init(
|
||||
name,
|
||||
cpu,
|
||||
mem,
|
||||
image,
|
||||
hyper=None,
|
||||
hypervisor='kvm',
|
||||
host=None,
|
||||
seed=True,
|
||||
nic='default',
|
||||
install=True):
|
||||
install=True,
|
||||
start=True,
|
||||
disk='default',
|
||||
saltenv='base'):
|
||||
'''
|
||||
This routine is used to create a new virtual machine. This routines takes
|
||||
a number of options to determine what the newly created virtual machine
|
||||
|
@ -186,58 +234,94 @@ def init(
|
|||
The network location of the virtual machine image, commonly a location
|
||||
on the salt fileserver, but http, https and ftp can also be used.
|
||||
|
||||
hyper
|
||||
The hypervisor to use for the new virtual machine, if this is omitted
|
||||
Salt will automatically detect what hypervisor to use.
|
||||
hypervisor
|
||||
The hypervisor to use for the new virtual machine. Default is 'kvm'.
|
||||
|
||||
host
|
||||
The host to use for the new virtual machine, if this is omitted
|
||||
Salt will automatically detect what host to use.
|
||||
|
||||
seed
|
||||
Set to False to prevent Salt from seeding the new virtual machine.
|
||||
|
||||
nic
|
||||
The nic profile to use, defaults to the "default" nic profile which
|
||||
assumes a single network interface per vm associated with the "br0"
|
||||
assumes a single network interface per VM associated with the "br0"
|
||||
bridge on the master.
|
||||
|
||||
install
|
||||
Set to False to prevent Salt from installing a minion on the new vm
|
||||
Set to False to prevent Salt from installing a minion on the new VM
|
||||
before it spins up.
|
||||
|
||||
disk
|
||||
The disk profile to use
|
||||
|
||||
saltenv
|
||||
The Salt environment to use
|
||||
'''
|
||||
__jid_event__.fire_event({'message': 'Searching for Hypervisors'}, 'progress')
|
||||
data = query(hyper, quiet=True)
|
||||
if hyper is not None:
|
||||
salt.utils.warn_until(
|
||||
'Carbon',
|
||||
'Please use "host" instead of "hyper". The "hyper" argument will '
|
||||
'be removed in the Carbon release of Salt'
|
||||
)
|
||||
host = hyper
|
||||
|
||||
__jid_event__.fire_event({'message': 'Searching for hosts'}, 'progress')
|
||||
data = query(host, quiet=True)
|
||||
# Check if the name is already deployed
|
||||
for hyper in data:
|
||||
if 'vm_info' in data[hyper]:
|
||||
if name in data[hyper]['vm_info']:
|
||||
__jid_event__.fire_event({'message': 'Virtual machine {0} is already deployed'.format(name)}, 'progress')
|
||||
for node in data:
|
||||
if 'vm_info' in data[node]:
|
||||
if name in data[node]['vm_info']:
|
||||
__jid_event__.fire_event(
|
||||
{'message': 'Virtual machine {0} is already deployed'.format(name)},
|
||||
'progress'
|
||||
)
|
||||
return 'fail'
|
||||
|
||||
if hyper is None:
|
||||
hyper = _determine_hyper(data)
|
||||
if host is None:
|
||||
host = _determine_host(data)
|
||||
|
||||
if hyper not in data or not hyper:
|
||||
__jid_event__.fire_event({'message': 'Hypervisor {0} was not found'.format(hyper)}, 'progress')
|
||||
if host not in data or not host:
|
||||
__jid_event__.fire_event(
|
||||
{'message': 'Host {0} was not found'.format(host)},
|
||||
'progress'
|
||||
)
|
||||
return 'fail'
|
||||
|
||||
pub_key = None
|
||||
priv_key = None
|
||||
if seed:
|
||||
__jid_event__.fire_event({'message': 'Minion will be preseeded'}, 'progress')
|
||||
kv_ = salt.utils.virt.VirtKey(hyper, name, __opts__)
|
||||
kv_.authorize()
|
||||
priv_key, pub_key = salt.utils.cloud.gen_keys()
|
||||
accepted_key = os.path.join(__opts__['pki_dir'], 'minions', name)
|
||||
with salt.utils.fopen(accepted_key, 'w') as fp_:
|
||||
fp_.write(pub_key)
|
||||
|
||||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
|
||||
__jid_event__.fire_event({'message': 'Creating VM {0} on hypervisor {1}'.format(name, hyper)}, 'progress')
|
||||
__jid_event__.fire_event(
|
||||
{'message': 'Creating VM {0} on host {1}'.format(name, host)},
|
||||
'progress'
|
||||
)
|
||||
try:
|
||||
cmd_ret = client.cmd_iter(
|
||||
hyper,
|
||||
host,
|
||||
'virt.init',
|
||||
[
|
||||
name,
|
||||
cpu,
|
||||
mem,
|
||||
image,
|
||||
'seed={0}'.format(seed),
|
||||
'nic={0}'.format(nic),
|
||||
'install={0}'.format(install),
|
||||
nic,
|
||||
hypervisor,
|
||||
start,
|
||||
disk,
|
||||
saltenv,
|
||||
seed,
|
||||
install,
|
||||
pub_key,
|
||||
priv_key,
|
||||
],
|
||||
timeout=600)
|
||||
except SaltClientError as client_error:
|
||||
|
@ -253,13 +337,13 @@ def init(
|
|||
print('VM {0} initialization failed. Returned error: {1}'.format(name, ret[minion_id]['ret']))
|
||||
return 'fail'
|
||||
|
||||
__jid_event__.fire_event({'message': 'VM {0} initialized on hypervisor {1}'.format(name, hyper)}, 'progress')
|
||||
__jid_event__.fire_event({'message': 'VM {0} initialized on host {1}'.format(name, host)}, 'progress')
|
||||
return 'good'
|
||||
|
||||
|
||||
def vm_info(name, quiet=False):
|
||||
'''
|
||||
Return the information on the named vm
|
||||
Return the information on the named VM
|
||||
'''
|
||||
data = query(quiet=True)
|
||||
return _find_vm(name, data, quiet)
|
||||
|
@ -267,18 +351,18 @@ def vm_info(name, quiet=False):
|
|||
|
||||
def reset(name):
|
||||
'''
|
||||
Force power down and restart an existing vm
|
||||
Force power down and restart an existing VM
|
||||
'''
|
||||
ret = {}
|
||||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
data = vm_info(name, quiet=True)
|
||||
if not data:
|
||||
__jid_event__.fire_event({'message': 'Failed to find vm {0} to reset'.format(name)}, 'progress')
|
||||
__jid_event__.fire_event({'message': 'Failed to find VM {0} to reset'.format(name)}, 'progress')
|
||||
return 'fail'
|
||||
hyper = next(six.iterkeys(data))
|
||||
host = next(six.iterkeys(data))
|
||||
try:
|
||||
cmd_ret = client.cmd_iter(
|
||||
hyper,
|
||||
host,
|
||||
'virt.reset',
|
||||
[name],
|
||||
timeout=600)
|
||||
|
@ -298,15 +382,15 @@ def start(name):
|
|||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
data = vm_info(name, quiet=True)
|
||||
if not data:
|
||||
__jid_event__.fire_event({'message': 'Failed to find vm {0} to start'.format(name)}, 'progress')
|
||||
__jid_event__.fire_event({'message': 'Failed to find VM {0} to start'.format(name)}, 'progress')
|
||||
return 'fail'
|
||||
hyper = next(six.iterkeys(data))
|
||||
if data[hyper][name]['state'] == 'running':
|
||||
host = next(six.iterkeys(data))
|
||||
if data[host][name]['state'] == 'running':
|
||||
print('VM {0} is already running'.format(name))
|
||||
return 'bad state'
|
||||
try:
|
||||
cmd_ret = client.cmd_iter(
|
||||
hyper,
|
||||
host,
|
||||
'virt.start',
|
||||
[name],
|
||||
timeout=600)
|
||||
|
@ -326,15 +410,15 @@ def force_off(name):
|
|||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
data = vm_info(name, quiet=True)
|
||||
if not data:
|
||||
print('Failed to find vm {0} to destroy'.format(name))
|
||||
print('Failed to find VM {0} to destroy'.format(name))
|
||||
return 'fail'
|
||||
hyper = next(six.iterkeys(data))
|
||||
if data[hyper][name]['state'] == 'shutdown':
|
||||
host = next(six.iterkeys(data))
|
||||
if data[host][name]['state'] == 'shutdown':
|
||||
print('VM {0} is already shutdown'.format(name))
|
||||
return'bad state'
|
||||
try:
|
||||
cmd_ret = client.cmd_iter(
|
||||
hyper,
|
||||
host,
|
||||
'virt.destroy',
|
||||
[name],
|
||||
timeout=600)
|
||||
|
@ -348,18 +432,18 @@ def force_off(name):
|
|||
|
||||
def purge(name, delete_key=True):
|
||||
'''
|
||||
Destroy the named vm
|
||||
Destroy the named VM
|
||||
'''
|
||||
ret = {}
|
||||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
data = vm_info(name, quiet=True)
|
||||
if not data:
|
||||
__jid_event__.fire_event({'error': 'Failed to find vm {0} to purge'.format(name)}, 'progress')
|
||||
__jid_event__.fire_event({'error': 'Failed to find VM {0} to purge'.format(name)}, 'progress')
|
||||
return 'fail'
|
||||
hyper = next(six.iterkeys(data))
|
||||
host = next(six.iterkeys(data))
|
||||
try:
|
||||
cmd_ret = client.cmd_iter(
|
||||
hyper,
|
||||
host,
|
||||
'virt.purge',
|
||||
[name, True],
|
||||
timeout=600)
|
||||
|
@ -370,6 +454,7 @@ def purge(name, delete_key=True):
|
|||
ret.update(comp)
|
||||
|
||||
if delete_key:
|
||||
log.debug('Deleting key {0}'.format(name))
|
||||
skey = salt.key.Key(__opts__)
|
||||
skey.delete_key(name)
|
||||
__jid_event__.fire_event({'message': 'Purged VM {0}'.format(name)}, 'progress')
|
||||
|
@ -378,7 +463,7 @@ def purge(name, delete_key=True):
|
|||
|
||||
def pause(name):
|
||||
'''
|
||||
Pause the named vm
|
||||
Pause the named VM
|
||||
'''
|
||||
ret = {}
|
||||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
|
@ -387,13 +472,13 @@ def pause(name):
|
|||
if not data:
|
||||
__jid_event__.fire_event({'error': 'Failed to find VM {0} to pause'.format(name)}, 'progress')
|
||||
return 'fail'
|
||||
hyper = next(six.iterkeys(data))
|
||||
if data[hyper][name]['state'] == 'paused':
|
||||
host = next(six.iterkeys(data))
|
||||
if data[host][name]['state'] == 'paused':
|
||||
__jid_event__.fire_event({'error': 'VM {0} is already paused'.format(name)}, 'progress')
|
||||
return 'bad state'
|
||||
try:
|
||||
cmd_ret = client.cmd_iter(
|
||||
hyper,
|
||||
host,
|
||||
'virt.pause',
|
||||
[name],
|
||||
timeout=600)
|
||||
|
@ -407,7 +492,7 @@ def pause(name):
|
|||
|
||||
def resume(name):
|
||||
'''
|
||||
Resume a paused vm
|
||||
Resume a paused VM
|
||||
'''
|
||||
ret = {}
|
||||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
|
@ -415,13 +500,13 @@ def resume(name):
|
|||
if not data:
|
||||
__jid_event__.fire_event({'error': 'Failed to find VM {0} to pause'.format(name)}, 'progress')
|
||||
return 'not found'
|
||||
hyper = next(six.iterkeys(data))
|
||||
if data[hyper][name]['state'] != 'paused':
|
||||
host = next(six.iterkeys(data))
|
||||
if data[host][name]['state'] != 'paused':
|
||||
__jid_event__.fire_event({'error': 'VM {0} is not paused'.format(name)}, 'progress')
|
||||
return 'bad state'
|
||||
try:
|
||||
cmd_ret = client.cmd_iter(
|
||||
hyper,
|
||||
host,
|
||||
'virt.resume',
|
||||
[name],
|
||||
timeout=600)
|
||||
|
@ -435,36 +520,36 @@ def resume(name):
|
|||
|
||||
def migrate(name, target=''):
|
||||
'''
|
||||
Migrate a vm from one hypervisor to another. This routine will just start
|
||||
Migrate a VM from one host to another. This routine will just start
|
||||
the migration and display information on how to look up the progress.
|
||||
'''
|
||||
client = salt.client.get_local_client(__opts__['conf_file'])
|
||||
data = query(quiet=True)
|
||||
origin_data = _find_vm(name, data, quiet=True)
|
||||
try:
|
||||
origin_hyper = list(origin_data.keys())[0]
|
||||
origin_host = list(origin_data.keys())[0]
|
||||
except IndexError:
|
||||
__jid_event__.fire_event({'error': 'Named vm {0} was not found to migrate'.format(name)}, 'progress')
|
||||
__jid_event__.fire_event({'error': 'Named VM {0} was not found to migrate'.format(name)}, 'progress')
|
||||
return ''
|
||||
disks = origin_data[origin_hyper][name]['disks']
|
||||
disks = origin_data[origin_host][name]['disks']
|
||||
if not origin_data:
|
||||
__jid_event__.fire_event({'error': 'Named vm {0} was not found to migrate'.format(name)}, 'progress')
|
||||
__jid_event__.fire_event({'error': 'Named VM {0} was not found to migrate'.format(name)}, 'progress')
|
||||
return ''
|
||||
if not target:
|
||||
target = _determine_hyper(data, origin_hyper)
|
||||
target = _determine_host(data, origin_host)
|
||||
if target not in data:
|
||||
__jid_event__.fire_event({'error': 'Target hypervisor {0} not found'.format(origin_data)}, 'progress')
|
||||
__jid_event__.fire_event({'error': 'Target host {0} not found'.format(origin_data)}, 'progress')
|
||||
return ''
|
||||
try:
|
||||
client.cmd(target, 'virt.seed_non_shared_migrate', [disks, True])
|
||||
jid = client.cmd_async(origin_hyper,
|
||||
jid = client.cmd_async(origin_host,
|
||||
'virt.migrate_non_shared',
|
||||
[name, target])
|
||||
except SaltClientError as client_error:
|
||||
return 'Virtual machine {0} could not be migrated: {1}'.format(name, client_error)
|
||||
|
||||
msg = ('The migration of virtual machine {0} to hypervisor {1} has begun, '
|
||||
msg = ('The migration of virtual machine {0} to host {1} has begun, '
|
||||
'and can be tracked via jid {2}. The ``salt-run virt.query`` '
|
||||
'runner can also be used, the target vm will be shown as paused '
|
||||
'runner can also be used, the target VM will be shown as paused '
|
||||
'until the migration is complete.').format(name, target, jid)
|
||||
__jid_event__.fire_event({'message': msg}, 'progress')
|
||||
|
|
Loading…
Add table
Reference in a new issue