Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / src / builder / b-deletion.c
Author[]Andy Green <andy@warmcat.com> 2026-05-17 09:37 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-05-17 09:37 UTC
Treec7df245f9d0cd642214af2be94016b16b908044c   Raw Patch
 
sai-virt: phase4
sai-virt: phase4
diff --git a/CMakeLists.txt b/CMakeLists.txt index fe0a485..ef531f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,12 +158,12 @@ if (requirements) add_subdirectory(src/web) if (NOT MSVC AND NOT WIN32 AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")) add_subdirectory(src/power) - add_subdirectory(src/virt) endif() endif() if (SAI_BUILDER) add_subdirectory(src/builder) add_subdirectory(src/resource) + add_subdirectory(src/virt) if (NOT MSVC AND NOT WIN32 AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")) add_subdirectory(src/device) diff --git a/src/virt/CMakeLists.txt b/src/virt/CMakeLists.txt index a74deea..ac66ef4 100644 --- a/src/virt/CMakeLists.txt +++ b/src/virt/CMakeLists.txt @@ -4,6 +4,8 @@ set(CPACK_DEBIAN_VIRT_PACKAGE_NAME "sai-virt") set(SRCS v-sai.c v-ws-server.c + v-libvirt.c + v-http-api.c ../common/c-utils.c ../common/struct-metadata.c ) diff --git a/src/virt/v-http-api.c b/src/virt/v-http-api.c new file mode 100644 index 0000000..e76e26a --- /dev/null +++ b/src/virt/v-http-api.c @@ -0,0 +1,65 @@ +/* + * sai-virt - v-http-api.c + * + * Copyright (C) 2019 - 2026 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + */ + +#include <libwebsockets.h> +#include <string.h> + +#include "v-private.h" + +int +callback_virt_http(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + const char *path; + char vm_id[64]; + + switch (reason) { + case LWS_CALLBACK_HTTP: + path = (const char *)in; + if (len > 16 && !strncmp(path, "/auto-power-off/", 16)) { + lws_strncpy(vm_id, path + 16, sizeof(vm_id)); + lwsl_notice("%s: Received auto-power-off for %s\n", __func__, vm_id); + if (virt.ops) + virt.ops->destroy(&virt, vm_id); + + lws_return_http_status(wsi, HTTP_STATUS_OK, NULL); + return -1; /* hang up */ + } + + if (len > 6 && !strncmp(path, "/stay/", 6)) { + lws_strncpy(vm_id, path + 6, sizeof(vm_id)); + lwsl_notice("%s: Received stay for %s\n", __func__, vm_id); + /* We never return stay = true for ephemeral VMs */ + uint8_t stay_res = '0'; + if (lws_write(wsi, &stay_res, 1, LWS_WRITE_HTTP) != 1) + return -1; + return -1; /* hang up */ + } + + lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL); + return -1; + + default: + break; + } + + return lws_callback_http_dummy(wsi, reason, user, in, len); +} + +const struct lws_protocols virt_protocols[] = { + { + "http-only", + callback_virt_http, + 0, + 0, + }, + { NULL, NULL, 0, 0 } /* terminator */ +}; diff --git a/src/virt/v-libvirt.c b/src/virt/v-libvirt.c new file mode 100644 index 0000000..5cfa876 --- /dev/null +++ b/src/virt/v-libvirt.c @@ -0,0 +1,92 @@ +/* + * sai-virt - v-libvirt.c + * + * Copyright (C) 2019 - 2026 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + */ + +#include <libwebsockets.h> +#include <string.h> +#include <stdio.h> + +#include "v-private.h" + +/* + * We use virsh via lws_spawn_piped to avoid a hard dependency on libvirt.so + * and to easily integrate with the asynchronous lws event loop. + */ + +static void +reap_virsh(void *opaque, const lws_spawn_resource_us_t *res, siginfo_t *si, int we_killed_him) +{ + lwsl_notice("%s: virsh exited with code %d\n", __func__, si->si_status); +} + +static int +spawn_virsh_command(struct sai_virt *virt, const char * const *exec_array) +{ + struct lws_spawn_piped_info info; + struct lws_spawn_piped *lsp; + + memset(&info, 0, sizeof(info)); + info.vh = virt->vhost; + info.exec_array = exec_array; + info.max_log_lines = 10; + info.reap_cb = reap_virsh; + + lsp = lws_spawn_piped(&info); + if (!lsp) { + lwsl_err("%s: failed to spawn virsh\n", __func__); + return 1; + } + + return 0; +} + +static int +ops_libvirt_init(struct sai_virt *virt) +{ + lwsl_notice("%s: libvirt ops initialized\n", __func__); + return 0; +} + +static int +ops_libvirt_spawn(struct sai_virt *virt, const char *platform) +{ + /* + * Mock implementation: + * Ideally, we would run: + * virsh virt-clone --original sai-template-<platform> --name sai-ephemeral-<uuid> --auto-clone + * virsh start sai-ephemeral-<uuid> + */ + const char * const exec_array[] = { + "/usr/bin/virsh", "list", "--all", NULL + }; + + lwsl_notice("%s: Spawning ephemeral VM for platform: %s\n", __func__, platform); + + return spawn_virsh_command(virt, exec_array); +} + +static int +ops_libvirt_destroy(struct sai_virt *virt, const char *vm_id) +{ + /* + * Mock implementation: + * virsh destroy <vm_id> + * virsh undefine <vm_id> --remove-all-storage + */ + lwsl_notice("%s: Destroying ephemeral VM: %s\n", __func__, vm_id); + return 0; +} + +const sai_virt_ops_t ops_libvirt = { + .name = "libvirt", + .init = ops_libvirt_init, + .spawn = ops_libvirt_spawn, + .destroy = ops_libvirt_destroy, +}; diff --git a/src/virt/v-private.h b/src/virt/v-private.h index ff914e8..c7fd1fd 100644 --- a/src/virt/v-private.h +++ b/src/virt/v-private.h @@ -15,7 +15,14 @@ #include "../common/include/private.h" #include <pthread.h> -struct saiv_server; +struct sai_virt; + +typedef struct sai_virt_ops { + const char *name; + int (*init)(struct sai_virt *virt); + int (*spawn)(struct sai_virt *virt, const char *platform); + int (*destroy)(struct sai_virt *virt, const char *vm_id); +} sai_virt_ops_t; /* * Represents the virt process state @@ -25,6 +32,8 @@ struct sai_virt { struct lws_context *context; struct lws_vhost *vhost; + const sai_virt_ops_t *ops; + const char *bind; /* listen socket binding */ const char *perms; /* user:group */ const char *port; /* port we listen on */ @@ -48,6 +57,8 @@ LWS_SS_USER_TYPEDEF extern struct sai_virt virt; extern const lws_ss_info_t ssi_saiv_server_link_t; +extern const sai_virt_ops_t ops_libvirt; +extern const struct lws_protocols virt_protocols[]; int saiv_config(struct sai_virt *virt, const char *d); diff --git a/src/virt/v-sai.c b/src/virt/v-sai.c index 18c65b5..1113272 100644 --- a/src/virt/v-sai.c +++ b/src/virt/v-sai.c @@ -65,10 +65,16 @@ int main(int argc, const char **argv) if (gethostname(virt.hostname, sizeof(virt.hostname) - 1)) lws_strncpy(virt.hostname, "unknown", sizeof(virt.hostname)); + const struct lws_protocols *pprotocols[] = { + &virt_protocols[0], + NULL + }; + memset(&info, 0, sizeof info); - info.port = CONTEXT_PORT_NO_LISTEN; + info.port = 8000; info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_VALIDATE_UTF8; + info.pprotocols = pprotocols; signal(SIGINT, sigint_handler); @@ -80,6 +86,9 @@ int main(int argc, const char **argv) return 1; } + virt.ops = &ops_libvirt; + virt.ops->init(&virt); + virt.vhost = lws_create_vhost(virt.context, &info); if (!virt.vhost) { lwsl_err("lws init failed\n"); diff --git a/src/virt/v-ws-server.c b/src/virt/v-ws-server.c index afc7276..87dbf8a 100644 --- a/src/virt/v-ws-server.c +++ b/src/virt/v-ws-server.c @@ -60,6 +60,9 @@ saiv_server_rx(void *userobj, const uint8_t *buf, size_t len, int flags) lws_start_foreach_dll(struct lws_dll2 *, p, pt->tasks.head) { sai_platform_pending_task_t *t = lws_container_of(p, sai_platform_pending_task_t, list); lwsl_notice(" - %s: %u pending\n", t->plat, t->pending); + if (t->pending > 0 && virt.ops) { + virt.ops->spawn(&virt, t->plat); + } } lws_end_foreach_dll(p); }
Page fetched 0s ago, creation time: 3ms (vhost etag hits: 0%, cache hits: 0%)