src: add support for direct command execution

Update live shell run mode for the new REST API interface.
Evaluate the "inline" field to diferentiate between execution of
script in /opt/opengnsys/shell/ and a cmd execution.

Remove usage of echo argument of the API REST.

Update Windows and Linux mode for direct command execution.
Set OutputEncoding environment variable to 'utf-8' in Windows to
unify the encoding of stdout for the invoked programs.

Decode stdout to utf-8-sig to remove potential BOM.

While at this, remove strange legacy ;|\n\r terminator.
master v1.3.2-25
Alejandro Sirgo Rica 2024-11-26 11:50:52 +01:00
parent a36c4daa23
commit e4be5c34eb
5 changed files with 72 additions and 62 deletions

View File

@ -7,9 +7,9 @@
# (at your option) any later version.
import os
import shlex
import psutil
import subprocess
from subprocess import CalledProcessError
from src.log import OgError
from src.ogRest import ThreadState
@ -30,20 +30,22 @@ class OgLinuxOperations:
def shellrun(self, request, ogRest):
cmd = request.getrun()
is_inline = request.get_inline()
if not is_inline:
raise OgError("Only inline mode is supported on Linux")
try:
result = subprocess.run(cmd,
shell=True,
stdin=subprocess.DEVNULL,
capture_output=True,
text=True,
check=True)
except CalledProcessError as error:
if error.stderr:
return error.stderr
if error.stdout:
return error.stdout
return "{Non zero exit code and empty output}"
return result.stdout
ogRest.proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
shell=True)
(output, error) = ogRest.proc.communicate()
except (OSError, subprocess.SubprocessError) as e:
raise OgError(f'Error when running "shell run" subprocess: {e}') from e
output = output.decode('utf-8-sig', errors='replace')
return (ogRest.proc.returncode, cmd, output)
def session(self, request, ogRest):
raise OgError('Function not implemented')

View File

@ -38,8 +38,6 @@ from src.utils.hw_inventory import get_hardware_inventory, legacy_list_hardware_
from src.log import OgError
OG_SHELL = '/bin/bash'
class OgLiveOperations:
def __init__(self, config):
self._url = config['opengnsys']['url']
@ -381,32 +379,38 @@ class OgLiveOperations:
def shellrun(self, request, ogRest):
cmd = request.getrun()
cmds = cmd.split(";|\n\r")
is_inline = request.get_inline()
self._restartBrowser(self._url_log)
shell_path = '/opt/opengnsys/shell/'
if is_inline:
cmds = cmd
else:
cmds = shlex.split(cmd)
shell_path = '/opt/opengnsys/shell/'
restricted_mode = False
try:
shell_path_files = os.listdir(shell_path)
except OSError as e:
raise OgError(f'Error accessing {shell_path}: {e}') from e
for file_name in os.listdir(shell_path):
file_path = os.path.join(shell_path, file_name)
for file_name in shell_path_files:
file_path = os.path.join(shell_path, file_name)
if cmds[0] == file_name:
cmds[0] = file_path
restricted_mode = True
break
if cmds[0] == file_name:
cmds[0] = file_path
cmd = " ".join(cmds)
break
else:
raise OgError(f'Script {cmds[0]} not found in {shell_path}')
try:
if restricted_mode:
ogRest.proc = subprocess.Popen(cmds, stdout=subprocess.PIPE)
else:
ogRest.proc = subprocess.Popen(cmds,
stdout=subprocess.PIPE,
shell=True,
executable=OG_SHELL)
ogRest.proc = subprocess.Popen(
cmds,
stdout=subprocess.PIPE,
shell=is_inline)
(output, error) = ogRest.proc.communicate()
except OSError as e:
except (OSError, subprocess.SubprocessError) as e:
raise OgError(f'Error when running "shell run" subprocess: {e}') from e
if ogRest.proc.returncode != 0:
@ -416,7 +420,8 @@ class OgLiveOperations:
self.refresh(ogRest)
return (ogRest.proc.returncode, " ".join(cmds), output.decode('utf-8'))
output = output.decode('utf-8-sig', errors='replace')
return (ogRest.proc.returncode, cmd, output)
def session(self, request, ogRest):
disk = request.getDisk()

View File

@ -97,16 +97,12 @@ class ogThread():
ogRest.send_internal_server_error(client, exc=e)
return
if request.getEcho():
json_body = jsonBody()
json_body.add_element('cmd', cmd)
json_body.add_element('out', shellout)
json_body.add_element('retcode', retcode)
response = restResponse(ogResponses.OK, json_body, seq=client.seq)
client.send(response.get())
else:
response = restResponse(ogResponses.OK, seq=client.seq)
client.send(response.get())
json_body = jsonBody()
json_body.add_element('cmd', cmd)
json_body.add_element('out', shellout)
json_body.add_element('retcode', retcode)
response = restResponse(ogResponses.OK, json_body, seq=client.seq)
client.send(response.get())
ogRest.state = ThreadState.IDLE

View File

@ -33,7 +33,7 @@ class restRequest:
self.type = None
self.profile = None
self.id = None
self.echo = None
self.inline = None
self.code = None
self.seq = None
self.backup = None
@ -72,7 +72,7 @@ class restRequest:
if "run" in json_param:
self.run = json_param["run"]
try:
self.echo = json_param["echo"]
self.inline = json_param["inline"]
except:
pass
@ -160,8 +160,8 @@ class restRequest:
def getId(self):
return self.id
def getEcho(self):
return self.echo
def get_inline(self):
return self.inline
def getCode(self):
return self.code

View File

@ -7,10 +7,10 @@
# (at your option) any later version.
import os
import locale
import ctypes
import psutil
import subprocess
from subprocess import CalledProcessError
import multiprocessing as mp
from multiprocessing import Process, freeze_support
from src.log import OgError
@ -84,20 +84,27 @@ class OgWindowsOperations:
def shellrun(self, request, ogRest):
cmd = request.getrun()
is_inline = request.get_inline()
if not is_inline:
raise OgError("Only inline mode is supported on Windows")
env = os.environ.copy()
env['OutputEncoding'] = 'utf8'
try:
result = subprocess.run(cmd,
shell=True,
stdin=subprocess.DEVNULL,
capture_output=True,
text=True,
check=True)
except CalledProcessError as error:
if error.stderr:
return error.stderr
if error.stdout:
return error.stdout
return "{Non zero exit code and empty output}"
return (result.returncode, cmd, result.stdout)
ogRest.proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
shell=True,
env=env,
)
output, error = ogRest.proc.communicate()
except (OSError, subprocess.SubprocessError) as e:
raise OgError(f'Error when running "shell run" subprocess: {e}') from e
output = output.decode('utf-8-sig', errors='replace')
return (ogRest.proc.returncode, cmd, output)
def session(self, request, ogRest):
raise OgError('Function not implemented')