Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

lti changes #644

Open
wants to merge 61 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
7ec5396
lti changes
rupeshparab Mar 21, 2022
ee0dfd7
added illumidesk secret option
Abhi94N Mar 22, 2022
d07623c
Dockerfile changes
rupeshparab Mar 22, 2022
f30091c
add env variable
rupeshparab Mar 22, 2022
32db3a5
initialization of secrets manager
Abhi94N Mar 25, 2022
070ca4f
updated graderservice to add restart grader functionality
Abhi94N Mar 25, 2022
4554626
updated route to restart grader
Abhi94N Mar 25, 2022
2ad280f
added response code for route
Abhi94N Mar 25, 2022
938df6a
updated formgrader secretsmanager version to a valid one
Abhi94N Mar 25, 2022
b8944e5
graderservice restart grader timeout 10 seconds
Abhi94N Mar 26, 2022
48a6467
grader service sleep changed
Abhi94N Mar 29, 2022
7ac98ac
updated to jupyterhub ltiauthenticator
Abhi94N Mar 29, 2022
abe0606
updated jinja2 and markupsafe version
Abhi94N Mar 29, 2022
47bf382
remove markup package
Abhi94N Mar 29, 2022
089e1c3
set jinja version to 3.0.3
Abhi94N Mar 29, 2022
508d95d
removed markup safe
Abhi94N Mar 29, 2022
28d73e9
updated jinja2 and packages dependent on jinja2
Abhi94N Mar 29, 2022
96390e1
fixed jinja version
Abhi94N Mar 29, 2022
6a7c7a1
update jedi version
Abhi94N Mar 29, 2022
5bfdada
jinja 3.1.1
Abhi94N Mar 29, 2022
0216198
oauthlib 3.1.1
Abhi94N Mar 29, 2022
40f79ca
revert jinja2 to 3.0.3
Abhi94N Mar 29, 2022
980b972
updated flask to version 2.1.0
Abhi94N Mar 29, 2022
cee4464
revert flask version
Abhi94N Mar 29, 2022
e2aceec
flask version 1.1.1
Abhi94N Mar 29, 2022
db33df4
update requirements
Abhi94N Mar 29, 2022
784dd48
update requirements
Abhi94N Mar 29, 2022
5d3a3f4
update test location in makefile
Abhi94N Mar 29, 2022
8a4c151
removed asyncnbgrader test
Abhi94N Apr 1, 2022
972352e
add async_test back
Abhi94N Apr 3, 2022
aa9d7da
uses secretmanager package to fetch secret values
Abhi94N Apr 7, 2022
e1fdbb5
fix role addition issue
rupeshparab Apr 12, 2022
98d951e
update markup safe
Abhi94N Apr 12, 2022
29cb562
update jinja2 version
Abhi94N Apr 12, 2022
fb09de6
updated flask to version 2.1.0
Abhi94N Apr 12, 2022
0405223
updated jinja2
Abhi94N Apr 12, 2022
e2fb9a7
update jinja2 for async_nbgrader
Abhi94N Apr 12, 2022
92db213
updated jinja2 to semver 2.10>=jinja2<3.1.0
Abhi94N Apr 12, 2022
56d5cbb
updated nbconvert version
Abhi94N Apr 12, 2022
9e6533a
jinja2 version downgrade to 3.1.0
Abhi94N Apr 12, 2022
7ba436a
updated flask to 2.1.0
Abhi94N Apr 12, 2022
13d4ad2
revert nbconvert
Abhi94N Apr 12, 2022
c365961
update werkzeug
Abhi94N Apr 12, 2022
a4691ea
update jinja2 to the latest version
Abhi94N Apr 12, 2022
a533e56
jinja 3.1
Abhi94N Apr 12, 2022
08463b3
nbconvert version 6.4.3
Abhi94N Apr 12, 2022
9da1fb6
reverted requirements txt
Abhi94N Apr 12, 2022
7c53d06
updates ltiauthenticator to use pypi version
Abhi94N Apr 12, 2022
83856ec
matched kubernetes version
Abhi94N Apr 12, 2022
b336d3f
update requirements.txt
Abhi94N Apr 12, 2022
a39211c
fix build
rupeshparab Apr 14, 2022
819dbb7
updated graderservice.py
Abhi94N Apr 14, 2022
6f05a41
updated secrets manager with restart grader route
Abhi94N Apr 14, 2022
839a1a8
tests for secrets and rollow restart route
Abhi94N Apr 14, 2022
d29cbd7
merge secrets pr to include secretsarn
Abhi94N Apr 15, 2022
17ea6c3
add default course hook for auth0
rupeshparab Apr 20, 2022
1d8a951
Merge branch 'lti_changes' of github.com:IllumiDesk/illumidesk into l…
rupeshparab Apr 20, 2022
9fbb70e
fix requirements
rupeshparab Apr 20, 2022
1351cc1
update default course name
rupeshparab Apr 21, 2022
6c0ce3f
add user to default course
rupeshparab Apr 22, 2022
3abcc7f
deployment fixes
rupeshparab May 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,13 @@ jobs:
run: |
make -C main dev

