|
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
|