Source code for saltext.vcf.clients.vim_vm_customization

"""Guest OS customization specs + apply.

Two surfaces:

* Build a customization spec from kwargs (``linux_spec``, ``windows_spec``)
  for use with :func:`saltext.vcf.clients.vim_vm.clone`.
* Apply a spec to an existing VM via ``CustomizeVM_Task``.

The customization manager can also store named specs server-side; that
surface is exposed via :func:`spec_get`, :func:`spec_create`,
:func:`spec_delete`.
"""

from pyVmomi import vim

from saltext.vcf.utils import vim as soap


def _csmgr(opts, profile=None):
    return soap.content(opts, profile=profile).customizationSpecManager


# ---------------------------------------------------------------------------
# Spec builders (return ``vim.vm.customization.Specification`` objects)
# ---------------------------------------------------------------------------


[docs] def linux_spec( hostname, domain, time_zone="UTC", hw_clock_utc=True, nics=None, dns_servers=None, dns_search_path=None, ): """Build a Linux customization spec. *nics* is a list of network adapter dicts: .. code-block:: python [{"dhcp": True}, {"ip": "10.0.0.5", "subnet": "255.255.255.0", "gateway": ["10.0.0.1"]}] """ identity = vim.vm.customization.LinuxPrep( hostName=vim.vm.customization.FixedName(name=hostname), domain=domain, timeZone=time_zone, hwClockUTC=hw_clock_utc, ) return _build_spec(identity, nics, dns_servers, dns_search_path)
[docs] def windows_spec( hostname, workgroup_or_domain, *, domain_join=False, domain_admin=None, domain_admin_password=None, admin_password=None, auto_logon=False, auto_logon_count=1, license_mode="perServer", product_id=None, full_name="Administrator", org_name="VMware", time_zone=85, nics=None, dns_servers=None, dns_search_path=None, ): """Build a Windows customization spec. *time_zone* is the Microsoft TimeZoneIndex (85 = Pacific). """ identity = vim.vm.customization.Sysprep() identity.guiUnattended = vim.vm.customization.GuiUnattended( autoLogon=auto_logon, autoLogonCount=auto_logon_count, timeZone=time_zone, ) if admin_password is not None: identity.guiUnattended.password = vim.vm.customization.Password( value=admin_password, plainText=True ) identity.userData = vim.vm.customization.UserData( fullName=full_name, orgName=org_name, computerName=vim.vm.customization.FixedName(name=hostname), productId=product_id or "", ) if domain_join: identity.identification = vim.vm.customization.Identification( joinDomain=workgroup_or_domain, domainAdmin=domain_admin, domainAdminPassword=( vim.vm.customization.Password(value=domain_admin_password, plainText=True) if domain_admin_password else None ), ) else: identity.identification = vim.vm.customization.Identification( joinWorkgroup=workgroup_or_domain ) identity.licenseFilePrintData = vim.vm.customization.LicenseFilePrintData(autoMode=license_mode) return _build_spec(identity, nics, dns_servers, dns_search_path)
def _build_spec(identity, nics, dns_servers, dns_search_path): global_ip = vim.vm.customization.GlobalIPSettings( dnsServerList=list(dns_servers or []), dnsSuffixList=list(dns_search_path or []), ) adapter_mappings = [] for nic in nics or []: ip = _ip_for(nic) adapter = vim.vm.customization.IPSettings( ip=ip, subnetMask=nic.get("subnet", ""), gateway=list(nic.get("gateway") or []), dnsServerList=list(nic.get("dns_servers") or []), ) adapter_mappings.append(vim.vm.customization.AdapterMapping(adapter=adapter)) return vim.vm.customization.Specification( identity=identity, globalIPSettings=global_ip, nicSettingMap=adapter_mappings, ) def _ip_for(nic): if nic.get("dhcp"): return vim.vm.customization.DhcpIpGenerator() if nic.get("ip"): return vim.vm.customization.FixedIp(ipAddress=nic["ip"]) raise ValueError(f"nic spec must include 'dhcp' or 'ip': {nic!r}") # --------------------------------------------------------------------------- # Apply # ---------------------------------------------------------------------------
[docs] def apply(opts, vm_id_or_name, spec, profile=None): """Apply *spec* (built via :func:`linux_spec` / :func:`windows_spec`) to a VM.""" from saltext.vcf.clients.vim_vm import _vm # avoid circular at import time vm = _vm(opts, vm_id_or_name, profile=profile) task = vm.CustomizeVM_Task(spec=spec) return task._moId # noqa: SLF001
# --------------------------------------------------------------------------- # Server-side named specs # ---------------------------------------------------------------------------
[docs] def spec_list(opts, profile=None): """Return the names of every saved customization spec on the vCenter.""" return [info.name for info in (_csmgr(opts, profile=profile).info or [])]
[docs] def spec_get(opts, name, profile=None): """Return a saved spec by name (as a ``vim.vm.customization.Specification``).""" mgr = _csmgr(opts, profile=profile) item = mgr.GetCustomizationSpec(name=name) return item.spec
[docs] def spec_create(opts, name, description, spec, profile=None): """Save *spec* under *name* on the vCenter.""" mgr = _csmgr(opts, profile=profile) item = vim.CustomizationSpecItem( info=vim.CustomizationSpecInfo( name=name, description=description, type="Lin" # Lin/Win — vCenter accepts both ), spec=spec, ) mgr.CreateCustomizationSpec(item=item)
def spec_delete(opts, name, profile=None): _csmgr(opts, profile=profile).DeleteCustomizationSpec(name=name)