<div dir="ltr">Not at all as I already did it on my tree, sending in a minute as v4...</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Sep 18, 2013 at 2:58 PM, Stéphane Graber <span dir="ltr"><<a href="mailto:stgraber@ubuntu.com" target="_blank">stgraber@ubuntu.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">On Wed, Sep 18, 2013 at 02:53:33PM -0400, S.Çağlar Onur wrote:<br>
> Do you want me to sync this on top of staging and re-send?I think they are<br>
> conflicting right now.<br>
<br>
</div>Ah, if you don't mind, that'd be great (I started doing it but I'm<br>
getting interrupted quite a bit since I'm attending a conference)!<br>
<div class="HOEnZb"><div class="h5"><br>
> On Wed, Sep 18, 2013 at 2:47 PM, Stéphane Graber <<a href="mailto:stgraber@ubuntu.com">stgraber@ubuntu.com</a>>wrote:<br>
><br>
> > On Mon, Sep 16, 2013 at 05:01:11PM -0400, S.Çağlar Onur wrote:<br>
> > > get_ips accepts an interface name as a parameter but there was no<br>
> > > way to get the interfaces names from the container. This patch<br>
> > > introduces a new get_interfaces call to the API so that users<br>
> > > can obtain the name of the interfaces.<br>
> > ><br>
> > > Support for python bindings also introduced as a part of this version.<br>
> > ><br>
> > > Signed-off-by: S.Çağlar Onur <<a href="mailto:caglar@10ur.org">caglar@10ur.org</a>><br>
> ><br>
> > Acked-by: Stéphane Graber <<a href="mailto:stgraber@ubuntu.com">stgraber@ubuntu.com</a>><br>
> ><br>
> > > ---<br>
> > >  src/lxc/lxccontainer.c              | 129<br>
> > ++++++++++++++++++++++++++----------<br>
> > >  src/lxc/lxccontainer.h              |   3 +<br>
> > >  src/lxc/utils.c                     |  22 +++++-<br>
> > >  src/lxc/utils.h                     |   1 +<br>
> > >  src/python-lxc/examples/api_test.py |   5 ++<br>
> > >  src/python-lxc/lxc.c                |  60 +++++++++++++++--<br>
> > >  src/python-lxc/lxc/__init__.py      |   8 +++<br>
> > >  7 files changed, 189 insertions(+), 39 deletions(-)<br>
> > ><br>
> > > diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c<br>
> > > index 79237df..8621cd8 100644<br>
> > > --- a/src/lxc/lxccontainer.c<br>
> > > +++ b/src/lxc/lxccontainer.c<br>
> > > @@ -1179,23 +1179,26 @@ static bool lxcapi_clear_config_item(struct<br>
> > lxc_container *c, const char *key)<br>
> > >       return ret == 0;<br>
> > >  }<br>
> > ><br>
> > > -char** lxcapi_get_ips(struct lxc_container *c, char* interface, char*<br>
> > family, int scope)<br>
> > > -{<br>
> > > -     int count = 0;<br>
> > > -     struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;<br>
> > > -     char addressOutputBuffer[INET6_ADDRSTRLEN];<br>
> > > -     void *tempAddrPtr = NULL;<br>
> > > -     char **addresses = NULL, **temp;<br>
> > > -     char *address = NULL;<br>
> > > +static inline void exit_from_ns(struct lxc_container *c, int<br>
> > *old_netns, int *new_netns) {<br>
> > > +     /* Switch back to original netns */<br>
> > > +     if (*old_netns >= 0 && setns(*old_netns, CLONE_NEWNET))<br>
> > > +             SYSERROR("failed to setns");<br>
> > > +     if (*new_netns >= 0)<br>
> > > +             close(*new_netns);<br>
> > > +     if (*old_netns >= 0)<br>
> > > +             close(*old_netns);<br>
> > > +}<br>
> > > +<br>
> > > +static inline bool enter_to_ns(struct lxc_container *c, int *old_netns,<br>
> > int *new_netns) {<br>
> > > +     int ret = 0;<br>
> > >       char new_netns_path[MAXPATHLEN];<br>
> > > -     int old_netns = -1, new_netns = -1, ret = 0;<br>
> > ><br>
> > >       if (!c->is_running(c))<br>
> > >               goto out;<br>
> > ><br>
> > >       /* Save reference to old netns */<br>
> > > -     old_netns = open("/proc/self/ns/net", O_RDONLY);<br>
> > > -     if (old_netns < 0) {<br>
> > > +     *old_netns = open("/proc/self/ns/net", O_RDONLY);<br>
> > > +     if (*old_netns < 0) {<br>
> > >               SYSERROR("failed to open /proc/self/ns/net");<br>
> > >               goto out;<br>
> > >       }<br>
> > > @@ -1205,16 +1208,91 @@ char** lxcapi_get_ips(struct lxc_container *c,<br>
> > char* interface, char* family, in<br>
> > >       if (ret < 0 || ret >= MAXPATHLEN)<br>
> > >               goto out;<br>
> > ><br>
> > > -     new_netns = open(new_netns_path, O_RDONLY);<br>
> > > -     if (new_netns < 0) {<br>
> > > +     *new_netns = open(new_netns_path, O_RDONLY);<br>
> > > +     if (*new_netns < 0) {<br>
> > >               SYSERROR("failed to open %s", new_netns_path);<br>
> > >               goto out;<br>
> > >       }<br>
> > ><br>
> > > -     if (setns(new_netns, CLONE_NEWNET)) {<br>
> > > +     if (setns(*new_netns, CLONE_NEWNET)) {<br>
> > >               SYSERROR("failed to setns");<br>
> > >               goto out;<br>
> > >       }<br>
> > > +     return true;<br>
> > > +out:<br>
> > > +     exit_from_ns(c, old_netns, new_netns);<br>
> > > +     return false;<br>
> > > +}<br>
> > > +<br>
> > > +static char** lxcapi_get_interfaces(struct lxc_container *c)<br>
> > > +{<br>
> > > +     int count = 0, i;<br>
> > > +     bool found = false;<br>
> > > +     struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;<br>
> > > +     char **interfaces = NULL, **temp;<br>
> > > +     int old_netns = -1, new_netns = -1;<br>
> > > +<br>
> > > +     if (!enter_to_ns(c, &old_netns, &new_netns))<br>
> > > +             goto out;<br>
> > > +<br>
> > > +     /* Grab the list of interfaces */<br>
> > > +     if (getifaddrs(&interfaceArray)) {<br>
> > > +             SYSERROR("failed to get interfaces list");<br>
> > > +             goto out;<br>
> > > +     }<br>
> > > +<br>
> > > +     /* Iterate through the interfaces */<br>
> > > +     for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr =<br>
> > tempIfAddr->ifa_next) {<br>
> > > +             /*<br>
> > > +              * WARNING: Following "for" loop does a linear search over<br>
> > the interfaces array<br>
> > > +              * For the containers with lots of interfaces this may be<br>
> > problematic.<br>
> > > +         * I'm not expecting this to be the common usage but if it<br>
> > turns out to be<br>
> > > +              *     than using binary search or a hash table could be<br>
> > more elegant solution.<br>
> > > +              */<br>
> > > +             for (i = 0; i < count; i++) {<br>
> > > +                     if (strcmp(interfaces[i], tempIfAddr->ifa_name) ==<br>
> > 0) {<br>
> > > +                             found = true;<br>
> > > +                             break;<br>
> > > +                     }<br>
> > > +             }<br>
> > > +<br>
> > > +             if (!found) {<br>
> > > +                     count += 1;<br>
> > > +                     temp = realloc(interfaces, count *<br>
> > sizeof(*interfaces));<br>
> > > +                     if (!temp) {<br>
> > > +                             count -= 1;<br>
> > > +                             goto out;<br>
> > > +                     }<br>
> > > +                     interfaces = temp;<br>
> > > +                     interfaces[count - 1] =<br>
> > strdup(tempIfAddr->ifa_name);<br>
> > > +             }<br>
> > > +             found = false;<br>
> > > +    }<br>
> > > +<br>
> > > +out:<br>
> > > +       if (interfaceArray)<br>
> > > +               freeifaddrs(interfaceArray);<br>
> > > +<br>
> > > +       exit_from_ns(c, &old_netns, &new_netns);<br>
> > > +<br>
> > > +       /* Append NULL to the array */<br>
> > > +       interfaces = (char **)lxc_append_null_to_array((void<br>
> > **)interfaces, count);<br>
> > > +<br>
> > > +       return interfaces;<br>
> > > +}<br>
> > > +<br>
> > > +static char** lxcapi_get_ips(struct lxc_container *c, char* interface,<br>
> > char* family, int scope)<br>
> > > +{<br>
> > > +     int count = 0;<br>
> > > +     struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;<br>
> > > +     char addressOutputBuffer[INET6_ADDRSTRLEN];<br>
> > > +     void *tempAddrPtr = NULL;<br>
> > > +     char **addresses = NULL, **temp;<br>
> > > +     char *address = NULL;<br>
> > > +     int old_netns = -1, new_netns = -1;<br>
> > > +<br>
> > > +     if (!enter_to_ns(c, &old_netns, &new_netns))<br>
> > > +             goto out;<br>
> > ><br>
> > >       /* Grab the list of interfaces */<br>
> > >       if (getifaddrs(&interfaceArray)) {<br>
> > > @@ -1265,28 +1343,10 @@ out:<br>
> > >       if(interfaceArray)<br>
> > >               freeifaddrs(interfaceArray);<br>
> > ><br>
> > > -     /* Switch back to original netns */<br>
> > > -     if (old_netns >= 0 && setns(old_netns, CLONE_NEWNET))<br>
> > > -             SYSERROR("failed to setns");<br>
> > > -     if (new_netns >= 0)<br>
> > > -             close(new_netns);<br>
> > > -     if (old_netns >= 0)<br>
> > > -             close(old_netns);<br>
> > > +     exit_from_ns(c, &old_netns, &new_netns);<br>
> > ><br>
> > >       /* Append NULL to the array */<br>
> > > -     if (count) {<br>
> > > -             count++;<br>
> > > -             temp = realloc(addresses, count * sizeof(*addresses));<br>
> > > -             if (!temp) {<br>
> > > -                     int i;<br>
> > > -                     for (i = 0; i < count-1; i++)<br>
> > > -                             free(addresses[i]);<br>
> > > -                     free(addresses);<br>
> > > -                     return NULL;<br>
> > > -             }<br>
> > > -             addresses = temp;<br>
> > > -             addresses[count - 1] = NULL;<br>
> > > -     }<br>
> > > +     addresses = (char **)lxc_append_null_to_array((void **)addresses,<br>
> > count);<br>
> > ><br>
> > >       return addresses;<br>
> > >  }<br>
> > > @@ -2576,6 +2636,7 @@ struct lxc_container *lxc_container_new(const char<br>
> > *name, const char *configpath<br>
> > >       c->get_config_path = lxcapi_get_config_path;<br>
> > >       c->set_config_path = lxcapi_set_config_path;<br>
> > >       c->clone = lxcapi_clone;<br>
> > > +     c->get_interfaces = lxcapi_get_interfaces;<br>
> > >       c->get_ips = lxcapi_get_ips;<br>
> > >       c->attach = lxcapi_attach;<br>
> > >       c->attach_run_wait = lxcapi_attach_run_wait;<br>
> > > diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h<br>
> > > index f9ae43b..89b55bd 100644<br>
> > > --- a/src/lxc/lxccontainer.h<br>
> > > +++ b/src/lxc/lxccontainer.h<br>
> > > @@ -90,6 +90,9 @@ struct lxc_container {<br>
> > >        * the length which was our would be printed. */<br>
> > >       int (*get_config_item)(struct lxc_container *c, const char *key,<br>
> > char *retv, int inlen);<br>
> > >       int (*get_keys)(struct lxc_container *c, const char *key, char<br>
> > *retv, int inlen);<br>
> > > +     // Return interface names.  The result is strdup()d, so free the<br>
> > result.<br>
> > > +     char** (*get_interfaces)(struct lxc_container *c);<br>
> > > +     // Return IP addresses.  The result is strdup()d, so free the<br>
> > result.<br>
> > >       char** (*get_ips)(struct lxc_container *c, char* interface, char*<br>
> > family, int scope);<br>
> > >       /*<br>
> > >        * get_cgroup_item returns the number of bytes read, or an error<br>
> > (<0).<br>
> > > diff --git a/src/lxc/utils.c b/src/lxc/utils.c<br>
> > > index 78b234d..924cc19 100644<br>
> > > --- a/src/lxc/utils.c<br>
> > > +++ b/src/lxc/utils.c<br>
> > > @@ -852,7 +852,7 @@ int lxc_write_to_file(const char *filename, const<br>
> > void* buf, size_t count, bool<br>
> > >               return -1;<br>
> > >       ret = lxc_write_nointr(fd, buf, count);<br>
> > >       if (ret < 0)<br>
> > > -             goto out_error;<br>
> > > +             goto out_error;<br>
> > >       if ((size_t)ret != count)<br>
> > >               goto out_error;<br>
> > >       if (add_newline) {<br>
> > > @@ -899,3 +899,23 @@ int lxc_read_from_file(const char *filename, void*<br>
> > buf, size_t count)<br>
> > >       errno = saved_errno;<br>
> > >       return ret;<br>
> > >  }<br>
> > > +<br>
> > > +void **lxc_append_null_to_array(void **array, size_t count)<br>
> > > +{<br>
> > > +     void **temp;<br>
> > > +<br>
> > > +     /* Append NULL to the array */<br>
> > > +     if (count) {<br>
> > > +             temp = realloc(array, (count + 1) * sizeof(*array));<br>
> > > +             if (!temp) {<br>
> > > +                     int i;<br>
> > > +                     for (i = 0; i < count; i++)<br>
> > > +                             free(array[i]);<br>
> > > +                     free(array);<br>
> > > +                     return NULL;<br>
> > > +             }<br>
> > > +             array = temp;<br>
> > > +             array[count] = NULL;<br>
> > > +     }<br>
> > > +     return array;<br>
> > > +}<br>
> > > diff --git a/src/lxc/utils.h b/src/lxc/utils.h<br>
> > > index ba7cfb3..55f98fa 100644<br>
> > > --- a/src/lxc/utils.h<br>
> > > +++ b/src/lxc/utils.h<br>
> > > @@ -236,4 +236,5 @@ extern void lxc_free_array(void **array, lxc_free_fn<br>
> > element_free_fn);<br>
> > >  extern size_t lxc_array_len(void **array);<br>
> > >  extern void **lxc_dup_array(void **array, lxc_dup_fn element_dup_fn,<br>
> > lxc_free_fn element_free_fn);<br>
> > ><br>
> > > +extern void **lxc_append_null_to_array(void **array, size_t count);<br>
> > >  #endif<br>
> > > diff --git a/src/python-lxc/examples/api_test.py<br>
> > b/src/python-lxc/examples/api_test.py<br>
> > > index e078d2b..4754332 100644<br>
> > > --- a/src/python-lxc/examples/api_test.py<br>
> > > +++ b/src/python-lxc/examples/api_test.py<br>
> > > @@ -89,6 +89,11 @@ assert(container.init_pid > 1)<br>
> > >  assert(container.running)<br>
> > >  assert(container.state == "RUNNING")<br>
> > ><br>
> > > +<br>
> > > +## Checking IP address<br>
> > > +print("Getting the interface names")<br>
> > > +assert(container.get_interfaces() == ('lo', 'eth0'))<br>
> > > +<br>
> > >  ## Checking IP address<br>
> > >  print("Getting the IP addresses")<br>
> > ><br>
> > > diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c<br>
> > > index bd053a7..b6e0804 100644<br>
> > > --- a/src/python-lxc/lxc.c<br>
> > > +++ b/src/python-lxc/lxc.c<br>
> > > @@ -411,6 +411,52 @@ Container_get_keys(Container *self, PyObject *args,<br>
> > PyObject *kwds)<br>
> > >  }<br>
> > ><br>
> > >  static PyObject *<br>
> > > +Container_get_interfaces(Container *self)<br>
> > > +{<br>
> > > +    int i = 0;<br>
> > > +    char** interfaces = NULL;<br>
> > > +<br>
> > > +    PyObject* ret;<br>
> > > +<br>
> > > +    /* Get the interfaces */<br>
> > > +    interfaces = self->container->get_interfaces(self->container);<br>
> > > +    if (!interfaces)<br>
> > > +        return PyTuple_New(0);<br>
> > > +<br>
> > > +    /* Count the entries */<br>
> > > +    while (interfaces[i])<br>
> > > +        i++;<br>
> > > +<br>
> > > +    /* Create the new tuple */<br>
> > > +    ret = PyTuple_New(i);<br>
> > > +    if (!ret)<br>
> > > +        return NULL;<br>
> > > +<br>
> > > +    /* Add the entries to the tuple and free the memory */<br>
> > > +    i = 0;<br>
> > > +    while (interfaces[i]) {<br>
> > > +        PyObject *unicode = PyUnicode_FromString(interfaces[i]);<br>
> > > +        if (!unicode) {<br>
> > > +            Py_DECREF(ret);<br>
> > > +            ret = NULL;<br>
> > > +            break;<br>
> > > +        }<br>
> > > +        PyTuple_SET_ITEM(ret, i, unicode);<br>
> > > +        i++;<br>
> > > +    }<br>
> > > +<br>
> > > +    /* Free the list of IPs */<br>
> > > +    i = 0;<br>
> > > +    while (interfaces[i]) {<br>
> > > +        free(interfaces[i]);<br>
> > > +        i++;<br>
> > > +    }<br>
> > > +    free(interfaces);<br>
> > > +<br>
> > > +    return ret;<br>
> > > +}<br>
> > > +<br>
> > > +static PyObject *<br>
> > >  Container_get_ips(Container *self, PyObject *args, PyObject *kwds)<br>
> > >  {<br>
> > >      static char *kwlist[] = {"interface", "family", "scope", NULL};<br>
> > > @@ -898,15 +944,15 @@ LXC_arch_to_personality(PyObject *self, PyObject<br>
> > *arg)<br>
> > >          PyErr_SetString(PyExc_ValueError, "Expected a string");<br>
> > >          return NULL;<br>
> > >      }<br>
> > > -<br>
> > > +<br>
> > >      pystr = PyUnicode_AsUTF8String(arg);<br>
> > >      if (!pystr)<br>
> > >          return NULL;<br>
> > > -<br>
> > > +<br>
> > >      str = PyBytes_AsString(pystr);<br>
> > >      if (!str)<br>
> > >          goto out;<br>
> > > -<br>
> > > +<br>
> > >      rv = lxc_config_parse_arch(str);<br>
> > >      if (rv == -1)<br>
> > >          PyErr_SetString(PyExc_KeyError, "Failed to lookup<br>
> > architecture.");<br>
> > > @@ -1025,6 +1071,12 @@ static PyMethodDef Container_methods[] = {<br>
> > >       "\n"<br>
> > >       "Get a list of valid sub-keys for a key."<br>
> > >      },<br>
> > > +    {"get_interfaces", (PyCFunction)Container_get_interfaces,<br>
> > > +     METH_NOARGS,<br>
> > > +     "get_interface() -> tuple\n"<br>
> > > +     "\n"<br>
> > > +     "Get a tuple of interfaces for the container."<br>
> > > +    },<br>
> > >      {"get_ips", (PyCFunction)Container_get_ips,<br>
> > >       METH_VARARGS|METH_KEYWORDS,<br>
> > >       "get_ips(interface, family, scope) -> tuple\n"<br>
> > > @@ -1205,7 +1257,7 @@ PyInit__lxc(void)<br>
> > ><br>
> > >      /* add constants */<br>
> > >      d = PyModule_GetDict(m);<br>
> > > -<br>
> > > +<br>
> > >      #define PYLXC_EXPORT_CONST(c) PyDict_SetItemString(d, #c,<br>
> > PyLong_FromLong(c))<br>
> > ><br>
> > >      /* environment variable handling */<br>
> > > diff --git a/src/python-lxc/lxc/__init__.py<br>
> > b/src/python-lxc/lxc/__init__.py<br>
> > > index 3fb76dc..6a29903 100644<br>
> > > --- a/src/python-lxc/lxc/__init__.py<br>
> > > +++ b/src/python-lxc/lxc/__init__.py<br>
> > > @@ -333,6 +333,14 @@ class Container(_lxc.Container):<br>
> > >          else:<br>
> > >              return value<br>
> > ><br>
> > > +    def get_interfaces(self):<br>
> > > +        """<br>
> > > +            Get a tuple of interfaces for the container.<br>
> > > +        """<br>
> > > +<br>
> > > +        return _lxc.Container.get_interfaces(self)<br>
> > > +<br>
> > > +<br>
> > >      def get_ips(self, interface=None, family=None, scope=None,<br>
> > timeout=0):<br>
> > >          """<br>
> > >              Get a tuple of IPs for the container.<br>
> > > --<br>
> > > 1.8.1.2<br>
> > ><br>
> > ><br>
> > ><br>
> > ------------------------------------------------------------------------------<br>
> > > LIMITED TIME SALE - Full Year of Microsoft Training For Just $49.99!<br>
> > > 1,500+ hours of tutorials including VisualStudio 2012, Windows 8,<br>
> > SharePoint<br>
> > > 2013, SQL 2012, MVC 4, more. BEST VALUE: New Multi-Library Power Pack<br>
> > includes<br>
> > > Mobile, Cloud, Java, and UX Design. Lowest price ever! Ends 9/20/13.<br>
> > ><br>
> > <a href="http://pubads.g.doubleclick.net/gampad/clk?id=58041151&iu=/4140/ostg.clktrk" target="_blank">http://pubads.g.doubleclick.net/gampad/clk?id=58041151&iu=/4140/ostg.clktrk</a><br>
> > > _______________________________________________<br>
> > > Lxc-devel mailing list<br>
> > > <a href="mailto:Lxc-devel@lists.sourceforge.net">Lxc-devel@lists.sourceforge.net</a><br>
> > > <a href="https://lists.sourceforge.net/lists/listinfo/lxc-devel" target="_blank">https://lists.sourceforge.net/lists/listinfo/lxc-devel</a><br>
> ><br>
> > --<br>
> > Stéphane Graber<br>
> > Ubuntu developer<br>
> > <a href="http://www.ubuntu.com" target="_blank">http://www.ubuntu.com</a><br>
> ><br>
><br>
><br>
><br>
> --<br>
> S.Çağlar Onur <<a href="mailto:caglar@10ur.org">caglar@10ur.org</a>><br>
<br>
--<br>
Stéphane Graber<br>
Ubuntu developer<br>
<a href="http://www.ubuntu.com" target="_blank">http://www.ubuntu.com</a><br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br>S.Çağlar Onur <<a href="mailto:caglar@10ur.org">caglar@10ur.org</a>>
</div>