diff options
author | Scott Moser <smoser@ubuntu.com> | 2010-01-28 15:49:29 -0500 |
---|---|---|
committer | Scott Moser <smoser@ubuntu.com> | 2010-01-28 15:49:29 -0500 |
commit | f8eb4061196c8c2489ac7bf084e0fc0d3e6d27fc (patch) | |
tree | cf124cde80f291930a626874fb38b64661ee8315 | |
parent | eb74cd6f36a2f4d2ebdee04d6b388834b1bc72d4 (diff) | |
download | vyos-cloud-init-f8eb4061196c8c2489ac7bf084e0fc0d3e6d27fc.tar.gz vyos-cloud-init-f8eb4061196c8c2489ac7bf084e0fc0d3e6d27fc.zip |
Add support for user defined mount points
Also, move swap to use this format for specifying mounts. That way
the user can turn off swap if they want with:
| mounts:
| - [ swap ]
Other change wrapped in here is to have DataSourceEc2 read plain text
(evalable) text for its metadata rather than pickl. This is really for
debuging anyway, so any speed difference is not important.
-rw-r--r-- | doc/examples/cloud-config.txt | 27 | ||||
-rwxr-xr-x | ec2-init.py | 10 | ||||
-rw-r--r-- | ec2init/CloudConfig.py | 114 | ||||
-rw-r--r-- | ec2init/DataSource.py | 9 | ||||
-rw-r--r-- | ec2init/DataSourceEc2.py | 28 | ||||
-rw-r--r-- | ec2init/__init__.py | 42 |
6 files changed, 165 insertions, 65 deletions
diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index b808f99a..f4de88e8 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -81,6 +81,33 @@ packages: - pwgen - pastebinit +# set up mount points +# 'mounts' contains a list of lists +# the inner list are entries for an /etc/fstab line +# ie : [ fs_spec, fs_file, fs_vfstype, fs_mntops, fs-freq, fs_passno ] +# +# default: +# mounts: +# - [ ephemeral0, /mnt ] +# - [ swap, none, swap, sw, 0, 0 ] +# +# in order to remove a previously listed mount (ie, one from defaults) +# list only the fs_spec. For example, to override the default, of +# mounting swap: +# - [ swap ] +# or +# - [ swap, null ] +# +# - if a device does not exist at the time, an entry will still be +# written to /etc/fstab. +# - '/dev' can be ommitted for device names that begin with: xvd, sd, hd, vd +# - if an entry does not have all 6 fields, they will be filled in +# from the following: [ None, None, "auto", "defaults", "0", "0" ] +# +mounts: + - [ ephemeral0, /mnt, auto, "defaults,noexec" ] + - [ sdc, /opt/data ] + - [ dd, /dev/zero ] # add each entry to ~/.ssh/authorized_keys for the configured user ssh_authorized_keys: diff --git a/ec2-init.py b/ec2-init.py index 7597e9c6..06662f7b 100755 --- a/ec2-init.py +++ b/ec2-init.py @@ -41,16 +41,6 @@ def main(): except: warn("failed to set defaults\n") - # enable swap - try: - cloud.sem_and_run("enable_swap", "once-per-instance", - cloud.enable_swap,[],False) - except: - import traceback - traceback.print_exc(file=sys.stderr) - warn("enabling swap failed!\n") - - # finish, send the cloud-config event cloud.initctl_emit() diff --git a/ec2init/CloudConfig.py b/ec2init/CloudConfig.py index 51618943..4875e999 100644 --- a/ec2init/CloudConfig.py +++ b/ec2init/CloudConfig.py @@ -39,6 +39,7 @@ class CloudConfig(): self.add_handler('apt-update-upgrade', self.h_apt_update_upgrade) self.add_handler('config-ssh') self.add_handler('disable-ec2-metadata') + self.add_handler('config-mounts') def get_config_obj(self,cfgfile): f=file(cfgfile) @@ -189,7 +190,118 @@ class CloudConfig(): def h_config_runurl(self,name,args): print "Warning, not doing anything for config %s" % name - + def h_config_mounts(self,name,args): + # handle 'mounts' + + # these are our default set of mounts + defmnts = [ [ "ephemeral0", "/mnt", "auto", "defaults", "0", "0" ], + [ "swap", "none", "swap", "sw", "0", "0" ] ] + + # fs_spec, fs_file, fs_vfstype, fs_mntops, fs-freq, fs_passno + defvals = [ None, None, "auto", "defaults", "0", "0" ] + + cfgmnt = [ ] + if self.cfg.has_key("mounts"): + cfgmnt = self.cfg["mounts"] + + for i in range(len(cfgmnt)): + # skip something that wasn't a list + if not isinstance(cfgmnt[i],list): continue + + # workaround, allow user to specify 'ephemeral' + # rather than more ec2 correct 'ephemeral0' + if cfgmnt[i] == "ephemeral": + cfgmnt[i] = "ephemeral0" + + newname = cfgmnt[i][0] + if not newname.startswith("/"): + newname = self.cloud.device_name_to_device(cfgmnt[i][0]) + if newname is not None: + cfgmnt[i][0] = newname + else: + # there is no good way of differenciating between + # a name that *couldn't* exist in the md service and + # one that merely didnt + # in order to allow user to specify 'sda3' rather + # than '/dev/sda3', go through some hoops + ok = False + for f in [ "/", "sd", "hd", "vd", "xvd" ]: + if cfgmnt[i][0].startswith(f): + ok = True + break + if not ok: + cfgmnt[i][1] = None + + for i in range(len(cfgmnt)): + # fill in values with + for j in range(len(defvals)): + if len(cfgmnt[i]) <= j: + cfgmnt[i].append(defvals[j]) + elif cfgmnt[i][j] is None: + cfgmnt[i][j] = defvals[j] + + if not cfgmnt[i][0].startswith("/"): + cfgmnt[i][0]="/dev/%s" % cfgmnt[i][0] + + # if the second entry in the list is 'None' this + # clears all previous entries of that same 'fs_spec' + # (fs_spec is the first field in /etc/fstab, ie, that device) + if cfgmnt[i][1] is None: + for j in range(i): + if cfgmnt[j][0] == cfgmnt[i][0]: + cfgmnt[j][1] = None + + + # for each of the "default" mounts, add them only if no other + # entry has the same device name + for defmnt in defmnts: + devname = self.cloud.device_name_to_device(defmnt[0]) + if devname is None: continue + if not devname.startswith("/"): + defmnt[0] = "/dev/%s" % devname + + cfgmnt_has = False + for cfgm in cfgmnt: + if cfgm[0] == defmnt[0]: + cfgmnt_has = True + break + + if cfgmnt_has: continue + cfgmnt.append(defmnt) + + + # now, each entry in the cfgmnt list has all fstab values + # if the second field is None (not the string, the value) we skip it + actlist = filter(lambda x: x[1] is not None, cfgmnt) + + if len(actlist) == 0: return + + needswap = False + dirs = [ ] + + fstab=file("/etc/fstab","ab") + fstab.write("# cloud-config mounts\n") + for line in actlist: + fstab.write('\t'.join(line) + "\n") + if line[2] == "swap": needswap = True + if line[1].startswith("/"): dirs.append(line[1]) + fstab.close() + + if needswap: + try: util.subp(("swapon", "-a")) + except: warn("Failed to enable swap") + + for d in dirs: + if os.path.exists(d): continue + try: os.makedirs(d) + except: warn("Failed to make '%s' config-mount\n",d) + + try: util.subp(("mount","-a")) + except: pass + + + + def apply_credentials(keys, user, disable_root): keys = set(keys) if user: diff --git a/ec2init/DataSource.py b/ec2init/DataSource.py index c761ae3e..9fe38b17 100644 --- a/ec2init/DataSource.py +++ b/ec2init/DataSource.py @@ -21,5 +21,10 @@ class DataSource: def get_public_ssh_keys(self): return([]) - def getswap_devs(self): - raise Exception("do not know how to generate swap list") + def device_name_to_device(self, name): + # translate a 'name' to a device + # the primary function at this point is on ec2 + # to consult metadata service, that has + # ephemeral0: sdb + # and return 'sdb' for input 'ephemeral0' + return(None) diff --git a/ec2init/DataSourceEc2.py b/ec2init/DataSourceEc2.py index 123ede67..1e81fddb 100644 --- a/ec2init/DataSourceEc2.py +++ b/ec2init/DataSourceEc2.py @@ -4,7 +4,6 @@ import ec2init import socket import urllib2 import time -import cPickle import boto_utils class DataSourceEc2(DataSource.DataSource): @@ -26,8 +25,9 @@ class DataSourceEc2(DataSource.DataSource): self.userdata_raw = udf.read() udf.close() - mdf = open(self.cachedir + "/meta-data.pkl") - self.metadata = cPickle.load(mdf) + mdf = open(self.cachedir + "/meta-data.raw") + data = mdf.read() + self.metadata = eval(data) mdf.close() return True @@ -109,13 +109,17 @@ class DataSourceEc2(DataSource.DataSource): return(keys) - def getswap_devs(self): + def device_name_to_device(self, name): + # consult metadata service, that has + # ephemeral0: sdb + # and return 'sdb' for input 'ephemeral0' if not self.metadata.has_key('block-device-mapping'): - raise Exception("no block-device-mapping") - list = [] - for use_t, device in self.metadata['block-device-mapping'].items(): - if not device.startswith("/dev"): - device="/dev/%s" % device - if use_t == "swap": - list.append(device) - return(list) + return(None) + + for entname, device in self.metadata['block-device-mapping'].items(): + if entname == name: + return(device) + # LP: #513842 mapping in Euca has 'ephemeral' not 'ephemeral0' + if entname == "ephemeral" and name == "ephemeral0": + return(device) + return None diff --git a/ec2init/__init__.py b/ec2init/__init__.py index c4923f1b..5405b5e4 100644 --- a/ec2init/__init__.py +++ b/ec2init/__init__.py @@ -285,43 +285,5 @@ class EC2Init: def get_hostname(self): return(self.datasource.get_hostname()) - def enable_swap(self): - swaps=[] - try: - swaps=self.datasource.getswap_devs() - except: - process = subprocess.Popen( - ['blkid', '-t', 'TYPE=swap', '-o', 'device'], - stdout=subprocess.PIPE) - (out,err)=process.communicate() - swaps=out.strip().split('\n') - - if len(swaps) == 0: return - - fstab="/etc/fstab" - f=file(fstab,"rb") - lines=f.read().split('\n') - f.close() - existing=[] - for line in lines: - try: - (dev,mp,type,opts,dump,pss)=line.split() - if dev.startswith("#"): continue - except: - continue - existing.append(dev) - - to_add=[] - for dev in swaps: - if not dev in existing: - to_add.append(dev) - - if len(to_add) == 0 : return - - f=file(fstab,"ab") - for dev in to_add: - f.write("%s\tnone\tswap\tsw\t0\t0\n" % dev) - f.close() - - subprocess.Popen(['swapon', '-a']).communicate() - + def device_name_to_device(self,name): + return(self.datasource.device_name_to_device(name)) |