Skip to content

Commit

Permalink
COmpute COmparison json and html
Browse files Browse the repository at this point in the history
add utils.py
default return type html
  • Loading branch information
andylytical committed Aug 24, 2024
1 parent c064f80 commit 9fd02b8
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*_customized.conf
*_customized.sql


# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
1 change: 0 additions & 1 deletion Operations_Warehouse_Django/cider/filters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.db.models import Q
from cider.models import *
from itertools import chain

###############################################################################
# Active CiDeR Resource Filtering Criteria
Expand Down
6 changes: 6 additions & 0 deletions Operations_Warehouse_Django/cider/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
from cider.models import *
from rest_framework import serializers


class CiderInfrastructure_OtherAttrs_Serializer( serializers.ModelSerializer ):
class Meta:
model = CiderInfrastructure
fields = ( 'other_attributes', )

class CiderInfrastructure_Summary_Serializer(serializers.ModelSerializer):
cider_view_url = serializers.SerializerMethodField()
cider_data_url = serializers.SerializerMethodField()
Expand Down
65 changes: 65 additions & 0 deletions Operations_Warehouse_Django/cider/templates/coco.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{% extends "web/base_nav_none.html" %}

{% block title %}Compute Comparison{% endblock %}

{% block page_extra_scripts %}
<style>
.coco {
border: 1px solid black;
}

table.coco {
width: 100%;
border-collapse: collapse;
}

th.coco {
text-align: center;
}

.bgwhite {
background-color: white;
}
.bglight {
background-color: silver;
}

.remainder {
display: none;
}
.truncated:hover + .remainder {
display: inline;
color: red;
}
</style>
{% endblock %}

{% block content %}

<h1>Compute Comparison</h1>

<table class="coco">
<tr class="coco">
{% for header in results.headers %}
{% autoescape off %}
<th class="coco"> {{ header }} </th>
{% endautoescape %}
{% endfor %}
</tr>
{% for row in results.table %}
<tr class="coco {% cycle 'bgwhite' 'bglight' %}">
{% for v in row %}
{% if v|length > 35 %}
<td class="coco">
<div class="truncated">{{v|truncatechars:34}}</div>
<div class="remainder">{{v|slice:"33:"}}</div>
</td>
{% else %}
<td class="coco">{{v}}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>

{% endblock %}
1 change: 1 addition & 0 deletions Operations_Warehouse_Django/cider/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
path(r'v1/cider_resource_id/<str:cider_resource_id>/', CiderInfrastructure_v1_Detail.as_view(), name='cider-detail-v1-id'),
path(r'v1/info_resourceid/<str:info_resourceid>/', CiderInfrastructure_v1_Detail.as_view(), name='cider-detail-v1-infoid'),
path(r'v1/access-active/', CiderInfrastructure_v1_ACCESSActiveList.as_view(), name='cider-accessactivelist-v1'),
path(r'v1/coco/', CiderInfrastructure_v1_ACCESSComputeCompare.as_view(), name='cider-accesscomputecompare-v1'),
path(r'v2/access-active/', CiderInfrastructure_v2_ACCESSActiveList.as_view(), name='cider-accessactivelist-v2'),
path(r'v2/access-all/', CiderInfrastructure_v2_ACCESSAllList.as_view(), name='cider-accessalllist-v2'),
path(r'v1/access-allocated/', CiderInfrastructure_v1_ACCESSAllocatedList.as_view(), name='cider-accessallocatedlist-v1'),
Expand Down
191 changes: 191 additions & 0 deletions Operations_Warehouse_Django/cider/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
def get_best_org_details( org_list ):
''' find org with the largest quantity of non-null fields '''
keys = [
'organization_name',
'organization_url',
'organization_abbreviation',
'organization_logo_url',
'organization_id',
]
scores = [0] * len(org_list)
for i in range( len(org_list) ):
org = org_list[i]
org_scores = [ org[k] is not None for k in keys ]
scores[i] = sum( org_scores )
best = scores.index( max( scores ) )
return org_list[ best ]


def get_resource_info( attrs ):
''' INPUT cider other_attributes dict
OUTPUT dict with org info, keys:
platform_name " Indiana Jetstream2 GPU"
public_url "https://cider.access-ci.…lic/resources/RDR_000904"
resource_descriptive_name "Indiana Jetstream2 GPU"
short_name "Jetstream2 GPU"
+++++++ PLUS ORG INFO +++++++
city "Bloomington"
state "IN"
country "US"
organization_id 561
organization_url "https://pti.iu.edu/"
organization_code "0087312"
organization_name "Indiana University"
organization_logo_url "https://cider.access-ci.…ource_providers/369/logo"
external_organization_id "grid.257410.5"
organization_abbreviation "Indiana U"
external_organization_id_type "GRID"
'''
keys = [
'compute_resource_id',
'platform_name',
'public_url',
'resource_descriptive_name',
'short_name',
]
resource_info = { k: attrs[k] for k in keys }
resource_info.update( get_best_org_details( attrs['organizations'] ) )
return resource_info


