From 281bc8491216b3be4026ec0ab58a62ef104a6f35 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 15 Feb 2018 17:33:12 +1100 Subject: [PATCH] ctdb-event: Add event daemon protocol Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/event/event_protocol.c | 1122 +++++++++++++++++++ ctdb/event/event_protocol.h | 100 ++ ctdb/event/event_protocol_api.h | 61 + ctdb/event/event_protocol_test.c | 415 +++++++ ctdb/event/event_protocol_util.c | 46 + ctdb/tests/cunit/event_protocol_test_001.sh | 25 + ctdb/wscript | 13 + 7 files changed, 1782 insertions(+) create mode 100644 ctdb/event/event_protocol.c create mode 100644 ctdb/event/event_protocol.h create mode 100644 ctdb/event/event_protocol_api.h create mode 100644 ctdb/event/event_protocol_test.c create mode 100644 ctdb/event/event_protocol_util.c create mode 100755 ctdb/tests/cunit/event_protocol_test_001.sh diff --git a/ctdb/event/event_protocol.c b/ctdb/event/event_protocol.c new file mode 100644 index 000000000000..21adb430c20d --- /dev/null +++ b/ctdb/event/event_protocol.c @@ -0,0 +1,1122 @@ +/* + CTDB event daemon protocol + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include + +#include "protocol/protocol_basic.h" + +#include "event_protocol.h" +#include "event_protocol_api.h" + +static size_t ctdb_event_script_action_len(enum ctdb_event_script_action in) +{ + uint32_t u32 = in; + + return ctdb_uint32_len(&u32); +} + +static void ctdb_event_script_action_push(enum ctdb_event_script_action in, + uint8_t *buf, + size_t *npush) +{ + uint32_t u32 = in; + + ctdb_uint32_push(&u32, buf, npush); +} + +static int ctdb_event_script_action_pull(uint8_t *buf, + size_t buflen, + enum ctdb_event_script_action *out, + size_t *npull) +{ + enum ctdb_event_script_action value; + uint32_t u32; + size_t np; + int ret; + + ret = ctdb_uint32_pull(buf, buflen, &u32, &np); + if (ret != 0) { + return ret; + } + + switch (u32) { + case 0: + value = CTDB_EVENT_SCRIPT_DISABLE; + break; + + case 1: + value = CTDB_EVENT_SCRIPT_ENABLE; + break; + + default: + return EINVAL; + } + + *out = value; + *npull = np; + + return 0; +} + +static size_t ctdb_event_command_len(enum ctdb_event_command in) +{ + uint32_t u32 = in; + + return ctdb_uint32_len(&u32); +} + +static void ctdb_event_command_push(enum ctdb_event_command in, + uint8_t *buf, + size_t *npush) +{ + uint32_t u32 = in; + + ctdb_uint32_push(&u32, buf, npush); +} + +static int ctdb_event_command_pull(uint8_t *buf, + size_t buflen, + enum ctdb_event_command *out, + size_t *npull) +{ + enum ctdb_event_command value; + uint32_t u32; + size_t np; + int ret; + + ret = ctdb_uint32_pull(buf, buflen, &u32, &np); + if (ret != 0) { + return ret; + } + + switch (u32) { + case 1: + value = CTDB_EVENT_CMD_RUN; + break; + + case 2: + value = CTDB_EVENT_CMD_STATUS; + break; + + case 3: + value = CTDB_EVENT_CMD_SCRIPT; + break; + + default: + return EINVAL; + } + + *out = value; + *npull = np; + + return 0; +} + +static size_t ctdb_event_script_len(struct ctdb_event_script *in) +{ + return ctdb_stringn_len(&in->name) + + ctdb_timeval_len(&in->begin) + + ctdb_timeval_len(&in->end) + + ctdb_int32_len(&in->result) + + ctdb_stringn_len(&in->output); +} + +static void ctdb_event_script_push(struct ctdb_event_script *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_stringn_push(&in->name, buf+offset, &np); + offset += np; + + ctdb_timeval_push(&in->begin, buf+offset, &np); + offset += np; + + ctdb_timeval_push(&in->end, buf+offset, &np); + offset += np; + + ctdb_int32_push(&in->result, buf+offset, &np); + offset += np; + + ctdb_stringn_push(&in->output, buf+offset, &np); + offset += np; + + *npush = offset; +} + +static int ctdb_event_script_pull_elems(uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_script *value, + size_t *npull) +{ + size_t offset = 0, np; + int ret; + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + mem_ctx, + &value->name, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_timeval_pull(buf+offset, + buflen-offset, + &value->begin, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_timeval_pull(buf+offset, + buflen-offset, + &value->end, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_int32_pull(buf+offset, + buflen-offset, + &value->result, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + mem_ctx, + &value->output, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + *npull = offset; + + return 0; +} + +#ifdef EVENT_PROTOCOL_TEST +static int ctdb_event_script_pull(uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_script **out, + size_t *npull) +{ + struct ctdb_event_script *value; + int ret; + + value = talloc(mem_ctx, struct ctdb_event_script); + if (value == NULL) { + return ENOMEM; + } + + ret = ctdb_event_script_pull_elems(buf, buflen, value, value, npull); + if (ret != 0) { + talloc_free(value); + return ret; + } + + *out = value; + + return 0; +} +#endif + +static size_t ctdb_event_script_list_len(struct ctdb_event_script_list *in) +{ + size_t len; + int i; + + len = ctdb_int32_len(&in->num_scripts); + + for (i=0; inum_scripts; i++) { + len += ctdb_event_script_len(&in->script[i]); + } + + return len; +} + +static void ctdb_event_script_list_push(struct ctdb_event_script_list *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + int i; + + ctdb_int32_push(&in->num_scripts, buf+offset, &np); + offset += np; + + for (i=0; inum_scripts; i++) { + ctdb_event_script_push(&in->script[i], buf+offset, &np); + offset += np; + } + + *npush = offset; +} + +static int ctdb_event_script_list_pull(uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_script_list **out, + size_t *npull) +{ + struct ctdb_event_script_list *value = NULL; + size_t offset = 0, np; + int num_scripts; + int ret, i; + + ret = ctdb_int32_pull(buf+offset, buflen-offset, &num_scripts, &np); + if (ret != 0) { + return ret; + } + offset += np; + + if (num_scripts < 0) { + return EINVAL; + } + + value = talloc_zero(mem_ctx, struct ctdb_event_script_list); + if (value == NULL) { + return ENOMEM; + } + + value->num_scripts = num_scripts; + if (num_scripts == 0) { + goto done; + } + + value->script = talloc_array(value, struct ctdb_event_script, + num_scripts); + if (value->script == NULL) { + goto fail; + } + + for (i=0; iscript[i], + &np); + if (ret != 0) { + goto fail; + } + offset += np; + } + +done: + *out = value; + *npull = offset; + + return 0; + +fail: + talloc_free(value); + return ret; +} + +static size_t ctdb_event_request_run_len(struct ctdb_event_request_run *in) +{ + return ctdb_stringn_len(&in->component) + + ctdb_stringn_len(&in->event) + + ctdb_stringn_len(&in->args) + + ctdb_uint32_len(&in->timeout) + + ctdb_uint32_len(&in->flags); +} + +static void ctdb_event_request_run_push(struct ctdb_event_request_run *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_stringn_push(&in->component, buf+offset, &np); + offset += np; + + ctdb_stringn_push(&in->event, buf+offset, &np); + offset += np; + + ctdb_stringn_push(&in->args, buf+offset, &np); + offset += np; + + ctdb_uint32_push(&in->timeout, buf+offset, &np); + offset += np; + + ctdb_uint32_push(&in->flags, buf+offset, &np); + offset += np; + + *npush = offset; +} + +static int ctdb_event_request_run_pull(uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_request_run **out, + size_t *npull) +{ + struct ctdb_event_request_run *value; + size_t offset = 0, np; + int ret; + + value = talloc(mem_ctx, struct ctdb_event_request_run); + if (value == NULL) { + return ENOMEM; + } + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + value, + &value->component, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + value, + &value->event, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + value, + &value->args, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_uint32_pull(buf+offset, + buflen-offset, + &value->timeout, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_uint32_pull(buf+offset, + buflen-offset, + &value->flags, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + *out = value; + *npull = offset; + + return 0; + +fail: + talloc_free(value); + return ret; +} + +static size_t ctdb_event_request_status_len( + struct ctdb_event_request_status *in) +{ + return ctdb_stringn_len(&in->component) + + ctdb_stringn_len(&in->event); +} + +static void ctdb_event_request_status_push( + struct ctdb_event_request_status *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_stringn_push(&in->component, buf+offset, &np); + offset += np; + + ctdb_stringn_push(&in->event, buf+offset, &np); + offset += np; + + *npush = offset; +} + +static int ctdb_event_request_status_pull( + uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_request_status **out, + size_t *npull) +{ + struct ctdb_event_request_status *value; + size_t offset = 0, np; + int ret; + + value = talloc(mem_ctx, struct ctdb_event_request_status); + if (value == NULL) { + return ENOMEM; + } + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + value, + &value->component, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + value, + &value->event, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + *out = value; + *npull = offset; + + return 0; + +fail: + talloc_free(value); + return ret; +} + +static size_t ctdb_event_request_script_len( + struct ctdb_event_request_script *in) +{ + return ctdb_stringn_len(&in->component) + + ctdb_stringn_len(&in->script) + + ctdb_event_script_action_len(in->action); +} + +static void ctdb_event_request_script_push( + struct ctdb_event_request_script *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_stringn_push(&in->component, buf+offset, &np); + offset += np; + + ctdb_stringn_push(&in->script, buf+offset, &np); + offset += np; + + ctdb_event_script_action_push(in->action, buf+offset, &np); + offset += np; + + *npush = offset; +} + +static int ctdb_event_request_script_pull( + uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_request_script **out, + size_t *npull) +{ + struct ctdb_event_request_script *value; + size_t offset = 0, np; + int ret; + + value = talloc(mem_ctx, struct ctdb_event_request_script); + if (value == NULL) { + return ENOMEM; + } + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + value, + &value->component, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_stringn_pull(buf+offset, + buflen-offset, + value, + &value->script, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_event_script_action_pull(buf+offset, + buflen-offset, + &value->action, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + *out = value; + *npull = offset; + + return 0; + +fail: + talloc_free(value); + return ret; +} + +static size_t ctdb_event_reply_status_len( + struct ctdb_event_reply_status *in) +{ + return ctdb_int32_len(&in->summary) + + ctdb_event_script_list_len(in->script_list); +} + +static void ctdb_event_reply_status_push( + struct ctdb_event_reply_status *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_int32_push(&in->summary, buf+offset, &np); + offset += np; + + ctdb_event_script_list_push(in->script_list, buf+offset, &np); + offset += np; + + *npush = offset; +} + +static int ctdb_event_reply_status_pull( + uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_reply_status **out, + size_t *npull) +{ + struct ctdb_event_reply_status *value; + size_t offset = 0, np; + int ret; + + value = talloc(mem_ctx, struct ctdb_event_reply_status); + if (value == NULL) { + return ENOMEM; + } + + ret = ctdb_int32_pull(buf+offset, buflen-offset, &value->summary, &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_event_script_list_pull(buf+offset, + buflen-offset, + value, + &value->script_list, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + *out = value; + *npull = offset; + + return 0; + +fail: + talloc_free(value); + return ret; +} + +static size_t ctdb_event_header_len(struct ctdb_event_header *in) +{ + return ctdb_uint32_len(&in->length) + + ctdb_uint32_len(&in->version) + + ctdb_uint32_len(&in->reqid); +} + +static void ctdb_event_header_push(struct ctdb_event_header *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_uint32_push(&in->length, buf+offset, &np); + offset += np; + + ctdb_uint32_push(&in->version, buf+offset, &np); + offset += np; + + ctdb_uint32_push(&in->reqid, buf+offset, &np); + offset += np; + + *npush = offset; +} + +static int ctdb_event_header_pull(uint8_t *buf, + size_t buflen, + struct ctdb_event_header *value, + size_t *npull) +{ + size_t offset = 0, np; + int ret; + + ret = ctdb_uint32_pull(buf+offset, + buflen-offset, + &value->length, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_uint32_pull(buf+offset, + buflen-offset, + &value->version, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_uint32_pull(buf+offset, + buflen-offset, + &value->reqid, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + *npull = offset; + + return 0; +} + +int ctdb_event_header_extract(uint8_t *buf, + size_t buflen, + struct ctdb_event_header *value) +{ + size_t np; + + return ctdb_event_header_pull(buf, buflen, value, &np); +} + +static size_t ctdb_event_request_data_len(struct ctdb_event_request *in) +{ + size_t len; + + len = ctdb_event_command_len(in->cmd); + + switch (in->cmd) { + case CTDB_EVENT_CMD_RUN: + len += ctdb_event_request_run_len(in->data.run); + break; + + case CTDB_EVENT_CMD_STATUS: + len += ctdb_event_request_status_len(in->data.status); + break; + + case CTDB_EVENT_CMD_SCRIPT: + len += ctdb_event_request_script_len(in->data.script); + break; + + default: + break; + } + + return len; +} + +static void ctdb_event_request_data_push(struct ctdb_event_request *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_event_command_push(in->cmd, buf+offset, &np); + offset += np; + + switch (in->cmd) { + case CTDB_EVENT_CMD_RUN: + ctdb_event_request_run_push(in->data.run, buf+offset, &np); + break; + + case CTDB_EVENT_CMD_STATUS: + ctdb_event_request_status_push(in->data.status, + buf+offset, + &np); + break; + + case CTDB_EVENT_CMD_SCRIPT: + ctdb_event_request_script_push(in->data.script, + buf+offset, + &np); + break; + default: + np = 0; + break; + } + offset += np; + + *npush = offset; +} + +static int ctdb_event_request_data_pull(uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_request **out, + size_t *npull) +{ + struct ctdb_event_request *value; + size_t offset = 0, np; + int ret; + + value = talloc(mem_ctx, struct ctdb_event_request); + if (value == NULL) { + return ENOMEM; + } + + ret = ctdb_event_command_pull(buf+offset, + buflen-offset, + &value->cmd, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + switch (value->cmd) { + case CTDB_EVENT_CMD_RUN: + ret = ctdb_event_request_run_pull(buf+offset, + buflen-offset, + value, + &value->data.run, + &np); + break; + + case CTDB_EVENT_CMD_STATUS: + ret = ctdb_event_request_status_pull(buf+offset, + buflen-offset, + value, + &value->data.status, + &np); + break; + + case CTDB_EVENT_CMD_SCRIPT: + ret = ctdb_event_request_script_pull(buf+offset, + buflen-offset, + value, + &value->data.script, + &np); + break; + + default: + np = 0; + break; + } + + if (ret != 0) { + goto fail; + } + offset += np; + + *out = value; + *npull = offset; + + return 0; + +fail: + talloc_free(value); + return ret; +} + +static size_t ctdb_event_reply_data_len(struct ctdb_event_reply *in) +{ + size_t len; + + len = ctdb_event_command_len(in->cmd) + + ctdb_int32_len(&in->result); + + if (in->result != 0) { + goto done; + } + + switch (in->cmd) { + case CTDB_EVENT_CMD_STATUS: + len += ctdb_event_reply_status_len(in->data.status); + break; + + default: + break; + } + +done: + return len; +} + +static void ctdb_event_reply_data_push(struct ctdb_event_reply *in, + uint8_t *buf, + size_t *npush) +{ + size_t offset = 0, np; + + ctdb_event_command_push(in->cmd, buf+offset, &np); + offset += np; + + ctdb_int32_push(&in->result, buf+offset, &np); + offset += np; + + if (in->result != 0) { + goto done; + } + + switch (in->cmd) { + case CTDB_EVENT_CMD_STATUS: + ctdb_event_reply_status_push(in->data.status, buf+offset, &np); + break; + + default: + np = 0; + break; + } + offset += np; + +done: + *npush = offset; +} + +static int ctdb_event_reply_data_pull(uint8_t *buf, + size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_event_reply **out, + size_t *npull) +{ + struct ctdb_event_reply *value; + size_t offset = 0, np; + int ret; + + value = talloc(mem_ctx, struct ctdb_event_reply); + if (value == NULL) { + return ENOMEM; + } + + ret = ctdb_event_command_pull(buf+offset, + buflen-offset, + &value->cmd, + &np); + if (ret != 0) { + goto fail; + } + offset += np; + + ret = ctdb_int32_pull(buf+offset, buflen-offset, &value->result, &np); + if (ret != 0) { + goto fail; + } + offset += np; + + if (value->result != 0) { + goto done; + } + + switch (value->cmd) { + case CTDB_EVENT_CMD_STATUS: + ret = ctdb_event_reply_status_pull(buf+offset, + buflen-offset, + value, + &value->data.status, + &np); + break; + + default: + np = 0; + break; + } + + if (ret != 0) { + goto fail; + } + offset += np; + +done: + *out = value; + *npull = offset; + + return 0; + +fail: + talloc_free(value); + return ret; +} + +size_t ctdb_event_request_len(struct ctdb_event_header *h, + struct ctdb_event_request *in) +{ + return ctdb_event_header_len(h) + + ctdb_event_request_data_len(in); +} + +int ctdb_event_request_push(struct ctdb_event_header *h, + struct ctdb_event_request *in, + uint8_t *buf, + size_t *buflen) +{ + size_t len, offset = 0, np; + + len = ctdb_event_request_len(h, in); + if (*buflen < len) { + *buflen = len; + return EMSGSIZE; + } + + h->length = *buflen; + + ctdb_event_header_push(h, buf+offset, &np); + offset += np; + + ctdb_event_request_data_push(in, buf+offset, &np); + offset += np; + + if (offset > *buflen) { + return EMSGSIZE; + } + + return 0; +} + +int ctdb_event_request_pull(uint8_t *buf, + size_t buflen, + struct ctdb_event_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_event_request **out) +{ + size_t offset = 0, np; + int ret; + + ret = ctdb_event_header_pull(buf+offset, buflen-offset, h, &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_event_request_data_pull(buf+offset, + buflen-offset, + mem_ctx, + out, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + if (offset > buflen) { + return EMSGSIZE; + } + + return 0; +} + +size_t ctdb_event_reply_len(struct ctdb_event_header *h, + struct ctdb_event_reply *in) +{ + return ctdb_event_header_len(h) + + ctdb_event_reply_data_len(in); +} + +int ctdb_event_reply_push(struct ctdb_event_header *h, + struct ctdb_event_reply *in, + uint8_t *buf, + size_t *buflen) +{ + size_t len, offset = 0, np; + + len = ctdb_event_reply_len(h, in); + if (*buflen < len) { + *buflen = len; + return EMSGSIZE; + } + + h->length = *buflen; + + ctdb_event_header_push(h, buf+offset, &np); + offset += np; + + ctdb_event_reply_data_push(in, buf+offset, &np); + offset += np; + + if (offset > *buflen) { + return EMSGSIZE; + } + + return 0; +} + +int ctdb_event_reply_pull(uint8_t *buf, + size_t buflen, + struct ctdb_event_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_event_reply **out) +{ + size_t offset = 0, np; + int ret; + + ret = ctdb_event_header_pull(buf+offset, buflen-offset, h, &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_event_reply_data_pull(buf+offset, + buflen-offset, + mem_ctx, + out, + &np); + if (ret != 0) { + return ret; + } + offset += np; + + if (offset > buflen) { + return EMSGSIZE; + } + + return 0; +} diff --git a/ctdb/event/event_protocol.h b/ctdb/event/event_protocol.h new file mode 100644 index 000000000000..e7680fc3cb17 --- /dev/null +++ b/ctdb/event/event_protocol.h @@ -0,0 +1,100 @@ +/* + CTDB event daemon protocol + Based on eventd code + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_EVENT_PROTOCOL_H__ +#define __CTDB_EVENT_PROTOCOL_H__ + +#define CTDB_EVENT_PROTOCOL_VERSION 1 + +enum ctdb_event_script_action { + CTDB_EVENT_SCRIPT_DISABLE = 0, + CTDB_EVENT_SCRIPT_ENABLE = 1, +}; + +enum ctdb_event_command { + CTDB_EVENT_CMD_RUN = 1, + CTDB_EVENT_CMD_STATUS = 2, + CTDB_EVENT_CMD_SCRIPT = 3, + CTDB_EVENT_CMD_MAX = 4, +}; + +struct ctdb_event_script { + const char *name; + struct timeval begin; + struct timeval end; + int result; + const char *output; +}; + +struct ctdb_event_script_list { + int num_scripts; + struct ctdb_event_script *script; +}; + +#define CTDB_EVENT_RUN_ALL 1 + +struct ctdb_event_request_run { + const char *component; + const char *event; + const char *args; + uint32_t timeout; + uint32_t flags; +}; + +struct ctdb_event_request_status { + const char *component; + const char *event; +}; + +struct ctdb_event_request_script { + const char *component; + const char *script; + enum ctdb_event_script_action action; +}; + +struct ctdb_event_reply_status { + int32_t summary; + struct ctdb_event_script_list *script_list; +}; + +struct ctdb_event_header { + uint32_t length; + uint32_t version; + uint32_t reqid; +}; + +struct ctdb_event_request { + enum ctdb_event_command cmd; + union { + struct ctdb_event_request_run *run; + struct ctdb_event_request_status *status; + struct ctdb_event_request_script *script; + } data; +}; + +struct ctdb_event_reply { + enum ctdb_event_command cmd; + int32_t result; + union { + struct ctdb_event_reply_status *status; + } data; +}; + +#endif /* __CTDB_EVENT_PROTOCOL_H__ */ diff --git a/ctdb/event/event_protocol_api.h b/ctdb/event/event_protocol_api.h new file mode 100644 index 000000000000..e2ab439fd840 --- /dev/null +++ b/ctdb/event/event_protocol_api.h @@ -0,0 +1,61 @@ +/* + CTDB event daemon protocol + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_EVENT_PROTOCOL_API_H__ +#define __CTDB_EVENT_PROTOCOL_API_H__ + +#include + +#include "event/event_protocol.h" + +/* From event/event_protocol.c */ + +int ctdb_event_header_extract(uint8_t *buf, + size_t buflen, + struct ctdb_event_header *h); + +size_t ctdb_event_request_len(struct ctdb_event_header *h, + struct ctdb_event_request *in); +int ctdb_event_request_push(struct ctdb_event_header *h, + struct ctdb_event_request *in, + uint8_t *buf, + size_t *buflen); +int ctdb_event_request_pull(uint8_t *buf, + size_t buflen, + struct ctdb_event_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_event_request **out); + +size_t ctdb_event_reply_len(struct ctdb_event_header *h, + struct ctdb_event_reply *in); +int ctdb_event_reply_push(struct ctdb_event_header *h, + struct ctdb_event_reply *in, + uint8_t *buf, + size_t *buflen); +int ctdb_event_reply_pull(uint8_t *buf, + size_t buflen, + struct ctdb_event_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_event_reply **out); + +/* From event/event_protocol_util.c */ + +const char *ctdb_event_command_to_string(enum ctdb_event_command cmd); + +#endif /* __CTDB_EVENT_PROTOCOL_API_H__ */ diff --git a/ctdb/event/event_protocol_test.c b/ctdb/event/event_protocol_test.c new file mode 100644 index 000000000000..7f939f881cf3 --- /dev/null +++ b/ctdb/event/event_protocol_test.c @@ -0,0 +1,415 @@ +/* + CTDB event daemon - protocol test + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include +#include + +#define EVENT_PROTOCOL_TEST +#include "event/event_protocol.c" + +#include "tests/src/protocol_common_basic.h" + +/* + * Functions to fill and verify event protocol structures + */ + +static void fill_ctdb_event_script(TALLOC_CTX *mem_ctx, + struct ctdb_event_script *p) +{ + fill_ctdb_stringn(mem_ctx, &p->name); + fill_ctdb_timeval(&p->begin); + fill_ctdb_timeval(&p->end); + p->result = rand32i(); + fill_ctdb_stringn(mem_ctx, &p->output); +} + +static void verify_ctdb_event_script(struct ctdb_event_script *p1, + struct ctdb_event_script *p2) +{ + verify_ctdb_stringn(&p1->name, &p2->name); + verify_ctdb_timeval(&p1->begin, &p2->begin); + verify_ctdb_timeval(&p1->end, &p2->end); + assert(p1->result == p2->result); + verify_ctdb_stringn(&p1->output, &p2->output); +} + +static void fill_ctdb_event_script_list(TALLOC_CTX *mem_ctx, + struct ctdb_event_script_list *p) +{ + int i; + + p->num_scripts = rand_int(32); + if (p->num_scripts > 0) { + p->script = talloc_array(mem_ctx, + struct ctdb_event_script, + p->num_scripts); + assert(p->script != NULL); + + for (i=0; inum_scripts; i++) { + fill_ctdb_event_script(mem_ctx, &p->script[i]); + } + } else { + p->script = NULL; + } +} + +static void verify_ctdb_event_script_list(struct ctdb_event_script_list *p1, + struct ctdb_event_script_list *p2) +{ + int i; + + assert(p1->num_scripts == p2->num_scripts); + for (i=0; inum_scripts; i++) { + verify_ctdb_event_script(&p1->script[i], &p2->script[i]); + } +} + +static void fill_ctdb_event_request_run(TALLOC_CTX *mem_ctx, + struct ctdb_event_request_run *p) +{ + fill_ctdb_stringn(mem_ctx, &p->component); + fill_ctdb_stringn(mem_ctx, &p->event); + fill_ctdb_stringn(mem_ctx, &p->args); + p->timeout = rand32(); + p->flags = rand32(); +} + +static void verify_ctdb_event_request_run(struct ctdb_event_request_run *p1, + struct ctdb_event_request_run *p2) +{ + verify_ctdb_stringn(&p1->component, &p2->component); + verify_ctdb_stringn(&p1->event, &p2->event); + verify_ctdb_stringn(&p1->args, &p2->args); + assert(p1->timeout == p2->timeout); + assert(p1->flags == p2->flags); +} + +static void fill_ctdb_event_request_status(TALLOC_CTX *mem_ctx, + struct ctdb_event_request_status *p) +{ + fill_ctdb_stringn(mem_ctx, &p->component); + fill_ctdb_stringn(mem_ctx, &p->event); +} + +static void verify_ctdb_event_request_status( + struct ctdb_event_request_status *p1, + struct ctdb_event_request_status *p2) +{ + verify_ctdb_stringn(&p1->component, &p2->component); + verify_ctdb_stringn(&p1->event, &p2->event); +} + +static void fill_ctdb_event_request_script(TALLOC_CTX *mem_ctx, + struct ctdb_event_request_script *p) +{ + fill_ctdb_stringn(mem_ctx, &p->component); + fill_ctdb_stringn(mem_ctx, &p->script); + if (rand_int(1) == 0) { + p->action = CTDB_EVENT_SCRIPT_DISABLE; + } else { + p->action = CTDB_EVENT_SCRIPT_ENABLE; + } +} + +static void fill_ctdb_event_reply_status(TALLOC_CTX *mem_ctx, + struct ctdb_event_reply_status *p) +{ + p->summary = rand32i(); + p->script_list = talloc(mem_ctx, struct ctdb_event_script_list); + assert(p->script_list != NULL); + + fill_ctdb_event_script_list(mem_ctx, p->script_list); +} + +static void verify_ctdb_event_reply_status(struct ctdb_event_reply_status *p1, + struct ctdb_event_reply_status *p2) +{ + assert(p1->summary == p2->summary); + verify_ctdb_event_script_list(p1->script_list, p2->script_list); +} + +static void verify_ctdb_event_request_script( + struct ctdb_event_request_script *p1, + struct ctdb_event_request_script *p2) +{ + verify_ctdb_stringn(&p1->component, &p2->component); + verify_ctdb_stringn(&p1->script, &p2->script); + assert(p1->action == p2->action); +} + +static void fill_ctdb_event_request_data(TALLOC_CTX *mem_ctx, + struct ctdb_event_request *p, + uint32_t cmd) +{ + p->cmd = cmd; + + switch (cmd) { + case CTDB_EVENT_CMD_RUN: + p->data.run = talloc(mem_ctx, struct ctdb_event_request_run); + assert(p->data.run != NULL); + + fill_ctdb_event_request_run(mem_ctx, p->data.run); + break; + + case CTDB_EVENT_CMD_STATUS: + p->data.status = talloc(mem_ctx, + struct ctdb_event_request_status); + assert(p->data.status != NULL); + + fill_ctdb_event_request_status(mem_ctx, p->data.status); + break; + + case CTDB_EVENT_CMD_SCRIPT: + p->data.script = talloc(mem_ctx, + struct ctdb_event_request_script); + assert(p->data.script != NULL); + + fill_ctdb_event_request_script(mem_ctx, p->data.script); + break; + + default: + assert(cmd > 0 && cmd < CTDB_EVENT_CMD_MAX); + } +} + +static void verify_ctdb_event_request_data(struct ctdb_event_request *p1, + struct ctdb_event_request *p2) +{ + assert(p1->cmd == p2->cmd); + + switch (p1->cmd) { + case CTDB_EVENT_CMD_RUN: + verify_ctdb_event_request_run(p1->data.run, p2->data.run); + break; + + case CTDB_EVENT_CMD_STATUS: + verify_ctdb_event_request_status(p1->data.status, + p2->data.status); + break; + + case CTDB_EVENT_CMD_SCRIPT: + verify_ctdb_event_request_script(p1->data.script, + p2->data.script); + break; + + default: + assert(p1->cmd > 0 && p1->cmd < CTDB_EVENT_CMD_MAX); + } +} + +static void fill_ctdb_event_reply_data(TALLOC_CTX *mem_ctx, + struct ctdb_event_reply *p, + uint32_t cmd) +{ + p->cmd = cmd; + p->result = rand32i(); + + if (p->result != 0) { + return; + } + + switch (cmd) { + case CTDB_EVENT_CMD_STATUS: + p->data.status = talloc(mem_ctx, + struct ctdb_event_reply_status); + assert(p->data.status != NULL); + + fill_ctdb_event_reply_status(mem_ctx, p->data.status); + break; + + default: + assert(cmd > 0 && cmd < CTDB_EVENT_CMD_MAX); + } +} + +static void verify_ctdb_event_reply_data(struct ctdb_event_reply *p1, + struct ctdb_event_reply *p2) +{ + assert(p1->cmd == p2->cmd); + assert(p1->result == p2->result); + + if (p1->result != 0) { + return; + } + + switch (p1->cmd) { + case CTDB_EVENT_CMD_STATUS: + verify_ctdb_event_reply_status(p1->data.status, + p2->data.status); + break; + + default: + assert(p1->cmd > 0 && p1->cmd < CTDB_EVENT_CMD_MAX); + } +} + +static void fill_ctdb_event_header(struct ctdb_event_header *p) +{ + p->length = 0; /* updated by push functions */ + p->version = 0; /* updated by push functions */ + p->reqid = rand32(); +} + +static void verify_ctdb_event_header(struct ctdb_event_header *p1, + struct ctdb_event_header *p2) +{ + assert(p1->length == p2->length); + assert(p1->version == p2->version); + assert(p1->reqid == p2->reqid); +} + +static void fill_ctdb_event_request(TALLOC_CTX *mem_ctx, + struct ctdb_event_request *p, + uint32_t cmd) +{ + fill_ctdb_event_request_data(mem_ctx, p, cmd); +} + +static void verify_ctdb_event_request(struct ctdb_event_request *p1, + struct ctdb_event_request *p2) +{ + verify_ctdb_event_request_data(p1, p2); +} + +static void fill_ctdb_event_reply(TALLOC_CTX *mem_ctx, + struct ctdb_event_reply *p, + uint32_t cmd) +{ + fill_ctdb_event_reply_data(mem_ctx, p, cmd); +} + +static void verify_ctdb_event_reply(struct ctdb_event_reply *p1, + struct ctdb_event_reply *p2) +{ + verify_ctdb_event_reply_data(p1, p2); +} + +#define EVENT_PROTOCOL1_TEST(TYPE, NAME) \ +static void TEST_FUNC(NAME)(uint32_t cmd) \ +{ \ + TALLOC_CTX *mem_ctx; \ + TYPE c1, *c2; \ + uint8_t *buf; \ + size_t buflen, np; \ + int ret; \ +\ + printf("%s %u\n", #NAME, cmd); \ + fflush(stdout); \ + mem_ctx = talloc_new(NULL); \ + assert(mem_ctx != NULL); \ + FILL_FUNC(NAME)(mem_ctx, &c1, cmd); \ + buflen = LEN_FUNC(NAME)(&c1); \ + buf = talloc_size(mem_ctx, buflen); \ + assert(buf != NULL); \ + np = 0; \ + PUSH_FUNC(NAME)(&c1, buf, &np); \ + assert(np == buflen); \ + np = 0; \ + ret = PULL_FUNC(NAME)(buf, buflen, mem_ctx, &c2, &np); \ + assert(ret == 0); \ + assert(np == buflen); \ + VERIFY_FUNC(NAME)(&c1, c2); \ + talloc_free(mem_ctx); \ +} + +#define EVENT_PROTOCOL2_TEST(TYPE, NAME) \ +static void TEST_FUNC(NAME)(uint32_t cmd) \ +{ \ + TALLOC_CTX *mem_ctx; \ + struct ctdb_event_header h1, h2; \ + TYPE c1, *c2; \ + uint8_t *buf; \ + size_t buflen, len; \ + int ret; \ +\ + printf("%s %u\n", #NAME, cmd); \ + fflush(stdout); \ + mem_ctx = talloc_new(NULL); \ + assert(mem_ctx != NULL); \ + fill_ctdb_event_header(&h1); \ + FILL_FUNC(NAME)(mem_ctx, &c1, cmd); \ + buflen = LEN_FUNC(NAME)(&h1, &c1); \ + buf = talloc_size(mem_ctx, buflen); \ + assert(buf != NULL); \ + len = 0; \ + ret = PUSH_FUNC(NAME)(&h1, &c1, buf, &len); \ + assert(ret == EMSGSIZE); \ + assert(len == buflen); \ + ret = PUSH_FUNC(NAME)(&h1, &c1, buf, &buflen); \ + assert(ret == 0); \ + ret = PULL_FUNC(NAME)(buf, buflen, &h2, mem_ctx, &c2); \ + assert(ret == 0); \ + verify_ctdb_event_header(&h1, &h2); \ + VERIFY_FUNC(NAME)(&c1, c2); \ + talloc_free(mem_ctx); \ +} + +PROTOCOL_TYPE3_TEST(struct ctdb_event_script, ctdb_event_script); +PROTOCOL_TYPE3_TEST(struct ctdb_event_script_list, ctdb_event_script_list); + +PROTOCOL_TYPE3_TEST(struct ctdb_event_request_run, ctdb_event_request_run); +PROTOCOL_TYPE3_TEST(struct ctdb_event_request_status, + ctdb_event_request_status); +PROTOCOL_TYPE3_TEST(struct ctdb_event_request_script, + ctdb_event_request_script); + +PROTOCOL_TYPE3_TEST(struct ctdb_event_reply_status, ctdb_event_reply_status); + +EVENT_PROTOCOL1_TEST(struct ctdb_event_request, ctdb_event_request_data); +EVENT_PROTOCOL1_TEST(struct ctdb_event_reply, ctdb_event_reply_data); + +EVENT_PROTOCOL2_TEST(struct ctdb_event_request, ctdb_event_request); +EVENT_PROTOCOL2_TEST(struct ctdb_event_reply, ctdb_event_reply); + +int main(int argc, const char **argv) +{ + uint32_t cmd; + + if (argc == 2) { + int seed = atoi(argv[1]); + srandom(seed); + } + + TEST_FUNC(ctdb_event_script)(); + TEST_FUNC(ctdb_event_script_list)(); + + TEST_FUNC(ctdb_event_request_run)(); + TEST_FUNC(ctdb_event_request_status)(); + TEST_FUNC(ctdb_event_request_script)(); + + TEST_FUNC(ctdb_event_reply_status)(); + + for (cmd=1; cmd. +*/ + +#include "replace.h" + +#include "event/event_protocol.h" +#include "event/event_protocol_api.h" + +static struct { + enum ctdb_event_command command; + const char *label; +} event_command_map[] = { + { CTDB_EVENT_CMD_RUN, "RUN" }, + { CTDB_EVENT_CMD_STATUS, "STATUS" }, + { CTDB_EVENT_CMD_SCRIPT, "SCRIPT" }, + { CTDB_EVENT_CMD_MAX, NULL }, +}; + +const char *ctdb_event_command_to_string(enum ctdb_event_command command) +{ + int i; + + for (i=0; event_command_map[i].label != NULL; i++) { + if (event_command_map[i].command == command) { + return event_command_map[i].label; + } + } + + return "UNKNOWN"; +} diff --git a/ctdb/tests/cunit/event_protocol_test_001.sh b/ctdb/tests/cunit/event_protocol_test_001.sh new file mode 100755 index 000000000000..d1a7778c77f6 --- /dev/null +++ b/ctdb/tests/cunit/event_protocol_test_001.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +last_command=3 + +generate_output () +{ + for i in $(seq 1 $last_command) ; do + echo "$1 $i" + done +} + +output=$( + generate_output "ctdb_event_request_data" + generate_output "ctdb_event_reply_data" + generate_output "ctdb_event_request" + generate_output "ctdb_event_reply" +) + +ok "$output" + +for i in $(seq 1 100) ; do + unit_test event_protocol_test $i +done diff --git a/ctdb/wscript b/ctdb/wscript index c762106ccc05..90cb0a6b2b31 100644 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -497,6 +497,13 @@ def build(bld): ctdb-util samba-util talloc replace popt''', install_path='${CTDB_HELPER_BINDIR}') + bld.SAMBA_SUBSYSTEM('ctdb-event-protocol', + source=bld.SUBDIR('event', + '''event_protocol.c + event_protocol_util.c + '''), + deps='ctdb-protocol-basic') + bld.SAMBA_BINARY('ctdbd', source='server/ctdbd.c ' + bld.SUBDIR('server', @@ -879,6 +886,12 @@ def build(bld): samba-util talloc tdb''', install_path='${CTDB_TEST_LIBEXECDIR}') + bld.SAMBA_BINARY('event_protocol_test', + source='event/event_protocol_test.c', + deps='''ctdb-protocol-tests-basic + ctdb-protocol-basic talloc''', + install_path='${CTDB_TEST_LIBEXECDIR}') + bld.SAMBA_SUBSYSTEM('ctdb-tests-common', source=bld.SUBDIR('tests/src', 'cluster_wait.c test_options.c'), -- 2.34.1