Files
edx-platform/xmodule/capa/safe_exec/remote_exec.py
Soban Javed 9eba9f983a refactor!: move common/lib/capa/capa to xmodule/capa
As part of dissolving our sub-projects in edx-platform, we are moving this package under the xmodule directory.
We have fixed all the occurences of import of this package and also fixed all documents related references.
This might break your platform if you have any reference of `import capa` or `from capa import` in your codebase or in any Xblock.

Ref: https://openedx.atlassian.net/browse/BOM-2582
2022-07-19 12:20:04 +05:00

108 lines
3.8 KiB
Python

"""
Helper methods related to safe exec.
"""
import json
import logging
from importlib import import_module
import requests
from codejail.safe_exec import SafeExecException
from django.conf import settings
from edx_toggles.toggles import SettingToggle
from requests.exceptions import RequestException, HTTPError
from simplejson import JSONDecodeError
from django.utils.translation import gettext as _
from .exceptions import CodejailServiceParseError, CodejailServiceStatusError, CodejailServiceUnavailable
log = logging.getLogger(__name__)
# .. toggle_name: ENABLE_CODEJAIL_REST_SERVICE
# .. toggle_implementation: SettingToggle
# .. toggle_default: False
# .. toggle_description: Set this to True if you want to run Codejail code using
# a separate VM or container and communicate with edx-platform using REST API.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2021-08-19
ENABLE_CODEJAIL_REST_SERVICE = SettingToggle(
"ENABLE_CODEJAIL_REST_SERVICE", default=False, module_name=__name__
)
def is_codejail_rest_service_enabled():
return ENABLE_CODEJAIL_REST_SERVICE.is_enabled()
def get_remote_exec(*args, **kwargs):
"""Get remote exec function based on setting and executes it."""
remote_exec_function_name = settings.CODE_JAIL_REST_SERVICE_REMOTE_EXEC
try:
mod_name, func_name = remote_exec_function_name.rsplit('.', 1)
remote_exec_module = import_module(mod_name)
remote_exec_function = getattr(remote_exec_module, func_name)
if not remote_exec_function:
remote_exec_function = send_safe_exec_request_v0
except ModuleNotFoundError:
return send_safe_exec_request_v0(*args, **kwargs)
return remote_exec_function(*args, **kwargs)
def get_codejail_rest_service_endpoint():
return f"{settings.CODE_JAIL_REST_SERVICE_HOST}/api/v0/code-exec"
def send_safe_exec_request_v0(data):
"""
Sends a request to a codejail api service forwarding required code and files.
Arguments:
data: Dict containing code and other parameters
required for jailed code execution.
It also includes extra_files (python_lib.zip) required by the codejail execution.
Returns:
Response received from codejail api service
"""
globals_dict = data["globals_dict"]
extra_files = data.pop("extra_files")
codejail_service_endpoint = get_codejail_rest_service_endpoint()
payload = json.dumps(data)
try:
response = requests.post(
codejail_service_endpoint,
files=extra_files,
data={'payload': payload},
timeout=(settings.CODE_JAIL_REST_SERVICE_CONNECT_TIMEOUT, settings.CODE_JAIL_REST_SERVICE_READ_TIMEOUT)
)
except RequestException as err:
log.error("Failed to connect to codejail api service: url=%s, params=%s",
codejail_service_endpoint, str(payload))
raise CodejailServiceUnavailable(_(
"Codejail API Service is unavailable. "
"Please try again in a few minutes."
)) from err
try:
response.raise_for_status()
except HTTPError as err:
raise CodejailServiceStatusError(_("Codejail API Service invalid response.")) from err
try:
response_json = response.json()
except JSONDecodeError as err:
log.error("Invalid JSON response received from codejail api service: Response_Content=%s", response.content)
raise CodejailServiceParseError(_("Invalid JSON response received from codejail api service.")) from err
emsg = response_json.get("emsg")
exception = None
if emsg:
exception_msg = f"{emsg}. For more information check Codejail Service logs."
exception = SafeExecException(exception_msg)
globals_dict.update(response_json.get("globals_dict"))
return emsg, exception