feat(ha-config-bootstrap): implement --vcpus CLI, wire validation, remove vcpus from config (task 2.2)

- Add --vcpus N argp option in main.c; store in myconf.vcpus
- Replace inline argp guard with validate_vcpus() call (returns -EINVAL for <=0)
- Add validate_startup_config() in startup_validation.c: returns 0; writes
  deprecation warning into caller-supplied warn_buf when vcpus key present
- Wire validate_startup_config() into myapp_run() after conffile resolved;
  emit WARN() if warn_buf non-empty (Req 4.4)
- Remove vcpus field from cluster_config_t (clusterconfig.h)
- Preserve capnp ordinal: vcpus @7 -> vcpusDeprecated @7: Void in controller.capnp
- vtaskmgr_init uses only myconf->vcpus with hardcoded default 8
- Add stub C types in typemap.h for capnp schema extensions from task 1.1
- 96 tests pass
This commit is contained in:
Rongsong Shen 2026-05-28 04:17:06 +00:00
parent bfa41eb135
commit 3ab2e6e4bf
12 changed files with 225 additions and 8 deletions

View file

@ -0,0 +1,125 @@
/* startup_validation.c — Startup pre-flight validation functions.
*
* Implements validate_vcpus(), validate_startup_config(),
* validate_peer_count(), and validate_cert_files() for use in main.c
* and the controller unit test suite.
*
* Requirements: 4.1 (peer count), 4.2 (cert pre-flight),
* 4.3 (vcpus), 4.4 (vcpus key deprecation warn)
*/
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
/* ── Req 4.3: --vcpus validation ─────────────────────────────────────── */
/*
* validate_vcpus: returns 0 if vcpus >= 1, -EINVAL otherwise.
* Called from main.c after argp_parse() sets arguments.vcpus.
*/
int validate_vcpus(int vcpus)
{
if (vcpus <= 0) {
return -EINVAL;
}
return 0;
}
/* ── Req 4.4: vcpus key in config file — warn only ───────────────────── */
/*
* validate_startup_config: scan config_path for a "vcpus" key.
* If found, write a deprecation warning into warn_buf (must contain "vcpus").
* Always returns 0 — the presence of a vcpus key is not a fatal error.
* warn_buf is left empty (first byte = '\0') when no vcpus key is found.
*
* The scan is line-based: a line contains the vcpus key if it starts with
* optional whitespace followed by the literal string "vcpus".
*/
int validate_startup_config(const char *config_path,
char *warn_buf, size_t warn_len)
{
if (warn_buf && warn_len > 0) {
warn_buf[0] = '\0';
}
if (!config_path) {
return 0;
}
FILE *fp = fopen(config_path, "r");
if (!fp) {
return 0; /* can't open — not a fatal error at this stage */
}
char line[1024];
while (fgets(line, sizeof(line), fp)) {
/* skip leading whitespace */
const char *p = line;
while (*p == ' ' || *p == '\t') {
p++;
}
if (strncmp(p, "vcpus", 5) == 0) {
/* Found a vcpus key — write deprecation warning */
if (warn_buf && warn_len > 0) {
snprintf(warn_buf, warn_len,
"config file contains deprecated 'vcpus' key; "
"use --vcpus CLI parameter instead");
}
break;
}
}
fclose(fp);
return 0;
}
/* ── Req 4.1: even-N peer count rejection ─────────────────────────────── */
/*
* validate_peer_count: returns 0 for valid odd counts (1, 3, 5, ...),
* -EINVAL for even counts > 1.
* n_peers == 1 is single-node mode — always valid.
* Even counts > 1 cannot form a safe majority partition.
*/
int validate_peer_count(int n_peers)
{
if (n_peers > 1 && (n_peers % 2) == 0) {
return -EINVAL;
}
return 0;
}
/* ── Req 4.2: TLS cert pre-flight ─────────────────────────────────────── */
/*
* validate_cert_files: check that cert_path and key_path are readable.
* On the first missing/unreadable file, sets err_buf to a message
* containing the full file path and returns -ENOENT.
* Returns 0 if both files are accessible.
*/
int validate_cert_files(const char *cert_path, const char *key_path,
char *err_buf, size_t err_len)
{
if (access(cert_path, R_OK) != 0) {
if (err_buf && err_len > 0) {
snprintf(err_buf, err_len,
"TLS certificate not found or unreadable: %s",
cert_path);
}
return -ENOENT;
}
if (access(key_path, R_OK) != 0) {
if (err_buf && err_len > 0) {
snprintf(err_buf, err_len,
"TLS key not found or unreadable: %s",
key_path);
}
return -ENOENT;
}
return 0;
}