Blame cloudinit/sources/DataSourceOVF.py

Packit Service a04d08
# Copyright (C) 2011 Canonical Ltd.
Packit Service a04d08
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
Packit Service a04d08
# Copyright (C) 2012 Yahoo! Inc.
Packit Service a04d08
#
Packit Service a04d08
# Author: Scott Moser <scott.moser@canonical.com>
Packit Service a04d08
# Author: Juerg Hafliger <juerg.haefliger@hp.com>
Packit Service a04d08
# Author: Joshua Harlow <harlowja@yahoo-inc.com>
Packit Service a04d08
#
Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
import base64
Packit Service a04d08
import os
Packit Service a04d08
import re
Packit Service a04d08
import time
Packit Service 751c4a
from xml.dom import minidom
Packit Service a04d08
Packit Service a04d08
from cloudinit import log as logging
Packit Service a04d08
from cloudinit import sources
Packit Service 751c4a
from cloudinit import subp
Packit Service a04d08
from cloudinit import util
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.config \
Packit Service a04d08
    import Config
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.config_custom_script \
Packit Service a04d08
    import PreCustomScript, PostCustomScript
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.config_file \
Packit Service a04d08
    import ConfigFile
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.config_nic \
Packit Service a04d08
    import NicConfigurator
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.config_passwd \
Packit Service a04d08
    import PasswordConfigurator
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.guestcust_error \
Packit Service a04d08
    import GuestCustErrorEnum
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.guestcust_event \
Packit Service a04d08
    import GuestCustEventEnum as GuestCustEvent
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.guestcust_state \
Packit Service a04d08
    import GuestCustStateEnum
Packit Service a04d08
from cloudinit.sources.helpers.vmware.imc.guestcust_util import (
Packit Service a04d08
    enable_nics,
Packit Service a04d08
    get_nics_to_enable,
Packit Service a04d08
    set_customization_status,
Packit Service 751c4a
    get_tools_config,
Packit Service 751c4a
    set_gc_status
Packit Service a04d08
)
Packit Service a04d08
Packit Service a04d08
LOG = logging.getLogger(__name__)
Packit Service a04d08
Packit Service a04d08
CONFGROUPNAME_GUESTCUSTOMIZATION = "deployPkg"
Packit Service a04d08
GUESTCUSTOMIZATION_ENABLE_CUST_SCRIPTS = "enable-custom-scripts"
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class DataSourceOVF(sources.DataSource):
Packit Service a04d08
Packit Service a04d08
    dsname = "OVF"
Packit Service a04d08
Packit Service a04d08
    def __init__(self, sys_cfg, distro, paths):
Packit Service a04d08
        sources.DataSource.__init__(self, sys_cfg, distro, paths)
Packit Service a04d08
        self.seed = None
Packit Service a04d08
        self.seed_dir = os.path.join(paths.seed_dir, 'ovf')
Packit Service a04d08
        self.environment = None
Packit Service a04d08
        self.cfg = {}
Packit Service a04d08
        self.supported_seed_starts = ("/", "file://")
Packit Service a04d08
        self.vmware_customization_supported = True
Packit Service a04d08
        self._network_config = None
Packit Service a04d08
        self._vmware_nics_to_enable = None
Packit Service a04d08
        self._vmware_cust_conf = None
Packit Service a04d08
        self._vmware_cust_found = False
Packit Service a04d08
Packit Service a04d08
    def __str__(self):
Packit Service a04d08
        root = sources.DataSource.__str__(self)
Packit Service a04d08
        return "%s [seed=%s]" % (root, self.seed)
Packit Service a04d08
Packit Service a04d08
    def _get_data(self):
Packit Service a04d08
        found = []
Packit Service a04d08
        md = {}
Packit Service a04d08
        ud = ""
Packit Service a04d08
        vmwareImcConfigFilePath = None
Packit Service a04d08
        nicspath = None
Packit Service a04d08
Packit Service a04d08
        defaults = {
Packit Service a04d08
            "instance-id": "iid-dsovf",
Packit Service a04d08
        }
Packit Service a04d08
Packit Service a04d08
        (seedfile, contents) = get_ovf_env(self.paths.seed_dir)
Packit Service a04d08
Packit Service a04d08
        system_type = util.read_dmi_data("system-product-name")
Packit Service a04d08
        if system_type is None:
Packit Service a04d08
            LOG.debug("No system-product-name found")
Packit Service a04d08
Packit Service a04d08
        if seedfile:
Packit Service a04d08
            # Found a seed dir
Packit Service a04d08
            seed = os.path.join(self.paths.seed_dir, seedfile)