- name: Copy SSH private key
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: echo $SSH_PRIVATE_KEY | base64 --decode > ./ssh_pvt_key

- name: Build Kubernetes JupyterHub Image
run: make -C main build-hubs-k8
run: make -C main build-hubs-k8 SSH_PRIVATE_KEY=$(cat ./ssh_pvt_key)
env:
# Full logs for CI build
BUILDKIT_PROGRESS: plain
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ build-grader-setup-service: ## build grader-setup-service docker image

build-hubs-k8: ## build jupyterhub images kubernetes setups
@docker build --build-arg BASE_IMAGE=${JUPYTERHUB_K8_BASE_IMAGE}:${JUPYTERHUB_K8_BASE_TAG} -t ${OWNER}/k8s-hub:base-${JUPYTERHUB_K8_BASE_TAG} src/illumidesk/. --no-cache
@docker build --build-arg BASE_IMAGE=${OWNER}/k8s-hub:base-${JUPYTERHUB_K8_BASE_TAG} -t ${OWNER}/k8s-hub:${JUPYTERHUB_K8_BASE_TAG} src/illumideskdummyauthenticator/. --no-cache
@docker build --build-arg BASE_IMAGE=${OWNER}/k8s-hub:base-${JUPYTERHUB_K8_BASE_TAG} --build-arg SSH_PRIVATE_KEY="$(SSH_PRIVATE_KEY)" -t ${OWNER}/k8s-hub:${JUPYTERHUB_K8_BASE_TAG} src/illumideskdummyauthenticator/. --no-cache

build-hubs: ## build jupyterhub images for standard docker-compose and docker run setups
@docker build --build-arg BASE_IMAGE=${JUPYTERHUB_DOCKER_BASE_IMAGE} -t ${OWNER}/jupyterhub:base-${JUPYTERHUB_DOCKER_BASE_TAG} src/illumidesk/. --no-cache
Expand Down
2 changes: 1 addition & 1 deletion src/async_nbgrader/dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ sphinx_rtd_theme
sphinx-autodoc-typehints
nbval
requests-mock
wheel
wheel
5 changes: 3 additions & 2 deletions src/formgradernext/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
62 changes: 50 additions & 12 deletions src/graderservice/graderservice/graderservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,9 +37,6 @@
"ILLUMIDESK_NB_EXCHANGE_MNT_ROOT", "/illumidesk-nb-exchange"
)
GRADER_PVC = os.environ.get("GRADER_PVC", "grader-setup-pvc")
GRADER_EXCHANGE_SHARED_PVC = os.environ.get(
Copy link

Choose a reason for hiding this comment

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

Has the removal of GRADER_EXCHANGE_SHARED_PVC been tested? I was still having issues after I removed the deployment. That being said I was testing it without efs access points as we didn't need that in the Oregon cluster. I can try again with a new image and approve this afterward. Let me know if you have a new image, if not I'll fetch this PR and create the image and once tested, approve this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have created a new image of this with pr-71 tag

"GRADER_SHARED_PVC", "exchange-shared-volume"
)

# user UI and GID to use within the grader container
NB_UID = os.environ.get("NB_UID", 10001)
Expand All @@ -53,13 +52,20 @@
JUPYTERHUB_API_URL = os.environ.get("JUPYTERHUB_API_URL") or "http://hub:8081/hub/api"
JUPYTERHUB_BASE_URL = os.environ.get("JUPYTERHUB_BASE_URL") or "/"

CAMPUS_ID = os.environ.get("CAMPUS_ID")

