diff --git a/src/async_nbgrader/dev-requirements.txt b/src/async_nbgrader/dev-requirements.txt index 220e1565..2bfe8cb7 100644 --- a/src/async_nbgrader/dev-requirements.txt +++ b/src/async_nbgrader/dev-requirements.txt @@ -15,4 +15,4 @@ sphinx_rtd_theme sphinx-autodoc-typehints nbval requests-mock -wheel +wheel \ No newline at end of file diff --git a/src/formgradernext/requirements.txt b/src/formgradernext/requirements.txt index 5fce9ae0..143fe0b3 100644 --- a/src/formgradernext/requirements.txt +++ b/src/formgradernext/requirements.txt @@ -58,7 +58,7 @@ ipywidgets==7.6.5 # via jupyter jedi==0.18.0 # via ipython -jinja2==3.0.2 +jinja2==3.0.3 # via # nbconvert # notebook @@ -212,6 +212,7 @@ webencodings==0.5.1 # via bleach widgetsnbextension==3.5.2 # via ipywidgets +secretsmanager-illumidesk==0.0.3 # The following packages are considered to be unsafe in a requirements file: -# setuptools +# setuptools \ No newline at end of file diff --git a/src/graderservice/graderservice/graderservice.py b/src/graderservice/graderservice/graderservice.py index 5981cabf..602f6776 100644 --- a/src/graderservice/graderservice/graderservice.py +++ b/src/graderservice/graderservice/graderservice.py @@ -6,10 +6,12 @@ from os import path from pathlib import Path from secrets import token_hex - from kubernetes import client from kubernetes import config from kubernetes.config import ConfigException +from kubernetes.client.rest import ApiException +from secretsmanager.secretsmanager import SecretsManager +import time from .templates import NBGRADER_COURSE_CONFIG_TEMPLATE from .templates import NBGRADER_HOME_CONFIG_TEMPLATE @@ -60,6 +62,11 @@ nbgrader_db_port = os.environ.get("POSTGRES_NBGRADER_PORT") nbgrader_db_name = os.environ.get("POSTGRES_NBGRADER_DB_NAME") +aws_secret_arn = os.environ.get('AWS_SECRET_ARN') +region = os.environ.get('AWS_REGION') or 'us-west-2' +secretmanager = SecretsManager(aws_secret_arn, region_name=region) +if secretmanager.host == "": + secretmanager.host = nbgrader_db_host class GraderServiceLauncher: def __init__(self, org_name: str, course_id: str): @@ -180,11 +187,16 @@ def _create_nbgrader_files(self): logger.info( f"Writing the nbgrader_config.py file at jupyter directory (within the grader home): {grader_nbconfig_path}" ) + db_url = '' + if aws_secret_arn != "" or aws_secret_arn is not None: + db_url = secretmanager.rds_connection(f'{self.org_name}_{self.course_id}') + else: + db_url = f"postgresql://{nbgrader_db_user}:{nbgrader_db_password}@{nbgrader_db_host}:5432/{self.org_name}_{self.course_id}" # write the file grader_home_nbconfig_content = NBGRADER_HOME_CONFIG_TEMPLATE.format( grader_name=self.grader_name, course_id=self.course_id, - db_url=f"postgresql://{nbgrader_db_user}:{nbgrader_db_password}@{nbgrader_db_host}:5432/{self.org_name}_{self.course_id}", + db_url=db_url, ) grader_nbconfig_path.write_text(grader_home_nbconfig_content) # Write the nbgrader_config.py file at grader home directory @@ -358,3 +370,35 @@ def update_jhub_deployment(self): name="hub", namespace=NAMESPACE, body=deployment ) logger.info(f"Jhub patch response:{api_response}") + + # Restarts deployment in namespace + def restart_deployment(self, deployment, namespace): + now = datetime.utcnow() + now = str(now.isoformat("T") + "Z") + body = { + 'spec': { + 'template': { + 'metadata': { + 'annotations': { + 'kubectl.kubernetes.io/restartedAt': now + } + } + } + } + } + deployment_status = f'{deployment} failed to deploy to organization: {namespace}', 404 + try: + restart_deployment = self.apps_v1.patch_namespaced_deployment(deployment, namespace, body, pretty='true') + except ApiException as e: + logger.error("Exception when calling AppsV1Api->read_namespaced_deployment_status: %s\n" % e) + except Exception as e: + logger.error(deployment_status, e) + else: + while restart_deployment.status.updated_replicas != restart_deployment.spec.replicas: + logger.info(f'Waiting for status to update for grader{deployment} to organization {namespace}') + time.sleep(5) + deployment_status = f'{deployment} successfully deployed to organization {namespace}', 200 + return deployment_status + + + diff --git a/src/graderservice/graderservice/routes.py b/src/graderservice/graderservice/routes.py index 93416c4d..4a9fc3cc 100644 --- a/src/graderservice/graderservice/routes.py +++ b/src/graderservice/graderservice/routes.py @@ -203,7 +203,23 @@ def assignment_dir_creation(org_name: str, course_id: str, assignment_name: str) success=True, message=f"Created new assignment directory: {assignment_dir}", ) +@grader_setup_bp.route( + "/services///restart", methods=["POST"] +) +def restart_grader(org_name: str, course_id: str): + launcher = GraderServiceLauncher(org_name=org_name, course_id=course_id) + try: + restart_deployment_status = launcher.restart_deployment(f'grader-{course_id}',org_name) + except Exception as e: + logger.error(f"Error restarting grader: {e}") + logger.info(restart_deployment_status) + success = True if restart_deployment_status[1]==200 else False + return jsonify( + success=success, + message=f"{restart_deployment_status[0]}" + ), restart_deployment_status[1] + @grader_setup_bp.route("/healthcheck") def healthcheck(): diff --git a/src/graderservice/requirements.txt b/src/graderservice/requirements.txt index aea7f9e2..c22fcb1f 100644 --- a/src/graderservice/requirements.txt +++ b/src/graderservice/requirements.txt @@ -30,9 +30,9 @@ idna==2.10 # via requests itsdangerous==2.0.0 # via flask -jinja2==3.0.0 +jinja2==3.0.3 # via flask -kubernetes==12.0.1 +kubernetes==17.17.0 # via graderservice (src/graderservice/setup.py) markupsafe==2.0.0 # via jinja2 @@ -70,8 +70,9 @@ urllib3==1.26.5 # requests websocket-client==0.59.0 # via kubernetes -werkzeug==2.0.0 +werkzeug==2.0.2 # via flask +secretsmanager-illumidesk==0.0.3 # The following packages are considered to be unsafe in a requirements file: -# setuptools +# setuptools \ No newline at end of file diff --git a/src/graderservice/setup.py b/src/graderservice/setup.py index 61c30550..174156cf 100644 --- a/src/graderservice/setup.py +++ b/src/graderservice/setup.py @@ -37,7 +37,7 @@ "flask==1.1.2", "flask-sqlalchemy==2.5.1", "gunicorn==20.0.4", - "kubernetes==12.0.1", + "kubernetes==17.17.0", ], # noqa: E231 package_data={ "": ["*.html"], diff --git a/src/illumidesk/illumidesk/apis/nbgrader_service.py b/src/illumidesk/illumidesk/apis/nbgrader_service.py index d9e1cae7..cbcf3843 100644 --- a/src/illumidesk/illumidesk/apis/nbgrader_service.py +++ b/src/illumidesk/illumidesk/apis/nbgrader_service.py @@ -9,6 +9,8 @@ from sqlalchemy_utils import database_exists from illumidesk.authenticators.utils import LTIUtils +from secretsmanager.secretsmanager import SecretsManager + logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -25,6 +27,12 @@ if not org_name: raise EnvironmentError("ORGANIZATION_NAME env-var is not set") +aws_secret_arn = os.environ.get('AWS_SECRET_ARN') +region = os.environ.get('AWS_REGION') or 'us-west-2' +secretmanager = SecretsManager(aws_secret_arn, region_name=region) +if secretmanager.host == "": + secretmanager.host = nbgrader_db_host + def nbgrader_format_db_url(course_id: str) -> str: """ @@ -35,6 +43,10 @@ def nbgrader_format_db_url(course_id: str) -> str: """ course_id = LTIUtils().normalize_string(course_id) database_name = f"{org_name}_{course_id}" + if aws_secret_arn != "" or aws_secret_arn is not None: + logger.info(f'secrets manager db secret : {secretmanager.db_secret}') + logger.info(f'secrets manager rds connection : {secretmanager.rds_connection(database_name)}') + return secretmanager.rds_connection(database_name) return f"postgresql://{nbgrader_db_user}:{nbgrader_db_password}@{nbgrader_db_host}:{nbgrader_db_port}/{database_name}" @@ -137,4 +149,4 @@ def register_assignment(self, assignment_name: str, **kwargs: dict) -> Assignmen logger.debug("Added assignment %s to gradebook" % assignment_name) except InvalidEntry as e: logger.debug("Error ocurred by adding assignment to gradebook: %s" % e) - return assignment + return assignment \ No newline at end of file diff --git a/src/illumidesk/illumidesk/lti13/handlers.py b/src/illumidesk/illumidesk/lti13/handlers.py index 1fb292fc..63380529 100644 --- a/src/illumidesk/illumidesk/lti13/handlers.py +++ b/src/illumidesk/illumidesk/lti13/handlers.py @@ -199,4 +199,4 @@ async def get(self): files=link_item_files, action_url=auth_state["launch_return_url"], ) - self.finish(html) + self.finish(html) \ No newline at end of file diff --git a/src/illumidesk/requirements.txt b/src/illumidesk/requirements.txt index 3d222b0b..c3aac6e1 100644 --- a/src/illumidesk/requirements.txt +++ b/src/illumidesk/requirements.txt @@ -28,7 +28,7 @@ ipython-genutils==0.2.0 # via nbformat, notebook, qtconsole, traitlets ipython==7.23.1 # via ipykernel, ipywidgets, jupyter-console ipywidgets==7.6.3 # via jupyter jedi==0.18.0 # via ipython -jinja2==3.0.0 # via jupyterhub, jupyterhub-kubespawner, nbconvert, notebook +jinja2==3.0.3 # via jupyterhub, jupyterhub-kubespawner, nbconvert, notebook josepy==1.4.0 # via illumidesk (setup.py) jsonschema==3.2.0 # via jupyter-telemetry, nbformat, nbgrader jupyter-client==6.1.12 # via ipykernel, jupyter-console, nbgrader, notebook, qtconsole @@ -37,7 +37,7 @@ jupyter-core==4.7.1 # via jupyter-client, nbconvert, nbformat, nbgrader, n jupyter-telemetry==0.1.0 # via jupyterhub jupyter==1.0.0 # via nbgrader jupyterhub-kubespawner==0.14.1 # via illumidesk (setup.py) -git+git://github.com/jupyterhub/ltiauthenticator.git@71d86a9da2562df4bdcc9f374af834a172ac52d5 # via illumidesk (setup.py) +jupyterhub-ltiauthenticator==1.3.0 # via illumidesk (setup.py) jupyterhub==1.4.1 # via jupyterhub-kubespawner, jupyterhub-ltiauthenticator, oauthenticator jupyterlab-widgets==1.0.0 # via ipywidgets jwcrypto==0.8 # via illumidesk (setup.py) @@ -102,6 +102,7 @@ wcwidth==0.2.5 # via prompt-toolkit webencodings==0.5.1 # via bleach websocket-client==0.59.0 # via kubernetes widgetsnbextension==3.5.1 # via ipywidgets +secretsmanager-illumidesk==0.0.3 # The following packages are considered to be unsafe in a requirements file: -# setuptools +# setuptools \ No newline at end of file diff --git a/src/illumidesk/setup.py b/src/illumidesk/setup.py index b0cd6319..81731e34 100644 --- a/src/illumidesk/setup.py +++ b/src/illumidesk/setup.py @@ -38,8 +38,9 @@ install_requires=[ "josepy==1.4.0", "jupyterhub-kubespawner==0.14.1", - "jupyterhub-ltiauthenticator@git+git://github.com/jupyterhub/ltiauthenticator.git@71d86a9da2562df4bdcc9f374af834a172ac52d5", + "jupyterhub-ltiauthenticator==1.3.0", "jwcrypto==0.8", + "secretsmanager-illumidesk==0.0.3", "nbgrader==0.6.2", "oauthlib==3.1", "oauthenticator>=0.13.0",