summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/sources/DataSourceOpenNebula.py78
-rw-r--r--tests/unittests/test_datasource/test_opennebula.py95
2 files changed, 132 insertions, 41 deletions
diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py
index a1995aca..1b419cfd 100644
--- a/cloudinit/sources/DataSourceOpenNebula.py
+++ b/cloudinit/sources/DataSourceOpenNebula.py
@@ -35,6 +35,7 @@ LOG = logging.getLogger(__name__)
DEFAULT_IID = "iid-dsopennebula"
DEFAULT_MODE = 'net'
+DEFAULT_PARSEUSER = 'nobody'
CONTEXT_DISK_FILES = ["context.sh"]
VALID_DSMODES = ("local", "net", "disabled")
@@ -51,33 +52,35 @@ class DataSourceOpenNebula(sources.DataSource):
return "%s [seed=%s][dsmode=%s]" % (root, self.seed, self.dsmode)
def get_data(self):
- defaults = {
- "instance-id": DEFAULT_IID, #TODO:????
- "DSMODE": self.dsmode
- }
-
+ defaults = {"instance-id": DEFAULT_IID}
+ results = None
seed = None
- results = {}
- # first try to read local seed_dir
- if os.path.isdir(self.seed_dir):
+ # decide parseuser for context.sh shell reader
+ parseuser = DEFAULT_PARSEUSER
+ if self.ds_cfg.get('parseuser'):
+ parseuser = self.ds_cfg.get('parseuser')
+
+ candidates = [self.seed_dir]
+ candidates.extend(find_candidate_devs())
+ for cdev in candidates:
try:
- results = read_context_disk_dir(self.seed_dir)
- seed = self.seed_dir
+ if os.path.isdir(self.seed_dir):
+ results = read_context_disk_dir(cdev, asuser=parseuser)
+ elif cdev.startswith("/dev"):
+ results = util.mount_cb(cdev, read_context_disk_dir,
+ data=parseuser)
except NonContextDiskDir:
- util.logexc(LOG, "Failed reading context from %s",
- self.seed_dir)
+ continue
+ except BrokenContextDiskDir as exc:
+ raise exc
+ except util.MountFailedError:
+ LOG.warn("%s was not mountable" % cdev)
- 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)
- seed = dev
- break
- except (NonContextDiskDir, util.MountFailedError):
- pass
+ if results:
+ seed = cdev
+ LOG.debug("found datasource in %s", cdev)
+ break
if not seed:
return False
@@ -95,7 +98,7 @@ class DataSourceOpenNebula(sources.DataSource):
# decide dsmode
if user_dsmode:
dsmode = user_dsmode
- elif self.ds_cfg.get('dsmode'): #TODO: fakt se k tomu nekdy dostane?
+ elif self.ds_cfg.get('dsmode'):
dsmode = self.ds_cfg.get('dsmode')
else:
dsmode = DEFAULT_MODE
@@ -137,6 +140,10 @@ class NonContextDiskDir(Exception):
pass
+class BrokenContextDiskDir(Exception):
+ pass
+
+
class OpenNebulaNetwork(object):
REG_DEV_MAC = re.compile(
r'^\d+: (eth\d+):.*?link\/ether (..:..:..:..:..:..) ?',
@@ -306,7 +313,8 @@ def parse_shell_config(content, keylist=None, bash=None, asuser=None):
cmd.extend(bash)
sp = subprocess.Popen(cmd, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
(output, error) = sp.communicate(input=bcmd)
if sp.returncode != 0:
@@ -340,7 +348,7 @@ def parse_shell_config(content, keylist=None, bash=None, asuser=None):
return ret
-def read_context_disk_dir(source_dir):
+def read_context_disk_dir(source_dir, asuser=None):
"""
read_context_disk_dir(source_dir):
read source_dir and return a tuple with metadata dict and user-data
@@ -355,23 +363,31 @@ def read_context_disk_dir(source_dir):
if not found:
raise NonContextDiskDir("%s: %s" % (source_dir, "no files found"))
- results = {'userdata': None, 'metadata': {}}
context = {}
+ results = {'userdata': None, 'metadata': {}}
if "context.sh" in found:
try:
with open(os.path.join(source_dir, 'context.sh'), 'r') as f:
- content = f.read().strip()
- if content:
- context = parse_shell_config(content)
+ content = f.read().strip()
f.close()
- except (IOError, Exception) as e:
+
+ # don't pass empty context script
+ # to shell parser
+ non_empty = re.match(r'.*?^\s*([^# ]+)', content,
+ re.MULTILINE | re.DOTALL)
+
+ if non_empty:
+ context = parse_shell_config(content, asuser=asuser)
+ except IOError as e:
raise NonContextDiskDir("Error reading context.sh: %s" % (e))
+ except Exception as e:
+ raise BrokenContextDiskDir("Error processing context.sh: %s" % (e))
else:
raise NonContextDiskDir("Missing context.sh")
if not context:
- raise NonContextDiskDir("No context variables found")
+ return results
results['metadata'] = context
diff --git a/tests/unittests/test_datasource/test_opennebula.py b/tests/unittests/test_datasource/test_opennebula.py
index f544e145..752638b6 100644
--- a/tests/unittests/test_datasource/test_opennebula.py
+++ b/tests/unittests/test_datasource/test_opennebula.py
@@ -1,4 +1,5 @@
from cloudinit.sources import DataSourceOpenNebula as ds
+from cloudinit import helpers
from cloudinit import util
from mocker import MockerTestCase
from tests.unittests.helpers import populate_dir
@@ -20,6 +21,8 @@ TEST_VARS = {
'VAR12': '$', # expect $
}
+INVALID_PARSEUSER = 'cloud-init-mocker-opennebula-invalid'
+INVALID_CONTEXT = ';'
USER_DATA = '#cloud-config\napt_upgrade: true'
SSH_KEY = 'ssh-rsa AAAAB3NzaC1....sIkJhq8wdX+4I3A4cYbYP ubuntu@server-460-%i'
HOSTNAME = 'foo.example.com'
@@ -38,21 +41,93 @@ class TestOpenNebulaDataSource(MockerTestCase):
def setUp(self):
super(TestOpenNebulaDataSource, self).setUp()
self.tmp = self.makeDir()
+ self.paths = helpers.Paths({'cloud_dir': self.tmp})
+
+ # defaults for few tests
+ self.ds = ds.DataSourceOpenNebula
+ self.seed_dir = os.path.join(self.paths.seed_dir, "opennebula")
+ self.sys_cfg = {'datasource': {'OpenNebula': {'dsmode': 'local'}}}
+
+ def test_get_data_non_contextdisk(self):
+ try:
+ # dont' try to lookup for CDs
+ orig_find_devs_with = util.find_devs_with
+ util.find_devs_with = lambda n: []
+
+ dsrc = self.ds(sys_cfg=self.sys_cfg, distro=None, paths=self.paths)
+ ret = dsrc.get_data()
+ self.assertFalse(ret)
+ finally:
+ util.find_devs_with = orig_find_devs_with
+
+ def test_get_data_broken_contextdisk(self):
+ try:
+ # dont' try to lookup for CDs
+ orig_find_devs_with = util.find_devs_with
+ util.find_devs_with = lambda n: []
+
+ populate_dir(self.seed_dir, {'context.sh': INVALID_CONTEXT})
+ dsrc = self.ds(sys_cfg=self.sys_cfg, distro=None, paths=self.paths)
+ self.assertRaises(ds.BrokenContextDiskDir, dsrc.get_data)
+ finally:
+ util.find_devs_with = orig_find_devs_with
+
+ def test_get_data_invalid_identity(self):
+ try:
+ # dont' try to lookup for CDs
+ orig_find_devs_with = util.find_devs_with
+ util.find_devs_with = lambda n: []
+
+ sys_cfg = self.sys_cfg
+ sys_cfg['datasource']['OpenNebula']['parseuser'] = \
+ INVALID_PARSEUSER
+
+ populate_context_dir(self.seed_dir, {'KEY1': 'val1'})
+ dsrc = self.ds(sys_cfg=sys_cfg, distro=None, paths=self.paths)
+ self.assertRaises(ds.BrokenContextDiskDir, dsrc.get_data)
+ finally:
+ util.find_devs_with = orig_find_devs_with
+
+ def test_get_data(self):
+ try:
+ # dont' try to lookup for CDs
+ orig_find_devs_with = util.find_devs_with
+ util.find_devs_with = lambda n: []
+ populate_context_dir(self.seed_dir, {'KEY1': 'val1'})
+ dsrc = self.ds(sys_cfg=self.sys_cfg, distro=None, paths=self.paths)
+ ret = dsrc.get_data()
+ self.assertTrue(ret)
+ finally:
+ util.find_devs_with = orig_find_devs_with
def test_seed_dir_non_contextdisk(self):
- my_d = os.path.join(self.tmp, 'non-contextdisk')
- self.assertRaises(ds.NonContextDiskDir, ds.read_context_disk_dir, my_d)
+ self.assertRaises(ds.NonContextDiskDir, ds.read_context_disk_dir,
+ self.seed_dir)
+
+ def test_seed_dir_empty1_context(self):
+ populate_dir(self.seed_dir, {'context.sh': ''})
+ results = ds.read_context_disk_dir(self.seed_dir)
+
+ self.assertEqual(results['userdata'], None)
+ self.assertEqual(results['metadata'], {})
+
+ def test_seed_dir_empty2_context(self):
+ populate_context_dir(self.seed_dir, {})
+ results = ds.read_context_disk_dir(self.seed_dir)
+
+ self.assertEqual(results['userdata'], None)
+ self.assertEqual(results['metadata'], {})
+
+ def test_seed_dir_broken_context(self):
+ populate_dir(self.seed_dir, {'context.sh': INVALID_CONTEXT})
- def test_seed_dir_bad_context(self):
- my_d = os.path.join(self.tmp, 'bad-context')
- os.mkdir(my_d)
- open(os.path.join(my_d, "context.sh"), "w").close()
- self.assertRaises(ds.NonContextDiskDir, ds.read_context_disk_dir, my_d)
+ self.assertRaises(ds.BrokenContextDiskDir,
+ ds.read_context_disk_dir,
+ self.seed_dir)
def test_context_parser(self):
- my_d = os.path.join(self.tmp, 'context-parser')
- populate_context_dir(my_d, TEST_VARS)
- results = ds.read_context_disk_dir(my_d)
+ populate_context_dir(self.seed_dir, TEST_VARS)
+ results = ds.read_context_disk_dir(self.seed_dir)
self.assertTrue('metadata' in results)
self.assertEqual(TEST_VARS, results['metadata'])