class LXC::Container

This class contains methods to manage Linux containers.

Public Class Methods

LXC::Container.new(name, config_path = LXC.global_config_item('lxc.lxcpath')) click to toggle source

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

add_device_node(src_path, dest_path = src_path) click to toggle source

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;
}
attach(opts = {}, &block) click to toggle source

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);
}
cgroup_item(key) click to toggle source

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;
}
clear_config click to toggle source

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;
}
clear_config_item(key) click to toggle source

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;
}
clone(clone_name, opts = {}) click to toggle source

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);
}
config_file_name click to toggle source

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);
}
config_item(key) click to toggle source

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;
}
config_path click to toggle source

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));
}
config_path = path click to toggle source

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;
}
console(opts = {}) click to toggle source

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;
}
console_fd(tty_num = nil) click to toggle source

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);
}
controllable?() click to toggle source
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;
}
create(template, bdevtype = nil, bdevspecs = {}, flags = 0, args = []) click to toggle source

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;
}
defined?() click to toggle source
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;
}
destroy click to toggle source

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;
}
freeze click to toggle source

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;
}
init_pid click to toggle source

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);
}
interfaces click to toggle source

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;
}
ip_addresses click to toggle source

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;
}
keys(key) click to toggle source

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;
}
load_config(config_path = nil) click to toggle source

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;
}
name click to toggle source

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);
}
reboot click to toggle source

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;
}
remove_device_node(src_path, dest_path = src_path) click to toggle source

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;
}
rename(new_name) click to toggle source

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);
}
running?() click to toggle source
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;
}
running_config_item(key) click to toggle source

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;
}
save_config(p1 = v1) click to toggle source
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;
}
set_cgroup_item(key, value) click to toggle source

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;
}
set_config_item(key, value) click to toggle source

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");
    }
}
shutdown(timeout = -1) click to toggle source

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;
}
snapshot(path = nil) click to toggle source

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);
}
snapshot_destroy(name) click to toggle source

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;
}
snapshot_list click to toggle source

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;
}
snapshot_restore(name, new_name = nil) click to toggle source

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;
}
start(opts = {}) click to toggle source

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;
}
state click to toggle source

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));
}
stop click to toggle source

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;
}
unfreeze click to toggle source

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;
}
wait(state, timeout = -1) click to toggle source

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;
}