diff options
-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)) |