diff options
-rw-r--r-- | cloudinit/sources/DataSourceOpenNebula.py | 96 | ||||
-rw-r--r-- | tests/unittests/helpers.py | 1 | ||||
-rw-r--r-- | tests/unittests/test_datasource/test_opennebula.py | 16 |
3 files changed, 45 insertions, 68 deletions
diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py index ff8e6b6b..d2ab348f 100644 --- a/cloudinit/sources/DataSourceOpenNebula.py +++ b/cloudinit/sources/DataSourceOpenNebula.py @@ -24,7 +24,6 @@ import os import re -import subprocess from cloudinit import log as logging from cloudinit import sources @@ -86,7 +85,7 @@ class DataSourceOpenNebula(sources.DataSource): # check for valid user specified dsmode user_dsmode = results.get('dsmode', None) if user_dsmode not in VALID_DSMODES + (None,): - LOG.warn("user specified invalid mode: %s" % user_dsmode) + LOG.warn("user specified invalid mode: %s", user_dsmode) user_dsmode = None # decide dsmode @@ -136,7 +135,9 @@ class NonContextDiskDir(Exception): class OpenNebulaNetwork(object): - REG_DEV_MAC = re.compile('^\d+: (eth\d+):.*link\/ether (..:..:..:..:..:..) ') + REG_DEV_MAC = re.compile( + r'^\d+: (eth\d+):.*?link\/ether (..:..:..:..:..:..) ?', + re.MULTILINE | re.DOTALL) def __init__(self, ip, context_sh): self.ip = ip @@ -144,7 +145,7 @@ class OpenNebulaNetwork(object): self.ifaces = self.get_ifaces() def get_ifaces(self): - return [self.REG_DEV_MAC.search(f).groups() for f in self.ip.split("\n") if self.REG_DEV_MAC.match(f)] + return self.REG_DEV_MAC.findall(self.ip) def mac2ip(self, mac): components = mac.split(':')[2:] @@ -157,7 +158,7 @@ class OpenNebulaNetwork(object): else: return '.'.join(components) - def get_mask(self, dev, components): + def get_mask(self, dev): var_name = dev + '_mask' if var_name in self.context_sh: return self.context_sh[var_name] @@ -171,26 +172,26 @@ class OpenNebulaNetwork(object): else: return '.'.join(components[:-1]) + '.0' - def get_gateway(self, dev, components): + def get_gateway(self, dev): var_name = dev + '_gateway' if var_name in self.context_sh: return self.context_sh[var_name] else: - None + return None - def get_dns(self, dev, components): + def get_dns(self, dev): var_name = dev + '_dns' if var_name in self.context_sh: return self.context_sh[var_name] else: - None + return None - def get_domain(self, dev, components): + def get_domain(self, dev): var_name = dev + '_domain' if var_name in self.context_sh: return self.context_sh[var_name] else: - None + return None def gen_conf(self): global_dns = [] @@ -211,18 +212,18 @@ class OpenNebulaNetwork(object): conf.append('iface ' + dev + ' inet static') conf.append(' address ' + self.get_ip(dev, ip_components)) conf.append(' network ' + self.get_network(dev, ip_components)) - conf.append(' netmask ' + self.get_mask(dev, ip_components)) + conf.append(' netmask ' + self.get_mask(dev)) - gateway = self.get_gateway(dev, ip_components) + gateway = self.get_gateway(dev) if gateway: conf.append(' gateway ' + gateway) - domain = self.get_domain(dev, ip_components) + domain = self.get_domain(dev) if domain: conf.append(' dns-search ' + domain) # add global DNS servers to all interfaces - dns = self.get_dns(dev, ip_components) + dns = self.get_dns(dev) if global_dns or dns: all_dns = global_dns if dns: @@ -272,51 +273,22 @@ def read_context_disk_dir(source_dir): if "context.sh" in found: try: - # Note: context.sh is a "shell" script with defined context - # variables, like: X="Y" . It's ready to use as a shell source - # e.g.: ". context.sh" and as a shell script it can also reference - # to already defined shell variables. So to have same context var. - # values as we can have in custom shell script, we use bash itself - # to read context.sh and dump variables in easily parsable way. - # - # normalized variables dump format (get by cmd "set"): - # 1. simple single word assignment ........ X=Y - # 2. multiword assignment ................. X='Y Z' - # 3. assignments with backslash escapes ... X=$'Y\nZ' - # - # how context variables are read: - # 1. list existing ("old") shell variables and store into $VARS - # 2. read context variables - # 3. use comm to filter "old" variables from all current - # variables and excl. few other vars with grep - BASH_CMD = 'VARS=`set | sort -u `;' \ - 'source %s/context.sh;' \ - 'comm -23 <(set | sort -u) <(echo "$VARS") | egrep -v "^(VARS|PIPESTATUS|_)="' - - (out, err) = util.subp(['bash', '--noprofile', '--norc', - '-c', BASH_CMD % (source_dir)]) - - for (key, value) in [l.split('=', 1) for l in out.rstrip().split("\n")]: - k = key.lower() - - # with backslash escapes, e.g. - # X=$'Y\nZ' - r = re.match("^\$'(.*)'$", value) - if r: - context_sh[k] = r.group(1).decode('string_escape') - else: - # multiword values, e.g.: - # X='Y Z' - # X='Y'\''Z' for "Y'Z" - r = re.match("^'(.*)'$", value) - if r: - context_sh[k] = r.group(1).replace("'\\''", "'") - else: - # simple values, e.g.: - # X=Y - context_sh[k] = value - - except util.ProcessExecutionError as e: + f = open('%s/context.sh' % (source_dir), 'r') + text = f.read() + f.close() + + context_reg = re.compile(r"^([\w_]+)=['\"](.*?[^\\])['\"]$", + re.MULTILINE | re.DOTALL) + variables = context_reg.findall(text) + + if not variables: + raise NonContextDiskDir("No variables in context") + + context_sh = {} + for k, v in variables: + context_sh[k.lower()] = v + + except (IOError, NonContextDiskDir) as e: raise NonContextDiskDir("Error reading context.sh: %s" % (e)) results['metadata'] = context_sh @@ -353,8 +325,8 @@ def read_context_disk_dir(source_dir): # only if there are any required context variables # http://opennebula.org/documentation:rel3.8:cong#network_configuration for k in context_sh.keys(): - if re.match('^eth\d+_ip$', k): - (out, err) = util.subp(['/sbin/ip', '-o', 'link']) + if re.match(r'^eth\d+_ip$', k): + (out, _) = util.subp(['/sbin/ip', '-o', 'link']) net = OpenNebulaNetwork(out, context_sh) results['network-interfaces'] = net.gen_conf() break diff --git a/tests/unittests/helpers.py b/tests/unittests/helpers.py index 91a50e18..904677f1 100644 --- a/tests/unittests/helpers.py +++ b/tests/unittests/helpers.py @@ -183,6 +183,7 @@ class FilesystemMockingTestCase(ResourceUsingTestCase): setattr(mod, f, trap_func) self.patched_funcs.append((mod, f, func)) + def populate_dir(path, files): os.makedirs(path) for (name, content) in files.iteritems(): diff --git a/tests/unittests/test_datasource/test_opennebula.py b/tests/unittests/test_datasource/test_opennebula.py index bc6c4b73..27725930 100644 --- a/tests/unittests/test_datasource/test_opennebula.py +++ b/tests/unittests/test_datasource/test_opennebula.py @@ -19,9 +19,11 @@ SSH_KEY = 'ssh-rsa AAAAB3NzaC1....sIkJhq8wdX+4I3A4cYbYP ubuntu@server-460-%i' HOSTNAME = 'foo.example.com' PUBLIC_IP = '10.0.0.3' -CMD_IP_OUT = '''\ -1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \ link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 -2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000\ link/ether 02:00:0a:12:01:01 brd ff:ff:ff:ff:ff:ff +CMD_IP_OUT = ''' +1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 +2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 + link/ether 02:00:0a:12:01:01 brd ff:ff:ff:ff:ff:ff ''' @@ -52,7 +54,7 @@ class TestOpenNebulaDataSource(MockerTestCase): self.assertEqual(TEST_VARS, results['metadata']) def test_ssh_key(self): - public_keys = [] + public_keys = ['first key', 'second key'] for c in range(4): for k in ('SSH_KEY', 'SSH_PUBLIC_KEY'): my_d = os.path.join(self.tmp, "%s-%i" % (k, c)) @@ -61,7 +63,8 @@ class TestOpenNebulaDataSource(MockerTestCase): self.assertTrue('metadata' in results) self.assertTrue('public-keys' in results['metadata']) - self.assertEqual(public_keys, results['metadata']['public-keys']) + self.assertEqual(public_keys, + results['metadata']['public-keys']) public_keys.append(SSH_KEY % (c + 1,)) @@ -96,7 +99,8 @@ class TestOpenNebulaDataSource(MockerTestCase): try: orig_find_devs_with = util.find_devs_with util.find_devs_with = my_devs_with - self.assertEqual(["/dev/sr0", "/dev/vdb"], ds.find_candidate_devs()) + self.assertEqual(["/dev/sr0", "/dev/vdb"], + ds.find_candidate_devs()) finally: util.find_devs_with = orig_find_devs_with |