tree-wide: remove lua bindings

parent a9145d62
...@@ -18,7 +18,7 @@ before_install: ...@@ -18,7 +18,7 @@ before_install:
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
- sudo add-apt-repository ppa:ubuntu-lxc/daily -y - sudo add-apt-repository ppa:ubuntu-lxc/daily -y
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev liblua5.2-dev libselinux1-dev - sudo apt-get install -qq libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev libselinux1-dev
script: script:
- ./autogen.sh - ./autogen.sh
- rm -Rf build - rm -Rf build
......
...@@ -13,10 +13,6 @@ EXTRA_DIST = \ ...@@ -13,10 +13,6 @@ EXTRA_DIST = \
RPMARGS = RPMARGS =
if ENABLE_LUA
RPMARGS += --with lua
endif
if ENABLE_PYTHON if ENABLE_PYTHON
RPMARGS += --with python RPMARGS += --with python
endif endif
......
...@@ -416,53 +416,6 @@ m4_ifdef([PKG_CHECK_VAR], [], ...@@ -416,53 +416,6 @@ m4_ifdef([PKG_CHECK_VAR], [],
])# PKG_CHECK_VAR ])# PKG_CHECK_VAR
]) ])
# Lua module and scripts
AC_ARG_ENABLE([lua],
[AC_HELP_STRING([--enable-lua], [enable lua binding [default=auto]])],
[], [enable_lua=auto])
AC_ARG_WITH([lua-pc],
[AS_HELP_STRING(
[--with-lua-pc=PKG],
[Specify pkg-config package name for lua]
)], [], [with_lua_pc=no])
if test "x$enable_lua" = "xyes" -a "x$with_lua_pc" != "xno"; then
# exit with error if not found
PKG_CHECK_MODULES([LUA], [$with_lua_pc], [LUAPKGCONFIG=$with_lua_pc])
fi
if test "x$enable_lua" = "xauto" -a "x$with_lua_pc" != "xno"; then
PKG_CHECK_MODULES([LUA], [$with_lua_pc],
[LUAPKGCONFIG=$with_lua_pc
enable_lua=yes],
[enable_lua=no])
fi
if test "x$enable_lua" != "xno"; then
PKG_CHECK_MODULES([LUA], [lua], [LUAPKGCONFIG=lua],
[PKG_CHECK_MODULES([LUA], [lua5.2], [LUAPKGCONFIG=lua5.2],
[PKG_CHECK_MODULES([LUA], [lua5.1], [LUAPKGCONFIG=lua5.1],
[AS_IF([test "x$enable_lua" = "xyes"],
[AC_MSG_ERROR([Lua not found. Please use --with-lua-pc=PKG])],
[enable_lua=no])]
)]
)])
AS_IF([test "x$LUAPKGCONFIG" != "x"], [enable_lua=yes])
fi
AM_CONDITIONAL([ENABLE_LUA],
[test "x$enable_lua" = "xyes"])
AM_COND_IF([ENABLE_LUA],
[AC_MSG_CHECKING([Lua version])
PKG_CHECK_VAR([LUA_VERSION], [$LUAPKGCONFIG], [V],,
[PKG_CHECK_VAR([LUA_VERSION], [$LUAPKGCONFIG], [major_version])])
AC_MSG_RESULT([$LUA_VERSION])
AC_SUBST([LUA_LIBDIR], [$libdir/lua/$LUA_VERSION])
AC_SUBST([LUA_SHAREDIR], [$datadir/lua/$LUA_VERSION])
])
# Optional bash integration # Optional bash integration
AC_ARG_ENABLE([bash], AC_ARG_ENABLE([bash],
[AC_HELP_STRING([--enable-bash], [build bash integration [default=yes]])], [AC_HELP_STRING([--enable-bash], [build bash integration [default=yes]])],
...@@ -943,8 +896,6 @@ AC_CONFIG_FILES([ ...@@ -943,8 +896,6 @@ AC_CONFIG_FILES([
src/lxc/version.h src/lxc/version.h
src/python-lxc/Makefile src/python-lxc/Makefile
src/lua-lxc/Makefile
src/tests/Makefile src/tests/Makefile
src/tests/lxc-test-usernic src/tests/lxc-test-usernic
]) ])
...@@ -1007,7 +958,6 @@ PAM: ...@@ -1007,7 +958,6 @@ PAM:
- cgroup PAM module: $pamdir - cgroup PAM module: $pamdir
Bindings: Bindings:
- lua: $enable_lua
- python3: $enable_python - python3: $enable_python
Documentation: Documentation:
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
%global with_python %{?_with_python: 1} %{?!_with_python: 0} %global with_python %{?_with_python: 1} %{?!_with_python: 0}
%global with_lua %{?_with_lua: 1} %{?!_with_lua: 0}
# Set with_systemd on distros that use it, so we can install the service # Set with_systemd on distros that use it, so we can install the service
# file, otherwise the sysvinit script will be installed # file, otherwise the sysvinit script will be installed
...@@ -124,23 +123,10 @@ Requires: %{name} = %{version}-%{release}, pkgconfig ...@@ -124,23 +123,10 @@ Requires: %{name} = %{version}-%{release}, pkgconfig
The %{name}-devel package contains header files and library needed for The %{name}-devel package contains header files and library needed for
development of the Linux containers. development of the Linux containers.
%if %{with_lua}
%package lua
Summary: Lua bindings for %{name}
Group: System Environment/Libraries
Requires: lua-filesystem lua-alt-getopt
BuildRequires: lua-devel
%description lua
The %{name}-lua package contains %{name} bindings for lua.
%endif
%prep %prep
%setup -q -n %{name}-%{version}%{?beta_dot} %setup -q -n %{name}-%{version}%{?beta_dot}
%build %build
PATH=$PATH:/usr/sbin:/sbin %configure $args \ PATH=$PATH:/usr/sbin:/sbin %configure $args \
%if %{with_lua}
--enable-lua \
%endif
%if %{with_python} %if %{with_python}
--enable-python \ --enable-python \
%endif %endif
...@@ -284,13 +270,6 @@ fi ...@@ -284,13 +270,6 @@ fi
%{python3_sitearch}/* %{python3_sitearch}/*
%endif %endif
%if %{with_lua}
%files lua
%defattr(-,root,root)
%{_datadir}/lua
%{_libdir}/lua
%endif
%files devel %files devel
%defattr(-,root,root) %defattr(-,root,root)
%{_includedir}/%{name}/* %{_includedir}/%{name}/*
......
SUBDIRS = lxc tests python-lxc lua-lxc SUBDIRS = lxc tests python-lxc
if ENABLE_LUA
luasharedir=$(LUA_SHAREDIR)
lualibdir=$(LUA_LIBDIR)
luadir=$(luasharedir)
sodir=$(lualibdir)/lxc
lua_DATA=lxc.lua
lib_LTLIBRARIES = libcore.la
libcore_la_SOURCES = core.c
AM_CFLAGS=-I$(top_builddir)/src -I$(top_srcdir)/src $(LUA_CFLAGS) -DVERSION=\"$(VERSION)\" -DLXCPATH=\"$(LXCPATH)\"
libcore_la_CFLAGS = -fPIC -DPIC $(AM_CFLAGS)
libcore_la_LDFLAGS = \
-shared \
-L$(top_builddir)/src/lxc \
-Wl,-soname,core.so.$(firstword $(subst ., ,$(VERSION)))
libcore_la_LIBADD = -llxc
install-exec-local: install-libLTLIBRARIES
mkdir -p $(DESTDIR)$(lualibdir)/lxc/
mv $(DESTDIR)$(libdir)/libcore.so.0.0.0 $(DESTDIR)$(lualibdir)/lxc/core.so
rm $(DESTDIR)$(libdir)/libcore.*
uninstall-local:
$(RM) $(DESTDIR)$(lualibdir)/lxc/core.so*
lxc.lua:
endif
EXTRA_DIST= \
lxc.lua \
test/apitest.lua
/*
* lua-lxc: lua bindings for lxc
*
* Copyright © 2012 Oracle.
*
* Authors:
* Dwight Engen <dwight.engen@oracle.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define LUA_LIB
#define _GNU_SOURCE
#include <lua.h>
#include <lauxlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <lxc/lxccontainer.h>
#include "lxc/commands.h"
#if LUA_VERSION_NUM < 502
#define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
#define luaL_setfuncs(L,l,n) (assert(n==0), luaL_register(L,NULL,l))
#define luaL_checkunsigned(L,n) luaL_checknumber(L,n)
#endif
#if LUA_VERSION_NUM >= 503
#ifndef luaL_checkunsigned
#define luaL_checkunsigned(L,n) ((lua_Unsigned)luaL_checkinteger(L,n))
#endif
#endif
#ifdef NO_CHECK_UDATA
#define checkudata(L,i,tname) lua_touserdata(L, i)
#else
#define checkudata(L,i,tname) luaL_checkudata(L, i, tname)
#endif
#define lua_boxpointer(L,u) \
(*(void **) (lua_newuserdata(L, sizeof(void *))) = (u))
#define lua_unboxpointer(L,i,tname) \
(*(void **) (checkudata(L, i, tname)))
#define CONTAINER_TYPENAME "lxc.container"
/* Max Lua arguments for function */
#define MAXVARS 200
static int container_new(lua_State *L)
{
struct lxc_container *c;
const char *name = luaL_checkstring(L, 1);
const char *configpath = NULL;
int argc = lua_gettop(L);
if (argc > 1)
configpath = luaL_checkstring(L, 2);
c = lxc_container_new(name, configpath);
if (c) {
lua_boxpointer(L, c);
luaL_getmetatable(L, CONTAINER_TYPENAME);
lua_setmetatable(L, -2);
} else {
lua_pushnil(L);
}
return 1;
}
static int container_gc(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
/* XXX what to do if this fails? */
lxc_container_put(c);
return 0;
}
static int container_config_file_name(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
char *config_file_name;
config_file_name = c->config_file_name(c);
lua_pushstring(L, config_file_name);
free(config_file_name);
return 1;
}
static int container_defined(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushboolean(L, !!c->is_defined(c));
return 1;
}
static int container_name(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushstring(L, c->name);
return 1;
}
static int container_create(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
char *template_name = strdupa(luaL_checkstring(L, 2));
int argc = lua_gettop(L);
char **argv;
int i;
argv = alloca((argc+1) * sizeof(char *));
for (i = 0; i < argc-2; i++)
argv[i] = strdupa(luaL_checkstring(L, i+3));
argv[i] = NULL;
lua_pushboolean(L, !!c->create(c, template_name, NULL, NULL, 0, argv));
return 1;
}
static int container_destroy(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushboolean(L, !!c->destroy(c));
return 1;
}
/* container state */
static int container_start(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
int argc = lua_gettop(L);
char **argv = NULL;
int i,j;
int useinit = 0;
if (argc > 1) {
argv = alloca((argc+1) * sizeof(char *));
for (i = 0, j = 0; i < argc-1; i++) {
const char *arg = luaL_checkstring(L, i+2);
if (!strcmp(arg, "useinit"))
useinit = 1;
else
argv[j++] = strdupa(arg);
}
argv[j] = NULL;
}
c->want_daemonize(c, true);
lua_pushboolean(L, !!c->start(c, useinit, argv));
return 1;
}
static int container_stop(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushboolean(L, !!c->stop(c));
return 1;
}
static int container_shutdown(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
int timeout = luaL_checkinteger(L, 2);
lua_pushboolean(L, !!c->shutdown(c, timeout));
return 1;
}
static int container_wait(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *state = luaL_checkstring(L, 2);
int timeout = luaL_checkinteger(L, 3);
lua_pushboolean(L, !!c->wait(c, state, timeout));
return 1;
}
static int container_rename(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *new_name;
int argc = lua_gettop(L);
if (argc > 1) {
new_name = luaL_checkstring(L, 2);
lua_pushboolean(L, !!c->rename(c, new_name));
} else
lua_pushnil(L);
return 1;
}
static int container_freeze(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushboolean(L, !!c->freeze(c));
return 1;
}
static int container_unfreeze(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushboolean(L, !!c->unfreeze(c));
return 1;
}
static int container_running(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushboolean(L, !!c->is_running(c));
return 1;
}
static int container_state(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushstring(L, c->state(c));
return 1;
}
static int container_init_pid(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
lua_pushinteger(L, c->init_pid(c));
return 1;
}
/* configuration file methods */
static int container_load_config(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
int arg_cnt = lua_gettop(L);
const char *alt_path = NULL;
if (arg_cnt > 1)
alt_path = luaL_checkstring(L, 2);
lua_pushboolean(L, !!c->load_config(c, alt_path));
return 1;
}
static int container_save_config(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
int arg_cnt = lua_gettop(L);
const char *alt_path = NULL;
if (arg_cnt > 1)
alt_path = luaL_checkstring(L, 2);
lua_pushboolean(L, !!c->save_config(c, alt_path));
return 1;
}
static int container_get_config_path(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *config_path;
config_path = c->get_config_path(c);
lua_pushstring(L, config_path);
return 1;
}
static int container_set_config_path(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *config_path = luaL_checkstring(L, 2);
lua_pushboolean(L, !!c->set_config_path(c, config_path));
return 1;
}
static int container_clear_config_item(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *key = luaL_checkstring(L, 2);
lua_pushboolean(L, !!c->clear_config_item(c, key));
return 1;
}
static int container_get_cgroup_item(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *key = luaL_checkstring(L, 2);
int len;
char *value;
len = c->get_cgroup_item(c, key, NULL, 0);
if (len <= 0)
goto not_found;
value = alloca(sizeof(char)*len + 1);
if (c->get_cgroup_item(c, key, value, len + 1) != len)
goto not_found;
lua_pushstring(L, value);
return 1;
not_found:
lua_pushnil(L);
return 1;
}
static int container_get_config_item(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *key = luaL_checkstring(L, 2);
int len;
char *value;
len = c->get_config_item(c, key, NULL, 0);
if (len <= 0)
goto not_found;
value = alloca(sizeof(char)*len + 1);
if (c->get_config_item(c, key, value, len + 1) != len)
goto not_found;
lua_pushstring(L, value);
return 1;
not_found:
lua_pushnil(L);
return 1;
}
static int container_set_cgroup_item(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *key = luaL_checkstring(L, 2);
const char *value = luaL_checkstring(L, 3);
lua_pushboolean(L, !!c->set_cgroup_item(c, key, value));
return 1;
}
static int container_set_config_item(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *key = luaL_checkstring(L, 2);
const char *value = luaL_checkstring(L, 3);
lua_pushboolean(L, !!c->set_config_item(c, key, value));
return 1;
}
static int container_get_keys(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
const char *key = NULL;
int len;
char *value;
int arg_cnt = lua_gettop(L);
if (arg_cnt > 1)
key = luaL_checkstring(L, 2);
len = c->get_keys(c, key, NULL, 0);
if (len <= 0)
goto not_found;
value = alloca(sizeof(char)*len + 1);
if (c->get_keys(c, key, value, len + 1) != len)
goto not_found;
lua_pushstring(L, value);
return 1;
not_found:
lua_pushnil(L);
return 1;
}
static int container_attach(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
int argc = lua_gettop(L);
char **argv = NULL;
int i;
if (argc > 1) {
argv = alloca((argc+1) * sizeof(char *));
for (i = 0; i < argc-1; i++) {
const char *arg = luaL_checkstring(L, i+2);
argv[i] = strdupa(arg);
}
argv[i] = NULL;
}
else
{
lua_pushnil(L);
return 1;
}
lua_pushboolean(L, !(c->attach_run_wait(c, NULL, argv[0], (const char**)argv)));
return 1;
}
static int container_get_interfaces(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
char **ifaces;
int i;
ifaces = c->get_interfaces(c);
if (!ifaces){
lua_pushnil(L);
return 1;
}
for (i = 0; ifaces[i]; i++);
/* protect LUA stack form overflow */
if (i > MAXVARS || !lua_checkstack(L, i)){
for (i = 0; ifaces[i]; i++)
free(ifaces[i]);
lua_pushnil(L);
return 1;
}
for (i = 0; ifaces[i]; i++){
lua_pushstring(L, ifaces[i]);
free(ifaces[i]);
}
return i;
}
static int container_get_ips(lua_State *L)
{
struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
int argc = lua_gettop(L);
char **addresses;
char *iface = NULL, *family = NULL;
int i, scope = 0;
if (argc > 1)
iface = (char *)luaL_checkstring(L, 2);
if (argc > 2)
family = (char *)luaL_checkstring(L, 3);
if (argc > 3)
scope = luaL_checkinteger(L, 4);
addresses = c->get_ips(c, iface, family, scope);
if (!addresses){
lua_pushnil(L);
return 1;
}
for (i = 0; addresses[i]; i++);
/* protect LUA stack form overflow */
if (i > MAXVARS || !lua_checkstack(L, i)){
for (i = 0; addresses[i]; i++)
free(addresses[i]);
lua_pushnil(L);
return 1;
}
for (i = 0; addresses[i]; i++){
lua_pushstring(L, addresses[i]);
free(addresses[i]);
}
return i;
}
static luaL_Reg lxc_container_methods[] =
{
{"attach", container_attach},
{"create", container_create},
{"defined", container_defined},
{"destroy", container_destroy},
{"init_pid", container_init_pid},
{"name", container_name},
{"running", container_running},
{"state", container_state},
{"freeze", container_freeze},
{"unfreeze", container_unfreeze},
{"start", container_start},
{"stop", container_stop},
{"shutdown", container_shutdown},
{"wait", container_wait},
{"rename", container_rename},
{"config_file_name", container_config_file_name},
{"load_config", container_load_config},
{"save_config", container_save_config},
{"get_cgroup_item", container_get_cgroup_item},
{"set_cgroup_item", container_set_cgroup_item},
{"get_config_path", container_get_config_path},
{"set_config_path", container_set_config_path},
{"get_config_item", container_get_config_item},
{"set_config_item", container_set_config_item},
{"clear_config_item", container_clear_config_item},
{"get_keys", container_get_keys},
{"get_interfaces", container_get_interfaces},
{"get_ips", container_get_ips},
{NULL, NULL}
};
static int lxc_version_get(lua_State *L) {
lua_pushstring(L, VERSION);
return 1;
}
static int lxc_default_config_path_get(lua_State *L) {
const char *lxcpath = lxc_get_global_config_item("lxc.lxcpath");
lua_pushstring(L, lxcpath);
return 1;
}
static int cmd_get_config_item(lua_State *L)
{
int arg_cnt = lua_gettop(L);
const char *name = luaL_checkstring(L, 1);
const char *key = luaL_checkstring(L, 2);
const char *lxcpath = NULL;
char *value;
if (arg_cnt > 2)
lxcpath = luaL_checkstring(L, 3);
value = lxc_cmd_get_config_item(name, key, lxcpath);
if (!value)
goto not_found;
lua_pushstring(L, value);
return 1;
not_found:
lua_pushnil(L);
return 1;
}
/* utility functions */
static int lxc_util_usleep(lua_State *L) {
usleep((useconds_t)luaL_checkunsigned(L, 1));
return 0;
}
static int lxc_util_dirname(lua_State *L) {
char *path = strdupa(luaL_checkstring(L, 1));
lua_pushstring(L, dirname(path));
return 1;
}
static luaL_Reg lxc_lib_methods[] = {
{"version_get", lxc_version_get},
{"default_config_path_get", lxc_default_config_path_get},
{"cmd_get_config_item", cmd_get_config_item},
{"container_new", container_new},
{"usleep", lxc_util_usleep},
{"dirname", lxc_util_dirname},
{NULL, NULL}
};
static int lxc_lib_uninit(lua_State *L) {
(void) L;
/* this is where we would fini liblxc.so if we needed to */
return 0;
}
LUALIB_API int luaopen_lxc_core(lua_State *L) {
/* this is where we would initialize liblxc.so if we needed to */
luaL_newlib(L, lxc_lib_methods);
lua_newuserdata(L, 0);
lua_newtable(L); /* metatable */
lua_pushvalue(L, -1);
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, lxc_lib_uninit);
lua_rawset(L, -3);
lua_setmetatable(L, -3);
lua_rawset(L, -3);
luaL_newmetatable(L, CONTAINER_TYPENAME);
luaL_setfuncs(L, lxc_container_methods, 0);
lua_pushvalue(L, -1); /* push metatable */
lua_pushstring(L, "__gc");
lua_pushcfunction(L, container_gc);
lua_settable(L, -3);
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
lua_pop(L, 1);
return 1;
}
--
-- lua lxc module
--
-- Copyright © 2012 Oracle.
--
-- Authors:
-- Dwight Engen <dwight.engen@oracle.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--
local core = require("lxc.core")
local lfs = require("lfs")
local table = require("table")
local string = require("string")
local io = require("io")
module("lxc", package.seeall)
local lxc_path
local log_level = 3
-- lua 5.1 compat
if table.unpack == nil then
table.unpack = unpack
end
-- the following two functions can be useful for debugging
function printf(...)
local function wrapper(...) io.write(string.format(...)) end
local status, result = pcall(wrapper, ...)
if not status then
error(result, 2)
end
end
function log(level, ...)
if (log_level >= level) then
printf(os.date("%Y-%m-%d %T "))
printf(...)
end
end
function string:split(delim, max_cols)
local cols = {}
local start = 1
local nextc
repeat
nextc = string.find(self, delim, start)
if (nextc and #cols ~= max_cols - 1) then
table.insert(cols, string.sub(self, start, nextc-1))
start = nextc + #delim
else
table.insert(cols, string.sub(self, start, string.len(self)))
nextc = nil
end
until nextc == nil or start > #self
return cols
end
-- container class
container = {}
container_mt = {}
container_mt.__index = container
function container:new(lname, config)
local lcore
local lnetcfg = {}
local lstats = {}
if lname then
if config then
lcore = core.container_new(lname, config)
else
lcore = core.container_new(lname)
end
end
return setmetatable({ctname = lname, core = lcore, netcfg = lnetcfg, stats = lstats}, container_mt)
end
-- methods interfacing to core functionality
function container:attach(what, ...)
return self.core:attach(what, ...)
end
function container:config_file_name()
return self.core:config_file_name()
end
function container:defined()
return self.core:defined()
end
function container:init_pid()
return self.core:init_pid()
end
function container:name()
return self.core:name()
end
function container:start()
return self.core:start()
end
function container:stop()
return self.core:stop()
end
function container:shutdown(timeout)
return self.core:shutdown(timeout)
end
function container:wait(state, timeout)
return self.core:wait(state, timeout)
end
function container:freeze()
return self.core:freeze()
end
function container:unfreeze()
return self.core:unfreeze()
end
function container:running()
return self.core:running()
end
function container:state()
return self.core:state()
end
function container:create(template, ...)
return self.core:create(template, ...)
end
function container:destroy()
return self.core:destroy()
end
-- return nil if name missing
function container:rename(name)
return self.core:rename(name)
end
function container:get_config_path()
return self.core:get_config_path()
end
function container:set_config_path(path)
return self.core:set_config_path(path)
end
function container:append_config_item(key, value)
return self.core:set_config_item(key, value)
end
function container:clear_config_item(key)
return self.core:clear_config_item(key)
end
function container:get_cgroup_item(key)
return self.core:get_cgroup_item(key)
end
function container:get_config_item(key)
local value
local vals = {}
value = self.core:get_config_item(key)
-- check if it is a single item
if (not value or not string.find(value, "\n")) then
return value
end
-- it must be a list type item, make a table of it
vals = value:split("\n", 1000)
-- make it a "mixed" table, ie both dictionary and list for ease of use
for _,v in ipairs(vals) do
vals[v] = true
end
return vals
end
function container:set_cgroup_item(key, value)
return self.core:set_cgroup_item(key, value)
end
function container:set_config_item(key, value)
return self.core:set_config_item(key, value)
end
function container:get_keys(base)
local ktab = {}
local keys
if (base) then
keys = self.core:get_keys(base)
base = base .. "."
else
keys = self.core:get_keys()
base = ""
end
if (keys == nil) then
return nil
end
keys = keys:split("\n", 1000)
for _,v in ipairs(keys) do
local config_item = base .. v
ktab[v] = self.core:get_config_item(config_item)
end
return ktab
end
-- return nil or more args
function container:get_interfaces()
return self.core:get_interfaces()
end
-- return nil or more args
function container:get_ips(...)
return self.core:get_ips(...)
end
function container:load_config(alt_path)
if (alt_path) then
return self.core:load_config(alt_path)
else
return self.core:load_config()
end
end
function container:save_config(alt_path)
if (alt_path) then
return self.core:save_config(alt_path)
else
return self.core:save_config()
end
end
-- methods for stats collection from various cgroup files
-- read integers at given coordinates from a cgroup file
function container:stat_get_ints(item, coords)
local lines = {}
local result = {}
local flines = self:get_cgroup_item(item)
if (flines == nil) then
for k,c in ipairs(coords) do
table.insert(result, 0)
end
else
for line in flines:gmatch("[^\r\n]+") do
table.insert(lines, line)
end
for k,c in ipairs(coords) do
local col
col = lines[c[1]]:split(" ", 80)
local val = tonumber(col[c[2]])
table.insert(result, val)
end
end
return table.unpack(result)
end
-- read an integer from a cgroup file
function container:stat_get_int(item)
local line = self:get_cgroup_item(item)
-- if line is nil (on an error like Operation not supported because
-- CONFIG_MEMCG_SWAP_ENABLED isn't enabled) return 0
return tonumber(line) or 0
end
function container:stat_match_get_int(item, match, column)
local val
local lines = self:get_cgroup_item(item)
if (lines == nil) then
return 0
end
for line in lines:gmatch("[^\r\n]+") do
if (string.find(line, match)) then
local col
col = line:split(" ", 80)
val = tonumber(col[column]) or 0
end
end
return val
end
function container:stats_get(total)
local stat = {}
stat.mem_used = self:stat_get_int("memory.usage_in_bytes")
stat.mem_limit = self:stat_get_int("memory.limit_in_bytes")
stat.memsw_used = self:stat_get_int("memory.memsw.usage_in_bytes")
stat.memsw_limit = self:stat_get_int("memory.memsw.limit_in_bytes")
stat.kmem_used = self:stat_get_int("memory.kmem.usage_in_bytes")
stat.kmem_limit = self:stat_get_int("memory.kmem.limit_in_bytes")
stat.cpu_use_nanos = self:stat_get_int("cpuacct.usage")
stat.cpu_use_user,
stat.cpu_use_sys = self:stat_get_ints("cpuacct.stat", {{1, 2}, {2, 2}})
stat.blkio = self:stat_match_get_int("blkio.throttle.io_service_bytes", "Total", 2)
if (total) then
total.mem_used = total.mem_used + stat.mem_used
total.mem_limit = total.mem_limit + stat.mem_limit
total.memsw_used = total.memsw_used + stat.memsw_used
total.memsw_limit = total.memsw_limit + stat.memsw_limit
total.kmem_used = total.kmem_used + stat.kmem_used
total.kmem_limit = total.kmem_limit + stat.kmem_limit
total.cpu_use_nanos = total.cpu_use_nanos + stat.cpu_use_nanos
total.cpu_use_user = total.cpu_use_user + stat.cpu_use_user
total.cpu_use_sys = total.cpu_use_sys + stat.cpu_use_sys
total.blkio = total.blkio + stat.blkio
end
return stat
end
local M = { container = container }
function M.stats_clear(stat)
stat.mem_used = 0
stat.mem_limit = 0
stat.memsw_used = 0
stat.memsw_limit = 0
stat.kmem_used = 0
stat.kmem_limit = 0
stat.cpu_use_nanos = 0
stat.cpu_use_user = 0
stat.cpu_use_sys = 0
stat.blkio = 0
end
-- return configured containers found in LXC_PATH directory
function M.containers_configured(names_only)
local containers = {}
for dir in lfs.dir(lxc_path) do
if (dir ~= "." and dir ~= "..")
then
local cfgfile = lxc_path .. "/" .. dir .. "/config"
local cfgattr = lfs.attributes(cfgfile)
if (cfgattr and cfgattr.mode == "file") then
if (names_only) then
-- note, this is a "mixed" table, ie both dictionary and list
containers[dir] = true
table.insert(containers, dir)
else
local ct = container:new(dir)
-- note, this is a "mixed" table, ie both dictionary and list
containers[dir] = ct
table.insert(containers, dir)
end
end
end
end
table.sort(containers, function (a,b) return (a < b) end)
return containers
end
-- return running containers found in cgroup fs
function M.containers_running(names_only)
local containers = {}
local names = M.containers_configured(true)
for _,name in ipairs(names) do
local ct = container:new(name)
if ct:running() then
-- note, this is a "mixed" table, ie both dictionary and list
table.insert(containers, name)
if (names_only) then
containers[name] = true
ct = nil
else
containers[name] = ct
end
end
end
table.sort(containers, function (a,b) return (a < b) end)
return containers
end
function M.version_get()
return core.version_get()
end
function M.default_config_path_get()
return core.default_config_path_get()
end
function M.cmd_get_config_item(name, item, lxcpath)
if (lxcpath) then
return core.cmd_get_config_item(name, item, lxcpath)
else
return core.cmd_get_config_item(name, item)
end
end
lxc_path = core.default_config_path_get()
return M
#!/usr/bin/env lua
--
-- test the lxc lua api
--
-- Copyright © 2012 Oracle.
--
-- Authors:
-- Dwight Engen <dwight.engen@oracle.com>
--
-- This library is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2, as
-- published by the Free Software Foundation.
--
-- This program 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 General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program; if not, write to the Free Software Foundation, Inc.,
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--
local lxc = require("lxc")
local lfs = require("lfs")
local getopt = require("alt_getopt")
local LXC_PATH = lxc.default_config_path_get()
local container
local cfg_containers = {}
local optarg = {}
local optind = {}
function printf(...)
local function wrapper(...) io.write(string.format(...)) end
local status, result = pcall(wrapper, ...)
if not status then
error(result, 2)
end
end
function log(level, ...)
if (optarg["v"] >= level) then
printf(os.date("%Y-%m-%d %T "))
printf(...)
printf("\n")
end
end
function die(...)
printf(...)
os.exit(1)
end
function test_global_info()
local cfg_containers
local run_containers
log(0, "%-20s %s", "LXC version:", lxc.version_get())
log(0, "%-20s %s", "Container name:", optarg["n"])
if (optarg["c"]) then
log(0, "%-20s %s", "Creating container:", "yes")
log(0, "%-20s %s", "With template:", optarg["t"])
end
log(0, "%-20s %s", "Containers path:", LXC_PATH)
cfg_containers = lxc.containers_configured()
log(0, "%-20s", "Containers configured:")
for _,v in ipairs(cfg_containers) do
log(0, " %s", v)
end
run_containers = lxc.containers_running(true)
log(0, "%-20s", "Containers running:")
for _,v in ipairs(run_containers) do
log(0, " %s", v)
end
end
function test_container_new()
container = lxc.container:new(optarg["n"])
assert(container ~= nil)
assert(container:config_file_name() == string.format("%s/%s/config", LXC_PATH, optarg["n"]))
end
function test_container_config_path()
local cfgcontainer
local cfgpath = "/tmp/" .. optarg["n"]
local cfgname = cfgpath .. "/config"
log(0, "Test container config path...")
-- create a config file in the new location from container's config
assert(lfs.mkdir(cfgpath))
assert(container:save_config(cfgname))
cfgcontainer = lxc.container:new(optarg["n"], "/tmp")
assert(cfgcontainer ~= nil)
log(0, "cfgname:%s cfgpath:%s", cfgcontainer:config_file_name(), cfgcontainer:get_config_path())
assert(cfgcontainer:config_file_name() == cfgname)
assert(cfgcontainer:get_config_path() == "/tmp")
assert(cfgcontainer:set_config_path(LXC_PATH))
assert(cfgcontainer:get_config_path() == LXC_PATH)
assert(os.remove(cfgname))
assert(lfs.rmdir(cfgpath))
end
function test_container_create()
if (optarg["c"]) then
log(0, "%-20s %s", "Destroy existing container:", optarg["n"])
container:destroy()
assert(container:defined() == false)
else
local cfg_containers = lxc.containers_configured()
if (cfg_containers[optarg["n"]]) then
log(0, "%-20s %s", "Use existing container:", optarg["n"])
return
end
end
log(0, "%-20s %s", "Creating rootfs using:", optarg["t"])
assert(container:create(optarg["t"]) == true)
assert(container:defined() == true)
assert(container:name() == optarg["n"])
end
function test_container_started()
local now_running
log(2, "state:%s pid:%d\n", container:state(), container:init_pid())
assert(container:init_pid() > 1)
assert(container:running() == true)
assert(container:state() == "RUNNING")
now_running = lxc.containers_running(true)
assert(now_running[optarg["n"]] ~= nil)
log(1, "%-20s %s", "Running, init pid:", container:init_pid())
end
function test_container_stopped()
local now_running
assert(container:init_pid() == -1)
assert(container:running() == false)
assert(container:state() == "STOPPED")
now_running = lxc.containers_running(true)
assert(now_running[optarg["n"]] == nil)
end
function test_container_frozen()
local now_running
assert(container:init_pid() > 1)
assert(container:running() == true)
assert(container:state() == "FROZEN")
now_running = lxc.containers_running(true)
assert(now_running[optarg["n"]] ~= nil)
end
function test_container_start()
log(0, "Starting...")
if (not container:start()) then
log(1, "Start returned failure, waiting another 10 seconds...")
container:wait("RUNNING", 10)
end
container:wait("RUNNING", 1)
end
function test_container_stop()
log(0, "Stopping...")
if (not container:stop()) then
log(1, "Stop returned failure, waiting another 10 seconds...")
container:wait("STOPPED", 10)
end
container:wait("STOPPED", 1)
end
function test_container_freeze()
log(0, "Freezing...")
if (not container:freeze()) then
log(1, "Freeze returned failure, waiting another 10 seconds...")
container:wait("FROZEN", 10)
end
end
function test_container_unfreeze()
log(0, "Unfreezing...")
if (not container:unfreeze()) then
log(1, "Unfreeze returned failure, waiting another 10 seconds...")
container:wait("RUNNING", 10)
end
end
function test_container_shutdown()
log(0, "Shutting down...")
container:shutdown(5)
if (container:running()) then
test_container_stop()
end
end
function test_container_in_cfglist(should_find)
local cfg_containers = lxc.containers_configured()
if (should_find) then
assert(cfg_containers[container:name()] ~= nil)
else
assert(cfg_containers[container:name()] == nil)
end
end
function test_container_attach()
log(0, "Test attach...")
assert(container:running() == true)
assert(container:attach("/bin/ps") == true)
end
function test_container_cgroup()
log(0, "Test get/set cgroup items...")
max_mem = container:get_cgroup_item("memory.max_usage_in_bytes")
saved_limit = container:get_cgroup_item("memory.limit_in_bytes")
assert(saved_limit ~= max_mem)
assert(container:set_cgroup_item("memory.limit_in_bytes", max_mem))
assert(container:get_cgroup_item("memory.limit_in_bytes") ~= saved_limit)
assert(container:set_cgroup_item("memory.limit_in_bytes", "-1"))
end
function test_container_cmd()
log(0, "Test get config from running container...")
veth_pair = lxc.cmd_get_config_item(optarg["n"], "lxc.net.0.veth.pair")
log(0, " veth.pair:%s", veth_pair)
end
function test_config_items()
log(0, "Test set/clear configuration items...")
-- test setting a 'single type' item
assert(container:get_config_item("lxc.uts.name") == optarg["n"])
container:set_config_item("lxc.uts.name", "foobar")
assert(container:get_config_item("lxc.uts.name") == "foobar")
container:set_config_item("lxc.uts.name", optarg["n"])
assert(container:get_config_item("lxc.uts.name") == optarg["n"])
-- test clearing/setting a 'list type' item
container:clear_config_item("lxc.cap.drop")
container:set_config_item("lxc.cap.drop", "new_cap1")
container:set_config_item("lxc.cap.drop", "new_cap2")
local cap_drop = container:get_config_item("lxc.cap.drop")
assert(cap_drop["new_cap1"] ~= nil)
assert(cap_drop["new_cap2"] ~= nil)
-- note: clear_config_item only works on list type items
container:clear_config_item("lxc.cap.drop")
assert(container:get_config_item("lxc.cap.drop") == nil)
local altname = "/tmp/" .. optarg["n"] .. ".altconfig"
log(0, "Test saving to an alternate (%s) config file...", altname)
assert(container:save_config(altname))
assert(os.remove(altname))
end
function test_config_mount_entries()
local mntents
-- mount entries are a list type item
mntents = container:get_config_item("lxc.mount.entry")
log(0, "Mount entries:")
for _,v in ipairs(mntents) do
log(0, " %s", v)
end
end
function test_config_keys()
local keys
keys = container:get_keys()
log(0, "Top level keys:")
for k,v in pairs(keys) do
log(0, " %s = %s", k, v or "")
end
end
function test_config_network(net_nr)
log(0, "Test network %d config...", net_nr)
local netcfg
netcfg = container:get_keys("lxc.net." .. net_nr)
if (netcfg == nil) then
return
end
for k,v in pairs(netcfg) do
log(0, " %s = %s", k, v or "")
end
assert(netcfg["flags"] == "up")
assert(container:get_config_item("lxc.net."..net_nr..".type") == "veth")
end
function usage()
die("Usage: apitest <options>\n" ..
" -v|--verbose increase verbosity with each -v\n" ..
" -h|--help print help message\n" ..
" -n|--name name of container to use for testing\n" ..
" -c|--create create the test container anew\n" ..
" -l|--login do interactive login test\n" ..
" -t|--template template to use when creating test container\n"
)
end
local long_opts = {
verbose = "v",
help = "h",
name = "n",
create = "c",
template = "t",
}
optarg,optind = alt_getopt.get_opts (arg, "hvn:ct:", long_opts)
optarg["v"] = tonumber(optarg["v"]) or 0
optarg["n"] = optarg["n"] or "lua-apitest"
optarg["c"] = optarg["c"] or nil
optarg["t"] = optarg["t"] or "busybox"
if (optarg["h"] ~= nil) then
usage()
end
test_global_info()
test_container_new()
test_container_create()
test_container_stopped()
test_container_in_cfglist(true)
test_container_config_path()
test_config_items()
test_config_keys()
test_config_mount_entries()
test_config_network(0)
test_container_start()
test_container_started()
test_container_attach()
test_container_cgroup()
test_container_cmd()
test_container_freeze()
test_container_frozen()
test_container_unfreeze()
test_container_started()
test_container_shutdown()
test_container_stopped()
container:destroy()
test_container_in_cfglist(false)
log(0, "All tests passed")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment