Mini Shell
"""
XenServer Cloud Driver
======================
The XenServer driver is designed to work with a Citrix XenServer.
Requires XenServer SDK
(can be downloaded from https://www.citrix.com/downloads/xenserver/product-software/ )
Place a copy of the XenAPI.py in the Python site-packages folder.
:depends: XenAPI
Example provider configuration:
.. code-block:: yaml
# /etc/salt/cloud.providers.d/myxen.conf
myxen:
driver: xen
url: http://10.0.0.120
user: root
password: p@ssw0rd
Example profile configuration:
.. code-block:: yaml
# /etc/salt/cloud.profiles.d/myxen.conf
suse:
provider: myxen
user: root
password: p@ssw0rd
image: opensuseleap42_2-template
storage_repo: 'Local storage'
resource_pool: default_pool
clone: True
minion:
master: 10.0.0.18
sles:
provider: myxen
user: root
clone: False
image: sles12sp2-template
deploy: False
w2k12:
provider: myxen
image: w2k12svr-template
clone: True
userdata_file: /srv/salt/win/files/windows-firewall.ps1
win_installer: /srv/salt/win/files/Salt-Minion-2016.11.3-AMD64-Setup.exe
win_username: Administrator
win_password: p@ssw0rd
use_winrm: False
ipv4_cidr: 10.0.0.215/24
ipv4_gw: 10.0.0.1
"""
import logging
import time
from datetime import datetime
import salt.config as config
import salt.utils.cloud
from salt.exceptions import SaltCloudException, SaltCloudSystemExit
# Get logging started
log = logging.getLogger(__name__)
try:
import XenAPI
HAS_XEN_API = True
except ImportError:
HAS_XEN_API = False
__virtualname__ = "xen"
cache = None
def __virtual__():
"""
Only load if Xen configuration and XEN SDK is found.
"""
if get_configured_provider() is False:
return False
if _get_dependencies() is False:
return False
global cache # pylint: disable=global-statement,invalid-name
cache = salt.cache.Cache(__opts__)
return __virtualname__
def _get_active_provider_name():
try:
return __active_provider_name__.value()
except AttributeError:
return __active_provider_name__
def _get_dependencies():
"""
Warn if dependencies aren't met.
Checks for the XenAPI.py module
"""
return config.check_driver_dependencies(__virtualname__, {"XenAPI": HAS_XEN_API})
def get_configured_provider():
"""
Return the first configured instance.
"""
return config.is_provider_configured(
__opts__, _get_active_provider_name() or __virtualname__, ("url",)
)
def _get_session():
"""
Get a connection to the XenServer host
"""
api_version = "1.0"
originator = f"salt_cloud_{__virtualname__}_driver"
url = config.get_cloud_config_value(
"url", get_configured_provider(), __opts__, search_global=False
)
user = config.get_cloud_config_value(
"user", get_configured_provider(), __opts__, search_global=False
)
password = config.get_cloud_config_value(
"password", get_configured_provider(), __opts__, search_global=False
)
ignore_ssl = config.get_cloud_config_value(
"ignore_ssl",
get_configured_provider(),
__opts__,
default=False,
search_global=False,
)
try:
session = XenAPI.Session(url, ignore_ssl=ignore_ssl)
log.debug(
"url: %s user: %s password: %s, originator: %s",
url,
user,
"XXX-pw-redacted-XXX",
originator,
)
session.xenapi.login_with_password(user, password, api_version, originator)
except XenAPI.Failure as ex:
pool_master_addr = str(ex.__dict__["details"][1])
slash_parts = url.split("/")
new_url = "/".join(slash_parts[:2]) + "/" + pool_master_addr
session = XenAPI.Session(new_url)
log.debug(
"session is -> url: %s user: %s password: %s, originator:%s",
new_url,
user,
"XXX-pw-redacted-XXX",
originator,
)
session.xenapi.login_with_password(user, password, api_version, originator)
return session
def list_nodes():
"""
List virtual machines
.. code-block:: bash
salt-cloud -Q
"""
session = _get_session()
vms = session.xenapi.VM.get_all_records()
ret = {}
for vm in vms:
record = session.xenapi.VM.get_record(vm)
if not record["is_a_template"] and not record["is_control_domain"]:
try:
base_template_name = record["other_config"]["base_template_name"]
except Exception: # pylint: disable=broad-except
base_template_name = None
log.debug(
"VM %s, does not have base_template_name attribute",
record["name_label"],
)
ret[record["name_label"]] = {
"id": record["uuid"],
"image": base_template_name,
"name": record["name_label"],
"size": record["memory_dynamic_max"],
"state": record["power_state"],
"private_ips": get_vm_ip(record["name_label"], session),
"public_ips": None,
}
return ret
def get_vm_ip(name=None, session=None, call=None):
"""
Get the IP address of the VM
.. code-block:: bash
salt-cloud -a get_vm_ip xenvm01
.. note:: Requires xen guest tools to be installed in VM
"""
if call == "function":
raise SaltCloudException("This function must be called with -a or --action.")
if session is None:
log.debug("New session being created")
session = _get_session()
vm = _get_vm(name, session=session)
ret = None
# -- try to get ip from vif
vifs = session.xenapi.VM.get_VIFs(vm)
if vifs is not None:
for vif in vifs:
if session.xenapi.VIF.get_ipv4_addresses(vif):
cidr = session.xenapi.VIF.get_ipv4_addresses(vif).pop()
ret, subnet = cidr.split("/")
log.debug("VM vif returned for instance: %s ip: %s", name, ret)
return ret
# -- try to get ip from get tools metrics
vgm = session.xenapi.VM.get_guest_metrics(vm)
try:
net = session.xenapi.VM_guest_metrics.get_networks(vgm)
if "0/ip" in net.keys():
log.debug(
"VM guest metrics returned for instance: %s 0/ip: %s", name, net["0/ip"]
)
ret = net["0/ip"]
# except Exception as ex: # pylint: disable=broad-except
except XenAPI.Failure:
log.info("Could not get vm metrics at this time")
return ret
def set_vm_ip(name=None, ipv4_cidr=None, ipv4_gw=None, session=None, call=None):
"""
Set the IP address on a virtual interface (vif)
"""
mode = "static"
# TODO: Need to add support for IPv6
if call == "function":
raise SaltCloudException("The function must be called with -a or --action.")
log.debug(
"Setting name: %s ipv4_cidr: %s ipv4_gw: %s mode: %s",
name,
ipv4_cidr,
ipv4_gw,
mode,
)
if session is None:
log.debug("New session being created")
session = _get_session()
vm = _get_vm(name, session)
# -- try to get ip from vif
# TODO: for now will take first interface
# addition consideration needed for
# multiple interface(vif) VMs
vifs = session.xenapi.VM.get_VIFs(vm)
if vifs is not None:
log.debug("There are %s vifs.", len(vifs))
for vif in vifs:
record = session.xenapi.VIF.get_record(vif)
log.debug(record)
try:
session.xenapi.VIF.configure_ipv4(vif, mode, ipv4_cidr, ipv4_gw)
except XenAPI.Failure:
log.info("Static IP assignment could not be performed.")
return True
def list_nodes_full(session=None):
"""
List full virtual machines
.. code-block:: bash
salt-cloud -F
"""
if session is None:
session = _get_session()
ret = {}
vms = session.xenapi.VM.get_all()
for vm in vms:
record = session.xenapi.VM.get_record(vm)
if not record["is_a_template"] and not record["is_control_domain"]:
# deal with cases where the VM doesn't have 'base_template_name' attribute
try:
base_template_name = record["other_config"]["base_template_name"]
except Exception: # pylint: disable=broad-except
base_template_name = None
log.debug(
"VM %s, does not have base_template_name attribute",
record["name_label"],
)
vm_cfg = session.xenapi.VM.get_record(vm)
vm_cfg["id"] = record["uuid"]
vm_cfg["name"] = record["name_label"]
vm_cfg["image"] = base_template_name
vm_cfg["size"] = None
vm_cfg["state"] = record["power_state"]
vm_cfg["private_ips"] = get_vm_ip(record["name_label"], session)
vm_cfg["public_ips"] = None
if "snapshot_time" in vm_cfg.keys():
del vm_cfg["snapshot_time"]
ret[record["name_label"]] = vm_cfg
provider = _get_active_provider_name() or "xen"
if ":" in provider:
comps = provider.split(":")
provider = comps[0]
log.debug("ret: %s", ret)
log.debug("provider: %s", provider)
log.debug("__opts__: %s", __opts__)
__utils__["cloud.cache_node_list"](ret, provider, __opts__)
return ret
def list_nodes_select(call=None):
"""
Perform a select query on Xen VM instances
.. code-block:: bash
salt-cloud -S
"""
return salt.utils.cloud.list_nodes_select(
list_nodes_full(),
__opts__["query.selection"],
call,
)
def vdi_list(call=None, kwargs=None):
"""
Return available Xen VDI images
If this function is called with the ``-f`` or ``--function`` then
it can return a list with minimal deatil using the ``terse=True`` keyword
argument.
.. code-block:: bash
salt-cloud -f vdi_list myxen terse=True
"""
if call == "action":
raise SaltCloudException("This function must be called with -f or --function.")
log.debug("kwargs is %s", kwargs)
if kwargs is not None:
if "terse" in kwargs:
if kwargs["terse"] == "True":
terse = True
else:
terse = False
else:
terse = False
else:
kwargs = {}
terse = False
session = _get_session()
vdis = session.xenapi.VDI.get_all()
ret = {}
for vdi in vdis:
data = session.xenapi.VDI.get_record(vdi)
log.debug(type(terse))
if terse is True:
ret[data.get("name_label")] = {"uuid": data.get("uuid"), "OpqueRef": vdi}
else:
data.update({"OpaqueRef": vdi})
ret[data.get("name_label")] = data
return ret
def avail_locations(session=None, call=None):
"""
Return available Xen locations (not implemented)
.. code-block:: bash
salt-cloud --list-locations myxen
"""
# TODO: need to figure out a good meaning of locations in Xen
if call == "action":
raise SaltCloudException(
"The avail_locations function must be called with -f or --function."
)
return pool_list()
def avail_sizes(session=None, call=None):
"""
Return a list of Xen template definitions
.. code-block:: bash
salt-cloud --list-sizes myxen
"""
if call == "action":
raise SaltCloudException(
"The avail_sizes function must be called with -f or --function."
)
return {
"STATUS": (
"Sizes are build into templates. Consider running --list-images to see"
" sizes"
)
}
def template_list(call=None):
"""
Return available Xen template information.
This returns the details of
each template to show number cores, memory sizes, etc..
.. code-block:: bash
salt-cloud -f template_list myxen
"""
templates = {}
session = _get_session()
vms = session.xenapi.VM.get_all()
for vm in vms:
record = session.xenapi.VM.get_record(vm)
if record["is_a_template"]:
templates[record["name_label"]] = record
return templates
def show_instance(name, session=None, call=None):
"""
Show information about a specific VM or template
.. code-block:: bash
salt-cloud -a show_instance xenvm01
.. note:: memory is memory_dynamic_max
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
log.debug("show_instance-> name: %s session: %s", name, session)
if session is None:
session = _get_session()
vm = _get_vm(name, session=session)
record = session.xenapi.VM.get_record(vm)
if not record["is_a_template"] and not record["is_control_domain"]:
try:
base_template_name = record["other_config"]["base_template_name"]
except Exception: # pylint: disable=broad-except
base_template_name = None
log.debug(
"VM %s, does not have base_template_name attribute",
record["name_label"],
)
ret = {
"id": record["uuid"],
"image": base_template_name,
"name": record["name_label"],
"size": record["memory_dynamic_max"],
"state": record["power_state"],
"private_ips": get_vm_ip(name, session),
"public_ips": None,
}
__utils__["cloud.cache_node"](ret, _get_active_provider_name(), __opts__)
return ret
def _determine_resource_pool(session, vm_):
"""
Called by create() used to determine resource pool
"""
resource_pool = ""
if "resource_pool" in vm_.keys():
resource_pool = _get_pool(vm_["resource_pool"], session)
else:
pool = session.xenapi.pool.get_all()
if not pool:
resource_pool = None
else:
first_pool = session.xenapi.pool.get_all()[0]
resource_pool = first_pool
pool_record = session.xenapi.pool.get_record(resource_pool)
log.debug("resource pool: %s", pool_record["name_label"])
return resource_pool
def _determine_storage_repo(session, resource_pool, vm_):
"""
Called by create() used to determine storage repo for create
"""
storage_repo = ""
if "storage_repo" in vm_.keys():
storage_repo = _get_sr(vm_["storage_repo"], session)
else:
storage_repo = None
if resource_pool:
default_sr = session.xenapi.pool.get_default_SR(resource_pool)
sr_record = session.xenapi.SR.get_record(default_sr)
log.debug("storage repository: %s", sr_record["name_label"])
storage_repo = default_sr
else:
storage_repo = None
log.debug("storage repository: %s", storage_repo)
return storage_repo
def create(vm_):
"""
Create a VM in Xen
The configuration for this function is read from the profile settings.
.. code-block:: bash
salt-cloud -p some_profile xenvm01
"""
name = vm_["name"]
record = {}
ret = {}
# fire creating event
__utils__["cloud.fire_event"](
"event",
"starting create",
f"salt/cloud/{name}/creating",
args={"name": name, "profile": vm_["profile"], "provider": vm_["driver"]},
sock_dir=__opts__["sock_dir"],
transport=__opts__["transport"],
)
log.debug("Adding %s to cloud cache.", name)
__utils__["cloud.cachedir_index_add"](
vm_["name"], vm_["profile"], "xen", vm_["driver"]
)
# connect to xen
session = _get_session()
# determine resource pool
resource_pool = _determine_resource_pool(session, vm_)
# determine storage repo
storage_repo = _determine_storage_repo(session, resource_pool, vm_)
# build VM
image = vm_.get("image")
clone = vm_.get("clone")
if clone is None:
clone = True
log.debug("Clone: %s ", clone)
# fire event to read new vm properties (requesting)
__utils__["cloud.fire_event"](
"event",
"requesting instance",
f"salt/cloud/{name}/requesting",
sock_dir=__opts__["sock_dir"],
transport=__opts__["transport"],
)
# create by cloning template
if clone:
_clone_vm(image, name, session)
else:
_copy_vm(image, name, session, storage_repo)
# provision template to vm
_provision_vm(name, session)
vm = _get_vm(name, session)
# start vm
start(name, None, session)
# get new VM
vm = _get_vm(name, session)
# wait for vm to report IP via guest tools
_wait_for_ip(name, session)
# set static IP if configured
_set_static_ip(name, session, vm_)
# if not deploying salt then exit
deploy = vm_.get("deploy", True)
log.debug("delopy is set to %s", deploy)
if deploy:
record = session.xenapi.VM.get_record(vm)
if record is not None:
_deploy_salt_minion(name, session, vm_)
else:
log.debug("The Salt minion will not be installed, deploy: %s", vm_["deploy"])
record = session.xenapi.VM.get_record(vm)
ret = show_instance(name)
ret.update({"extra": record})
__utils__["cloud.fire_event"](
"event",
"created instance",
f"salt/cloud/{name}/created",
args={"name": name, "profile": vm_["profile"], "provider": vm_["driver"]},
sock_dir=__opts__["sock_dir"],
transport=__opts__["transport"],
)
return ret
def _deploy_salt_minion(name, session, vm_):
"""
Deploy salt minion during create()
"""
# Get bootstrap values
vm_["ssh_host"] = get_vm_ip(name, session)
vm_["user"] = vm_.get("user", "root")
vm_["password"] = vm_.get("password", "p@ssw0rd!")
vm_["provider"] = vm_.get("provider", "xen")
log.debug("%s has IP of %s", name, vm_["ssh_host"])
# Bootstrap Salt minion!
if vm_["ssh_host"] is not None:
log.info("Installing Salt minion on %s", name)
boot_ret = __utils__["cloud.bootstrap"](vm_, __opts__)
log.debug("boot return: %s", boot_ret)
def _set_static_ip(name, session, vm_):
"""
Set static IP during create() if defined
"""
ipv4_cidr = ""
ipv4_gw = ""
if "ipv4_gw" in vm_.keys():
log.debug("ipv4_gw is found in keys")
ipv4_gw = vm_["ipv4_gw"]
if "ipv4_cidr" in vm_.keys():
log.debug("ipv4_cidr is found in keys")
ipv4_cidr = vm_["ipv4_cidr"]
log.debug("attempting to set IP in instance")
set_vm_ip(name, ipv4_cidr, ipv4_gw, session, None)
def _wait_for_ip(name, session):
"""
Wait for IP to be available during create()
"""
start_time = datetime.now()
status = None
while status is None:
status = get_vm_ip(name, session)
if status is not None:
# ignore APIPA address
if status.startswith("169"):
status = None
check_time = datetime.now()
delta = check_time - start_time
log.debug(
"Waited %s seconds for %s to report ip address...", delta.seconds, name
)
if delta.seconds > 180:
log.warning("Timeout getting IP address")
break
time.sleep(5)
def _run_async_task(task=None, session=None):
"""
Run XenAPI task in asynchronous mode to prevent timeouts
"""
if task is None or session is None:
return None
task_name = session.xenapi.task.get_name_label(task)
log.debug("Running %s", task_name)
while session.xenapi.task.get_status(task) == "pending":
progress = round(session.xenapi.task.get_progress(task), 2) * 100
log.debug("Task progress %.2f%%", progress)
time.sleep(1)
log.debug("Cleaning up task %s", task_name)
session.xenapi.task.destroy(task)
def _clone_vm(image=None, name=None, session=None):
"""
Create VM by cloning
This is faster and should be used if source and target are
in the same storage repository
"""
if session is None:
session = _get_session()
log.debug("Creating VM %s by cloning %s", name, image)
source = _get_vm(image, session)
task = session.xenapi.Async.VM.clone(source, name)
_run_async_task(task, session)
def _copy_vm(template=None, name=None, session=None, sr=None):
"""
Create VM by copy
This is slower and should be used if source and target are
NOT in the same storage repository
template = object reference
name = string name of new VM
session = object reference
sr = object reference
"""
if session is None:
session = _get_session()
log.debug("Creating VM %s by copying %s", name, template)
source = _get_vm(template, session)
task = session.xenapi.Async.VM.copy(source, name, sr)
_run_async_task(task, session)
def _provision_vm(name=None, session=None):
"""
Provision vm right after clone/copy
"""
if session is None:
session = _get_session()
log.info("Provisioning VM %s", name)
vm = _get_vm(name, session)
task = session.xenapi.Async.VM.provision(vm)
_run_async_task(task, session)
def start(name, call=None, session=None):
"""
Start a vm
.. code-block:: bash
salt-cloud -a start xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
if session is None:
session = _get_session()
log.info("Starting VM %s", name)
vm = _get_vm(name, session)
task = session.xenapi.Async.VM.start(vm, False, True)
_run_async_task(task, session)
return show_instance(name)
def pause(name, call=None, session=None):
"""
Pause a vm
.. code-block:: bash
salt-cloud -a pause xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
if session is None:
session = _get_session()
log.info("Pausing VM %s", name)
vm = _get_vm(name, session)
task = session.xenapi.Async.VM.pause(vm)
_run_async_task(task, session)
return show_instance(name)
def unpause(name, call=None, session=None):
"""
UnPause a vm
.. code-block:: bash
salt-cloud -a unpause xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
if session is None:
session = _get_session()
log.info("Unpausing VM %s", name)
vm = _get_vm(name, session)
task = session.xenapi.Async.VM.unpause(vm)
_run_async_task(task, session)
return show_instance(name)
def suspend(name, call=None, session=None):
"""
Suspend a vm to disk
.. code-block:: bash
salt-cloud -a suspend xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
if session is None:
session = _get_session()
log.info("Suspending VM %s", name)
vm = _get_vm(name, session)
task = session.xenapi.Async.VM.suspend(vm)
_run_async_task(task, session)
return show_instance(name)
def resume(name, call=None, session=None):
"""
Resume a vm from disk
.. code-block:: bash
salt-cloud -a resume xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
if session is None:
session = _get_session()
log.info("Resuming VM %s", name)
vm = _get_vm(name, session)
task = session.xenapi.Async.VM.resume(vm, False, True)
_run_async_task(task, session)
return show_instance(name)
def stop(name, call=None, session=None):
"""
Stop a vm
.. code-block:: bash
salt-cloud -a stop xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
return shutdown(name, call, session)
def shutdown(name, call=None, session=None):
"""
Shutdown a vm
.. code-block:: bash
salt-cloud -a shutdown xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
if session is None:
session = _get_session()
log.info("Starting VM %s", name)
vm = _get_vm(name, session)
task = session.xenapi.Async.VM.shutdown(vm)
_run_async_task(task, session)
return show_instance(name)
def reboot(name, call=None, session=None):
"""
Reboot a vm
.. code-block:: bash
salt-cloud -a reboot xenvm01
"""
if call == "function":
raise SaltCloudException(
"The show_instnce function must be called with -a or --action."
)
if session is None:
session = _get_session()
log.info("Starting VM %s", name)
vm = _get_vm(name, session)
power_state = session.xenapi.VM.get_power_state(vm)
if power_state == "Running":
task = session.xenapi.Async.VM.clean_reboot(vm)
_run_async_task(task, session)
return show_instance(name)
else:
return f"{name} is not running to be rebooted"
def _get_vm(name=None, session=None):
"""
Get XEN vm instance object reference
"""
if session is None:
session = _get_session()
vms = session.xenapi.VM.get_by_name_label(name)
vms = [x for x in vms if not session.xenapi.VM.get_is_a_template(x)]
if len(vms) == 1:
return vms[0]
else:
log.error("VM %s returned %s matches. 1 match expected.", name, len(vms))
return None
def _get_sr(name=None, session=None):
"""
Get XEN sr (storage repo) object reference
"""
if session is None:
session = _get_session()
srs = session.xenapi.SR.get_by_name_label(name)
if len(srs) == 1:
return srs[0]
return None
def _get_pool(name=None, session=None):
"""
Get XEN resource pool object reference
"""
if session is None:
session = _get_session()
pools = session.xenapi.pool.get_all()
for pool in pools:
pool_record = session.xenapi.pool.get_record(pool)
if name in pool_record.get("name_label"):
return pool
return None
def destroy(name=None, call=None):
"""
Destroy Xen VM or template instance
.. code-block:: bash
salt-cloud -d xenvm01
"""
if call == "function":
raise SaltCloudSystemExit(
"The destroy action must be called with -d, --destroy, -a or --action."
)
ret = {}
__utils__["cloud.fire_event"](
"event",
"destroying instance",
f"salt/cloud/{name}/destroying",
args={"name": name},
sock_dir=__opts__["sock_dir"],
transport=__opts__["transport"],
)
session = _get_session()
vm = _get_vm(name)
if vm:
# get vm
record = session.xenapi.VM.get_record(vm)
log.debug("power_state: %s", record["power_state"])
# shut down
if record["power_state"] != "Halted":
task = session.xenapi.Async.VM.hard_shutdown(vm)
_run_async_task(task, session)
# destroy disk (vdi) by reading vdb on vm
ret["vbd"] = destroy_vm_vdis(name, session)
# destroy vm
task = session.xenapi.Async.VM.destroy(vm)
_run_async_task(task, session)
ret["destroyed"] = True
__utils__["cloud.fire_event"](
"event",
"destroyed instance",
f"salt/cloud/{name}/destroyed",
args={"name": name},
sock_dir=__opts__["sock_dir"],
transport=__opts__["transport"],
)
if __opts__.get("update_cachedir", False) is True:
__utils__["cloud.delete_minion_cachedir"](
name, _get_active_provider_name().split(":")[0], __opts__
)
__utils__["cloud.cachedir_index_del"](name)
return ret
def sr_list(call=None):
"""
Geta list of storage repositories
.. code-block:: bash
salt-cloud -f sr_list myxen
"""
if call != "function":
raise SaltCloudSystemExit(
"This function must be called with -f, --function argument."
)
ret = {}
session = _get_session()
srs = session.xenapi.SR.get_all()
for sr in srs:
sr_record = session.xenapi.SR.get_record(sr)
ret[sr_record["name_label"]] = sr_record
return ret
def host_list(call=None):
"""
Get a list of Xen Servers
.. code-block:: bash
salt-cloud -f host_list myxen
"""
if call == "action":
raise SaltCloudSystemExit(
"This function must be called with -f, --function argument."
)
ret = {}
session = _get_session()
hosts = session.xenapi.host.get_all()
for host in hosts:
host_record = session.xenapi.host.get_record(host)
ret[host_record["name_label"]] = host_record
return ret
def pool_list(call=None):
"""
Get a list of Resource Pools
.. code-block:: bash
salt-cloud -f pool_list myxen
"""
if call == "action":
raise SaltCloudSystemExit(
"This function must be called with -f, --function argument."
)
ret = {}
session = _get_session()
pools = session.xenapi.pool.get_all()
for pool in pools:
pool_record = session.xenapi.pool.get_record(pool)
ret[pool_record["name_label"]] = pool_record
return ret
def pif_list(call=None):
"""
Get a list of Resource Pools
.. code-block:: bash
salt-cloud -f pool_list myxen
"""
if call != "function":
raise SaltCloudSystemExit(
"This function must be called with -f, --function argument."
)
ret = {}
session = _get_session()
pifs = session.xenapi.PIF.get_all()
for pif in pifs:
record = session.xenapi.PIF.get_record(pif)
ret[record["uuid"]] = record
return ret
def vif_list(name, call=None, kwargs=None):
"""
Get a list of virtual network interfaces on a VM
**requires**: the name of the vm with the vbd definition
.. code-block:: bash
salt-cloud -a vif_list xenvm01
"""
if call == "function":
raise SaltCloudSystemExit(
"This function must be called with -a, --action argument."
)
if name is None:
return "A name kwarg is rquired"
ret = {}
data = {}
session = _get_session()
vm = _get_vm(name)
vifs = session.xenapi.VM.get_VIFs(vm)
if vifs is not None:
x = 0
for vif in vifs:
vif_record = session.xenapi.VIF.get_record(vif)
data[f"vif-{x}"] = vif_record
x += 1
ret[name] = data
return ret
def vbd_list(name=None, call=None):
"""
Get a list of VBDs on a VM
**requires**: the name of the vm with the vbd definition
.. code-block:: bash
salt-cloud -a vbd_list xenvm01
"""
if call == "function":
raise SaltCloudSystemExit(
"This function must be called with -a, --action argument."
)
if name is None:
return "A name kwarg is rquired"
ret = {}
data = {}
session = _get_session()
vms = session.xenapi.VM.get_by_name_label(name)
if len(vms) == 1:
vm = vms[0]
vbds = session.xenapi.VM.get_VBDs(vm)
if vbds is not None:
x = 0
for vbd in vbds:
vbd_record = session.xenapi.VBD.get_record(vbd)
data[f"vbd-{x}"] = vbd_record
x += 1
ret = data
return ret
def avail_images(call=None):
"""
Get a list of images from Xen
If called with the `--list-images` then it returns
images with all details.
.. code-block:: bash
salt-cloud --list-images myxen
"""
if call == "action":
raise SaltCloudSystemExit(
"This function must be called with -f, --function argument."
)
return template_list()
def destroy_vm_vdis(name=None, session=None, call=None):
"""
Get virtual block devices on VM
.. code-block:: bash
salt-cloud -a destroy_vm_vdis xenvm01
"""
if session is None:
session = _get_session()
ret = {}
# get vm object
vms = session.xenapi.VM.get_by_name_label(name)
if len(vms) == 1:
# read virtual block device (vdb)
vbds = session.xenapi.VM.get_VBDs(vms[0])
if vbds is not None:
x = 0
for vbd in vbds:
vbd_record = session.xenapi.VBD.get_record(vbd)
if vbd_record["VDI"] != "OpaqueRef:NULL":
# read vdi on vdb
vdi_record = session.xenapi.VDI.get_record(vbd_record["VDI"])
if "iso" not in vdi_record["name_label"]:
session.xenapi.VDI.destroy(vbd_record["VDI"])
ret[f"vdi-{x}"] = vdi_record["name_label"]
x += 1
return ret
def destroy_template(name=None, call=None, kwargs=None):
"""
Destroy Xen VM or template instance
.. code-block:: bash
salt-cloud -f destroy_template myxen name=testvm2
"""
if call == "action":
raise SaltCloudSystemExit(
"The destroy_template function must be called with -f."
)
if kwargs is None:
kwargs = {}
name = kwargs.get("name", None)
session = _get_session()
vms = session.xenapi.VM.get_all_records()
ret = {}
found = False
for vm in vms:
record = session.xenapi.VM.get_record(vm)
if record["is_a_template"]:
if record["name_label"] == name:
found = True
# log.debug(record['name_label'])
session.xenapi.VM.destroy(vm)
ret[name] = {"status": "destroyed"}
if not found:
ret[name] = {"status": "not found"}
return ret
def get_pv_args(name, session=None, call=None):
"""
Get PV arguments for a VM
.. code-block:: bash
salt-cloud -a get_pv_args xenvm01
"""
if call == "function":
raise SaltCloudException("This function must be called with -a or --action.")
if session is None:
log.debug("New session being created")
session = _get_session()
vm = _get_vm(name, session=session)
pv_args = session.xenapi.VM.get_PV_args(vm)
if pv_args:
return pv_args
return None
def set_pv_args(name, kwargs=None, session=None, call=None):
"""
Set PV arguments for a VM
.. code-block:: bash
salt-cloud -a set_pv_args xenvm01 pv_args="utf-8 graphical"
"""
if call == "function":
raise SaltCloudException("This function must be called with -a or --action.")
if session is None:
log.debug("New session being created")
session = _get_session()
vm = _get_vm(name, session=session)
try:
log.debug("Setting PV Args: %s", kwargs["pv_args"])
session.xenapi.VM.set_PV_args(vm, str(kwargs["pv_args"]))
except KeyError:
log.error("No pv_args parameter found.")
return False
except XenAPI.Failure:
log.info("Setting PV Args failed.")
return False
return True
Zerion Mini Shell 1.0