Skip to content

Commit

Permalink
Merge pull request #311 from helxplatform/develop
Browse files Browse the repository at this point in the history
Develop merge
  • Loading branch information
pj-linebaugh authored Oct 26, 2023
2 parents af01d75 + d966855 commit 6612c0d
Show file tree
Hide file tree
Showing 25 changed files with 223 additions and 32 deletions.
1 change: 1 addition & 0 deletions appstore/api/v1/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Instance:
ephemeralStorage: str
host: InitVar[str]
username: InitVar[str]
is_ready: bool
url: str = field(init=False)
status: str = field(init=False)
protocol: InitVar[str] = os.environ.get("ACCOUNT_DEFAULT_HTTP_PROTOCOL", "http")
Expand Down
216 changes: 191 additions & 25 deletions appstore/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,34 @@ def get_social_tokens(username):

class AppViewSet(viewsets.GenericViewSet):
"""
Tycho App information.
AppViewSet - ViewSet for managing Tycho apps.
This ViewSet provides endpoints to list all available apps and retrieve details
about a specific app based on its app_id.
Endpoints:
- List All Apps:
- URL: /apps/
- HTTP Method: GET
- Method: list
- Description: Lists all available apps, parses resource specifications,
and returns them in a structured format. GPU reservations
and limits are specially handled. Any errors during the
parsing of an app's data are logged and the app is skipped.
- Retrieve App Details:
- URL: /apps/{app_id}/
- HTTP Method: GET
- Method: retrieve
- Description: Provides detailed information about a specific app based on its
app_id. Similar to the list method, it parses resource specifications
and returns them in a structured format.
Note:
- The app_id is used as a lookup field.
- The ViewSet interacts with an external system named 'tycho' to fetch app definitions
and other relevant data. There are also utility functions like 'parse_spec_resources'
and 'search_for_gpu_reservation' that are presumably defined elsewhere in the codebase.
"""

lookup_field = "app_id"
Expand Down Expand Up @@ -277,7 +304,41 @@ def retrieve(self, request, app_id=None):

class InstanceViewSet(viewsets.GenericViewSet):
"""
Active user instances.
InstanceViewSet - ViewSet for managing instances.
Endpoints:
- List Endpoint:
- URL: /instances/
- HTTP Method: GET
- Method: list
- Create Endpoint:
- URL: /instances/
- HTTP Method: POST
- Method: create
- Retrieve (Detail) Endpoint:
- URL: /instances/{sid}/
- HTTP Method: GET
- Method: retrieve
- Note: {sid} is a placeholder for the instance's ID.
- Destroy (Delete) Endpoint:
- URL: /instances/{sid}/
- HTTP Method: DELETE
- Method: destroy
- Partial Update Endpoint:
- URL: /instances/{sid}/
- HTTP Method: PATCH
- Method: partial_update
- Check Instance Readiness:
- URL: /instances/{sid}/is_ready/
- HTTP Method: GET
- Method: is_ready
- Description: Checks if a specific user instance, identified by its 'sid', is ready.
"""

lookup_field = "sid"
Expand Down Expand Up @@ -307,6 +368,31 @@ def get_queryset(self):
status = tycho.status({"username": self.request.user.username})
return status.services

def get_instance(self, sid, username, host):
active = self.get_queryset()

for instance in active:
if instance.identifier == sid:
app = tycho.apps.get(instance.app_id.rpartition("-")[0], {})
app_name = instance.app_id.replace(f"-{instance.identifier}", "")
return Instance(
app.get("name"),
app.get("docs"),
app_name,
instance.identifier,
instance.app_id,
instance.creation_time,
instance.total_util["cpu"],
instance.total_util["gpu"],
instance.total_util["memory"],
instance.total_util["ephemeralStorage"],
app.get("app_id"),
host,
username,
instance.is_ready
)
return None

def list(self, request):
"""
Provide all active instances.
Expand Down Expand Up @@ -342,6 +428,7 @@ def list(self, request):
instance.total_util["ephemeralStorage"],
host,
username,
instance.is_ready
)
instances.append(asdict(inst))
else:
Expand Down Expand Up @@ -414,35 +501,36 @@ def retrieve(self, request, sid=None):
"""
Provide active instance details.
"""
active = self.get_queryset()
principal = self.get_principal(request.user)
username = principal.username
host = get_host(request)
instance = None

for instance in active:
if instance.identifier == sid:
app = tycho.apps.get(instance.app_id.rpartition("-")[0], {})
inst = Instance(
app.get("name"),
app.get("docs"),
instance.identifier,
instance.app_id,
instance.creation_time,
instance.total_util["cpu"],
instance.total_util["gpu"],
instance.total_util["memory"],
instance.total_util["ephemeralStorage"],
app.get("app_id"),
host,
username,
)

serializer = self.get_serializer(data=asdict(inst))
if sid != None:
instance = self.get_instance(sid,username,host)
if instance != None:
serializer = self.get_serializer(data=asdict(instance))
serializer.is_valid(raise_exception=True)
return Response(serializer.validated_data)

logger.error(f"\n{sid} not found\n")
return Response(status=drf_status.HTTP_404_NOT_FOUND)

@action(detail=True, methods=['get'])
def is_ready(self, request, sid=None):
principal = self.get_principal(request.user)
username = principal.username
host = get_host(request)
instance = None

if sid != None:
instance = self.get_instance(sid,username,host)
if instance != None:
return Response({'is_ready': instance.is_ready})

logger.error(f"\n{sid} not found\n")
return Response(status=drf_status.HTTP_404_NOT_FOUND)


def destroy(self, request, sid=None):
"""
Expand Down Expand Up @@ -483,7 +571,32 @@ def partial_update(self, request, sid=None):

class UsersViewSet(viewsets.GenericViewSet):
"""
User information.
UsersViewSet - ViewSet for managing user information.
This ViewSet provides endpoints to retrieve details of the currently logged-in user
and to handle user logout.
Endpoints:
- List User Details:
- URL: /users/
- HTTP Method: GET
- Method: list
- Description: Provides details of the currently logged-in user, including their
username and access token. This endpoint is designed to support
scenarios where a reverse proxy (like nginx) performs authentication
before proxying a request.
- Logout:
- URL: /users/logout/
- HTTP Method: POST
- Method: logout
- Description: Logs out the current user and returns a success message.
Note:
- The ViewSet uses a private method '_get_access_token' to retrieve the user's
access token from the session.
- 'EmptySerializer' is used for the 'logout' action, likely to simply validate the
request without any specific data.
"""

def get_serializer_class(self):
Expand Down Expand Up @@ -520,7 +633,38 @@ def logout(self, request):

class LoginProviderViewSet(viewsets.GenericViewSet):
"""
Login provider information.
LoginProviderViewSet - ViewSet for retrieving login provider information.
This ViewSet provides information about the available social login providers
from `allauth`, Django's default login, and any product-specific providers like SSO.
It's designed to list out these available authentication providers and their
respective login URLs.
Attributes:
- permission_classes: Allow any user (authenticated or not) to access this endpoint.
- serializer_class: Uses `LoginProviderSerializer` to serialize the data.
Methods:
- get_queryset: Returns the global `settings` object.
- _get_social_providers: A private method to retrieve social login providers
from `allauth`.
- _get_django_provider: A private method to check if Django's default login
is enabled and to get its login URL.
- _get_product_providers: A private method to check for any product-specific
SSO providers and retrieve their details.
- _get_login_providers: An aggregation method that combines the results
from the above three methods to get a comprehensive
list of login providers.
- list: The main endpoint which uses `_get_login_providers` to fetch all
available login providers and returns them after serialization.
Endpoints:
- List Login Providers:
- URL: /providers/
- HTTP Method: GET
- Method: list
- Description: Lists all available authentication/login providers
and their respective login URLs.
"""

permission_classes = [AllowAny]
Expand Down Expand Up @@ -603,7 +747,29 @@ def list(self, request):

