Skip to content

Commit

Permalink
Add autogen password logic
Browse files Browse the repository at this point in the history
  • Loading branch information
frostyfan109 committed May 30, 2024
1 parent 2b3fc55 commit d5e5075
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 0 deletions.
80 changes: 80 additions & 0 deletions appstore/api/v1/k8s_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import base64
import os
from kubernetes import client, config
from app.models.user import UserType

class KubernetesService:
def __init__(self):
self.api_instance = self.get_v1_client()

@staticmethod
def get_v1_client() -> client.CoreV1Api:
try:
config.load_incluster_config()
except:
config.load_kube_config()

return client.CoreV1Api()

def get_current_namespace(self):
# This will exist if ran in-cluster with a service account
ns_path = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
if os.path.exists(ns_path):
with open(ns_path, "r") as f:
return f.read().strip()
try:
# Doesn't work when ran in-cluster (there is no kubeconfig)
contexts, current_context = config.list_kube_config_contexts()
return current_context["context"]["namespace"]
except KeyError:
return "default"

def create_credential_secret(self, course_name: str, onyen: str, password: str, user_type: UserType):
current_namespace = self.get_current_namespace()

secret_name = self._compute_credential_secret_name(course_name, onyen)
secret_data = {
"onyen": onyen,
"password": password,
"class": course_name,
"user_type": user_type.value,
}
encoded_secret_data = {
key: base64.b64encode(value.encode()).decode() for (key, value) in secret_data.items()
}

secret = client.V1Secret(
api_version="v1",
kind="Secret",
metadata=client.V1ObjectMeta(
name=secret_name,
namespace=current_namespace
),
type="Opaque",
data=encoded_secret_data
)

self.api_instance.create_namespaced_secret(
namespace=current_namespace,
body=secret
)

def delete_credential_secret(self, course_name: str, onyen: str):
current_namespace = self.get_current_namespace()

secret_name = self._compute_credential_secret_name(course_name, onyen)
self.api_instance.delete_namespaced_secret(
namespace=current_namespace,
name=secret_name
)

def get_autogen_password(self, course_name: str, onyen: str) -> str:
current_namespace = self.get_current_namespace()
secret_name = self._compute_credential_secret_name(course_name, onyen)
secret = self.api_instance.read_namespaced_secret(secret_name, current_namespace)
return base64.decode(secret.data["password"]).decode("utf-8")

@staticmethod
def _compute_credential_secret_name(course_name: str, onyen: str) -> str:
# Secret names are subject to RFC 1123 meaning they cannot contain uppercase characters, spaces, or underscores.
return f"{course_name.lower().replace(' ', '-')}-{onyen.lower()}-credential-secret"
3 changes: 3 additions & 0 deletions appstore/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
InstanceModifySerializer,
EmptySerializer,
)
from .k8s_service import KubernetesService

from urllib.parse import urljoin

Expand Down Expand Up @@ -600,6 +601,8 @@ def create(self, request):
env = {}
if settings.GRADER_API_URL is not None:
env["GRADER_API_URL"] = settings.GRADER_API_URL
if settings.EDUHELX_CLASS_NAME is not None:
env["USER_AUTOGEN_PASSWORD"] = KubernetesService().get_autogen_password(settings.EDUHELX_CLASS_NAME, username)

host = get_host(request)
system = tycho.start(principal, app_id, resource_request.resources, host, env)
Expand Down
1 change: 1 addition & 0 deletions appstore/appstore/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
]

GRADER_API_URL = os.environ.get("GRADER_API_URL", None)
EDUHELX_CLASS_NAME = os.environ.get("EDUHELX_CLASS_NAME", None)

SESSION_IDLE_TIMEOUT = int(os.environ.get("DJANGO_SESSION_IDLE_TIMEOUT", 300))
EXPORTABLE_ENV = os.environ.get("EXPORTABLE_ENV",None)
Expand Down

0 comments on commit d5e5075

Please sign in to comment.