Blame cloudinit/sources/DataSourceAltCloud.py

Packit Service a04d08
# Copyright (C) 2009-2010 Canonical Ltd.
Packit Service a04d08
# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P.
Packit Service a04d08
# Copyright (C) 2012 Yahoo! Inc.
Packit Service a04d08
#
Packit Service a04d08
# Author: Joe VLcek <JVLcek@RedHat.com>
Packit Service a04d08
# Author: Juerg Haefliger <juerg.haefliger@hp.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
'''
Packit Service a04d08
This file contains code used to gather the user data passed to an
Packit Service a04d08
instance on RHEVm and vSphere.
Packit Service a04d08
'''
Packit Service a04d08
Packit Service a04d08
import errno
Packit Service a04d08
import os
Packit Service a04d08
import os.path
Packit Service a04d08
Packit Service a04d08
from cloudinit import log as logging
Packit Service a04d08
from cloudinit import sources
Packit Service 9bfd13
from cloudinit import subp
Packit Service a04d08
from cloudinit import util
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
LOG = logging.getLogger(__name__)
Packit Service a04d08
Packit Service a04d08
# Needed file paths
Packit Service a04d08
CLOUD_INFO_FILE = '/etc/sysconfig/cloud-info'
Packit Service a04d08
Packit Service a04d08
# Shell command lists
Packit Service a04d08
CMD_PROBE_FLOPPY = ['modprobe', 'floppy']
Packit Service a04d08
Packit Service a04d08
META_DATA_NOT_SUPPORTED = {
Packit Service a04d08
    'block-device-mapping': {},
Packit Service a04d08
    'instance-id': 455,
Packit Service a04d08
    'local-hostname': 'localhost',
Packit Service a04d08
    'placement': {},
Packit Service a04d08
}
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def read_user_data_callback(mount_dir):
Packit Service a04d08
    '''
Packit Service a04d08
    Description:
Packit Service a04d08
        This callback will be applied by util.mount_cb() on the mounted
Packit Service a04d08
        file.
Packit Service a04d08
Packit Service a04d08
        Deltacloud file name contains deltacloud. Those not using
Packit Service a04d08
        Deltacloud but instead instrumenting the injection, could
Packit Service a04d08
        drop deltacloud from the file name.
Packit Service a04d08
Packit Service a04d08
    Input:
Packit Service a04d08
        mount_dir - Mount directory
Packit Service a04d08
Packit Service a04d08
    Returns:
Packit Service a04d08
        User Data
Packit Service a04d08
Packit Service a04d08
    '''
Packit Service a04d08
Packit Service a04d08
    deltacloud_user_data_file = mount_dir + '/deltacloud-user-data.txt'
Packit Service a04d08
    user_data_file = mount_dir + '/user-data.txt'
Packit Service a04d08
Packit Service a04d08
    # First try deltacloud_user_data_file. On failure try user_data_file.
Packit Service a04d08
    try:
Packit Service a04d08
        user_data = util.load_file(deltacloud_user_data_file).strip()
Packit Service a04d08
    except IOError:
Packit Service a04d08
        try:
Packit Service a04d08
            user_data = util.load_file(user_data_file).strip()
Packit Service a04d08
        except IOError:
Packit Service a04d08
            util.logexc(LOG, 'Failed accessing user data file.')
Packit Service a04d08
            return None
Packit Service a04d08
Packit Service a04d08
    return user_data
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class DataSourceAltCloud(sources.DataSource):
Packit Service a04d08
Packit Service a04d08
    dsname = 'AltCloud'
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.supported_seed_starts = ("/", "file://")
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_cloud_type(self):
Packit Service a04d08
        '''
Packit Service a04d08
        Description:
Packit Service a04d08
            Get the type for the cloud back end this instance is running on
Packit Service a04d08
            by examining the string returned by reading either:
Packit Service a04d08
                CLOUD_INFO_FILE or
Packit Service a04d08
                the dmi data.
Packit Service a04d08
Packit Service a04d08
        Input:
Packit Service a04d08
            None
Packit Service a04d08
Packit Service a04d08
        Returns:
Packit Service a04d08
            One of the following strings:
Packit Service a04d08
            'RHEV', 'VSPHERE' or 'UNKNOWN'
Packit Service a04d08
Packit Service a04d08
        '''
Packit Service a04d08
        if os.path.exists(CLOUD_INFO_FILE):
