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 / assets / solaris-11.svg
Author[]google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.c...> 2025-11-30 17:53 UTC
Committer[]Andy Green <andy@warmcat.com> 2025-12-03 14:58 UTC
Tree60825b389ee5733a1e71b71e6ee2bb0118c3e57b   Raw Patch
 
Refactor power management to PCON-centric topology
Refactor power management to PCON-centric topology

- sai-power: Manages Power Controllers (PCONs) and their dependencies. Accepts builder registrations via WebSocket to learn topology. Defaults PCONs to ON if no builders registered (cold start).
- sai-builder: Connects to sai-power via WebSocket to register PCON binding and platforms.
- sai-server: Receives PCON topology from sai-power, persists it to DB (schema updates handled), and serves it to Web UI.
- Web UI: Updated to render PCONs with nested builders.
- Fixes: SQL syntax error in server, JS reference error in frontend, linker error for saip_switch, and memory leaks in builder handling.
diff --git a/READMEs/README-systemd-nspawn.md b/READMEs/README-systemd-nspawn.md index 73c593a..ad4458d 100644 --- a/READMEs/README-systemd-nspawn.md +++ b/READMEs/README-systemd-nspawn.md @@ -30,6 +30,12 @@ same first 11 chars in their name! Pick your machine name, in this example `xenial-amd64`. +### Step 0: Install systemd-nspawn on host + +``` +Host # sudo dnf install systemd-container +``` + ### Step 1: Create the initial host config for the machine On the host, `mkdir /etc/systemd/nspawn` and then create in @@ -75,6 +81,12 @@ Replace the debootstrap part above with Host # debootstrap --arch=amd64 stable buster-amd64 ``` +or, + +``` +Host # debootstrap --arch=arm64 --variant=buildd stable debian-stable https://deb.debian.org/debian +``` + #### Variations: Centos 8 Create a file "centos8.repo" diff --git a/src/builder/b-power.c b/src/builder/b-power.c index 28aa0e2..fc05ec3 100644 --- a/src/builder/b-power.c +++ b/src/builder/b-power.c @@ -71,12 +71,16 @@ saib_power_client_state(void *userobj, void *sh, lws_ss_constate_t state, sai_builder_registration_t r; struct lwsac *ac = NULL; + lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state), + (unsigned int)ack); + switch (state) { case LWSSSCS_CONNECTED: - lwsl_notice("%s: Connected to sai-power, sending registration\n", __func__); + lwsl_notice("%s: Connected to sai-power, sending registration: '%s' '%s'\n", __func__, builder.host, builder.power_controller_name); /* Prepare registration message */ memset(&r, 0, sizeof(r)); + lws_strncpy(r.builder_name, builder.host, sizeof(r.builder_name)); if (builder.power_controller_name) lws_strncpy(r.power_controller_name, builder.power_controller_name, sizeof(r.power_controller_name)); @@ -472,46 +476,47 @@ saib_power_init(void) * Do we have a url for sai-power? If not, nothing we can do. */ - if (!builder.url_sai_power) + if (!builder.url_sai_power) { + lwsl_err("%s: *** missing URL for url_sai_power\n", __func__); return 1; - - /* - * The plan is ask sai-power to turn us off... we don't know our - * dependency situation since we're just a standalone builder. - * - * We will have to let sai-power figure the deps out and say if - * it's willing to auto power-off or not. - */ + } /* Existing SS creation for power-off logic */ - lwsl_notice("%s: creating sai-power ss...\n", __func__); + lwsl_notice("%s: *** creating sai-power ss...\n", __func__); if (lws_ss_create(builder.context, 0, &ssi_saib_power_link_t, (void *)builder.host, &builder.ss_power_off, NULL, NULL)) { - lwsl_err("%s: failed to create sai-power ss\n", __func__); + lwsl_err("%s: *** failed to create sai-power ss\n", __func__); return 1; } saib_reassess_idle_situation(); - /* - * NEW: Create the persistent WS connection for registration - * We reuse builder.url_sai_power. - * Note: builder.url_sai_power is a URL string. We need to extract the policy endpoint? - * The policy for sai-power client needs to be defined. - * 'sai_power' in policy covers it. - */ + lwsl_notice("%s: *** creating sai-power client ss...\n", __func__); if (lws_ss_create(builder.context, 0, &ssi_saib_power_client_t, NULL, &ss_power_client, NULL, NULL)) { - lwsl_err("%s: failed to create sai-power client ss\n", __func__); - } else { - /* Set metadata for URL? The policy handles 'sai_power' endpoint. - * We might need to ensure the policy matches what we expect. - * The existing code assumes 'sai_power' policy exists. - */ + lwsl_err("%s: *** failed to create sai-power client ss\n", __func__); + + return 1; } + /* + * Set metadata for URL? The policy handles 'sai_power' endpoint. + * We might need to ensure the policy matches what we expect. + * The existing code assumes 'sai_power' policy exists. + */ + lws_ss_state_return_t r; + + lwsl_notice("%s: ****** starting sai-power-client link %s\n", __func__, builder.url_sai_power); + + if (lws_ss_set_metadata(ss_power_client, "url", builder.url_sai_power, + strlen(builder.url_sai_power))) + lwsl_warn("%s: unable to set url metadata\n", __func__); + + r = lws_ss_request_tx(ss_power_client); + if (r) + lwsl_notice("%s: initial tx request says %d\n", __func__, (int)r); return 0; } diff --git a/src/builder/b-sai.c b/src/builder/b-sai.c index 98ba30f..38dda21 100644 --- a/src/builder/b-sai.c +++ b/src/builder/b-sai.c @@ -168,6 +168,18 @@ static const char * const default_ss_policy = "\"metadata\": [" "{\"url\": \"\"}" "]" + "}}," + /* + * Used to register with sai-power + */ + "{\"sai_power_client\": {" + "\"endpoint\":" "\"${url}\"," + "\"protocol\":" "\"ws\"," + "\"http_url\":" "\"\"," /* filled in by url */ + "\"retry\":" "\"default\"," + "\"metadata\": [" + "{\"url\": \"\"}" + "]" "}}" "]}" ; diff --git a/src/builder/b-suspender.c b/src/builder/b-suspender.c index 7dd910c..011c009 100644 --- a/src/builder/b-suspender.c +++ b/src/builder/b-suspender.c @@ -125,7 +125,7 @@ callback_sai_suspender_stdwsi(struct lws *wsi, enum lws_callback_reasons reason, struct lws_protocols protocol_suspender_stdxxx = { "sai-suspender-stdxxx", callback_sai_suspender_stdwsi, 0, 0 }; -#if !defined(__APPLE__) && !defined(__NetBSD__) && !defined(__OpenBSD__) +#if !defined(__APPLE__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) static void reap(void *opaque, const lws_spawn_resource_us_t *res, siginfo_t *si, int we_killed_him) { diff --git a/src/builder/b-task.c b/src/builder/b-task.c index 470824f..5eadab8 100644 --- a/src/builder/b-task.c +++ b/src/builder/b-task.c @@ -107,7 +107,7 @@ const char *git_helper_bat = " mkdir \"!MIRROR_PATH!\" 2>nul\n" " if errorlevel 1 (\n" " echo \"git mirror locked, waiting...\"\n" - " timeout /t 1 /nobreak > nul\n" + " C:\\Windows\\System32\\timeout.exe /t 1 /nobreak > nul\n" " goto :lock_wait\n" " )\n" " if exist \"!MIRROR_PATH!\\\\.git\" (\n" diff --git a/src/common/c-utils.c b/src/common/c-utils.c index 96d0f40..46c1fdf 100644 --- a/src/common/c-utils.c +++ b/src/common/c-utils.c @@ -142,6 +142,8 @@ sai_ss_serialize_queue_helper(struct lws_ss_handle *h, r = lws_struct_json_serialize(js, buf + LWS_PRE, sizeof(buf) - LWS_PRE, &w); + lwsl_hexdump_err(buf + LWS_PRE, w); + sai_ss_queue_frag_on_buflist_REQUIRES_LWS_PRE(h, buflist, buf + LWS_PRE, w, (unsigned int)((fi ? LWSSS_FLAG_SOM : 0) | (r == LSJS_RESULT_FINISH ? LWSSS_FLAG_EOM : 0))); diff --git a/src/power/p-http-api.c b/src/power/p-http-api.c index 986df3a..ba0b580 100644 --- a/src/power/p-http-api.c +++ b/src/power/p-http-api.c @@ -223,17 +223,35 @@ local_srv_rx(void *userobj, const uint8_t *buf, size_t len, int flags) { local_srv_t *g = (local_srv_t *)userobj; struct lws_ss_handle *h = lws_ss_from_user(g); - saip_pcon_t *pc; saip_builder_t *b; + saip_pcon_t *pc; + + lwsl_err("%s: %%%%%%%%%%%%%%%%%%%%%% %.*s\n", __func__, (int)len, (const char *)buf); if (!g->ctx.user) { /* first time */ memset(&g->a, 0, sizeof(g->a)); - g->a.map_st[0] = lsm_schema_builder_registration; - g->a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema_builder_registration); - g->a.ac_block_size = 2048; + + g->a.map_st[0] = lsm_schema_builder_registration; + g->a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema_builder_registration); + g->a.ac_block_size = 2048; + lws_struct_json_init_parse(&g->ctx, NULL, &g->a); } + /* + * Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0000: 7B 22 73 63 68 65 6D 61 22 3A 22 63 6F 6D 2E 77 {"schema":"com.w + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0010: 61 72 6D 63 61 74 2E 73 61 69 2E 62 75 69 6C 64 armcat.sai.build + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0020: 65 72 5F 72 65 67 69 73 74 72 61 74 69 6F 6E 22 er_registration" + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0030: 2C 22 70 6C 61 74 66 6F 72 6D 73 22 3A 5B 7B 22 ,"platforms":[{" + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0040: 6E 61 6D 65 22 3A 22 66 72 65 65 62 73 64 2E 66 name":"freebsd.f + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0050: 72 65 65 62 73 64 2F 61 61 72 63 68 36 34 2F 6C reebsd/aarch64/l + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0060: 6C 76 6D 22 7D 5D 2C 22 62 75 69 6C 64 65 72 5F lvm"}],"builder_ + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0070: 6E 61 6D 65 22 3A 22 66 72 65 65 62 73 64 22 2C name":"freebsd", + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0080: 22 70 6F 77 65 72 5F 63 6F 6E 74 72 6F 6C 6C 65 "power_controlle + Dec 02 05:45:31 warmcat.com sai-power[2690328]: 0090: 72 5F 6E 61 6D 65 22 3A 22 70 31 22 7D r_name":"p1"} + * + */ + if (lejp_parse(&g->ctx, buf, (int)len) < 0 || !g->a.dest) { lwsl_ss_warn(h, "JSON decode failed"); lwsac_free(&g->a.ac); @@ -335,8 +353,6 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state, /* g->b->wsi = NULL; */ g->b = NULL; } - /* Clean up lejp if pending? */ - lws_struct_json_init_parse(&g->ctx, NULL, NULL); /* Reset */ break; case LWSSSCS_SERVER_TXN: diff --git a/src/power/p-private.h b/src/power/p-private.h index 83fdc8e..345c96d 100644 --- a/src/power/p-private.h +++ b/src/power/p-private.h @@ -202,6 +202,9 @@ saip_ss_create_tasmota(void); void saip_pcon_start_check(void); +void +saip_switch(saip_pcon_t *pc, int on); + /* Handler for builder WS connections */ int callback_builder(struct lws *wsi, enum lws_callback_reasons reason, diff --git a/src/power/p-utils.c b/src/power/p-utils.c index b4d3480..c8741be 100644 --- a/src/power/p-utils.c +++ b/src/power/p-utils.c @@ -58,3 +58,19 @@ saip_pcon_create(struct sai_power *power, const char *name) return pc; } + +void +saip_switch(saip_pcon_t *pc, int on) +{ + struct lws_ss_handle *h = on ? pc->ss_tasmota_on : pc->ss_tasmota_off; + + if (!h) { + lwsl_err("%s: %s: no ss handle for %s\n", __func__, + pc->name, on ? "ON" : "OFF"); + return; + } + + if (lws_ss_client_connect(h)) + lwsl_ss_err(h, "failed to connect tasmota %s secure stream", + on ? "ON" : "OFF"); +}
Page fetched 0s ago, creation time: 17ms (vhost etag hits: 0%, cache hits: 0%)