class AppContextViewSet(viewsets.GenericViewSet):
"""
Brand/Product configuration information.
AppContextViewSet - ViewSet for retrieving brand/product configuration information.
This ViewSet provides information about the brand or product's configuration settings.
It fetches the settings from the global `settings` object and serializes them using
the `AppContextSerializer`.
Attributes:
- permission_classes: Allow any user (authenticated or not) to access this endpoint.
- serializer_class: Uses `AppContextSerializer` to serialize the data.
Methods:
- get_queryset: Returns the global `settings` object.
- list: Fetches specific configuration settings from the `settings` object,
combines them with specific environment variables from `EXPORTABLE_ENV`,
and returns the aggregated data.
Endpoints:
- List Brand/Product Configuration:
- URL: /context/
- HTTP Method: GET
- Method: list
- Description: Lists specific configuration settings related to the brand or product
and certain environment variables specified in `EXPORTABLE_ENV`.
"""

permission_classes = [AllowAny]
Expand Down
14 changes: 14 additions & 0 deletions appstore/appstore/settings/eduhelx-data720_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from .base import *
from product.configuration import ProductSettings, ProductColorScheme, ProductLink

# TODO remove Application brand once the new frontend is complete and
# the django templates in core are removed.
APPLICATION_BRAND = "eduhelx-data720"

PRODUCT_SETTINGS = ProductSettings(
brand="eduhelx-data720",
title="EduHeLx Data720",
logo_url="/static/images/eduhelx-data720/logo.png",
color_scheme=ProductColorScheme("#666666", "#e6e6e6"), #TBD
links=[],
)
12 changes: 12 additions & 0 deletions appstore/appstore/settings/ordrd_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from .base import * # noqa: F401,F403
from product.configuration import ProductSettings, ProductColorScheme

APPLICATION_BRAND = "ordrd"

PRODUCT_SETTINGS = ProductSettings(
brand="ordrd",
title="Ordr D",
logo_url="/static/images/ordrd/logo.png",
color_scheme=ProductColorScheme("#191348", "#0079bc"),
links=None,
)
Binary file added appstore/core/static/images/argus/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/bdc/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/braini/favicon.ico
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file added appstore/core/static/images/eduhelx/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/heal/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/helx/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/monarch/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/ordrd/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/ordrd/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added appstore/core/static/images/restartr/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/scidas/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/testing/favicon.ico
Binary file not shown.
Binary file added appstore/core/static/images/tracs/favicon.ico
Binary file not shown.
6 changes: 2 additions & 4 deletions appstore/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,12 @@ def get_brand_details(brand):
"braini": {"name": "BRAIN-I", "logo": "logo.png"},
"scidas": {"name": "SciDAS", "logo": "logo.png"},
"bdc": {"name": "BioData Catalyst", "logo": "logo.svg"},
"restartr": {
"name": "UNC Restarting Research",
"logo": "logo.png",
},
"restartr": { "name": "UNC Restarting Research", "logo": "logo.png", },
"heal": {"name": "NIH Heal Initiative", "logo": "logo.png"},
"argus": {"name": "Argus Array", "logo": "logo.png"},
"eduhelx": {"name": "EduHelx", "logo": "logo.png"},
"testing": {"name": "Testing", "logo": "logo.png"},
"ordrd": {"name": "Ordr D", "logo": "logo.png"},
}[brand]


Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Django==3.2
django-allauth
django-allauth==0.54.0
django-cors-headers==3.7.0
django-crispy-forms==1.11.2
django-debug-toolbar==3.2
Expand All @@ -15,7 +15,7 @@ python3-openid==3.1.0
requests==2.31.0
requests-oauthlib
selenium==3.141.0
tycho-api==1.14.1
tycho-api>=1.17.2
webdriver-manager==3.2.1
sqlparse==0.4.2
asgiref==3.4.1
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ install_requires =
django-saml2-auth==2.2.1
djangorestframework==3.12.2
drf-spectacular==0.15.1
tycho-api==1.14.1
tycho-api==1.17.2
pysaml2==6.3.1
python3-openid==3.1.0
requests==2.31.0
Expand Down

0 comments on commit 6612c0d

Please sign in to comment.