Packit Service a04d08
            (md, ud, cfg) = read_ovf_environment(contents)
Packit Service a04d08
            self.environment = contents
Packit Service a04d08
            found.append(seed)
Packit Service a04d08
        elif system_type and 'vmware' in system_type.lower():
Packit Service a04d08
            LOG.debug("VMware Virtualization Platform found")
Packit Service a04d08
            if not self.vmware_customization_supported:
Packit Service a04d08
                LOG.debug("Skipping the check for "
Packit Service a04d08
                          "VMware Customization support")
Packit Service a04d08
            elif not util.get_cfg_option_bool(
Packit Service a04d08
                    self.sys_cfg, "disable_vmware_customization", True):
Packit Service a04d08
Packit Service a04d08
                search_paths = (
Packit Service a04d08
                    "/usr/lib/vmware-tools", "/usr/lib64/vmware-tools",
Packit Service a04d08
                    "/usr/lib/open-vm-tools", "/usr/lib64/open-vm-tools")
Packit Service a04d08
Packit Service a04d08
                plugin = "libdeployPkgPlugin.so"
Packit Service a04d08
                deployPkgPluginPath = None
Packit Service a04d08
                for path in search_paths:
Packit Service a04d08
                    deployPkgPluginPath = search_file(path, plugin)
Packit Service a04d08
                    if deployPkgPluginPath:
Packit Service a04d08
                        LOG.debug("Found the customization plugin at %s",
Packit Service a04d08
                                  deployPkgPluginPath)
Packit Service a04d08
                        break
Packit Service a04d08
Packit Service a04d08
                if deployPkgPluginPath:
Packit Service a04d08
                    # When the VM is powered on, the "VMware Tools" daemon
Packit Service a04d08
                    # copies the customization specification file to
Packit Service a04d08
                    # /var/run/vmware-imc directory. cloud-init code needs
Packit Service a04d08
                    # to search for the file in that directory.
Packit Service a04d08
                    max_wait = get_max_wait_from_cfg(self.ds_cfg)
Packit Service a04d08
                    vmwareImcConfigFilePath = util.log_time(
Packit Service a04d08
                        logfunc=LOG.debug,
Packit Service a04d08
                        msg="waiting for configuration file",
Packit Service a04d08
                        func=wait_for_imc_cfg_file,
Packit Service a04d08
                        args=("cust.cfg", max_wait))
Packit Service a04d08
                else:
Packit Service a04d08
                    LOG.debug("Did not find the customization plugin.")
Packit Service a04d08
Packit Service a04d08
                if vmwareImcConfigFilePath:
Packit Service a04d08
                    LOG.debug("Found VMware Customization Config File at %s",
Packit Service a04d08
                              vmwareImcConfigFilePath)
Packit Service a04d08
                    nicspath = wait_for_imc_cfg_file(
Packit Service a04d08
                        filename="nics.txt", maxwait=10, naplen=5)
Packit Service a04d08
                else:
Packit Service a04d08
                    LOG.debug("Did not find VMware Customization Config File")
Packit Service a04d08
            else:
Packit Service a04d08
                LOG.debug("Customization for VMware platform is disabled.")
Packit Service a04d08
Packit Service a04d08
        if vmwareImcConfigFilePath:
Packit Service a04d08
            self._vmware_nics_to_enable = ""
Packit Service a04d08
            try:
Packit Service a04d08
                cf = ConfigFile(vmwareImcConfigFilePath)
Packit Service a04d08
                self._vmware_cust_conf = Config(cf)
Packit Service 751c4a
                set_gc_status(self._vmware_cust_conf, "Started")
Packit Service 751c4a
Packit Service a04d08
                (md, ud, cfg) = read_vmware_imc(self._vmware_cust_conf)
Packit Service a04d08
                self._vmware_nics_to_enable = get_nics_to_enable(nicspath)
Packit Service a04d08
                imcdirpath = os.path.dirname(vmwareImcConfigFilePath)
Packit Service a04d08
                product_marker = self._vmware_cust_conf.marker_id
Packit Service a04d08
                hasmarkerfile = check_marker_exists(
Packit Service a04d08
                    product_marker, os.path.join(self.paths.cloud_dir, 'data'))
Packit Service a04d08
                special_customization = product_marker and not hasmarkerfile
Packit Service a04d08
                customscript = self._vmware_cust_conf.custom_script_name
Packit Service 751c4a
Packit Service 751c4a
                # In case there is a custom script, check whether VMware
Packit Service 751c4a
                # Tools configuration allow the custom script to run.
Packit Service 751c4a
                if special_customization and customscript:
