feat: P0-2a C-side plumbing for host control
Add the full call chain for host control operations from the Go API server through the C library to the controller: - schema/controller.capnp: HostControl struct + hostctrlmsg @21 in Request.body union - include/typemap.h: xce_hostctrl_t* hostctrlmsg in body union (placed after @20 clrpreasonmsg, matching capnp ordinal) - include/client.h, xceapi.h, request.h: declarations for xcecli_hostctrl, xce_hostctrl, xce_hostctrl_req - lib/client.c: xcecli_hostctrl (validate + delegate to xce_hostctrl) - lib/xceapi.c: xce_hostctrl (validate ctx state + send + wait reply) - lib/request.c: xce_hostctrl_req (validate hostname/empty/nil, accept only HOST_OPEN/HOST_CLOSE, reject HOST_TAG/UNTAG) - lib/helper.c: Request_body_hostctrlmsg cases in xce_request_body() and xce_request_msg_name() - controller/cluster.c: OPCode_hostcontrol dispatch - controller/include/cluster.h: do_hostcontrol_op declaration - controller/worker.c: do_hostcontrol_op + fix pre-existing goto-clean bug in worker_ctrl that leaked write lock and reference on HOST_OPEN/HOST_CLOSE no-op paths TDD: 8 xce_hostctrl_req validation tests (null ep, null ctrl, null/empty hostname, HOST_DO_NONE no-op, HOST_TAG/UNTAG reject, negative action reject, HOST_OPEN/CLOSE accept via xce_request). 116/116 xcelib tests pass. CGO_ENABLED=0 Go backend tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ac7ac99ced
commit
dcb1b4fe25
15 changed files with 187 additions and 4 deletions
|
|
@ -516,6 +516,19 @@ int xcecli_queuectrl(xcecli_ctx_t c, xce_queuectrl_t* ctrlinfo)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int xcecli_hostctrl(xcecli_ctx_t c, xce_hostctrl_t* ctrlinfo)
|
||||
{
|
||||
api_ctx_t* ctx = (api_ctx_t*)c;
|
||||
int rc;
|
||||
|
||||
if ((ctx == NULL) || (ctrlinfo == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = xce_hostctrl(&(ctx->ctx), ctrlinfo);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int xcecli_runtask(xcecli_ctx_t c, xce_taskrun_t* info)
|
||||
{
|
||||
api_ctx_t* ctx = (api_ctx_t*)c;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ void* xce_request_body(xce_request_t* req)
|
|||
return req->body.jobctrlmsg;
|
||||
case Request_body_queuectrlmsg:
|
||||
return req->body.queuectrlmsg;
|
||||
case Request_body_hostctrlmsg:
|
||||
return req->body.hostctrlmsg;
|
||||
case Request_body_runtaskmsg:
|
||||
return req->body.runtaskmsg;
|
||||
case Request_body_preasonmsg:
|
||||
|
|
@ -85,6 +87,8 @@ char* xce_request_msg_name(xce_request_t* req)
|
|||
return "jobctrlmsg";
|
||||
case Request_body_queuectrlmsg:
|
||||
return "queuectrlmsg";
|
||||
case Request_body_hostctrlmsg:
|
||||
return "hostctrlmsg";
|
||||
case Request_body_runtaskmsg:
|
||||
return "runtaskmsg";
|
||||
case Request_body_preasonmsg:
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ libxce_test_src = ['testsuite/test.c',
|
|||
'testsuite/test_jobj.c',
|
||||
'testsuite/test_wobj.c',
|
||||
'testsuite/test_qobj.c',
|
||||
'testsuite/test_request.c',
|
||||
]
|
||||
|
||||
libxce_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_dep]
|
||||
|
|
|
|||
|
|
@ -844,6 +844,37 @@ int xce_queuectrl_req(endpoint_t* ep, xce_queuectrl_t* ctrlinfo)
|
|||
return xce_request(ep, &request);
|
||||
}
|
||||
|
||||
int xce_hostctrl_req(endpoint_t* ep, xce_hostctrl_t* ctrlinfo)
|
||||
{
|
||||
/* clang-format off */
|
||||
xce_request_t request = {
|
||||
.opcode = OPCode_hostcontrol,
|
||||
.body_which = Request_body_hostctrlmsg,
|
||||
.body = {
|
||||
.hostctrlmsg = ctrlinfo
|
||||
}
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
if ((ep == NULL) || (ctrlinfo == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((ctrlinfo->hostname == NULL) || (strlen(ctrlinfo->hostname) == 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ctrlinfo->action == HOST_DO_NONE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctrlinfo->action != HOST_OPEN && ctrlinfo->action != HOST_CLOSE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return xce_request(ep, &request);
|
||||
}
|
||||
|
||||
int xce_runtask_req(endpoint_t* ep, xce_taskrun_t* runinfo)
|
||||
{
|
||||
/* clang-format off */
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ extern void test_kv(void);
|
|||
extern void test_jobobj(void);
|
||||
extern void test_qobj(void);
|
||||
extern void test_wobj(void);
|
||||
extern void test_request(void);
|
||||
|
||||
void setUp(void) { return; }
|
||||
|
||||
|
|
@ -123,6 +124,7 @@ int main(int argc, char* argv[])
|
|||
TEST(test_jobobj);
|
||||
TEST(test_wobj);
|
||||
TEST(test_qobj);
|
||||
TEST(test_request);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
|
|||
79
src/lib/testsuite/test_request.c
Normal file
79
src/lib/testsuite/test_request.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unity/unity.h>
|
||||
#include "request.h"
|
||||
#include "xce/types.h"
|
||||
|
||||
/* Tests for xce_hostctrl_req() validation paths.
|
||||
* We test only early-return paths (before xce_request() is called)
|
||||
* since a live endpoint is not available in unit tests. */
|
||||
|
||||
static void test_hostctrl_req_null_ep(void)
|
||||
{
|
||||
xce_hostctrl_t ctrl = { .action = HOST_OPEN, .hostname = "host1" };
|
||||
int rc = xce_hostctrl_req(NULL, &ctrl);
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, rc);
|
||||
}
|
||||
|
||||
static void test_hostctrl_req_null_ctrl(void)
|
||||
{
|
||||
/* non-NULL dummy ep is enough; the NULL ctrl check fires first */
|
||||
int rc = xce_hostctrl_req((endpoint_t*)0x1, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, rc);
|
||||
}
|
||||
|
||||
static void test_hostctrl_req_null_hostname(void)
|
||||
{
|
||||
xce_hostctrl_t ctrl = { .action = HOST_OPEN, .hostname = NULL };
|
||||
int rc = xce_hostctrl_req((endpoint_t*)0x1, &ctrl);
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, rc);
|
||||
}
|
||||
|
||||
static void test_hostctrl_req_empty_hostname(void)
|
||||
{
|
||||
xce_hostctrl_t ctrl = { .action = HOST_OPEN, .hostname = "" };
|
||||
int rc = xce_hostctrl_req((endpoint_t*)0x1, &ctrl);
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, rc);
|
||||
}
|
||||
|
||||
static void test_hostctrl_req_noop(void)
|
||||
{
|
||||
xce_hostctrl_t ctrl = { .action = HOST_DO_NONE, .hostname = "host1" };
|
||||
int rc = xce_hostctrl_req((endpoint_t*)0x1, &ctrl);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
}
|
||||
|
||||
static void test_hostctrl_req_reject_tag(void)
|
||||
{
|
||||
xce_hostctrl_t ctrl = { .action = HOST_TAG, .hostname = "host1" };
|
||||
int rc = xce_hostctrl_req((endpoint_t*)0x1, &ctrl);
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, rc);
|
||||
}
|
||||
|
||||
static void test_hostctrl_req_reject_untag(void)
|
||||
{
|
||||
xce_hostctrl_t ctrl = { .action = HOST_UNTAG, .hostname = "host1" };
|
||||
int rc = xce_hostctrl_req((endpoint_t*)0x1, &ctrl);
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, rc);
|
||||
}
|
||||
|
||||
static void test_hostctrl_req_reject_negative_action(void)
|
||||
{
|
||||
xce_hostctrl_t ctrl = { .action = -1, .hostname = "host1" };
|
||||
int rc = xce_hostctrl_req((endpoint_t*)0x1, &ctrl);
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, rc);
|
||||
}
|
||||
|
||||
void test_request(void)
|
||||
{
|
||||
printf("\n>> host control request validation tests\n\n");
|
||||
RUN_TEST(test_hostctrl_req_null_ep);
|
||||
RUN_TEST(test_hostctrl_req_null_ctrl);
|
||||
RUN_TEST(test_hostctrl_req_null_hostname);
|
||||
RUN_TEST(test_hostctrl_req_empty_hostname);
|
||||
RUN_TEST(test_hostctrl_req_noop);
|
||||
RUN_TEST(test_hostctrl_req_reject_tag);
|
||||
RUN_TEST(test_hostctrl_req_reject_untag);
|
||||
RUN_TEST(test_hostctrl_req_reject_negative_action);
|
||||
}
|
||||
|
|
@ -561,6 +561,32 @@ int xce_queuectrl(xce_ctx_t* ctx, xce_queuectrl_t* ctrl)
|
|||
return status;
|
||||
}
|
||||
|
||||
int xce_hostctrl(xce_ctx_t* ctx, xce_hostctrl_t* ctrl)
|
||||
{
|
||||
int rc;
|
||||
int status;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ctx->state != XCE_CTX_RUN) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = xce_hostctrl_req(ctx->ep, ctrl);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cbuf_get(&(ctx->wbuf), &status);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int xce_runtask(xce_ctx_t* ctx, xce_taskrun_t* runinfo)
|
||||
{
|
||||
int rc;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue