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:
parent
bd183cb716
commit
fd572349e4
@ -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:
|
||||
|
@ -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']
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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 = []
|
||||
|
Loading…
x
Reference in New Issue
Block a user