Packit Service 751c4a
                    defVal = "false"
Packit Service 751c4a
                    if self._vmware_cust_conf.default_run_post_script:
Packit Service 751c4a
                        LOG.debug(
Packit Service 751c4a
                            "Set default value to true due to"
Packit Service 751c4a
                            " customization configuration."
Packit Service 751c4a
                        )
Packit Service 751c4a
                        defVal = "true"
Packit Service 751c4a
Packit Service 751c4a
                    custScriptConfig = get_tools_config(
Packit Service 751c4a
                        CONFGROUPNAME_GUESTCUSTOMIZATION,
Packit Service 751c4a
                        GUESTCUSTOMIZATION_ENABLE_CUST_SCRIPTS,
Packit Service 751c4a
                        defVal)
Packit Service 751c4a
                    if custScriptConfig.lower() != "true":
Packit Service 751c4a
                        # Update the customization status if custom script
Packit Service 751c4a
                        # is disabled
Packit Service a04d08
                        msg = "Custom script is disabled by VM Administrator"
Packit Service a04d08
                        LOG.debug(msg)
Packit Service a04d08
                        set_customization_status(
Packit Service a04d08
                            GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
Packit Service a04d08
                            GuestCustErrorEnum.GUESTCUST_ERROR_SCRIPT_DISABLED)
Packit Service a04d08
                        raise RuntimeError(msg)
Packit Service a04d08
Packit Service a04d08
                ccScriptsDir = os.path.join(
Packit Service a04d08
                    self.paths.get_cpath("scripts"),
Packit Service a04d08
                    "per-instance")
Packit Service a04d08
            except Exception as e:
Packit Service a04d08
                _raise_error_status(
Packit Service a04d08
                    "Error parsing the customization Config File",
Packit Service a04d08
                    e,
Packit Service a04d08
                    GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
Packit Service 751c4a
                    vmwareImcConfigFilePath,
Packit Service 751c4a
                    self._vmware_cust_conf)
Packit Service a04d08
Packit Service a04d08
            if special_customization:
Packit Service a04d08
                if customscript:
Packit Service a04d08
                    try:
Packit Service a04d08
                        precust = PreCustomScript(customscript, imcdirpath)
Packit Service a04d08
                        precust.execute()
Packit Service a04d08
                    except Exception as e:
Packit Service a04d08
                        _raise_error_status(
Packit Service a04d08
                            "Error executing pre-customization script",
Packit Service a04d08
                            e,
Packit Service a04d08
                            GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
Packit Service 751c4a
                            vmwareImcConfigFilePath,
Packit Service 751c4a
                            self._vmware_cust_conf)
Packit Service a04d08
Packit Service a04d08
            try:
Packit Service a04d08
                LOG.debug("Preparing the Network configuration")
Packit Service a04d08
                self._network_config = get_network_config_from_conf(
Packit Service a04d08
                    self._vmware_cust_conf,
Packit Service a04d08
                    True,
Packit Service a04d08
                    True,
Packit Service a04d08
                    self.distro.osfamily)
Packit Service a04d08
            except Exception as e:
Packit Service a04d08
                _raise_error_status(
Packit Service a04d08
                    "Error preparing Network Configuration",
Packit Service a04d08
                    e,
Packit Service a04d08
                    GuestCustEvent.GUESTCUST_EVENT_NETWORK_SETUP_FAILED,
Packit Service 751c4a
                    vmwareImcConfigFilePath,
Packit Service 751c4a
                    self._vmware_cust_conf)
Packit Service a04d08
Packit Service a04d08
            if special_customization:
Packit Service a04d08
                LOG.debug("Applying password customization")
Packit Service a04d08
                pwdConfigurator = PasswordConfigurator()
Packit Service a04d08
                adminpwd = self._vmware_cust_conf.admin_password
Packit Service a04d08
                try:
Packit Service a04d08
                    resetpwd = self._vmware_cust_conf.reset_password
Packit Service a04d08
                    if adminpwd or resetpwd:
Packit Service a04d08
                        pwdConfigurator.configure(adminpwd, resetpwd,
Packit Service a04d08
                                                  self.distro)
Packit Service a04d08
                    else:
Packit Service a04d08
                        LOG.debug("Changing password is not needed")
Packit Service a04d08
                except Exception as e:
Packit Service a04d08
                    _raise_error_status(
Packit Service a04d08
                        "Error applying Password Configuration",
Packit Service a04d08
                        e,
Packit Service a04d08
                        GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
Packit Service 751c4a
                        vmwareImcConfigFilePath,
Packit Service 751c4a
                        self._vmware_cust_conf)
