Skip to content

Commit 2047d59

Browse files
committed
yanglint UPDATE extension parsing and validation
1 parent edccb40 commit 2047d59

File tree

7 files changed

+165
-12
lines changed

7 files changed

+165
-12
lines changed

tools/lint/cmd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ COMMAND commands[] = {
7070
},
7171
{
7272
"data", cmd_data_opt, cmd_data_dep, cmd_data_store, cmd_data_process, cmd_data_help, NULL,
73-
"Load, validate and optionally print instance data", "d:ef:F:hmo:O:R:r:nt:x:"
73+
"Load, validate and optionally print instance data", "d:ef:F:hmo:O:R:r:nt:x:k:"
7474
},
7575
{
7676
"list", cmd_list_opt, cmd_list_dep, cmd_list_exec, NULL, cmd_list_help, NULL,

tools/lint/cmd.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,15 @@ int cmd_debug_dep(struct yl_opt *yo, int posc);
381381
*/
382382
int cmd_debug_store(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv);
383383

384+
/**
385+
* @brief Store the values: mod_name, name, argument of extension.
386+
*
387+
* @param[in] extension_id String in format "<module-name>:<extension-name>:<argument>".
388+
* @param[in,out] yo Options for yanglint.
389+
* @return 0 on success.
390+
*/
391+
int parse_ext_string(const char *extension_id, struct yl_opt *yo);
392+
384393
/**
385394
* @brief Set debug logging.
386395
*

tools/lint/cmd_data.c

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* @author Michal Vasko <[email protected]>
44
* @author Radek Krejci <[email protected]>
55
* @author Adam Piecek <[email protected]>
6+
* @author Juraj Budai <[email protected]>
67
* @brief 'data' command of the libyang's yanglint tool.
78
*
89
* Copyright (c) 2015-2023 CESNET, z.s.p.o.
@@ -68,7 +69,9 @@ cmd_data_help_type(void)
6869
" element without <eventTime>).\n"
6970
" nc-notif - Similar to 'notif' but expect and check also the NETCONF\n"
7071
" envelope <notification> with element <eventTime> and its\n"
71-
" sibling as the actual notification.\n");
72+
" sibling as the actual notification.\n"
73+
" ext - Validates extension data based on loaded YANG modules.\n"
74+
" Need to be used with -k parameter.\n");
7275
}
7376

7477
static void
@@ -139,7 +142,12 @@ cmd_data_help(void)
139142
" existence is also checked in these operational data.\n"
140143
" -R FILE, --reply-rpc=FILE\n"
141144
" Provide source RPC for parsing of the 'nc-reply' TYPE. The FILE\n"
142-
" is supposed to contain the source 'nc-rpc' operation of the reply.\n");
145+
" is supposed to contain the source 'nc-rpc' operation of the reply.\n"
146+
" -k, --ext-inst <name>\n"
147+
" Name of extension instance in format:\n"
148+
" <module-name>:<extension-name>:<argument>\n"
149+
" -i --ext\n"
150+
" Validates extension data based on loaded YANG modules\n");
143151
cmd_data_help_format();
144152
cmd_data_help_in_format();
145153
printf(" -o OUTFILE, --output=OUTFILE\n"
@@ -166,6 +174,7 @@ cmd_data_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
166174
{"not-strict", no_argument, NULL, 'n'},
167175
{"type", required_argument, NULL, 't'},
168176
{"xpath", required_argument, NULL, 'x'},
177+
{"ext-inst", required_argument, NULL, 'k'},
169178
{NULL, 0, NULL, 0}
170179
};
171180

@@ -255,6 +264,12 @@ cmd_data_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
255264
return 1;
256265
}
257266
break;
267+
case 'k': /* --ext-id */
268+
if (parse_ext_string(optarg, yo)) {
269+
YLMSG_E("Invalid name of extension instance.");
270+
return 1;
271+
}
272+
break;
258273

259274
case 'h': /* --help */
260275
cmd_data_help();
@@ -346,6 +361,23 @@ cmd_data_dep(struct yl_opt *yo, int posc)
346361
}
347362
}
348363

