3
# Copyright (C) 2009-2010 Canonical Ltd.
4
# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P.
5
# Copyright (C) 2012 Yahoo! Inc.
7
# Author: Joe VLcek <JVLcek@RedHat.com>
8
# Author: Juerg Haefliger <juerg.haefliger@hp.com>
10
# This program is free software: you can redistribute it and/or modify
11
# it under the terms of the GNU General Public License version 3, as
12
# published by the Free Software Foundation.
14
# This program is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
19
# You should have received a copy of the GNU General Public License
20
# along with this program. If not, see <http://www.gnu.org/licenses/>.
23
This file contains code used to gather the user data passed to an
24
instance on RHEVm and vSphere.
31
from cloudinit import log as logging
32
from cloudinit import sources
33
from cloudinit import util
35
from cloudinit.util import ProcessExecutionError
37
LOG = logging.getLogger(__name__)
40
CLOUD_INFO_FILE = '/etc/sysconfig/cloud-info'
43
CMD_PROBE_FLOPPY = ['/sbin/modprobe', 'floppy']
44
CMD_UDEVADM_SETTLE = ['/sbin/udevadm', 'settle', '--timeout=5']
46
META_DATA_NOT_SUPPORTED = {
47
'block-device-mapping': {},
49
'local-hostname': 'localhost',
54
def read_user_data_callback(mount_dir):
57
This callback will be applied by util.mount_cb() on the mounted
60
Deltacloud file name contains deltacloud. Those not using
61
Deltacloud but instead instrumenting the injection, could
62
drop deltacloud from the file name.
65
mount_dir - Mount directory
72
deltacloud_user_data_file = mount_dir + '/deltacloud-user-data.txt'
73
user_data_file = mount_dir + '/user-data.txt'
75
# First try deltacloud_user_data_file. On failure try user_data_file.
77
user_data = util.load_file(deltacloud_user_data_file).strip()
80
user_data = util.load_file(user_data_file).strip()
82
util.logexc(LOG, 'Failed accessing user data file.')
88
class DataSourceAltCloud(sources.DataSource):
89
def __init__(self, sys_cfg, distro, paths):
90
sources.DataSource.__init__(self, sys_cfg, distro, paths)
92
self.supported_seed_starts = ("/", "file://")
95
root = sources.DataSource.__str__(self)
96
return "%s [seed=%s]" % (root, self.seed)
98
def get_cloud_type(self):
101
Get the type for the cloud back end this instance is running on
102
by examining the string returned by reading the dmi data.
108
One of the following strings:
109
'RHEV', 'VSPHERE' or 'UNKNOWN'
113
uname_arch = os.uname()[4]
114
if uname_arch.startswith("arm") or uname_arch == "aarch64":
115
# Disabling because dmi data is not available on ARM processors
116
LOG.debug("Disabling AltCloud datasource on arm (LP: #1243287)")
119
system_name = util.read_dmi_data("system-product-name")
123
sys_name = system_name.upper()
125
if sys_name.startswith('RHEV'):
128
if sys_name.startswith('VMWARE'):
136
User Data is passed to the launching instance which
137
is used to perform instance configuration.
139
Cloud providers expose the user data differently.
140
It is necessary to determine which cloud provider
141
the current instance is running on to determine
142
how to access the user data. Images built with
143
image factory will contain a CLOUD_INFO_FILE which
144
contains a string identifying the cloud provider.
146
Images not built with Imagefactory will try to
147
determine what the cloud provider is based on system
151
LOG.debug('Invoked get_data()')
153
if os.path.exists(CLOUD_INFO_FILE):
155
cloud_type = util.load_file(CLOUD_INFO_FILE).strip().upper()
157
util.logexc(LOG, 'Unable to access cloud info file at %s.',
161
cloud_type = self.get_cloud_type()
163
LOG.debug('cloud_type: ' + str(cloud_type))
165
if 'RHEV' in cloud_type:
166
if self.user_data_rhevm():
168
elif 'VSPHERE' in cloud_type:
169
if self.user_data_vsphere():
172
# there was no recognized alternate cloud type
173
# indicating this handler should not be used.
177
util.logexc(LOG, 'Failed accessing user data.')
180
def user_data_rhevm(self):
182
RHEVM specific userdata read
184
If on RHEV-M the user data will be contained on the
185
floppy device in file <user_data_file>
189
Leverage util.mount_cb to:
190
mkdir <tmp mount dir>
191
mount /dev/fd0 <tmp mount dir>
192
The call back passed to util.mount_cb will do:
193
read <tmp mount dir>/<user_data_file>
200
cmd = CMD_PROBE_FLOPPY
201
(cmd_out, _err) = util.subp(cmd)
202
LOG.debug(('Command: %s\nOutput%s') % (' '.join(cmd), cmd_out))
203
except ProcessExecutionError as _err:
204
util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd),
207
except OSError as _err:
208
util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd), _err)
211
floppy_dev = '/dev/fd0'
213
# udevadm settle for floppy device
215
cmd = CMD_UDEVADM_SETTLE
216
cmd.append('--exit-if-exists=' + floppy_dev)
217
(cmd_out, _err) = util.subp(cmd)
218
LOG.debug(('Command: %s\nOutput%s') % (' '.join(cmd), cmd_out))
219
except ProcessExecutionError as _err:
220
util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd),
223
except OSError as _err:
224
util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd),
229
return_str = util.mount_cb(floppy_dev, read_user_data_callback)
230
except OSError as err:
231
if err.errno != errno.ENOENT:
233
except util.MountFailedError:
234
util.logexc(LOG, "Failed to mount %s when looking for user data",
237
self.userdata_raw = return_str
238
self.metadata = META_DATA_NOT_SUPPORTED
245
def user_data_vsphere(self):
247
vSphere specific userdata read
249
If on vSphere the user data will be contained on the
250
cdrom device in file <user_data_file>
252
Leverage util.mount_cb to:
253
mkdir <tmp mount dir>
254
mount /dev/fd0 <tmp mount dir>
255
The call back passed to util.mount_cb will do:
256
read <tmp mount dir>/<user_data_file>
260
cdrom_list = util.find_devs_with('LABEL=CDROM')
261
for cdrom_dev in cdrom_list:
263
return_str = util.mount_cb(cdrom_dev, read_user_data_callback)
266
except OSError as err:
267
if err.errno != errno.ENOENT:
269
except util.MountFailedError:
270
util.logexc(LOG, "Failed to mount %s when looking for user "
273
self.userdata_raw = return_str
274
self.metadata = META_DATA_NOT_SUPPORTED
281
# Used to match classes to dependencies
282
# Source DataSourceAltCloud does not really depend on networking.
283
# In the future 'dsmode' like behavior can be added to offer user
284
# the ability to run before networking.
286
(DataSourceAltCloud, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
290
# Return a list of data sources that match this set of dependencies
291
def get_datasource_list(depends):
292
return sources.list_from_depends(depends, datasources)