Packit Service a04d08
Packit Service a04d08
                if customscript:
Packit Service a04d08
                    try:
Packit Service a04d08
                        postcust = PostCustomScript(customscript,
Packit Service a04d08
                                                    imcdirpath,
Packit Service a04d08
                                                    ccScriptsDir)
Packit Service a04d08
                        postcust.execute()
Packit Service a04d08
                    except Exception as e:
Packit Service a04d08
                        _raise_error_status(
Packit Service a04d08
                            "Error executing post-customization script",
Packit Service a04d08
                            e,
Packit Service a04d08
                            GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
Packit Service 751c4a
                            vmwareImcConfigFilePath,
Packit Service 751c4a
                            self._vmware_cust_conf)
Packit Service a04d08
Packit Service a04d08
            if product_marker:
Packit Service a04d08
                try:
Packit Service a04d08
                    setup_marker_files(
Packit Service a04d08
                        product_marker,
Packit Service a04d08
                        os.path.join(self.paths.cloud_dir, 'data'))
Packit Service a04d08
                except Exception as e:
Packit Service a04d08
                    _raise_error_status(
Packit Service a04d08
                        "Error creating marker files",
Packit Service a04d08
                        e,
Packit Service a04d08
                        GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
Packit Service 751c4a
                        vmwareImcConfigFilePath,
Packit Service 751c4a
                        self._vmware_cust_conf)
Packit Service a04d08
Packit Service a04d08
            self._vmware_cust_found = True
Packit Service a04d08
            found.append('vmware-tools')
Packit Service a04d08
Packit Service a04d08
            # TODO: Need to set the status to DONE only when the
Packit Service a04d08
            # customization is done successfully.
Packit Service a04d08
            util.del_dir(os.path.dirname(vmwareImcConfigFilePath))
Packit Service a04d08
            enable_nics(self._vmware_nics_to_enable)
Packit Service a04d08
            set_customization_status(
Packit Service a04d08
                GuestCustStateEnum.GUESTCUST_STATE_DONE,
Packit Service a04d08
                GuestCustErrorEnum.GUESTCUST_ERROR_SUCCESS)
Packit Service 751c4a
            set_gc_status(self._vmware_cust_conf, "Successful")
Packit Service a04d08
Packit Service a04d08
        else:
Packit Service a04d08
            np = [('com.vmware.guestInfo', transport_vmware_guestinfo),
Packit Service a04d08
                  ('iso', transport_iso9660)]
Packit Service a04d08
            name = None
Packit Service a04d08
            for name, transfunc in np:
Packit Service a04d08
                contents = transfunc()
Packit Service a04d08
                if contents:
Packit Service a04d08
                    break
Packit Service a04d08
            if contents:
Packit Service a04d08
                (md, ud, cfg) = read_ovf_environment(contents)
Packit Service a04d08
                self.environment = contents
Packit Service a04d08
                found.append(name)
Packit Service a04d08
Packit Service a04d08
        # There was no OVF transports found
Packit Service a04d08
        if len(found) == 0:
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
        if 'seedfrom' in md and md['seedfrom']:
Packit Service a04d08
            seedfrom = md['seedfrom']
Packit Service a04d08
            seedfound = False
Packit Service a04d08
            for proto in self.supported_seed_starts:
Packit Service a04d08
                if seedfrom.startswith(proto):
Packit Service a04d08
                    seedfound = proto
Packit Service a04d08
                    break
Packit Service a04d08
            if not seedfound:
Packit Service a04d08
                LOG.debug("Seed from %s not supported by %s",
Packit Service a04d08
                          seedfrom, self)
Packit Service a04d08
                return False
Packit Service a04d08
Packit Service a04d08
            (md_seed, ud) = util.read_seeded(seedfrom, timeout=None)
Packit Service a04d08
            LOG.debug("Using seeded cache data from %s", seedfrom)
Packit Service a04d08
Packit Service a04d08
            md = util.mergemanydict([md, md_seed])
Packit Service a04d08
            found.append(seedfrom)
Packit Service a04d08
Packit Service a04d08
        # Now that we have exhausted any other places merge in the defaults
Packit Service a04d08
        md = util.mergemanydict([md, defaults])
Packit Service a04d08
Packit Service a04d08
        self.seed = ",".join(found)
Packit Service a04d08
        self.metadata = md
Packit Service a04d08
        self.userdata_raw = ud
Packit Service a04d08
        self.cfg = cfg
Packit Service a04d08
        return True
Packit Service a04d08
Packit Service a04d08
    def _get_subplatform(self):
