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