Add RHEVm and vSphere support as datasource AltCloud
These changes add a new data source to cloud-init to support passing user data to RHEVm and vSphere. The user data is passed to RHEVm v3.0 (current version) using a floppy injection hook and to vSphere via cdrom device. RHEVm v3.1 will use a method similar to vSphere. Once available support for that is also expected.
This commit is contained in:
commit
2548f7de9c
@ -1,4 +1,5 @@
|
|||||||
0.7.0:
|
0.7.0:
|
||||||
|
- Added RHEVm and vSphere support as source AltCloud [Joseph VLcek]
|
||||||
- add write-files module (LP: #1012854)
|
- add write-files module (LP: #1012854)
|
||||||
- Add setuptools + cheetah to debian package build dependencies (LP: #1022101)
|
- Add setuptools + cheetah to debian package build dependencies (LP: #1022101)
|
||||||
- Adjust the sysvinit local script to provide 'cloud-init-local' and have
|
- Adjust the sysvinit local script to provide 'cloud-init-local' and have
|
||||||
|
@ -31,6 +31,7 @@ CFG_BUILTIN = {
|
|||||||
'datasource_list': [
|
'datasource_list': [
|
||||||
'NoCloud',
|
'NoCloud',
|
||||||
'ConfigDrive',
|
'ConfigDrive',
|
||||||
|
'AltCloud',
|
||||||
'OVF',
|
'OVF',
|
||||||
'MAAS',
|
'MAAS',
|
||||||
'Ec2',
|
'Ec2',
|
||||||
|
299
cloudinit/sources/DataSourceAltCloud.py
Normal file
299
cloudinit/sources/DataSourceAltCloud.py
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
# vi: ts=4 expandtab
|
||||||
|
#
|
||||||
|
# Copyright (C) 2009-2010 Canonical Ltd.
|
||||||
|
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
|
||||||
|
# Copyright (C) 2012 Yahoo! Inc.
|
||||||
|
#
|
||||||
|
# Author: Joe VLcek <JVLcek@RedHat.com>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 3, as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
'''
|
||||||
|
This file contains code used to gather the user data passed to an
|
||||||
|
instance on RHEVm and vSphere.
|
||||||
|
'''
|
||||||
|
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
from cloudinit import log as logging
|
||||||
|
from cloudinit import sources
|
||||||
|
from cloudinit import util
|
||||||
|
from cloudinit.util import ProcessExecutionError
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Needed file paths
|
||||||
|
CLOUD_INFO_FILE = '/etc/sysconfig/cloud-info'
|
||||||
|
|
||||||
|
# Shell command lists
|
||||||
|
CMD_DMI_SYSTEM = ['/usr/sbin/dmidecode', '--string', 'system-product-name']
|
||||||
|
CMD_PROBE_FLOPPY = ['/sbin/modprobe', 'floppy']
|
||||||
|
CMD_UDEVADM_SETTLE = ['/sbin/udevadm', 'settle', '--quiet', '--timeout=5']
|
||||||
|
|
||||||
|
META_DATA_NOT_SUPPORTED = {
|
||||||
|
'block-device-mapping': {},
|
||||||
|
'instance-id': 455,
|
||||||
|
'local-hostname': 'localhost',
|
||||||
|
'placement': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def read_user_data_callback(mount_dir):
|
||||||
|
'''
|
||||||
|
Description:
|
||||||
|
This callback will be applied by util.mount_cb() on the mounted
|
||||||
|
file.
|
||||||
|
|
||||||
|
Deltacloud file name contains deltacloud. Those not using
|
||||||
|
Deltacloud but instead instrumenting the injection, could
|
||||||
|
drop deltacloud from the file name.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
mount_dir - Mount directory
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
User Data
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
deltacloud_user_data_file = mount_dir + '/deltacloud-user-data.txt'
|
||||||
|
user_data_file = mount_dir + '/user-data.txt'
|
||||||
|
|
||||||
|
# First try deltacloud_user_data_file. On failure try user_data_file.
|
||||||
|
try:
|
||||||
|
with open(deltacloud_user_data_file, 'r') as user_data_f:
|
||||||
|
user_data = user_data_f.read().strip()
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
with open(user_data_file, 'r') as user_data_f:
|
||||||
|
user_data = user_data_f.read().strip()
|
||||||
|
except:
|
||||||
|
util.logexc(LOG, ('Failed accessing user data file.'))
|
||||||
|
return None
|
||||||
|
|
||||||
|
return user_data
|
||||||
|
|
||||||
|
|
||||||
|
class DataSourceAltCloud(sources.DataSource):
|
||||||
|
def __init__(self, sys_cfg, distro, paths):
|
||||||
|
sources.DataSource.__init__(self, sys_cfg, distro, paths)
|
||||||
|
self.seed = None
|
||||||
|
self.supported_seed_starts = ("/", "file://")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
mstr = "%s [seed=%s]" % (util.obj_name(self), self.seed)
|
||||||
|
return mstr
|
||||||
|
|
||||||
|
def get_cloud_type(self):
|
||||||
|
'''
|
||||||
|
Description:
|
||||||
|
Get the type for the cloud back end this instance is running on
|
||||||
|
by examining the string returned by:
|
||||||
|
dmidecode --string system-product-name
|
||||||
|
|
||||||
|
On VMWare/vSphere dmidecode returns: RHEV Hypervisor
|
||||||
|
On VMWare/vSphere dmidecode returns: VMware Virtual Platform
|
||||||
|
|
||||||
|
Input:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
One of the following strings:
|
||||||
|
'RHEV', 'VSPHERE' or 'UNKNOWN'
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
cmd = CMD_DMI_SYSTEM
|
||||||
|
try:
|
||||||
|
(cmd_out, _err) = util.subp(cmd)
|
||||||
|
except ProcessExecutionError, _err:
|
||||||
|
LOG.debug(('Failed command: %s\n%s') % \
|
||||||
|
(' '.join(cmd), _err.message))
|
||||||
|
return 'UNKNOWN'
|
||||||
|
except OSError, _err:
|
||||||
|
LOG.debug(('Failed command: %s\n%s') % \
|
||||||
|
(' '.join(cmd), _err.message))
|
||||||
|
return 'UNKNOWN'
|
||||||
|
|
||||||
|
if cmd_out.upper().startswith('RHEV'):
|
||||||
|
return 'RHEV'
|
||||||
|
|
||||||
|
if cmd_out.upper().startswith('VMWARE'):
|
||||||
|
return 'VSPHERE'
|
||||||
|
|
||||||
|
return 'UNKNOWN'
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
'''
|
||||||
|
Description:
|
||||||
|
User Data is passed to the launching instance which
|
||||||
|
is used to perform instance configuration.
|
||||||
|
|
||||||
|
Cloud providers expose the user data differently.
|
||||||
|
It is necessary to determine which cloud provider
|
||||||
|
the current instance is running on to determine
|
||||||
|
how to access the user data. Images built with
|
||||||
|
image factory will contain a CLOUD_INFO_FILE which
|
||||||
|
contains a string identifying the cloud provider.
|
||||||
|
|
||||||
|
Images not built with Imagefactory will try to
|
||||||
|
determine what the cloud provider is based on system
|
||||||
|
information.
|
||||||
|
'''
|
||||||
|
|
||||||
|
LOG.debug('Invoked get_data()')
|
||||||
|
|
||||||
|
if os.path.exists(CLOUD_INFO_FILE):
|
||||||
|
try:
|
||||||
|
cloud_info = open(CLOUD_INFO_FILE)
|
||||||
|
cloud_type = cloud_info.read().strip().upper()
|
||||||
|
cloud_info.close()
|
||||||
|
except:
|
||||||
|
util.logexc(LOG, 'Unable to access cloud info file.')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
cloud_type = self.get_cloud_type()
|
||||||
|
|
||||||
|
LOG.debug('cloud_type: ' + str(cloud_type))
|
||||||
|
|
||||||
|
if 'RHEV' in cloud_type:
|
||||||
|
if self.user_data_rhevm():
|
||||||
|
return True
|
||||||
|
elif 'VSPHERE' in cloud_type:
|
||||||
|
if self.user_data_vsphere():
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# there was no recognized alternate cloud type
|
||||||
|
# indicating this handler should not be used.
|
||||||
|
return False
|
||||||
|
|
||||||
|
# No user data found
|
||||||
|
util.logexc(LOG, ('Failed accessing user data.'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def user_data_rhevm(self):
|
||||||
|
'''
|
||||||
|
RHEVM specific userdata read
|
||||||
|
|
||||||
|
If on RHEV-M the user data will be contained on the
|
||||||
|
floppy device in file <user_data_file>
|
||||||
|
To access it:
|
||||||
|
modprobe floppy
|
||||||
|
|
||||||
|
Leverage util.mount_cb to:
|
||||||
|
mkdir <tmp mount dir>
|
||||||
|
mount /dev/fd0 <tmp mount dir>
|
||||||
|
The call back passed to util.mount_cb will do:
|
||||||
|
read <tmp mount dir>/<user_data_file>
|
||||||
|
'''
|
||||||
|
|
||||||
|
return_str = None
|
||||||
|
|
||||||
|
# modprobe floppy
|
||||||
|
try:
|
||||||
|
cmd = CMD_PROBE_FLOPPY
|
||||||
|
(cmd_out, _err) = util.subp(cmd)
|
||||||
|
LOG.debug(('Command: %s\nOutput%s') % (' '.join(cmd), cmd_out))
|
||||||
|
except ProcessExecutionError, _err:
|
||||||
|
util.logexc(LOG, (('Failed command: %s\n%s') % \
|
||||||
|
(' '.join(cmd), _err.message)))
|
||||||
|
return False
|
||||||
|
except OSError, _err:
|
||||||
|
util.logexc(LOG, (('Failed command: %s\n%s') % \
|
||||||
|
(' '.join(cmd), _err.message)))
|
||||||
|
return False
|
||||||
|
|
||||||
|
floppy_dev = '/dev/fd0'
|
||||||
|
|
||||||
|
# udevadm settle for floppy device
|
||||||
|
try:
|
||||||
|
cmd = CMD_UDEVADM_SETTLE
|
||||||
|
cmd.append('--exit-if-exists=' + floppy_dev)
|
||||||
|
(cmd_out, _err) = util.subp(cmd)
|
||||||
|
LOG.debug(('Command: %s\nOutput%s') % (' '.join(cmd), cmd_out))
|
||||||
|
except ProcessExecutionError, _err:
|
||||||
|
util.logexc(LOG, (('Failed command: %s\n%s') % \
|
||||||
|
(' '.join(cmd), _err.message)))
|
||||||
|
return False
|
||||||
|
except OSError, _err:
|
||||||
|
util.logexc(LOG, (('Failed command: %s\n%s') % \
|
||||||
|
(' '.join(cmd), _err.message)))
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
return_str = util.mount_cb(floppy_dev, read_user_data_callback)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno != errno.ENOENT:
|
||||||
|
raise
|
||||||
|
except util.MountFailedError:
|
||||||
|
util.logexc(LOG, ("Failed to mount %s"
|
||||||
|
" when looking for user data"), floppy_dev)
|
||||||
|
|
||||||
|
self.userdata_raw = return_str
|
||||||
|
self.metadata = META_DATA_NOT_SUPPORTED
|
||||||
|
|
||||||
|
if return_str:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def user_data_vsphere(self):
|
||||||
|
'''
|
||||||
|
vSphere specific userdata read
|
||||||
|
|
||||||
|
If on vSphere the user data will be contained on the
|
||||||
|
cdrom device in file <user_data_file>
|
||||||
|
To access it:
|
||||||
|
Leverage util.mount_cb to:
|
||||||
|
mkdir <tmp mount dir>
|
||||||
|
mount /dev/fd0 <tmp mount dir>
|
||||||
|
The call back passed to util.mount_cb will do:
|
||||||
|
read <tmp mount dir>/<user_data_file>
|
||||||
|
'''
|
||||||
|
|
||||||
|
return_str = None
|
||||||
|
cdrom_list = util.find_devs_with('LABEL=CDROM')
|
||||||
|
for cdrom_dev in cdrom_list:
|
||||||
|
try:
|
||||||
|
return_str = util.mount_cb(cdrom_dev, read_user_data_callback)
|
||||||
|
if return_str:
|
||||||
|
break
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno != errno.ENOENT:
|
||||||
|
raise
|
||||||
|
except util.MountFailedError:
|
||||||
|
util.logexc(LOG, ("Failed to mount %s"
|
||||||
|
" when looking for user data"), cdrom_dev)
|
||||||
|
|
||||||
|
self.userdata_raw = return_str
|
||||||
|
self.metadata = META_DATA_NOT_SUPPORTED
|
||||||
|
|
||||||
|
if return_str:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Used to match classes to dependencies
|
||||||
|
# Source DataSourceAltCloud does not really depend on networking.
|
||||||
|
# In the future 'dsmode' like behavior can be added to offer user
|
||||||
|
# the ability to run before networking.
|
||||||
|
datasources = [
|
||||||
|
(DataSourceAltCloud, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Return a list of data sources that match this set of dependencies
|
||||||
|
def get_datasource_list(depends):
|
||||||
|
return sources.list_from_depends(depends, datasources)
|
65
doc/altcloud/README
Normal file
65
doc/altcloud/README
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
Data souce AltCloud will be used to pick up user data on
|
||||||
|
RHEVm and vSphere.
|
||||||
|
|
||||||
|
RHEVm:
|
||||||
|
======
|
||||||
|
For REHVm v3.0 the userdata is injected into the VM using floppy
|
||||||
|
injection via the RHEVm dashboard "Custom Properties". The format
|
||||||
|
of the Custom Properties entry must be:
|
||||||
|
"floppyinject=user-data.txt:<base64 encoded data>"
|
||||||
|
|
||||||
|
e.g.: To pass a simple bash script
|
||||||
|
|
||||||
|
% cat simple_script.bash
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Hello Joe!" >> /tmp/JJV_Joe_out.txt
|
||||||
|
|
||||||
|
% base64 < simple_script.bash
|
||||||
|
IyEvYmluL2Jhc2gKZWNobyAiSGVsbG8gSm9lISIgPj4gL3RtcC9KSlZfSm9lX291dC50eHQK
|
||||||
|
|
||||||
|
To pass this example script to cloud-init running in a RHEVm v3.0 VM
|
||||||
|
set the "Custom Properties" when creating the RHEMv v3.0 VM to:
|
||||||
|
floppyinject=user-data.txt:IyEvYmluL2Jhc2gKZWNobyAiSGVsbG8gSm9lISIgPj4gL3RtcC9KSlZfSm9lX291dC50eHQK
|
||||||
|
|
||||||
|
NOTE: The prefix with file name must be: "floppyinject=user-data.txt:"
|
||||||
|
|
||||||
|
It is also possible to launch a RHEVm v3.0 VM and pass optional user
|
||||||
|
data to it using the Delta Cloud.
|
||||||
|
For more inforation on Delta Cloud see: http://deltacloud.apache.org
|
||||||
|
|
||||||
|
vSphere:
|
||||||
|
========
|
||||||
|
For VMWare's vSphere the userdata is injected into the VM an ISO
|
||||||
|
via the cdrom. This can be done using the vSphere dashboard
|
||||||
|
by connecting an ISO image to the CD/DVD drive.
|
||||||
|
|
||||||
|
To pass this example script to cloud-init running in a vSphere VM
|
||||||
|
set the CD/DVD drive when creating the vSphere VM to point to an
|
||||||
|
ISO on the data store.
|
||||||
|
|
||||||
|
The ISO must contain the user data:
|
||||||
|
|
||||||
|
For example, to pass the same simple_script.bash to vSphere:
|
||||||
|
|
||||||
|
Create the ISO:
|
||||||
|
===============
|
||||||
|
% mkdir my-iso
|
||||||
|
|
||||||
|
NOTE: The file name on the ISO must be: "user-data.txt"
|
||||||
|
% cp simple_scirpt.bash my-iso/user-data.txt
|
||||||
|
|
||||||
|
% genisoimage -o user-data.iso -r my-iso
|
||||||
|
|
||||||
|
Verify the ISO:
|
||||||
|
===============
|
||||||
|
% sudo mkdir /media/vsphere_iso
|
||||||
|
% sudo mount -o loop JoeV_CI_02.iso /media/vsphere_iso
|
||||||
|
% cat /media/vsphere_iso/user-data.txt
|
||||||
|
% sudo umount /media/vsphere_iso
|
||||||
|
|
||||||
|
Then, launch the vSphere VM the ISO user-data.iso attached as a CDrom.
|
||||||
|
|
||||||
|
It is also possible to launch a vSphere VM and pass optional user
|
||||||
|
data to it using the Delta Cloud.
|
||||||
|
|
||||||
|
For more inforation on Delta Cloud see: http://deltacloud.apache.org
|
436
tests/unittests/test_datasource/test_altcloud.py
Normal file
436
tests/unittests/test_datasource/test_altcloud.py
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
# vi: ts=4 expandtab
|
||||||
|
#
|
||||||
|
# Copyright (C) 2009-2010 Canonical Ltd.
|
||||||
|
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
|
||||||
|
# Copyright (C) 2012 Yahoo! Inc.
|
||||||
|
#
|
||||||
|
# Author: Joe VLcek <JVLcek@RedHat.com>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 3, as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
'''
|
||||||
|
This test file exercises the code in sources DataSourceAltCloud.py
|
||||||
|
'''
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from unittest import TestCase
|
||||||
|
from cloudinit import helpers
|
||||||
|
|
||||||
|
# Get the cloudinit.sources.DataSourceAltCloud import items needed.
|
||||||
|
import cloudinit.sources.DataSourceAltCloud
|
||||||
|
from cloudinit.sources.DataSourceAltCloud import DataSourceAltCloud
|
||||||
|
from cloudinit.sources.DataSourceAltCloud import read_user_data_callback
|
||||||
|
|
||||||
|
def _write_cloud_info_file(value):
|
||||||
|
'''
|
||||||
|
Populate the CLOUD_INFO_FILE which would be populated
|
||||||
|
with a cloud backend identifier ImageFactory when building
|
||||||
|
an image with ImageFactory.
|
||||||
|
'''
|
||||||
|
cifile = open(cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE, 'w')
|
||||||
|
cifile.write(value)
|
||||||
|
cifile.close()
|
||||||
|
os.chmod(cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE, 0664)
|
||||||
|
|
||||||
|
def _remove_cloud_info_file():
|
||||||
|
'''
|
||||||
|
Remove the test CLOUD_INFO_FILE
|
||||||
|
'''
|
||||||
|
os.remove(cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE)
|
||||||
|
|
||||||
|
def _write_user_data_files(mount_dir, value):
|
||||||
|
'''
|
||||||
|
Populate the deltacloud_user_data_file the user_data_file
|
||||||
|
which would be populated with user data.
|
||||||
|
'''
|
||||||
|
deltacloud_user_data_file = mount_dir + '/deltacloud-user-data.txt'
|
||||||
|
user_data_file = mount_dir + '/user-data.txt'
|
||||||
|
|
||||||
|
udfile = open(deltacloud_user_data_file, 'w')
|
||||||
|
udfile.write(value)
|
||||||
|
udfile.close()
|
||||||
|
os.chmod(deltacloud_user_data_file, 0664)
|
||||||
|
|
||||||
|
udfile = open(user_data_file, 'w')
|
||||||
|
udfile.write(value)
|
||||||
|
udfile.close()
|
||||||
|
os.chmod(user_data_file, 0664)
|
||||||
|
|
||||||
|
def _remove_user_data_files(mount_dir,
|
||||||
|
dc_file=True,
|
||||||
|
non_dc_file=True):
|
||||||
|
'''
|
||||||
|
Remove the test files: deltacloud_user_data_file and
|
||||||
|
user_data_file
|
||||||
|
'''
|
||||||
|
deltacloud_user_data_file = mount_dir + '/deltacloud-user-data.txt'
|
||||||
|
user_data_file = mount_dir + '/user-data.txt'
|
||||||
|
|
||||||
|
# Ignore any failures removeing files that are already gone.
|
||||||
|
if dc_file:
|
||||||
|
try:
|
||||||
|
os.remove(deltacloud_user_data_file)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if non_dc_file:
|
||||||
|
try:
|
||||||
|
os.remove(user_data_file)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestGetCloudType(TestCase):
|
||||||
|
'''
|
||||||
|
Test to exercise method: DataSourceAltCloud.get_cloud_type()
|
||||||
|
'''
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
''' Set up '''
|
||||||
|
self.paths = helpers.Paths({ 'cloud_dir': '/tmp' })
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Reset
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['dmidecode', '--string', 'system-product-name']
|
||||||
|
|
||||||
|
def test_rhev(self):
|
||||||
|
'''
|
||||||
|
Test method get_cloud_type() for RHEVm systems.
|
||||||
|
Forcing dmidecode return to match a RHEVm system: RHEV Hypervisor
|
||||||
|
'''
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['echo', 'RHEV Hypervisor']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
self.assertEquals('RHEV', \
|
||||||
|
dsrc.get_cloud_type())
|
||||||
|
|
||||||
|
def test_vsphere(self):
|
||||||
|
'''
|
||||||
|
Test method get_cloud_type() for vSphere systems.
|
||||||
|
Forcing dmidecode return to match a vSphere system: RHEV Hypervisor
|
||||||
|
'''
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['echo', 'VMware Virtual Platform']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
self.assertEquals('VSPHERE', \
|
||||||
|
dsrc.get_cloud_type())
|
||||||
|
|
||||||
|
def test_unknown(self):
|
||||||
|
'''
|
||||||
|
Test method get_cloud_type() for unknown systems.
|
||||||
|
Forcing dmidecode return to match an unrecognized return.
|
||||||
|
'''
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['echo', 'Unrecognized Platform']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
self.assertEquals('UNKNOWN', \
|
||||||
|
dsrc.get_cloud_type())
|
||||||
|
|
||||||
|
def test_exception1(self):
|
||||||
|
'''
|
||||||
|
Test method get_cloud_type() where command dmidecode fails.
|
||||||
|
'''
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['ls', 'bad command']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
self.assertEquals('UNKNOWN', \
|
||||||
|
dsrc.get_cloud_type())
|
||||||
|
|
||||||
|
def test_exception2(self):
|
||||||
|
'''
|
||||||
|
Test method get_cloud_type() where command dmidecode is not available.
|
||||||
|
'''
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['bad command']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
self.assertEquals('UNKNOWN', \
|
||||||
|
dsrc.get_cloud_type())
|
||||||
|
|
||||||
|
class TestGetDataCloudInfoFile(TestCase):
|
||||||
|
'''
|
||||||
|
Test to exercise method: DataSourceAltCloud.get_data()
|
||||||
|
With a contrived CLOUD_INFO_FILE
|
||||||
|
'''
|
||||||
|
def setUp(self):
|
||||||
|
''' Set up '''
|
||||||
|
self.paths = helpers.Paths({ 'cloud_dir': '/tmp' })
|
||||||
|
self.cloud_info_file = tempfile.mkstemp()[1]
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE = \
|
||||||
|
self.cloud_info_file
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Reset
|
||||||
|
|
||||||
|
# Attempt to remove the temp file ignoring errors
|
||||||
|
try:
|
||||||
|
os.remove(self.cloud_info_file)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE = \
|
||||||
|
'/etc/sysconfig/cloud-info'
|
||||||
|
|
||||||
|
def test_rhev(self):
|
||||||
|
'''Success Test module get_data() forcing RHEV '''
|
||||||
|
|
||||||
|
_write_cloud_info_file('RHEV')
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
dsrc.user_data_rhevm = lambda : True
|
||||||
|
self.assertEquals(True, dsrc.get_data())
|
||||||
|
|
||||||
|
def test_vsphere(self):
|
||||||
|
'''Success Test module get_data() forcing VSPHERE '''
|
||||||
|
|
||||||
|
_write_cloud_info_file('VSPHERE')
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
dsrc.user_data_vsphere = lambda : True
|
||||||
|
self.assertEquals(True, dsrc.get_data())
|
||||||
|
|
||||||
|
def test_fail_rhev(self):
|
||||||
|
'''Failure Test module get_data() forcing RHEV '''
|
||||||
|
|
||||||
|
_write_cloud_info_file('RHEV')
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
dsrc.user_data_rhevm = lambda : False
|
||||||
|
self.assertEquals(False, dsrc.get_data())
|
||||||
|
|
||||||
|
def test_fail_vsphere(self):
|
||||||
|
'''Failure Test module get_data() forcing VSPHERE '''
|
||||||
|
|
||||||
|
_write_cloud_info_file('VSPHERE')
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
dsrc.user_data_vsphere = lambda : False
|
||||||
|
self.assertEquals(False, dsrc.get_data())
|
||||||
|
|
||||||
|
def test_unrecognized(self):
|
||||||
|
'''Failure Test module get_data() forcing unrecognized '''
|
||||||
|
|
||||||
|
_write_cloud_info_file('unrecognized')
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
self.assertEquals(False, dsrc.get_data())
|
||||||
|
|
||||||
|
class TestGetDataNoCloudInfoFile(TestCase):
|
||||||
|
'''
|
||||||
|
Test to exercise method: DataSourceAltCloud.get_data()
|
||||||
|
Without a CLOUD_INFO_FILE
|
||||||
|
'''
|
||||||
|
def setUp(self):
|
||||||
|
''' Set up '''
|
||||||
|
self.paths = helpers.Paths({ 'cloud_dir': '/tmp' })
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE = \
|
||||||
|
'no such file'
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Reset
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE = \
|
||||||
|
'/etc/sysconfig/cloud-info'
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['dmidecode', '--string', 'system-product-name']
|
||||||
|
|
||||||
|
def test_rhev_no_cloud_file(self):
|
||||||
|
'''Test No cloud info file module get_data() forcing RHEV '''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['echo', 'RHEV Hypervisor']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
dsrc.user_data_rhevm = lambda : True
|
||||||
|
self.assertEquals(True, dsrc.get_data())
|
||||||
|
|
||||||
|
def test_vsphere_no_cloud_file(self):
|
||||||
|
'''Test No cloud info file module get_data() forcing VSPHERE '''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['echo', 'VMware Virtual Platform']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
dsrc.user_data_vsphere = lambda : True
|
||||||
|
self.assertEquals(True, dsrc.get_data())
|
||||||
|
|
||||||
|
def test_failure_no_cloud_file(self):
|
||||||
|
'''Test No cloud info file module get_data() forcing unrecognized '''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_DMI_SYSTEM = \
|
||||||
|
['echo', 'Unrecognized Platform']
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
self.assertEquals(False, dsrc.get_data())
|
||||||
|
|
||||||
|
class TestUserDataRhevm(TestCase):
|
||||||
|
'''
|
||||||
|
Test to exercise method: DataSourceAltCloud.user_data_rhevm()
|
||||||
|
'''
|
||||||
|
def setUp(self):
|
||||||
|
''' Set up '''
|
||||||
|
self.paths = helpers.Paths({ 'cloud_dir': '/tmp' })
|
||||||
|
self.mount_dir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
_write_user_data_files(self.mount_dir, 'test user data')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Reset
|
||||||
|
|
||||||
|
_remove_user_data_files(self.mount_dir)
|
||||||
|
|
||||||
|
# Attempt to remove the temp dir ignoring errors
|
||||||
|
try:
|
||||||
|
shutil.rmtree(self.mount_dir)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE = \
|
||||||
|
'/etc/sysconfig/cloud-info'
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_PROBE_FLOPPY = \
|
||||||
|
['/sbin/modprobe', 'floppy']
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_UDEVADM_SETTLE = \
|
||||||
|
['/sbin/udevadm', 'settle', '--quiet', '--timeout=5']
|
||||||
|
|
||||||
|
def test_mount_cb_fails(self):
|
||||||
|
'''Test user_data_rhevm() where mount_cb fails'''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_PROBE_FLOPPY = \
|
||||||
|
['echo', 'modprobe floppy']
|
||||||
|
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
|
||||||
|
self.assertEquals(False, dsrc.user_data_rhevm())
|
||||||
|
|
||||||
|
def test_modprobe_fails(self):
|
||||||
|
'''Test user_data_rhevm() where modprobe fails. '''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_PROBE_FLOPPY = \
|
||||||
|
['ls', 'modprobe floppy']
|
||||||
|
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
|
||||||
|
self.assertEquals(False, dsrc.user_data_rhevm())
|
||||||
|
|
||||||
|
def test_no_modprobe_cmd(self):
|
||||||
|
'''Test user_data_rhevm() with no modprobe command. '''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_PROBE_FLOPPY = \
|
||||||
|
['bad command', 'modprobe floppy']
|
||||||
|
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
|
||||||
|
self.assertEquals(False, dsrc.user_data_rhevm())
|
||||||
|
|
||||||
|
def test_udevadm_fails(self):
|
||||||
|
'''Test user_data_rhevm() where udevadm fails. '''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_UDEVADM_SETTLE = \
|
||||||
|
['ls', 'udevadm floppy']
|
||||||
|
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
|
||||||
|
self.assertEquals(False, dsrc.user_data_rhevm())
|
||||||
|
|
||||||
|
def test_no_udevadm_cmd(self):
|
||||||
|
'''Test user_data_rhevm() with no udevadm command. '''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CMD_UDEVADM_SETTLE = \
|
||||||
|
['bad command', 'udevadm floppy']
|
||||||
|
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
|
||||||
|
self.assertEquals(False, dsrc.user_data_rhevm())
|
||||||
|
|
||||||
|
class TestUserDataVsphere(TestCase):
|
||||||
|
'''
|
||||||
|
Test to exercise method: DataSourceAltCloud.user_data_vsphere()
|
||||||
|
'''
|
||||||
|
def setUp(self):
|
||||||
|
''' Set up '''
|
||||||
|
self.paths = helpers.Paths({ 'cloud_dir': '/tmp' })
|
||||||
|
self.mount_dir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
_write_user_data_files(self.mount_dir, 'test user data')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Reset
|
||||||
|
|
||||||
|
_remove_user_data_files(self.mount_dir)
|
||||||
|
|
||||||
|
# Attempt to remove the temp dir ignoring errors
|
||||||
|
try:
|
||||||
|
shutil.rmtree(self.mount_dir)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.CLOUD_INFO_FILE = \
|
||||||
|
'/etc/sysconfig/cloud-info'
|
||||||
|
|
||||||
|
def test_user_data_vsphere(self):
|
||||||
|
'''Test user_data_vsphere() where mount_cb fails'''
|
||||||
|
|
||||||
|
cloudinit.sources.DataSourceAltCloud.MEDIA_DIR = self.mount_dir
|
||||||
|
|
||||||
|
dsrc = DataSourceAltCloud({}, None, self.paths)
|
||||||
|
|
||||||
|
self.assertEquals(False, dsrc.user_data_vsphere())
|
||||||
|
|
||||||
|
class TestReadUserDataCallback(TestCase):
|
||||||
|
'''
|
||||||
|
Test to exercise method: DataSourceAltCloud.read_user_data_callback()
|
||||||
|
'''
|
||||||
|
def setUp(self):
|
||||||
|
''' Set up '''
|
||||||
|
self.paths = helpers.Paths({ 'cloud_dir': '/tmp' })
|
||||||
|
self.mount_dir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
_write_user_data_files(self.mount_dir, 'test user data')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Reset
|
||||||
|
|
||||||
|
_remove_user_data_files(self.mount_dir)
|
||||||
|
|
||||||
|
# Attempt to remove the temp dir ignoring errors
|
||||||
|
try:
|
||||||
|
shutil.rmtree(self.mount_dir)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_both(self):
|
||||||
|
'''Test read_user_data_callback() with both files'''
|
||||||
|
|
||||||
|
self.assertEquals('test user data',
|
||||||
|
read_user_data_callback(self.mount_dir))
|
||||||
|
|
||||||
|
def test_callback_dc(self):
|
||||||
|
'''Test read_user_data_callback() with only DC file'''
|
||||||
|
|
||||||
|
_remove_user_data_files(self.mount_dir,
|
||||||
|
dc_file=False,
|
||||||
|
non_dc_file=True)
|
||||||
|
|
||||||
|
self.assertEquals('test user data',
|
||||||
|
read_user_data_callback(self.mount_dir))
|
||||||
|
|
||||||
|
def test_callback_non_dc(self):
|
||||||
|
'''Test read_user_data_callback() with only non-DC file'''
|
||||||
|
|
||||||
|
_remove_user_data_files(self.mount_dir,
|
||||||
|
dc_file=True,
|
||||||
|
non_dc_file=False)
|
||||||
|
|
||||||
|
self.assertEquals('test user data',
|
||||||
|
read_user_data_callback(self.mount_dir))
|
||||||
|
|
||||||
|
def test_callback_none(self):
|
||||||
|
'''Test read_user_data_callback() no files are found'''
|
||||||
|
|
||||||
|
_remove_user_data_files(self.mount_dir)
|
||||||
|
self.assertEquals(None, read_user_data_callback(self.mount_dir))
|
||||||
|
|
||||||
|
# vi: ts=4 expandtab
|
Loading…
x
Reference in New Issue
Block a user