Packit Service a04d08
        system_type = util.read_dmi_data("system-product-name").lower()
Packit Service a04d08
        if system_type == 'vmware':
Packit Service a04d08
            return 'vmware (%s)' % self.seed
Packit Service a04d08
        return 'ovf (%s)' % self.seed
Packit Service a04d08
Packit Service a04d08
    def get_public_ssh_keys(self):
Packit Service a04d08
        if 'public-keys' not in self.metadata:
Packit Service a04d08
            return []
Packit Service a04d08
        pks = self.metadata['public-keys']
Packit Service a04d08
        if isinstance(pks, (list)):
Packit Service a04d08
            return pks
Packit Service a04d08
        else:
Packit Service a04d08
            return [pks]
Packit Service a04d08
Packit Service a04d08
    # The data sources' config_obj is a cloud-config formatted
Packit Service a04d08
    # object that came to it from ways other than cloud-config
Packit Service a04d08
    # because cloud-config content would be handled elsewhere
Packit Service a04d08
    def get_config_obj(self):
Packit Service a04d08
        return self.cfg
Packit Service a04d08
Packit Service a04d08
    @property
Packit Service a04d08
    def network_config(self):
Packit Service a04d08
        return self._network_config
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class DataSourceOVFNet(DataSourceOVF):
Packit Service a04d08
    def __init__(self, sys_cfg, distro, paths):
Packit Service a04d08
        DataSourceOVF.__init__(self, sys_cfg, distro, paths)
Packit Service a04d08
        self.seed_dir = os.path.join(paths.seed_dir, 'ovf-net')
Packit Service 751c4a
        self.supported_seed_starts = ("http://", "https://")
Packit Service a04d08
        self.vmware_customization_supported = False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_max_wait_from_cfg(cfg):
Packit Service a04d08
    default_max_wait = 90
Packit Service a04d08
    max_wait_cfg_option = 'vmware_cust_file_max_wait'
Packit Service a04d08
    max_wait = default_max_wait
Packit Service a04d08
Packit Service a04d08
    if not cfg:
Packit Service a04d08
        return max_wait
Packit Service a04d08
Packit Service a04d08
    try:
Packit Service a04d08
        max_wait = int(cfg.get(max_wait_cfg_option, default_max_wait))
Packit Service a04d08
    except ValueError:
Packit Service a04d08
        LOG.warning("Failed to get '%s', using %s",
Packit Service a04d08
                    max_wait_cfg_option, default_max_wait)
Packit Service a04d08
Packit Service a04d08
    if max_wait <= 0:
Packit Service a04d08
        LOG.warning("Invalid value '%s' for '%s', using '%s' instead",
Packit Service a04d08
                    max_wait, max_wait_cfg_option, default_max_wait)
Packit Service a04d08
        max_wait = default_max_wait
Packit Service a04d08
Packit Service a04d08
    return max_wait
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def wait_for_imc_cfg_file(filename, maxwait=180, naplen=5,
Packit Service a04d08
                          dirpath="/var/run/vmware-imc"):
Packit Service a04d08
    waited = 0
Packit Service a04d08
Packit Service a04d08
    while waited < maxwait:
Packit Service a04d08
        fileFullPath = os.path.join(dirpath, filename)
Packit Service a04d08
        if os.path.isfile(fileFullPath):
Packit Service a04d08
            return fileFullPath
Packit Service a04d08
        LOG.debug("Waiting for VMware Customization Config File")
Packit Service a04d08
        time.sleep(naplen)
Packit Service a04d08
        waited += naplen
Packit Service a04d08
    return None
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_network_config_from_conf(config, use_system_devices=True,
Packit Service a04d08
                                 configure=False, osfamily=None):
Packit Service a04d08
    nicConfigurator = NicConfigurator(config.nics, use_system_devices)
Packit Service a04d08
    nics_cfg_list = nicConfigurator.generate(configure, osfamily)
Packit Service a04d08
Packit Service a04d08
    return get_network_config(nics_cfg_list,
Packit Service a04d08
                              config.name_servers,
Packit Service a04d08
                              config.dns_suffixes)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_network_config(nics=None, nameservers=None, search=None):
Packit Service a04d08
    config_list = nics
Packit Service a04d08
Packit Service a04d08
    if nameservers or search:
Packit Service a04d08
        config_list.append({'type': 'nameserver', 'address': nameservers,
Packit Service a04d08
                            'search': search})
Packit Service a04d08
Packit Service a04d08
    return {'version': 1, 'config': config_list}
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# This will return a dict with some content
Packit Service a04d08
#  meta-data, user-data, some config
Packit Service a04d08
def read_vmware_imc(config):
Packit Service a04d08
    md = {}