# NBGrader database settings to save in nbgrader_config.py file
nbgrader_db_host = os.environ.get("POSTGRES_NBGRADER_HOST")
nbgrader_db_password = os.environ.get("POSTGRES_NBGRADER_PASSWORD")
nbgrader_db_user = os.environ.get("POSTGRES_NBGRADER_USER")
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):
Expand Down Expand Up @@ -180,11 +186,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(nbgrader_db_name)
else:
db_url = f"postgresql://{nbgrader_db_user}:{nbgrader_db_password}@{nbgrader_db_host}:5432/{nbgrader_db_name}"
# 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
Expand Down Expand Up @@ -269,6 +280,7 @@ def _create_deployment_object(self):
client.V1EnvVar(name="NB_UID", value=str(NB_UID)),
client.V1EnvVar(name="NB_GID", value=str(NB_GID)),
client.V1EnvVar(name="NB_USER", value=self.grader_name),
client.V1EnvVar(name="CAMPUS_ID", value=str(CAMPUS_ID)),
],
volume_mounts=[
client.V1VolumeMount(
Expand All @@ -278,7 +290,7 @@ def _create_deployment_object(self):
),
client.V1VolumeMount(
mount_path="/srv/nbgrader/exchange",
name=GRADER_EXCHANGE_SHARED_PVC,
name=GRADER_PVC,
sub_path=sub_path_exchange,
),
],
Expand All @@ -298,12 +310,6 @@ def _create_deployment_object(self):
claim_name=GRADER_PVC
),
),
client.V1Volume(
name=GRADER_EXCHANGE_SHARED_PVC,
persistent_volume_claim=client.V1PersistentVolumeClaimVolumeSource(
claim_name=GRADER_EXCHANGE_SHARED_PVC
),
),
],
),
)
Expand Down Expand Up @@ -358,3 +364,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



16 changes: 16 additions & 0 deletions src/graderservice/graderservice/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/<org_name>/<course_id>/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():
Expand Down
9 changes: 5 additions & 4 deletions src/graderservice/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion src/graderservice/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
47 changes: 42 additions & 5 deletions src/illumidesk/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,37 +1,74 @@
# for kubernetes, use the --build-arg when building image or uncomment
# ARG BASE_IMAGE=jupyterhub/k8s-hub:1.1.2
ARG BASE_IMAGE=jupyterhub/jupyterhub:1.4.2
ARG BASE_IMAGE=jupyterhub/k8s-hub:1.1.2
#ARG BASE_IMAGE=jupyterhub/jupyterhub:1.4.2
ARG SSH_PRIVATE_KEY
FROM "${BASE_IMAGE}"

USER root

RUN apt-get update \
&& apt-get install -y \
curl \
git \
unzip \
wget \
openssh-server \
libmysqlclient-dev \
&& rm -rf /var/lib/apt/lists/*

USER "${NB_USER}"

ARG SSH_PRIVATE_KEY
RUN mkdir ~/.ssh/
RUN echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_ed25519
RUN chmod 600 ~/.ssh/id_ed25519
RUN ssh-keyscan github.com >> ~/.ssh/known_hosts
# Print SSH_PRIVATE_KEY (for test)
RUN echo "${SSH_PRIVATE_KEY}"

# # Authorize SSH Host
# RUN mkdir -p "/home/${NB_USER}/.ssh" && \
# chmod 0700 "/home/${NB_USER}/.ssh"

# COPY ./id_illumidesk_ssh "/home/${NB_USER}/.ssh/id_rsa"
# COPY ./id_illumidesk_ssh.pub "/home/${NB_USER}/.ssh/id_rsa.pub"

# # Add the keys and set permissions
# RUN chmod 600 "/home/${NB_USER}/.ssh/id_rsa" && \
# chmod 600 "/home/${NB_USER}/.ssh/id_rsa.pub" && \
# touch "/home/${NB_USER}/.ssh"/known_hosts

# RUN chown -R "${NB_USER}" "/home/${NB_USER}/.ssh"

# # RUN ssh-keyscan github.com >> "/home/${NB_USER}/.ssh"/known_hosts
# RUN ssh-keyscan -t ssh-ed25519 github.com >> "/home/${NB_USER}/.ssh"/known_hosts

# RUN file="/home/${NB_USER}/.ssh"/known_hosts && echo $file

# # RUN echo "Host github.com\n\tStrictHostKeyChecking no\n" >> "/home/${NB_USER}/.ssh/config"
# RUN file="/home/${NB_USER}/.ssh/config" && echo $file

WORKDIR /tmp
RUN wget https://configs.illumidesk.com/images/illumidesk-80.png \
&& cp -r /tmp/illumidesk-80.png /srv/jupyterhub/ \
&& cp -r /tmp/illumidesk-80.png /usr/local/share/jupyterhub/static/images/illumidesk-80.png \
&& chown "${NB_UID}" /srv/jupyterhub/illumidesk-80.png

USER "${NB_UID}"

ENV PATH="/home/${NB_USER}/.local/bin:${PATH}"
# ENV PYTHONUNBUFFERED 1

# ensure pip is up to date
RUN python3 -m pip install --upgrade pip

COPY requirements.txt /tmp/
RUN pip install -r /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt --use-deprecated=legacy-resolver

WORKDIR /tmp
COPY . /tmp
RUN python3 -m pip install /tmp/.

RUN rm -rf "/home/${NB_USER}/.ssh/"

WORKDIR /srv/jupyterhub/

# This config is overwitten with k8s setup
Expand Down