Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

utils: T6975: Add 'vrf' and 'netns' arguments to functions in 'vyos.utils.process' #4253

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 45 additions & 7 deletions python/vyos/utils/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,23 @@
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:
Copy link
Member

@c-po c-po Dec 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does auth do? Where do we use it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auth was added in this PR to prevent showing username and password in error message

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
Expand All @@ -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)
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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='')
natali-rs1985 marked this conversation as resolved.
Show resolved Hide resolved
command = f'{wrapper} {command}'
feedback = message + '\n' if message else ''
feedback += f'failed to run command: {command}\n'
feedback += f'returned: {decoded}\n'
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Loading