summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStéphane Graber <stgraber@ubuntu.com>2016-09-29 01:40:32 -0400
committerScott Moser <smoser@brickies.net>2016-09-29 12:23:02 -0400
commit02f6c4bb8cef17b3fe04ef4dc1ef199e20aeb4d9 (patch)
tree6b53ce90cd1d969af46aafb7ed840cee47a50a37
parent9f83bb8e80806d3dd79ba426474dc3c696e19a41 (diff)
downloadvyos-cloud-init-02f6c4bb8cef17b3fe04ef4dc1ef199e20aeb4d9.tar.gz
vyos-cloud-init-02f6c4bb8cef17b3fe04ef4dc1ef199e20aeb4d9.zip
lxd: Update network config for LXD 2.3
Prior to LXD 2.3, the bridge configuration was done through distro packaging. Thus, lxd module interacted with debconf. With 2.3 and higher, this is now done inside LXD itself, so we need to use "lxc network" there. For now, this perfectly matches what we had before with debconf and doesn't cover any of the new options. We can always add those later. A set of tests similar to what we had for debconf has been added to make sure things look good. This is tested in Yakkety container running LXD 2.3 and all options seem to be passed through as expected, giving me the bridge I defined. Signed-off-by: Stéphane Graber <stgraber@ubuntu.com>
-rw-r--r--cloudinit/config/cc_lxd.py107
-rw-r--r--tests/unittests/test_handler/test_handler_lxd.py51
2 files changed, 140 insertions, 18 deletions
diff --git a/cloudinit/config/cc_lxd.py b/cloudinit/config/cc_lxd.py
index 0086840f..cead2c95 100644
--- a/cloudinit/config/cc_lxd.py
+++ b/cloudinit/config/cc_lxd.py
@@ -46,6 +46,7 @@ Example config:
"""
from cloudinit import util
+import os
distros = ['ubuntu']
@@ -105,25 +106,43 @@ def handle(name, cfg, cloud, log, args):
# Set up lxd-bridge if bridge config is given
dconf_comm = "debconf-communicate"
- if bridge_cfg and util.which(dconf_comm):
- debconf = bridge_to_debconf(bridge_cfg)
+ if bridge_cfg:
+ if os.path.exists("/etc/default/lxd-bridge") \
+ and util.which(dconf_comm):
+ # Bridge configured through packaging
+
+ debconf = bridge_to_debconf(bridge_cfg)
+
+ # Update debconf database
+ try:
+ log.debug("Setting lxd debconf via " + dconf_comm)
+ data = "\n".join(["set %s %s" % (k, v)
+ for k, v in debconf.items()]) + "\n"
+ util.subp(['debconf-communicate'], data)
+ except Exception:
+ util.logexc(log, "Failed to run '%s' for lxd with" %
+ dconf_comm)
+
+ # Remove the existing configuration file (forces re-generation)
+ util.del_file("/etc/default/lxd-bridge")
+
+ # Run reconfigure
+ log.debug("Running dpkg-reconfigure for lxd")
+ util.subp(['dpkg-reconfigure', 'lxd',
+ '--frontend=noninteractive'])
+ else:
+ # Built-in LXD bridge support
+ cmd_create, cmd_attach = bridge_to_cmd(bridge_cfg)
+ if cmd_create:
+ log.debug("Creating lxd bridge: %s" %
+ " ".join(cmd_create))
+ util.subp(cmd_create)
+
+ if cmd_attach:
+ log.debug("Setting up default lxd bridge: %s" %
+ " ".join(cmd_create))
+ util.subp(cmd_attach)
- # Update debconf database
- try:
- log.debug("Setting lxd debconf via " + dconf_comm)
- data = "\n".join(["set %s %s" % (k, v)
- for k, v in debconf.items()]) + "\n"
- util.subp(['debconf-communicate'], data)
- except Exception:
- util.logexc(log, "Failed to run '%s' for lxd with" % dconf_comm)
-
- # Remove the existing configuration file (forces re-generation)
- util.del_file("/etc/default/lxd-bridge")
-
- # Run reconfigure
- log.debug("Running dpkg-reconfigure for lxd")
- util.subp(['dpkg-reconfigure', 'lxd',
- '--frontend=noninteractive'])
elif bridge_cfg:
raise RuntimeError(
"Unable to configure lxd bridge without %s." + dconf_comm)
@@ -177,3 +196,55 @@ def bridge_to_debconf(bridge_cfg):
raise Exception("invalid bridge mode \"%s\"" % bridge_cfg.get("mode"))
return debconf
+
+
+def bridge_to_cmd(bridge_cfg):
+ if bridge_cfg.get("mode") == "none":
+ return None, None
+
+ bridge_name = bridge_cfg.get("name", "lxdbr0")
+ cmd_create = []
+ cmd_attach = ["lxc", "network", "attach-profile", bridge_name,
+ "default", "eth0", "--force-local"]
+
+ if bridge_cfg.get("mode") == "existing":
+ return None, cmd_attach
+
+ if bridge_cfg.get("mode") != "new":
+ raise Exception("invalid bridge mode \"%s\"" % bridge_cfg.get("mode"))
+
+ cmd_create = ["lxc", "network", "create", bridge_name]
+
+ if bridge_cfg.get("ipv4_address") and bridge_cfg.get("ipv4_netmask"):
+ cmd_create.append("ipv4.address=%s/%s" %
+ (bridge_cfg.get("ipv4_address"),
+ bridge_cfg.get("ipv4_netmask")))
+
+ if bridge_cfg.get("ipv4_nat", "true") == "true":
+ cmd_create.append("ipv4.nat=true")
+
+ if bridge_cfg.get("ipv4_dhcp_first") and \
+ bridge_cfg.get("ipv4_dhcp_last"):
+ dhcp_range = "%s-%s" % (bridge_cfg.get("ipv4_dhcp_first"),
+ bridge_cfg.get("ipv4_dhcp_last"))
+ cmd_create.append("ipv4.dhcp.ranges=%s" % dhcp_range)
+ else:
+ cmd_create.append("ipv4.address=none")
+
+ if bridge_cfg.get("ipv6_address") and bridge_cfg.get("ipv6_netmask"):
+ cmd_create.append("ipv6.address=%s/%s" %
+ (bridge_cfg.get("ipv6_address"),
+ bridge_cfg.get("ipv6_netmask")))
+
+ if bridge_cfg.get("ipv6_nat", "false") == "true":
+ cmd_create.append("ipv6.nat=true")
+
+ else:
+ cmd_create.append("ipv6.address=none")
+
+ if bridge_cfg.get("domain"):
+ cmd_create.append("dns.domain=%s" % bridge_cfg.get("domain"))
+
+ cmd_create.append("--force-local")
+
+ return cmd_create, cmd_attach
diff --git a/tests/unittests/test_handler/test_handler_lxd.py b/tests/unittests/test_handler/test_handler_lxd.py
index 6f90defb..14366a10 100644
--- a/tests/unittests/test_handler/test_handler_lxd.py
+++ b/tests/unittests/test_handler/test_handler_lxd.py
@@ -132,3 +132,54 @@ class TestLxd(t_help.TestCase):
cc_lxd.bridge_to_debconf(data),
{"lxd/setup-bridge": "false",
"lxd/bridge-name": ""})
+
+ def test_lxd_cmd_new_full(self):
+ data = {"mode": "new",
+ "name": "testbr0",
+ "ipv4_address": "10.0.8.1",
+ "ipv4_netmask": "24",
+ "ipv4_dhcp_first": "10.0.8.2",
+ "ipv4_dhcp_last": "10.0.8.254",
+ "ipv4_dhcp_leases": "250",
+ "ipv4_nat": "true",
+ "ipv6_address": "fd98:9e0:3744::1",
+ "ipv6_netmask": "64",
+ "ipv6_nat": "true",
+ "domain": "lxd"}
+ self.assertEqual(
+ cc_lxd.bridge_to_cmd(data),
+ (["lxc", "network", "create", "testbr0",
+ "ipv4.address=10.0.8.1/24", "ipv4.nat=true",
+ "ipv4.dhcp.ranges=10.0.8.2-10.0.8.254",
+ "ipv6.address=fd98:9e0:3744::1/64",
+ "ipv6.nat=true", "dns.domain=lxd",
+ "--force-local"],
+ ["lxc", "network", "attach-profile",
+ "testbr0", "default", "eth0", "--force-local"]))
+
+ def test_lxd_cmd_new_partial(self):
+ data = {"mode": "new",
+ "ipv6_address": "fd98:9e0:3744::1",
+ "ipv6_netmask": "64",
+ "ipv6_nat": "true"}
+ self.assertEqual(
+ cc_lxd.bridge_to_cmd(data),
+ (["lxc", "network", "create", "lxdbr0", "ipv4.address=none",
+ "ipv6.address=fd98:9e0:3744::1/64", "ipv6.nat=true",
+ "--force-local"],
+ ["lxc", "network", "attach-profile",
+ "lxdbr0", "default", "eth0", "--force-local"]))
+
+ def test_lxd_cmd_existing(self):
+ data = {"mode": "existing",
+ "name": "testbr0"}
+ self.assertEqual(
+ cc_lxd.bridge_to_cmd(data),
+ (None, ["lxc", "network", "attach-profile",
+ "testbr0", "default", "eth0", "--force-local"]))
+
+ def test_lxd_cmd_none(self):
+ data = {"mode": "none"}
+ self.assertEqual(
+ cc_lxd.bridge_to_cmd(data),
+ (None, None))