Packit Service a04d08
            try:
Packit Service a04d08
                cloud_type = util.load_file(CLOUD_INFO_FILE).strip().upper()
Packit Service a04d08
            except IOError:
Packit Service a04d08
                util.logexc(LOG, 'Unable to access cloud info file at %s.',
Packit Service a04d08
                            CLOUD_INFO_FILE)
Packit Service a04d08
                return 'UNKNOWN'
Packit Service a04d08
            return cloud_type
Packit Service a04d08
        system_name = util.read_dmi_data("system-product-name")
Packit Service a04d08
        if not system_name:
Packit Service a04d08
            return 'UNKNOWN'
Packit Service a04d08
Packit Service a04d08
        sys_name = system_name.upper()
Packit Service a04d08
Packit Service a04d08
        if sys_name.startswith('RHEV'):
Packit Service a04d08
            return 'RHEV'
Packit Service a04d08
Packit Service a04d08
        if sys_name.startswith('VMWARE'):
Packit Service a04d08
            return 'VSPHERE'
Packit Service a04d08
Packit Service a04d08
        return 'UNKNOWN'
Packit Service a04d08
Packit Service a04d08
    def _get_data(self):
Packit Service a04d08
        '''
Packit Service a04d08
        Description:
Packit Service a04d08
            User Data is passed to the launching instance which
Packit Service a04d08
            is used to perform instance configuration.
Packit Service a04d08
Packit Service a04d08
            Cloud providers expose the user data differently.
Packit Service a04d08
            It is necessary to determine which cloud provider
Packit Service a04d08
            the current instance is running on to determine
Packit Service a04d08
            how to access the user data. Images built with
Packit Service a04d08
            image factory will contain a CLOUD_INFO_FILE which
Packit Service a04d08
            contains a string identifying the cloud provider.
Packit Service a04d08
Packit Service a04d08
            Images not built with Imagefactory will try to
Packit Service a04d08
            determine what the cloud provider is based on system
Packit Service a04d08
            information.
Packit Service a04d08
        '''
Packit Service a04d08
Packit Service a04d08
        LOG.debug('Invoked get_data()')
Packit Service a04d08
Packit Service a04d08
        cloud_type = self.get_cloud_type()
Packit Service a04d08
Packit Service a04d08
        LOG.debug('cloud_type: %s', str(cloud_type))
Packit Service a04d08
Packit Service a04d08
        if 'RHEV' in cloud_type:
Packit Service a04d08
            if self.user_data_rhevm():
Packit Service a04d08
                return True
Packit Service a04d08
        elif 'VSPHERE' in cloud_type:
Packit Service a04d08
            if self.user_data_vsphere():
Packit Service a04d08
                return True
Packit Service a04d08
        else:
Packit Service a04d08
            # there was no recognized alternate cloud type
Packit Service a04d08
            # indicating this handler should not be used.
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
        # No user data found
Packit Service a04d08
        util.logexc(LOG, 'Failed accessing user data.')
Packit Service a04d08
        return False
Packit Service a04d08
Packit Service a04d08
    def _get_subplatform(self):
Packit Service a04d08
        """Return the subplatform metadata details."""
Packit Service a04d08
        cloud_type = self.get_cloud_type()
Packit Service a04d08
        if not hasattr(self, 'source'):
Packit Service a04d08
            self.source = sources.METADATA_UNKNOWN
Packit Service a04d08
        if cloud_type == 'RHEV':
Packit Service a04d08
            self.source = '/dev/fd0'
Packit Service a04d08
        return '%s (%s)' % (cloud_type.lower(), self.source)
Packit Service a04d08
Packit Service a04d08
    def user_data_rhevm(self):
Packit Service a04d08
        '''
Packit Service a04d08
        RHEVM specific userdata read
Packit Service a04d08
Packit Service a04d08
         If on RHEV-M the user data will be contained on the
Packit Service a04d08
         floppy device in file <user_data_file>
Packit Service a04d08
         To access it:
Packit Service a04d08
           modprobe floppy
Packit Service a04d08
Packit Service a04d08
           Leverage util.mount_cb to:
Packit Service a04d08
               mkdir <tmp mount dir>
Packit Service a04d08
               mount /dev/fd0 <tmp mount dir>
Packit Service a04d08
               The call back passed to util.mount_cb will do:
Packit Service a04d08
                   read <tmp mount dir>/<user_data_file>
Packit Service a04d08
        '''