Packit Service a04d08
    cfg = {}
Packit Service a04d08
    ud = None
Packit Service a04d08
    if config.host_name:
Packit Service a04d08
        if config.domain_name:
Packit Service a04d08
            md['local-hostname'] = config.host_name + "." + config.domain_name
Packit Service a04d08
        else:
Packit Service a04d08
            md['local-hostname'] = config.host_name
Packit Service a04d08
Packit Service a04d08
    if config.timezone:
Packit Service a04d08
        cfg['timezone'] = config.timezone
Packit Service a04d08
Packit Service a04d08
    md['instance-id'] = "iid-vmware-imc"
Packit Service a04d08
    return (md, ud, cfg)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# This will return a dict with some content
Packit Service a04d08
#  meta-data, user-data, some config
Packit Service a04d08
def read_ovf_environment(contents):
Packit Service a04d08
    props = get_properties(contents)
Packit Service a04d08
    md = {}
Packit Service a04d08
    cfg = {}
Packit Service a04d08
    ud = None
Packit Service a04d08
    cfg_props = ['password']
Packit Service a04d08
    md_props = ['seedfrom', 'local-hostname', 'public-keys', 'instance-id']
Packit Service a04d08
    for (prop, val) in props.items():
Packit Service a04d08
        if prop == 'hostname':
Packit Service a04d08
            prop = "local-hostname"
Packit Service a04d08
        if prop in md_props:
Packit Service a04d08
            md[prop] = val
Packit Service a04d08
        elif prop in cfg_props:
Packit Service a04d08
            cfg[prop] = val
Packit Service a04d08
        elif prop == "user-data":
Packit Service a04d08
            try:
Packit Service a04d08
                ud = base64.b64decode(val.encode())
Packit Service a04d08
            except Exception:
Packit Service a04d08
                ud = val.encode()
Packit Service a04d08
    return (md, ud, cfg)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# Returns tuple of filename (in 'dirname', and the contents of the file)
Packit Service a04d08
# on "not found", returns 'None' for filename and False for contents
Packit Service a04d08
def get_ovf_env(dirname):
Packit Service a04d08
    env_names = ("ovf-env.xml", "ovf_env.xml", "OVF_ENV.XML", "OVF-ENV.XML")
Packit Service a04d08
    for fname in env_names:
Packit Service a04d08
        full_fn = os.path.join(dirname, fname)
Packit Service a04d08
        if os.path.isfile(full_fn):
Packit Service a04d08
            try:
Packit Service a04d08
                contents = util.load_file(full_fn)
Packit Service a04d08
                return (fname, contents)
Packit Service a04d08
            except Exception:
Packit Service a04d08
                util.logexc(LOG, "Failed loading ovf file %s", full_fn)
Packit Service a04d08
    return (None, False)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def maybe_cdrom_device(devname):
Packit Service a04d08
    """Test if devname matches known list of devices which may contain iso9660
Packit Service a04d08
       filesystems.
Packit Service a04d08
Packit Service a04d08
    Be helpful in accepting either knames (with no leading /dev/) or full path
Packit Service a04d08
    names, but do not allow paths outside of /dev/, like /dev/foo/bar/xxx.
Packit Service a04d08
    """
Packit Service a04d08
    if not devname:
Packit Service a04d08
        return False
Packit Service 751c4a
    elif not isinstance(devname, str):
Packit Service a04d08
        raise ValueError("Unexpected input for devname: %s" % devname)
Packit Service a04d08
Packit Service a04d08
    # resolve '..' and multi '/' elements
Packit Service a04d08
    devname = os.path.normpath(devname)
Packit Service a04d08
Packit Service a04d08
    # drop leading '/dev/'
Packit Service a04d08
    if devname.startswith("/dev/"):
Packit Service a04d08
        # partition returns tuple (before, partition, after)
Packit Service a04d08
        devname = devname.partition("/dev/")[-1]
Packit Service a04d08
Packit Service a04d08
    # ignore leading slash (/sr0), else fail on / in name (foo/bar/xvdc)
Packit Service a04d08
    if devname.startswith("/"):
Packit Service a04d08
        devname = devname.split("/")[-1]
Packit Service a04d08
    elif devname.count("/") > 0:
Packit Service a04d08
        return False
Packit Service a04d08
Packit Service a04d08
    # if empty string
Packit Service a04d08
    if not devname:
Packit Service a04d08
        return False
Packit Service a04d08
Packit Service a04d08
    # default_regex matches values in /lib/udev/rules.d/60-cdrom_id.rules
