summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNataliia Solomko <natalirs1985@gmail.com>2024-12-23 15:17:56 +0200
committerNataliia Solomko <natalirs1985@gmail.com>2025-01-06 13:37:48 +0200
commitce961f933f8651108f577ba53420d11bd2219fe3 (patch)
treeb123ddc3fbe54a0f44b4a1b9e47a00ea66d2af47
parent3168305a0474573ad0f36fee399baa423cbce5e4 (diff)
downloadvyos-1x-ce961f933f8651108f577ba53420d11bd2219fe3.tar.gz
vyos-1x-ce961f933f8651108f577ba53420d11bd2219fe3.zip
utils: T6975: Add 'vrf' and 'netns' arguments to functions in 'vyos.utils.process'
-rw-r--r--python/vyos/utils/process.py52
1 files changed, 45 insertions, 7 deletions
diff --git a/python/vyos/utils/process.py b/python/vyos/utils/process.py
index d8aabb822..054088325 100644
--- a/python/vyos/utils/process.py
+++ b/python/vyos/utils/process.py
@@ -20,10 +20,23 @@ from subprocess import PIPE
from subprocess import STDOUT
from subprocess import DEVNULL
+
+def get_wrapper(vrf, netns, auth):
+ wrapper = ''
+ if vrf:
+ wrapper = f'ip vrf exec {vrf} '
+ elif netns:
+ wrapper = f'ip netns exec {netns} '
+ if auth:
+ wrapper = f'{auth} {wrapper}'
+ return wrapper
+
+
def popen(command, flag='', shell=None, input=None, timeout=None, env=None,
- stdout=PIPE, stderr=PIPE, decode='utf-8'):
+ stdout=PIPE, stderr=PIPE, decode='utf-8', auth='', vrf=None,
+ netns=None):
"""
- popen is a wrapper helper aound subprocess.Popen
+ popen is a wrapper helper around subprocess.Popen
with it default setting it will return a tuple (out, err)
out: the output of the program run
err: the error code returned by the program
@@ -45,6 +58,8 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None,
- DEVNULL, discard the output
decode: specify the expected text encoding (utf-8, ascii, ...)
the default is explicitely utf-8 which is python's own default
+ vrf: run command in a VRF context
+ netns: run command in the named network namespace
usage:
get both stdout and stderr: popen('command', stdout=PIPE, stderr=STDOUT)
@@ -60,6 +75,16 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None,
if not debug.enabled(flag):
flag = 'command'
+ # Must be run as root to execute command in VRF or network namespace
+ if vrf or netns:
+ if os.getuid() != 0:
+ raise OSError(
+ 'Permission denied: cannot execute commands in VRF and netns contexts as an unprivileged user'
+ )
+
+ wrapper = get_wrapper(vrf, netns, auth)
+ command = f'{wrapper} {command}'
+
cmd_msg = f"cmd '{command}'"
debug.message(cmd_msg, flag)
@@ -111,7 +136,7 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None,
def run(command, flag='', shell=None, input=None, timeout=None, env=None,
- stdout=DEVNULL, stderr=PIPE, decode='utf-8'):
+ stdout=DEVNULL, stderr=PIPE, decode='utf-8', vrf=None, netns=None):
"""
A wrapper around popen, which discard the stdout and
will return the error code of a command
@@ -122,13 +147,15 @@ def run(command, flag='', shell=None, input=None, timeout=None, env=None,
input=input, timeout=timeout,
env=env, shell=shell,
decode=decode,
+ vrf=vrf,
+ netns=netns,
)
return code
def cmd(command, flag='', shell=None, input=None, timeout=None, env=None,
stdout=PIPE, stderr=PIPE, decode='utf-8', raising=None, message='',
- expect=[0], auth=''):
+ expect=[0], auth='', vrf=None, netns=None):
"""
A wrapper around popen, which returns the stdout and
will raise the error code of a command
@@ -139,13 +166,18 @@ def cmd(command, flag='', shell=None, input=None, timeout=None, env=None,
expect: a list of error codes to consider as normal
"""
decoded, code = popen(
- f'{auth} {command}'.strip(), flag,
+ command, flag,
stdout=stdout, stderr=stderr,
input=input, timeout=timeout,
env=env, shell=shell,
decode=decode,
+ auth=auth,
+ vrf=vrf,
+ netns=netns,
)
if code not in expect:
+ wrapper = get_wrapper(vrf, netns, auth='')
+ command = f'{wrapper} {command}'
feedback = message + '\n' if message else ''
feedback += f'failed to run command: {command}\n'
feedback += f'returned: {decoded}\n'
@@ -159,7 +191,7 @@ def cmd(command, flag='', shell=None, input=None, timeout=None, env=None,
def rc_cmd(command, flag='', shell=None, input=None, timeout=None, env=None,
- stdout=PIPE, stderr=STDOUT, decode='utf-8'):
+ stdout=PIPE, stderr=STDOUT, decode='utf-8', vrf=None, netns=None):
"""
A wrapper around popen, which returns the return code
of a command and stdout
@@ -175,11 +207,14 @@ def rc_cmd(command, flag='', shell=None, input=None, timeout=None, env=None,
input=input, timeout=timeout,
env=env, shell=shell,
decode=decode,
+ vrf=vrf,
+ netns=netns,
)
return code, out
+
def call(command, flag='', shell=None, input=None, timeout=None, env=None,
- stdout=None, stderr=None, decode='utf-8'):
+ stdout=None, stderr=None, decode='utf-8', vrf=None, netns=None):
"""
A wrapper around popen, which print the stdout and
will return the error code of a command
@@ -190,11 +225,14 @@ def call(command, flag='', shell=None, input=None, timeout=None, env=None,
input=input, timeout=timeout,
env=env, shell=shell,
decode=decode,
+ vrf=vrf,
+ netns=netns,
)
if out:
print(out)
return code
+
def process_running(pid_file):
""" Checks if a process with PID in pid_file is running """
from psutil import pid_exists