Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F71813257
build-command-templates
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
build-command-templates
View Options
#!/usr/bin/env python3
#
# build-command-template: converts new style command definitions in XML
# to the old style (bunch of dirs and node.def's) command templates
#
# Copyright (C) 2017 VyOS maintainers <maintainers@vyos.net>
#
# 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; either
# version 2.1 of the License, or (at your option) any later version.
#
# 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
import
sys
import
os
import
argparse
import
copy
import
functools
from
lxml
import
etree
as
ET
# Defaults
#validator_dir = "/usr/libexec/vyos/validators"
validator_dir
=
"$
{vyos_validators_dir}
"
default_constraint_err_msg
=
"Invalid value"
## Get arguments
parser
=
argparse
.
ArgumentParser
(
description
=
'Converts new-style XML interface definitions to old-style command templates'
)
parser
.
add_argument
(
'--debug'
,
help
=
'Enable debug information output'
,
action
=
'store_true'
)
parser
.
add_argument
(
'INPUT_FILE'
,
type
=
str
,
help
=
"XML interface definition file"
)
parser
.
add_argument
(
'SCHEMA_FILE'
,
type
=
str
,
help
=
"RelaxNG schema file"
)
parser
.
add_argument
(
'OUTPUT_DIR'
,
type
=
str
,
help
=
"Output directory"
)
args
=
parser
.
parse_args
()
input_file
=
args
.
INPUT_FILE
schema_file
=
args
.
SCHEMA_FILE
output_dir
=
args
.
OUTPUT_DIR
debug
=
args
.
debug
debug
=
True
## Load and validate the inputs
try
:
xml
=
ET
.
parse
(
input_file
)
except
Exception
as
e
:
print
(
"Failed to load interface definition file
{0}
"
.
format
(
input_file
))
print
(
e
)
sys
.
exit
(
1
)
try
:
relaxng_xml
=
ET
.
parse
(
schema_file
)
validator
=
ET
.
RelaxNG
(
relaxng_xml
)
if
not
validator
.
validate
(
xml
):
print
(
validator
.
error_log
)
print
(
"Interface definition file
{0}
does not match the schema!"
.
format
(
input_file
))
sys
.
exit
(
1
)
except
Exception
as
e
:
print
(
"Failed to load the XML schema
{0}
"
.
format
(
schema_file
))
print
(
e
)
sys
.
exit
(
1
)
if
not
os
.
access
(
output_dir
,
os
.
W_OK
):
print
(
"The output directory
{0}
is not writeable"
.
format
(
output_dir
))
sys
.
exit
(
1
)
## If we got this far, everything must be ok and we can convert the file
def
make_path
(
l
):
path
=
functools
.
reduce
(
os
.
path
.
join
,
l
)
if
debug
:
print
(
path
)
return
path
def
get_properties
(
p
):
props
=
{}
if
p
is
None
:
return
props
# Get the help string
try
:
props
[
"help"
]
=
p
.
find
(
"help"
)
.
text
except
:
pass
# Get value help strings
try
:
vhe
=
p
.
findall
(
"valueHelp"
)
vh
=
[]
for
v
in
vhe
:
vh
.
append
(
(
v
.
find
(
"format"
)
.
text
,
v
.
find
(
"description"
)
.
text
)
)
props
[
"val_help"
]
=
vh
except
:
props
[
"val_help"
]
=
[]
# Get the constraint statements
try
:
error_msg
=
default_constraint_err_msg
# Get the error message if it's there
try
:
error_msg
=
p
.
find
(
"constraintErrorMessage"
)
.
text
except
:
pass
vce
=
p
.
find
(
"constraint"
)
vc
=
[]
# The old backend doesn't support multiple validators in OR mode
# so we emulate it
regex_elements
=
vce
.
findall
(
"regex"
)
regexes
=
[]
if
regex_elements
is
not
None
:
regexes
=
list
(
map
(
lambda
e
:
e
.
text
,
regex_elements
))
validator_elements
=
vce
.
findall
(
"validator"
)
validators
=
[]
if
validator_elements
is
not
None
:
for
v
in
validator_elements
:
v_name
=
os
.
path
.
join
(
validator_dir
,
v
.
get
(
"name"
))
# XXX: lxml returns None for empty arguments
v_argument
=
None
try
:
v_argument
=
v
.
get
(
"argument"
)
except
:
pass
if
v_argument
is
None
:
v_argument
=
""
validators
.
append
(
"
{0}
{1}
"
.
format
(
v_name
,
v_argument
))
regex_args
=
" "
.
join
(
map
(
lambda
s
:
"--regex
\\\'
{0}
\\\'
"
.
format
(
s
),
regexes
))
validator_args
=
" "
.
join
(
map
(
lambda
s
:
"--exec
\\\"
{0}
\\\"
"
.
format
(
s
),
validators
))
validator_script
=
'$
{vyos_libexec_dir}
/validate-value.py'
validator_string
=
"exec
\"
{0}
{1}
{2}
--value
\\\'
$VAR(@)
\\\'\"
;
\"
{3}
\"
"
.
format
(
validator_script
,
regex_args
,
validator_args
,
error_msg
)
props
[
"constraint"
]
=
validator_string
except
Exception
as
exn
:
print
(
exn
)
pass
# Get the completion help strings
try
:
che
=
p
.
findall
(
"completionHelp"
)
ch
=
""
for
c
in
che
:
scripts
=
c
.
findall
(
"script"
)
paths
=
c
.
findall
(
"path"
)
lists
=
c
.
findall
(
"list"
)
# Current backend doesn't support multiple allowed: tags
# so we get to emulate it
comp_exprs
=
[]
for
i
in
lists
:
comp_exprs
.
append
(
"echo
\"
{0}
\"
"
.
format
(
i
.
text
))
for
i
in
paths
:
comp_exprs
.
append
(
"/bin/cli-shell-api listNodes
{0}
"
.
format
(
i
.
text
))
for
i
in
scripts
:
comp_exprs
.
append
(
"sh -c
\"
{0}
\"
"
.
format
(
i
.
text
))
comp_help
=
" && "
.
join
(
comp_exprs
)
props
[
"comp_help"
]
=
comp_help
except
:
props
[
"comp_help"
]
=
[]
# Get priority
try
:
props
[
"priority"
]
=
p
.
find
(
"priority"
)
.
text
except
:
pass
# Get "multi"
if
p
.
find
(
"multi"
)
is
not
None
:
props
[
"multi"
]
=
True
# Get "valueless"
if
p
.
find
(
"valueless"
)
is
not
None
:
props
[
"valueless"
]
=
True
return
props
def
make_node_def
(
props
):
# XXX: replace with a template processor if it grows
# out of control
node_def
=
""
if
"tag"
in
props
:
node_def
+=
"tag:
\n
"
if
"multi"
in
props
:
node_def
+=
"multi:
\n
"
if
"type"
in
props
:
# Will always be txt in practice if it's set
node_def
+=
"type:
{0}
\n
"
.
format
(
props
[
"type"
])
if
"priority"
in
props
:
node_def
+=
"priority:
{0}
\n
"
.
format
(
props
[
"priority"
])
if
"help"
in
props
:
node_def
+=
"help:
{0}
\n
"
.
format
(
props
[
"help"
])
if
"val_help"
in
props
:
for
v
in
props
[
"val_help"
]:
node_def
+=
"val_help:
{0}
;
{1}
\n
"
.
format
(
v
[
0
],
v
[
1
])
if
"comp_help"
in
props
:
node_def
+=
"allowed:
{0}
\n
"
.
format
(
props
[
"comp_help"
])
if
"constraint"
in
props
:
node_def
+=
"syntax:expression:
{0}
\n
"
.
format
(
props
[
"constraint"
])
if
"owner"
in
props
:
node_def
+=
"end: sudo sh -c
\"
{0}
\"\n
"
.
format
(
props
[
"owner"
])
if
debug
:
print
(
"The contents of the node.def file:
\n
"
,
node_def
)
return
node_def
def
process_node
(
n
,
tmpl_dir
):
# Avoid mangling the path from the outer call
my_tmpl_dir
=
copy
.
copy
(
tmpl_dir
)
props_elem
=
n
.
find
(
"properties"
)
children
=
n
.
find
(
"children"
)
name
=
n
.
get
(
"name"
)
owner
=
n
.
get
(
"owner"
)
node_type
=
n
.
tag
my_tmpl_dir
.
append
(
name
)
if
debug
:
print
(
"Name of the node:
{}
;
\n
Created directory: "
.
format
(
name
),
end
=
""
)
os
.
makedirs
(
make_path
(
my_tmpl_dir
),
exist_ok
=
True
)
props
=
get_properties
(
props_elem
)
if
owner
:
props
[
"owner"
]
=
owner
# Type should not be set for non-tag, non-leaf nodes
# For non-valueless leaf nodes, set the type to txt: to make them have some type,
# actual value validation is handled by constraints translated to syntax:expression:
if
node_type
!=
"node"
:
if
"valueless"
not
in
props
.
keys
():
props
[
"type"
]
=
"txt"
if
node_type
==
"tagNode"
:
props
[
"tag"
]
=
"True"
with
open
(
os
.
path
.
join
(
make_path
(
my_tmpl_dir
),
"node.def"
),
"w"
)
as
f
:
f
.
write
(
make_node_def
(
props
))
if
node_type
==
"node"
:
inner_nodes
=
children
.
iterfind
(
"*"
)
for
inner_n
in
inner_nodes
:
process_node
(
inner_n
,
my_tmpl_dir
)
if
node_type
==
"tagNode"
:
my_tmpl_dir
.
append
(
"node.tag"
)
if
debug
:
print
(
"Created path for the tagNode:"
,
end
=
""
)
os
.
makedirs
(
make_path
(
my_tmpl_dir
),
exist_ok
=
True
)
inner_nodes
=
children
.
iterfind
(
"*"
)
for
inner_n
in
inner_nodes
:
process_node
(
inner_n
,
my_tmpl_dir
)
else
:
# This is a leaf node
pass
root
=
xml
.
getroot
()
nodes
=
root
.
iterfind
(
"*"
)
for
n
in
nodes
:
process_node
(
n
,
[
output_dir
])
File Metadata
Details
Attached
Mime Type
text/x-script.python
Expires
Fri, Jan 30, 11:45 AM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3162474
Default Alt Text
build-command-templates (8 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment