Mini Shell
"""
Module for running vmadm command on SmartOS
"""
import logging
import os
import shlex
import salt.utils.args
import salt.utils.files
import salt.utils.json
import salt.utils.path
import salt.utils.platform
import salt.utils.stringutils
from salt.utils.odict import OrderedDict
log = logging.getLogger(__name__)
# Function aliases
__func_alias__ = {"list_vms": "list"}
# Define the module's virtual name
__virtualname__ = "vmadm"
def __virtual__():
"""
Provides vmadm on SmartOS
"""
if (
salt.utils.platform.is_smartos_globalzone()
and salt.utils.path.which("vmadm")
and salt.utils.path.which("zfs")
):
return __virtualname__
return (
False,
f"{__virtualname__} module can only be loaded on SmartOS compute nodes",
)
def _exit_status(retcode):
"""
Translate exit status of vmadm
"""
ret = {
0: "Successful completion.",
1: "An error occurred.",
2: "Usage error.",
}
return ret[retcode]
def _create_update_from_file(mode="create", uuid=None, path=None):
"""
Create vm from file
"""
ret = {}
if not os.path.isfile(path) or path is None:
ret["Error"] = f"File ({path}) does not exists!"
return ret
# vmadm validate create|update [-f <filename>]
cmd = "vmadm validate {mode} {brand} -f {path}".format(
mode=mode, brand=get(uuid)["brand"] if uuid is not None else "", path=path
)
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = _exit_status(retcode)
if "stderr" in res:
if res["stderr"][0] == "{":
ret["Error"] = salt.utils.json.loads(res["stderr"])
else:
ret["Error"] = res["stderr"]
return ret
# vmadm create|update [-f <filename>]
cmd = "vmadm {mode} {uuid} -f {path}".format(
mode=mode, uuid=uuid if uuid is not None else "", path=path
)
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = _exit_status(retcode)
if "stderr" in res:
if res["stderr"][0] == "{":
ret["Error"] = salt.utils.json.loads(res["stderr"])
else:
ret["Error"] = res["stderr"]
return ret
else:
if res["stderr"].startswith("Successfully created VM"):
return res["stderr"][24:]
return True
def _create_update_from_cfg(mode="create", uuid=None, vmcfg=None):
"""
Create vm from configuration
"""
ret = {}
# write json file
vmadm_json_file = __salt__["temp.file"](prefix="vmadm-")
with salt.utils.files.fopen(vmadm_json_file, "w") as vmadm_json:
salt.utils.json.dump(vmcfg, vmadm_json)
# vmadm validate create|update [-f <filename>]
cmd = "vmadm validate {mode} {brand} -f {vmadm_json_file}".format(
mode=mode,
brand=get(uuid)["brand"] if uuid is not None else "",
vmadm_json_file=vmadm_json_file,
)
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = _exit_status(retcode)
if "stderr" in res:
if res["stderr"][0] == "{":
ret["Error"] = salt.utils.json.loads(res["stderr"])
else:
ret["Error"] = res["stderr"]
return ret
# vmadm create|update [-f <filename>]
cmd = "vmadm {mode} {uuid} -f {vmadm_json_file}".format(
mode=mode,
uuid=uuid if uuid is not None else "",
vmadm_json_file=vmadm_json_file,
)
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = _exit_status(retcode)
if "stderr" in res:
if res["stderr"][0] == "{":
ret["Error"] = salt.utils.json.loads(res["stderr"])
else:
ret["Error"] = res["stderr"]
return ret
else:
# cleanup json file (only when successful to help troubleshooting)
salt.utils.files.safe_rm(vmadm_json_file)
# return uuid
if res["stderr"].startswith("Successfully created VM"):
return res["stderr"][24:]
return True
def start(vm, options=None, key="uuid"):
"""
Start a vm
vm : string
vm to be started
options : string
optional additional options
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.start 186da9ab-7392-4f55-91a5-b8f1fe770543
salt '*' vmadm.start 186da9ab-7392-4f55-91a5-b8f1fe770543 'order=c,once=d cdrom=/path/to/image.iso,ide'
salt '*' vmadm.start vm=nacl key=alias
salt '*' vmadm.start vm=nina.example.org key=hostname
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm start <uuid> [option=value ...]
cmd = "vmadm start {uuid} {options}".format(
uuid=vm, options=options if options else ""
)
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def stop(vm, force=False, key="uuid"):
"""
Stop a vm
vm : string
vm to be stopped
force : boolean
force stop of vm if true
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.stop 186da9ab-7392-4f55-91a5-b8f1fe770543
salt '*' vmadm.stop 186da9ab-7392-4f55-91a5-b8f1fe770543 True
salt '*' vmadm.stop vm=nacl key=alias
salt '*' vmadm.stop vm=nina.example.org key=hostname
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm stop <uuid> [-F]
cmd = "vmadm stop {force} {uuid}".format(force="-F" if force else "", uuid=vm)
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = _exit_status(retcode)
return ret
return True
def reboot(vm, force=False, key="uuid"):
"""
Reboot a vm
vm : string
vm to be rebooted
force : boolean
force reboot of vm if true
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.reboot 186da9ab-7392-4f55-91a5-b8f1fe770543
salt '*' vmadm.reboot 186da9ab-7392-4f55-91a5-b8f1fe770543 True
salt '*' vmadm.reboot vm=nacl key=alias
salt '*' vmadm.reboot vm=nina.example.org key=hostname
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm reboot <uuid> [-F]
cmd = "vmadm reboot {force} {uuid}".format(force="-F" if force else "", uuid=vm)
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def list_vms(search=None, sort=None, order="uuid,type,ram,state,alias", keyed=True):
"""
Return a list of VMs
search : string
vmadm filter property
sort : string
vmadm sort (-s) property
order : string
vmadm order (-o) property -- Default: uuid,type,ram,state,alias
keyed : boolean
specified if the output should be an array (False) or dict (True)
For a dict the key is the first item from the order parameter.
Note: If key is not unique last vm wins.
CLI Example:
.. code-block:: bash
salt '*' vmadm.list
salt '*' vmadm.list order=alias,ram,cpu_cap sort=-ram,-cpu_cap
salt '*' vmadm.list search='type=KVM'
"""
ret = {}
# vmadm list [-p] [-H] [-o field,...] [-s field,...] [field=value ...]
cmd = "vmadm list -p -H {order} {sort} {search}".format(
order=f"-o {order}" if order else "",
sort=f"-s {sort}" if sort else "",
search=search if search else "",
)
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
result = OrderedDict() if keyed else []
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
fields = order.split(",")
for vm in res["stdout"].splitlines():
vm_data = OrderedDict()
vm = vm.split(":")
if keyed:
for field in fields:
if fields.index(field) == 0:
continue
vm_data[field.strip()] = vm[fields.index(field)].strip()
result[vm[0]] = vm_data
else:
if len(vm) > 1:
for field in fields:
vm_data[field.strip()] = vm[fields.index(field)].strip()
else:
vm_data = vm[0]
result.append(vm_data)
return result
def lookup(search=None, order=None, one=False):
"""
Return a list of VMs using lookup
search : string
vmadm filter property
order : string
vmadm order (-o) property -- Default: uuid,type,ram,state,alias
one : boolean
return only one result (vmadm's -1)
CLI Example:
.. code-block:: bash
salt '*' vmadm.lookup search='state=running'
salt '*' vmadm.lookup search='state=running' order=uuid,alias,hostname
salt '*' vmadm.lookup search='alias=nacl' one=True
"""
ret = {}
# vmadm lookup [-j|-1] [-o field,...] [field=value ...]
cmd = "vmadm lookup {one} {order} {search}".format(
one="-1" if one else "-j",
order=f"-o {order}" if order else "",
search=search if search else "",
)
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
result = []
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
if one:
result = res["stdout"]
else:
for vm in salt.utils.json.loads(res["stdout"]):
result.append(vm)
return result
def sysrq(vm, action="nmi", key="uuid"):
"""
Send non-maskable interrupt to vm or capture a screenshot
vm : string
vm to be targeted
action : string
nmi or screenshot -- Default: nmi
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.sysrq 186da9ab-7392-4f55-91a5-b8f1fe770543 nmi
salt '*' vmadm.sysrq 186da9ab-7392-4f55-91a5-b8f1fe770543 screenshot
salt '*' vmadm.sysrq nacl nmi key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
if action not in ["nmi", "screenshot"]:
ret["Error"] = "Action must be either nmi or screenshot"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm sysrq <uuid> <nmi|screenshot>
cmd = f"vmadm sysrq {vm} {action}"
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def delete(vm, key="uuid"):
"""
Delete a vm
vm : string
vm to be deleted
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.delete 186da9ab-7392-4f55-91a5-b8f1fe770543
salt '*' vmadm.delete nacl key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm delete <uuid>
cmd = f"vmadm delete {vm}"
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def get(vm, key="uuid"):
"""
Output the JSON object describing a VM
vm : string
vm to be targeted
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.get 186da9ab-7392-4f55-91a5-b8f1fe770543
salt '*' vmadm.get nacl key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm get <uuid>
cmd = f"vmadm get {vm}"
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return salt.utils.json.loads(res["stdout"])
def info(vm, info_type="all", key="uuid"):
"""
Lookup info on running kvm
vm : string
vm to be targeted
info_type : string [all|block|blockstats|chardev|cpus|kvm|pci|spice|version|vnc]
info type to return
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.info 186da9ab-7392-4f55-91a5-b8f1fe770543
salt '*' vmadm.info 186da9ab-7392-4f55-91a5-b8f1fe770543 vnc
salt '*' vmadm.info nacl key=alias
salt '*' vmadm.info nacl vnc key=alias
"""
ret = {}
if info_type not in [
"all",
"block",
"blockstats",
"chardev",
"cpus",
"kvm",
"pci",
"spice",
"version",
"vnc",
]:
ret["Error"] = "Requested info_type is not available"
return ret
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm info <uuid> [type,...]
cmd = f"vmadm info {vm} {info_type}"
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return salt.utils.json.loads(res["stdout"])
def create_snapshot(vm, name, key="uuid"):
"""
Create snapshot of a vm
vm : string
vm to be targeted
name : string
snapshot name
The snapname must be 64 characters or less
and must only contain alphanumeric characters and
characters in the set [-_.:%] to comply with ZFS restrictions.
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.create_snapshot 186da9ab-7392-4f55-91a5-b8f1fe770543 baseline
salt '*' vmadm.create_snapshot nacl baseline key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
vmobj = get(vm)
if "datasets" in vmobj:
ret["Error"] = "VM cannot have datasets"
return ret
if vmobj["brand"] in ["kvm"]:
ret["Error"] = "VM must be of type OS"
return ret
if vmobj["zone_state"] not in ["running"]: # work around a vmadm bug
ret["Error"] = "VM must be running to take a snapshot"
return ret
# vmadm create-snapshot <uuid> <snapname>
cmd = f"vmadm create-snapshot {vm} {name}"
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def delete_snapshot(vm, name, key="uuid"):
"""
Delete snapshot of a vm
vm : string
vm to be targeted
name : string
snapshot name
The snapname must be 64 characters or less
and must only contain alphanumeric characters and
characters in the set [-_.:%] to comply with ZFS restrictions.
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.delete_snapshot 186da9ab-7392-4f55-91a5-b8f1fe770543 baseline
salt '*' vmadm.delete_snapshot nacl baseline key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
vmobj = get(vm)
if "datasets" in vmobj:
ret["Error"] = "VM cannot have datasets"
return ret
if vmobj["brand"] in ["kvm"]:
ret["Error"] = "VM must be of type OS"
return ret
# vmadm delete-snapshot <uuid> <snapname>
cmd = f"vmadm delete-snapshot {vm} {name}"
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def rollback_snapshot(vm, name, key="uuid"):
"""
Rollback snapshot of a vm
vm : string
vm to be targeted
name : string
snapshot name
The snapname must be 64 characters or less
and must only contain alphanumeric characters and
characters in the set [-_.:%] to comply with ZFS restrictions.
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.rollback_snapshot 186da9ab-7392-4f55-91a5-b8f1fe770543 baseline
salt '*' vmadm.rollback_snapshot nacl baseline key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
vmobj = get(vm)
if "datasets" in vmobj:
ret["Error"] = "VM cannot have datasets"
return ret
if vmobj["brand"] in ["kvm"]:
ret["Error"] = "VM must be of type OS"
return ret
# vmadm rollback-snapshot <uuid> <snapname>
cmd = f"vmadm rollback-snapshot {vm} {name}"
res = __salt__["cmd.run_all"](cmd)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def reprovision(vm, image, key="uuid"):
"""
Reprovision a vm
vm : string
vm to be reprovisioned
image : string
uuid of new image
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.reprovision 186da9ab-7392-4f55-91a5-b8f1fe770543 c02a2044-c1bd-11e4-bd8c-dfc1db8b0182
salt '*' vmadm.reprovision nacl c02a2044-c1bd-11e4-bd8c-dfc1db8b0182 key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
if image not in __salt__["imgadm.list"]():
ret["Error"] = f"Image ({image}) is not present on this host"
return ret
# vmadm reprovision <uuid> [-f <filename>]
cmd = "echo {image} | vmadm reprovision {uuid}".format(
uuid=salt.utils.stringutils.to_unicode(vm),
image=shlex.quote(salt.utils.json.dumps({"image_uuid": image})),
)
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def create(from_file=None, **kwargs):
"""
Create a new vm
from_file : string
json file to create the vm from -- if present, all other options will be ignored
kwargs : string|int|...
options to set for the vm
CLI Example:
.. code-block:: bash
salt '*' vmadm.create from_file=/tmp/new_vm.json
salt '*' vmadm.create image_uuid='...' alias='...' nics='[{ "nic_tag": "admin", "ip": "198.51.100.123", ...}, {...}]' [...]
"""
ret = {}
# prepare vmcfg
vmcfg = {}
kwargs = salt.utils.args.clean_kwargs(**kwargs)
for k, v in kwargs.items():
vmcfg[k] = v
if from_file:
return _create_update_from_file("create", path=from_file)
else:
return _create_update_from_cfg("create", vmcfg=vmcfg)
def update(vm, from_file=None, key="uuid", **kwargs):
"""
Update a new vm
vm : string
vm to be updated
from_file : string
json file to update the vm with -- if present, all other options will be ignored
key : string [uuid|alias|hostname]
value type of 'vm' parameter
kwargs : string|int|...
options to update for the vm
CLI Example:
.. code-block:: bash
salt '*' vmadm.update vm=186da9ab-7392-4f55-91a5-b8f1fe770543 from_file=/tmp/new_vm.json
salt '*' vmadm.update vm=nacl key=alias from_file=/tmp/new_vm.json
salt '*' vmadm.update vm=186da9ab-7392-4f55-91a5-b8f1fe770543 max_physical_memory=1024
"""
ret = {}
# prepare vmcfg
vmcfg = {}
kwargs = salt.utils.args.clean_kwargs(**kwargs)
for k, v in kwargs.items():
vmcfg[k] = v
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
uuid = lookup(f"{key}={vm}", one=True)
if "Error" in uuid:
return uuid
if from_file:
return _create_update_from_file("update", uuid, path=from_file)
else:
return _create_update_from_cfg("update", uuid, vmcfg=vmcfg)
def send(vm, target, key="uuid"):
"""
Send a vm to a directory
vm : string
vm to be sent
target : string
target directory
key : string [uuid|alias|hostname]
value type of 'vm' parameter
CLI Example:
.. code-block:: bash
salt '*' vmadm.send 186da9ab-7392-4f55-91a5-b8f1fe770543 /opt/backups
salt '*' vmadm.send vm=nacl target=/opt/backups key=alias
"""
ret = {}
if key not in ["uuid", "alias", "hostname"]:
ret["Error"] = "Key must be either uuid, alias or hostname"
return ret
if not os.path.isdir(target):
ret["Error"] = "Target must be a directory or host"
return ret
vm = lookup(f"{key}={vm}", one=True)
if "Error" in vm:
return vm
# vmadm send <uuid> [target]
cmd = "vmadm send {uuid} > {target}".format(
uuid=vm, target=os.path.join(target, f"{vm}.vmdata")
)
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
vmobj = get(vm)
if "datasets" not in vmobj:
return True
log.warning("one or more datasets detected, this is not supported!")
log.warning("trying to zfs send datasets...")
for dataset in vmobj["datasets"]:
name = dataset.split("/")
name = name[-1]
cmd = "zfs send {dataset} > {target}".format(
dataset=dataset,
target=os.path.join(target, f"{vm}-{name}.zfsds"),
)
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
def receive(uuid, source):
"""
Receive a vm from a directory
uuid : string
uuid of vm to be received
source : string
source directory
CLI Example:
.. code-block:: bash
salt '*' vmadm.receive 186da9ab-7392-4f55-91a5-b8f1fe770543 /opt/backups
"""
ret = {}
if not os.path.isdir(source):
ret["Error"] = "Source must be a directory or host"
return ret
if not os.path.exists(os.path.join(source, f"{uuid}.vmdata")):
ret["Error"] = f"Unknow vm with uuid in {source}"
return ret
# vmadm receive
cmd = "vmadm receive < {source}".format(
source=os.path.join(source, f"{uuid}.vmdata")
)
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0 and not res["stderr"].endswith("datasets"):
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
vmobj = get(uuid)
if "datasets" not in vmobj:
return True
log.warning("one or more datasets detected, this is not supported!")
log.warning("trying to restore datasets, mountpoints will need to be set again...")
for dataset in vmobj["datasets"]:
name = dataset.split("/")
name = name[-1]
cmd = "zfs receive {dataset} < {source}".format(
dataset=dataset,
source=os.path.join(source, f"{uuid}-{name}.zfsds"),
)
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0:
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
cmd = f"vmadm install {uuid}"
res = __salt__["cmd.run_all"](cmd, python_shell=True)
retcode = res["retcode"]
if retcode != 0 and not res["stderr"].endswith("datasets"):
ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode)
return ret
return True
Zerion Mini Shell 1.0