vmware-tanzu-labs / educates-training-platform

A platform for hosting interactive workshop environments in Kubernetes, or on top of a local container runtime.
https://docs.educates.dev
Apache License 2.0
63 stars 15 forks source link

Workshop environment in STARTING state cannot be refreshed. #434

Closed GrahamDumpleton closed 2 weeks ago

GrahamDumpleton commented 2 weeks ago

Describe the bug

If a workshop environment gets stuck in the STARTING state as determined by the training portal, it is not possible to refresh the workshop environment from the training portal admin pages.

An attempt to do so results in the application error:

[Fri Jun 14 02:28:52.200135 2024] [wsgi:error] [pid 14:tid 35] [remote 10.0.1.30:33152]   File "/opt/app-root/src/p
roject/apps/workshops/admin.py", line 137, in refresh_environments
[Fri Jun 14 02:28:52.200138 2024] [wsgi:error] [pid 14:tid 35] [remote 10.0.1.30:33152]     replace_workshop_enviro
nment(environment)
[Fri Jun 14 02:28:52.200140 2024] [wsgi:error] [pid 14:tid 35] [remote 10.0.1.30:33152]   File "/opt/app-root/src/p
roject/apps/workshops/manager/environments.py", line 563, in replace_workshop_environment
[Fri Jun 14 02:28:52.200142 2024] [wsgi:error] [pid 14:tid 35] [remote 10.0.1.30:33152]     "name": environment.wor
kshop.name,
[Fri Jun 14 02:28:52.200144 2024] [wsgi:error] [pid 14:tid 35] [remote 10.0.1.30:33152]             ^^^^^^^^^^^^^^^
^^^^^^^^^^
[Fri Jun 14 02:28:52.200146 2024] [wsgi:error] [pid 14:tid 35] [remote 10.0.1.30:33152] AttributeError: 'NoneType'
object has no attribute 'name'
10.0.1.30 - - [14/Jun/2024:02:28:52 +0000] "POST /admin/workshops/environment/ HTTP/1.1" 500 145

The reason it fails is because code to refresh the workshop environment recreates a temporary workshop description by using:

    workshop = {
        "name": environment.workshop.name,
        "capacity": environment.capacity,
        "initial": environment.initial,
        "reserved": environment.reserved,
        "expires": int(environment.expires.total_seconds()),
        "overtime": int(environment.overtime.total_seconds()),
        "deadline": int(environment.deadline.total_seconds()),
        "orphaned": int(environment.orphaned.total_seconds()),
        "overdue": int(environment.overdue.total_seconds()),
        "refresh": int(environment.refresh.total_seconds()),
        "registry": environment.registry,
        "env": environment.env,
        "labels": environment.labels,
    }

but at that point when workshop environment is stuck in starting, environment.workshop will still be None as it hasn't been linked to the database record for the workshop as yet.

What the code should do is:

    workshop = {
        "name": environment.workshop_name,
        "capacity": environment.capacity,
        "initial": environment.initial,
        "reserved": environment.reserved,
        "expires": int(environment.expires.total_seconds()),
        "overtime": int(environment.overtime.total_seconds()),
        "deadline": int(environment.deadline.total_seconds()),
        "orphaned": int(environment.orphaned.total_seconds()),
        "overdue": int(environment.overdue.total_seconds()),
        "refresh": int(environment.refresh.total_seconds()),
        "registry": environment.registry,
        "env": environment.env,
        "labels": environment.labels,
    }

That is, access the workshop_name field of environment, which has the name of the workshop as a string.

Additional information

No response