364+
if (yo->data_ext && !yo->mod_name) {
365+
if (yo->interactive) {
366+
YLMSG_E("When using '-i' the '-k' parameter need to be also set.");
367+
} else {
368+
YLMSG_E("When using '-t ext' the '-k' parameter need to be also set.");
369+
}
370+
return 1;
371+
}
372+
if (!yo->data_ext && yo->mod_name) {
373+
if (yo->interactive) {
374+
YLMSG_E("When using '-k' parameter the '-i' need to be also set.");
375+
} else {
376+
YLMSG_E("When using '-k' parameter the '-t ext' need to be also set.");
377+
}
378+
return 1;
379+
}
380+
349381
return 0;
350382
}
351383

@@ -417,6 +449,35 @@ evaluate_xpath(const struct lyd_node *tree, const char *xpath)
417449
return 0;
418450
}
419451

452+
int
453+
parse_ext_string(const char *extension_instance, struct yl_opt *yo)
454+
{
455+
const char *start = extension_instance;
456+
char *end;
457+
458+
end = strchr(start, ':');
459+
if (!end) {
460+
return -1;
461+
}
462+
yo->mod_name = strndup(start, end - start);
463+
start = end + 1;
464+
465+
end = strchr(start, ':');
466+
if (!end) {
467+
return -1;
468+
}
469+
yo->name = strndup(start, end - start);
470+
start = end + 1;
471+
472+
if (*start == '\0') {
473+
return -1;
474+
}
475+
476+
yo->argument = strdup(start);
477+
478+
return 0;
479+
}
480+
420481
/**
421482
* @brief Checking that a parent data node exists in the datastore for the nested-notification and action.
422483
*
@@ -672,14 +733,72 @@ process_data(struct ly_ctx *ctx, enum lyd_type type, uint8_t merge, LYD_FORMAT o
672733
return ret;
673734
}
674735

736+
/**
737+
* @brief Iterate trough modules to find extension instance
738+
*
739+
* @param[in] ctx libyang context with schema.
740+
* @param[in] yo context for yanglint.
741+
*
742+
* @return 0 on success.
743+
*/
744+
static int
745+
find_extension(struct ly_ctx *ctx, struct yl_opt *yo)
746+
{
747+
struct lys_module *module;
748+
uint32_t idx = 0;
749+
LY_ARRAY_COUNT_TYPE i;
750+
751+
while ((module = ly_ctx_get_module_iter(ctx, &idx))) {
752+
if (!strcmp(module->name, yo->mod_name)) {
753+
break;
754+
}
755+
}
756+
757+
if (!module) {
758+
YLMSG_E("Cannot find the \"%s\" name in yang modules.", yo->name);
759+
return 1;
760+
}
761+
762+
/* get the extension from module that user is looking for */
763+
LY_ARRAY_FOR(module->compiled->exts, i) {
764+
if (!strcmp(module->compiled->exts[i].def->name, yo->name) &&
765+
!strcmp(module->compiled->exts[i].argument, yo->argument)) {
766+
yo->ext = &module->compiled->exts[i];
767+
return 0;
768+
}
769+
}
770+
return 1;
771+
}
772+
675773
int
676774
cmd_data_process(struct ly_ctx *ctx, struct yl_opt *yo)
677775
{
678-
/* parse, validate and print data */
679-
if (process_data(ctx, yo->data_type, yo->data_merge, yo->data_out_format, yo->out, yo->data_parse_options,
680-
yo->data_validate_options, yo->data_print_options, &yo->data_operational, &yo->reply_rpc,
681-
&yo->data_inputs, &yo->data_xpath)) {
682-
return 1;
776+
if (yo->data_ext) {
777+
struct lyd_node *tree;
778+
struct cmdline_file *input_f;
779+
780+
if (find_extension(ctx, yo)) {
781+
YLMSG_E("Extension '%s:%s:%s' not found in module.", yo->mod_name, yo->name, yo->argument);
782+
return 1;
783+
}
784+
785+
input_f = (struct cmdline_file *)yo->data_inputs.objs[0];
786+
787+
if (lyd_parse_ext_data(yo->ext, NULL, input_f->in, input_f->format, 0, 0, &tree)) {
788+
YLMSG_E("Parsing of extension data failed.")
789+
return 1;
790+
}
791+
792+
lyd_free_all(tree);
793+
yo->data_ext = 0;
794+
795+
} else {
796+
/* parse, validate and print data */
797+
if (process_data(ctx, yo->data_type, yo->data_merge, yo->data_out_format, yo->out, yo->data_parse_options,
798+
yo->data_validate_options, yo->data_print_options, &yo->data_operational, &yo->reply_rpc,
799+
&yo->data_inputs, &yo->data_xpath)) {
800+
return 1;
801+
}
683802
}
684803

685804
return 0;

tools/lint/examples/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ Preparation:
548548
> clear
549549
550550
> add example-jukebox.yang
551-
> data -i -k rc:yang-data:yang-errors ext-data.xml
551+
> data -t ext -k ietf-restconf:yang-data:yang-errors ext-data.xml
552552
```
553553

554554
Output:

tools/lint/main_ni.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ help(int shortout)
154154
" notif - Notification instance of a YANG notification.\n"
155155
" nc-notif - Similar to 'notif' but expect and check also the NETCONF\n"
156156
" envelope <notification> with element <eventTime> and its\n"
157-
" sibling as the actual notification.\n\n");
157+
" sibling as the actual notification.\n"
158+
" ext - Validates extension data based on loaded YANG modules.\n"
159+
" Need to be used with -k parameter.\n\n");
158160

159161
printf(" -d MODE, --default=MODE\n"
160162
" Print data with default values, according to the MODE\n"
@@ -215,6 +217,10 @@ help(int shortout)
215217
printf(" -J, --json-null\n"
216218
" Allow usage of JSON empty values ('null') within input data\n\n");
217219

220+
printf(" -k, --ext-inst\n"
221+
" Name of extension instance in format: <module-name>:<extension-name>:<argument>.\n"
222+
" Need to be used with -t ext parameter.\n\n");
223+
218224
printf(" -G GROUPS, --debug=GROUPS\n"
219225
#ifndef NDEBUG
220226
" Enable printing of specific debugging message group\n"
@@ -499,7 +505,7 @@ fill_context(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
499505
yo->line_length = 0;
500506

501507
opterr = 0;
502-
while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:t:d:lL:o:O:R:myY:XJx:G:", options, &opt_index)) != -1) {
508+
while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:t:d:lL:o:O:R:myY:XJx:G:k:", options, &opt_index)) != -1) {
503509
switch (opt) {
504510
case 'h': /* --help */
505511
help(0);
@@ -688,7 +694,12 @@ fill_context(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
688694
return -1;
689695
}
690696
break;
691-
697+
case 'k': /* --ext-id */
698+
if (parse_ext_string(optarg, yo)) {
699+
YLMSG_E("Invalid name of extension instance.");
700+
return -1;
701+
}
702+
break;
692703
default:
693704
YLMSG_E("Invalid option or missing argument: -%c.", optopt);
694705
return -1;

tools/lint/yl_opt.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ yl_opt_erase(struct yl_opt *yo)
8686
/* context */
8787
free(yo->searchpaths);
8888

89+
/*extension instance string*/
90+
free(yo->mod_name);
91+
free(yo->name);
92+
free(yo->argument);
93+
8994
/* --reply-rpc */
9095
ly_in_free(yo->reply_rpc.in, 1);
9196

@@ -193,6 +198,8 @@ yl_opt_update_data_type(const char *arg, struct yl_opt *yo)
193198
yo->data_type = LYD_TYPE_NOTIF_NETCONF;
194199
} else if (!strcasecmp(arg, "data")) {
195200
/* default option */
201+
} else if (!strcasecmp(arg, "ext")) {
202+
yo->data_ext = 1;
196203
} else {
197204
return 1;
198205
}

tools/lint/yl_opt.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,17 @@ struct yl_opt {
112112
*/
113113
/* various options based on --type option */
114114
enum lyd_type data_type;
115+
ly_bool data_ext;
115116
uint32_t data_parse_options;
116117
uint32_t data_validate_options;
117118
uint32_t data_print_options;
118119

120+
/* unique identifier of extension instance*/
121+
char *mod_name;
122+
char *name;
123+
char *argument;
124+
struct lysc_ext_instance *ext;
125+
119126
/* flag for --merge option */
120127
uint8_t data_merge;
121128

0 commit comments

Comments
 (0)