mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 05:03:17 +00:00
Add get_interfaces to the API
get_ips accepts an interface name as a parameter but there was no way to get the interfaces names from the container. This patch introduces a new get_interfaces call to the API so that users can obtain the name of the interfaces. Support for python bindings also introduced as a part of this version. Signed-off-by: S.Çağlar Onur <caglar@10ur.org> Acked-by: Stéphane Graber <stgraber@ubuntu.com>
This commit is contained in:
parent
025ed0f391
commit
799f29ab69
@ -1179,25 +1179,30 @@ static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key)
|
|||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, int scope)
|
static inline void exit_from_ns(struct lxc_container *c, int *old_netns, int *new_netns) {
|
||||||
{
|
/* Switch back to original netns */
|
||||||
int count = 0;
|
if (*old_netns >= 0 && setns(*old_netns, CLONE_NEWNET))
|
||||||
struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
|
SYSERROR("failed to setns");
|
||||||
char addressOutputBuffer[INET6_ADDRSTRLEN];
|
process_lock();
|
||||||
void *tempAddrPtr = NULL;
|
if (*new_netns >= 0)
|
||||||
char **addresses = NULL, **temp;
|
close(*new_netns);
|
||||||
char *address = NULL;
|
if (*old_netns >= 0)
|
||||||
|
close(*old_netns);
|
||||||
|
process_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool enter_to_ns(struct lxc_container *c, int *old_netns, int *new_netns) {
|
||||||
|
int ret = 0;
|
||||||
char new_netns_path[MAXPATHLEN];
|
char new_netns_path[MAXPATHLEN];
|
||||||
int old_netns = -1, new_netns = -1, ret = 0;
|
|
||||||
|
|
||||||
if (!c->is_running(c))
|
if (!c->is_running(c))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Save reference to old netns */
|
/* Save reference to old netns */
|
||||||
process_lock();
|
process_lock();
|
||||||
old_netns = open("/proc/self/ns/net", O_RDONLY);
|
*old_netns = open("/proc/self/ns/net", O_RDONLY);
|
||||||
process_unlock();
|
process_unlock();
|
||||||
if (old_netns < 0) {
|
if (*old_netns < 0) {
|
||||||
SYSERROR("failed to open /proc/self/ns/net");
|
SYSERROR("failed to open /proc/self/ns/net");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1208,17 +1213,92 @@ char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, in
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
process_lock();
|
process_lock();
|
||||||
new_netns = open(new_netns_path, O_RDONLY);
|
*new_netns = open(new_netns_path, O_RDONLY);
|
||||||
process_unlock();
|
process_unlock();
|
||||||
if (new_netns < 0) {
|
if (*new_netns < 0) {
|
||||||
SYSERROR("failed to open %s", new_netns_path);
|
SYSERROR("failed to open %s", new_netns_path);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setns(new_netns, CLONE_NEWNET)) {
|
if (setns(*new_netns, CLONE_NEWNET)) {
|
||||||
SYSERROR("failed to setns");
|
SYSERROR("failed to setns");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
out:
|
||||||
|
exit_from_ns(c, old_netns, new_netns);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char** lxcapi_get_interfaces(struct lxc_container *c)
|
||||||
|
{
|
||||||
|
int count = 0, i;
|
||||||
|
bool found = false;
|
||||||
|
struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
|
||||||
|
char **interfaces = NULL, **temp;
|
||||||
|
int old_netns = -1, new_netns = -1;
|
||||||
|
|
||||||
|
if (!enter_to_ns(c, &old_netns, &new_netns))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Grab the list of interfaces */
|
||||||
|
if (getifaddrs(&interfaceArray)) {
|
||||||
|
SYSERROR("failed to get interfaces list");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate through the interfaces */
|
||||||
|
for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
|
||||||
|
/*
|
||||||
|
* WARNING: Following "for" loop does a linear search over the interfaces array
|
||||||
|
* For the containers with lots of interfaces this may be problematic.
|
||||||
|
* I'm not expecting this to be the common usage but if it turns out to be
|
||||||
|
* than using binary search or a hash table could be more elegant solution.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (strcmp(interfaces[i], tempIfAddr->ifa_name) == 0) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
count += 1;
|
||||||
|
temp = realloc(interfaces, count * sizeof(*interfaces));
|
||||||
|
if (!temp) {
|
||||||
|
count -= 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
interfaces = temp;
|
||||||
|
interfaces[count - 1] = strdup(tempIfAddr->ifa_name);
|
||||||
|
}
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (interfaceArray)
|
||||||
|
freeifaddrs(interfaceArray);
|
||||||
|
|
||||||
|
exit_from_ns(c, &old_netns, &new_netns);
|
||||||
|
|
||||||
|
/* Append NULL to the array */
|
||||||
|
interfaces = (char **)lxc_append_null_to_array((void **)interfaces, count);
|
||||||
|
|
||||||
|
return interfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, int scope)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
|
||||||
|
char addressOutputBuffer[INET6_ADDRSTRLEN];
|
||||||
|
void *tempAddrPtr = NULL;
|
||||||
|
char **addresses = NULL, **temp;
|
||||||
|
char *address = NULL;
|
||||||
|
int old_netns = -1, new_netns = -1;
|
||||||
|
|
||||||
|
if (!enter_to_ns(c, &old_netns, &new_netns))
|
||||||
|
goto out;
|
||||||
|
|
||||||
/* Grab the list of interfaces */
|
/* Grab the list of interfaces */
|
||||||
if (getifaddrs(&interfaceArray)) {
|
if (getifaddrs(&interfaceArray)) {
|
||||||
@ -1269,30 +1349,10 @@ out:
|
|||||||
if(interfaceArray)
|
if(interfaceArray)
|
||||||
freeifaddrs(interfaceArray);
|
freeifaddrs(interfaceArray);
|
||||||
|
|
||||||
/* Switch back to original netns */
|
exit_from_ns(c, &old_netns, &new_netns);
|
||||||
if (old_netns >= 0 && setns(old_netns, CLONE_NEWNET))
|
|
||||||
SYSERROR("failed to setns");
|
|
||||||
process_lock();
|
|
||||||
if (new_netns >= 0)
|
|
||||||
close(new_netns);
|
|
||||||
if (old_netns >= 0)
|
|
||||||
close(old_netns);
|
|
||||||
process_unlock();
|
|
||||||
|
|
||||||
/* Append NULL to the array */
|
/* Append NULL to the array */
|
||||||
if (count) {
|
addresses = (char **)lxc_append_null_to_array((void **)addresses, count);
|
||||||
count++;
|
|
||||||
temp = realloc(addresses, count * sizeof(*addresses));
|
|
||||||
if (!temp) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < count-1; i++)
|
|
||||||
free(addresses[i]);
|
|
||||||
free(addresses);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
addresses = temp;
|
|
||||||
addresses[count - 1] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
@ -2642,6 +2702,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
|
|||||||
c->get_config_path = lxcapi_get_config_path;
|
c->get_config_path = lxcapi_get_config_path;
|
||||||
c->set_config_path = lxcapi_set_config_path;
|
c->set_config_path = lxcapi_set_config_path;
|
||||||
c->clone = lxcapi_clone;
|
c->clone = lxcapi_clone;
|
||||||
|
c->get_interfaces = lxcapi_get_interfaces;
|
||||||
c->get_ips = lxcapi_get_ips;
|
c->get_ips = lxcapi_get_ips;
|
||||||
c->attach = lxcapi_attach;
|
c->attach = lxcapi_attach;
|
||||||
c->attach_run_wait = lxcapi_attach_run_wait;
|
c->attach_run_wait = lxcapi_attach_run_wait;
|
||||||
|
@ -90,6 +90,9 @@ struct lxc_container {
|
|||||||
* the length which was our would be printed. */
|
* the length which was our would be printed. */
|
||||||
int (*get_config_item)(struct lxc_container *c, const char *key, char *retv, int inlen);
|
int (*get_config_item)(struct lxc_container *c, const char *key, char *retv, int inlen);
|
||||||
int (*get_keys)(struct lxc_container *c, const char *key, char *retv, int inlen);
|
int (*get_keys)(struct lxc_container *c, const char *key, char *retv, int inlen);
|
||||||
|
// Return interface names. The result is strdup()d, so free the result.
|
||||||
|
char** (*get_interfaces)(struct lxc_container *c);
|
||||||
|
// Return IP addresses. The result is strdup()d, so free the result.
|
||||||
char** (*get_ips)(struct lxc_container *c, char* interface, char* family, int scope);
|
char** (*get_ips)(struct lxc_container *c, char* interface, char* family, int scope);
|
||||||
/*
|
/*
|
||||||
* get_cgroup_item returns the number of bytes read, or an error (<0).
|
* get_cgroup_item returns the number of bytes read, or an error (<0).
|
||||||
|
@ -935,3 +935,23 @@ int lxc_read_from_file(const char *filename, void* buf, size_t count)
|
|||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void **lxc_append_null_to_array(void **array, size_t count)
|
||||||
|
{
|
||||||
|
void **temp;
|
||||||
|
|
||||||
|
/* Append NULL to the array */
|
||||||
|
if (count) {
|
||||||
|
temp = realloc(array, (count + 1) * sizeof(*array));
|
||||||
|
if (!temp) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
free(array[i]);
|
||||||
|
free(array);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
array = temp;
|
||||||
|
array[count] = NULL;
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
@ -236,4 +236,5 @@ extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
|
|||||||
extern size_t lxc_array_len(void **array);
|
extern size_t lxc_array_len(void **array);
|
||||||
extern void **lxc_dup_array(void **array, lxc_dup_fn element_dup_fn, lxc_free_fn element_free_fn);
|
extern void **lxc_dup_array(void **array, lxc_dup_fn element_dup_fn, lxc_free_fn element_free_fn);
|
||||||
|
|
||||||
|
extern void **lxc_append_null_to_array(void **array, size_t count);
|
||||||
#endif
|
#endif
|
||||||
|
@ -89,6 +89,11 @@ assert(container.init_pid > 1)
|
|||||||
assert(container.running)
|
assert(container.running)
|
||||||
assert(container.state == "RUNNING")
|
assert(container.state == "RUNNING")
|
||||||
|
|
||||||
|
|
||||||
|
## Checking IP address
|
||||||
|
print("Getting the interface names")
|
||||||
|
assert(container.get_interfaces() == ('lo', 'eth0'))
|
||||||
|
|
||||||
## Checking IP address
|
## Checking IP address
|
||||||
print("Getting the IP addresses")
|
print("Getting the IP addresses")
|
||||||
|
|
||||||
|
@ -410,6 +410,52 @@ Container_get_keys(Container *self, PyObject *args, PyObject *kwds)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
Container_get_interfaces(Container *self)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
char** interfaces = NULL;
|
||||||
|
|
||||||
|
PyObject* ret;
|
||||||
|
|
||||||
|
/* Get the interfaces */
|
||||||
|
interfaces = self->container->get_interfaces(self->container);
|
||||||
|
if (!interfaces)
|
||||||
|
return PyTuple_New(0);
|
||||||
|
|
||||||
|
/* Count the entries */
|
||||||
|
while (interfaces[i])
|
||||||
|
i++;
|
||||||
|
|
||||||
|
/* Create the new tuple */
|
||||||
|
ret = PyTuple_New(i);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Add the entries to the tuple and free the memory */
|
||||||
|
i = 0;
|
||||||
|
while (interfaces[i]) {
|
||||||
|
PyObject *unicode = PyUnicode_FromString(interfaces[i]);
|
||||||
|
if (!unicode) {
|
||||||
|
Py_DECREF(ret);
|
||||||
|
ret = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PyTuple_SET_ITEM(ret, i, unicode);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the list of IPs */
|
||||||
|
i = 0;
|
||||||
|
while (interfaces[i]) {
|
||||||
|
free(interfaces[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
free(interfaces);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
Container_get_ips(Container *self, PyObject *args, PyObject *kwds)
|
Container_get_ips(Container *self, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
@ -1025,6 +1071,12 @@ static PyMethodDef Container_methods[] = {
|
|||||||
"\n"
|
"\n"
|
||||||
"Get a list of valid sub-keys for a key."
|
"Get a list of valid sub-keys for a key."
|
||||||
},
|
},
|
||||||
|
{"get_interfaces", (PyCFunction)Container_get_interfaces,
|
||||||
|
METH_NOARGS,
|
||||||
|
"get_interface() -> tuple\n"
|
||||||
|
"\n"
|
||||||
|
"Get a tuple of interfaces for the container."
|
||||||
|
},
|
||||||
{"get_ips", (PyCFunction)Container_get_ips,
|
{"get_ips", (PyCFunction)Container_get_ips,
|
||||||
METH_VARARGS|METH_KEYWORDS,
|
METH_VARARGS|METH_KEYWORDS,
|
||||||
"get_ips(interface, family, scope) -> tuple\n"
|
"get_ips(interface, family, scope) -> tuple\n"
|
||||||
|
@ -333,6 +333,14 @@ class Container(_lxc.Container):
|
|||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def get_interfaces(self):
|
||||||
|
"""
|
||||||
|
Get a tuple of interfaces for the container.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return _lxc.Container.get_interfaces(self)
|
||||||
|
|
||||||
|
|
||||||
def get_ips(self, interface=None, family=None, scope=None, timeout=0):
|
def get_ips(self, interface=None, family=None, scope=None, timeout=0):
|
||||||
"""
|
"""
|
||||||
Get a tuple of IPs for the container.
|
Get a tuple of IPs for the container.
|
||||||
|
Loading…
Reference in New Issue
Block a user