diff options
author | Vlastimil Holer <vlastimil.holer@gmail.com> | 2013-09-05 17:55:53 +0200 |
---|---|---|
committer | Vlastimil Holer <vlastimil.holer@gmail.com> | 2013-09-05 17:55:53 +0200 |
commit | d0e7898d4d0aef452fbfdd9b51fa2da6437397ff (patch) | |
tree | 51cccff01ab8af5637ecf5a564491737c1a55b03 /cloudinit/sources/DataSourceOpenNebula.py | |
parent | 744c779182cba32314f8435660a61c2711cb9f54 (diff) | |
download | vyos-cloud-init-d0e7898d4d0aef452fbfdd9b51fa2da6437397ff.tar.gz vyos-cloud-init-d0e7898d4d0aef452fbfdd9b51fa2da6437397ff.zip |
PEP8 and Pylint fixes. Move context.sh "parser" into separate
function. Fix fetching user specified dsmode (from context).
Rename context_sh->context. Reuse unittests.helpers.populate_dir.
Diffstat (limited to 'cloudinit/sources/DataSourceOpenNebula.py')
-rw-r--r-- | cloudinit/sources/DataSourceOpenNebula.py | 163 |
1 files changed, 88 insertions, 75 deletions
diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py index fef7beac..87ec51bd 100644 --- a/cloudinit/sources/DataSourceOpenNebula.py +++ b/cloudinit/sources/DataSourceOpenNebula.py @@ -3,7 +3,7 @@ # Copyright (C) 2012 Canonical Ltd. # Copyright (C) 2012 Yahoo! Inc. # Copyright (C) 2012-2013 CERIT Scientific Cloud -# Copyright (C) 2012 OpenNebula.org +# Copyright (C) 2012-2013 OpenNebula.org # # Author: Scott Moser <scott.moser@canonical.com> # Author: Joshua Harlow <harlowja@yahoo-inc.com> @@ -45,45 +45,47 @@ class DataSourceOpenNebula(sources.DataSource): self.seed_dir = os.path.join(paths.seed_dir, 'opennebula') def __str__(self): - return "%s [seed=%s][dsmode=%s]" % \ - (util.obj_name(self), self.seed, self.dsmode) + root = sources.DataSource.__str__(self) + return "%s [seed=%s][dsmode=%s]" % (root, self.seed, self.dsmode) def get_data(self): defaults = { "instance-id": DEFAULT_IID, - "dsmode": self.dsmode} + "dsmode": self.dsmode + } - found = None - md = {} + seed = None results = {} + # first try to read local seed_dir if os.path.isdir(self.seed_dir): try: results = read_context_disk_dir(self.seed_dir) - found = self.seed_dir + seed = self.seed_dir except NonContextDiskDir: - util.logexc(LOG, "Failed reading context disk from %s", + util.logexc(LOG, "Failed reading context from %s", self.seed_dir) - # find candidate devices, try to mount them and - # read context script if present - if not found: + if not seed: + # then try to detect and mount candidate devices and + # read contextualization if present for dev in find_candidate_devs(): try: results = util.mount_cb(dev, read_context_disk_dir) - found = dev + seed = dev break except (NonContextDiskDir, util.MountFailedError): pass - if not found: + if not seed: return False + # merge fetched metadata with datasource defaults md = results['metadata'] - md = util.mergedict(md, defaults) + md = util.mergemanydict([md, defaults]) # check for valid user specified dsmode - user_dsmode = results.get('dsmode', None) + user_dsmode = results['metadata'].get('dsmode', None) if user_dsmode not in VALID_DSMODES + (None,): LOG.warn("user specified invalid mode: %s", user_dsmode) user_dsmode = None @@ -109,10 +111,9 @@ class DataSourceOpenNebula(sources.DataSource): LOG.debug("%s: not claiming datasource, dsmode=%s", self, dsmode) return False - self.seed = found + self.seed = seed self.metadata = md self.userdata_raw = results.get('userdata') - return True def get_hostname(self, fqdn=False, resolve_ip=None): @@ -139,9 +140,9 @@ class OpenNebulaNetwork(object): r'^\d+: (eth\d+):.*?link\/ether (..:..:..:..:..:..) ?', re.MULTILINE | re.DOTALL) - def __init__(self, ip, context_sh): + def __init__(self, ip, context): self.ip = ip - self.context_sh = context_sh + self.context = context self.ifaces = self.get_ifaces() def get_ifaces(self): @@ -153,50 +154,50 @@ class OpenNebulaNetwork(object): def get_ip(self, dev, components): var_name = dev + '_ip' - if var_name in self.context_sh: - return self.context_sh[var_name] + if var_name in self.context: + return self.context[var_name] else: return '.'.join(components) def get_mask(self, dev): var_name = dev + '_mask' - if var_name in self.context_sh: - return self.context_sh[var_name] + if var_name in self.context: + return self.context[var_name] else: return '255.255.255.0' def get_network(self, dev, components): var_name = dev + '_network' - if var_name in self.context_sh: - return self.context_sh[var_name] + if var_name in self.context: + return self.context[var_name] else: return '.'.join(components[:-1]) + '.0' def get_gateway(self, dev): var_name = dev + '_gateway' - if var_name in self.context_sh: - return self.context_sh[var_name] + if var_name in self.context: + return self.context[var_name] else: return None def get_dns(self, dev): var_name = dev + '_dns' - if var_name in self.context_sh: - return self.context_sh[var_name] + if var_name in self.context: + return self.context[var_name] else: return None def get_domain(self, dev): var_name = dev + '_domain' - if var_name in self.context_sh: - return self.context_sh[var_name] + if var_name in self.context: + return self.context[var_name] else: return None def gen_conf(self): global_dns = [] - if 'dns' in self.context_sh: - global_dns.append(self.context_sh['dns']) + if 'dns' in self.context: + global_dns.append(self.context['dns']) conf = [] conf.append('auto lo') @@ -241,101 +242,113 @@ def find_candidate_devs(): """ combined = [] for f in ('LABEL=CONTEXT', 'LABEL=CDROM', 'TYPE=iso9660'): - for d in util.find_devs_with(f).sort(): + devs = util.find_devs_with(f) + devs.sort() + for d in devs: if d not in combined: combined.append(d) return combined +def parse_context_data(data): + """ + parse_context_data(data) + parse context.sh variables provided as a single string. Uses + very simple matching RE. Returns None if nothing is matched. + """ + # RE groups: + # 1: key + # 2: single quoted value, respect '\'' + # 3: old double quoted value, but doesn't end with \" + context_reg = re.compile( + r"^([\w_]+)=(?:'((?:[^']|'\\'')*?)'|\"(.*?[^\\])\")$", + re.MULTILINE | re.DOTALL) + + found = context_reg.findall(data) + if not found: + return None + + variables = {} + for k, v1, v2 in found: + k = k.lower() + if v1: + # take single quoted variable 'xyz' + # (ON>=4) and unquote '\'' -> ' + variables[k] = v1.replace(r"'\''", r"'") + elif v2: + # take double quoted variable "xyz" + # (old ON<4) and unquote \" -> " + variables[k] = v2.replace(r'\"', r'"') + + return variables + + def read_context_disk_dir(source_dir): """ read_context_disk_dir(source_dir): read source_dir and return a tuple with metadata dict and user-data string populated. If not a valid dir, raise a NonContextDiskDir """ - found = {} for af in CONTEXT_DISK_FILES: fn = os.path.join(source_dir, af) if os.path.isfile(fn): found[af] = fn - if len(found) == 0: + if not found: raise NonContextDiskDir("%s: %s" % (source_dir, "no files found")) results = {'userdata': None, 'metadata': {}} - context_sh = {} + context = {} if "context.sh" in found: try: - f = open('%s/context.sh' % (source_dir), 'r') - text = f.read() - f.close() - - # lame matching: - # 1. group = key - # 2. group = single quoted value, respect '\'' - # 3. group = old double quoted value, but doesn't end with \" - context_reg = re.compile( - r"^([\w_]+)=(?:'((?:[^']|'\\'')*?)'|\"(.*?[^\\])\")$", - re.MULTILINE | re.DOTALL) - - variables = context_reg.findall(text) - if not variables: + with open(os.path.join(source_dir, 'context.sh'), 'r') as f: + context = parse_context_data(f.read()) + f.close() + if not context: raise NonContextDiskDir("No variables in context") - for k, v1, v2 in variables: - k = k.lower() - if v1: - # take single quoted variable 'xyz' - # (ON>=4) and unquote '\'' -> ' - context_sh[k] = v1.replace(r"'\''", r"'") - elif v2: - # take double quoted variable "xyz" - # (old ON<4) and unquote \" -> " - context_sh[k] = v2.replace(r'\"', r'"') - except (IOError, NonContextDiskDir) as e: raise NonContextDiskDir("Error reading context.sh: %s" % (e)) - results['metadata'] = context_sh + results['metadata'] = context else: raise NonContextDiskDir("Missing context.sh") # process single or multiple SSH keys ssh_key_var = None - - if "ssh_key" in context_sh: + if "ssh_key" in context: ssh_key_var = "ssh_key" - elif "ssh_public_key" in context_sh: + elif "ssh_public_key" in context: ssh_key_var = "ssh_public_key" if ssh_key_var: - lines = context_sh.get(ssh_key_var).splitlines() + lines = context.get(ssh_key_var).splitlines() results['metadata']['public-keys'] = [l for l in lines if len(l) and not l.startswith("#")] # custom hostname -- try hostname or leave cloud-init # itself create hostname from IP address later for k in ('hostname', 'public_ip', 'ip_public', 'eth0_ip'): - if k in context_sh: - results['metadata']['local-hostname'] = context_sh[k] + if k in context: + results['metadata']['local-hostname'] = context[k] break # raw user data - if "user_data" in context_sh: - results['userdata'] = context_sh["user_data"] - elif "userdata" in context_sh: - results['userdata'] = context_sh["userdata"] + if "user_data" in context: + results['userdata'] = context["user_data"] + elif "userdata" in context: + results['userdata'] = context["userdata"] # generate static /etc/network/interfaces # only if there are any required context variables # http://opennebula.org/documentation:rel3.8:cong#network_configuration - for k in context_sh.keys(): + for k in context.keys(): if re.match(r'^eth\d+_ip$', k): (out, _) = util.subp(['/sbin/ip', 'link']) - net = OpenNebulaNetwork(out, context_sh) + net = OpenNebulaNetwork(out, context) results['network-interfaces'] = net.gen_conf() break |