Packit Service a04d08
    # KERNEL!="sr[0-9]*|hd[a-z]|xvd*", GOTO="cdrom_end"
Packit Service a04d08
    default_regex = r"^(sr[0-9]+|hd[a-z]|xvd.*)"
Packit Service a04d08
    devname_regex = os.environ.get("CLOUD_INIT_CDROM_DEV_REGEX", default_regex)
Packit Service a04d08
    cdmatch = re.compile(devname_regex)
Packit Service a04d08
Packit Service a04d08
    return cdmatch.match(devname) is not None
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# Transport functions are called with no arguments and return
Packit Service a04d08
# either None (indicating not present) or string content of an ovf-env.xml
Packit Service a04d08
def transport_iso9660(require_iso=True):
Packit Service a04d08
Packit Service a04d08
    # Go through mounts to see if it was already mounted
Packit Service a04d08
    mounts = util.mounts()
Packit Service a04d08
    for (dev, info) in mounts.items():
Packit Service a04d08
        fstype = info['fstype']
Packit Service a04d08
        if fstype != "iso9660" and require_iso:
Packit Service a04d08
            continue
Packit Service a04d08
        if not maybe_cdrom_device(dev):
Packit Service a04d08
            continue
Packit Service a04d08
        mp = info['mountpoint']
Packit Service a04d08
        (_fname, contents) = get_ovf_env(mp)
Packit Service a04d08
        if contents is not False:
Packit Service a04d08
            return contents
Packit Service a04d08
Packit Service a04d08
    if require_iso:
Packit Service a04d08
        mtype = "iso9660"
Packit Service a04d08
    else:
Packit Service a04d08
        mtype = None
Packit Service a04d08
Packit Service a04d08
    # generate a list of devices with mtype filesystem, filter by regex
Packit Service a04d08
    devs = [dev for dev in
Packit Service a04d08
            util.find_devs_with("TYPE=%s" % mtype if mtype else None)
Packit Service a04d08
            if maybe_cdrom_device(dev)]
Packit Service a04d08
    for dev in devs:
Packit Service a04d08
        try:
Packit Service a04d08
            (_fname, contents) = util.mount_cb(dev, get_ovf_env, mtype=mtype)
Packit Service a04d08
        except util.MountFailedError:
Packit Service a04d08
            LOG.debug("%s not mountable as iso9660", dev)
Packit Service a04d08
            continue
Packit Service a04d08
Packit Service a04d08
        if contents is not False:
Packit Service a04d08
            return contents
Packit Service a04d08
Packit Service a04d08
    return None
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def transport_vmware_guestinfo():
Packit Service a04d08
    rpctool = "vmware-rpctool"
Packit Service a04d08
    not_found = None
Packit Service 751c4a
    if not subp.which(rpctool):
Packit Service a04d08
        return not_found
Packit Service a04d08
    cmd = [rpctool, "info-get guestinfo.ovfEnv"]
Packit Service a04d08
    try:
Packit Service 751c4a
        out, _err = subp.subp(cmd)
Packit Service a04d08
        if out:
Packit Service a04d08
            return out
Packit Service a04d08
        LOG.debug("cmd %s exited 0 with empty stdout: %s", cmd, out)
Packit Service 751c4a
    except subp.ProcessExecutionError as e:
Packit Service a04d08
        if e.exit_code != 1:
Packit Service a04d08
            LOG.warning("%s exited with code %d", rpctool, e.exit_code)
Packit Service a04d08
            LOG.debug(e)
Packit Service a04d08
    return not_found
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def find_child(node, filter_func):
Packit Service a04d08
    ret = []
Packit Service a04d08
    if not node.hasChildNodes():
Packit Service a04d08
        return ret
Packit Service a04d08
    for child in node.childNodes:
Packit Service a04d08
        if filter_func(child):
Packit Service a04d08
            ret.append(child)
Packit Service a04d08
    return ret
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_properties(contents):
Packit Service a04d08
Packit Service a04d08
    dom = minidom.parseString(contents)
Packit Service a04d08
    if dom.documentElement.localName != "Environment":
Packit Service a04d08
        raise XmlError("No Environment Node")
Packit Service a04d08
Packit Service a04d08
    if not dom.documentElement.hasChildNodes():
Packit Service a04d08
        raise XmlError("No Child Nodes")
Packit Service a04d08
Packit Service a04d08
    envNsURI = "http://schemas.dmtf.org/ovf/environment/1"
Packit Service a04d08
Packit Service a04d08
    # could also check here that elem.namespaceURI ==
