diff --git a/ldms/python/ldmsd/ldmsd_communicator.py b/ldms/python/ldmsd/ldmsd_communicator.py index 0512b3c66..3e7fcaaf8 100644 --- a/ldms/python/ldmsd/ldmsd_communicator.py +++ b/ldms/python/ldmsd/ldmsd_communicator.py @@ -144,6 +144,7 @@ ##### Misc. ##### 'greeting': {'req_attr': [], 'opt_attr': ['name', 'offset', 'level', 'test', 'path']}, 'example': {'req_attr': [], 'opt_attr': []}, + 'dump_cfg': {'req_attr':[], 'opt_attr': ['path']}, 'set_info': {'req_attr': ['instance'], 'opt_attr': []}, 'xprt_stats': {'req_attr':[], 'opt_attr': ['reset']}, 'thread_stats': {'req_attr':[], 'opt_attr': ['reset']}, @@ -456,6 +457,7 @@ class LDMSD_Request(object): EXAMPLE = 1 GREETING = 2 CFG_CNTR = 3 + DUMP_CFG = 4 PRDCR_ADD = 0x100 PRDCR_DEL = 0x100 + 1 @@ -560,6 +562,7 @@ class LDMSD_Request(object): 'example': {'id': EXAMPLE}, 'greeting': {'id': GREETING}, 'cfg_cntr': {'id': CFG_CNTR}, + 'dump_cfg': {'id': DUMP_CFG}, 'prdcr_add': {'id': PRDCR_ADD}, 'prdcr_del': {'id': PRDCR_DEL}, @@ -949,7 +952,9 @@ def reconnect(self, timeout=0): def connect(self, timeout=0): try: - self.ldms.connect(self.host, self.port, timeout=timeout) + if not self.ldms: + self.ldms = ldms.Xprt(name=self.xprt, auth=self.auth, auth_opts=self.auth_opt) + rc = self.ldms.connect(self.host, self.port, timeout=timeout) except Exception as e: if self.auth is not None: if self.auth_opt is not None: @@ -962,6 +967,8 @@ def connect(self, timeout=0): print(f'{e}: connecting to {self.host} on port {self.port} using {self.xprt}{auth_s}') self.state = self.CLOSED return errno.ENOTCONN + if rc: + return 1 self.type = 'inband' self.state = self.CONNECTED rc, self.CFG_CNTR = self.getCfgCntr() @@ -1032,6 +1039,29 @@ def greeting(self, name=None, offset=None, level=None, test=None, path=None): except Exception as e: return errno.ENOTCONN, str(e) + def dump_cfg(self, path=None): + """ + Dumps the currently running configuration of a running ldmsd + Parameters: + path - The path to write the configuration to + defaults to the current users home directory + Returns: + - status is an errno from the errno module + - data is an error message if status is !=0 or None + """ + if path is None: + path = os.path.expanduser('~') + filename = f'{path}/{self.host}-{self.port}.conf' + req = LDMSD_Request(command_id=LDMSD_Request.DUMP_CFG, + attrs = [ LDMSD_Req_Attr(attr_id=LDMSD_Req_Attr.STRING, value=filename) ] + ) + try: + req.send(self) + resp = req.receive(self) + return resp['errcode'], resp['msg'] + except Exception as e: + return errno.ENOTCONN, str(e) + def auth_add(self, name, plugin=None, auth_opt=None): """ Add an authentication domain diff --git a/ldms/python/ldmsd/ldmsd_controller b/ldms/python/ldmsd/ldmsd_controller index 68d3a8808..d3e3d7ffe 100755 --- a/ldms/python/ldmsd/ldmsd_controller +++ b/ldms/python/ldmsd/ldmsd_controller @@ -255,6 +255,19 @@ class LdmsdCmdParser(cmd.Cmd): for cmd in fin: self.onecmd(cmd) + def do_dump_cfg(self, arg): + """ + Dump the current running configuration to a file specified in the path + + Parameters: + path - path to file + """ + arg = self.handle_args('dump_cfg', arg) + if arg: + rc, msg = self.comm.dump_cfg(arg['path']) + if rc: + print(f'Error {rc} printing current configuration: {msg}') + def do_source(self, arg): """ Parse commands from the specified file as if they were entered diff --git a/ldms/src/ldmsd/ldmsd.c b/ldms/src/ldmsd/ldmsd.c index c9fae25c6..e4f2fe0c7 100644 --- a/ldms/src/ldmsd/ldmsd.c +++ b/ldms/src/ldmsd/ldmsd.c @@ -1456,6 +1456,11 @@ ldmsd_listen_t ldmsd_listen_new(char *xprt, char *port, char *host, char *auth) errno = ENOMEM; goto err; } + listen->auth_dom_name = strdup(auth_dom->obj.name); + if (!listen->auth_dom_name) { + errno = ENOMEM; + goto err; + } if (auth_dom->attrs) { listen->auth_attrs = av_copy(auth_dom->attrs); if (!listen->auth_attrs) { diff --git a/ldms/src/ldmsd/ldmsd.h b/ldms/src/ldmsd/ldmsd.h index c19f9c7ce..cfc0749f7 100644 --- a/ldms/src/ldmsd/ldmsd.h +++ b/ldms/src/ldmsd/ldmsd.h @@ -209,6 +209,7 @@ typedef struct ldmsd_prdcr { char *xprt_name; /* Transport name */ ldms_t xprt; long conn_intrvl_us; /* connect interval */ + char *conn_auth_name; /* auth domain name */ char *conn_auth; /* auth method for the connection */ struct attr_value_list *conn_auth_args; /* auth options of the connection auth */ @@ -743,6 +744,7 @@ int process_config_file(const char *path, int *lineno, int trust); struct attr_value_list; struct ldmsd_plugin { char name[LDMSD_MAX_PLUGIN_NAME_LEN]; + struct attr_value_list *av_list; enum ldmsd_plugin_type { LDMSD_PLUGIN_OTHER = 0, LDMSD_PLUGIN_SAMPLER, @@ -1370,6 +1372,7 @@ typedef struct ldmsd_listen { unsigned short port_no; char *host; char *auth_name; + char *auth_dom_name; struct attr_value_list *auth_attrs; ldms_t x; } *ldmsd_listen_t; diff --git a/ldms/src/ldmsd/ldmsd_config.c b/ldms/src/ldmsd/ldmsd_config.c index 7f22a29cb..de4ad4e85 100644 --- a/ldms/src/ldmsd/ldmsd_config.c +++ b/ldms/src/ldmsd/ldmsd_config.c @@ -206,6 +206,7 @@ void destroy_plugin(struct ldmsd_plugin_cfg *p) { free(p->libpath); free(p->name); + av_free(p->plugin->av_list); LIST_REMOVE(p, entry); dlclose(p->handle); free(p); @@ -314,6 +315,17 @@ int ldmsd_config_plugin(char *plugin_name, pthread_mutex_lock(&pi->lock); rc = pi->plugin->config(pi->plugin, _kw_list, _av_list); + pi->plugin->av_list = av_copy(_av_list); + /* + int i; + pi->plugin->av_list = av_new(_av_list->count); + pi->plugin->av_list->count = _av_list->count; + for (i = 0; i < _av_list->count; i++) { + struct attr_value *v = &_av_list->list[i]; + pi->plugin->av_list->list[i].name = strdup(v->name); + pi->plugin->av_list->list[i].value = strdup(v->value); + } + */ pthread_mutex_unlock(&pi->lock); return rc; } diff --git a/ldms/src/ldmsd/ldmsd_prdcr.c b/ldms/src/ldmsd/ldmsd_prdcr.c index b4a6320a6..7f2424f82 100644 --- a/ldms/src/ldmsd/ldmsd_prdcr.c +++ b/ldms/src/ldmsd/ldmsd_prdcr.c @@ -836,6 +836,9 @@ ldmsd_prdcr_new_with_auth(const char *name, const char *xprt_name, errno = ENOENT; goto out; } + prdcr->conn_auth_name = strdup(auth_dom->obj.name); + if (!prdcr->conn_auth_name) + goto out; prdcr->conn_auth = strdup(auth_dom->plugin); if (!prdcr->conn_auth) goto out; diff --git a/ldms/src/ldmsd/ldmsd_request.c b/ldms/src/ldmsd/ldmsd_request.c index 1f5de470b..604948829 100644 --- a/ldms/src/ldmsd/ldmsd_request.c +++ b/ldms/src/ldmsd/ldmsd_request.c @@ -197,6 +197,7 @@ struct request_handler_entry { static int example_handler(ldmsd_req_ctxt_t req_ctxt); static int ldmsd_cfg_cntr_handler(ldmsd_req_ctxt_t req_ctxt); +static int dump_cfg_handler(ldmsd_req_ctxt_t req_ctxt); static int prdcr_add_handler(ldmsd_req_ctxt_t req_ctxt); static int prdcr_del_handler(ldmsd_req_ctxt_t req_ctxt); static int prdcr_start_handler(ldmsd_req_ctxt_t req_ctxt); @@ -311,6 +312,7 @@ static int cmd_line_arg_set_handler(ldmsd_req_ctxt_t reqc); static struct request_handler_entry request_handler[] = { [LDMSD_EXAMPLE_REQ] = { LDMSD_EXAMPLE_REQ, example_handler, XALL }, [LDMSD_CFG_CNTR_REQ] = { LDMSD_CFG_CNTR_REQ, ldmsd_cfg_cntr_handler, XUG }, + [LDMSD_DUMP_CFG_REQ] = { LDMSD_DUMP_CFG_REQ, dump_cfg_handler, XUG }, /* PRDCR */ [LDMSD_PRDCR_ADD_REQ] = { @@ -6144,6 +6146,185 @@ static int greeting_handler(ldmsd_req_ctxt_t reqc) return 0; } +static int dump_cfg_handler(ldmsd_req_ctxt_t reqc) +{ + FILE *fp; + char *filename = NULL; + extern struct plugin_list plugin_list; + struct ldmsd_plugin_cfg *p; + int rc; + int i; + reqc->errcode = 0; + filename = ldmsd_req_attr_str_value_get_by_id(reqc, LDMSD_ATTR_STRING); + fp = fopen(filename, "w+"); + + /* Auth */ + ldmsd_auth_t auth; + ldmsd_cfg_lock(LDMSD_CFGOBJ_AUTH); + for (auth = (ldmsd_auth_t)ldmsd_cfgobj_first(LDMSD_CFGOBJ_AUTH); auth; + auth = (ldmsd_auth_t)ldmsd_cfgobj_next(&auth->obj)) { + fprintf(fp, "auth_add name=%s plugin=%s", auth->obj.name, auth->plugin); + if (auth->attrs) { + for (i = 0; i < auth->attrs->count; i++) { + struct attr_value *v = &auth->attrs->list[i]; + fprintf(fp, " %s=%s", v->name, v->value); + } + } + fprintf(fp, "\n"); + } + ldmsd_cfg_unlock(LDMSD_CFGOBJ_AUTH); + /* Listeners */ + ldmsd_listen_t listen; + for (listen = (ldmsd_listen_t)ldmsd_cfgobj_first(LDMSD_CFGOBJ_LISTEN); listen; + listen = (ldmsd_listen_t)ldmsd_cfgobj_next(&listen->obj)) { + fprintf(fp, "listen xprt=%s port=%d", + listen->xprt, + listen->port_no); + if (listen->host) + fprintf(fp, " host=%s", listen->host); + if (listen->auth_name) { + if (listen->auth_dom_name) + fprintf(fp, " auth=%s", listen->auth_dom_name); + else + fprintf(fp, " auth=DEFAULT"); + } + fprintf(fp, "\n"); + } + /* Producers */ + ldmsd_prdcr_t prdcr = NULL; + + ldmsd_cfg_lock(LDMSD_CFGOBJ_PRDCR); + for (prdcr = ldmsd_prdcr_first(); prdcr; + prdcr = ldmsd_prdcr_next(prdcr)) { + ldmsd_prdcr_stream_t s; + + ldmsd_prdcr_lock(prdcr); + fprintf(fp, "prdcr_add name=%s host=%s port=%d xprt=%s type=%s interval=%ld auth=%s uid=%d gid=%d\n", + prdcr->obj.name, prdcr->host_name, + prdcr->port_no, prdcr->xprt_name, + ldmsd_prdcr_type2str(prdcr->type), + prdcr->conn_intrvl_us, + prdcr->conn_auth_name, + prdcr->obj.uid, prdcr->obj.gid); + if (prdcr->conn_state == LDMSD_PRDCR_STATE_CONNECTED) + fprintf(fp, "prdcr_start name=%s\n", prdcr->obj.name); + /* Streams */ + LIST_FOREACH(s, &prdcr->stream_list, entry) { + fprintf(fp, "prdcr_subscribe regex=%s stream=%s\n", prdcr->obj.name, s->name); + } + ldmsd_prdcr_unlock(prdcr); + } + ldmsd_cfg_unlock(LDMSD_CFGOBJ_PRDCR); + /* Plugins */ + LIST_FOREACH(p, &plugin_list, entry) { + fprintf(fp, "load name=%s\n", p->name); + fprintf(fp, "config name=%s ", p->name); + for (i = 0; i < p->plugin->av_list->count; i++) { + struct attr_value *v = &p->plugin->av_list->list[i]; + if (i > 0) + fprintf(fp, " "); + fprintf(fp, "%s=%s", v->name, v->value); + } + fprintf(fp, "\n"); + if (p->plugin->type == LDMSD_PLUGIN_SAMPLER) + fprintf(fp, "start name=%s interval=%ld offset=%ld\n", + p->plugin->name, + p->sample_interval_us, + p->sample_offset_us); + } + /* Updaters WIP - push modes */ + ldmsd_name_match_t match; + ldmsd_updtr_t updtr; + char *sel_str; + char *updtr_mode = NULL; + + ldmsd_cfg_lock(LDMSD_CFGOBJ_UPDTR); + for (updtr = ldmsd_updtr_first(); updtr; + updtr = ldmsd_updtr_next(updtr)) { + /* Initial updater configuration */ + fprintf(fp, "updtr_add name=%s", updtr->obj.name); + if (updtr->is_auto_task) + updtr_mode = "auto_interval=true"; + else if (updtr->push_flags & LDMSD_UPDTR_F_PUSH) + updtr_mode = "push=true"; + else if (updtr->push_flags & LDMSD_UPDTR_F_PUSH_CHANGE) + updtr_mode = "push=onchange"; + if (updtr_mode) + fprintf(fp, " %s", updtr_mode); + fprintf(fp, " interval=%ld\n", updtr->default_task.task.sched_us); + /* Add producers to updater */ + ldmsd_prdcr_ref_t ref; + for (ref = ldmsd_updtr_prdcr_first(updtr); ref; + ref = ldmsd_updtr_prdcr_next(ref)) { + ldmsd_prdcr_lock(ref->prdcr); + if (ref->prdcr->conn_state == LDMSD_PRDCR_STATE_CONNECTED) + fprintf(fp, "updtr_prdcr_add name=%s regex=%s\n", updtr->obj.name, ref->prdcr->obj.name); + ldmsd_prdcr_unlock(ref->prdcr); + } + /* Add match sets if there are any */ + if (!LIST_EMPTY(&updtr->match_list)) { + LIST_FOREACH(match, &updtr->match_list, entry) { + for (ref = ldmsd_updtr_prdcr_first(updtr); ref; + ref = ldmsd_updtr_prdcr_next(ref)) { + ldmsd_prdcr_lock(ref->prdcr); + ldmsd_prdcr_set_t prd_set; + for (prd_set = ldmsd_prdcr_set_first(ref->prdcr); prd_set; + prd_set = ldmsd_prdcr_set_next(prd_set)) { + if (match->selector == LDMSD_NAME_MATCH_INST_NAME) + rc = regexec(&match->regex, prd_set->inst_name, 0, NULL, 0); + else + rc = regexec(&match->regex, prd_set->schema_name, 0, NULL, 0); + if (rc) + continue; + if (match->selector == LDMSD_NAME_MATCH_INST_NAME) + sel_str = "inst"; + else + sel_str = "schema"; + fprintf(fp, "updtr_match_add name=%s match=%s regex=%s\n", + updtr->obj.name, sel_str, match->regex_str); + } + ldmsd_prdcr_unlock(ref->prdcr); + } + } + } + fprintf(fp, "updtr_start name=%s\n", updtr->obj.name); + } + ldmsd_cfg_unlock(LDMSD_CFGOBJ_UPDTR); + /* Storage Policies */ + ldmsd_strgp_t strgp; + + ldmsd_cfg_lock(LDMSD_CFGOBJ_STRGP); + for (strgp = ldmsd_strgp_first(); strgp; + strgp = ldmsd_strgp_next(strgp)) { + fprintf(fp, "strgp_add name=%s " + "plugin=%s " + "container=%s " + "schema=%s " + "flush=%ld " + "perm=%d ", + strgp->obj.name, + strgp->plugin_name, + strgp->container, + strgp->schema, + strgp->flush_interval.tv_sec, + strgp->obj.perm); + /* + if (strgp->decomp) + fprintf(fp, "decomposition=%s", strgp->decomp); + */ + fprintf(fp, "\n"); + if (strgp->state == LDMSD_STRGP_STATE_RUNNING) + fprintf(fp, "strgp_start name=%s\n", strgp->obj.name); + } + ldmsd_cfg_unlock(LDMSD_CFGOBJ_STRGP); + goto send_reply; +send_reply: + fclose(fp); + free(filename); + ldmsd_send_req_response(reqc, reqc->line_buf); + return rc; +} + static int unimplemented_handler(ldmsd_req_ctxt_t reqc) { size_t cnt; diff --git a/ldms/src/ldmsd/ldmsd_request.h b/ldms/src/ldmsd/ldmsd_request.h index 7d5724d46..8e55c45f6 100644 --- a/ldms/src/ldmsd/ldmsd_request.h +++ b/ldms/src/ldmsd/ldmsd_request.h @@ -74,6 +74,7 @@ enum ldmsd_request { LDMSD_EXAMPLE_REQ = 0x1, LDMSD_GREETING_REQ = 0x2, LDMSD_CFG_CNTR_REQ = 0x3, + LDMSD_DUMP_CFG_REQ = 0x4, LDMSD_PRDCR_ADD_REQ = 0x100, LDMSD_PRDCR_DEL_REQ, LDMSD_PRDCR_START_REQ,