class LXC::Container
This class contains methods to manage Linux containers.
Public Class Methods
Creates a new container instance with the given name, under the given configuration path.
static VALUE
container_initialize(int argc, VALUE *argv, VALUE self)
{
char *name, *config_path;
struct lxc_container *container;
struct container_data *data;
VALUE rb_name, rb_config_path;
rb_scan_args(argc, argv, "11", &rb_name, &rb_config_path);
name = StringValuePtr(rb_name);
config_path = NIL_P(rb_config_path) ? NULL : StringValuePtr(rb_config_path);
container = lxc_container_new(name, config_path);
if (container == NULL)
rb_raise(Error, "error creating container %s", name);
Data_Get_Struct(self, struct container_data, data);
data->container = container;
return self;
}
Public Instance Methods
Adds a device node to the container.
static VALUE
container_add_device_node(int argc, VALUE *argv, VALUE self)
{
int ret;
VALUE rb_src_path, rb_dest_path;
struct add_device_node_without_gvl_args args;
rb_scan_args(argc, argv, "11", &rb_src_path, &rb_dest_path);
args.src_path = StringValuePtr(rb_src_path);
args.dest_path = NIL_P(rb_dest_path) ? NULL : StringValuePtr(rb_dest_path);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(add_device_node_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to add device node");
return self;
}
Calls block in the context of the attached container. The options may contain the following keys.
-
:flags -
:namespaces -
:personality -
:initial_cwd -
:uid -
:gid -
:env_policy -
:extra_env_vars -
:extra_keep_env -
:stdin -
:stdout -
:stderr -
:wait
static VALUE
container_attach(int argc, VALUE *argv, VALUE self)
{
int wait;
long ret;
pid_t pid;
lxc_attach_options_t *opts;
struct container_data *data;
VALUE block, rb_opts;
if (!rb_block_given_p())
rb_raise(Error, "no block given");
block = rb_block_proc();
rb_scan_args(argc, argv, "01", &rb_opts);
wait = 0;
if (!NIL_P(rb_opts)) {
VALUE rb_wait;
Check_Type(rb_opts, T_HASH);
rb_wait = rb_hash_delete(rb_opts, SYMBOL("wait"));
if (rb_wait != Qnil && rb_wait != Qfalse)
wait = 1;
}
opts = lxc_attach_parse_options(rb_opts);
if (opts == NULL)
rb_raise(Error, "unable to parse attach options");
Data_Get_Struct(self, struct container_data, data);
ret = data->container->attach(data->container, lxc_attach_exec,
(void *)block, opts, &pid);
if (ret < 0)
goto out;
if (wait) {
ret = RELEASING_GVL2(wait_for_pid_status_without_gvl, &pid,
kill_pid_without_gvl, &pid);
/* handle case where attach fails */
if (WIFEXITED(ret) && WEXITSTATUS(ret) == 255)
ret = -1;
} else {
ret = pid;
}
out:
lxc_attach_free_options(opts);
return LONG2NUM(ret);
}
Returns the value corresponding to the given cgroup item configuration.
static VALUE
container_cgroup_item(VALUE self, VALUE rb_key)
{
int len1, len2;
char *key, *value;
struct container_data *data;
struct lxc_container *container;
VALUE ret;
Data_Get_Struct(self, struct container_data, data);
container = data->container;
key = StringValuePtr(rb_key);
len1 = container->get_cgroup_item(container, key, NULL, 0);
if (len1 < 0)
rb_raise(Error, "invalid cgroup entry for %s", key);
value = malloc(sizeof(char) * len1 + 1);
if (value == NULL)
rb_raise(rb_eNoMemError, "unable to allocate cgroup value");
len2 = container->get_cgroup_item(container, key, value, len1 + 1);
if (len1 != len2) {
free(value);
rb_raise(Error, "unable to read cgroup value");
}
ret = rb_str_new2(value);
free(value);
return ret;
}
Clears the container configuration.
static VALUE
container_clear_config(VALUE self)
{
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
data->container->clear_config(data->container);
return self;
}
Clears the container configuration item key.
static VALUE
container_clear_config_item(VALUE self, VALUE rb_key)
{
int ret;
char *key;
struct container_data *data;
key = StringValuePtr(rb_key);
Data_Get_Struct(self, struct container_data, data);
ret = data->container->clear_config_item(data->container, key);
if (!ret)
rb_raise(Error, "unable to clear config item %s", key);
return self;
}
Clones the container, returning a new one with the given name. The options hash may contain the following keys:
-
:config_path -
:flags -
:bdev_type -
:bdev_data -
:new_size -
:hook_args
static VALUE
container_clone(int argc, VALUE *argv, VALUE self)
{
VALUE rb_name, rb_opts;
VALUE rb_flags, rb_config_path, rb_bdev_type, rb_bdev_data;
VALUE rb_new_size, rb_hook_args;
VALUE rb_args[2];
struct clone_without_gvl_args args;
rb_scan_args(argc, argv, "11", &rb_name, &rb_opts);
args.name = StringValuePtr(rb_name);
args.config_path = NULL;
args.flags = 0;
args.bdev_type = NULL;
args.bdev_data = NULL;
args.new_size = 0;
args.hook_args = NULL;
rb_config_path = Qnil;
if (!NIL_P(rb_opts)) {
Check_Type(rb_opts, T_HASH);
rb_config_path = rb_hash_aref(rb_opts, SYMBOL("config_path"));
if (!NIL_P(rb_config_path))
args.config_path = StringValuePtr(rb_config_path);
rb_flags = rb_hash_aref(rb_opts, SYMBOL("flags"));
if (!NIL_P(rb_flags))
args.flags = NUM2INT(rb_flags);
rb_bdev_type = rb_hash_aref(rb_opts, SYMBOL("bdev_type"));
if (!NIL_P(rb_bdev_type))
args.bdev_type = StringValuePtr(rb_bdev_type);
rb_bdev_data = rb_hash_aref(rb_opts, SYMBOL("bdev_data"));
if (!NIL_P(rb_bdev_data))
args.bdev_data = StringValuePtr(rb_bdev_data);
rb_new_size = rb_hash_aref(rb_opts, SYMBOL("new_size"));
if (!NIL_P(rb_bdev_data))
args.new_size = NUM2ULL(rb_new_size);
rb_hook_args = rb_hash_aref(rb_opts, SYMBOL("hook_args"));
if (!NIL_P(rb_hook_args))
args.hook_args = ruby_to_c_string_array(rb_hook_args);
}
Data_Get_Struct(self, struct container_data, args.data);
RELEASING_GVL_VOID(clone_without_gvl, &args);
if (args.hook_args)
free_c_string_array(args.hook_args);
if (args.new_container == NULL)
rb_raise(Error, "unable to clone container");
lxc_container_put(args.new_container);
rb_args[0] = rb_name;
rb_args[1] = rb_config_path;
return rb_class_new_instance(2, rb_args, Container);
}
Returns the name of the container's configuration file.
static VALUE
container_config_file_name(VALUE self)
{
char *config_file_name;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
config_file_name = data->container->config_file_name(data->container);
return rb_str_new2(config_file_name);
}
Returns the value corresponding to the given configuration item.
static VALUE
container_config_item(VALUE self, VALUE rb_key)
{
int len1, len2, mlines;
char *key, *value;
struct container_data *data;
struct lxc_container *container;
VALUE rb_config;
Data_Get_Struct(self, struct container_data, data);
container = data->container;
key = StringValuePtr(rb_key);
len1 = container->get_config_item(container, key, NULL, 0);
if (len1 < 0)
rb_raise(Error, "invalid configuration key: %s", key);
if (len1 == 0)
return Qnil;
value = malloc(sizeof(char) * len1 + 1);
if (value == NULL)
rb_raise(rb_eNoMemError, "unable to allocate configuration value");
len2 = container->get_config_item(container, key, value, len1 + 1);
if (len1 != len2) {
free(value);
rb_raise(Error, "unable to read configuration file");
}
rb_config = rb_str_new2(value);
mlines = value[len2-1] == '\n';
free(value);
/* Return a list in case of multiple lines */
return mlines ? rb_str_split(rb_config, "\n") : rb_config;
}
Returns the configuration path for the container.
static VALUE
container_config_path(VALUE self)
{
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
return rb_str_new2(data->container->get_config_path(data->container));
}
Sets the container configuration path.
static VALUE
container_set_config_path(VALUE self, VALUE rb_path)
{
int ret;
char *path;
struct container_data *data;
path = StringValuePtr(rb_path);
Data_Get_Struct(self, struct container_data, data);
ret = data->container->set_config_path(data->container, path);
if (!ret)
rb_raise(Error, "unable to set configuration path to %s", path);
return self;
}
Accesses the container's console. The options hash may contain the following keys.
-
:tty_num -
:stdin_fd -
:stdout_fd -
:stderr_fd -
:escape
static VALUE
container_console(int argc, VALUE *argv, VALUE self)
{
int ret;
struct console_without_gvl_args args;
VALUE rb_opts;
VALUE rb_opt;
args.tty_num = -1;
args.stdin_fd = 0;
args.stdout_fd = 1;
args.stderr_fd = 2;
args.escape = 1;
rb_scan_args(argc, argv, "01", &rb_opts);
switch (TYPE(rb_opts)) {
case T_HASH:
rb_opt = rb_hash_aref(rb_opts, SYMBOL("tty_num"));
if (!NIL_P(rb_opt))
args.tty_num = NUM2INT(rb_opt);
rb_opt = rb_hash_aref(rb_opts, SYMBOL("stdin_fd"));
if (!NIL_P(rb_opt))
args.stdin_fd = NUM2INT(rb_opt);
rb_opt = rb_hash_aref(rb_opts, SYMBOL("stdout_fd"));
if (!NIL_P(rb_opt))
args.stdout_fd = NUM2INT(rb_opt);
rb_opt = rb_hash_aref(rb_opts, SYMBOL("stderr_fd"));
if (!NIL_P(rb_opt))
args.stderr_fd = NUM2INT(rb_opt);
rb_opt = rb_hash_aref(rb_opts, SYMBOL("escape"));
if (!NIL_P(rb_opt))
args.escape = NUM2INT(rb_opt);
break;
case T_NIL:
break;
default:
rb_raise(rb_eArgError, "options must be a hash");
}
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(console_without_gvl, &args);
if (ret != 0)
rb_raise(Error, "unable to access container console");
return self;
}
Returns an IO object referring to the container's console file descriptor.
static VALUE
container_console_fd(int argc, VALUE *argv, VALUE self)
{
int ret, tty_num, master_fd;
struct container_data *data;
VALUE rb_tty_num;
VALUE rb_io_args[1];
rb_scan_args(argc, argv, "01", &rb_tty_num);
tty_num = NIL_P(rb_tty_num) ? -1 : NUM2INT(rb_tty_num);
Data_Get_Struct(self, struct container_data, data);
ret = data->container->console_getfd(data->container, &tty_num, &master_fd);
if (ret < 0)
rb_raise(Error, "unable to allocate tty");
rb_io_args[0] = INT2NUM(master_fd);
return rb_class_new_instance(1, rb_io_args, rb_cIO);
}
static VALUE
container_controllable_p(VALUE self)
{
int controllable;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
controllable = data->container->may_control(data->container);
return controllable ? Qtrue : Qfalse;
}
Creates a structure for the container according to the given template. This usually consists of downloading and installing a Linux distribution inside the container's rootfs.
The flags argument is an OR of LXC_CREATE_* flags.
static VALUE
container_create(int argc, VALUE *argv, VALUE self)
{
int ret;
struct bdev_specs spec;
struct container_create_without_gvl_args args;
char **default_args = { NULL };
VALUE rb_template, rb_bdevtype, rb_bdevspecs, rb_flags, rb_args;
VALUE fstype, fssize, zfsroot, lvname, vgname, thinpool, dir;
args.args = default_args;
rb_scan_args(argc, argv, "14",
&rb_template, &rb_bdevtype, &rb_bdevspecs, &rb_flags,
&rb_args);
if (!NIL_P(rb_bdevspecs)) {
memset(&spec, 0, sizeof(spec));
fstype = rb_hash_aref(rb_bdevspecs, SYMBOL("fstype"));
if (!NIL_P(fstype))
spec.fstype = StringValuePtr(fstype);
fssize = rb_hash_aref(rb_bdevspecs, SYMBOL("fssize"));
if (!NIL_P(fssize))
spec.fssize = NUM2ULONG(fssize);
zfsroot = rb_hash_aref(rb_bdevspecs, SYMBOL("zfsroot"));
if (!NIL_P(zfsroot))
spec.zfs.zfsroot = StringValuePtr(zfsroot);
lvname = rb_hash_aref(rb_bdevspecs, SYMBOL("lvname"));
if (!NIL_P(lvname))
spec.lvm.lv = StringValuePtr(lvname);
vgname = rb_hash_aref(rb_bdevspecs, SYMBOL("vgname"));
if (!NIL_P(vgname))
spec.lvm.vg = StringValuePtr(vgname);
thinpool = rb_hash_aref(rb_bdevspecs, SYMBOL("thinpool"));
if (!NIL_P(thinpool))
spec.lvm.thinpool = StringValuePtr(thinpool);
dir = rb_hash_aref(rb_bdevspecs, SYMBOL("dir"));
if (!NIL_P(dir))
spec.dir = StringValuePtr(dir);
args.bdevspecs = &spec;
} else {
args.bdevspecs = NULL;
}
args.template = StringValuePtr(rb_template);
args.bdevtype = NIL_P(rb_bdevtype) ? NULL : StringValuePtr(rb_bdevtype);
args.flags = NIL_P(rb_flags) ? 0 : NUM2INT(rb_flags);
if (!NIL_P(rb_args))
args.args = ruby_to_c_string_array(rb_args);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(container_create_without_gvl, &args);
if (!NIL_P(rb_args))
free_c_string_array(args.args);
if (!ret)
rb_raise(Error, "unable to create container");
return self;
}
static VALUE
container_defined_p(VALUE self)
{
int defined;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
defined = data->container->is_defined(data->container);
return defined ? Qtrue : Qfalse;
}
Destroys the container.
static VALUE
container_destroy(VALUE self)
{
int ret;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
ret = RELEASING_GVL(destroy_without_gvl, data);
if (!ret)
rb_raise(Error, "unable to destroy container");
return self;
}
Freezes the container.
static VALUE
container_freeze(VALUE self)
{
int ret;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
ret = RELEASING_GVL(freeze_without_gvl, data);
if (!ret)
rb_raise(Error, "unable to freeze container");
return self;
}
Returns the PID of the container's init process from the host's point of view.
static VALUE
container_init_pid(VALUE self)
{
pid_t pid;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
pid = data->container->init_pid(data->container);
if (pid < 0)
return Qnil;
return INT2NUM(pid);
}
Returns the list of network interfaces of the container.
static VALUE
container_interfaces(VALUE self)
{
int i, num_interfaces;
char **interfaces;
struct container_data *data;
VALUE rb_interfaces;
Data_Get_Struct(self, struct container_data, data);
interfaces = data->container->get_interfaces(data->container);
if (!interfaces)
return rb_ary_new();
for (num_interfaces = 0; interfaces[num_interfaces]; num_interfaces++)
;
rb_interfaces = rb_ary_new2(num_interfaces);
for (i = 0; i < num_interfaces; i++)
rb_ary_store(rb_interfaces, i, rb_str_new2(interfaces[i]));
free_c_string_array(interfaces);
return rb_interfaces;
}
Returns the list of IP addresses of the container.
static VALUE
container_ips(int argc, VALUE *argv, VALUE self)
{
int i, num_ips, scope;
char *interface, *family;
char **ips;
struct container_data *data;
VALUE rb_ips, rb_interface, rb_family, rb_scope;
rb_scan_args(argc, argv, "03", &rb_interface, &rb_family, &rb_scope);
interface = NIL_P(rb_interface) ? NULL : StringValuePtr(rb_interface);
family = NIL_P(rb_family) ? NULL : StringValuePtr(rb_family);
scope = NIL_P(rb_scope) ? 0 : NUM2INT(rb_scope);
Data_Get_Struct(self, struct container_data, data);
ips = data->container->get_ips(data->container, interface, family, scope);
if (ips == NULL)
return rb_ary_new();
for (num_ips = 0; ips[num_ips]; num_ips++)
;
rb_ips = rb_ary_new2(num_ips);
for (i = 0; i < num_ips; i++)
rb_ary_store(rb_ips, i, rb_str_new2(ips[i]));
free_c_string_array(ips);
return rb_ips;
}
Returns a list of valid sub-keys for the given configuration key.
Keys can be in the format 'lxc.network.<idx>', (eg. 'lxc.network.0', 'lxc.network.1'). The result shows which keys are valid according to type of network interface.
static VALUE
container_keys(VALUE self, VALUE rb_key)
{
int len1, len2;
char *key, *value;
struct container_data *data;
struct lxc_container *container;
VALUE rb_keys;
Data_Get_Struct(self, struct container_data, data);
container = data->container;
key = StringValuePtr(rb_key);
len1 = container->get_keys(container, key, NULL, 0);
if (len1 < 0)
rb_raise(Error, "invalid configuration key: %s", key);
value = malloc(sizeof(char) * len1 + 1);
if (value == NULL)
rb_raise(rb_eNoMemError, "unable to allocate configuration value");
len2 = container->get_keys(container, key, value, len1 + 1);
if (len1 != len2) {
free(value);
rb_raise(Error, "unable to read configuration keys");
}
rb_keys = rb_str_new2(value);
free(value);
return value[len2-1] == '\n' ? rb_str_split(rb_keys, "\n") : rb_keys;
}
Loads the container's configuration.
static VALUE
container_load_config(int argc, VALUE *argv, VALUE self)
{
int ret;
VALUE rb_path;
struct load_config_without_gvl_args args;
rb_scan_args(argc, argv, "01", &rb_path);
args.path = NIL_P(rb_path) ? NULL : StringValuePtr(rb_path);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(load_config_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to load configuration file");
return self;
}
Returns the name of the container.
static VALUE
container_name(VALUE self)
{
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
return rb_str_new2(data->container->name);
}
Reboots the container.
static VALUE
container_reboot(VALUE self)
{
int ret;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
ret = RELEASING_GVL(reboot_without_gvl, data);
if (!ret)
rb_raise(Error, "unable to reboot container");
return self;
}
Removes a device node from the container.
static VALUE
container_remove_device_node(int argc, VALUE *argv, VALUE self)
{
int ret;
VALUE rb_src_path, rb_dest_path;
struct remove_device_node_without_gvl_args args;
rb_scan_args(argc, argv, "11", &rb_src_path, &rb_dest_path);
args.src_path = StringValuePtr(rb_src_path);
args.dest_path = NIL_P(rb_dest_path) ? NULL : StringValuePtr(rb_dest_path);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(remove_device_node_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to remove device node");
return self;
}
Renames the container and returns a new LXC::Container instance of the container with the new name.
static VALUE
container_rename(VALUE self, VALUE rb_name)
{
int ret;
VALUE rb_args[2];
struct rename_without_gvl_args args;
Data_Get_Struct(self, struct container_data, args.data);
args.name = StringValuePtr(rb_name);
ret = RELEASING_GVL(rename_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to rename container");
rb_args[0] = rb_name;
rb_args[1] = Qnil;
return rb_class_new_instance(2, rb_args, Container);
}
static VALUE
container_running_p(VALUE self)
{
int running;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
running = data->container->is_running(data->container);
return running ? Qtrue : Qfalse;
}
Returns the value corresponding to the given configuration item from a running container.
static VALUE
container_running_config_item(VALUE self, VALUE rb_key)
{
char *key, *value;
struct container_data *data;
struct lxc_container *container;
VALUE rb_value;
Data_Get_Struct(self, struct container_data, data);
container = data->container;
key = StringValuePtr(rb_key);
value = container->get_running_config_item(container, key);
if (value == NULL)
rb_raise(Error, "unable to read running configuration item: %s", key);
rb_value = rb_str_new2(value);
free(value);
return rb_value;
}
static VALUE
container_save_config(int argc, VALUE *argv, VALUE self)
{
int ret;
VALUE rb_path;
struct save_config_without_gvl_args args;
rb_scan_args(argc, argv, "01", &rb_path);
args.path = NIL_P(rb_path) ? NULL : StringValuePtr(rb_path);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(save_config_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to save configuration file");
return self;
}
Sets the value of a cgroup configuration item.
static VALUE
container_set_cgroup_item(VALUE self, VALUE rb_key, VALUE rb_value)
{
int ret;
char *key, *value;
struct container_data *data;
key = StringValuePtr(rb_key);
value = StringValuePtr(rb_value);
Data_Get_Struct(self, struct container_data, data);
ret = data->container->set_cgroup_item(data->container, key, value);
if (!ret)
rb_raise(Error, "unable to set cgroup item %s to %s", key, value);
return self;
}
Sets the value of a configuration item.
static VALUE
container_set_config_item(VALUE self, VALUE rb_key, VALUE rb_value)
{
int ret;
char *key, *value;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
key = StringValuePtr(rb_key);
switch (TYPE(rb_value)) {
case T_STRING: {
value = StringValuePtr(rb_value);
ret = data->container->set_config_item(data->container, key, value);
if (!ret) {
rb_raise(Error, "unable to set configuration item %s to %s",
key, value);
}
return self;
}
case T_ARRAY: {
size_t i;
size_t len = RARRAY_LEN(rb_value);
for (i = 0; i < len; i++) {
VALUE rb_entry = rb_ary_entry(rb_value, i);
char *entry = StringValuePtr(rb_entry);
ret = data->container->set_config_item(data->container, key, entry);
if (!ret) {
rb_raise(Error, "unable to set configuration item %s to %s",
key, entry);
}
}
return self;
}
default:
rb_raise(Error, "configuration value must be either string or array");
}
}
Shuts down the container, optionally waiting for timeout seconds. If timeout is -1, wait as long as necessary for the container to shutdown.
static VALUE
container_shutdown(int argc, VALUE *argv, VALUE self)
{
int ret;
VALUE rb_timeout;
struct shutdown_without_gvl_args args;
rb_scan_args(argc, argv, "01", &rb_timeout);
Data_Get_Struct(self, struct container_data, args.data);
args.timeout = NIL_P(rb_timeout) ? -1 : NUM2INT(rb_timeout);
ret = RELEASING_GVL(shutdown_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to shutdown container");
return self;
}
Creates a snapshot of the container. Returns the snapshot name.
static VALUE
container_snapshot(int argc, VALUE *argv, VALUE self)
{
int ret;
char new_name[20];
VALUE rb_path;
struct snapshot_without_gvl_args args;
rb_scan_args(argc, argv, "01", &rb_path);
args.path = NIL_P(rb_path) ? NULL : StringValuePtr(rb_path);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(snapshot_without_gvl, &args);
if (ret < 0)
rb_raise(Error, "unable to snapshot container");
ret = snprintf(new_name, 20, "snap%d", ret);
if (ret < 0 || ret >= 20)
rb_raise(Error, "unable to snapshot container");
return rb_str_new2(new_name);
}
Destroys the given snapshot.
static VALUE
container_snapshot_destroy(VALUE self, VALUE rb_name)
{
int ret;
struct snapshot_destroy_without_gvl_args args;
Data_Get_Struct(self, struct container_data, args.data);
args.name = StringValuePtr(rb_name);
ret = RELEASING_GVL(snapshot_destroy_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to destroy snapshot");
return self;
}
Returns a list of existing snapshots for the container.
static VALUE
container_snapshot_list(VALUE self)
{
int i, num_snapshots;
VALUE rb_snapshots;
struct snapshot_list_without_gvl_args args;
Data_Get_Struct(self, struct container_data, args.data);
num_snapshots = RELEASING_GVL(snapshot_list_without_gvl, &args);
if (num_snapshots < 0)
rb_raise(Error, "unable to list snapshots");
rb_snapshots = rb_ary_new2(num_snapshots);
for (i = 0; i < num_snapshots; i++) {
VALUE attrs = rb_ary_new2(4);
rb_ary_store(attrs, 0, rb_str_new2(args.snapshots[i].name));
rb_ary_store(attrs, 1, rb_str_new2(args.snapshots[i].comment_pathname));
rb_ary_store(attrs, 2, rb_str_new2(args.snapshots[i].timestamp));
rb_ary_store(attrs, 3, rb_str_new2(args.snapshots[i].lxcpath));
args.snapshots[i].free(&args.snapshots[i]);
rb_ary_store(rb_snapshots, i, attrs);
}
return rb_snapshots;
}
Restores the given snapshot.
static VALUE
container_snapshot_restore(int argc, VALUE *argv, VALUE self)
{
int ret;
struct snapshot_restore_without_gvl_args args;
VALUE rb_name, rb_new_name;
rb_scan_args(argc, argv, "11", &rb_name, &rb_new_name);
args.name = StringValuePtr(rb_name);
args.new_name = NIL_P(rb_new_name) ? NULL : StringValuePtr(rb_new_name);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(snapshot_restore_without_gvl, &args);
if (!ret)
rb_raise(Error, "unable to restore snapshot");
return self;
}
Starts the container. The options hash may contain the following keys.
-
:use_init -
:daemonize -
:close_fds -
:args
static VALUE
container_start(int argc, VALUE *argv, VALUE self)
{
int ret;
VALUE rb_use_init, rb_daemonize, rb_close_fds, rb_args, rb_opts;
struct start_without_gvl_args args;
args.use_init = 0;
args.daemonize = 1;
args.close_fds = 0;
args.args = NULL;
rb_args = Qnil;
rb_scan_args(argc, argv, "01", &rb_opts);
if (!NIL_P(rb_opts)) {
Check_Type(rb_opts, T_HASH);
rb_use_init = rb_hash_aref(rb_opts, SYMBOL("use_init"));
if (!NIL_P(rb_use_init))
args.use_init = (rb_use_init != Qfalse);
rb_daemonize = rb_hash_aref(rb_opts, SYMBOL("daemonize"));
if (!NIL_P(rb_daemonize))
args.daemonize = (rb_daemonize != Qfalse);
rb_close_fds = rb_hash_aref(rb_opts, SYMBOL("close_fds"));
if (!NIL_P(rb_close_fds))
args.close_fds = (rb_close_fds != Qfalse);
rb_args = rb_hash_aref(rb_opts, SYMBOL("args"));
if (!NIL_P(rb_args))
args.args = ruby_to_c_string_array(rb_args);
}
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(start_without_gvl, &args);
if (!NIL_P(rb_args))
free_c_string_array(args.args);
if (!ret)
rb_raise(Error, "unable to start container");
return self;
}
Returns a symbol representing the state of the container.
-
:stopped -
:starting -
:running -
:stopping -
:aborting -
:freezing -
:frozen -
:thawed
static VALUE
container_state(VALUE self)
{
struct container_data *data;
VALUE rb_state;
Data_Get_Struct(self, struct container_data, data);
rb_state = rb_str_new2(data->container->state(data->container));
return rb_str_intern(rb_funcall(rb_state, rb_intern("downcase"), 0));
}
Stops the container.
static VALUE
container_stop(VALUE self)
{
int ret;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
ret = RELEASING_GVL(stop_without_gvl, data);
if (!ret)
rb_raise(Error, "unable to stop container");
return self;
}
Thaws a frozen container.
static VALUE
container_unfreeze(VALUE self)
{
int ret;
struct container_data *data;
Data_Get_Struct(self, struct container_data, data);
ret = RELEASING_GVL(unfreeze_without_gvl, data);
if (!ret)
rb_raise(Error, "unable to unfreeze container");
return self;
}
Waits for timeout seconds (or as long as necessary if timeout is -1) until the container's state becomes state.
static VALUE
container_wait(int argc, VALUE *argv, VALUE self)
{
int ret;
VALUE rb_state_str, rb_state, rb_timeout;
struct wait_without_gvl_args args;
rb_scan_args(argc, argv, "11", &rb_state, &rb_timeout);
rb_state_str = rb_funcall(rb_state, rb_intern("to_s"), 0);
rb_state_str = rb_funcall(rb_state_str, rb_intern("upcase"), 0);
args.state = StringValuePtr(rb_state_str);
args.timeout = NIL_P(rb_timeout) ? -1 : NUM2INT(rb_timeout);
Data_Get_Struct(self, struct container_data, args.data);
ret = RELEASING_GVL(wait_without_gvl, &args);
if (!ret)
rb_raise(Error, "error waiting for container");
return self;
}