Fixes for the MP.

Changed cc_disk_setup to handle the file systems as a label, no longer
passing "log" around.

Tidied up the documentation to reflect the changes and made grammer,
spelling and improved the content a little.

Added disk_setup to the default modules list.
This commit is contained in:
Ben Howard 2013-09-19 16:49:50 -06:00
parent bd183cb716
commit fd572349e4
6 changed files with 317 additions and 173 deletions

View File

@ -18,14 +18,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from cloudinit import util
from cloudinit.settings import PER_INSTANCE
import re
import traceback
import logging
import shlex
frequency = PER_INSTANCE
virtal_devices = ["ephemeral0", "swap"]
defmnts = ["ephemeral0", "swap"]
# Define the commands to use
UDEVADM_CMD = util.which('udevadm')
SFDISK_CMD = util.which("sfdisk")
@ -33,46 +30,47 @@ LSBLK_CMD = util.which("lsblk")
BLKID_CMD = util.which("blkid")
BLKDEV_CMD = util.which("blockdev")
LOG = logging.getLogger(__name__)
def handle(_name, cfg, cloud, log, _args):
"""
Call util.prep_disk for disk_setup cloud-config.
The format is:
disk_setup:
ephmeral0: {type='mbr', layout='True', overwrite='False'}
/dev/xvdj: {type='None'}
/dev/xvdh: {type='mbr', layout:[(33,83),66], overwrite='True'}
fs_setup:
ephemeral0: {filesystem='ext3', device='ephemeral0', partition='auto'}
mylabel2: {filesystem='ext3', device='/dev/xvda1', partition='None'}
special1: {cmd="mkfs -t %(FILESYSTEM)s -L %(LABEL)s %(DEVICE)s", filesystem='btrfs', device='/dev/xvda1'}
See doc/examples/cloud-config_disk-setup.txt for documentation on the
format.
"""
disk_setup = cfg.get("disk_setup")
if isinstance(disk_setup, dict):
log.info("Partitioning disks.")
for disk, definition in disk_setup.items():
if not isinstance(definition, dict):
log.debug("Invalid disk definition for %s" % disk)
log.warn("Invalid disk definition for %s" % disk)
continue
util.log_time(logfunc=log.info,
try:
log.debug("Creating new partition table/disk")
util.log_time(logfunc=LOG.debug,
msg="Creating partition on %s" % disk,
func=mkpart, args=(disk, cloud, definition, log))
func=mkpart, args=(disk, cloud, definition))
except Exception as e:
util.logexc(LOG, "Failed partitioning operation\n%s" % e)
fs_setup = cfg.get("fs_setup")
if isinstance(fs_setup, dict):
log.info("Setting up filesystems")
for label, definition in fs_setup.items():
if isinstance(fs_setup, list):
log.info("Creating file systems.")
for definition in fs_setup:
if not isinstance(definition, dict):
log.debug("Invalid filesystem definition for %s" % label)
log.warn("Invalid file system definition: %s" % definition)
continue
util.log_time(logfunc=log.debug, msg="Creating fs for %s" % label,
func=mkfs, args=(label, cloud, definition, log))
try:
log.debug("Creating new filesystem.")
device = definition.get('device')
util.log_time(logfunc=LOG.debug,
msg="Creating fs for %s" % device,
func=mkfs, args=(cloud, definition))
except Exception as e:
util.logexc(LOG, "Failed during filesystem operation\n%s" % e)
def is_default_device(name, cloud, fallback=None):
@ -82,10 +80,11 @@ def is_default_device(name, cloud, fallback=None):
fallback if so defined.
"""
_dev = None
try:
_dev = cloud.device_name_to_device(name)
except Exception as e:
print e
util.logexc(LOG, "Failed to find mapping for %s" % e)
if _dev:
return _dev
@ -96,34 +95,19 @@ def is_default_device(name, cloud, fallback=None):
return name
def check_value(key, dct, default=None):
"""
Convience function for getting value out of a dict.
"""
if key in dct:
return dct[key]
if default:
return default
return None
def value_splitter(values, start=None):
"""
Returns the key/value pairs of output sent as string
like: FOO='BAR' HOME='127.0.0.1'
"""
_values = values.split()
_values = shlex.split(values)
if start:
_values = _values[start:]
for key, value in [x.split('=') for x in _values]:
if value == '""':
value = None
elif '"' in value:
value = value.replace('"','')
yield key, value
def device_type(device):
"""
Return the device type of the device by calling lsblk.
@ -148,7 +132,13 @@ def is_device_valid(name, partition=False):
"""
Check if the device is a valid device.
"""
d_type = ""
try:
d_type = device_type(name)
except:
LOG.warn("Query against device %s failed" % name)
return False
if partition and d_type == 'part':
return True
elif not partition and d_type == 'disk':
@ -171,7 +161,6 @@ def check_fs(device):
try:
out, _err = util.subp(blkid_cmd, rcs=[0, 2])
except Exception as e:
util.logexc(e)
raise Exception("Failed during disk check for %s\n%s" % (device, e))
if out:
@ -195,7 +184,8 @@ def is_filesystem(device):
return fs_type
def find_device_node(device, fs_type=None, label=None, valid_targets=None):
def find_device_node(device, fs_type=None, label=None, valid_targets=None,
label_match=True):
"""
Find a device that is either matches the spec, or the first
@ -208,7 +198,8 @@ def find_device_node(device, fs_type=None, label=None, valid_targets=None):
if not valid_targets:
valid_targets = ['disk', 'part']
lsblk_cmd = [LSBLK_CMD, '--pairs', '--out', 'NAME,TYPE,FSTYPE,LABEL', device]
lsblk_cmd = [LSBLK_CMD, '--pairs', '--out', 'NAME,TYPE,FSTYPE,LABEL',
device]
info = None
try:
info, _err = util.subp(lsblk_cmd)
@ -228,7 +219,8 @@ def find_device_node(device, fs_type=None, label=None, valid_targets=None):
for key, value in value_splitter(part):
d[key.lower()] = value
if d['fstype'] == fs_type and d['label'] == label:
if d['fstype'] == fs_type and \
((label_match and d['label'] == label) or not label_match):
# If we find a matching device, we return that
return ('/dev/%s' % d['name'], True)
@ -247,6 +239,7 @@ def find_device_node(device, fs_type=None, label=None, valid_targets=None):
if not raw_device_used:
return (device, False)
LOG.warn("Failed to find device during available device search.")
return (None, False)
@ -262,6 +255,8 @@ def is_disk_used(device):
info, _err = util.subp(lsblk_cmd)
except Exception as e:
# if we error out, we can't use the device
util.logexc(LOG,
"Error checking for filesystem on %s\n%s" % (device, e))
return True
# If there is any output, then the device has something
@ -313,6 +308,7 @@ def get_dyn_func(*args):
except KeyError:
raise Exception("No such function %s to call!" % func_name)
def check_partition_mbr_layout(device, layout):
"""
Returns true if the partition layout matches the one on the disk
@ -455,10 +451,13 @@ def read_parttbl(device):
reliable way to probe the partition table.
"""
blkdev_cmd = [BLKDEV_CMD, '--rereadpt', device]
udev_cmd = [UDEVADM_CMD, 'settle']
try:
util.subp(udev_cmd)
util.subp(blkdev_cmd)
util.subp(udev_cmd)
except Exception as e:
raise Exception("Failed on call to partprobe\n%s" % e)
util.logexc(LOG, "Failed reading the partition table %s" % e)
def exec_mkpart_mbr(device, layout):
@ -475,6 +474,7 @@ def exec_mkpart_mbr(device, layout):
read_parttbl(device)
def exec_mkpart(table_type, device, layout):
"""
Fetches the function for creating the table type.
@ -488,7 +488,7 @@ def exec_mkpart(table_type, device, layout):
return get_dyn_func("exec_mkpart_%s", table_type, device, layout)
def mkpart(device, cloud, definition, log):
def mkpart(device, cloud, definition):
"""
Creates the partition table.
@ -504,14 +504,14 @@ def mkpart(device, cloud, definition, log):
device: the device to work on.
"""
log.debug("Checking values for %s definition" % device)
overwrite = check_value('overwrite', definition, False)
layout = check_value('layout', definition, False)
table_type = check_value('type', definition, 'mbr')
LOG.debug("Checking values for %s definition" % device)
overwrite = definition.get('overwrite', False)
layout = definition.get('layout', False)
table_type = definition.get('table_type', 'mbr')
_device = is_default_device(device, cloud)
# Check if the default device is a partition or not
log.debug("Checking against default devices")
LOG.debug("Checking against default devices")
if _device and (_device != device):
if not is_device_valid(_device):
_device = _device[:-1]
@ -519,40 +519,43 @@ def mkpart(device, cloud, definition, log):
if not is_device_valid(_device):
raise Exception("Unable to find backing block device for %s" % \
device)
else:
LOG.debug("Mapped %s to physical device %s" % (device, _device))
device = _device
if (isinstance(layout, bool) and not layout) or not layout:
log.debug("Device is not to be partitioned, skipping")
LOG.debug("Device is not to be partitioned, skipping")
return # Device is not to be partitioned
# This prevents you from overwriting the device
log.debug("Checking if device %s is a valid device" % device)
LOG.debug("Checking if device %s is a valid device" % device)
if not is_device_valid(device):
raise Exception("Device %s is not a disk device!" % device)
log.debug("Checking if device layout matches")
LOG.debug("Checking if device layout matches")
if check_partition_layout(table_type, device, layout):
log.debug("Device partitioning layout matches")
LOG.debug("Device partitioning layout matches")
return True
log.debug("Checking if device is safe to partition")
LOG.debug("Checking if device is safe to partition")
if not overwrite and (is_disk_used(device) or is_filesystem(device)):
log.debug("Skipping partitioning on configured device %s" % device)
LOG.debug("Skipping partitioning on configured device %s" % device)
return
log.debug("Checking for device size")
LOG.debug("Checking for device size")
device_size = get_hdd_size(device)
log.debug("Calculating partition layout")
LOG.debug("Calculating partition layout")
part_definition = get_partition_layout(table_type, device_size, layout)
log.debug(" Layout is: %s" % part_definition)
LOG.debug(" Layout is: %s" % part_definition)
log.debug("Creating partition table on %s" % device)
LOG.debug("Creating partition table on %s" % device)
exec_mkpart(table_type, device, part_definition)
log.debug("Partition table created for %s" % device)
LOG.debug("Partition table created for %s" % device)
def mkfs(label, cloud, fs_cfg, log):
def mkfs(cloud, fs_cfg):
"""
Create a file system on the device.
@ -568,67 +571,93 @@ def mkfs(label, cloud, fs_cfg, log):
first free device or the first device which
matches both label and type will be used.
'any' means the first filesystem that matches
on the device.
When 'cmd' is provided then no other parameter is required.
"""
device = check_value('device', fs_cfg)
partition = str(check_value('partition', fs_cfg))
fs_type = check_value('filesystem', fs_cfg)
fs_cmd = check_value('cmd', fs_cfg, [])
fs_opts = check_value('extra_opts', fs_cfg, [])
overwrite = check_value('overwrite', fs_cfg, False)
fs_cfg['partition'] = 'any'
label = fs_cfg.get('label')
device = fs_cfg.get('device')
partition = str(fs_cfg.get('partition'))
fs_type = fs_cfg.get('filesystem')
fs_cmd = fs_cfg.get('cmd', [])
fs_opts = fs_cfg.get('extra_opts', [])
overwrite = fs_cfg.get('overwrite', False)
# This allows you to define the default ephemeral or swap
log.debug("Checking %s label against default devices" % label)
device = is_default_device(label, cloud, fallback=device)
LOG.debug("Checking %s against default devices" % device)
_device = is_default_device(label, cloud, fallback=device)
if _device and (_device != device):
if not is_device_valid(_device):
raise Exception("Unable to find backing block device for %s" % \
device)
else:
LOG.debug("Mapped %s to physical device %s" % (device, _device))
device = _device
if not partition or partition.isdigit():
# Handle manual definition of partition
if partition.isdigit():
device = "%s%s" % (device, partition)
log.debug("Manual request of partition %s for %s" % (
LOG.debug("Manual request of partition %s for %s" % (
partition, device))
# Check to see if the fs already exists
log.debug("Checking device %s" % device)
LOG.debug("Checking device %s" % device)
check_label, check_fstype, _ = check_fs(device)
log.debug("Device %s has %s %s" % (device, check_label, check_fstype))
LOG.debug("Device %s has %s %s" % (device, check_label, check_fstype))
if check_label == label and check_fstype == fs_type:
log.debug("Existing file system found at %s" % device)
LOG.debug("Existing file system found at %s" % device)
if not overwrite:
log.debug("Device %s has required file system" % device)
LOG.warn("Device %s has required file system" % device)
return
else:
log.debug("Destroying filesystem on %s" % device)
LOG.warn("Destroying filesystem on %s" % device)
else:
log.debug("Device %s is cleared for formating" % device)
LOG.debug("Device %s is cleared for formating" % device)
elif partition and partition == 'auto':
elif partition and str(partition).lower() in ('auto', 'any'):
# For auto devices, we match if the filesystem does exist
log.debug("Identifying device to create %s filesytem on" % label)
device, reuse = find_device_node(device, fs_type=fs_type, label=label)
log.debug("Device identified as %s" % device)
odevice = device
LOG.debug("Identifying device to create %s filesytem on" % label)
# any mean pick the first match on the device with matching fs_type
label_match = True
if partition.lower() == 'any':
label_match = False
device, reuse = find_device_node(device, fs_type=fs_type, label=label,
label_match=label_match)
LOG.debug("Automatic device for %s identified as %s" % (
odevice, device))
if reuse:
log.debug("Found filesystem match, skipping formating.")
LOG.debug("Found filesystem match, skipping formating.")
return
if not device:
LOG.debug("No device aviable that matches request.")
LOG.debug("Skipping fs creation for %s" % fs_cfg)
return
else:
log.debug("Error in device identification handling.")
LOG.debug("Error in device identification handling.")
return
log.debug("File system %s will be created on %s" % (label, device))
LOG.debug("File system %s will be created on %s" % (label, device))
# Make sure the device is defined
if not device:
raise Exception("Device identification error for %s" % label)
LOG.critical("Device is not known: %s" % fs_cfg)
return
# Check that we can create the FS
if not label or not fs_type:
log.debug("Command to create filesystem %s is bad. Skipping." % \
LOG.debug("Command to create filesystem %s is bad. Skipping." % \
label)
# Create the commands
@ -638,22 +667,26 @@ def mkfs(label, cloud, fs_cfg, log):
'device': device,
}
else:
# Find the mkfs command
mkfs_cmd = util.which("mkfs.%s" % fs_type)
if not mkfs_cmd:
mkfs_cmd = util.which("mk%s" % fs_type)
if not mkfs_cmd:
log.debug("Unable to locate command to create filesystem.")
LOG.critical("Unable to locate command to create filesystem.")
return
fs_cmd = [mkfs_cmd, "-L", label, device]
fs_cmd = [mkfs_cmd, device]
if label:
fs_cmd.extend(["-L", label])
# Add the extends FS options
if fs_opts:
fs_cmd.extend(fs_opts)
log.debug("Creating file system %s on %s" % (label, device))
print fs_cmd
LOG.debug("Creating file system %s on %s" % (label, device))
LOG.debug(" Using cmd: %s" % "".join(fs_cmd))
try:
util.subp(fs_cmd)
except Exception as e:

View File

@ -35,8 +35,7 @@ import os
import os.path
import serial
DEF_TTY_LOC = '/dev/ttyS1'
DEF_TTY_TIMEOUT = 60
LOG = logging.getLogger(__name__)
SMARTOS_ATTRIB_MAP = {
@ -49,24 +48,61 @@ SMARTOS_ATTRIB_MAP = {
'motd_sys_info': ('motd_sys_info', True),
}
# These are values which will never be base64 encoded.
# They come from the cloud platform, not user
SMARTOS_NO_BASE64 = ['root_authorized_keys', 'motd_sys_info',
'iptables_disable']
DS_NAME = 'SmartOS'
DS_CFG_PATH = ['datasource', DS_NAME]
# BUILT-IN DATASOURCE CONFIGURATION
# The following is the built-in configuration. If the values
# are not set via the system configuration, then these default
# will be used:
# serial_device: which serial device to use for the meta-data
# seed_timeout: how long to wait on the device
# no_base64_decode: values which are not base64 encoded and
# are fetched directly from SmartOS, not meta-data values
# base64_keys: meta-data keys that are delivered in base64
# base64_all: with the exclusion of no_base64_decode values,
# treat all meta-data as base64 encoded
# disk_setup: describes how to partition the ephemeral drive
# fs_setup: describes how to format the ephemeral drive
#
BUILTIN_DS_CONFIG = {
'serial_device': '/dev/ttyS1',
'seed_timeout': 60,
'no_base64_decode': ['root_authorized_keys',
'motd_sys_info',
'iptables_disable'],
'base64_keys': [],
'base64_all': False,
'ephemeral_disk': '/dev/vdb',
'disk_setup': {
'ephemeral0': {'table_type': 'mbr',
'layout': True,
'overwrite': False}
},
'fs_setup': [{'label': 'ephemeral0', 'filesystem': 'ext3',
'device': '/dev/xvdb', 'partition': 'auto'}],
}
class DataSourceSmartOS(sources.DataSource):
def __init__(self, sys_cfg, distro, paths):
sources.DataSource.__init__(self, sys_cfg, distro, paths)
self.seed_dir = os.path.join(paths.seed_dir, 'sdc')
self.is_smartdc = None
self.seed = self.ds_cfg.get("serial_device", DEF_TTY_LOC)
self.seed_timeout = self.ds_cfg.get("serial_timeout", DEF_TTY_TIMEOUT)
self.smartos_no_base64 = self.ds_cfg.get('no_base64_decode',
SMARTOS_NO_BASE64)
self.b64_keys = self.ds_cfg.get('base64_keys', [])
self.b64_all = self.ds_cfg.get('base64_all', False)
self.ds_cfg = util.mergemanydict([
self.ds_cfg,
util.get_cfg_by_path(sys_cfg, DS_CFG_PATH, {}),
BUILTIN_DS_CONFIG])
self.metadata = {}
self.cfg = {}
self.cfg['disk_setup'] = self.ds_cfg.get('disk_setup')
self.cfg['fs_setup'] = self.ds_cfg.get('fs_setup')
self.seed = self.ds_cfg.get("serial_device")
self.seed_timeout = self.ds_cfg.get("serial_timeout")
self.smartos_no_base64 = self.ds_cfg.get('no_base64_decode')
self.b64_keys = self.ds_cfg.get('base64_keys')
self.b64_all = self.ds_cfg.get('base64_all')
def __str__(self):
root = sources.DataSource.__str__(self)
@ -79,7 +115,6 @@ class DataSourceSmartOS(sources.DataSource):
if not os.path.exists(self.seed):
LOG.debug("Host does not appear to be on SmartOS")
return False
self.seed = self.seed
dmi_info = dmi_data()
if dmi_info is False:
@ -114,10 +149,17 @@ class DataSourceSmartOS(sources.DataSource):
elif md['user-script']:
ud = md['user-script']
self.metadata = md
self.metadata = util.mergemanydict([md, self.metadata])
self.userdata_raw = ud
return True
def device_name_to_device(self, name):
if 'ephemeral0' in name:
return self.ds_cfg['ephemeral_disk']
def get_config_obj(self):
return self.cfg
def get_instance_id(self):
return self.metadata['instance-id']

View File

@ -14,20 +14,6 @@ disable_root: true
# This will cause the set+update hostname module to not operate (if true)
preserve_hostname: false
# This sets the default for creating the ephemeral0 on clouds
# that support it.
disk_setup:
ephemeral0
type: 'mbr'
layout: True
overwrite: False
fs_setup:
ephemeral0
filesystem: 'ext3'
device: ephemeral0
partition: 'auto'
# Example datasource config
# datasource:
# Ec2:
@ -56,6 +42,7 @@ cloud_config_modules:
# Emit the cloud config ready event
# this can be used by upstart jobs for 'start on cloud-config'.
- emit_upstart
- disk_setup
- mounts
- ssh-import-id
- locale

View File

@ -1,24 +1,63 @@
Cloud-init supports the creation of simple partition tables and file systems
on devices.
default disk definitions
------------------------
Default disk definitions for AWS
--------------------------------
(Not implemented yet, but provided for future documentation)
disk_setup:
ephmeral0:
type: 'mbr'
layout: True
overwrite: False
fs_setup:
ephemeral0:
filesystem: 'ext3'
device: 'ephemeral0'
partition: 'auto'
- label: None,
filesystem: ext3
device: ephemeral0
partition: auto
Default disk definitions for Windows Azure
------------------------------------------
(Not implemented yet due to conflict with WALinuxAgent in Ubuntu)
disk_setup:
/dev/sdb:
type: mbr
layout: True
overwrite: False
fs_setup:
- label: ephemeral0
filesystem: ext3
device: ephemeral0
partition: any
Default disk definitions for SmartOS
------------------------------------
ephemeral_disk: /dev/vdb
disk_setup:
/dev/vdb:
type: mbr
layout: True
overwrite: False
fs_setup:
- label: ephemeral0
filesystem: ext3
device: /dev/vdb
partition: 1
Cavaut for SmartOS: if ephemeral disk is not defined, then the disk will
not be automatically added to the mounts.
The default definition is used to make sure that the ephemeral storage is
setup properly.
"disk_setup": disk parititioning
"disk_setup": disk partitioning
--------------------------------
The disk_setup directive instructs Cloud-init to partition a disk. The format is:
@ -36,7 +75,7 @@ The disk_setup directive instructs Cloud-init to partition a disk. The format is
overwrite: True
The format is a list of dicts of dicts. The first value is the name of the
device and the subsiquent values define how to create and layout the partition.
device and the subsequent values define how to create and layout the partition.
The general format is:
disk_setup:
@ -113,28 +152,29 @@ fs_setup: Setup the file system
fs_setup describes the how the file systems are supposed to look.
fs_setup:
ephemeral0:
- label: ephemeral0
filesystem: 'ext3'
device: 'ephemeral0'
partition: 'auto'
mylabl2:
- label: mylabl2
filesystem: 'ext4'
device: '/dev/xvda1'
special:
- special:
cmd: mkfs -t %(FILESYSTEM)s -L %(LABEL)s %(DEVICE)s
filesystem: 'btrfs'
device: '/dev/xvdh'
The general format is:
fs_setup:
<LABEL>:
- label: <LABEL>
filesystem: <FS_TYPE>
device: <DEVICE>
partition: <PART_VALUE>
overwrite: <OVERWRITE>
Where:
<LABEL>: The file system label to be used.
<LABEL>: The file system label to be used. If set to None, no label is
used.
<FS_TYPE>: The file system type. It is assumed that the there
will be a "mkfs.<FS_TYPE>" that behaves likes "mkfs". On a standard
@ -166,13 +206,5 @@ Where:
"false": If an existing file system exists, skip the creation.
"force": Recreate the file system, even it already exists
Behavior Caveat: The default behavior is to _check_ if the file system exists.
If a file system matches the specification, then the operation is a no-op.
For 'ephemeralX' or 'swap' labeled filesystems, the operation will be a
no-op if a file system of the same type is present, regardless of the label.
This is to accommodate Clouds like EC2 that present a blank file system with
out a label.

View File

@ -5,11 +5,13 @@ SmartOS Datasource
This datasource finds metadata and user-data from the SmartOS virtualization
platform (i.e. Joyent).
Please see http://smartos.org/ for information about SmartOS.
SmartOS Platform
----------------
The SmartOS virtualization platform meta-data to the instance via the second
serial console. On Linux, this is /dev/ttyS1. The data is a provided via a
simple protocol, where something queries for the userdata, where the console
The SmartOS virtualization platform uses meta-data to the instance via the
second serial console. On Linux, this is /dev/ttyS1. The data is a provided
via a simple protocol: something queries for the data, the console responds
responds with the status and if "SUCCESS" returns until a single ".\n".
New versions of the SmartOS tooling will include support for base64 encoded data.
@ -18,7 +20,7 @@ Userdata
--------
In SmartOS parlance, user-data is a actually meta-data. This userdata can be
provided a key-value pairs.
provided as key-value pairs.
Cloud-init supports reading the traditional meta-data fields supported by the
SmartOS tools. These are:
@ -36,13 +38,13 @@ user-script
SmartOS traditionally supports sending over a user-script for execution at the
rc.local level. Cloud-init supports running user-scripts as if they were
cloud-init user-data. In this sense, anything with a shell interpreter
directive will run
directive will run.
user-data and user-script
-------------------------
In the event that a user defines the meta-data key of "user-data" it will
always supercede any user-script data. This is for consistency.
always supersede any user-script data. This is for consistency.
base64
------
@ -70,3 +72,16 @@ or not to base64 decode something:
* no_base64_decode: This is a configuration setting
(i.e. /etc/cloud/cloud.cfg.d) that sets which values should not be
base64 decoded.
ephemeral_disk:
---------------
In order to instruct Cloud-init which disk to auto-mount. By default,
SmartOS only supports a single ephemeral disk.
The default SmartOS configuration will prepare the ephemeral disk and format
it for you. SmartOS does not, by default, prepare the ephemeral disk for you.
If you change ephemeral_disk, you should also consider changing
the default disk formatting parameters. See
doc/examples/cloud-config-disk-setup.txt for information on using this.

View File

@ -261,6 +261,41 @@ class TestSmartOSDataSource(MockerTestCase):
self.assertEquals(MOCK_RETURNS['enable_motd_sys_info'],
dsrc.metadata['motd_sys_info'])
def test_default_ephemeral(self):
# Test to make sure that the builtin config has the ephemeral
# configuration.
dsrc = self._get_ds()
cfg = dsrc.get_config_obj()
ret = dsrc.get_data()
self.assertTrue(ret)
assert 'disk_setup' in cfg
assert 'fs_setup' in cfg
self.assertIsInstance(cfg['disk_setup'], dict)
self.assertIsInstance(cfg['fs_setup'], list)
def test_override_builtin_ds(self):
# Test to make sure that the built-in DS is overriden
data = {}
data['disk_setup'] = {'test_dev': {}}
data['fs_setup'] = [{'label': 'test_dev'}]
data['serial_device'] = '/dev/ttyS2'
dsrc = self._get_ds(ds_cfg=data)
cfg = dsrc.get_config_obj()
ret = dsrc.get_data()
self.assertTrue(ret)
assert 'disk_setup' in cfg
assert 'fs_setup' in cfg
self.assertIsInstance(cfg['disk_setup'], dict)
self.assertIsInstance(cfg['fs_setup'], list)
assert 'test_dev' in cfg['disk_setup']
assert 'test_dev' in cfg['fs_setup'][0]['label']
self.assertEquals(data['serial_device'], dsrc.seed)
def apply_patches(patches):
ret = []