From 79152b99008aa732f3dc8d3ca807281d8c5c1cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 12:29:24 -0400 Subject: [PATCH 01/26] Assert that a valid clean-up pipe exists on ht_cleanup_push MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng-sessiond/utils.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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); From fa1e908409845cc1c21ee9a569e56cdae6c80a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 12:30:37 -0400 Subject: [PATCH 02/26] Express overwrite attribute as a byte in communication protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for 4 bytes to express a boolean state. Signed-off-by: Jérémie Galarneau --- include/lttng/save-internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lttng/save-internal.h b/include/lttng/save-internal.h index e2528be641..aac213e03f 100644 --- a/include/lttng/save-internal.h +++ b/include/lttng/save-internal.h @@ -33,7 +33,7 @@ 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; } LTTNG_PACKED; #endif /* LTTNG_SAVE_INTERNAL_ABI_H */ From 591069a542d812a3b81596c012adbda08501b7e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 12:36:07 -0400 Subject: [PATCH 03/26] Add name omission and output omission on save to lttng-ctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- include/lttng/save-internal.h | 4 ++++ include/lttng/save.h | 24 ++++++++++++++++++++ src/lib/lttng-ctl/save.c | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/include/lttng/save-internal.h b/include/lttng/save-internal.h index aac213e03f..c5feb4af47 100644 --- a/include/lttng/save-internal.h +++ b/include/lttng/save-internal.h @@ -34,6 +34,10 @@ struct lttng_save_session_attr { char configuration_url[PATH_MAX]; /* Overwrite the session configuration file if it exists. */ 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/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 From 87b2853a0f7b8280161742d6f52fae66264655e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 12:41:09 -0400 Subject: [PATCH 04/26] Clean-up: move mi_writer declaration with other declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng/commands/save.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/lttng/commands/save.c b/src/bin/lttng/commands/save.c index fe051966cd..5e45615463 100644 --- a/src/bin/lttng/commands/save.c +++ b/src/bin/lttng/commands/save.c @@ -31,6 +31,7 @@ static char *opt_output_path; static int opt_force; static int opt_save_all; +static struct mi_writer *writer; enum { OPT_HELP = 1, @@ -49,8 +50,6 @@ static struct poptOption save_opts[] = { {0, 0, 0, 0, 0, 0, 0} }; -static struct mi_writer *writer; - static int mi_partial_session(const char *session_name) { int ret; From f3eada70b4d54e96db49821c76ba66befe92a954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 12:41:39 -0400 Subject: [PATCH 05/26] Clean-up: harmonize popt option declarations in save.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng/commands/save.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bin/lttng/commands/save.c b/src/bin/lttng/commands/save.c index 5e45615463..958d1afc5b 100644 --- a/src/bin/lttng/commands/save.c +++ b/src/bin/lttng/commands/save.c @@ -42,10 +42,10 @@ enum { 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}, {0, 0, 0, 0, 0, 0, 0} }; From d31283b1a60409856edc2935b669bb39620d3044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 12:46:02 -0400 Subject: [PATCH 06/26] Use bool type for save command options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng/commands/save.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/lttng/commands/save.c b/src/bin/lttng/commands/save.c index 958d1afc5b..ee3e17c66e 100644 --- a/src/bin/lttng/commands/save.c +++ b/src/bin/lttng/commands/save.c @@ -29,8 +29,8 @@ #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 struct mi_writer *writer; enum { @@ -134,10 +134,10 @@ 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); @@ -154,7 +154,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; } } From cab91ee8eb29bfb012772909ae36bc63727cc1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 12:42:01 -0400 Subject: [PATCH 07/26] Add --omit-name and --omit-output options to the save command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng/commands/save.c | 46 ++++++++++++++++++++++++++ src/common/config/config-session-abi.h | 2 ++ src/common/config/session-config.c | 2 ++ src/common/mi-lttng-3.0.xsd | 2 ++ 4 files changed, 52 insertions(+) diff --git a/src/bin/lttng/commands/save.c b/src/bin/lttng/commands/save.c index ee3e17c66e..7370af01e3 100644 --- a/src/bin/lttng/commands/save.c +++ b/src/bin/lttng/commands/save.c @@ -31,6 +31,8 @@ static char *opt_output_path; 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 { @@ -38,6 +40,8 @@ enum { OPT_ALL, OPT_FORCE, OPT_LIST_OPTIONS, + OPT_OMIT_NAME, + OPT_OMIT_OUTPUT, }; static struct poptOption save_opts[] = { @@ -47,6 +51,8 @@ static struct poptOption save_opts[] = { {"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} }; @@ -108,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: @@ -142,6 +168,12 @@ int cmd_save(int argc, const char **argv) 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; @@ -179,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-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..f032e1a34c 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -128,6 +128,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"; 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. + + From 2074933a462eb83793633184dc5d75256ea43e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 14:53:37 -0400 Subject: [PATCH 08/26] Allow nameless sessions in session.xsd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/common/config/session.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index 550fea0ee2..9ea83243f9 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"> From 47895dd9fccf414ab1f62f296f7d9f0c82f64d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 14:53:56 -0400 Subject: [PATCH 09/26] Honor omit_name and omit_output options in sessiond save command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng-sessiond/save.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) 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 */ From f847e2944384d5b871b274a38d7f1ae6565d3440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jun 2016 18:14:49 -0400 Subject: [PATCH 10/26] Docs: document new save command options (--omit-name/--omit-output) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- doc/man/lttng-save.1.txt | 5 +++++ 1 file changed, 5 insertions(+) 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[] From ac451f950d448d29bd93a522804e9615e009a570 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Tue, 7 Jun 2016 22:02:05 -0400 Subject: [PATCH 11/26] refactor: split create_session in 4 functions validate_command: checks for invalid options configuration create_session_basic: responsible for session creation and configuration generate_output: responsible of outputting the info to the user Signed-off-by: Jonathan Rajotte --- src/bin/lttng/commands/create.c | 613 +++++++++++++++++++++++--------- 1 file changed, 438 insertions(+), 175 deletions(-) diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index 3379a3b27b..48ba805934 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -57,6 +57,20 @@ enum { OPT_LIVE_TIMER, }; +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[] = { @@ -160,14 +174,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; @@ -213,6 +219,215 @@ static int add_snapshot_output(const char *session_name, const char *ctrl_url, return ret; } +/* + * Validate the combinations of passed options + * + * CMD_ERROR on error + * CMD_SUCCESS on success + */ +static int validate_command_options(void) +{ + int ret = CMD_SUCCESS; + if (opt_snapshot && opt_live_timer) { + ERR("Snapshot and live modes are mutually exclusive."); + ret = CMD_ERROR; + 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; + 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 { + 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; + } + 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; + } + + 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 (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; + } + + /* 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; + } + + /* + * Set the session shared memory path + */ + if (shm_path) { + ret = lttng_set_session_shm_path(session_name, shm_path); + if (ret < 0) { + lttng_destroy_session(session_name); + goto error; + } + } +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; + } + } +error: + return ret; +} + /* * Create a tracing session. * If no name is specified, a default name is generated. @@ -222,33 +437,63 @@ static int add_snapshot_output(const char *session_name, const char *ctrl_url, static int create_session(void) { 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; + + /* 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; - char shm_path[PATH_MAX] = ""; + 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; + + /* Option validation */ + if (validate_command_options() != CMD_SUCCESS) { + 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); - /* 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"); - goto error; + /* Find the session type based on options */ + if(base_session_type == SESSION_UNKNOWN) { + if (opt_snapshot) { + base_session_type = SESSION_SNAPSHOT; + } else if (opt_live_timer) { + base_session_type = SESSION_LIVE; + } else { + base_session_type = SESSION_NORMAL; } - session_name = session_name_date; - DBG("Auto session name set to %s", session_name_date); - } else { + } + + /* + * 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; } /* @@ -257,206 +502,216 @@ static int create_session(void) * 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))) { + 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; + goto error; + } + + base_session_name = strndup(opt_session_name, NAME_MAX); + if (!base_session_name) { + PERROR("Strdup session name"); ret = CMD_ERROR; goto error; } - session_name = opt_session_name; - ret = snprintf(session_name_date, sizeof(session_name_date), - "%s-%s", session_name, datetime); + + ret = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); + if (ret < 0) { + PERROR("Asprintf session name"); + goto error; + } + DBG("Session name from command option set to %s", base_session_name); + } else if (base_session_name) { + ret = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); + if (ret < 0) { + PERROR("Asprintf session name"); + goto error; + } + } else { + /* Generate a name */ + /* TODO: use asprint */ + ret = asprintf(&base_session_name, DEFAULT_SESSION_NAME "-%s", datetime); if (ret < 0) { - PERROR("snprintf session name"); + PERROR("Asprintf generated session name"); goto error; } + session_name_date = strdup(base_session_name); + DBG("Auto session name set to %s", base_session_name); } - 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; + + /* + * 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 != NULL) { + if (opt_output_path) { + traces_path = utils_expand_path(opt_output_path); - if (traces_path == NULL) { + if (!traces_path) { ret = CMD_ERROR; goto error; } /* Create URL string from the local file system path */ - ret = asprintf(&alloc_url, "file://%s", traces_path); + ret = asprintf(&temp_url, "file://%s", traces_path); if (ret < 0) { PERROR("asprintf url path"); ret = CMD_FATAL; goto error; } - /* URL to use in the lttng_create_session() call */ - url = alloc_url; - print_str_url = traces_path; + + base_url = temp_url; } else if (opt_url) { /* Handling URL (-U opt) */ - url = opt_url; - print_str_url = url; + 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. + * 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; - goto error; - } - alloc_path = strdup(tmp_path); - if (!alloc_path) { - PERROR("allocating alloc_path"); - ret = CMD_FATAL; - 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; - goto error; - } - - url = alloc_url; - print_str_url = alloc_url + strlen("file://"); - } else { - /* No output means --no-output or --snapshot mode. */ - url = NULL; - } - - /* 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; - goto error; - } - url = alloc_url; - print_str_url = url; - } - - if (opt_snapshot && opt_live_timer) { - ERR("Snapshot and live modes are mutually exclusive."); - ret = CMD_ERROR; - goto error; - } + base_ctrl_url = strdup(opt_ctrl_url); + base_data_url = strdup(opt_data_url); + } else if (!(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; + } - if (opt_snapshot) { - /* No output by default. */ - const char *snapshot_url = NULL; + ret = asprintf(&tmp_url, + "file://%s/" DEFAULT_TRACE_DIR_NAME "/%s", + tmp_home_path, session_name_date); - 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; - } - ret = lttng_create_session_snapshot(session_name, snapshot_url); - } else if (opt_live_timer) { - const char *pathname; + if (ret < 0) { + PERROR("asprintf trace dir name"); + ret = CMD_FATAL; + goto error; + } - if (opt_relayd_path) { - pathname = opt_relayd_path; - } else { - pathname = INSTALL_BIN_PATH "/lttng-relayd"; - } - if (!opt_url && !opt_data_url && !check_relayd() && - spawn_relayd(pathname, 0) < 0) { - goto error; - } - ret = lttng_create_session_live(session_name, url, opt_live_timer); - } else { - ret = _lttng_create_session_ext(session_name, url, datetime); - } - 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); + base_url = tmp_url ; break; - default: + case SESSION_LIVE: + /* Default to a net output */ + ret = asprintf(&tmp_url, "net://127.0.0.1"); + if (ret < 0) { + PERROR("asprintf default live URL"); + ret = CMD_FATAL; + goto error; + } + base_url = tmp_url ; break; - } - goto error; - } - - if (opt_ctrl_url && opt_data_url) { - if (opt_snapshot) { - ret = add_snapshot_output(session_name, opt_ctrl_url, - opt_data_url); - } else { - /* Setting up control URI (-C or/and -D opt) */ - ret = set_consumer_url(session_name, opt_ctrl_url, opt_data_url); - } - if (ret < 0) { - /* Destroy created session because the URL are not valid. */ - lttng_destroy_session(session_name); + default: + ERR("Unknown session type"); + ret = CMD_FATAL; goto error; } } + /* + * Shared memory path handling + */ if (opt_shm_path) { - ret = snprintf(shm_path, sizeof(shm_path), - "%s/%s", opt_shm_path, session_name_date); + ret = asprintf(&base_shm_path, "%s/%s", opt_shm_path, session_name_date); if (ret < 0) { - PERROR("snprintf shm_path"); - goto error; - } - - ret = lttng_set_session_shm_path(session_name, shm_path); - if (ret < 0) { - lttng_destroy_session(session_name); + PERROR("asprintf shm_path"); goto error; } } - MSG("Session %s created.", session_name); - if (print_str_url && !opt_snapshot) { - MSG("Traces will be written in %s", print_str_url); + /* + * Live timer handling + */ + if (opt_live_timer) { + base_live_timer = opt_live_timer; + } - if (opt_live_timer) { - MSG("Live timer set to %u usec", opt_live_timer); + /* Get output type from urls */ + 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 (opt_snapshot) { - if (print_str_url) { - MSG("Default snapshot output set to: %s", print_str_url); + } 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; } - MSG("Snapshot mode set. Every channel enabled for that session will " - "be set in overwrite mode and mmap output."); + } 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 (opt_shm_path) { - MSG("Session %s set to shm_path: %s.", session_name, - shm_path); + + 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; } - /* Mi output */ - if (lttng_opt_mi) { - ret = mi_created_session(session_name); - if (ret) { - ret = CMD_ERROR; - 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 +720,20 @@ static int create_session(void) ret = CMD_SUCCESS; error: - free(alloc_url); - free(traces_path); - free(alloc_path); + + /* Session temp stuff */ + free(session_name_date); + + free(uris); 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; } @@ -710,6 +972,7 @@ int cmd_create(int argc, const char **argv) opt_session_name = (char*) poptGetArg(pc); command_ret = create_session(); + if (command_ret) { success = 0; } From d2f1302fdaa1fc048dbba3871c25c3a31fbae47c Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Tue, 7 Jun 2016 22:02:32 -0400 Subject: [PATCH 12/26] WIP add template and session_config function --- src/bin/lttng/commands/create.c | 443 ++++++++++++++++++- src/common/config/config-internal.h | 12 + src/common/config/session-config.c | 642 ++++++++++++++++++++++++++++ src/common/config/session-config.h | 62 +++ 4 files changed, 1144 insertions(+), 15 deletions(-) diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index 48ba805934..d8190c0159 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,6 +47,7 @@ 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; @@ -86,6 +88,7 @@ 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}, {0, 0, 0, 0, 0, 0, 0} }; @@ -225,7 +228,7 @@ static int add_snapshot_output(const char *session_name, const char *ctrl_url, * CMD_ERROR on error * CMD_SUCCESS on success */ -static int validate_command_options(void) +static int validate_command_options(int session_type) { int ret = CMD_SUCCESS; if (opt_snapshot && opt_live_timer) { @@ -240,6 +243,18 @@ static int validate_command_options(void) goto error; } + 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; + } + } + error: return ret; } @@ -428,6 +443,364 @@ static int generate_output(const char *session_name, 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; + 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; + ret = asprintf(url, "file://%s", raw_value); + if (ret < 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; + ret = asprintf(url, "file://%s", raw_value); + if (ret < 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; + 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 = 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")) { + asprintf(&tmp_string, "%d", live_timer); + config_document_replace_element_value(template, "/sessions/session/attributes/live_timer_interval", tmp_string); + 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 + */ + + /* 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 */ + uri_array_size = 0; + } + + /* 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; + } + config_element_free(temp_element); + + 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); + break; + default: + ret = CMD_ERROR; + goto error; + } + + temp_element = config_element_create("destination", NULL); + if (!temp_element) { + ERR("Could not create destination node configuration"); + ret = CMD_ERROR; + goto error; + } + + 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; + } + + /* + * 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 = 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; + } + + 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; + } + + + + /* 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 = 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; + } + } + + 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. @@ -438,6 +811,10 @@ static int create_session(void) { int ret; + + /* Template */ + struct config_document *template = NULL; + /* Base data */ int base_session_type = SESSION_UNKNOWN; int base_output_type = OUTPUT_UNKNOWN; @@ -462,17 +839,40 @@ static int create_session(void) struct lttng_uri *uris = NULL; ssize_t uri_array_size = 0; - /* Option validation */ - if (validate_command_options() != CMD_SUCCESS) { - 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_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; + } + /* Find the session type based on options */ if(base_session_type == SESSION_UNKNOWN) { if (opt_snapshot) { @@ -685,15 +1085,28 @@ static int create_session(void) goto error; } - 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 (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; } 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/session-config.c b/src/common/config/session-config.c index f032e1a34c..a93abd427b 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 @@ -2724,6 +2725,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) @@ -3020,3 +3062,603 @@ 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: + 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; + } +} + +LTTNG_HIDDEN +int config_document_replace_element_value(struct config_document *document, + const char *xpath, const char *value) +{ + int ret; + 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: + 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 (!old_node) { + ret = -1; + xmlFreeNode(copy); + ERR("Node replacement failed"); + goto end; + } + xmlFree(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) { + xmlFree(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 */ From c628f44d884ddc203d72377f60d097fba7a7a133 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Tue, 7 Jun 2016 21:46:42 -0400 Subject: [PATCH 13/26] WIP TEST: template testing --- configure.ac | 2 + tests/regression/Makefile.am | 3 +- tests/regression/tools/Makefile.am | 2 +- tests/regression/tools/templates/Makefile.am | 17 + .../tools/templates/sessions/Makefile.am | 18 + .../tools/templates/sessions/full_load.lttng | 54 ++ .../tools/templates/sessions/live.lttng | 21 + .../sessions/live_output_generation.lttng | 17 + .../templates/sessions/name_generation.lttng | 14 + .../templates/sessions/normal_local.lttng | 15 + .../tools/templates/sessions/normal_net.lttng | 18 + .../templates/sessions/normal_no_output.lttng | 15 + .../sessions/normal_output_generation.lttng | 14 + .../tools/templates/sessions/shm_path.lttng | 16 + .../templates/sessions/snapshot_local.lttng | 24 + .../templates/sessions/snapshot_net.lttng | 27 + .../sessions/snapshot_output_generation.lttng | 23 + tests/regression/tools/templates/test_create | 718 ++++++++++++++++++ tests/utils/utils.sh | 23 + 19 files changed, 1039 insertions(+), 2 deletions(-) create mode 100644 tests/regression/tools/templates/Makefile.am create mode 100644 tests/regression/tools/templates/sessions/Makefile.am create mode 100644 tests/regression/tools/templates/sessions/full_load.lttng create mode 100644 tests/regression/tools/templates/sessions/live.lttng create mode 100644 tests/regression/tools/templates/sessions/live_output_generation.lttng create mode 100644 tests/regression/tools/templates/sessions/name_generation.lttng create mode 100644 tests/regression/tools/templates/sessions/normal_local.lttng create mode 100644 tests/regression/tools/templates/sessions/normal_net.lttng create mode 100644 tests/regression/tools/templates/sessions/normal_no_output.lttng create mode 100644 tests/regression/tools/templates/sessions/normal_output_generation.lttng create mode 100644 tests/regression/tools/templates/sessions/shm_path.lttng create mode 100644 tests/regression/tools/templates/sessions/snapshot_local.lttng create mode 100644 tests/regression/tools/templates/sessions/snapshot_net.lttng create mode 100644 tests/regression/tools/templates/sessions/snapshot_output_generation.lttng create mode 100755 tests/regression/tools/templates/test_create 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/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 () { From 6ebcd9a271558233f0c5721211033bf13ded994e Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Tue, 7 Jun 2016 21:50:52 -0400 Subject: [PATCH 14/26] WIP sessiond.xsd --- src/common/config/session.xsd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index 9ea83243f9..42cbf0fded 100644 --- a/src/common/config/session.xsd +++ b/src/common/config/session.xsd @@ -281,7 +281,7 @@ elementFormDefault="qualified" version="3.0"> - + @@ -317,7 +317,7 @@ elementFormDefault="qualified" version="3.0"> - + From 458db88fa9077e855443f5d46dcb5afcbe73d500 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Thu, 9 Jun 2016 11:10:50 -0400 Subject: [PATCH 15/26] Fix session-config: mem leak and uninitialized ret value --- src/common/config/session-config.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index a93abd427b..3464e245ab 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -3127,6 +3127,7 @@ struct config_document *config_document_get(const char *path) } end: + fini_session_config_validation_ctx(&validation_ctx); return document; error: xmlFreeDoc(document->document); @@ -3141,13 +3142,15 @@ void config_document_free(struct config_document *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; + int ret = 0; int xpath_result_size; xmlXPathContextPtr xpath_context = NULL; @@ -3247,6 +3250,7 @@ int config_load_configuration_sessions(struct config_document *document, ret = load_session_from_document(document, session_name, &validation_ctx, override); end: + fini_session_config_validation_ctx(&validation_ctx); return ret; } @@ -3327,15 +3331,17 @@ int config_document_replace_element(struct config_document *document, 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; } - xmlFree(old_node); + xmlUnlinkNode(old_node); + xmlFreeNode(old_node); end: xmlXPathFreeContext(xpath_context); xmlXPathFreeObject(xpath_object); @@ -3656,8 +3662,8 @@ int config_document_insert_element(struct config_document *document, LTTNG_HIDDEN void config_element_free(struct config_element *element) { - if (element->element) { - xmlFree(element->element); + if (element && element->element) { + xmlFreeNode(element->element); } free(element); From 341364fd34c2874800910b10215d4490d01a6a8a Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Thu, 9 Jun 2016 11:13:09 -0400 Subject: [PATCH 16/26] Fix: use temporary data for return of asprintf --- src/bin/lttng/commands/create.c | 63 ++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index d8190c0159..5ecbc08676 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -454,6 +454,7 @@ static int parse_template (struct config_document *template, char **shm_path) { int ret = 0; + int printed_byte; char *raw_value = NULL; assert(template); @@ -490,8 +491,8 @@ static int parse_template (struct config_document *template, if (strlen(raw_value) > 0) { *output_type = OUTPUT_LOCAL; - ret = asprintf(url, "file://%s", raw_value); - if (ret < 0) { + printed_byte = asprintf(url, "file://%s", raw_value); + if (printed_byte < 0) { ret = -1; goto error; } @@ -527,8 +528,8 @@ static int parse_template (struct config_document *template, if (strlen(raw_value) > 0) { *output_type = OUTPUT_LOCAL; - ret = asprintf(url, "file://%s", raw_value); - if (ret < 0) { + printed_byte = asprintf(url, "file://%s", raw_value); + if (printed_byte < 0) { ret = -1; goto error; } @@ -574,6 +575,7 @@ static int create_session_from_template(struct config_document *template, const char *datetime) { int ret = CMD_SUCCESS; + int printed_byte; struct config_element *temp_element = NULL; struct config_element *temp_element_child = NULL; char tmp_ctrl_uri[PATH_MAX]; @@ -614,8 +616,21 @@ static int create_session_from_template(struct config_document *template, */ if (session_type == SESSION_LIVE) { if (config_document_element_exist(template, "/sessions/session/attributes/live_timer_interval")) { - asprintf(&tmp_string, "%d", live_timer); - config_document_replace_element_value(template, "/sessions/session/attributes/live_timer_interval", tmp_string); + printed_byte = asprintf(&tmp_string, "%d", live_timer); + if (printed_byte < 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 { @@ -810,6 +825,7 @@ static int create_session_from_template(struct config_document *template, static int create_session(void) { int ret; + int printed_byte; /* Template */ @@ -920,24 +936,26 @@ static int create_session(void) goto error; } - ret = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); - if (ret < 0) { + printed_byte = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); + if (printed_byte < 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) { - ret = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); - if (ret < 0) { + printed_byte = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); + if (printed_byte < 0) { PERROR("Asprintf session name"); + ret = CMD_ERROR; goto error; } } else { /* Generate a name */ - /* TODO: use asprint */ - ret = asprintf(&base_session_name, DEFAULT_SESSION_NAME "-%s", datetime); - if (ret < 0) { + printed_byte = asprintf(&base_session_name, DEFAULT_SESSION_NAME "-%s", datetime); + if (printed_byte < 0) { PERROR("Asprintf generated session name"); + ret = CMD_ERROR; goto error; } session_name_date = strdup(base_session_name); @@ -971,8 +989,8 @@ static int create_session(void) } /* Create URL string from the local file system path */ - ret = asprintf(&temp_url, "file://%s", traces_path); - if (ret < 0) { + printed_byte = asprintf(&temp_url, "file://%s", traces_path); + if (printed_byte < 0) { PERROR("asprintf url path"); ret = CMD_FATAL; goto error; @@ -1004,11 +1022,11 @@ static int create_session(void) goto error; } - ret = asprintf(&tmp_url, + printed_byte = asprintf(&tmp_url, "file://%s/" DEFAULT_TRACE_DIR_NAME "/%s", tmp_home_path, session_name_date); - if (ret < 0) { + if (printed_byte < 0) { PERROR("asprintf trace dir name"); ret = CMD_FATAL; goto error; @@ -1018,8 +1036,8 @@ static int create_session(void) break; case SESSION_LIVE: /* Default to a net output */ - ret = asprintf(&tmp_url, "net://127.0.0.1"); - if (ret < 0) { + printed_byte = asprintf(&tmp_url, "net://127.0.0.1"); + if (printed_byte < 0) { PERROR("asprintf default live URL"); ret = CMD_FATAL; goto error; @@ -1037,9 +1055,12 @@ static int create_session(void) * Shared memory path handling */ if (opt_shm_path) { - ret = asprintf(&base_shm_path, "%s/%s", opt_shm_path, session_name_date); - if (ret < 0) { + /* Overwrite shm_path so clear any previously defined one */ + free(base_shm_path); + printed_byte = asprintf(&base_shm_path, "%s/%s", opt_shm_path, session_name_date); + if (printed_byte < 0) { PERROR("asprintf shm_path"); + ret = CMD_FATAL; goto error; } } From 3b2377e020b4f60ad032e105ed5b581f2a5ec37b Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Thu, 9 Jun 2016 11:14:22 -0400 Subject: [PATCH 17/26] Fix: memory management in create.c --- src/bin/lttng/commands/create.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index 5ecbc08676..c4d58f8fab 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -714,7 +714,9 @@ static int create_session_from_template(struct config_document *template, ret = CMD_ERROR; goto error; } + config_element_free(temp_element); + temp_element = NULL; temp_element = config_element_create("data_uri", tmp_data_uri); @@ -731,6 +733,7 @@ static int create_session_from_template(struct config_document *template, goto error; } config_element_free(temp_element); + temp_element = NULL; break; default: ret = CMD_ERROR; @@ -751,6 +754,10 @@ static int create_session_from_template(struct config_document *template, goto error; } + config_element_free(temp_element_child); + temp_element_child = NULL; + + /* * validate and replace the destination node for each session type * TODO: export string as const and simply assign a base path for the @@ -782,6 +789,8 @@ static int create_session_from_template(struct config_document *template, goto error; } + config_element_free(temp_element); + temp_element = NULL; /* Shm path */ @@ -802,6 +811,9 @@ static int create_session_from_template(struct config_document *template, ret = CMD_ERROR; goto error; } + + config_element_free(temp_element); + temp_element = NULL; } ret = config_load_configuration_sessions(template, session_name, 0); @@ -1156,9 +1168,10 @@ static int create_session(void) error: /* Session temp stuff */ + config_document_free(template); free(session_name_date); - free(uris); + free(traces_path); if (ret < 0) { ERR("%s", lttng_strerror(ret)); From 97581f2e7457771fc29693dba97dc72abeed0be1 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Thu, 9 Jun 2016 11:15:59 -0400 Subject: [PATCH 18/26] Fix format and variable name create.c --- src/bin/lttng/commands/create.c | 51 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index c4d58f8fab..88e8d7e41a 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -454,7 +454,7 @@ static int parse_template (struct config_document *template, char **shm_path) { int ret = 0; - int printed_byte; + int printed_bytes; char *raw_value = NULL; assert(template); @@ -491,8 +491,8 @@ static int parse_template (struct config_document *template, if (strlen(raw_value) > 0) { *output_type = OUTPUT_LOCAL; - printed_byte = asprintf(url, "file://%s", raw_value); - if (printed_byte < 0) { + printed_bytes = asprintf(url, "file://%s", raw_value); + if (printed_bytes < 0) { ret = -1; goto error; } @@ -528,8 +528,8 @@ static int parse_template (struct config_document *template, if (strlen(raw_value) > 0) { *output_type = OUTPUT_LOCAL; - printed_byte = asprintf(url, "file://%s", raw_value); - if (printed_byte < 0) { + printed_bytes = asprintf(url, "file://%s", raw_value); + if (printed_bytes < 0) { ret = -1; goto error; } @@ -575,7 +575,7 @@ static int create_session_from_template(struct config_document *template, const char *datetime) { int ret = CMD_SUCCESS; - int printed_byte; + int printed_bytes; struct config_element *temp_element = NULL; struct config_element *temp_element_child = NULL; char tmp_ctrl_uri[PATH_MAX]; @@ -616,8 +616,8 @@ static int create_session_from_template(struct config_document *template, */ if (session_type == SESSION_LIVE) { if (config_document_element_exist(template, "/sessions/session/attributes/live_timer_interval")) { - printed_byte = asprintf(&tmp_string, "%d", live_timer); - if (printed_byte < 0) { + printed_bytes = asprintf(&tmp_string, "%d", live_timer); + if (printed_bytes < 0) { ERR("Asprintf failed for live timer"); ret = CMD_ERROR; goto error; @@ -837,7 +837,7 @@ static int create_session_from_template(struct config_document *template, static int create_session(void) { int ret; - int printed_byte; + int printed_bytes; /* Template */ @@ -948,24 +948,24 @@ static int create_session(void) goto error; } - printed_byte = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); - if (printed_byte < 0) { + 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) { - printed_byte = asprintf(&session_name_date, "%s-%s", base_session_name, datetime); - if (printed_byte < 0) { + 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_byte = asprintf(&base_session_name, DEFAULT_SESSION_NAME "-%s", datetime); - if (printed_byte < 0) { + 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; @@ -1001,8 +1001,8 @@ static int create_session(void) } /* Create URL string from the local file system path */ - printed_byte = asprintf(&temp_url, "file://%s", traces_path); - if (printed_byte < 0) { + printed_bytes = asprintf(&temp_url, "file://%s", traces_path); + if (printed_bytes < 0) { PERROR("asprintf url path"); ret = CMD_FATAL; goto error; @@ -1034,11 +1034,11 @@ static int create_session(void) goto error; } - printed_byte = asprintf(&tmp_url, + printed_bytes = asprintf(&tmp_url, "file://%s/" DEFAULT_TRACE_DIR_NAME "/%s", tmp_home_path, session_name_date); - if (printed_byte < 0) { + if (printed_bytes < 0) { PERROR("asprintf trace dir name"); ret = CMD_FATAL; goto error; @@ -1048,8 +1048,8 @@ static int create_session(void) break; case SESSION_LIVE: /* Default to a net output */ - printed_byte = asprintf(&tmp_url, "net://127.0.0.1"); - if (printed_byte < 0) { + printed_bytes = asprintf(&tmp_url, "net://127.0.0.1"); + if (printed_bytes < 0) { PERROR("asprintf default live URL"); ret = CMD_FATAL; goto error; @@ -1069,8 +1069,8 @@ static int create_session(void) if (opt_shm_path) { /* Overwrite shm_path so clear any previously defined one */ free(base_shm_path); - printed_byte = asprintf(&base_shm_path, "%s/%s", opt_shm_path, session_name_date); - if (printed_byte < 0) { + 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; @@ -1085,6 +1085,7 @@ static int create_session(void) } /* 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); @@ -1130,7 +1131,7 @@ static int create_session(void) base_shm_path, datetime); } else { - ret = create_session_basic (base_session_name, + ret = create_session_basic(base_session_name, base_session_type, base_live_timer, base_output_type, @@ -1144,7 +1145,7 @@ static int create_session(void) goto error; } - ret = generate_output (base_session_name, + ret = generate_output(base_session_name, base_session_type, base_live_timer, base_output_type, From fa409aa00c7b706782b79afdce57423fb682aee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 16:58:54 -0400 Subject: [PATCH 19/26] Implement create command --default-name option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng/commands/create.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index 88e8d7e41a..505e03bd27 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -52,11 +52,13 @@ 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; enum { OPT_HELP = 1, OPT_LIST_OPTIONS, OPT_LIVE_TIMER, + OPT_DEFAULT_NAME, }; enum { @@ -89,6 +91,7 @@ static struct poptOption long_options[] = { {"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}, {0, 0, 0, 0, 0, 0, 0} }; @@ -255,6 +258,11 @@ static int validate_command_options(int session_type) } } + 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; + } error: return ret; } @@ -955,7 +963,7 @@ static int create_session(void) goto error; } DBG("Session name from command option set to %s", base_session_name); - } else if (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"); @@ -1372,6 +1380,9 @@ 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; default: ret = CMD_UNDEFINED; goto end; From a01d3d5a8212a4b3fa526f5eb5805af96a8f13b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 16:57:27 -0400 Subject: [PATCH 20/26] Docs: document create command --default-name option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- doc/man/lttng-create.1.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/man/lttng-create.1.txt b/doc/man/lttng-create.1.txt index 14c9b0182f..b05475cade 100644 --- a/doc/man/lttng-create.1.txt +++ b/doc/man/lttng-create.1.txt @@ -224,6 +224,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[] From 4718348e81fc3e116d86b9cef790b4aa0bb9fd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 16:59:51 -0400 Subject: [PATCH 21/26] Implement --default-output option of create command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/bin/lttng/commands/create.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index 505e03bd27..a390f125c4 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -53,12 +53,14 @@ 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 { @@ -92,6 +94,7 @@ static struct poptOption long_options[] = { {"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} }; @@ -263,6 +266,13 @@ static int validate_command_options(int session_type) 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; } @@ -1026,8 +1036,9 @@ static int create_session(void) */ base_ctrl_url = strdup(opt_ctrl_url); base_data_url = strdup(opt_data_url); - } else if (!(opt_no_output || base_output_type == OUTPUT_NONE || - base_url || base_ctrl_url || base_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: @@ -1383,6 +1394,9 @@ int cmd_create(int argc, const char **argv) case OPT_DEFAULT_NAME: opt_default_name = true; break; + case OPT_DEFAULT_OUTPUT: + opt_default_output = true; + break; default: ret = CMD_UNDEFINED; goto end; From 7d3984c10bcc26f64cbf67cb696c76a94460e0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 16:59:14 -0400 Subject: [PATCH 22/26] Docs: document new --default-output option of create command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- doc/man/lttng-create.1.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/man/lttng-create.1.txt b/doc/man/lttng-create.1.txt index b05475cade..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 ~~~ From ff5b827daae1d0e1e71cfc8d6f38576f588223d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 19:27:14 -0400 Subject: [PATCH 23/26] Make the domain's buffer type optional in session.xsd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/common/config/session-config.c | 7 +++++++ src/common/config/session.xsd | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 3464e245ab..40b0b1a4cc 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -1028,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)) { @@ -1047,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 */ @@ -1066,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; diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index 42cbf0fded..cdc6942043 100644 --- a/src/common/config/session.xsd +++ b/src/common/config/session.xsd @@ -254,7 +254,7 @@ elementFormDefault="qualified" version="3.0"> - + From 8094712bf52c3fa5ffeb0c450bf9a52b30ff75b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 20:23:07 -0400 Subject: [PATCH 24/26] Make channel name attribute optional in session.xsd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/common/config/session-config.c | 8 ++++++++ src/common/config/session.xsd | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 40b0b1a4cc..fd571aa9df 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -1798,6 +1798,7 @@ int process_channel_attr_node(xmlNodePtr attr_node, xmlNodePtr *events_node) { int ret; + bool name_set = false; assert(attr_node); assert(channel); @@ -1825,6 +1826,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; @@ -2040,6 +2042,12 @@ 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; + } ret = 0; end: return ret; diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index cdc6942043..5b496c0fa8 100644 --- a/src/common/config/session.xsd +++ b/src/common/config/session.xsd @@ -179,7 +179,7 @@ elementFormDefault="qualified" version="3.0"> - + From 3a5e9d439885a836914094638f0eee6fab21edd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 20:25:48 -0400 Subject: [PATCH 25/26] Make channel output type optional in session.xsd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/common/config/session-config.c | 24 ++++++++++++++++++------ src/common/config/session.xsd | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index fd571aa9df..432db6ecbd 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -1793,12 +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); @@ -1973,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; @@ -2048,6 +2050,13 @@ int process_channel_attr_node(xmlNodePtr attr_node, 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; @@ -2302,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 }; @@ -2354,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; } @@ -2625,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; } diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index 5b496c0fa8..c28d8380d1 100644 --- a/src/common/config/session.xsd +++ b/src/common/config/session.xsd @@ -186,7 +186,7 @@ elementFormDefault="qualified" version="3.0"> - + From 22ad58f08cdd1adc9da15457a1afea5c13acd86f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 15 Jun 2016 20:26:21 -0400 Subject: [PATCH 26/26] Make channel read timer interval optional in session.xsd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- src/common/config/session.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index c28d8380d1..e21bdee534 100644 --- a/src/common/config/session.xsd +++ b/src/common/config/session.xsd @@ -185,7 +185,7 @@ elementFormDefault="qualified" version="3.0"> - +