diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a99d2cc95f1de1c828e06ab682bfa03c9f417252..16558514316b50e4c2d2aea64b50e2a77e67daba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -143,7 +143,6 @@ test:ubuntu:latest: - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_register_job]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_update_job]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_unregister_job]" - - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_ping]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_add_process]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_remove_process]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_resource_init]" @@ -156,6 +155,7 @@ test:ubuntu:latest: - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_submit]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_status]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_status]" + - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::nornsctl_send_command]" after_script: - pwd - if [[ -e tests.log ]]; diff --git a/include/norns/norns_error.h b/include/norns/norns_error.h index 167889f3059b4e04fa08f35f479e3f7d22756d24..d9d5b830686403b94a642fa685bcee390ec9e939 100644 --- a/include/norns/norns_error.h +++ b/include/norns/norns_error.h @@ -50,6 +50,7 @@ extern "C" { #define NORNS_ECONNFAILED -5 #define NORNS_ERPCSENDFAILED -6 #define NORNS_ERPCRECVFAILED -7 +#define NORNS_EACCEPTPAUSED -8 /* errors about jobs */ #define NORNS_EJOBEXISTS -10 diff --git a/include/norns/nornsctl.h b/include/norns/nornsctl.h index c6cceea7fc3a557ad80b34c11bbc425a4e8d31f4..2d4bb87b5326bb321a3b07dacf904c18f5e2d322 100644 --- a/include/norns/nornsctl.h +++ b/include/norns/nornsctl.h @@ -120,10 +120,6 @@ nornsctl_job_init(nornsctl_job_t* job, nornsctl_job_limit_t** limits, size_t nlimits) __THROW; -/* Check if the service daemon is running */ -norns_error_t -nornsctl_ping(void) __THROW; - /* Send a command to the service daemon */ norns_error_t nornsctl_send_command(nornsctl_command_t command, diff --git a/include/norns/nornsctl_types.h b/include/norns/nornsctl_types.h index aacfa0e3b708f5f7eb335c92884298ab24ce5fb5..07b8fb9cbc3f7dba88458eb175b5d364e38b32c5 100644 --- a/include/norns/nornsctl_types.h +++ b/include/norns/nornsctl_types.h @@ -34,9 +34,17 @@ extern "C" { #include "norns_types.h" -/* Types */ +/* Additional administrative types */ typedef uint32_t nornsctl_backend_flags_t; -typedef uint32_t nornsctl_command_t; +//typedef uint32_t nornsctl_command_t; + +/* Administrative command IDs valid for nornsctl_send_command() */ +typedef enum { + NORNSCTL_COMMAND_PING = 1000, + NORNSCTL_COMMAND_PAUSE_ACCEPT, + NORNSCTL_COMMAND_RESUME_ACCEPT, +} nornsctl_command_t; + #ifdef __cplusplus }; diff --git a/lib/communication.c b/lib/communication.c index 5a5c7946c651ce8cff4331f969d636d57e5fc6be..263a5d5259b78f80018ba751023bd7b28209dc33 100644 --- a/lib/communication.c +++ b/lib/communication.c @@ -47,12 +47,12 @@ #include "log.h" static int connect_to_daemon(const char* socket_path); -static int send_message(int conn, const msgbuffer_t* buffer); -static int recv_message(int conn, msgbuffer_t* buffer); +static int send_message(int conn, const norns_msgbuffer_t* buffer); +static int recv_message(int conn, norns_msgbuffer_t* buffer); static ssize_t recv_data(int conn, void* data, size_t size); static ssize_t send_data(int conn, const void* data, size_t size); static void print_hex(void* buffer, size_t bytes) __attribute__((unused)); -static norns_error_t send_request(norns_rpc_type_t type, norns_response_t* resp, ...); +static norns_error_t send_request(norns_msgtype_t type, norns_response_t* resp, ...); norns_error_t send_submit_request(norns_iotask_t* task) { @@ -81,6 +81,25 @@ send_submit_request(norns_iotask_t* task) { return resp.r_error_code; } +norns_error_t +send_control_command_request(nornsctl_command_t cmd, void* args) { + + int res; + norns_response_t resp; + + if((res = send_request(NORNSCTL_COMMAND, &resp, cmd, args)) + != NORNS_SUCCESS) { + return res; + } + + if(resp.r_type != NORNSCTL_COMMAND) { + return NORNS_ESNAFU; + } + + return NORNS_SUCCESS; +} + + norns_error_t send_status_request(norns_iotask_t* task, norns_stat_t* stats) { @@ -113,12 +132,12 @@ send_control_status_request(nornsctl_stat_t* stats) { int res; norns_response_t resp; - if((res = send_request(NORNSCTL_STATUS, &resp)) + if((res = send_request(NORNSCTL_GLOBAL_STATUS, &resp)) != NORNS_SUCCESS) { return res; } - if(resp.r_type != NORNSCTL_STATUS) { + if(resp.r_type != NORNSCTL_GLOBAL_STATUS) { return NORNS_ESNAFU; } @@ -130,24 +149,7 @@ send_control_status_request(nornsctl_stat_t* stats) { } norns_error_t -send_ping_request() { - - int res; - norns_response_t resp; - - if((res = send_request(NORNS_PING, &resp)) != NORNS_SUCCESS) { - return res; - } - - if(resp.r_type != NORNS_PING) { - return NORNS_ESNAFU; - } - - return resp.r_error_code; -} - -norns_error_t -send_job_request(norns_rpc_type_t type, uint32_t jobid, nornsctl_job_t* job) { +send_job_request(norns_msgtype_t type, uint32_t jobid, nornsctl_job_t* job) { int res; norns_response_t resp; @@ -166,7 +168,7 @@ send_job_request(norns_rpc_type_t type, uint32_t jobid, nornsctl_job_t* job) { norns_error_t -send_process_request(norns_rpc_type_t type, uint32_t jobid, +send_process_request(norns_msgtype_t type, uint32_t jobid, uid_t uid, gid_t gid, pid_t pid) { int res; @@ -185,7 +187,7 @@ send_process_request(norns_rpc_type_t type, uint32_t jobid, } norns_error_t -send_namespace_request(norns_rpc_type_t type, const char* nsid, +send_namespace_request(norns_msgtype_t type, const char* nsid, nornsctl_backend_t* ns) { int res; @@ -204,12 +206,12 @@ send_namespace_request(norns_rpc_type_t type, const char* nsid, } static int -send_request(norns_rpc_type_t type, norns_response_t* resp, ...) { +send_request(norns_msgtype_t type, norns_response_t* resp, ...) { int res; int conn = -1; - msgbuffer_t req_buf = MSGBUFFER_INIT(); - msgbuffer_t resp_buf = MSGBUFFER_INIT(); + norns_msgbuffer_t req_buf = MSGBUFFER_INIT(); + norns_msgbuffer_t resp_buf = MSGBUFFER_INIT(); libcontext_t* ctx = get_context(); @@ -245,7 +247,19 @@ send_request(norns_rpc_type_t type, norns_response_t* resp, ...) { break; } - case NORNSCTL_STATUS: + case NORNSCTL_COMMAND: + { + const nornsctl_command_t cmd = va_arg(ap, nornsctl_command_t); + const void* args = va_arg(ap, const void*); + + if((res = pack_to_buffer(type, &req_buf, cmd, args)) + != NORNS_SUCCESS) { + return res; + } + break; + } + + case NORNSCTL_GLOBAL_STATUS: case NORNS_PING: { if((res = pack_to_buffer(type, &req_buf)) != NORNS_SUCCESS) { @@ -384,7 +398,7 @@ connect_to_daemon(const char* socket_path) { } static int -send_message(int conn, const msgbuffer_t* buffer) { +send_message(int conn, const norns_msgbuffer_t* buffer) { if(buffer == NULL || buffer->b_data == NULL || buffer->b_size == 0) { return -1; @@ -412,7 +426,7 @@ send_message(int conn, const msgbuffer_t* buffer) { } static int -recv_message(int conn, msgbuffer_t* buffer) { +recv_message(int conn, norns_msgbuffer_t* buffer) { // first of all read the message prefix and decode it // so that we know how much data to receive diff --git a/lib/communication.h b/lib/communication.h index 7e4064904389e253d1525f2b79ab9c8dd590b240..02be1823f3b95ed2c57de0badd032b8d6cef911c 100644 --- a/lib/communication.h +++ b/lib/communication.h @@ -33,15 +33,15 @@ #pragma GCC visibility push(hidden) norns_error_t send_submit_request(norns_iotask_t* task); +norns_error_t send_control_command_request(nornsctl_command_t cmd, void* args); norns_error_t send_status_request(norns_iotask_t* task, norns_stat_t* stats); -norns_error_t send_job_request(norns_rpc_type_t type, uint32_t jobid, +norns_error_t send_job_request(norns_msgtype_t type, uint32_t jobid, nornsctl_job_t* job); -norns_error_t send_process_request(norns_rpc_type_t type, uint32_t jobid, +norns_error_t send_process_request(norns_msgtype_t type, uint32_t jobid, uid_t uid, gid_t gid, pid_t pid); -norns_error_t send_namespace_request(norns_rpc_type_t type, const char* nsid, +norns_error_t send_namespace_request(norns_msgtype_t type, const char* nsid, nornsctl_backend_t* backend); norns_error_t send_control_status_request(nornsctl_stat_t* stats); -norns_error_t send_ping_request(); #pragma GCC visibility pop diff --git a/lib/errors.c b/lib/errors.c index b28c2069d16bff354c0a4040bf4a35ff4811dc26..91b407ef66aa7d6f26113297780733a8efe935af 100644 --- a/lib/errors.c +++ b/lib/errors.c @@ -30,19 +30,17 @@ #define ERR_REMAP(n) ((n) < 0 ? -(n) : (n)) const char* const norns_errlist[NORNS_ERRMAX + 1] = { - /* misc errors */ [ERR_REMAP(NORNS_SUCCESS)] = "Success", [ERR_REMAP(NORNS_ESNAFU)] = "Internal error", [ERR_REMAP(NORNS_EBADREQUEST)] = "Bad request", [ERR_REMAP(NORNS_EBADARGS)] = "Bad arguments", [ERR_REMAP(NORNS_ENOMEM)] = "Cannot allocate memory", - [ERR_REMAP(NORNS_ENOTSUPPORTED)] = "Not supported", - [ERR_REMAP(NORNS_ESYSTEMERROR)] = "Operating system error", /* communication errors */ [ERR_REMAP(NORNS_ECONNFAILED)] = "Cannot connect to daemon", [ERR_REMAP(NORNS_ERPCSENDFAILED)] = "Cannot send requests to daemon", [ERR_REMAP(NORNS_ERPCRECVFAILED)] = "Cannot receive responses from daemon", + [ERR_REMAP(NORNS_EACCEPTPAUSED)] = "Daemon does not accept new tasks", /* job errors */ [ERR_REMAP(NORNS_EJOBEXISTS)] = "Job already exists", @@ -61,6 +59,10 @@ const char* const norns_errlist[NORNS_ERRMAX + 1] = { [ERR_REMAP(NORNS_ENOSUCHTASK)] = "Task does not exist", [ERR_REMAP(NORNS_ETOOMANYTASKS)] = "Too many pending tasks", + /* misc errors */ + [ERR_REMAP(NORNS_ENOTSUPPORTED)] = "Not supported", + [ERR_REMAP(NORNS_ESYSTEMERROR)] = "Operating system error", + /* fallback */ [ERR_REMAP(NORNS_ERRMAX)] = "Unknown error", diff --git a/lib/libnornsctl.c b/lib/libnornsctl.c index 192e634a205a59f7d8a138b51159de267ed36a29..cccbbc95c3dbbe994389bb5674f61ec1b6b356d4 100644 --- a/lib/libnornsctl.c +++ b/lib/libnornsctl.c @@ -148,19 +148,17 @@ libnornsctl_reload_config_file(void) { #endif /* Control API */ -norns_error_t -nornsctl_ping(void) { - return send_ping_request(); -} - norns_error_t nornsctl_send_command(nornsctl_command_t command, void* args) { - // TODO - (void) command; - (void) args; - return NORNS_SUCCESS; + // we don't have any commands right now that support arguments + if(args != NULL) { + ERR("invalid arguments"); + return NORNS_EBADARGS; + } + + return send_control_command_request(command, args); } norns_error_t diff --git a/lib/requests.c b/lib/requests.c index d470e854fdc90532089354ad8890ca4f46fdf0f2..b0b0d55a90f9ae5b3f6f09024f6d6f755bec6015 100644 --- a/lib/requests.c +++ b/lib/requests.c @@ -77,13 +77,18 @@ build_path_msg(const norns_posix_path_t* path); static void free_path_msg(Norns__Rpc__Request__Task__PosixPath* msg); +static Norns__Rpc__Request__Command* +build_command_msg(const nornsctl_command_t cmd, const void* args); +static void +free_command_msg(Norns__Rpc__Request__Command* msg) __attribute__((unused)); + static int -encode_request_type(norns_rpc_type_t type); -static norns_rpc_type_t +encode_request_type(norns_msgtype_t type); +static norns_msgtype_t decode_response_type(int type); static int -encode_request_type(norns_rpc_type_t type) { +encode_request_type(norns_msgtype_t type) { switch(type) { case NORNS_IOTASK_SUBMIT: return NORNS__RPC__REQUEST__TYPE__IOTASK_SUBMIT; @@ -107,14 +112,16 @@ encode_request_type(norns_rpc_type_t type) { return NORNS__RPC__REQUEST__TYPE__NAMESPACE_UPDATE; case NORNS_NAMESPACE_UNREGISTER: return NORNS__RPC__REQUEST__TYPE__NAMESPACE_UNREGISTER; - case NORNSCTL_STATUS: - return NORNS__RPC__REQUEST__TYPE__CTL_STATUS; + case NORNSCTL_GLOBAL_STATUS: + return NORNS__RPC__REQUEST__TYPE__GLOBAL_STATUS; + case NORNSCTL_COMMAND: + return NORNS__RPC__REQUEST__TYPE__CTL_COMMAND; default: return -1; } } -static norns_rpc_type_t +static norns_msgtype_t decode_response_type(int norns_rpc_type) { switch(norns_rpc_type) { case NORNS__RPC__RESPONSE__TYPE__IOTASK_SUBMIT: @@ -139,8 +146,10 @@ decode_response_type(int norns_rpc_type) { return NORNS_NAMESPACE_UPDATE; case NORNS__RPC__RESPONSE__TYPE__NAMESPACE_UNREGISTER: return NORNS_NAMESPACE_UNREGISTER; - case NORNS__RPC__RESPONSE__TYPE__CTL_STATUS: - return NORNSCTL_STATUS; + case NORNS__RPC__RESPONSE__TYPE__GLOBAL_STATUS: + return NORNSCTL_GLOBAL_STATUS; + case NORNS__RPC__REQUEST__TYPE__CTL_COMMAND: + return NORNSCTL_COMMAND; case NORNS__RPC__RESPONSE__TYPE__BAD_REQUEST: // intentionally fall through default: @@ -149,7 +158,7 @@ decode_response_type(int norns_rpc_type) { } Norns__Rpc__Request* -build_request_msg(norns_rpc_type_t type, va_list ap) { +build_request_msg(norns_msgtype_t type, va_list ap) { Norns__Rpc__Request* req_msg = NULL; @@ -165,6 +174,19 @@ build_request_msg(norns_rpc_type_t type, va_list ap) { } switch(type) { + + case NORNSCTL_COMMAND: + { + const nornsctl_command_t cmd = va_arg(ap, nornsctl_command_t); + const void* args = va_arg(ap, void*); + + if((req_msg->command = build_command_msg(cmd, args)) == NULL) { + goto cleanup_on_error; + } + + break; + } + case NORNS_IOTASK_SUBMIT: case NORNS_IOTASK_STATUS: { @@ -177,7 +199,7 @@ build_request_msg(norns_rpc_type_t type, va_list ap) { break; } - case NORNSCTL_STATUS: + case NORNSCTL_GLOBAL_STATUS: case NORNS_PING: { break; @@ -704,8 +726,31 @@ free_task_msg(Norns__Rpc__Request__Task* msg) { xfree(msg); } +Norns__Rpc__Request__Command* +build_command_msg(const nornsctl_command_t cmd, const void* args) { + + (void) args; + + Norns__Rpc__Request__Command* msg = xmalloc(sizeof(*msg)); + + if(msg == NULL) { + return NULL; + } + + norns__rpc__request__command__init(msg); + msg->id = cmd; + + return msg; +} + +void +free_command_msg(Norns__Rpc__Request__Command* msg) { + // TODO + (void) msg; +} + int -pack_to_buffer(norns_rpc_type_t type, msgbuffer_t* buf, ...) { +pack_to_buffer(norns_msgtype_t type, norns_msgbuffer_t* buf, ...) { Norns__Rpc__Request* req_msg = NULL; void* req_buf = NULL; @@ -748,7 +793,7 @@ cleanup_on_error: } int -unpack_from_buffer(msgbuffer_t* buf, norns_response_t* response) { +unpack_from_buffer(norns_msgbuffer_t* buf, norns_response_t* response) { Norns__Rpc__Response* rpc_resp = NULL; void* resp_buf = buf->b_data; @@ -780,7 +825,7 @@ unpack_from_buffer(msgbuffer_t* buf, norns_response_t* response) { response->r_errno = rpc_resp->stats->sys_errnum; break; - case NORNSCTL_STATUS: + case NORNSCTL_GLOBAL_STATUS: if(rpc_resp->gstats == NULL) { return NORNS_ERPCRECVFAILED; } diff --git a/lib/requests.h b/lib/requests.h index b96bc87e4debe2e5fd475ec4670673fecebfdeff..b6d228e070b4171c46b416f794d20f1ede098722 100644 --- a/lib/requests.h +++ b/lib/requests.h @@ -38,7 +38,10 @@ typedef enum { NORNS_IOTASK_SUBMIT, NORNS_IOTASK_STATUS, - NORNSCTL_STATUS, + NORNSCTL_GLOBAL_STATUS, + + /* control commands */ + NORNSCTL_COMMAND, NORNS_PING, @@ -55,12 +58,12 @@ typedef enum { NORNS_NAMESPACE_UNREGISTER, /* other */ NORNS_BAD_RPC -} norns_rpc_type_t; +} norns_msgtype_t; typedef struct { void* b_data; size_t b_size; -} msgbuffer_t; +} norns_msgbuffer_t; #define MSGBUFFER_INIT() \ { .b_data = 0, \ @@ -68,7 +71,7 @@ typedef struct { } typedef struct { - norns_rpc_type_t r_type; + norns_msgtype_t r_type; int r_error_code; union { size_t r_taskid; @@ -85,8 +88,8 @@ typedef struct { }; } norns_response_t; -int pack_to_buffer(norns_rpc_type_t type, msgbuffer_t* buf, ...); -int unpack_from_buffer(msgbuffer_t* buf, norns_response_t* response); +int pack_to_buffer(norns_msgtype_t type, norns_msgbuffer_t* buf, ...); +int unpack_from_buffer(norns_msgbuffer_t* buf, norns_response_t* response); #pragma GCC visibility pop diff --git a/rpc/messages.proto b/rpc/messages.proto index 6b95fc630fede0fee0d23623e1d2cab4ec44b4dc..f0b93dafd1560d023deb1895bce2a78a40263e56 100644 --- a/rpc/messages.proto +++ b/rpc/messages.proto @@ -8,6 +8,7 @@ message Request { IOTASK_SUBMIT = 1; IOTASK_STATUS = 2; PING = 3; + JOB_REGISTER = 4; JOB_UPDATE = 5; JOB_UNREGISTER = 6; @@ -17,7 +18,8 @@ message Request { NAMESPACE_UPDATE = 10; NAMESPACE_UNREGISTER = 11; - CTL_STATUS = 12; + GLOBAL_STATUS = 1000; + CTL_COMMAND = 1001; } // I/O task descriptor @@ -80,12 +82,18 @@ message Request { required int32 quota = 2; } + // command descriptor + message Command { + required uint32 id = 1; + } + required Type type = 1; optional Task task = 2; optional uint32 jobid = 3; optional Job job = 4; optional Process process = 5; optional Namespace nspace = 6; + optional Command command = 7; } message Response { @@ -105,8 +113,10 @@ message Response { NAMESPACE_UPDATE = 10; NAMESPACE_UNREGISTER = 11; - CTL_STATUS = 12; - BAD_REQUEST = 13; + GLOBAL_STATUS = 1000; + CTL_COMMAND = 1001; + + BAD_REQUEST = 2000; } message TaskStats { diff --git a/src/api/request.cpp b/src/api/request.cpp index c617eb1d8178d48fe0f2bb8765b609b116418263..32062b7d6518ab6a2379bf5114241b438bb9331a 100644 --- a/src/api/request.cpp +++ b/src/api/request.cpp @@ -72,6 +72,22 @@ norns::backend_type decode_backend_type(::google::protobuf::uint32 type) { } } +norns::command_type decode_command(::google::protobuf::uint32 type) { + + using norns::command_type; + + switch(type) { + case NORNSCTL_COMMAND_PING: + return command_type::ping; + case NORNSCTL_COMMAND_PAUSE_ACCEPT: + return command_type::pause_accept; + case NORNSCTL_COMMAND_RESUME_ACCEPT: + return command_type::resume_accept; + default: + return command_type::unknown; + } +} + bool is_valid(const norns::rpc::Request_Task_Resource& res) { if(!(res.type() & (NORNS_PROCESS_MEMORY | NORNS_POSIX_PATH))) { @@ -213,8 +229,16 @@ request_ptr request::create_from_buffer(const std::vector& buffer, int case norns::rpc::Request::PING: return std::make_unique(); - case norns::rpc::Request::CTL_STATUS: - return std::make_unique(); + case norns::rpc::Request::GLOBAL_STATUS: + return std::make_unique(); + + case norns::rpc::Request::CTL_COMMAND: + + if(rpc_req.has_command()) { + command_type cmd = ::decode_command(rpc_req.command().id()); + return std::make_unique(cmd); + } + break; case norns::rpc::Request::JOB_REGISTER: case norns::rpc::Request::JOB_UPDATE: @@ -353,10 +377,24 @@ std::string iotask_status_request::to_string() const { } template<> -std::string ctl_status_request::to_string() const { +std::string global_status_request::to_string() const { return "GLOBAL_STATUS"; } +template<> +std::string command_request::to_string() const { + switch(this->get<0>()) { + case command_type::ping: + return "PING"; + case command_type::pause_accept: + return "PAUSE_ACCEPT"; + case command_type::resume_accept: + return "RESUME_ACCEPT"; + default: + return "UNKNOWN"; + } +} + template<> std::string ping_request::to_string() const { return "PING"; diff --git a/src/api/request.hpp b/src/api/request.hpp index e90e9dae18ea66e1c191c88af3c8f1b8f93301b2..0d24f1d25e0891a9730f547336942e0a46050b21 100644 --- a/src/api/request.hpp +++ b/src/api/request.hpp @@ -77,7 +77,8 @@ namespace api { enum class request_type { iotask_create, iotask_status, - ctl_status, + global_status, + command, ping, job_register, job_update, @@ -255,8 +256,13 @@ using backend_unregister_request = detail::request_impl< std::string >; -using ctl_status_request = detail::request_impl< - request_type::ctl_status +using global_status_request = detail::request_impl< + request_type::global_status +>; + +using command_request = detail::request_impl< + request_type::command, + command_type >; } // namespace api diff --git a/src/api/response.cpp b/src/api/response.cpp index 353cb6c13b3986a5bd98a0ad221dbcbabdd91787..fbcfcbbe35561f0af2c1fe1f52b19a7ed2711ba7 100644 --- a/src/api/response.cpp +++ b/src/api/response.cpp @@ -59,8 +59,10 @@ norns::rpc::Response_Type encode(norns::api::response_type type) { return norns::rpc::Response::NAMESPACE_UPDATE; case response_type::backend_unregister: return norns::rpc::Response::NAMESPACE_UNREGISTER; - case response_type::ctl_status: - return norns::rpc::Response::CTL_STATUS; + case response_type::global_status: + return norns::rpc::Response::GLOBAL_STATUS; + case response_type::command: + return norns::rpc::Response::CTL_COMMAND; case response_type::bad_request: return norns::rpc::Response::BAD_REQUEST; default: @@ -157,10 +159,10 @@ std::string iotask_status_response::to_string() const { } ///////////////////////////////////////////////////////////////////////////////// -// specializations for ctl_status_response +// specializations for global_status_response ///////////////////////////////////////////////////////////////////////////////// template<> -void ctl_status_response::pack_extra_info(norns::rpc::Response& r) const { +void global_status_response::pack_extra_info(norns::rpc::Response& r) const { const auto& gstats = this->get<0>(); auto gstats_msg = new norns::rpc::Response_GlobalStats(); @@ -175,7 +177,7 @@ void ctl_status_response::pack_extra_info(norns::rpc::Response& r) const { } template<> -std::string ctl_status_response::to_string() const { +std::string global_status_response::to_string() const { const auto& gstats = this->get<0>(); return utils::to_string(gstats) + " " + utils::to_string(this->error_code()); } diff --git a/src/api/response.hpp b/src/api/response.hpp index 82ac789759c11e81625afaaa1151c8f12d7072f1..27ea49b40771a8f4da6fbd90b585f0efd8e600dd 100644 --- a/src/api/response.hpp +++ b/src/api/response.hpp @@ -54,7 +54,8 @@ namespace api { enum class response_type { iotask_create, iotask_status, - ctl_status, + global_status, + command, ping, job_register, job_update, @@ -185,11 +186,15 @@ using backend_unregister_response = detail::response_impl< response_type::backend_unregister >; -using ctl_status_response = detail::response_impl< - response_type::ctl_status, +using global_status_response = detail::response_impl< + response_type::global_status, io::global_stats >; +using command_response = detail::response_impl< + response_type::command +>; + using bad_request_response = detail::response_impl< response_type::bad_request >; diff --git a/src/common/types.cpp b/src/common/types.cpp index 0b001f4c40f84fbc4e4c20580766898531750498..e2b73d9b0195bd2d78ccd1423e93accd361cc29b 100644 --- a/src/common/types.cpp +++ b/src/common/types.cpp @@ -99,6 +99,8 @@ std::string to_string(urd_error ecode) { return "NORNS_ENOSUCHTASK"; case urd_error::too_many_tasks: return "NORNS_ETOOMANYTASKS"; + case urd_error::accept_paused: + return "NORNS_EACCEPTPAUSED"; default: return "UNKNOWN_ERROR"; } diff --git a/src/common/types.hpp b/src/common/types.hpp index e20156dfbde590d7eea73c180a1a4170773d1ed8..90dce2adc5a9a959a391e6015f693bfd95414a38 100644 --- a/src/common/types.hpp +++ b/src/common/types.hpp @@ -33,6 +33,7 @@ #include #include "norns.h" +#include "nornsctl.h" #ifndef __URD_TYPES_HPP__ #define __URD_TYPES_HPP__ @@ -60,6 +61,13 @@ enum class backend_type { unknown }; +enum class command_type { + ping, + pause_accept, + resume_accept, + unknown +}; + /*! Error codes */ enum class urd_error : norns_error_t { success = NORNS_SUCCESS, @@ -76,6 +84,7 @@ enum class urd_error : norns_error_t { connection_failed = NORNS_ECONNFAILED, rpc_send_failed = NORNS_ERPCSENDFAILED, rpc_recv_failed = NORNS_ERPCRECVFAILED, + accept_paused = NORNS_EACCEPTPAUSED, /* errors about jobs */ job_exists = NORNS_EJOBEXISTS, diff --git a/src/urd.cpp b/src/urd.cpp index 6e1fada59726d1884304df7c9b7ec00580f80ce8..c8b51299fcd0fc7bf0acad98320f4ea746bafbf4 100644 --- a/src/urd.cpp +++ b/src/urd.cpp @@ -59,6 +59,7 @@ namespace norns { urd::urd() : + m_is_paused(false), m_settings(std::make_shared()) {} urd::~urd() {} @@ -212,9 +213,15 @@ response_ptr urd::iotask_create_handler(const request_ptr base_request) { response_ptr resp; iotask_id tid = 0; + boost::optional auth; urd_error rv = urd_error::success; - const auto auth = request->credentials(); + if(m_is_paused) { + rv = urd_error::accept_paused; + goto log_and_return; + } + + auth = request->credentials(); if(!auth) { LOGGER_CRITICAL("Request without credentials"); @@ -562,7 +569,7 @@ response_ptr urd::namespace_remove_handler(const request_ptr base_request) { response_ptr urd::global_status_handler(const request_ptr /*base_request*/) { - auto resp = std::make_unique(); + auto resp = std::make_unique(); resp->set_error_code(urd_error::success); resp->set<0>(m_task_mgr->global_stats()); @@ -571,6 +578,39 @@ response_ptr urd::global_status_handler(const request_ptr /*base_request*/) { return std::move(resp); } +response_ptr +urd::command_handler(const request_ptr base_request) { + + // downcast the generic request to the concrete implementation + auto request = + utils::static_unique_ptr_cast( + std::move(base_request)); + auto resp = std::make_unique(); + resp->set_error_code(urd_error::success); + + switch(request->get<0>()) { + case command_type::ping: + break; // nothing special to do here + case command_type::pause_accept: + if(!m_is_paused) { + m_is_paused = true; + } + break; + case command_type::resume_accept: + if(m_is_paused) { + m_is_paused = false; + } + break; + case command_type::unknown: + resp->set_error_code(urd_error::bad_args); + break; + } + + LOGGER_INFO("COMMAND({}) = {}", request->to_string(), resp->to_string()); + return std::move(resp); +} + + response_ptr urd::unknown_request_handler(const request_ptr /*base_request*/) { response_ptr resp = std::make_unique(); @@ -759,9 +799,13 @@ void urd::init_event_handlers() { std::bind(&urd::namespace_remove_handler, this, std::placeholders::_1)); m_api_listener->register_callback( - api::request_type::ctl_status, + api::request_type::global_status, std::bind(&urd::global_status_handler, this, std::placeholders::_1)); + m_api_listener->register_callback( + api::request_type::command, + std::bind(&urd::command_handler, this, std::placeholders::_1)); + m_api_listener->register_callback( api::request_type::bad_request, std::bind(&urd::unknown_request_handler, this, std::placeholders::_1)); diff --git a/src/urd.hpp b/src/urd.hpp index 953d8a33ad6db8396adef3a30ea3644bafb3ac44..98805143a108de875a9f7c0ac83118e1eff4982b 100644 --- a/src/urd.hpp +++ b/src/urd.hpp @@ -113,6 +113,7 @@ private: response_ptr namespace_update_handler(const request_ptr req); response_ptr namespace_remove_handler(const request_ptr req); response_ptr global_status_handler(const request_ptr req); + response_ptr command_handler(const request_ptr req); response_ptr unknown_request_handler(const request_ptr req); // TODO: add helpers for remove and update @@ -121,6 +122,8 @@ private: const bfs::path& mount, uint32_t quota); private: + std::atomic m_is_paused; + std::shared_ptr m_settings; std::unique_ptr m_transferor_registry; diff --git a/tests/Makefile.am b/tests/Makefile.am index fbc3f0a415194eb427deaecc58b4a1f915fae2fb..cadfce6c02e26859e8f63949151291d2f53e5cb1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -53,13 +53,13 @@ api_SOURCES = \ api-job-register.cpp \ api-job-update.cpp \ api-job-unregister.cpp \ - api-ping.cpp \ api-process-add.cpp \ api-process-remove.cpp \ api-resource-init.cpp \ api-task-init.cpp \ api-task-submit.cpp \ api-task-status.cpp \ + api-send-command.cpp \ compare-files.cpp \ compare-files.hpp \ config-template.cpp \ diff --git a/tests/api-ping.cpp b/tests/api-send-command.cpp similarity index 52% rename from tests/api-ping.cpp rename to tests/api-send-command.cpp index a01e59344b571e701fa05c5d51e945c280481b37..2dc013328654905729ed2ed100fb87717e0cb55f 100644 --- a/tests/api-ping.cpp +++ b/tests/api-send-command.cpp @@ -25,40 +25,68 @@ * . * *************************************************************************/ - #include "norns.h" #include "nornsctl.h" -#include "catch.hpp" -#include "fake-daemon.hpp" #include "test-env.hpp" +#include "catch.hpp" -SCENARIO("ping request", "[api::nornsctl_ping]") { +SCENARIO("send control commands to urd", "[api::nornsctl_send_command]") { GIVEN("a running urd instance") { - test_env env; + test_env env( + fake_daemon_cfg { + true /* dry_run? */ + } + ); + + const char* nsid0 = "tmp0"; + bfs::path src_mnt; + std::tie(std::ignore, src_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); - WHEN("pinging urd") { + WHEN("a NORNSCTL_COMMAND_PAUSE_ACCEPT command is sent") { - int rv = nornsctl_ping(); + norns_error_t rv = nornsctl_send_command(NORNSCTL_COMMAND_PAUSE_ACCEPT, NULL); - THEN("NORNS_SUCCESS is returned") { + THEN("nornsctl_send_command() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); + + AND_THEN("norns_submit() returns NORNS_EACCEPTPAUSED") { + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION((void*)0xdeadbeef, 42), + NORNS_LOCAL_PATH(nsid0, "foobar")); + + rv = norns_submit(&task); + REQUIRE(rv == NORNS_EACCEPTPAUSED); + + AND_THEN("nornsctl_send_command() returns NORNS_SUCCESS and norns_submit() succeeds") { + norns_error_t rv = nornsctl_send_command(NORNSCTL_COMMAND_RESUME_ACCEPT, NULL); + REQUIRE(rv == NORNS_SUCCESS); + + rv = norns_submit(&task); + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id == 1); + } + } } } - env.notify_success(); - } + WHEN("a NORNSCTL_COMMAND_RESUME_ACCEPT command is sent") { + + norns_error_t rv = nornsctl_send_command(NORNSCTL_COMMAND_RESUME_ACCEPT, NULL); + + THEN("nornsctl_send_command() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + } + } -#ifndef USE_REAL_DAEMON - GIVEN("a non-running urd instance") { - WHEN("pinging urd") { + WHEN("a NORNSCTL_COMMAND_PING command is sent") { - int rv = nornsctl_ping(); + norns_error_t rv = nornsctl_send_command(NORNSCTL_COMMAND_PING, NULL); - THEN("NORNS_ECONNFAILED is returned") { - REQUIRE(rv == NORNS_ECONNFAILED); + THEN("nornsctl_send_command() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); } } } -#endif } diff --git a/tests/fake-daemon.cpp b/tests/fake-daemon.cpp index 0b094d67ff4acdb51122496885acba27bf68750e..87802f0eeab839a0e836e577bd4c9b000748dd26 100644 --- a/tests/fake-daemon.cpp +++ b/tests/fake-daemon.cpp @@ -108,7 +108,7 @@ void fake_daemon::run() { do { std::this_thread::sleep_for(std::chrono::milliseconds(1)); - rv = nornsctl_ping(); + rv = nornsctl_send_command(NORNSCTL_COMMAND_PING, NULL); } while(rv != NORNS_SUCCESS && --retries != 0); if(retries == 0) {