/*! * Forcibly stop the Hypervisor. * * \param config \ref cc_oci_config. * \param state \ref oci_state. * \param signum Signal number to send to hypervisor. * \param all_processes \c true to send a signal to all container's processes, * \c false to send a signal to container's workload. * * \return \c true on success, else \c false. */ gboolean cc_oci_kill (struct cc_oci_config *config, struct oci_state *state, int signum, gboolean all_processes) { enum oci_status last_status; if (! (config && state)) { return false; } if (! cc_oci_get_signame (signum)) { g_critical ("signal %d is not supported", signum); return false; } /* save current status */ last_status = config->state.status; /* A sandbox is not a running container, nothing to kill here */ if (cc_pod_is_sandbox(config)) { config->state.status = OCI_STATUS_STOPPED; /* update state file */ if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); goto error; } return true; } /* stopping container */ config->state.status = OCI_STATUS_STOPPING; /* update state file */ if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); goto error; } #ifndef UNIT_TESTING /* kill container's processes, cc-shim will catch exit code * and will end */ if (! cc_proxy_hyper_kill_container (config, signum, all_processes)) { g_critical ("failed to kill container %s: %s", config->optarg_container_id, strerror (errno)); /* revert container status */ config->state.status = last_status; if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); } return false; } #endif //UNIT_TESTING if (signum == SIGKILL) { /* cc-shim is not able to catch the exit code of a process * finished with SIGKILL signal hence cc-shim MUST receive * this signal too */ if (kill (state->pid, signum) < 0 && errno != ESRCH) { g_critical ("failed to stop cc-shim %u: %s", (unsigned)state->pid, strerror (errno)); return false; } } last_status = config->state.status; config->state.status = OCI_STATUS_STOPPED; /* update state file */ if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); goto error; } return true; error: /* revert container status */ config->state.status = last_status; return false; }
} END_TEST START_TEST(test_cc_oci_state_file_create) { struct cc_oci_config config = { { 0 } }; const gchar *timestamp = "foo"; struct oci_cfg_annotation* a = NULL; struct cc_oci_mount *m = NULL; g_autofree gchar *tmpdir = g_dir_make_tmp (NULL, NULL); gboolean ret; ck_assert(! cc_oci_state_file_create (NULL, NULL)); /* Needs: * * - comms_path * - procsock_path * - optarg_bundle_path * - optarg_container_id * - runtime_path * */ ck_assert(! cc_oci_state_file_create (&config, NULL)); ck_assert(! cc_oci_state_file_create (&config, timestamp)); config.optarg_container_id = ""; ck_assert(! cc_oci_state_file_create (&config, NULL)); ck_assert(! cc_oci_state_file_create (&config, timestamp)); config.optarg_container_id = "foo"; ck_assert(! cc_oci_state_file_create (&config, NULL)); ck_assert(! cc_oci_state_file_create (&config, timestamp)); config.bundle_path = g_strdup ("/tmp/bundle"); ck_assert(! cc_oci_state_file_create (&config, NULL)); ck_assert(! cc_oci_state_file_create (&config, timestamp)); config.root_dir = g_strdup (tmpdir); ck_assert (config.root_dir); ck_assert (cc_oci_runtime_dir_setup (&config)); ck_assert(! cc_oci_state_file_create (&config, NULL)); ck_assert(! cc_oci_state_file_create (&config, timestamp)); g_snprintf(config.state.comms_path, PATH_MAX, "/tmp"); g_snprintf(config.state.procsock_path, PATH_MAX, "/tmp"); ck_assert(! cc_oci_state_file_create (&config, NULL)); a = g_new0(struct oci_cfg_annotation, 1); a->key = g_strdup("key1"); a->value = g_strdup("val1"); config.oci.annotations = g_slist_append(config.oci.annotations, a); /* config->vm not set */ ck_assert(! cc_oci_state_file_create (&config, timestamp)); config.vm = g_malloc0 (sizeof(struct cc_oci_vm_cfg)); ck_assert (config.vm); g_strlcpy (config.vm->hypervisor_path, "hypervisor-path", sizeof (config.vm->hypervisor_path)); g_strlcpy (config.vm->image_path, "image-path", sizeof (config.vm->image_path)); g_strlcpy (config.vm->kernel_path, "kernel-path", sizeof (config.vm->kernel_path)); g_strlcpy (config.vm->workload_path, "workload-path", sizeof (config.vm->workload_path)); config.vm->kernel_params = g_strdup ("kernel params"); /* All required elements now set */ m = g_new0(struct cc_oci_mount, 1); g_snprintf(m->dest, sizeof(m->dest), "/tmp/tmp/tmp"); m->directory_created = g_strdup("/tmp/tmp/"); m->ignore_mount = true; config.oci.mounts = g_slist_append(config.oci.mounts, m); ck_assert (cc_oci_state_file_create (&config, timestamp)); ret = g_file_test (config.state.state_file_path, G_FILE_TEST_EXISTS); ck_assert (ret); ck_assert (! g_remove (config.state.state_file_path)); ck_assert (! g_remove (config.state.runtime_path)); ck_assert (! g_remove (tmpdir)); g_snprintf(config.state.runtime_path, PATH_MAX, "/abc/xyz/123"); ck_assert(!cc_oci_state_file_create (&config, timestamp)); /* clean up */ cc_oci_config_free (&config); } END_TEST
/** * Create a fake state file for the specified VM. * * \param name Name to use for VM. * \param root_dir Root directory to use. * \param config Already allocated \ref cc_oci_config. * * \return \c true on success, else \c false. */ gboolean test_helper_create_state_file (const char *name, const char *root_dir, struct cc_oci_config *config) { g_autofree gchar *timestamp = NULL; assert (name); assert (root_dir); assert (config); timestamp = g_strdup_printf ("timestamp for %s", name); assert (timestamp); config->optarg_container_id = name; config->root_dir = g_strdup (root_dir); assert (config->root_dir); config->console = g_strdup_printf ("console device for %s", name); assert (config->console); config->bundle_path = g_strdup_printf ("/tmp/bundle-for-%s", name); assert (config->bundle_path); /* set pid to ourselves so we know it's running */ if (! config->state.workload_pid) { config->state.workload_pid = getpid (); } g_strlcpy (config->state.procsock_path, "procsock-path", sizeof (config->state.procsock_path)); if (! cc_oci_runtime_dir_setup (config)) { fprintf (stderr, "ERROR: failed to setup runtime dir " "for vm %s", name); return false; } /* config->vm not set */ if (cc_oci_state_file_create (config, timestamp)) { fprintf (stderr, "ERROR: cc_oci_state_file_create " "worked unexpectedly for vm %s", name); return false; } config->vm = g_malloc0 (sizeof(struct cc_oci_vm_cfg)); assert (config->vm); g_strlcpy (config->vm->hypervisor_path, "hypervisor-path", sizeof (config->vm->hypervisor_path)); g_strlcpy (config->vm->image_path, "image-path", sizeof (config->vm->image_path)); g_strlcpy (config->vm->kernel_path, "kernel-path", sizeof (config->vm->kernel_path)); g_strlcpy (config->vm->workload_path, "workload-path", sizeof (config->vm->workload_path)); config->vm->kernel_params = g_strdup_printf ("kernel params for %s", name); /* config->vm now set */ if (! cc_oci_state_file_create (config, timestamp)) { fprintf (stderr, "ERROR: cc_oci_state_file_create " "failed unexpectedly"); return false; } return true; }
/*! * Forcibly stop the Hypervisor. * * \param config \ref cc_oci_config. * \param state \ref oci_state. * \param signum Signal number to send to hypervisor. * * \return \c true on success, else \c false. */ gboolean cc_oci_kill (struct cc_oci_config *config, struct oci_state *state, int signum) { enum oci_status last_status; if (! (config && state)) { return false; } /* save current status */ last_status = config->state.status; /* A sandbox is not a running container, nothing to kill here */ if (cc_pod_is_sandbox(config)) { config->state.status = OCI_STATUS_STOPPED; /* update state file */ if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); goto error; } return true; } /* stopping container */ config->state.status = OCI_STATUS_STOPPING; /* update state file */ if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); goto error; } /* send signal to cc-shim because it * will send killcontainer to hyperstart */ if (kill (state->pid, signum) < 0) { g_critical ("failed to stop container %s " "running with pid %u: %s", config->optarg_container_id, (unsigned)state->pid, strerror (errno)); /* revert container status */ config->state.status = last_status; if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); } return false; } #ifndef UNIT_TESTING /* cc-shim is not able to catch SIGKILL and SIGSTOP * signals for this reason we must kill the container * using hyperstart's API */ if (signum == SIGKILL || signum == SIGSTOP) { if (! cc_proxy_hyper_kill_container (config, signum)) { g_critical ("failed to kill container"); return false; } } #endif //UNIT_TESTING last_status = config->state.status; config->state.status = OCI_STATUS_STOPPED; /* update state file */ if (! cc_oci_state_file_create (config, state->create_time)) { g_critical ("failed to recreate state file"); goto error; } return true; error: /* revert container status */ config->state.status = last_status; return false; }