Packit Service a04d08
    #   "http://schemas.dmtf.org/ovf/environment/1"
Packit Service a04d08
    propSections = find_child(dom.documentElement,
Packit Service a04d08
                              lambda n: n.localName == "PropertySection")
Packit Service a04d08
Packit Service a04d08
    if len(propSections) == 0:
Packit Service a04d08
        raise XmlError("No 'PropertySection's")
Packit Service a04d08
Packit Service a04d08
    props = {}
Packit Service a04d08
    propElems = find_child(propSections[0],
Packit Service a04d08
                           (lambda n: n.localName == "Property"))
Packit Service a04d08
Packit Service a04d08
    for elem in propElems:
Packit Service a04d08
        key = elem.attributes.getNamedItemNS(envNsURI, "key").value
Packit Service a04d08
        val = elem.attributes.getNamedItemNS(envNsURI, "value").value
Packit Service a04d08
        props[key] = val
Packit Service a04d08
Packit Service a04d08
    return props
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def search_file(dirpath, filename):
Packit Service a04d08
    if not dirpath or not filename:
Packit Service a04d08
        return None
Packit Service a04d08
Packit Service a04d08
    for root, _dirs, files in os.walk(dirpath):
Packit Service a04d08
        if filename in files:
Packit Service a04d08
            return os.path.join(root, filename)
Packit Service a04d08
Packit Service a04d08
    return None
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class XmlError(Exception):
Packit Service a04d08
    pass
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# Used to match classes to dependencies
Packit Service a04d08
datasources = (
Packit Service a04d08
    (DataSourceOVF, (sources.DEP_FILESYSTEM, )),
Packit Service a04d08
    (DataSourceOVFNet, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
Packit Service a04d08
)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# Return a list of data sources that match this set of dependencies
Packit Service a04d08
def get_datasource_list(depends):
Packit Service a04d08
    return sources.list_from_depends(depends, datasources)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# To check if marker file exists
Packit Service a04d08
def check_marker_exists(markerid, marker_dir):
Packit Service a04d08
    """
Packit Service a04d08
    Check the existence of a marker file.
Packit Service a04d08
    Presence of marker file determines whether a certain code path is to be
Packit Service a04d08
    executed. It is needed for partial guest customization in VMware.
Packit Service a04d08
    @param markerid: is an unique string representing a particular product
Packit Service a04d08
                     marker.
Packit Service a04d08
    @param: marker_dir: The directory in which markers exist.
Packit Service a04d08
    """
Packit Service a04d08
    if not markerid:
Packit Service a04d08
        return False
Packit Service a04d08
    markerfile = os.path.join(marker_dir, ".markerfile-" + markerid + ".txt")
Packit Service a04d08
    if os.path.exists(markerfile):
Packit Service a04d08
        return True
Packit Service a04d08
    return False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# Create a marker file
Packit Service a04d08
def setup_marker_files(markerid, marker_dir):
Packit Service a04d08
    """
Packit Service a04d08
    Create a new marker file.
Packit Service a04d08
    Marker files are unique to a full customization workflow in VMware
Packit Service a04d08
    environment.
Packit Service a04d08
    @param markerid: is an unique string representing a particular product
Packit Service a04d08
                     marker.
Packit Service a04d08
    @param: marker_dir: The directory in which markers exist.
Packit Service a04d08
Packit Service a04d08
    """
Packit Service a04d08
    LOG.debug("Handle marker creation")
Packit Service a04d08
    markerfile = os.path.join(marker_dir, ".markerfile-" + markerid + ".txt")
Packit Service a04d08
    for fname in os.listdir(marker_dir):
Packit Service a04d08
        if fname.startswith(".markerfile"):
Packit Service a04d08
            util.del_file(os.path.join(marker_dir, fname))
Packit Service a04d08
    open(markerfile, 'w').close()
Packit Service a04d08
Packit Service a04d08
Packit Service 751c4a
def _raise_error_status(prefix, error, event, config_file, conf):
Packit Service a04d08
    """
Packit Service a04d08
    Raise error and send customization status to the underlying VMware
Packit Service a04d08
    Virtualization Platform. Also, cleanup the imc directory.
Packit Service a04d08
    """
Packit Service a04d08
    LOG.debug('%s: %s', prefix, error)
Packit Service a04d08
    set_customization_status(
Packit Service a04d08
        GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
Packit Service a04d08
        event)
Packit Service 751c4a
    set_gc_status(conf, prefix)
Packit Service a04d08
    util.del_dir(os.path.dirname(config_file))
Packit Service a04d08
    raise error
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab