[lxc-devel] [PATCH 1/3] python: Don't hardcode LXCPATH in python module

Stéphane Graber stgraber at ubuntu.com
Mon Mar 11 15:57:50 UTC 2013


Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 .gitignore                        |   1 -
 configure.ac                      |   1 -
 src/python-lxc/lxc.c              |  14 +-
 src/python-lxc/lxc/__init__.py    | 470 +++++++++++++++++++++++++++++++++++++
 src/python-lxc/lxc/__init__.py.in | 471 --------------------------------------
 5 files changed, 483 insertions(+), 474 deletions(-)
 create mode 100644 src/python-lxc/lxc/__init__.py
 delete mode 100644 src/python-lxc/lxc/__init__.py.in

diff --git a/.gitignore b/.gitignore
index a3f46eb..b54ce3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,7 +65,6 @@ src/lxc/lxc-wait
 src/lxc/legacy/lxc-ls
 
 src/python-lxc/build/
-src/python-lxc/lxc/__init__.py
 src/python-lxc/lxc/__pycache__/
 
 src/tests/lxc-test-containertests
diff --git a/configure.ac b/configure.ac
index a9b2803..0c94d37 100644
--- a/configure.ac
+++ b/configure.ac
@@ -382,7 +382,6 @@ AC_CONFIG_FILES([
 	src/lxc/lxc.functions
 
 	src/python-lxc/Makefile
-	src/python-lxc/lxc/__init__.py
 
 	src/lua-lxc/Makefile
 
diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c
index 2abdc4c..8fd0a78 100644
--- a/src/python-lxc/lxc.c
+++ b/src/python-lxc/lxc.c
@@ -95,6 +95,12 @@ Container_init(Container *self, PyObject *args, PyObject *kwds)
     return 0;
 }
 
+static PyObject *
+get_default_config_path(Container *self, PyObject *args, PyObject *kwds)
+{
+    return PyUnicode_FromString(lxc_get_default_config_path());
+}
+
 // Container properties
 static PyObject *
 Container_config_file_name(Container *self, PyObject *args, PyObject *kwds)
@@ -628,12 +634,18 @@ PyVarObject_HEAD_INIT(NULL, 0)
     Container_new,                  /* tp_new */
 };
 
+static PyMethodDef LXC_methods[] = {
+    {"get_default_config_path",  (PyCFunction)get_default_config_path, METH_NOARGS,
+     "Returns the current LXC config path"},
+    {NULL, NULL, 0, NULL}
+};
+
 static PyModuleDef _lxcmodule = {
     PyModuleDef_HEAD_INIT,
     "_lxc",
     "Binding for liblxc in python",
     -1,
-    NULL, NULL, NULL, NULL, NULL
+    LXC_methods
 };
 
 PyMODINIT_FUNC
diff --git a/src/python-lxc/lxc/__init__.py b/src/python-lxc/lxc/__init__.py
new file mode 100644
index 0000000..828a1cb
--- /dev/null
+++ b/src/python-lxc/lxc/__init__.py
@@ -0,0 +1,470 @@
+#
+# python-lxc: Python bindings for LXC
+#
+# (C) Copyright Canonical Ltd. 2012
+#
+# Authors:
+# Stéphane Graber <stgraber at ubuntu.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+import _lxc
+import glob
+import os
+import subprocess
+import stat
+import time
+import warnings
+
+warnings.warn("The python-lxc API isn't yet stable "
+              "and may change at any point in the future.", Warning, 2)
+
+default_config_path = _lxc.get_default_config_path()
+
+
+class ContainerNetwork():
+    props = {}
+
+    def __init__(self, container, index):
+        self.container = container
+        self.index = index
+
+        for key in self.container.get_keys("lxc.network.%s" % self.index):
+            if "." in key:
+                self.props[key.replace(".", "_")] = key
+            else:
+                self.props[key] = key
+
+        if not self.props:
+            return False
+
+    def __delattr__(self, key):
+        if key in ["container", "index", "props"]:
+            return object.__delattr__(self, key)
+
+        if key not in self.props:
+            raise AttributeError("'%s' network has no attribute '%s'" % (
+                                 self.__get_network_item("type"), key))
+
+        return self.__clear_network_item(self.props[key])
+
+    def __dir__(self):
+        return sorted(self.props.keys())
+
+    def __getattr__(self, key):
+        if key in ["container", "index", "props"]:
+            return object.__getattribute__(self, key)
+
+        if key not in self.props:
+            raise AttributeError("'%s' network has no attribute '%s'" % (
+                                 self.__get_network_item("type"), key))
+
+        return self.__get_network_item(self.props[key])
+
+    def __hasattr__(self, key):
+        if key in ["container", "index", "props"]:
+            return object.__hasattr__(self, key)
+
+        if key not in self.props:
+            raise AttributeError("'%s' network has no attribute '%s'" % (
+                                 self.__get_network_item("type"), key))
+
+        return True
+
+    def __repr__(self):
+        return "'%s' network at index '%s'" % (
+            self.__get_network_item("type"), self.index)
+
+    def __setattr__(self, key, value):
+        if key in ["container", "index", "props"]:
+            return object.__setattr__(self, key, value)
+
+        if key not in self.props:
+            raise AttributeError("'%s' network has no attribute '%s'" % (
+                                 self.__get_network_item("type"), key))
+
+        return self.__set_network_item(self.props[key], value)
+
+    def __clear_network_item(self, key):
+        return self.container.clear_config_item("lxc.network.%s.%s" % (
+                                                self.index, key))
+
+    def __get_network_item(self, key):
+        return self.container.get_config_item("lxc.network.%s.%s" % (
+                                              self.index, key))
+
+    def __set_network_item(self, key, value):
+        return self.container.set_config_item("lxc.network.%s.%s" % (
+                                              self.index, key), value)
+
+
+class ContainerNetworkList():
+    def __init__(self, container):
+        self.container = container
+
+    def __getitem__(self, index):
+        if index >= len(self):
+            raise IndexError("list index out of range")
+
+        return ContainerNetwork(self.container, index)
+
+    def __len__(self):
+        values = self.container.get_config_item("lxc.network")
+
+        if values:
+            return len(values)
+        else:
+            return 0
+
+    def add(self, network_type):
+        index = len(self)
+
+        return self.container.set_config_item("lxc.network.%s.type" % index,
+                                              network_type)
+
+    def remove(self, index):
+        count = len(self)
+        if index >= count:
+            raise IndexError("list index out of range")
+
+        return self.container.clear_config_item("lxc.network.%s" % index)
+
+
+class Container(_lxc.Container):
+    def __init__(self, name, config_path=None):
+        """
+            Creates a new Container instance.
+        """
+
+        if os.geteuid() != 0:
+            raise Exception("Running as non-root.")
+
+        if config_path:
+            _lxc.Container.__init__(self, name, config_path)
+        else:
+            _lxc.Container.__init__(self, name)
+
+        self.network = ContainerNetworkList(self)
+
+    def add_device_node(self, path, destpath=None):
+        """
+            Add block/char device to running container.
+        """
+
+        if not self.running:
+            return False
+
+        if not destpath:
+            destpath = path
+
+        if not os.path.exists(path):
+            return False
+
+        # Lookup the source
+        path_stat = os.stat(path)
+        mode = stat.S_IMODE(path_stat.st_mode)
+
+        # Allow the target
+        if stat.S_ISBLK(path_stat.st_mode):
+            self.set_cgroup_item("devices.allow",
+                                 "b %s:%s rwm" %
+                                 (int(path_stat.st_rdev / 256),
+                                  int(path_stat.st_rdev % 256)))
+        elif stat.S_ISCHR(path_stat.st_mode):
+            self.set_cgroup_item("devices.allow",
+                                 "c %s:%s rwm" %
+                                 (int(path_stat.st_rdev / 256),
+                                  int(path_stat.st_rdev % 256)))
+
+        # Create the target
+        rootfs = "/proc/%s/root/" % self.init_pid
+        container_path = "%s/%s" % (rootfs, destpath)
+
+        if os.path.exists(container_path):
+            os.remove(container_path)
+
+        os.mknod(container_path, path_stat.st_mode, path_stat.st_rdev)
+        os.chmod(container_path, mode)
+        os.chown(container_path, 0, 0)
+
+        return True
+
+    def add_device_net(self, name, destname=None):
+        """
+            Add network device to running container.
+        """
+
+        if not self.running:
+            return False
+
+        if not destname:
+            destname = name
+
+        if not os.path.exists("/sys/class/net/%s/" % name):
+            return False
+
+        return subprocess.call(['ip', 'link', 'set',
+                                'dev', name,
+                                'netns', str(self.init_pid),
+                                'name', destname]) == 0
+
+    def append_config_item(self, key, value):
+        """
+            Append 'value' to 'key', assuming 'key' is a list.
+            If 'key' isn't a list, 'value' will be set as the value of 'key'.
+        """
+
+        return _lxc.Container.set_config_item(self, key, value)
+
+    def attach(self, namespace="ALL", *cmd):
+        """
+            Attach to a running container.
+        """
+
+        if not self.running:
+            return False
+
+        attach = ["lxc-attach", "-n", self.name,
+                  "-P", self.get_config_path()]
+        if namespace != "ALL":
+            attach += ["-s", namespace]
+
+        if cmd:
+            attach += ["--"] + list(cmd)
+
+        if subprocess.call(
+                attach,
+                universal_newlines=True) != 0:
+            return False
+        return True
+
+    def create(self, template, args={}):
+        """
+            Create a new rootfs for the container.
+
+            "template" must be a valid template name.
+
+            "args" (optional) is a dictionary of parameters and values to pass
+            to the template.
+        """
+
+        template_args = []
+        for item in args.items():
+            template_args.append("--%s" % item[0])
+            template_args.append("%s" % item[1])
+
+        return _lxc.Container.create(self, template, tuple(template_args))
+
+    def clone(self, container):
+        """
+            Clone an existing container into a new one.
+        """
+
+        if self.defined:
+            return False
+
+        if isinstance(container, Container):
+            source = container
+        else:
+            source = Container(container)
+
+        if not source.defined:
+            return False
+
+        if subprocess.call(["lxc-clone", "-o", source.name, "-n", self.name],
+                           universal_newlines=True) != 0:
+            return False
+
+        self.load_config()
+        return True
+
+    def console(self, tty="1"):
+        """
+            Access the console of a container.
+        """
+
+        if not self.running:
+            return False
+
+        if subprocess.call(["lxc-console", "-n", self.name, "-t", "%s" % tty,
+                            "-P", self.get_config_path()],
+                           universal_newlines=True) != 0:
+            return False
+        return True
+
+    def get_cgroup_item(self, key):
+        """
+            Returns the value for a given cgroup entry.
+            A list is returned when multiple values are set.
+        """
+        value = _lxc.Container.get_cgroup_item(self, key)
+
+        if value is False:
+            return False
+        else:
+            return value.rstrip("\n")
+
+    def get_config_item(self, key):
+        """
+            Returns the value for a given config key.
+            A list is returned when multiple values are set.
+        """
+        value = _lxc.Container.get_config_item(self, key)
+
+        if value is False:
+            return False
+        elif value.endswith("\n"):
+            return value.rstrip("\n").split("\n")
+        else:
+            return value
+
+    def get_ips(self, timeout=60, interface=None, protocol=None):
+        """
+            Returns the list of IP addresses for the container.
+        """
+
+        if not self.running:
+            return False
+
+        ips = []
+
+        count = 0
+        while count < timeout:
+            if count != 0:
+                time.sleep(1)
+
+            base_cmd = ["lxc-attach", "-s", "NETWORK", "-n", self.name, "--",
+                        "ip"]
+
+            # Get IPv6
+            if protocol in ("ipv6", None):
+                ip6_cmd = base_cmd + ["-6", "addr", "show", "scope", "global"]
+                if interface:
+                    ip = subprocess.Popen(ip6_cmd + ["dev", interface],
+                                          stdout=subprocess.PIPE,
+                                          universal_newlines=True)
+                else:
+                    ip = subprocess.Popen(ip6_cmd, stdout=subprocess.PIPE,
+                                          universal_newlines=True)
+
+                ip.wait()
+                for line in ip.stdout.read().split("\n"):
+                    fields = line.split()
+                    if len(fields) > 2 and fields[0] == "inet6":
+                        ips.append(fields[1].split('/')[0])
+
+            # Get IPv4
+            if protocol in ("ipv4", None):
+                ip4_cmd = base_cmd + ["-4", "addr", "show", "scope", "global"]
+                if interface:
+                    ip = subprocess.Popen(ip4_cmd + ["dev", interface],
+                                          stdout=subprocess.PIPE,
+                                          universal_newlines=True)
+                else:
+                    ip = subprocess.Popen(ip4_cmd, stdout=subprocess.PIPE,
+                                          universal_newlines=True)
+
+                ip.wait()
+                for line in ip.stdout.read().split("\n"):
+                    fields = line.split()
+                    if len(fields) > 2 and fields[0] == "inet":
+                        ips.append(fields[1].split('/')[0])
+
+            if ips:
+                break
+
+            count += 1
+
+        return ips
+
+    def get_keys(self, key=None):
+        """
+            Returns a list of valid sub-keys.
+        """
+        if key:
+            value = _lxc.Container.get_keys(self, key)
+        else:
+            value = _lxc.Container.get_keys(self)
+
+        if value is False:
+            return False
+        elif value.endswith("\n"):
+            return value.rstrip("\n").split("\n")
+        else:
+            return value
+
+    def set_config_item(self, key, value):
+        """
+            Set a config key to a provided value.
+            The value can be a list for the keys supporting multiple values.
+        """
+        old_value = self.get_config_item(key)
+
+        # Check if it's a list
+        def set_key(key, value):
+            self.clear_config_item(key)
+            if isinstance(value, list):
+                for entry in value:
+                    if not _lxc.Container.set_config_item(self, key, entry):
+                        return False
+            else:
+                _lxc.Container.set_config_item(self, key, value)
+
+        set_key(key, value)
+        new_value = self.get_config_item(key)
+
+        if (isinstance(value, str) and isinstance(new_value, str) and
+                value == new_value):
+            return True
+        elif (isinstance(value, list) and isinstance(new_value, list) and
+                set(value) == set(new_value)):
+            return True
+        elif (isinstance(value, str) and isinstance(new_value, list) and
+                set([value]) == set(new_value)):
+            return True
+        elif old_value:
+            set_key(key, old_value)
+            return False
+        else:
+            self.clear_config_item(key)
+            return False
+
+    def wait(self, state, timeout=-1):
+        """
+            Wait for the container to reach a given state or timeout.
+        """
+
+        if isinstance(state, str):
+            state = state.upper()
+
+        return _lxc.Container.wait(self, state, timeout)
+
+
+def list_containers(as_object=False, config_path=None):
+    """
+        List the containers on the system.
+    """
+
+    if not config_path:
+        config_path = default_config_path
+
+    containers = []
+    for entry in glob.glob("%s/*/config" % config_path):
+        if as_object:
+            containers.append(Container(entry.split("/")[-2], config_path))
+        else:
+            containers.append(entry.split("/")[-2])
+    return containers
diff --git a/src/python-lxc/lxc/__init__.py.in b/src/python-lxc/lxc/__init__.py.in
deleted file mode 100644
index f1848f2..0000000
--- a/src/python-lxc/lxc/__init__.py.in
+++ /dev/null
@@ -1,471 +0,0 @@
-#
-# python-lxc: Python bindings for LXC
-#
-# (C) Copyright Canonical Ltd. 2012
-#
-# Authors:
-# Stéphane Graber <stgraber at ubuntu.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-import _lxc
-import glob
-import os
-import subprocess
-import stat
-import tempfile
-import time
-import warnings
-
-warnings.warn("The python-lxc API isn't yet stable "
-              "and may change at any point in the future.", Warning, 2)
-
-default_config_path = "@LXCPATH@"
-
-
-class ContainerNetwork():
-    props = {}
-
-    def __init__(self, container, index):
-        self.container = container
-        self.index = index
-
-        for key in self.container.get_keys("lxc.network.%s" % self.index):
-            if "." in key:
-                self.props[key.replace(".", "_")] = key
-            else:
-                self.props[key] = key
-
-        if not self.props:
-            return False
-
-    def __delattr__(self, key):
-        if key in ["container", "index", "props"]:
-            return object.__delattr__(self, key)
-
-        if key not in self.props:
-            raise AttributeError("'%s' network has no attribute '%s'" % (
-                                 self.__get_network_item("type"), key))
-
-        return self.__clear_network_item(self.props[key])
-
-    def __dir__(self):
-        return sorted(self.props.keys())
-
-    def __getattr__(self, key):
-        if key in ["container", "index", "props"]:
-            return object.__getattribute__(self, key)
-
-        if key not in self.props:
-            raise AttributeError("'%s' network has no attribute '%s'" % (
-                                 self.__get_network_item("type"), key))
-
-        return self.__get_network_item(self.props[key])
-
-    def __hasattr__(self, key):
-        if key in ["container", "index", "props"]:
-            return object.__hasattr__(self, key)
-
-        if key not in self.props:
-            raise AttributeError("'%s' network has no attribute '%s'" % (
-                                 self.__get_network_item("type"), key))
-
-        return True
-
-    def __repr__(self):
-        return "'%s' network at index '%s'" % (
-            self.__get_network_item("type"), self.index)
-
-    def __setattr__(self, key, value):
-        if key in ["container", "index", "props"]:
-            return object.__setattr__(self, key, value)
-
-        if key not in self.props:
-            raise AttributeError("'%s' network has no attribute '%s'" % (
-                                 self.__get_network_item("type"), key))
-
-        return self.__set_network_item(self.props[key], value)
-
-    def __clear_network_item(self, key):
-        return self.container.clear_config_item("lxc.network.%s.%s" % (
-                                                self.index, key))
-
-    def __get_network_item(self, key):
-        return self.container.get_config_item("lxc.network.%s.%s" % (
-                                              self.index, key))
-
-    def __set_network_item(self, key, value):
-        return self.container.set_config_item("lxc.network.%s.%s" % (
-                                              self.index, key), value)
-
-
-class ContainerNetworkList():
-    def __init__(self, container):
-        self.container = container
-
-    def __getitem__(self, index):
-        if index >= len(self):
-            raise IndexError("list index out of range")
-
-        return ContainerNetwork(self.container, index)
-
-    def __len__(self):
-        values = self.container.get_config_item("lxc.network")
-
-        if values:
-            return len(values)
-        else:
-            return 0
-
-    def add(self, network_type):
-        index = len(self)
-
-        return self.container.set_config_item("lxc.network.%s.type" % index,
-                                              network_type)
-
-    def remove(self, index):
-        count = len(self)
-        if index >= count:
-            raise IndexError("list index out of range")
-
-        return self.container.clear_config_item("lxc.network.%s" % index)
-
-
-class Container(_lxc.Container):
-    def __init__(self, name, config_path=None):
-        """
-            Creates a new Container instance.
-        """
-
-        if os.geteuid() != 0:
-            raise Exception("Running as non-root.")
-
-        if config_path:
-            _lxc.Container.__init__(self, name, config_path)
-        else:
-            _lxc.Container.__init__(self, name)
-
-        self.network = ContainerNetworkList(self)
-
-    def add_device_node(self, path, destpath=None):
-        """
-            Add block/char device to running container.
-        """
-
-        if not self.running:
-            return False
-
-        if not destpath:
-            destpath = path
-
-        if not os.path.exists(path):
-            return False
-
-        # Lookup the source
-        path_stat = os.stat(path)
-        mode = stat.S_IMODE(path_stat.st_mode)
-
-        # Allow the target
-        if stat.S_ISBLK(path_stat.st_mode):
-            self.set_cgroup_item("devices.allow",
-                                 "b %s:%s rwm" %
-                                 (int(path_stat.st_rdev / 256),
-                                  int(path_stat.st_rdev % 256)))
-        elif stat.S_ISCHR(path_stat.st_mode):
-            self.set_cgroup_item("devices.allow",
-                                 "c %s:%s rwm" %
-                                 (int(path_stat.st_rdev / 256),
-                                  int(path_stat.st_rdev % 256)))
-
-        # Create the target
-        rootfs = "/proc/%s/root/" % self.init_pid
-        container_path = "%s/%s" % (rootfs, destpath)
-
-        if os.path.exists(container_path):
-            os.remove(container_path)
-
-        os.mknod(container_path, path_stat.st_mode, path_stat.st_rdev)
-        os.chmod(container_path, mode)
-        os.chown(container_path, 0, 0)
-
-        return True
-
-    def add_device_net(self, name, destname=None):
-        """
-            Add network device to running container.
-        """
-
-        if not self.running:
-            return False
-
-        if not destname:
-            destname = name
-
-        if not os.path.exists("/sys/class/net/%s/" % name):
-            return False
-
-        return subprocess.call(['ip', 'link', 'set',
-                                'dev', name,
-                                'netns', str(self.init_pid),
-                                'name', destname]) == 0
-
-    def append_config_item(self, key, value):
-        """
-            Append 'value' to 'key', assuming 'key' is a list.
-            If 'key' isn't a list, 'value' will be set as the value of 'key'.
-        """
-
-        return _lxc.Container.set_config_item(self, key, value)
-
-    def attach(self, namespace="ALL", *cmd):
-        """
-            Attach to a running container.
-        """
-
-        if not self.running:
-            return False
-
-        attach = ["lxc-attach", "-n", self.name,
-                  "-P", self.get_config_path()]
-        if namespace != "ALL":
-            attach += ["-s", namespace]
-
-        if cmd:
-            attach += ["--"] + list(cmd)
-
-        if subprocess.call(
-                attach,
-                universal_newlines=True) != 0:
-            return False
-        return True
-
-    def create(self, template, args={}):
-        """
-            Create a new rootfs for the container.
-
-            "template" must be a valid template name.
-
-            "args" (optional) is a dictionary of parameters and values to pass
-            to the template.
-        """
-
-        template_args = []
-        for item in args.items():
-            template_args.append("--%s" % item[0])
-            template_args.append("%s" % item[1])
-
-        return _lxc.Container.create(self, template, tuple(template_args))
-
-    def clone(self, container):
-        """
-            Clone an existing container into a new one.
-        """
-
-        if self.defined:
-            return False
-
-        if isinstance(container, Container):
-            source = container
-        else:
-            source = Container(container)
-
-        if not source.defined:
-            return False
-
-        if subprocess.call(["lxc-clone", "-o", source.name, "-n", self.name],
-                           universal_newlines=True) != 0:
-            return False
-
-        self.load_config()
-        return True
-
-    def console(self, tty="1"):
-        """
-            Access the console of a container.
-        """
-
-        if not self.running:
-            return False
-
-        if subprocess.call(["lxc-console", "-n", self.name, "-t", "%s" % tty,
-                            "-P", self.get_config_path()],
-                           universal_newlines=True) != 0:
-            return False
-        return True
-
-    def get_cgroup_item(self, key):
-        """
-            Returns the value for a given cgroup entry.
-            A list is returned when multiple values are set.
-        """
-        value = _lxc.Container.get_cgroup_item(self, key)
-
-        if value is False:
-            return False
-        else:
-            return value.rstrip("\n")
-
-    def get_config_item(self, key):
-        """
-            Returns the value for a given config key.
-            A list is returned when multiple values are set.
-        """
-        value = _lxc.Container.get_config_item(self, key)
-
-        if value is False:
-            return False
-        elif value.endswith("\n"):
-            return value.rstrip("\n").split("\n")
-        else:
-            return value
-
-    def get_ips(self, timeout=60, interface=None, protocol=None):
-        """
-            Returns the list of IP addresses for the container.
-        """
-
-        if not self.running:
-            return False
-
-        ips = []
-
-        count = 0
-        while count < timeout:
-            if count != 0:
-                time.sleep(1)
-
-            base_cmd = ["lxc-attach", "-s", "NETWORK", "-n", self.name, "--",
-                        "ip"]
-
-            # Get IPv6
-            if protocol in ("ipv6", None):
-                ip6_cmd = base_cmd + ["-6", "addr", "show", "scope", "global"]
-                if interface:
-                    ip = subprocess.Popen(ip6_cmd + ["dev", interface],
-                                          stdout=subprocess.PIPE,
-                                          universal_newlines=True)
-                else:
-                    ip = subprocess.Popen(ip6_cmd, stdout=subprocess.PIPE,
-                                          universal_newlines=True)
-
-                ip.wait()
-                for line in ip.stdout.read().split("\n"):
-                    fields = line.split()
-                    if len(fields) > 2 and fields[0] == "inet6":
-                        ips.append(fields[1].split('/')[0])
-
-            # Get IPv4
-            if protocol in ("ipv4", None):
-                ip4_cmd = base_cmd + ["-4", "addr", "show", "scope", "global"]
-                if interface:
-                    ip = subprocess.Popen(ip4_cmd + ["dev", interface],
-                                          stdout=subprocess.PIPE,
-                                          universal_newlines=True)
-                else:
-                    ip = subprocess.Popen(ip4_cmd, stdout=subprocess.PIPE,
-                                          universal_newlines=True)
-
-                ip.wait()
-                for line in ip.stdout.read().split("\n"):
-                    fields = line.split()
-                    if len(fields) > 2 and fields[0] == "inet":
-                        ips.append(fields[1].split('/')[0])
-
-            if ips:
-                break
-
-            count += 1
-
-        return ips
-
-    def get_keys(self, key=None):
-        """
-            Returns a list of valid sub-keys.
-        """
-        if key:
-            value = _lxc.Container.get_keys(self, key)
-        else:
-            value = _lxc.Container.get_keys(self)
-
-        if value is False:
-            return False
-        elif value.endswith("\n"):
-            return value.rstrip("\n").split("\n")
-        else:
-            return value
-
-    def set_config_item(self, key, value):
-        """
-            Set a config key to a provided value.
-            The value can be a list for the keys supporting multiple values.
-        """
-        old_value = self.get_config_item(key)
-
-        # Check if it's a list
-        def set_key(key, value):
-            self.clear_config_item(key)
-            if isinstance(value, list):
-                for entry in value:
-                    if not _lxc.Container.set_config_item(self, key, entry):
-                        return False
-            else:
-                _lxc.Container.set_config_item(self, key, value)
-
-        set_key(key, value)
-        new_value = self.get_config_item(key)
-
-        if (isinstance(value, str) and isinstance(new_value, str) and
-                value == new_value):
-            return True
-        elif (isinstance(value, list) and isinstance(new_value, list) and
-                set(value) == set(new_value)):
-            return True
-        elif (isinstance(value, str) and isinstance(new_value, list) and
-                set([value]) == set(new_value)):
-            return True
-        elif old_value:
-            set_key(key, old_value)
-            return False
-        else:
-            self.clear_config_item(key)
-            return False
-
-    def wait(self, state, timeout=-1):
-        """
-            Wait for the container to reach a given state or timeout.
-        """
-
-        if isinstance(state, str):
-            state = state.upper()
-
-        return _lxc.Container.wait(self, state, timeout)
-
-
-def list_containers(as_object=False, config_path=None):
-    """
-        List the containers on the system.
-    """
-
-    if not config_path:
-        config_path = default_config_path
-
-    containers = []
-    for entry in glob.glob("%s/*/config" % config_path):
-        if as_object:
-            containers.append(Container(entry.split("/")[-2], config_path))
-        else:
-            containers.append(entry.split("/")[-2])
-    return containers
-- 
1.8.1.2





More information about the lxc-devel mailing list