Packit Service a04d08
Packit Service a04d08
        return_str = None
Packit Service a04d08
Packit Service a04d08
        # modprobe floppy
Packit Service a04d08
        try:
Packit Service a04d08
            modprobe_floppy()
Packit Service 9bfd13
        except subp.ProcessExecutionError as e:
Packit Service a04d08
            util.logexc(LOG, 'Failed modprobe: %s', e)
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
        floppy_dev = '/dev/fd0'
Packit Service a04d08
Packit Service a04d08
        # udevadm settle for floppy device
Packit Service a04d08
        try:
Packit Service a04d08
            util.udevadm_settle(exists=floppy_dev, timeout=5)
Packit Service 9bfd13
        except (subp.ProcessExecutionError, OSError) as e:
Packit Service a04d08
            util.logexc(LOG, 'Failed udevadm_settle: %s\n', e)
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
        try:
Packit Service a04d08
            return_str = util.mount_cb(floppy_dev, read_user_data_callback)
Packit Service a04d08
        except OSError as err:
Packit Service a04d08
            if err.errno != errno.ENOENT:
Packit Service a04d08
                raise
Packit Service a04d08
        except util.MountFailedError:
Packit Service a04d08
            util.logexc(LOG, "Failed to mount %s when looking for user data",
Packit Service a04d08
                        floppy_dev)
Packit Service a04d08
Packit Service a04d08
        self.userdata_raw = return_str
Packit Service a04d08
        self.metadata = META_DATA_NOT_SUPPORTED
Packit Service a04d08
Packit Service a04d08
        if return_str:
Packit Service a04d08
            return True
Packit Service a04d08
        else:
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
    def user_data_vsphere(self):
Packit Service a04d08
        '''
Packit Service a04d08
        vSphere specific userdata read
Packit Service a04d08
Packit Service a04d08
        If on vSphere the user data will be contained on the
Packit Service a04d08
        cdrom device in file <user_data_file>
Packit Service a04d08
        To access it:
Packit Service a04d08
           Leverage util.mount_cb to:
Packit Service a04d08
               mkdir <tmp mount dir>
Packit Service a04d08
               mount /dev/fd0 <tmp mount dir>
Packit Service a04d08
               The call back passed to util.mount_cb will do:
Packit Service a04d08
                   read <tmp mount dir>/<user_data_file>
Packit Service a04d08
        '''
Packit Service a04d08
Packit Service a04d08
        return_str = None
Packit Service a04d08
        cdrom_list = util.find_devs_with('LABEL=CDROM')
Packit Service a04d08
        for cdrom_dev in cdrom_list:
Packit Service a04d08
            try:
Packit Service a04d08
                return_str = util.mount_cb(cdrom_dev, read_user_data_callback)
Packit Service a04d08
                if return_str:
Packit Service a04d08
                    self.source = cdrom_dev
Packit Service a04d08
                    break
Packit Service a04d08
            except OSError as err:
Packit Service a04d08
                if err.errno != errno.ENOENT:
Packit Service a04d08
                    raise
Packit Service a04d08
            except util.MountFailedError:
Packit Service a04d08
                util.logexc(LOG, "Failed to mount %s when looking for user "
Packit Service a04d08
                            "data", cdrom_dev)
Packit Service a04d08
Packit Service a04d08
        self.userdata_raw = return_str
Packit Service a04d08
        self.metadata = META_DATA_NOT_SUPPORTED
Packit Service a04d08
Packit Service a04d08
        if return_str:
Packit Service a04d08
            return True
Packit Service a04d08
        else:
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def modprobe_floppy():
Packit Service 9bfd13
    out, _err = subp.subp(CMD_PROBE_FLOPPY)
Packit Service a04d08
    LOG.debug('Command: %s\nOutput%s', ' '.join(CMD_PROBE_FLOPPY), out)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# Used to match classes to dependencies
Packit Service a04d08
# Source DataSourceAltCloud does not really depend on networking.
Packit Service a04d08
# In the future 'dsmode' like behavior can be added to offer user
Packit Service a04d08
# the ability to run before networking.
Packit Service a04d08
datasources = [
Packit Service a04d08
    (DataSourceAltCloud, (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
# vi: ts=4 expandtab