← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~smoser/cloud-init:bug/1745663-use-lxd-console into cloud-init:master

 

Scott Moser has proposed merging ~smoser/cloud-init:bug/1745663-use-lxd-console into cloud-init:master.

Commit message:
tests: lxd platform replace console log implementation.

This disables the '_setup_console_log' path we had for getting a log
in lxd.  It implements a path that requires liblxc3.0.
This should currently work on lxd snap from edge.

LP: #1745663

Requested reviews:
  cloud-init commiters (cloud-init-dev)
Related bugs:
  Bug #1745663 in cloud-init: "tests: lxd console code breaks when using lxd as snap"
  https://bugs.launchpad.net/cloud-init/+bug/1745663

For more details, see:
https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/336722

see commit message
-- 
Your team cloud-init commiters is requested to review the proposed merge of ~smoser/cloud-init:bug/1745663-use-lxd-console into cloud-init:master.
diff --git a/tests/cloud_tests/collect.py b/tests/cloud_tests/collect.py
index 5ea88e5..d4f9135 100644
--- a/tests/cloud_tests/collect.py
+++ b/tests/cloud_tests/collect.py
@@ -44,8 +44,9 @@ def collect_console(instance, base_dir):
     LOG.debug('getting console log for %s to %s', instance, logfile)
     try:
         data = instance.console_log()
-    except NotImplementedError:
-        data = b'instance.console_log: not implemented'
+    except NotImplementedError as e:
+        # args[0] is hacky, but thats all I see to get at the message.
+        data = b'NotImplementedError:' + e.args[0].encode()
     with open(logfile, "wb") as fp:
         fp.write(data)
 
diff --git a/tests/cloud_tests/platforms/lxd/instance.py b/tests/cloud_tests/platforms/lxd/instance.py
index d2d2a1f..8b380e7 100644
--- a/tests/cloud_tests/platforms/lxd/instance.py
+++ b/tests/cloud_tests/platforms/lxd/instance.py
@@ -6,7 +6,8 @@ import os
 import shutil
 from tempfile import mkdtemp
 
-from cloudinit.util import subp, ProcessExecutionError
+from cloudinit.util import load_yaml, subp, ProcessExecutionError
+from tests.cloud_tests.util import PlatformError
 
 from ..instances import Instance
 
@@ -30,7 +31,6 @@ class LXDInstance(Instance):
         super(LXDInstance, self).__init__(
             platform, name, properties, config, features)
         self.tmpd = mkdtemp(prefix="%s-%s" % (type(self).__name__, name))
-        self._setup_console_log()
         self.name = name
 
     @property
@@ -39,21 +39,6 @@ class LXDInstance(Instance):
         self._pylxd_container.sync()
         return self._pylxd_container
 
-    def _setup_console_log(self):
-        logf = os.path.join(self.tmpd, "console.log")
-
-        # doing this ensures we can read it. Otherwise it ends up root:root.
-        with open(logf, "w") as fp:
-            fp.write("# %s\n" % self.name)
-
-        cfg = "lxc.console.logfile=%s" % logf
-        orig = self._pylxd_container.config.get('raw.lxc', "")
-        if orig:
-            orig += "\n"
-        self._pylxd_container.config['raw.lxc'] = orig + cfg
-        self._pylxd_container.save()
-        self._console_log_file = logf
-
     def _execute(self, command, stdin=None, env=None):
         if env is None:
             env = {}
@@ -97,19 +82,40 @@ class LXDInstance(Instance):
         """
         self.pylxd_container.files.put(remote_path, data)
 
+    def _assert_console_log_support(self):
+        stdout, _ = subp(['lxc', 'info'])
+        info = load_yaml(stdout)
+        if 'console' not in info.get('api_extensions', []):
+            raise NotImplementedError(
+                "LXD server does not support console api extension.")
+        dver = info.get('environment', {}).get('driver_version', "")
+        if dver.startswith("2.") or dver.startwith("1."):
+            raise NotImplementedError(
+                "LXD Driver version not 3.x+ (%s)" % dver)
+        try:
+            stdout, stderr = subp(['lxc', 'console', '--help'], decode=False)
+            if not (b'console' in stdout and b'log' in stdout):
+                raise NotImplementedError(
+                    "LXC Client console --help did not contain 'log'")
+        except ProcessExecutionError as e:
+            raise NotImplementedError(
+                "LXC client has no 'console' argument")
+
     def console_log(self):
         """Console log.
 
         @return_value: bytes of this instance’s console
         """
-        if not os.path.exists(self._console_log_file):
-            raise NotImplementedError(
-                "Console log '%s' does not exist. If this is a remote "
-                "lxc, then this is really NotImplementedError.  If it is "
-                "A local lxc, then this is a RuntimeError."
-                "https://github.com/lxc/lxd/issues/1129";)
-        with open(self._console_log_file, "rb") as fp:
-            return fp.read()
+        self._assert_console_log_support()
+        try:
+            stdout, stderr = subp(
+                ['lxc', 'console', '--show-log', self.name], decode=False)
+            return stdout
+        except ProcessExecutionError as e:
+            raise PlatformError(
+                "console log",
+                "Console log failed [%d]: stdout=%s stderr=%s" % (
+                    e.exit_code, e.stdout, e.stderr))
 
     def reboot(self, wait=True):
         """Reboot instance."""

Follow ups