def get_resource_attribute_names():
resource_attr_names = [
# access_description,
'advance_max_reservable_su',
'advance_reservation_support',
# allocations_info,
# alternate_login_hostname,
'batch_system',
'community_software_area',
# community_software_area_email,
# community_software_area_feature_user_description,
# compute_resource_id,
'cpu_count_per_node',
'cpu_speed_ghz',
'cpu_type',
'disk_size_tb',
'display_in_xsede_su_calculator',
# features,
# gateway_recommended_use,
'gpu_description',
'graphics_card',
'interconnect',
# ip_address,
'job_manager',
# latitude,
'local_storage_per_node_gb',
# login_hostname,
# longitude,
'machine_type',
'manufacturer',
'max_reservable_su',
'memory_per_cpu_gb',
'model',
'nfs_network',
'nickname',
'node_count',
'operating_system',
# organizations,
'parallel_file_system',
# parent_resource,
'peak_teraflops',
'platform_name',
'primary_storage_shared_gb',
# public_url,
# recommended_use,
# resource_descriptive_name,
'resource_type',
'rmax',
'rpeak',
# sensitive_data_support_description,
# short_name,
'storage_network',
'supports_sensitive_data',
# user_guide_url,
# 'xsede_services_only',
'xsedenet_participant',
]
return resource_attr_names


def mk_headers( cols, resources ):
''' Convert resources dict into html header data
'''
headers = [ '' ]
for resource_id in cols[1:]:
resource = resources[ resource_id ]
resource_url = resource[ 'public_url' ]
resource_short_name = resource[ 'short_name' ]
org_url = resource[ 'organization_url' ]
org_name = resource[ 'organization_name' ]
logo_url = resource[ 'organization_logo_url' ]
abbr = resource[ 'organization_abbreviation' ]
img_size=75
h = (
f'<!-- org_abbr: {abbr} -->'
f'<img width="{img_size}" height="{img_size}" src="{logo_url}" alt="{org_name}">'
'<br/>'
f'<a href="{org_url}">({abbr})</a>'
'<br/>'
f'<a href="{resource_url}">{resource_short_name}</a>'
)
headers.append( h )
return headers


def resource_ids_sorted_by( key, resources ):
''' return list of resource_ids sorted by "key" '''
id_list = []
key2id = {}
for id in resources.keys():
match_key = resources[id][key]
if match_key in key2id:
key2id[ match_key ].append( id )
else:
key2id[ match_key ] = [ id ]
for key in sorted( key2id.keys() ):
id_list.extend( key2id[ key ] )
return id_list


def mk_html_table( data ):
''' convert features to table with
resources along the top and
features down the first column
'''
features = data[ 'attributes' ]
resources = data[ 'resources' ]
resource_ids = resource_ids_sorted_by( 'organization_abbreviation', resources )
table = []
f_names = sorted( get_resource_attribute_names() )
for f in f_names:
row = [f]
for r in resource_ids:
row.append( features[f][r] )
table.append( row )
cols = [ 'Attribute' ] + resource_ids
headers = mk_headers( cols, resources )
return { 'headers':headers, 'table':table }


def cider_to_coco( objects ):
# objects is the data returned by the cider filter in django
resources = {}
features = {}
for result in objects[ 'results' ]:
attrs = result[ 'other_attributes' ]
# add resource details
resource_id = attrs[ 'compute_resource_id' ]
resources[ resource_id ] = get_resource_info( attrs )
# add feature data for this resource to the pivot table
for k,v in attrs.items():
try:
features[k][resource_id] = v
except KeyError as e:
features[k] = { 'Attribute': k, resource_id: v }
data = { 'resources': resources, 'attributes': features }
return data


if __name__ == '__main__':
raise UserWarning( 'not directly runnable' )
20 changes: 20 additions & 0 deletions Operations_Warehouse_Django/cider/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,31 @@
from .models import *
from .filters import *
from .serializers import *
from .utils import cider_to_coco, mk_html_table

from warehouse_tools.exceptions import MyAPIException
from warehouse_tools.responses import MyAPIResponse, CustomPagePagination

# Create your views here.

class CiderInfrastructure_v1_ACCESSComputeCompare(GenericAPIView):
'''
Comparison of ACCESS Active Allocated Compute Resources
'''
permission_classes = (IsAuthenticatedOrReadOnly,)
renderer_classes = (TemplateHTMLRenderer, JSONRenderer)
serializer_class = CiderInfrastructure_OtherAttrs_Serializer
def get(self, request, format=None, **kwargs):
returnformat = request.query_params.get('format' )
template_name = 'coco.html'
objects = CiderInfrastructure_Active_Filter( type='Compute' )
serializer = CiderInfrastructure_OtherAttrs_Serializer(objects, context={'request': request}, many=True)
coco_data = cider_to_coco( { 'results': serializer.data } )
if returnformat != 'json':
coco_data = mk_html_table( coco_data )
return MyAPIResponse( { 'results': coco_data }, template_name=template_name )


class CiderInfrastructure_v1_ACCESSActiveList(GenericAPIView):
'''
All ACCESS Active Allocated Compute and Storage Resources
Expand Down
4 changes: 2 additions & 2 deletions developer/docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ along with its prerequisites and various scripts for confguring and/or interacti
with it.


# How to setup the docker compose django dev environment
# How to setup the docker-compose django dev environment

## Prerequisites:
* A functional docker and docker compose ecosystem.
* A functional docker and docker-compose ecosystem.
* The django_aws_credential_key file, in your home dir. Get this from Eric or JP.
* Your local uid and gid (on linux systems, you can use the "id" command to get these)
* Docker vm.max_map_count >= 262144 (See also: faq.md)
Expand Down
Loading

0 comments on commit 9fd02b8

Please sign in to comment.