Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F118306205
configsource.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
configsource.py
View Options
# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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, see <http://www.gnu.org/licenses/>.
import
os
import
re
import
subprocess
from
vyos.configtree
import
ConfigTree
from
vyos.util
import
boot_configuration_complete
class
VyOSError
(
Exception
):
"""
Raised on config access errors.
"""
pass
class
ConfigSourceError
(
Exception
):
'''
Raised on error in ConfigSource subclass init.
'''
pass
class
ConfigSource
:
def
__init__
(
self
):
self
.
_running_config
:
ConfigTree
=
None
self
.
_session_config
:
ConfigTree
=
None
def
get_configtree_tuple
(
self
):
return
self
.
_running_config
,
self
.
_session_config
def
session_changed
(
self
):
"""
Returns:
True if the config session has uncommited changes, False otherwise.
"""
raise
NotImplementedError
(
f
"function not available for {type(self)}"
)
def
in_session
(
self
):
"""
Returns:
True if called from a configuration session, False otherwise.
"""
raise
NotImplementedError
(
f
"function not available for {type(self)}"
)
def
show_config
(
self
,
path
=
[],
default
=
None
,
effective
=
False
):
"""
Args:
path (str|list): Configuration tree path, or empty
default (str): Default value to return
Returns:
str: working configuration
"""
raise
NotImplementedError
(
f
"function not available for {type(self)}"
)
def
is_multi
(
self
,
path
):
"""
Args:
path (str): Configuration tree path
Returns:
True if a node can have multiple values, False otherwise.
Note:
It also returns False if node doesn't exist.
"""
raise
NotImplementedError
(
f
"function not available for {type(self)}"
)
def
is_tag
(
self
,
path
):
"""
Args:
path (str): Configuration tree path
Returns:
True if a node is a tag node, False otherwise.
Note:
It also returns False if node doesn't exist.
"""
raise
NotImplementedError
(
f
"function not available for {type(self)}"
)
def
is_leaf
(
self
,
path
):
"""
Args:
path (str): Configuration tree path
Returns:
True if a node is a leaf node, False otherwise.
Note:
It also returns False if node doesn't exist.
"""
raise
NotImplementedError
(
f
"function not available for {type(self)}"
)
class
ConfigSourceSession
(
ConfigSource
):
def
__init__
(
self
,
session_env
=
None
):
super
()
.
__init__
()
self
.
_cli_shell_api
=
"/bin/cli-shell-api"
self
.
_level
=
[]
if
session_env
:
self
.
__session_env
=
session_env
else
:
self
.
__session_env
=
None
# Running config can be obtained either from op or conf mode, it always succeeds
# once the config system is initialized during boot;
# before initialization, set to empty string
if
boot_configuration_complete
():
try
:
running_config_text
=
self
.
_run
([
self
.
_cli_shell_api
,
'--show-active-only'
,
'--show-show-defaults'
,
'--show-ignore-edit'
,
'showConfig'
])
except
VyOSError
:
running_config_text
=
''
else
:
running_config_text
=
''
# Session config ("active") only exists in conf mode.
# In op mode, we'll just use the same running config for both active and session configs.
if
self
.
in_session
():
try
:
session_config_text
=
self
.
_run
([
self
.
_cli_shell_api
,
'--show-working-only'
,
'--show-show-defaults'
,
'--show-ignore-edit'
,
'showConfig'
])
except
VyOSError
:
session_config_text
=
''
else
:
session_config_text
=
running_config_text
if
running_config_text
:
self
.
_running_config
=
ConfigTree
(
running_config_text
)
else
:
self
.
_running_config
=
None
if
session_config_text
:
self
.
_session_config
=
ConfigTree
(
session_config_text
)
else
:
self
.
_session_config
=
None
def
_make_command
(
self
,
op
,
path
):
args
=
path
.
split
()
cmd
=
[
self
.
_cli_shell_api
,
op
]
+
args
return
cmd
def
_run
(
self
,
cmd
):
if
self
.
__session_env
:
p
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
env
=
self
.
__session_env
)
else
:
p
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
)
out
=
p
.
stdout
.
read
()
p
.
wait
()
p
.
communicate
()
if
p
.
returncode
!=
0
:
raise
VyOSError
()
else
:
return
out
.
decode
()
def
set_level
(
self
,
path
):
"""
Set the *edit level*, that is, a relative config tree path.
Once set, all operations will be relative to this path,
for example, after ``set_level("system")``, calling
``exists("name-server")`` is equivalent to calling
``exists("system name-server"`` without ``set_level``.
Args:
path (str|list): relative config path
"""
# Make sure there's always a space between default path (level)
# and path supplied as method argument
# XXX: for small strings in-place concatenation is not a problem
if
isinstance
(
path
,
str
):
if
path
:
self
.
_level
=
re
.
split
(
r'\s+'
,
path
)
else
:
self
.
_level
=
[]
elif
isinstance
(
path
,
list
):
self
.
_level
=
path
.
copy
()
else
:
raise
TypeError
(
"Level path must be either a whitespace-separated string or a list"
)
def
session_changed
(
self
):
"""
Returns:
True if the config session has uncommited changes, False otherwise.
"""
try
:
self
.
_run
(
self
.
_make_command
(
'sessionChanged'
,
''
))
return
True
except
VyOSError
:
return
False
def
in_session
(
self
):
"""
Returns:
True if called from a configuration session, False otherwise.
"""
try
:
self
.
_run
(
self
.
_make_command
(
'inSession'
,
''
))
return
True
except
VyOSError
:
return
False
def
show_config
(
self
,
path
=
[],
default
=
None
,
effective
=
False
):
"""
Args:
path (str|list): Configuration tree path, or empty
default (str): Default value to return
Returns:
str: working configuration
"""
# show_config should be independent of CLI edit level.
# Set the CLI edit environment to the top level, and
# restore original on exit.
save_env
=
self
.
__session_env
env_str
=
self
.
_run
(
self
.
_make_command
(
'getEditResetEnv'
,
''
))
env_list
=
re
.
findall
(
r'([A-Z_]+)=\'([^;\s]+)\''
,
env_str
)
root_env
=
os
.
environ
for
k
,
v
in
env_list
:
root_env
[
k
]
=
v
self
.
__session_env
=
root_env
# FIXUP: by default, showConfig will give you a diff
# if there are uncommitted changes.
# The config parser obviously cannot work with diffs,
# so we need to supress diff production using appropriate
# options for getting either running (active)
# or proposed (working) config.
if
effective
:
path
=
[
'--show-active-only'
]
+
path
else
:
path
=
[
'--show-working-only'
]
+
path
if
isinstance
(
path
,
list
):
path
=
" "
.
join
(
path
)
try
:
out
=
self
.
_run
(
self
.
_make_command
(
'showConfig'
,
path
))
self
.
__session_env
=
save_env
return
out
except
VyOSError
:
self
.
__session_env
=
save_env
return
(
default
)
def
is_multi
(
self
,
path
):
"""
Args:
path (str): Configuration tree path
Returns:
True if a node can have multiple values, False otherwise.
Note:
It also returns False if node doesn't exist.
"""
try
:
path
=
" "
.
join
(
self
.
_level
)
+
" "
+
path
self
.
_run
(
self
.
_make_command
(
'isMulti'
,
path
))
return
True
except
VyOSError
:
return
False
def
is_tag
(
self
,
path
):
"""
Args:
path (str): Configuration tree path
Returns:
True if a node is a tag node, False otherwise.
Note:
It also returns False if node doesn't exist.
"""
try
:
path
=
" "
.
join
(
self
.
_level
)
+
" "
+
path
self
.
_run
(
self
.
_make_command
(
'isTag'
,
path
))
return
True
except
VyOSError
:
return
False
def
is_leaf
(
self
,
path
):
"""
Args:
path (str): Configuration tree path
Returns:
True if a node is a leaf node, False otherwise.
Note:
It also returns False if node doesn't exist.
"""
try
:
path
=
" "
.
join
(
self
.
_level
)
+
" "
+
path
self
.
_run
(
self
.
_make_command
(
'isLeaf'
,
path
))
return
True
except
VyOSError
:
return
False
class
ConfigSourceString
(
ConfigSource
):
def
__init__
(
self
,
running_config_text
=
None
,
session_config_text
=
None
):
super
()
.
__init__
()
try
:
self
.
_running_config
=
ConfigTree
(
running_config_text
)
if
running_config_text
else
None
self
.
_session_config
=
ConfigTree
(
session_config_text
)
if
session_config_text
else
None
except
ValueError
:
raise
ConfigSourceError
(
f
"Init error in {type(self)}"
)
File Metadata
Details
Attached
Mime Type
text/x-script.python
Expires
Sat, Oct 17, 12:13 AM (1 d, 23 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4359273
Default Alt Text
configsource.py (10 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment