diff --git a/configure.ac b/configure.ac index d6149feae8..31b955ea36 100644 --- a/configure.ac +++ b/configure.ac @@ -981,6 +981,8 @@ AC_CONFIG_FILES([ tests/regression/tools/wildcard/Makefile tests/regression/tools/crash/Makefile tests/regression/tools/metadata-regen/Makefile + tests/regression/tools/templates/Makefile + tests/regression/tools/templates/sessions/Makefile tests/regression/ust/Makefile tests/regression/ust/nprocesses/Makefile tests/regression/ust/high-throughput/Makefile diff --git a/doc/man/lttng-create.1.txt b/doc/man/lttng-create.1.txt index 14c9b0182f..414e0973d7 100644 --- a/doc/man/lttng-create.1.txt +++ b/doc/man/lttng-create.1.txt @@ -200,6 +200,9 @@ option:-o, option:--output='PATH':: option:--shm-path='PATH':: Create shared memory holding buffers at 'PATH'. +option:--default-output:: + Use the default output associated to the session's mode. + URL ~~~ @@ -224,6 +227,11 @@ In <> mode, 'URL' must start with `file://` followed by the destination path on the local file system. +Name +~~~~ +option:--default-name:: + Generate a session name of the form `auto-YYYYmmdd-HHMMSS`. + include::common-cmd-help-options.txt[] diff --git a/doc/man/lttng-save.1.txt b/doc/man/lttng-save.1.txt index 46fdb00b99..f5f9ac1a96 100644 --- a/doc/man/lttng-save.1.txt +++ b/doc/man/lttng-save.1.txt @@ -54,6 +54,11 @@ option:-f, option:--force:: option:-o, option:--output-path='PATH':: Set output directory path to 'PATH'. +option:--omit-name:: + Omit session name(s) from saved session configuration(s). + +option:--omit-output:: + Omit session output(s) from saved session configuration(s). include::common-cmd-help-options.txt[] diff --git a/include/lttng/save-internal.h b/include/lttng/save-internal.h index e2528be641..c5feb4af47 100644 --- a/include/lttng/save-internal.h +++ b/include/lttng/save-internal.h @@ -33,7 +33,11 @@ struct lttng_save_session_attr { /* Destination of the session configuration. See lttng(1) for URL format. */ char configuration_url[PATH_MAX]; /* Overwrite the session configuration file if it exists. */ - uint32_t overwrite; + uint8_t overwrite; + /* Omit the sessions' name(s). */ + uint8_t omit_name; + /* Omit the sessions' output(s). */ + uint8_t omit_output; } LTTNG_PACKED; #endif /* LTTNG_SAVE_INTERNAL_ABI_H */ diff --git a/include/lttng/save.h b/include/lttng/save.h index 1fbeb86f61..5ef22f6c92 100644 --- a/include/lttng/save.h +++ b/include/lttng/save.h @@ -59,6 +59,18 @@ const char *lttng_save_session_attr_get_output_url( */ int lttng_save_session_attr_get_overwrite( struct lttng_save_session_attr *attr); +/* + * Return the omit name configuration attribute. This attribute indicates + * whether or not the saved sessions' names should be omitted. + */ +int lttng_save_session_attr_get_omit_name( + struct lttng_save_session_attr *attr); +/* + * Return the omit output configuration attribute. This attribute indicates + * whether or not the saved sessions' output configuration should be omitted. + */ +int lttng_save_session_attr_get_omit_output( + struct lttng_save_session_attr *attr); /* * Save session attribute setter family functions. @@ -86,6 +98,18 @@ int lttng_save_session_attr_set_output_url( */ int lttng_save_session_attr_set_overwrite( struct lttng_save_session_attr *attr, int overwrite); +/* + * Set the omit name attribute. If set to true, the sessions' names are omitted + * from the resulting session configuration file. + */ +int lttng_save_session_attr_set_omit_name( + struct lttng_save_session_attr *attr, int omit_name); +/* + * Set the omit output attribute. If set to true, the sessions' output + * configurations are omitted from the resulting session configuration file. + */ +int lttng_save_session_attr_set_omit_output( + struct lttng_save_session_attr *attr, int omit_output); /* * Save session configuration(s). diff --git a/src/bin/lttng-sessiond/save.c b/src/bin/lttng-sessiond/save.c index 9ac7712cb1..7c72ff790c 100644 --- a/src/bin/lttng-sessiond/save.c +++ b/src/bin/lttng-sessiond/save.c @@ -1856,6 +1856,7 @@ int save_session(struct ltt_session *session, struct config_writer *writer = NULL; size_t session_name_len; const char *provided_path; + bool omit_name, omit_output; assert(session); assert(attr); @@ -1871,6 +1872,18 @@ int save_session(struct ltt_session *session, goto end; } + ret = lttng_save_session_attr_get_omit_name(attr); + if (ret < 0) { + goto end; + } + omit_name = !!ret; + + ret = lttng_save_session_attr_get_omit_output(attr); + if (ret < 0) { + goto end; + } + omit_output = !!ret; + provided_path = lttng_save_session_attr_get_output_url(attr); if (provided_path) { DBG3("Save session in provided path %s", provided_path); @@ -1963,11 +1976,13 @@ int save_session(struct ltt_session *session, goto end; } - ret = config_writer_write_element_string(writer, config_element_name, - session->name); - if (ret) { - ret = LTTNG_ERR_SAVE_IO_FAIL; - goto end; + if (!omit_name) { + ret = config_writer_write_element_string(writer, + config_element_name, session->name); + if (ret) { + ret = LTTNG_ERR_SAVE_IO_FAIL; + goto end; + } } if(session->shm_path[0] != '\0') { @@ -2023,9 +2038,11 @@ int save_session(struct ltt_session *session, } } - ret = save_session_output(writer, session); - if (ret) { - goto end; + if (!omit_output) { + ret = save_session_output(writer, session); + if (ret) { + goto end; + } } /* /session */ diff --git a/src/bin/lttng-sessiond/utils.c b/src/bin/lttng-sessiond/utils.c index f77a21ddb1..d676198208 100644 --- a/src/bin/lttng-sessiond/utils.c +++ b/src/bin/lttng-sessiond/utils.c @@ -55,8 +55,7 @@ void ht_cleanup_push(struct lttng_ht *ht) if (!ht) { return; } - if (fd < 0) - return; + assert(fd >= 0); ret = lttng_write(fd, &ht, sizeof(ht)); if (ret < sizeof(ht)) { PERROR("write ht cleanup pipe %d", fd); diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index 3379a3b27b..a390f125c4 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -30,6 +30,7 @@ #include #include +#include #include "../command.h" #include "../utils.h" @@ -46,17 +47,36 @@ static char *opt_url; static char *opt_ctrl_url; static char *opt_data_url; static char *opt_shm_path; +static char *opt_template_path; static int opt_no_consumer; static int opt_no_output; static int opt_snapshot; static unsigned int opt_live_timer; +static bool opt_default_name; +static bool opt_default_output; enum { OPT_HELP = 1, OPT_LIST_OPTIONS, OPT_LIVE_TIMER, + OPT_DEFAULT_NAME, + OPT_DEFAULT_OUTPUT, }; +enum { + OUTPUT_UNKNOWN = 1, + OUTPUT_NONE, + OUTPUT_LOCAL, + OUTPUT_NET, +}; +enum { + SESSION_UNKNOWN = 1, + SESSION_NORMAL, + SESSION_LIVE, + SESSION_SNAPSHOT, +}; + + static struct mi_writer *writer; static struct poptOption long_options[] = { @@ -72,6 +92,9 @@ static struct poptOption long_options[] = { {"snapshot", 0, POPT_ARG_VAL, &opt_snapshot, 1, 0, 0}, {"live", 0, POPT_ARG_INT | POPT_ARGFLAG_OPTIONAL, 0, OPT_LIVE_TIMER, 0, 0}, {"shm-path", 0, POPT_ARG_STRING, &opt_shm_path, 0, 0, 0}, + {"template-path", 0, POPT_ARG_STRING, &opt_template_path, 0, 0, 0}, + {"default-name", 0, POPT_ARG_NONE, NULL, OPT_DEFAULT_NAME, 0, 0}, + {"default-output", 0, POPT_ARG_NONE, NULL, OPT_DEFAULT_OUTPUT, 0, 0}, {0, 0, 0, 0, 0, 0, 0} }; @@ -160,14 +183,6 @@ static int set_consumer_url(const char *session_name, const char *ctrl_url, goto error; } - if (ctrl_url) { - MSG("Control URL %s set for session %s", ctrl_url, session_name); - } - - if (data_url) { - MSG("Data URL %s set for session %s", data_url, session_name); - } - error: lttng_destroy_handle(handle); return ret; @@ -214,249 +229,955 @@ static int add_snapshot_output(const char *session_name, const char *ctrl_url, } /* - * Create a tracing session. - * If no name is specified, a default name is generated. + * Validate the combinations of passed options * - * Returns one of the CMD_* result constants. + * CMD_ERROR on error + * CMD_SUCCESS on success */ -static int create_session(void) +static int validate_command_options(int session_type) { - int ret; - char *session_name = NULL, *traces_path = NULL, *alloc_path = NULL; - char *alloc_url = NULL, *url = NULL, datetime[16]; - char session_name_date[NAME_MAX + 17], *print_str_url = NULL; - time_t rawtime; - struct tm *timeinfo; - char shm_path[PATH_MAX] = ""; + int ret = CMD_SUCCESS; + if (opt_snapshot && opt_live_timer) { + ERR("Snapshot and live modes are mutually exclusive."); + ret = CMD_ERROR; + goto error; + } - /* Get date and time for automatic session name/path */ - time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo); + if ((!opt_ctrl_url && opt_data_url) || (opt_ctrl_url && !opt_data_url)) { + ERR("You need both control and data URL."); + ret = CMD_ERROR; + goto error; + } - /* Auto session name creation */ - if (opt_session_name == NULL) { - ret = snprintf(session_name_date, sizeof(session_name_date), - DEFAULT_SESSION_NAME "-%s", datetime); - if (ret < 0) { - PERROR("snprintf session name"); + if (opt_template_path) { + /* Restriction on flags exist when using template */ + /* Session type flags are not permitted */ + /* --live & --snapshot */ + if ((opt_live_timer && session_type != SESSION_LIVE) || + (opt_snapshot && session_type != SESSION_SNAPSHOT)) { + ERR("It is not possible to change the session type of a template"); + ret = CMD_ERROR; goto error; } - session_name = session_name_date; - DBG("Auto session name set to %s", session_name_date); + } + + if (opt_session_name && opt_default_name) { + ERR("A session name must not be provided if the --default-name option is used"); + ret = CMD_ERROR; + goto error; + } + + if (opt_default_output && (opt_data_url || opt_ctrl_url || opt_url || + opt_output_path)) { + ERR("The --default-output option may not be used with the --output/-o, --set-url/-U, --ctrl-url/-C, or --data-url/-D options"); + ret = CMD_ERROR; + goto error; + } +error: + return ret; +} + +/* + * Create a session via direct calls to liblttng-ctl. + * + * Return CMD_SUCCESS on success, negative value on internal lttng errors and positive + * value on command errors. + */ +static int create_session_basic (const char *session_name, + int session_type, + int live_timer, + int output_type, + const char* url, + const char* ctrl_url, + const char* data_url, + const char* shm_path, + const char* datetime) +{ + /* Create session based on session creation */ + int ret = CMD_SUCCESS; + const char *pathname; + + assert(datetime); + + if (opt_relayd_path) { + pathname = opt_relayd_path; } else { - if (strlen(opt_session_name) > NAME_MAX) { - ERR("Session name too long. Length must be lower or equal to %d", - NAME_MAX); - ret = LTTNG_ERR_SESSION_FAIL; + pathname = INSTALL_BIN_PATH "/lttng-relayd"; + } + + switch (session_type) { + case SESSION_NORMAL: + ret = _lttng_create_session_ext(session_name, url, datetime); + break; + case SESSION_SNAPSHOT: + if (output_type == OUTPUT_NONE) { + ERR("--no-output on a snapshot session is invalid"); + ret = CMD_UNSUPPORTED; goto error; } - /* - * Check if the session name begins with "auto-" or is exactly "auto". - * Both are reserved for the default session name. See bug #449 to - * understand why we need to check both here. - */ - if ((strncmp(opt_session_name, DEFAULT_SESSION_NAME "-", - strlen(DEFAULT_SESSION_NAME) + 1) == 0) || - (strncmp(opt_session_name, DEFAULT_SESSION_NAME, - strlen(DEFAULT_SESSION_NAME)) == 0 && - strlen(opt_session_name) == strlen(DEFAULT_SESSION_NAME))) { - ERR("%s is a reserved keyword for default session(s)", - DEFAULT_SESSION_NAME); - ret = CMD_ERROR; + ret = lttng_create_session_snapshot(session_name, url); + break; + case SESSION_LIVE: + if (output_type == OUTPUT_NONE) { + ERR("--no-output on a live session is invalid"); + ret = CMD_UNSUPPORTED; goto error; } - session_name = opt_session_name; - ret = snprintf(session_name_date, sizeof(session_name_date), - "%s-%s", session_name, datetime); - if (ret < 0) { - PERROR("snprintf session name"); + + if (output_type == OUTPUT_LOCAL) { + ERR("Local file output on a live session is invalid"); + ret = CMD_UNSUPPORTED; goto error; } + if (output_type != OUTPUT_NET && !check_relayd() && + spawn_relayd(pathname, 0) < 0) { + ret = CMD_FATAL; + goto error; + } + ret = lttng_create_session_live(session_name, url, live_timer); + break; + default: + ERR("Unknown session type"); + ret = CMD_UNDEFINED; + goto error; } - if ((!opt_ctrl_url && opt_data_url) || (opt_ctrl_url && !opt_data_url)) { - ERR("You need both control and data URL."); - ret = CMD_ERROR; + if (ret < 0) { + /* Don't set ret so lttng can interpret the sessiond error. */ + switch (-ret) { + case LTTNG_ERR_EXIST_SESS: + WARN("Session %s already exists", session_name); + break; + default: + break; + } goto error; } - if (opt_output_path != NULL) { - traces_path = utils_expand_path(opt_output_path); - if (traces_path == NULL) { - ret = CMD_ERROR; + /* Configure the session based on the output type */ + switch (output_type) { + case OUTPUT_LOCAL: + break; + case OUTPUT_NET: + if (session_type == SESSION_SNAPSHOT) { + ret = add_snapshot_output(session_name, ctrl_url, + data_url); + } else if (ctrl_url && data_url) { + /* + * Normal sessions and live sessions behave the same way + * regarding consumer url. + */ + ret = set_consumer_url(session_name, ctrl_url, data_url); + } + if (ret < 0) { + /* Destroy created session on errors */ + lttng_destroy_session(session_name); goto error; } + break; + case OUTPUT_NONE: + break; + default: + ERR("Unknown output type"); + ret = CMD_UNDEFINED; + goto error; + } - /* Create URL string from the local file system path */ - ret = asprintf(&alloc_url, "file://%s", traces_path); + /* + * Set the session shared memory path + */ + if (shm_path) { + ret = lttng_set_session_shm_path(session_name, shm_path); if (ret < 0) { - PERROR("asprintf url path"); - ret = CMD_FATAL; + lttng_destroy_session(session_name); goto error; } - /* URL to use in the lttng_create_session() call */ - url = alloc_url; - print_str_url = traces_path; - } else if (opt_url) { /* Handling URL (-U opt) */ - url = opt_url; - print_str_url = url; - } else if (opt_data_url && opt_ctrl_url) { - /* - * With both control and data, we'll be setting the consumer URL after - * session creation thus use no URL. - */ - url = NULL; - } else if (!opt_no_output) { - char *tmp_path; - - /* Auto output path */ - tmp_path = utils_get_home_dir(); - if (tmp_path == NULL) { - ERR("HOME path not found.\n \ - Please specify an output path using -o, --output PATH"); - ret = CMD_FATAL; + } +error: + return ret; +} + +static int generate_output(const char *session_name, + int session_type, + int live_timer, + int output_type, + const char* url, + const char* ctrl_url, + const char* data_url, + const char* shm_path) +{ + int ret = CMD_SUCCESS; + + /* + * TODO move this to after session name + * for now we only emulate previous behaviour. + */ + if (session_type != SESSION_SNAPSHOT) { + if (ctrl_url) { + MSG("Control URL %s set for session %s", ctrl_url, session_name); + } + + if (data_url) { + MSG("Data URL %s set for session %s", data_url, session_name); + } + } + + if (url && output_type == OUTPUT_LOCAL) { + /* Remove the file:// */ + if (strlen(url) > strlen("file://")){ + url = url + strlen("file://"); + } + } + + MSG("Session %s created.", session_name); + if (url && session_type != SESSION_SNAPSHOT) { + MSG("Traces will be written in %s", url); + + if (live_timer) { + MSG("Live timer set to %u usec", live_timer); + } + } else if (session_type == SESSION_SNAPSHOT) { + if (url) { + MSG("Default snapshot output set to: %s", url); + } + MSG("Snapshot mode set. Every channel enabled for that session will " + "be set in overwrite mode and mmap output."); + } + + if (shm_path) { + MSG("Session %s set to shm_path: %s.", session_name, + shm_path); + } + + /* Mi output */ + if (lttng_opt_mi) { + ret = mi_created_session(session_name); + if (ret) { + ret = CMD_ERROR; goto error; } - alloc_path = strdup(tmp_path); - if (!alloc_path) { - PERROR("allocating alloc_path"); - ret = CMD_FATAL; + } +error: + return ret; +} + +static int parse_template (struct config_document *template, + char **session_name, + int *session_type, + int *live_timer, + int *output_type, + char **url, + char **ctrl_url, + char **data_url, + char **shm_path) +{ + int ret = 0; + int printed_bytes; + char *raw_value = NULL; + + assert(template); + + /* Session name */ + *session_name = config_document_get_element_value(template,"/sessions/session/name"); + + /* Check the type of session we have in the template */ + if(config_document_element_exist(template, "/sessions/session/attributes/snapshot_mode")) { + *session_type = SESSION_SNAPSHOT; + } else if (config_document_element_exist(template, "/sessions/session/attributes/live_timer_interval")) { + *session_type = SESSION_LIVE; + raw_value = config_document_get_element_value(template,"/sessions/session/attributes/live_timer_interval"); + *live_timer = config_parse_value(raw_value); + free(raw_value); + raw_value = NULL; + } else { + *session_type = SESSION_NORMAL; + } + + /* Output */ + switch (*session_type) { + case SESSION_NORMAL: + case SESSION_LIVE: + if (!config_document_element_exist(template, "/sessions/session/output/consumer_output/destination")){ + break; + } + if (config_document_element_exist(template, "/sessions/session/output/consumer_output/destination/path")){ + raw_value = config_document_get_element_value(template, "/sessions/session/output/consumer_output/destination/path"); + if (!raw_value) { + ret = -1; + goto error; + } + + if (strlen(raw_value) > 0) { + *output_type = OUTPUT_LOCAL; + printed_bytes = asprintf(url, "file://%s", raw_value); + if (printed_bytes < 0) { + ret = -1; + goto error; + } + } else { + *output_type = OUTPUT_NONE; + } + + free(raw_value); + raw_value = NULL; + break; + } else if(config_document_element_exist(template, "/sessions/session/output/consumer_output/destination/net_output")) { + *ctrl_url = config_document_get_element_value(template, "/sessions/session/output/consumer_output/destination/net_output/control_uri"); + *data_url = config_document_get_element_value(template, "/sessions/session/output/consumer_output/destination/net_output/data_uri"); + if (!*ctrl_url || ! *data_url) { + ret = -1; + goto error; + } + *output_type = OUTPUT_NET; + } else { + /* There is no output definition */ + } + break; + case SESSION_SNAPSHOT: + if (!config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination")){ + break; + } + if (config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/path")){ + raw_value = config_document_get_element_value(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/path"); + if (!raw_value) { + ret = -1; + goto error; + } + + if (strlen(raw_value) > 0) { + *output_type = OUTPUT_LOCAL; + printed_bytes = asprintf(url, "file://%s", raw_value); + if (printed_bytes < 0) { + ret = -1; + goto error; + } + } else { + *output_type = OUTPUT_NONE; + } + + free(raw_value); + raw_value = NULL; + break; + } else if(config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/net_output")) { + *ctrl_url = config_document_get_element_value(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/net_output/control_uri"); + *data_url = config_document_get_element_value(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/net_output/data_uri"); + if (!*ctrl_url || ! *data_url) { + ret = -1; + goto error; + } + *output_type = OUTPUT_NET; + } else { + /* There is no output definition */ + } + break; + } + + + /* shared memory path */ + *shm_path = config_document_get_element_value(template,"/sessions/session/shared_memory_path"); + +error: + free(raw_value); + return ret; + +} +static int create_session_from_template(struct config_document *template, + const char *session_name, + int session_type, + int live_timer, + int output_type, + const char *url, + const char *ctrl_url, + const char *data_url, + const char *shm_path, + const char *datetime) +{ + int ret = CMD_SUCCESS; + int printed_bytes; + struct config_element *temp_element = NULL; + struct config_element *temp_element_child = NULL; + char tmp_ctrl_uri[PATH_MAX]; + char tmp_data_uri[PATH_MAX]; + struct lttng_uri *uris = NULL; + ssize_t uri_array_size = 0; + char *tmp_string = NULL; + + assert(template); + assert(session_name); + + memset(tmp_ctrl_uri, 0, sizeof(tmp_ctrl_uri)); + memset(tmp_data_uri, 0, sizeof(tmp_data_uri)); + + /* Session name */ + if (config_document_element_exist(template, "/sessions/session/name")) { + /* Replace the node value */ + config_document_replace_element_value(template, "/sessions/session/name", session_name); + } else { + /* insert the node */ + temp_element = config_element_create("name", session_name); + if (!temp_element) { + ERR("Could not create session name node configuration"); + ret = CMD_ERROR; goto error; } - ret = asprintf(&alloc_url, - "file://%s/" DEFAULT_TRACE_DIR_NAME "/%s", - alloc_path, session_name_date); - if (ret < 0) { - PERROR("asprintf trace dir name"); - ret = CMD_FATAL; + ret = config_document_insert_element(template, "/sessions/session", temp_element); + if (ret) { + ERR("Could not insert session name node configuration"); + ret = CMD_ERROR; goto error; } + config_element_free(temp_element); + } + + /* + * Live timer + */ + if (session_type == SESSION_LIVE) { + if (config_document_element_exist(template, "/sessions/session/attributes/live_timer_interval")) { + printed_bytes = asprintf(&tmp_string, "%d", live_timer); + if (printed_bytes < 0) { + ERR("Asprintf failed for live timer"); + ret = CMD_ERROR; + goto error; + } + ret = config_document_replace_element_value(template, "/sessions/session/attributes/live_timer_interval", tmp_string); + + if (ret) { + printf("error: %d\n", ret); + ERR("Replacement of live_timer_interval failed"); + ret = CMD_ERROR; + goto error; + } + + free(tmp_string); + tmp_string = NULL; + } else { + ERR("Invalid live timer template. Missing live timer node"); + ret = CMD_ERROR; + goto error; + } + + } + + /* + * Generate the output node + */ - url = alloc_url; - print_str_url = alloc_url + strlen("file://"); + /* Get output from urls */ + if (url) { + /* Get lttng uris from single url */ + uri_array_size = uri_parse_str_urls(url, NULL, &uris); + if (uri_array_size < 0) { + ret = CMD_ERROR; + goto error; + } + } else if (ctrl_url && data_url) { + uri_array_size = uri_parse_str_urls(ctrl_url, data_url, &uris); + if (uri_array_size < 0) { + ret = CMD_ERROR; + goto error; + } } else { - /* No output means --no-output or --snapshot mode. */ - url = NULL; + /* --no-output */ + uri_array_size = 0; } - /* Use default live URL if NO url is/are found. */ - if ((opt_live_timer && !opt_url) && (opt_live_timer && !opt_data_url)) { - ret = asprintf(&alloc_url, "net://127.0.0.1"); - if (ret < 0) { - PERROR("asprintf default live URL"); - ret = CMD_FATAL; + /* Validate if the session output type still match the passed data */ + if ( (uri_array_size == 0 && output_type != OUTPUT_NONE) || + (uri_array_size == 1 && output_type != OUTPUT_LOCAL) || + (uri_array_size == 2 && output_type != OUTPUT_NET)) { + ERR("Overwriting value for output do not match the base output type"); + ret = CMD_ERROR; + goto error; + } + + switch (output_type) { + case OUTPUT_NONE: + temp_element_child = config_element_create("path", ""); + if (!temp_element_child) { + ERR("Could not create empty path node configuration"); + ret = CMD_ERROR; + goto error; + } + break; + case OUTPUT_LOCAL: + temp_element_child = config_element_create("path", uris[0].dst.path); + if (!temp_element_child) { + ERR("Could not create local path node configuration"); + ret = CMD_ERROR; + goto error; + } + break; + case OUTPUT_NET: + uri_to_str_url(&uris[0], tmp_ctrl_uri, sizeof(tmp_ctrl_uri)); + uri_to_str_url(&uris[1], tmp_data_uri, sizeof(tmp_data_uri)); + + temp_element_child = config_element_create("net_output", NULL); + if (!temp_element_child) { + ERR("Could not create net_output node configuration"); + ret = CMD_ERROR; + goto error; + } + + temp_element = config_element_create("control_uri", tmp_ctrl_uri); + if (!temp_element_child) { + ERR("Could not create ctrl uri node configuration"); + ret = CMD_ERROR; + goto error; + } + + ret = config_element_add_child(temp_element_child, temp_element); + if (ret) { + ERR("Could not append control uri to the net_output node configuration"); + ret = CMD_ERROR; goto error; } - url = alloc_url; - print_str_url = url; + + config_element_free(temp_element); + temp_element = NULL; + + temp_element = config_element_create("data_uri", tmp_data_uri); + + if (!temp_element_child) { + ERR("Could not create data_uri configuration"); + ret = CMD_ERROR; + goto error; + } + + ret = config_element_add_child(temp_element_child, temp_element); + if (ret) { + ERR("Could not append data uri to the net_output node configuration"); + ret = CMD_ERROR; + goto error; + } + config_element_free(temp_element); + temp_element = NULL; + break; + default: + ret = CMD_ERROR; + goto error; } - if (opt_snapshot && opt_live_timer) { - ERR("Snapshot and live modes are mutually exclusive."); + temp_element = config_element_create("destination", NULL); + if (!temp_element) { + ERR("Could not create destination node configuration"); ret = CMD_ERROR; goto error; } - if (opt_snapshot) { - /* No output by default. */ - const char *snapshot_url = NULL; + ret = config_element_add_child(temp_element, temp_element_child); + if (ret) { + ERR("Could not append output data to the destination node configuration"); + ret = CMD_ERROR; + goto error; + } + + config_element_free(temp_element_child); + temp_element_child = NULL; + - if (opt_url) { - snapshot_url = url; - } else if (!opt_data_url && !opt_ctrl_url) { - /* This is the session path that we need to use as output. */ - snapshot_url = url; + /* + * validate and replace the destination node for each session type + * TODO: export string as const and simply assign a base path for the + * destination node based on the session type + **/ + switch (session_type) { + case SESSION_NORMAL: + case SESSION_LIVE: + if (!config_document_element_exist(template, "/sessions/session/output/consumer_output/destination")) { + ERR("Invalid template no destination node configuration present"); + ret = CMD_ERROR; + goto error; } - ret = lttng_create_session_snapshot(session_name, snapshot_url); - } else if (opt_live_timer) { - const char *pathname; - if (opt_relayd_path) { - pathname = opt_relayd_path; - } else { - pathname = INSTALL_BIN_PATH "/lttng-relayd"; + ret = config_document_replace_element(template, "/sessions/session/output/consumer_output/destination", temp_element); + break; + case SESSION_SNAPSHOT: + if (!config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination")) { + ERR("Invalid template no destination node configuration present"); + ret = CMD_ERROR; + goto error; } - if (!opt_url && !opt_data_url && !check_relayd() && - spawn_relayd(pathname, 0) < 0) { + + ret = config_document_replace_element(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination", temp_element); + break; + default: + ERR("Invalid session type"); + ret = CMD_UNDEFINED; + goto error; + } + + config_element_free(temp_element); + temp_element = NULL; + + + /* Shm path */ + if (shm_path && config_document_element_exist(template, "/sessions/session/shared_memory_path")) { + /* Replace the node value */ + config_document_replace_element_value(template, "/sessions/session/shared_memory_path", shm_path); + } else if (shm_path) { + /* insert the node */ + temp_element = config_element_create("shared_memory_path", shm_path); + if (!temp_element) { + ERR("Could not create shared_memory_path node configuration"); + ret = CMD_ERROR; goto error; } - ret = lttng_create_session_live(session_name, url, opt_live_timer); - } else { - ret = _lttng_create_session_ext(session_name, url, datetime); + ret = config_document_insert_element(template, "/sessions/session", temp_element); + if (ret) { + ERR("Could not insert shared_memory_path node configuration"); + ret = CMD_ERROR; + goto error; + } + + config_element_free(temp_element); + temp_element = NULL; } - if (ret < 0) { - /* Don't set ret so lttng can interpret the sessiond error. */ - switch (-ret) { - case LTTNG_ERR_EXIST_SESS: - WARN("Session %s already exists", session_name); - break; - default: - break; + + ret = config_load_configuration_sessions(template, session_name, 0); + + +error: + config_element_free(temp_element); + config_element_free(temp_element_child); + free(tmp_string); + free(uris); + return ret; + +} + +/* + * Create a tracing session. + * If no name is specified, a default name is generated. + * + * Returns one of the CMD_* result constants. + */ +static int create_session(void) +{ + int ret; + int printed_bytes; + + + /* Template */ + struct config_document *template = NULL; + + /* Base data */ + int base_session_type = SESSION_UNKNOWN; + int base_output_type = OUTPUT_UNKNOWN; + char *base_session_name = NULL; + char *base_url = NULL; + char *base_ctrl_url = NULL; + char *base_data_url = NULL; + char *base_shm_path = NULL; + int base_live_timer = 0; + + /* Time data */ + char datetime[16]; + time_t rawtime; + struct tm *timeinfo = NULL; + + /* Temporary variables */ + char *traces_path = NULL; + char *temp_url = NULL; + char *session_name_date = NULL; + char *tmp_url = NULL; + char *tmp_home_path = NULL; + struct lttng_uri *uris = NULL; + ssize_t uri_array_size = 0; + + + /* Get date and time for automatic session name/path */ + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo); + + if (opt_template_path) { + /* Restriction on flags exist when using template */ + /* Session type flags are not permitted */ + /* --live & --snapshot */ + template = config_document_get(opt_template_path); + if (!template) { + ERR("Template could not be parsed"); + ret = CMD_ERROR; + goto error; } + /* Load info from template if any */ + /* TODO: might want to use a struct in the end for the session... */ + ret = parse_template(template, &base_session_name, + &base_session_type, + &base_live_timer, + &base_output_type, + &base_url, + &base_ctrl_url, + &base_data_url, + &base_shm_path); + } + + /* Option validation */ + if (validate_command_options(base_session_type) != CMD_SUCCESS) { + ret = CMD_ERROR; goto error; } - if (opt_ctrl_url && opt_data_url) { + /* Find the session type based on options */ + if(base_session_type == SESSION_UNKNOWN) { if (opt_snapshot) { - ret = add_snapshot_output(session_name, opt_ctrl_url, - opt_data_url); + base_session_type = SESSION_SNAPSHOT; + } else if (opt_live_timer) { + base_session_type = SESSION_LIVE; } else { - /* Setting up control URI (-C or/and -D opt) */ - ret = set_consumer_url(session_name, opt_ctrl_url, opt_data_url); + base_session_type = SESSION_NORMAL; } - if (ret < 0) { - /* Destroy created session because the URL are not valid. */ - lttng_destroy_session(session_name); + } + + /* + * Session name handling + */ + if (opt_session_name) { + /* Override the session name */ + if (strlen(opt_session_name) > NAME_MAX) { + ERR("Session name too long. Length must be lower or equal to %d", + NAME_MAX); + ret = LTTNG_ERR_SESSION_FAIL; + free(session_name_date); goto error; } - } + /* + * Check if the session name begins with "auto-" or is exactly "auto". + * Both are reserved for the default session name. See bug #449 to + * understand why we need to check both here. + */ + if ((strncmp(opt_session_name, DEFAULT_SESSION_NAME "-", + strlen(DEFAULT_SESSION_NAME) + 1) == 0) || + (strncmp(opt_session_name, DEFAULT_SESSION_NAME, + strlen(DEFAULT_SESSION_NAME)) == 0 && + strlen(opt_session_name) == strlen(DEFAULT_SESSION_NAME))) { + ERR("%s is a reserved keyword for default session(s)", + DEFAULT_SESSION_NAME); - if (opt_shm_path) { - ret = snprintf(shm_path, sizeof(shm_path), - "%s/%s", opt_shm_path, session_name_date); - if (ret < 0) { - PERROR("snprintf shm_path"); + ret = CMD_ERROR; goto error; } - ret = lttng_set_session_shm_path(session_name, shm_path); - if (ret < 0) { - lttng_destroy_session(session_name); + base_session_name = strndup(opt_session_name, NAME_MAX); + if (!base_session_name) { + PERROR("Strdup session name"); + ret = CMD_ERROR; goto error; } + + printed_bytes = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); + if (printed_bytes < 0) { + PERROR("Asprintf session name"); + ret = CMD_ERROR; + goto error; + } + DBG("Session name from command option set to %s", base_session_name); + } else if (base_session_name && !opt_default_name) { + printed_bytes = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); + if (printed_bytes < 0) { + PERROR("Asprintf session name"); + ret = CMD_ERROR; + goto error; + } + } else { + /* Generate a name */ + printed_bytes = asprintf(&base_session_name, DEFAULT_SESSION_NAME "-%s", datetime); + if (printed_bytes < 0) { + PERROR("Asprintf generated session name"); + ret = CMD_ERROR; + goto error; + } + session_name_date = strdup(base_session_name); + DBG("Auto session name set to %s", base_session_name); } - MSG("Session %s created.", session_name); - if (print_str_url && !opt_snapshot) { - MSG("Traces will be written in %s", print_str_url); - if (opt_live_timer) { - MSG("Live timer set to %u usec", opt_live_timer); + /* + * Output handling + */ + + /* + * If any of those options are present clear all output related data. + */ + if (opt_output_path || opt_url || (opt_ctrl_url && opt_data_url) || opt_no_output) { + /* Overwrite output */ + free(base_url); + free(base_ctrl_url); + free(base_data_url); + base_url = NULL; + base_ctrl_url = NULL; + base_data_url = NULL; + } + + if (opt_output_path) { + + traces_path = utils_expand_path(opt_output_path); + if (!traces_path) { + ret = CMD_ERROR; + goto error; } - } else if (opt_snapshot) { - if (print_str_url) { - MSG("Default snapshot output set to: %s", print_str_url); + + /* Create URL string from the local file system path */ + printed_bytes = asprintf(&temp_url, "file://%s", traces_path); + if (printed_bytes < 0) { + PERROR("asprintf url path"); + ret = CMD_FATAL; + goto error; + } + + base_url = temp_url; + } else if (opt_url) { /* Handling URL (-U opt) */ + base_url = strdup(opt_url); + } else if (opt_data_url && opt_ctrl_url) { + /* + * With both control and data, we'll be setting the consumer URL + * after session creation thus use no URL. + */ + base_ctrl_url = strdup(opt_ctrl_url); + base_data_url = strdup(opt_data_url); + } else if (opt_default_output || !(opt_no_output || + base_output_type == OUTPUT_NONE || base_url || + base_ctrl_url || base_data_url)) { + /* Generate default output depending on the session type */ + switch (base_session_type) { + case SESSION_NORMAL: + /* fallthrough */ + case SESSION_SNAPSHOT: + /* Default to a local path */ + tmp_home_path = utils_get_home_dir(); + if (tmp_home_path == NULL) { + ERR("HOME path not found.\n \ + Please specify an output path using -o, --output PATH"); + ret = CMD_FATAL; + goto error; + } + + printed_bytes = asprintf(&tmp_url, + "file://%s/" DEFAULT_TRACE_DIR_NAME "/%s", + tmp_home_path, session_name_date); + + if (printed_bytes < 0) { + PERROR("asprintf trace dir name"); + ret = CMD_FATAL; + goto error; + } + + base_url = tmp_url ; + break; + case SESSION_LIVE: + /* Default to a net output */ + printed_bytes = asprintf(&tmp_url, "net://127.0.0.1"); + if (printed_bytes < 0) { + PERROR("asprintf default live URL"); + ret = CMD_FATAL; + goto error; + } + base_url = tmp_url ; + break; + default: + ERR("Unknown session type"); + ret = CMD_FATAL; + goto error; } - MSG("Snapshot mode set. Every channel enabled for that session will " - "be set in overwrite mode and mmap output."); } + + /* + * Shared memory path handling + */ if (opt_shm_path) { - MSG("Session %s set to shm_path: %s.", session_name, - shm_path); + /* Overwrite shm_path so clear any previously defined one */ + free(base_shm_path); + printed_bytes = asprintf(&base_shm_path, "%s/%s", opt_shm_path, session_name_date); + if (printed_bytes < 0) { + PERROR("asprintf shm_path"); + ret = CMD_FATAL; + goto error; + } } - /* Mi output */ - if (lttng_opt_mi) { - ret = mi_created_session(session_name); - if (ret) { + /* + * Live timer handling + */ + if (opt_live_timer) { + base_live_timer = opt_live_timer; + } + + /* Get output type from urls */ + /* TODO: Find a better way of inferring output type */ + if (base_url) { + /* Get lttng uris from single url */ + uri_array_size = uri_parse_str_urls(base_url, NULL, &uris); + if (uri_array_size < 0) { + ret = CMD_ERROR; + goto error; + } + } else if (base_ctrl_url && base_data_url) { + uri_array_size = uri_parse_str_urls(base_ctrl_url, base_data_url, &uris); + if (uri_array_size < 0) { ret = CMD_ERROR; goto error; } + } else { + /* --no-output */ + uri_array_size = 0; + } + + switch (uri_array_size) { + case 0: + base_output_type = OUTPUT_NONE; + break; + case 1: + base_output_type = OUTPUT_LOCAL; + break; + case 2: + base_output_type = OUTPUT_NET; + break; + default: + ret = CMD_ERROR; + goto error; + } + + if (template) { + ret = create_session_from_template(template, + base_session_name, + base_session_type, + base_live_timer, + base_output_type, + base_url, + base_ctrl_url, + base_data_url, + base_shm_path, + datetime); + } else { + ret = create_session_basic(base_session_name, + base_session_type, + base_live_timer, + base_output_type, + base_url, + base_ctrl_url, + base_data_url, + base_shm_path, + datetime); + } + if (ret) { + goto error; + } + + ret = generate_output(base_session_name, + base_session_type, + base_live_timer, + base_output_type, + base_url, + base_ctrl_url, + base_data_url, + base_shm_path); + if (ret) { + goto error; } /* Init lttng session config */ - ret = config_init(session_name); + ret = config_init(base_session_name); if (ret < 0) { ret = CMD_ERROR; goto error; @@ -465,13 +1186,21 @@ static int create_session(void) ret = CMD_SUCCESS; error: - free(alloc_url); + + /* Session temp stuff */ + config_document_free(template); + free(session_name_date); + free(uris); free(traces_path); - free(alloc_path); if (ret < 0) { ERR("%s", lttng_strerror(ret)); } + free(base_session_name); + free(base_url); + free(base_ctrl_url); + free(base_data_url); + free(base_shm_path); return ret; } @@ -662,6 +1391,12 @@ int cmd_create(int argc, const char **argv) DBG("Session live timer interval set to %d", opt_live_timer); break; } + case OPT_DEFAULT_NAME: + opt_default_name = true; + break; + case OPT_DEFAULT_OUTPUT: + opt_default_output = true; + break; default: ret = CMD_UNDEFINED; goto end; @@ -710,6 +1445,7 @@ int cmd_create(int argc, const char **argv) opt_session_name = (char*) poptGetArg(pc); command_ret = create_session(); + if (command_ret) { success = 0; } diff --git a/src/bin/lttng/commands/save.c b/src/bin/lttng/commands/save.c index fe051966cd..7370af01e3 100644 --- a/src/bin/lttng/commands/save.c +++ b/src/bin/lttng/commands/save.c @@ -29,28 +29,33 @@ #include static char *opt_output_path; -static int opt_force; -static int opt_save_all; +static bool opt_force; +static bool opt_save_all; +static bool opt_omit_name; +static bool opt_omit_output; +static struct mi_writer *writer; enum { OPT_HELP = 1, OPT_ALL, OPT_FORCE, OPT_LIST_OPTIONS, + OPT_OMIT_NAME, + OPT_OMIT_OUTPUT, }; static struct poptOption save_opts[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, - {"all", 'a', POPT_ARG_NONE, 0, OPT_ALL, 0, 0}, - {"output-path", 'o', POPT_ARG_STRING, &opt_output_path, 0, 0, 0}, - {"force", 'f', POPT_ARG_NONE, 0, OPT_FORCE, 0, 0}, + {"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL}, + {"all", 'a', POPT_ARG_NONE, NULL, OPT_ALL, NULL, NULL}, + {"output-path", 'o', POPT_ARG_STRING, &opt_output_path, 0, NULL, NULL}, + {"force", 'f', POPT_ARG_NONE, NULL, OPT_FORCE, NULL, NULL}, {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL}, + {"omit-name", 0, POPT_ARG_NONE, NULL, OPT_OMIT_NAME, NULL, NULL}, + {"omit-output", 0, POPT_ARG_NONE, NULL, OPT_OMIT_OUTPUT, NULL, NULL}, {0, 0, 0, 0, 0, 0, 0} }; -static struct mi_writer *writer; - static int mi_partial_session(const char *session_name) { int ret; @@ -109,6 +114,26 @@ static int mi_save_print(const char *session_name) } } + /* Omit session name. */ + if (opt_omit_name) { + /* Only print if true; assume default value otherwise. */ + ret = mi_lttng_writer_write_element_bool(writer, + config_element_omit_name, opt_omit_name); + if (ret) { + goto end; + } + } + + /* Omit session output. */ + if (opt_omit_output) { + /* Only print if true; assume default value otherwise. */ + ret = mi_lttng_writer_write_element_bool(writer, + config_element_omit_output, opt_omit_output); + if (ret) { + goto end; + } + } + /* Close save element */ ret = mi_lttng_writer_close_element(writer); end: @@ -135,14 +160,20 @@ int cmd_save(int argc, const char **argv) SHOW_HELP(); goto end; case OPT_ALL: - opt_save_all = 1; + opt_save_all = true; break; case OPT_FORCE: - opt_force = 1; + opt_force = true; break; case OPT_LIST_OPTIONS: list_cmd_options(stdout, save_opts); goto end; + case OPT_OMIT_NAME: + opt_omit_name = true; + break; + case OPT_OMIT_OUTPUT: + opt_omit_output = true; + break; default: ret = CMD_UNDEFINED; goto end; @@ -155,7 +186,7 @@ int cmd_save(int argc, const char **argv) DBG2("Session name: %s", session_name); } else { /* default to opt_save_all */ - opt_save_all = 1; + opt_save_all = true; } } @@ -180,6 +211,20 @@ int cmd_save(int argc, const char **argv) goto end_destroy; } + if (opt_omit_name) { + if (lttng_save_session_attr_set_omit_name(attr, true)) { + ret = CMD_ERROR; + goto end_destroy; + } + } + + if (opt_omit_output) { + if (lttng_save_session_attr_set_omit_output(attr, true)) { + ret = CMD_ERROR; + goto end_destroy; + } + } + /* Mi check */ if (lttng_opt_mi) { writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); diff --git a/src/common/config/config-internal.h b/src/common/config/config-internal.h index ff3e6293ec..f6de9005f2 100644 --- a/src/common/config/config-internal.h +++ b/src/common/config/config-internal.h @@ -16,8 +16,20 @@ */ #include +#include #include struct config_writer { xmlTextWriterPtr writer; }; + +struct config_document { + xmlDocPtr document; +}; + +struct config_element { + xmlNodePtr element; +}; + + + diff --git a/src/common/config/config-session-abi.h b/src/common/config/config-session-abi.h index 66d9cca73d..00757363fb 100644 --- a/src/common/config/config-session-abi.h +++ b/src/common/config/config-session-abi.h @@ -78,6 +78,8 @@ extern const char * const config_element_pid_tracker; extern const char * const config_element_trackers; extern const char * const config_element_targets; extern const char * const config_element_target_pid; +extern const char * const config_element_omit_name; +extern const char * const config_element_omit_output; extern const char * const config_domain_type_kernel; extern const char * const config_domain_type_ust; diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 6c639af440..432db6ecbd 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,8 @@ const char * const config_element_pid_tracker = "pid_tracker"; const char * const config_element_trackers = "trackers"; const char * const config_element_targets = "targets"; const char * const config_element_target_pid = "pid_target"; +const char * const config_element_omit_name = "omit_name"; +const char * const config_element_omit_output = "omit_output"; const char * const config_domain_type_kernel = "KERNEL"; const char * const config_domain_type_ust = "UST"; @@ -1025,6 +1028,7 @@ int init_domain(xmlNodePtr domain_node, struct lttng_domain *domain) { int ret; xmlNodePtr node; + bool buffer_type_set = false; for (node = xmlFirstElementChild(domain_node); node; node = xmlNextElementSibling(node)) { @@ -1044,6 +1048,7 @@ int init_domain(xmlNodePtr domain_node, struct lttng_domain *domain) } domain->type = ret; + buffer_type_set = true; } else if (!strcmp((const char *) node->name, config_element_buffer_type)) { /* buffer type */ @@ -1063,6 +1068,11 @@ int init_domain(xmlNodePtr domain_node, struct lttng_domain *domain) domain->buf_type = ret; } } + if (!buffer_type_set) { + /* Set the default buffer type of the domain. */ + domain->buf_type = domain->type == LTTNG_DOMAIN_KERNEL ? + LTTNG_BUFFER_GLOBAL : LTTNG_BUFFER_PER_UID; + } ret = 0; end: return ret; @@ -1783,11 +1793,13 @@ int process_events_node(xmlNodePtr events_node, struct lttng_handle *handle, } static -int process_channel_attr_node(xmlNodePtr attr_node, - struct lttng_channel *channel, xmlNodePtr *contexts_node, - xmlNodePtr *events_node) +int process_channel_attr_node(xmlNodePtr attr_node, bool snapshot_mode, + enum lttng_domain_type domain, struct lttng_channel *channel, + xmlNodePtr *contexts_node, xmlNodePtr *events_node) { int ret; + bool name_set = false; + bool output_type_set = false; assert(attr_node); assert(channel); @@ -1815,6 +1827,7 @@ int process_channel_attr_node(xmlNodePtr attr_node, strncpy(channel->name, (const char *) content, name_len); free(content); + name_set = true; } else if (!strcmp((const char *) attr_node->name, config_element_enabled)) { xmlChar *content; @@ -1961,6 +1974,7 @@ int process_channel_attr_node(xmlNodePtr attr_node, } channel->attr.output = ret; + output_type_set = true; } else if (!strcmp((const char *) attr_node->name, config_element_tracefile_size)) { xmlChar *content; @@ -2030,6 +2044,19 @@ int process_channel_attr_node(xmlNodePtr attr_node, /* contexts */ *contexts_node = attr_node; } + + if (!name_set) { + ERR("Encountered a channel with no name attribute."); + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + if (!output_type_set) { + /* Set default output type associated with the domain. */ + channel->attr.output = + (domain == LTTNG_DOMAIN_KERNEL && !snapshot_mode) ? + LTTNG_EVENT_SPLICE : LTTNG_EVENT_MMAP; + } ret = 0; end: return ret; @@ -2284,7 +2311,8 @@ int process_pid_tracker_node(xmlNodePtr pid_tracker_node, static -int process_domain_node(xmlNodePtr domain_node, const char *session_name) +int process_domain_node(xmlNodePtr domain_node, const char *session_name, + bool snapshot_mode) { int ret; struct lttng_domain domain = { 0 }; @@ -2336,7 +2364,8 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name) channel_attr_node; channel_attr_node = xmlNextElementSibling(channel_attr_node)) { ret = process_channel_attr_node(channel_attr_node, - &channel, &contexts_node, &events_node); + snapshot_mode, domain.type, &channel, + &contexts_node, &events_node); if (ret) { goto end; } @@ -2607,7 +2636,8 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, for (node = xmlFirstElementChild(domains_node); node; node = xmlNextElementSibling(node)) { - ret = process_domain_node(node, (const char *) name); + ret = process_domain_node(node, (const char *) name, + snapshot_mode == 1); if (ret) { goto end; } @@ -2722,6 +2752,47 @@ int load_session_from_file(const char *path, const char *session_name, return ret; } +/* TODO: DOC*/ +static +int load_session_from_document(struct config_document *document, const char *session_name, + struct session_config_validation_ctx *validation_ctx, int override) +{ + int ret, session_found = !session_name; + xmlNodePtr sessions_node; + xmlNodePtr session_node; + + assert(validation_ctx); + + ret = xmlSchemaValidateDoc(validation_ctx->schema_validation_ctx, document->document); + if (ret) { + ERR("Session configuration file validation failed"); + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + sessions_node = xmlDocGetRootElement(document->document); + if (!sessions_node) { + goto end; + } + + for (session_node = xmlFirstElementChild(sessions_node); + session_node; session_node = + xmlNextElementSibling(session_node)) { + ret = process_session_node(session_node, + session_name, override); + if (session_name && ret == 0) { + /* Target session found and loaded */ + session_found = 1; + break; + } + } +end: + if (!ret) { + ret = session_found ? 0 : -LTTNG_ERR_LOAD_SESSION_NOENT; + } + return ret; +} + /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */ static struct dirent *alloc_dirent(const char *path) @@ -3018,3 +3089,609 @@ void __attribute__((destructor)) session_config_exit(void) { xmlCleanupParser(); } + +LTTNG_HIDDEN +struct config_document *config_document_get(const char *path) +{ + int ret; + struct config_document *document = NULL; + struct session_config_validation_ctx validation_ctx = { 0 }; + + assert(path); + + ret = access(path, F_OK); + if (ret < 0) { + PERROR("access"); + switch (errno) { + case ENOENT: + ret = -LTTNG_ERR_INVALID; + WARN("Session configuration path does not exist."); + break; + case EACCES: + ret = -LTTNG_ERR_EPERM; + break; + default: + ret = -LTTNG_ERR_UNK; + break; + } + goto end; + } + + ret = init_session_config_validation_ctx(&validation_ctx); + if (ret) { + goto end; + } + + ret = validate_file_read_creds(path); + if (ret != 1) { + if (ret == -1) { + ret = -LTTNG_ERR_EPERM; + } else { + ret = -LTTNG_ERR_LOAD_SESSION_NOENT; + } + goto end; + } + + document = zmalloc(sizeof(struct config_document)); + if (!document) { + PERROR("zmalloc"); + ret = -errno; + goto end; + } + + document->document = xmlParseFile(path); + if (!document->document) { + ret = -LTTNG_ERR_LOAD_IO_FAIL; + goto error; + } + + ret = xmlSchemaValidateDoc(validation_ctx.schema_validation_ctx, + document->document); + if (ret) { + ERR("Session configuration file validation failed"); + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } + +end: + fini_session_config_validation_ctx(&validation_ctx); + return document; +error: + xmlFreeDoc(document->document); + free(document); + return NULL; +} + +LTTNG_HIDDEN +void config_document_free(struct config_document *document) +{ + if (document) { + xmlFreeDoc(document->document); + document->document = NULL; + } + + free(document); +} + +LTTNG_HIDDEN +int config_document_replace_element_value(struct config_document *document, + const char *xpath, const char *value) +{ + int ret = 0; + int xpath_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + xmlChar *internal_value = NULL; + + assert(document); + assert(xpath); + assert(value); + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to encode xpath string"); + goto end; + } + + internal_value = encode_string(value); + if (!internal_value) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to encode xpath replace value string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document->document); + if (!xpath_context) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate de xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + /* TODO: from here could be extracted and previopus could be a step in + * subsequent operation, modify/substitute/delete node. + */ + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + /*TODO set valid error */ + ret = -1; + ERR("Unset xpath result set or empty set ?"); + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + /* + * Reverse traversal since last element could be nested under parent + * element present in the result set. + */ + for (int i = xpath_result_size - 1; i >=0; i--) { + assert(xpath_result_set->nodeTab[i]); + xmlNodeSetContent(xpath_result_set->nodeTab[i], internal_value); + + /* + * Libxml2 quirk regarding the freing and namesplace node see + * libxml2 example and documentation for more details. + */ + if (xpath_result_set->nodeTab[i]->type != XML_NAMESPACE_DECL) { + xpath_result_set->nodeTab[i] = NULL; + } + } + + xmlDocDump(stdout, document->document); +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + xmlFree(internal_value); + return ret; +} + +LTTNG_HIDDEN +int config_load_configuration_sessions(struct config_document *document, + const char *session_name, int override) +{ + int ret; + struct session_config_validation_ctx validation_ctx = { 0 }; + + ret = init_session_config_validation_ctx(&validation_ctx); + if (ret) { + goto end; + } + ret = load_session_from_document(document, session_name, + &validation_ctx, override); +end: + fini_session_config_validation_ctx(&validation_ctx); + return ret; +} + +LTTNG_HIDDEN +int config_document_replace_element(struct config_document *document, + const char *xpath, const struct config_element *element) +{ + int ret = 0; + int xpath_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + xmlNodePtr old_node = NULL; + xmlNodePtr copy = NULL; + + assert(document); + assert(xpath); + assert(element); + assert(element->element); + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to encode xpath string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document->document); + if (!xpath_context) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate the xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + /*TODO set valid error */ + ret = -1; + ERR("Unset xpath result set or empty set ?"); + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + if (xpath_result_size > 1) { + /*TODO set valid error */ + ERR("To many result while fetching config element value"); + ret = -1; + goto end; + } + + if (xpath_result_size == 0) { + ret = -1; + goto end; + } + + assert(xpath_result_set->nodeTab[0]); + + /* Do a copy of the element to ease caller memory management */ + copy = xmlCopyNode(element->element, 1); + if (!copy) { + ret = -1; + ERR("Copy failed for node replacement"); + goto end; + } + + old_node = xmlReplaceNode(xpath_result_set->nodeTab[0], copy); + if (xpath_result_set->nodeTab[0]->type != XML_NAMESPACE_DECL) + xpath_result_set->nodeTab[0] = NULL; + if (!old_node) { + ret = -1; + xmlFreeNode(copy); + ERR("Node replacement failed"); + goto end; + } + xmlUnlinkNode(old_node); + xmlFreeNode(old_node); +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + return ret; +} + +/* TODO: DOC + * + */ +LTTNG_HIDDEN +char *config_document_get_element_value(struct config_document *document, + const char *xpath) +{ + char *value = NULL; + int xpath_result_size; + int value_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + xmlChar *internal_value = NULL; + + assert(document); + assert(xpath); + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + /*TODO set valid error */ + value = NULL; + ERR("Unable to encode xpath string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document->document); + if (!xpath_context) { + /*TODO set valid error */ + value = NULL; + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate the xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + /*TODO set valid error */ + value = NULL; + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + /*TODO set valid error */ + value = NULL; + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + if (xpath_result_size > 1) { + /*TODO set valid error */ + ERR("To many result while fetching config element value"); + value = NULL; + goto end; + } + + if (xpath_result_size == 0) { + value = NULL; + goto end; + } + + /* + * Reverse traversal since last element could be nested under parent + * element present in the result set. + */ + assert(xpath_result_set->nodeTab[0]); + internal_value = xmlNodeGetContent(xpath_result_set->nodeTab[0]); + if (!internal_value) { + value = NULL; + goto end; + } + + value_result_size = xmlStrlen(internal_value); + value = calloc(value_result_size + 1, sizeof(char)); + strncpy(value, (char *) internal_value, value_result_size); + +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + xmlFree(internal_value); + return value; +} + +LTTNG_HIDDEN +int config_document_element_exist(struct config_document *document, + const char *xpath) +{ + int exist = 0; + int xpath_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + + assert(document); + assert(document->document); + assert(xpath); + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + /*TODO set valid error */ + ERR("Unable to encode xpath string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document->document); + if (!xpath_context) { + /*TODO set valid error */ + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate the xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + /*TODO set valid error */ + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + if (xpath_result_size > 0) { + exist = 1; + } +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + return exist; + +} + +LTTNG_HIDDEN +struct config_element *config_element_create(const char *name, + const char* value) +{ + struct config_element *element; + + assert(name); + + xmlChar *internal_name = NULL; + xmlChar *internal_value = NULL; + + internal_name = encode_string(name); + + /* TODO check error*/ + + if (value) { + internal_value = encode_string(value); + } + + element = zmalloc(sizeof(struct config_element)); + if (!element) { + goto end; + } + + element->element = xmlNewNode(NULL, internal_name); + if (!element->element) { + free(element); + element = NULL; + } + + if (internal_value) { + xmlNodeAddContent(element->element, internal_value); + } +end: + xmlFree(internal_name); + xmlFree(internal_value); + return element; +} + +LTTNG_HIDDEN +int config_element_add_child(struct config_element *parent, + const struct config_element *child) +{ + assert(parent); + assert(child); + assert(parent->element); + assert(child->element); + + int ret = 0; + xmlNodePtr node = NULL; + xmlNodePtr copy = NULL; + + /* Do a copy to ease the memory management for caller */ + copy = xmlCopyNode(child->element, 1); + if (!copy) { + ERR("Duplication of child to be added failed"); + /* TODO: return valid error */ + ret = -1; + goto error; + } + node = xmlAddChild(parent->element, copy); + if (!node) { + ERR("Add child failed"); + /* TODO: return valid error */ + xmlFreeNode(copy); + ret = -1; + goto error; + } +error: + return ret; +} + + +LTTNG_HIDDEN +int config_document_insert_element(struct config_document *document, + const char *xpath, const struct config_element *element) +{ + /* TODO: real ret default value */ + int ret = 0; + int xpath_result_size; + + xmlXPathContextPtr xpath_context = NULL; + xmlXPathObjectPtr xpath_object = NULL; + xmlNodeSetPtr xpath_result_set = NULL; + xmlChar *internal_xpath = NULL; + xmlNodePtr child_node = NULL; + xmlNodePtr local_copy = NULL; + + assert(document); + assert(xpath); + assert(element); + assert(element->element); + + internal_xpath = encode_string(xpath); + if (!internal_xpath) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to encode xpath string"); + goto end; + } + + /* Initialize xpath context */ + xpath_context = xmlXPathNewContext(document->document); + if (!xpath_context) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to create xpath context"); + goto end; + } + + /* Evaluate the xpath expression */ + xpath_object = xmlXPathEvalExpression(internal_xpath, xpath_context); + if (!xpath_object) { + /*TODO set valid error */ + ret = -1; + ERR("Unable to evaluate xpath query (invalid query format)"); + goto end; + } + + xpath_result_set = xpath_object->nodesetval; + if (!xpath_result_set) { + /*TODO set valid error */ + ret = -1; + ERR("Unset xpath result set or empty set ?"); + goto end; + } + + xpath_result_size = xpath_result_set->nodeNr; + + if (xpath_result_size > 1) { + /*TODO set valid error */ + ERR("To many result while fetching config element value"); + ret = -1; + goto end; + } + + if (xpath_result_size == 0) { + ret = -1; + goto end; + } + + assert(xpath_result_set->nodeTab[0]); + /* Do a copy to simply memory management */ + local_copy = xmlCopyNode(element->element, 1); + if (!local_copy) { + ret = -1; + ERR("Duplication of node to be insert failed"); + goto end; + } + + child_node = xmlAddChild(xpath_result_set->nodeTab[0], local_copy); + if (!child_node) { + ret = -1; + xmlFreeNode(local_copy); + ERR("Insertion failed on add child"); + goto end; + } +end: + xmlXPathFreeContext(xpath_context); + xmlXPathFreeObject(xpath_object); + xmlFree(internal_xpath); + return ret; +} + +LTTNG_HIDDEN +void config_element_free(struct config_element *element) { + if (element && element->element) { + xmlFreeNode(element->element); + } + + free(element); +} diff --git a/src/common/config/session-config.h b/src/common/config/session-config.h index 939cb6cbf0..8e5d1506de 100644 --- a/src/common/config/session-config.h +++ b/src/common/config/session-config.h @@ -33,6 +33,11 @@ struct config_entry { /* Instance of a configuration writer. */ struct config_writer; +/* Instance of a configuration element */ +struct config_document; + +struct config_element; + /* * A config_entry_handler_cb receives config_entry structures belonging to the * sections the handler has been registered to. @@ -225,4 +230,61 @@ LTTNG_HIDDEN int config_load_session(const char *path, const char *session_name, int override, unsigned int autoload); +/* + * TODO: doc decide + * Load configuration based on a config_document + */ +LTTNG_HIDDEN +int config_load_configuration_sessions(struct config_document *document, + const char *session_name, int override); + +/* TODO: DOC + * + */ +LTTNG_HIDDEN +struct config_document *config_document_get(const char *path); + +LTTNG_HIDDEN +void config_document_free(struct config_document *document); + +/* TODO: DOC + * + */ +LTTNG_HIDDEN +int config_document_replace_element_value(struct config_document *document, const char *xpath, const char *value); + +/* TODO: DOC + * Swap a node by the new element (copy child etc) + */ +LTTNG_HIDDEN +int config_document_replace_element(struct config_document *document, const char *xpath, const struct config_element *element); + +/* TODO: DOC + * + */ +LTTNG_HIDDEN +char *config_document_get_element_value(struct config_document *document, const char *xpath); + +/* TODO: DOC + * return 1 if true 0 otherwise; + */ +LTTNG_HIDDEN +int config_document_element_exist(struct config_document *document, const char *xpath); + +/* TODO: DOC + * + */ +LTTNG_HIDDEN +void config_element_free(struct config_element *element); + +LTTNG_HIDDEN +struct config_element *config_element_create(const char *name, const char *value); + +LTTNG_HIDDEN +int config_element_add_child(struct config_element *parent, const struct config_element *child); + +LTTNG_HIDDEN +int config_document_insert_element(struct config_document *document, const char *xpath, const struct config_element *element); + + #endif /* _CONFIG_H */ diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index 550fea0ee2..e21bdee534 100644 --- a/src/common/config/session.xsd +++ b/src/common/config/session.xsd @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> +elementFormDefault="qualified" version="3.0"> @@ -179,14 +179,14 @@ elementFormDefault="qualified" version="2.8"> - + - - + + @@ -254,7 +254,7 @@ elementFormDefault="qualified" version="2.8"> - + @@ -281,7 +281,7 @@ elementFormDefault="qualified" version="2.8"> - + @@ -317,7 +317,7 @@ elementFormDefault="qualified" version="2.8"> - + diff --git a/src/common/mi-lttng-3.0.xsd b/src/common/mi-lttng-3.0.xsd index 436a9893b3..2c29c9cea8 100644 --- a/src/common/mi-lttng-3.0.xsd +++ b/src/common/mi-lttng-3.0.xsd @@ -417,6 +417,8 @@ THE SOFTWARE. + + diff --git a/src/lib/lttng-ctl/save.c b/src/lib/lttng-ctl/save.c index f8b9043b63..555006d0af 100644 --- a/src/lib/lttng-ctl/save.c +++ b/src/lib/lttng-ctl/save.c @@ -68,6 +68,18 @@ int lttng_save_session_attr_get_overwrite( return attr ? attr->overwrite : -LTTNG_ERR_INVALID; } +int lttng_save_session_attr_get_omit_name( + struct lttng_save_session_attr *attr) +{ + return attr ? attr->omit_name : -LTTNG_ERR_INVALID; +} + +int lttng_save_session_attr_get_omit_output( + struct lttng_save_session_attr *attr) +{ + return attr ? attr->omit_output : -LTTNG_ERR_INVALID; +} + int lttng_save_session_attr_set_session_name( struct lttng_save_session_attr *attr, const char *session_name) { @@ -151,6 +163,36 @@ int lttng_save_session_attr_set_overwrite( return ret; } +int lttng_save_session_attr_set_omit_name( + struct lttng_save_session_attr *attr, int omit_name) +{ + int ret = 0; + + if (!attr) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + attr->omit_name = !!omit_name; +end: + return ret; +} + +int lttng_save_session_attr_set_omit_output( + struct lttng_save_session_attr *attr, int omit_output) +{ + int ret = 0; + + if (!attr) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + attr->omit_output = !!omit_output; +end: + return ret; +} + /* * The lttng-ctl API does not expose all the information needed to save the * session configurations. Thus, we must send a save command to the session diff --git a/tests/regression/Makefile.am b/tests/regression/Makefile.am index 6a2d24c7bf..d1c19e6b4e 100644 --- a/tests/regression/Makefile.am +++ b/tests/regression/Makefile.am @@ -22,7 +22,8 @@ TESTS = tools/filtering/test_invalid_filter \ tools/mi/test_mi \ tools/wildcard/test_event_wildcard \ tools/crash/test_crash \ - tools/metadata-regen/test_ust + tools/metadata-regen/test_ust \ + tools/templates/test_create if HAVE_LIBLTTNG_UST_CTL SUBDIRS += ust diff --git a/tests/regression/tools/Makefile.am b/tests/regression/tools/Makefile.am index 6c39c9f18c..5c4207d94b 100644 --- a/tests/regression/tools/Makefile.am +++ b/tests/regression/tools/Makefile.am @@ -1,2 +1,2 @@ SUBDIRS = streaming filtering health tracefile-limits snapshots live exclusion save-load mi \ - wildcard crash metadata-regen + wildcard crash metadata-regen templates diff --git a/tests/regression/tools/templates/Makefile.am b/tests/regression/tools/templates/Makefile.am new file mode 100644 index 0000000000..8fe5b19869 --- /dev/null +++ b/tests/regression/tools/templates/Makefile.am @@ -0,0 +1,17 @@ +noinst_SCRIPTS = test_create +EXTRA_DIST = $(noinst_SCRIPTS) sessions +SUBDIRS= sessions + +all-local: + @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ + for script in $(EXTRA_DIST); do \ + cp -f $(srcdir)/$$script $(builddir); \ + done; \ + fi + +clean-local: + @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ + for script in $(EXTRA_DIST); do \ + rm -f $(builddir)/$$script; \ + done; \ + fi diff --git a/tests/regression/tools/templates/sessions/Makefile.am b/tests/regression/tools/templates/sessions/Makefile.am new file mode 100644 index 0000000000..484426bff9 --- /dev/null +++ b/tests/regression/tools/templates/sessions/Makefile.am @@ -0,0 +1,18 @@ +EXTRA_DIST = live.lttng live_output_generation.lttng name_generation.lttng \ + normal_local.lttng normal_net.lttng normal_no_output.lttng \ + normal_output_generation.lttng shm_path.lttng snapshot_local.lttng \ + snapshot_net.lttng snapshot_output_generation.lttng full_load.lttng + +all-local: + @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ + for script in $(EXTRA_DIST); do \ + cp -f $(srcdir)/$$script $(builddir); \ + done; \ + fi + +clean-local: + @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ + for script in $(EXTRA_DIST); do \ + rm -f $(builddir)/$$script; \ + done; \ + fi diff --git a/tests/regression/tools/templates/sessions/full_load.lttng b/tests/regression/tools/templates/sessions/full_load.lttng new file mode 100644 index 0000000000..938f3d7b2b --- /dev/null +++ b/tests/regression/tools/templates/sessions/full_load.lttng @@ -0,0 +1,54 @@ + + + + full_load + + + UST + PER_UID + + + channel0 + true + DISCARD + 131072 + 4 + 0 + 0 + MMAP + 0 + 0 + 0 + + + + + + + + JUL + PER_UID + + + + LOG4J + PER_UID + + + + PYTHON + PER_UID + + + + false + + + true + + /home/jonathan/lttng-traces/full_load-20160607-021349 + + + + + diff --git a/tests/regression/tools/templates/sessions/live.lttng b/tests/regression/tools/templates/sessions/live.lttng new file mode 100644 index 0000000000..206127527b --- /dev/null +++ b/tests/regression/tools/templates/sessions/live.lttng @@ -0,0 +1,21 @@ + + + + live + false + + 1000000 + + + + true + + + tcp4://127.0.0.1:5342/ + tcp4://127.0.0.1:5343/ + + + + + + diff --git a/tests/regression/tools/templates/sessions/live_output_generation.lttng b/tests/regression/tools/templates/sessions/live_output_generation.lttng new file mode 100644 index 0000000000..67d00dea45 --- /dev/null +++ b/tests/regression/tools/templates/sessions/live_output_generation.lttng @@ -0,0 +1,17 @@ + + + + live_output_generation + false + + 1000000 + + + + true + + + + + + diff --git a/tests/regression/tools/templates/sessions/name_generation.lttng b/tests/regression/tools/templates/sessions/name_generation.lttng new file mode 100644 index 0000000000..f2c44c9720 --- /dev/null +++ b/tests/regression/tools/templates/sessions/name_generation.lttng @@ -0,0 +1,14 @@ + + + + false + + + true + + /home/jonathan/lttng-traces/normal_local-20160606-132532 + + + + + diff --git a/tests/regression/tools/templates/sessions/normal_local.lttng b/tests/regression/tools/templates/sessions/normal_local.lttng new file mode 100644 index 0000000000..fe55111d61 --- /dev/null +++ b/tests/regression/tools/templates/sessions/normal_local.lttng @@ -0,0 +1,15 @@ + + + + normal_local + false + + + true + + /home/jonathan/lttng-traces/normal_local-20160606-132532 + + + + + diff --git a/tests/regression/tools/templates/sessions/normal_net.lttng b/tests/regression/tools/templates/sessions/normal_net.lttng new file mode 100644 index 0000000000..3e875a762e --- /dev/null +++ b/tests/regression/tools/templates/sessions/normal_net.lttng @@ -0,0 +1,18 @@ + + + + normal_net + false + + + true + + + tcp4://127.0.0.1:5342/normal_net-20160606-132620 + tcp4://127.0.0.1:5343/ + + + + + + diff --git a/tests/regression/tools/templates/sessions/normal_no_output.lttng b/tests/regression/tools/templates/sessions/normal_no_output.lttng new file mode 100644 index 0000000000..85eacb8e76 --- /dev/null +++ b/tests/regression/tools/templates/sessions/normal_no_output.lttng @@ -0,0 +1,15 @@ + + + + normal_no_output + false + + + true + + + + + + + diff --git a/tests/regression/tools/templates/sessions/normal_output_generation.lttng b/tests/regression/tools/templates/sessions/normal_output_generation.lttng new file mode 100644 index 0000000000..44844a250c --- /dev/null +++ b/tests/regression/tools/templates/sessions/normal_output_generation.lttng @@ -0,0 +1,14 @@ + + + + normal_output_generation + false + + + true + + + + + + diff --git a/tests/regression/tools/templates/sessions/shm_path.lttng b/tests/regression/tools/templates/sessions/shm_path.lttng new file mode 100644 index 0000000000..17bf2a30b7 --- /dev/null +++ b/tests/regression/tools/templates/sessions/shm_path.lttng @@ -0,0 +1,16 @@ + + + + shm_path + /tmp/shm_path-20160606-161801 + false + + + true + + /home/jonathan/lttng-traces/shm_path-20160606-161801 + + + + + diff --git a/tests/regression/tools/templates/sessions/snapshot_local.lttng b/tests/regression/tools/templates/sessions/snapshot_local.lttng new file mode 100644 index 0000000000..58a8ab4358 --- /dev/null +++ b/tests/regression/tools/templates/sessions/snapshot_local.lttng @@ -0,0 +1,24 @@ + + + + snapshot_local + false + + true + + + + + snapshot-1 + 0 + + true + + /home/jonathan/lttng-traces/snapshot_local-20160606-132651 + + + + + + + diff --git a/tests/regression/tools/templates/sessions/snapshot_net.lttng b/tests/regression/tools/templates/sessions/snapshot_net.lttng new file mode 100644 index 0000000000..8a068f60d5 --- /dev/null +++ b/tests/regression/tools/templates/sessions/snapshot_net.lttng @@ -0,0 +1,27 @@ + + + + snapshot_net + false + + true + + + + + snapshot-1 + 0 + + true + + + tcp4://127.0.0.1:5342/ + tcp4://127.0.0.1:5343/ + + + + + + + + diff --git a/tests/regression/tools/templates/sessions/snapshot_output_generation.lttng b/tests/regression/tools/templates/sessions/snapshot_output_generation.lttng new file mode 100644 index 0000000000..b0d2bd7658 --- /dev/null +++ b/tests/regression/tools/templates/sessions/snapshot_output_generation.lttng @@ -0,0 +1,23 @@ + + + + snapshot_output_generation + false + + true + + + + + snapshot-1 + 0 + + true + + + + + + + + diff --git a/tests/regression/tools/templates/test_create b/tests/regression/tools/templates/test_create new file mode 100755 index 0000000000..b16b00ed81 --- /dev/null +++ b/tests/regression/tools/templates/test_create @@ -0,0 +1,718 @@ +#!/bin/bash +# +# Copyright (C) - 2016 Jonathan Rajotte +# +# This library is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; version 2.1 of the License. +# +# This library 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 Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +TEST_DESC="Session creation based on template" + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/../../../ +SESSIOND_BIN="lttng-sessiond" +RELAYD_BIN="lttng-relayd" + +export LTTNG_SESSION_CONFIG_XSD_PATH=$(readlink -m ${TESTDIR}../src/common/config/) + +SESSION_NAME="load-42" + +DIR=$(readlink -f $TESTDIR) + +NUM_TESTS=89 + +source $TESTDIR/utils/utils.sh + +LTTNG_BIN="lttng --mi xml" + +# MUST set TESTDIR before calling those functions +plan_tests $NUM_TESTS + +print_test_banner "$TEST_DESC" + +#Test related data + +XPATH_SESSION_NAME="//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:name/text()" +XPATH_SESSION_PATH="//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path/text()" +XPATH_SESSION_SNAPSHOT_MODE="//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:snapshot_mode/text()" +XPATH_SESSION_SNAPSHOT_CTRL_URL="//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:ctrl_url/text()" +XPATH_SESSION_SNAPSHOT_DATA_URL="//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:data_url/text()" +XPATH_SESSION_LIVE_TIMER_INTERVAL="//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:live_timer_interval/text()" +XPATH_SAVE_SESSION_SHM_PATH="//sessions/session/shared_memory_path/text()" + +TEMPLATE_DIR="$CURDIR/sessions" + +# TODO: note: most of these fuctions could have been tested via lttng save and +# diffing the original and the saved one. Might want to go this way... + +function test_normal_local() +{ + diag "Load from template a normal session with local consumer output" + local template_name="normal_local.lttng" + local session_name="normal_local" + local output_path="/home/jonathan/lttng-traces/normal_local-20160606-132532" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate name + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_NAME}") + if [[ $mi_result = "$session_name" ]]; then + ok 0 "Session names are the same" + else + fail "Session names should be $session_name but value is $mi_result" + fi + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be $output_path but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_normal_no_output() +{ + diag "Load from template a normal session with no output (--no-output)" + local template_name="normal_no_output.lttng" + local session_name="normal_no_output" + local output_path="" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate name + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_NAME}") + if [[ $mi_result = "$session_name" ]]; then + ok 0 "Session names are the same" + else + fail "Session names should be $session_name but value is $mi_result" + fi + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_normal_net() +{ + diag "Load from template a normal session with net output" + local template_name="normal_net.lttng" + local session_name="normal_net" + local output_path="tcp4://127.0.0.1:5342/normal_net-20160606-132620 [data: 5343]" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate name + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_NAME}") + if [[ $mi_result = "$session_name" ]]; then + ok 0 "Session names are the same" + else + fail "Session names should be $session_name but value is $mi_result" + fi + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_snapshot_local() +{ + diag "Load from template a snapshot session with local output" + local template_name="snapshot_local.lttng" + local session_name="snapshot_local" + local output_path="" + local snapshot_ctrl_url="/home/jonathan/lttng-traces/snapshot_local-20160606-132651" + local snapshot_data_url="" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate name + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_MODE}") + if [[ $mi_result = "1" ]]; then + ok 0 "Session snapshot mode is enabled" + else + fail "Session snapshot mode is invalid value is $mi_result" + fi + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + OUTPUT_DEST="$mi_output_file" lttng_snapshot_list $session_name + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_CTRL_URL}") + if [[ $mi_result = "$snapshot_ctrl_url" ]]; then + ok 0 "Ctrl urls for snapshot are the same" + else + fail "Ctrl urls should be $snapshot_ctrl_url but value is $mi_result" + fi + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_DATA_URL}") + if [[ $mi_result = "$snapshot_data_url" ]]; then + ok 0 "Data urls for snapshot are the same" + else + fail "Data urls should be $snapshot_data_url but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_snapshot_net() +{ + diag "Load from template a snapshot session with net output" + local template_name="snapshot_net.lttng" + local session_name="snapshot_net" + local output_path="" + local snapshot_ctrl_url="tcp4://127.0.0.1:5342/" + local snapshot_data_url="tcp4://127.0.0.1:5343/" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate name + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_MODE}") + if [[ $mi_result = "1" ]]; then + ok 0 "Session snapshot mode is enabled" + else + fail "Session snapshot mode is invalid value is $mi_result" + fi + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + OUTPUT_DEST="$mi_output_file" lttng_snapshot_list $session_name + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_CTRL_URL}") + if [[ $mi_result = "$snapshot_ctrl_url" ]]; then + ok 0 "Ctrl urls for snapshot are the same" + else + fail "Ctrl urls should be $snapshot_ctrl_url but value is $mi_result" + fi + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_DATA_URL}") + if [[ $mi_result = "$snapshot_data_url" ]]; then + ok 0 "Data urls for snapshot are the same" + else + fail "Data urls should be $snapshot_data_url but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_live() +{ + diag "Load from template a live session" + local template_name="live.lttng" + local session_name="live" + local output_path="tcp4://127.0.0.1:5342/ [data: 5343]" + local live_timer_interval="1000000" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate name + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_NAME}") + if [[ $mi_result = "$session_name" ]]; then + ok 0 "Session names are the same" + else + fail "Session names should be $session_name but value is $mi_result" + fi + + # Validate live timer + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_LIVE_TIMER_INTERVAL}") + if [[ $mi_result = "$live_timer_interval" ]]; then + ok 0 "Session live timer intervals are the same" + else + fail "Session live timer should be $live_timer_interval but value is $mi_result" + fi + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_shm_path() +{ + # Since lttng list do not expose the shm path save the session and check + # for the shm path. + diag "Load from template a session with a shared memory path" + local template_name="shm_path.lttng" + local session_name="shm_path" + local shared_memory_path="/tmp/shm_path-20160606-161801" + + local template_path="$TEMPLATE_DIR/$template_name" + + local save_output_path=$(mktemp -d) + local save_output_file="${save_output_path}/$session_name.lttng" + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" + + lttng_save $session_name "-o ${save_output_path}" + + # Validate name + save_result=$($CURDIR/../mi/extract_xml $save_output_file "${XPATH_SAVE_SESSION_SHM_PATH}") + if [[ $save_result = "$shared_memory_path" ]]; then + ok 0 "Session shared memory paths are the same" + else + fail "Session shared memory path should be $shared_memory_path but value is $save_result" + fi + + rm $save_output_file + rmdir $save_output_path + destroy_lttng_session_ok $session_name +} + +# Default data generation +function test_name_generation() +{ + diag "Load from template a session with no name" + local template_name="name_generation.lttng" + local template_path="$TEMPLATE_DIR/$template_name" + + # On session creation success a name must have been generated. + create_lttng_session_template_ok "$template_path" + + destroy_lttng_session_ok $session_name +} + +function test_normal_output_generation() +{ + diag "Load from template a normal session with no consumer output defined" + local template_name="normal_output_generation.lttng" + local session_name="normal_output_generation" + local output_path="/home/jonathan/lttng-traces/normal_local-20160606-132532" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [ ! -z "$mi_result" ]; then + ok 0 "Output path was generated" + else + fail "Output path should not be empty $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_snapshot_output_generation() +{ + diag "Load from template a snapshot session with no local output defined" + local template_name="snapshot_output_generation.lttng" + local session_name="snapshot_output_generation" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" lttng_snapshot_list $session_name + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_CTRL_URL}") + if [ ! -z "${mi_result}" ]; then + ok 0 "Local snapshot output was generated" + else + fail "Local snapshot output is null" + fi + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_DATA_URL}") + if [ -z "${mi_result}" ]; then + ok 0 "Data url is empty as planned" + else + fail "Data url should be null but value is : $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_live_output_generation() +{ + diag "Load from template a live session with no consumer output defined" + local template_name="live_output_generation.lttng" + local session_name="live_output_generation" + local output_path="tcp4://127.0.0.1:5342/ [data: 5343]" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output path was generated and value is good: $mi_result" + else + fail "Output path default is invalid: $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +# Override +function test_overwrite_live_timer() +{ + diag "Load from template a live session - Overwrite live timer" + local template_name="live.lttng" + local session_name="live" + local output_path="tcp4://127.0.0.1:5342/ [data: 5343]" + local live_timer_interval="123456" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" "--live=${live_timer_interval}" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate live timer + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_LIVE_TIMER_INTERVAL}") + if [[ $mi_result = "$live_timer_interval" ]]; then + ok 0 "Session live timer intervals are the same: $mi_result == $live_timer_interval" + else + fail "Session live timer should be $live_timer_interval but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_overwrite_shm_path() +{ + # Since lttng list do not expose the shm path save the session and check + # for the shm path. + diag "Load from template a session with a shared memory path - Overwrite shm path" + local template_name="shm_path.lttng" + local session_name="shm_path" + local shared_memory_path="/tmp/beer-run" + + local template_path="$TEMPLATE_DIR/$template_name" + + local save_output_path=$(mktemp -d) + local save_output_file="${save_output_path}/$session_name.lttng" + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" "--shm-path=${shared_memory_path}" + + lttng_save $session_name "-o ${save_output_path}" + + # Validate name + save_result=$($CURDIR/../mi/extract_xml $save_output_file "${XPATH_SAVE_SESSION_SHM_PATH}") + if [[ $(dirname $save_result) = "$shared_memory_path" ]]; then + ok 0 "Session shared memory paths are the same" + else + fail "Session shared memory path should be $shared_memory_path but value is $save_result" + fi + + rm $save_output_file + rmdir $save_output_path + destroy_lttng_session_ok $session_name +} + +function test_overwrite_normal_net_to_local() +{ + diag "Load from template a normal session with net output - Overwrite to local output" + local template_name="normal_net.lttng" + local session_name="normal_net" + local output_path="/tmp/beer-run" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" "--set-url=file://${output_path}" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name + + create_lttng_session_template_ok "$template_path" "--output=${output_path}" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name + +} + +function test_overwrite_snapshot_local_to_net() +{ + diag "Load from template a snapshot session with local output" + local template_name="snapshot_local.lttng" + local session_name="snapshot_local" + local output_path="" + local snapshot_ctrl_url="tcp4://127.0.0.1:5342/" + local snapshot_data_url="tcp4://127.0.0.1:5343/" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" "--ctrl-url=${snapshot_ctrl_url} --data-url=${snapshot_data_url}" + + OUTPUT_DEST="$mi_output_file" lttng_snapshot_list $session_name + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_CTRL_URL}") + if [[ $mi_result = "$snapshot_ctrl_url" ]]; then + ok 0 "Ctrl urls for snapshot are the same" + else + fail "Ctrl urls should be $snapshot_ctrl_url but value is $mi_result" + fi + + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_SNAPSHOT_DATA_URL}") + if [[ $mi_result = "$snapshot_data_url" ]]; then + ok 0 "Data urls for snapshot are the same" + else + fail "Data urls should be $snapshot_data_url but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +function test_overwrite_live_net() +{ + diag "Load from template a live session - Overwrite net output" + local template_name="live.lttng" + local session_name="live" + local ctrl_url="tcp4://127.0.0.1:1000/" + local data_url="tcp4://127.0.0.1:1001/" + local output_path="tcp4://127.0.0.1:1000/ [data: 1001]" + + local template_path="$TEMPLATE_DIR/$template_name" + + local mi_output_file=$(mktemp) + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" "--ctrl-url=${ctrl_url} --data-url=${data_url}" + + OUTPUT_DEST="$mi_output_file" list_lttng_with_opts $session_name + + # Validate output + mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "${XPATH_SESSION_PATH}") + if [[ $mi_result = "$output_path" ]]; then + ok 0 "Output paths are the same" + else + fail "Output paths should be empty but value is $mi_result" + fi + + destroy_lttng_session_ok $session_name +} + +# With subchild data +function test_full_load() +{ + # Since lttng list do not expose the shm path save the session and check + # for the shm path. + diag "Load from template a complex session with henabled channel and events" + local template_name="full_load.lttng" + local session_name="full_load" + + local template_path="$TEMPLATE_DIR/$template_name" + + local save_output_path=$(mktemp -d) + local save_output_file="${save_output_path}/$session_name.lttng" + if [ $? -ne 0 ]; then + break; + fi + + create_lttng_session_template_ok "$template_path" + + lttng_save $session_name "-o ${save_output_path}" + + # Validate name + save_result=$($CURDIR/../mi/extract_xml $save_output_file "${XPATH_SAVE_SESSION_SHM_PATH}") + if diff $template_path $save_output_path ; then + ok 0 "Session complex load" + else + fail "Sessions results are different" + fi + + rm $save_output_file + rmdir $save_output_path + destroy_lttng_session_ok $session_name +} + +TESTS=( + test_normal_local + test_normal_no_output + test_normal_net + test_snapshot_local + test_snapshot_net + test_live + test_shm_path + # Default data generation + test_name_generation + test_normal_output_generation + test_snapshot_output_generation + test_live_output_generation + # Override + test_overwrite_live_timer + test_overwrite_shm_path + test_overwrite_normal_net_to_local + test_overwrite_snapshot_local_to_net + test_overwrite_live_net + # With subchild data + test_full_load +) + +start_lttng_relayd +start_lttng_sessiond + +for fct_test in ${TESTS[@]}; +do + ${fct_test} + if [ $? -ne 0 ]; then + break; + fi + # Only delete if successful +done + +stop_lttng_sessiond +stop_lttng_relayd + + diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index c59442b22c..54b83dc189 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -689,6 +689,29 @@ function create_lttng_session_fail () create_lttng_session 1 "$@" } +function create_lttng_session_template () +{ + local expected_to_fail=$1 + local template_path=$2 + local opt=$3 + + $TESTDIR/../src/bin/lttng/$LTTNG_BIN create --template-path="$template_path" $opt > $OUTPUT_DEST + ret=$? + if [[ $expected_to_fail -eq "1" ]]; then + test "$ret" -ne "0" + ok $? "Create session from template $template_path failed as expected" + else + ok $ret "Create session from template $template_path" + fi +} + +function create_lttng_session_template_ok () { + create_lttng_session_template 0 "$@" +} + +function create_lttng_session_template_fail () { + create_lttng_session_template 1 "$@" +} function enable_ust_lttng_channel () {