summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1
-rw-r--r--cloudinit/config/cc_lxd.py50
-rw-r--r--config/cloud.cfg1
-rw-r--r--tests/unittests/test_handler/test_handler_lxd.py62
4 files changed, 114 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 0ba16492..9fbc920d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -71,6 +71,7 @@
- Azure: get instance id from dmi instead of SharedConfig (LP: #1506187)
- systemd/power_state: fix power_state to work even if cloud-final
exited non-zero (LP: #1449318)
+ - lxd: add support for setting up lxd using 'lxd init'
0.7.6:
- open 0.7.6
- Enable vendordata on CloudSigma datasource (LP: #1303986)
diff --git a/cloudinit/config/cc_lxd.py b/cloudinit/config/cc_lxd.py
new file mode 100644
index 00000000..0db8356b
--- /dev/null
+++ b/cloudinit/config/cc_lxd.py
@@ -0,0 +1,50 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2016 Canonical Ltd.
+#
+# Author: Wesley Wiedenmeier <wesley.wiedenmeier@canonical.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+This module initializes lxd using 'lxd init'
+
+Example config:
+ #cloud-config
+ lxd:
+ init:
+ network_address: <ip addr>
+ network_port: <port>
+ storage_backend: <zfs/dir>
+ storage_create_device: <dev>
+ storage_create_loop: <size>
+ storage_pool: <name>
+ trust_password: <password>
+"""
+
+from cloudinit import util
+
+
+def handle(name, cfg, cloud, log, args):
+ if not cfg.get('lxd') and cfg['lxd'].get('init'):
+ log.debug("Skipping module named %s, not present or disabled by cfg")
+ return
+ lxd_conf = cfg['lxd']['init']
+ keys = ('network_address', 'network_port', 'storage_backend',
+ 'storage_create_device', 'storage_create_loop', 'storage_pool',
+ 'trust_password')
+ cmd = ['lxd', 'init', '--auto']
+ for k in keys:
+ if lxd_conf.get(k):
+ cmd.extend(["--%s" % k.replace('_', '-'), lxd_conf[k]])
+ util.subp(cmd)
diff --git a/config/cloud.cfg b/config/cloud.cfg
index 74794ab0..795df19f 100644
--- a/config/cloud.cfg
+++ b/config/cloud.cfg
@@ -56,6 +56,7 @@ cloud_config_modules:
- fan
- landscape
- timezone
+ - lxd
- puppet
- chef
- salt-minion
diff --git a/tests/unittests/test_handler/test_handler_lxd.py b/tests/unittests/test_handler/test_handler_lxd.py
new file mode 100644
index 00000000..89863d52
--- /dev/null
+++ b/tests/unittests/test_handler/test_handler_lxd.py
@@ -0,0 +1,62 @@
+from cloudinit.config import cc_lxd
+from cloudinit import (util, distros, helpers, cloud)
+from cloudinit.sources import DataSourceNoCloud
+from .. import helpers as t_help
+
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+class TestLxd(t_help.TestCase):
+ def setUp(self):
+ super(TestLxd, self).setUp()
+ self.unapply = []
+ apply_patches([(util, 'subp', self._mock_subp)])
+ self.subp_called = []
+
+ def tearDown(self):
+ apply_patches([i for i in reversed(self.unapply)])
+
+ def _mock_subp(self, *args, **kwargs):
+ if 'args' not in kwargs:
+ kwargs['args'] = args[0]
+ self.subp_called.append(kwargs)
+ return
+
+ def _get_cloud(self, distro):
+ cls = distros.fetch(distro)
+ paths = helpers.Paths({})
+ d = cls(distro, {}, paths)
+ ds = DataSourceNoCloud.DataSourceNoCloud({}, d, paths)
+ cc = cloud.Cloud(ds, paths, {}, d, None)
+ return cc
+
+ def test_lxd_init(self):
+ cfg = {
+ 'lxd': {
+ 'init': {
+ 'network_address': '0.0.0.0',
+ 'storage_backend': 'zfs',
+ 'storage_pool': 'poolname',
+ }
+ }
+ }
+ cc = self._get_cloud('ubuntu')
+ cc_lxd.handle('cc_lxd', cfg, cc, LOG, [])
+
+ self.assertEqual(
+ self.subp_called[0].get('args'),
+ ['lxd', 'init', '--auto', '--network-address', '0.0.0.0',
+ '--storage-backend', 'zfs', '--storage-pool', 'poolname'])
+
+
+def apply_patches(patches):
+ ret = []
+ for (ref, name, replace) in patches:
+ if replace is None:
+ continue
+ orig = getattr(ref, name)
+ setattr(ref, name, replace)
+ ret.append((ref, name, orig))
+ return ret