##
## GLUE 2.1 template for the compute-related information
##
<%!
  from datetime import datetime
%>\
<%
    static_compute_info = attributes['static_compute_info']
    suffix = static_compute_info['suffix']
    site_name = static_compute_info['site_name']
    shares = attributes['shares']

    compute_service_id = static_compute_info['compute_service_name'] + '_cloud.compute'
    compute_service_manager = compute_service_id + '_manager'

    timestamp = datetime.now().isoformat()
    validity = 3600

    all_endpoints = {url: endpoint for vo, share in shares.items() for url, endpoint in share['endpoints']['endpoints'].items()}

    instances = {instance_id: instance for vo, share in shares.items() for instance_id, instance in share['instances'].items()}
    running_instances = {instance_id: instance for instance_id, instance in instances.items() if instance['instance_status'] == 'ACTIVE'}
    suspended_instances = {instance_id: instance for instance_id, instance in instances.items() if instance['instance_status'] == 'SUSPENDED'}
    halted_instances = {instance_id: instance for instance_id, instance in instances.items() if instance['instance_status'] == 'SHUTOFF'}

    templates_cpu = [tpl['template_cpu'] for vo, share in shares.items() for tpl_id, tpl in share['templates'].items()]
    template_max_cpu = max(templates_cpu)
    template_min_cpu = min(templates_cpu)

    templates_memory = [tpl['template_memory'] for vo, share in shares.items() for tpl_id, tpl in share['templates'].items()]
    template_max_memory = max(templates_memory)
    template_min_memory = min(templates_memory)
%>\
##
## Cloud Computing Service - GLUE2CloudComputingService
##
dn: GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${suffix}
objectClass: GLUE2Entity
objectClass: GLUE2Service
objectClass: GLUE2CloudComputingService
GLUE2ServiceID: ${compute_service_id}
GLUE2EntityName: Cloud Compute service on ${site_name}
GLUE2EntityCreationTime: ${timestamp}
GLUE2EntityValidity: ${validity}
GLUE2ServiceAdminDomainForeignKey: ${site_name}
GLUE2ServiceType: org.cloud.iaas
GLUE2ServiceQualityLevel: ${static_compute_info['compute_service_production_level']}
GLUE2ServiceStatusInfo:  ${"http://argo.egi.eu/lavoisier/status_report-sf?site=%s" % site_name}
GLUE2CloudComputingServiceAUP: http://go.egi.eu/aup
GLUE2ServiceComplexity: endpointType=2,share=${len(shares)}
% for capability in static_compute_info['compute_capabilities']:
GLUE2ServiceCapability: ${capability}
% endfor
GLUE2CloudComputingServiceTotalVM: ${len(instances)}
GLUE2CloudComputingServiceRunningVM: ${len(running_instances)}
## XXX Missing
## GLUE2CloudComputingServicePendingVM:
GLUE2CloudComputingServiceSuspendedVM: ${len(suspended_instances)}
GLUE2CloudComputingServiceHaltedVM: ${len(halted_instances)}
% if 'gocdb_id' in static_compute_info:
GLUE2EntityOtherInfo: gocdb_id=${static_compute_info['gocdb_id']}
% endif

##
## Computing Manager - GLUE2CloudComputingManager
##
dn: GLUE2ManagerID=${compute_service_manager},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${suffix}
objectClass: GLUE2Entity
objectClass: GLUE2Manager
objectClass: GLUE2CloudComputingManager
GLUE2ManagerID: ${compute_service_manager}
GLUE2EntityName: Cloud Manager for ${static_compute_info['compute_service_name']}
GLUE2EntityCreationTime: ${timestamp}
GLUE2EntityValidity: ${validity}
GLUE2ManagerProductName: ${static_compute_info['compute_hypervisor']}
GLUE2ManagerProductVersion: ${static_compute_info['compute_hypervisor_version']}
GLUE2CloudComputingManagerHypervisorName: ${static_compute_info['compute_hypervisor']}
GLUE2CloudComputingManagerHypervisorVersion: ${static_compute_info['compute_hypervisor_version']}
GLUE2ManagerServiceForeignKey: ${compute_service_id}
GLUE2CloudComputingManagerCloudComputingServiceForeignKey: ${compute_service_id}
% if static_compute_info['compute_network_virt_type']:
## XXX could be present mulitple times
GLUE2CloudComputingManagerNetworkVirtualizationType: ${static_compute_info['compute_network_virt_type']}
% endif
% if static_compute_info['compute_cpu_virt_type']:
## XXX could be present mulitple times
GLUE2CloudComputingManagerCPUVirtualizationType: ${static_compute_info['compute_cpu_virt_type']}
% endif
## XXX Not in GlueSchema 2.1
## % if static_compute_info['compute_accelerators_virt_type']:
## GLUE2CloudComputingManagerAcceleratorVirtualizationType: ${static_compute_info['compute_accelerators_virt_type']}
## % endif
GLUE2CloudComputingManagerTotalCPUs: ${static_compute_info['compute_total_cores']}
GLUE2CloudComputingManagerTotalRAM: ${static_compute_info['compute_total_ram']}
## XXX Not in GlueSchema 2.1
## % if static_compute_info['compute_total_accelerators']:
## GLUE2CloudComputingManagerTotalAccelerators: ${static_compute_info['compute_total_accelerators']}
## % endif
GLUE2CloudComputingManagerInstanceMaxCPU: ${template_max_cpu}
GLUE2CloudComputingManagerInstanceMinCPU: ${template_min_cpu}
GLUE2CloudComputingManagerInstanceMaxRAM: ${template_max_memory}
GLUE2CloudComputingManagerInstanceMinRAM: ${template_min_memory}
GLUE2CloudComputingManagerInstanceMaxDedicatedRAM: ${static_compute_info['compute_max_dedicated_ram']}
GLUE2CloudComputingManagerInstanceMinDedicatedRAM: ${static_compute_info['compute_min_dedicated_ram']}
## XXX Not in GlueSchema 2.1
## % if static_compute_info['compute_max_accelerators']:
## GLUE2CloudComputingManagerInstanceMaxAccelerators: ${static_compute_info['compute_max_accelerators']}
## % endif
## % if static_compute_info['compute_min_accelerators']:
## GLUE2CloudComputingManagerInstanceMinAccelerators: ${static_compute_info['compute_min_accelerators']}
## % endif
% if static_compute_info.get('compute_virtual_disk_formats'):
% for virtual_disk_format in static_compute_info['compute_virtual_disk_formats']:
GLUE2CloudComputingManagerVirtualdiskFormat: ${virtual_disk_format}
% endfor
% endif
% if static_compute_info.get('compute_failover'):
GLUE2CloudComputingManagerFailover: ${static_compute_info['compute_failover']}
% endif
% if static_compute_info.get('compute_live_migration'):
GLUE2CloudComputingManagerLiveMigration: ${static_compute_info['compute_live_migration']}
% endif
% if static_compute_info.get('compute_vm_backup_restore'):
GLUE2CloudComputingManagerVMBackupRestore: ${static_compute_info['compute_vm_backup_restore']}
% endif

##
## List of Cloud Computing Endpoints - GLUE2CloudComputingEndpoint
##
## Images and templates are linked to each endpoints
##
## Native endpoints use native image and template IDs
## OCCI endpoints use OCCI-specific images and templates IDs
##
# List of all the endpoints
% for url, endpoint in all_endpoints.items():
<%
    native_endpoint = endpoint['compute_api_type'] != 'OCCI'
    if endpoint['compute_api_type'] == 'OpenStack':
        interface_name = 'org.openstack.nova'
        endpoint_semantics = 'https://developer.openstack.org/api-ref/compute'
    elif endpoint['compute_api_type'] == 'OpenNebula':
        interface_name = 'org.opennebula.compute'
        endpoint_semantics = 'UNKNOWN'
    else:
        endpoint_semantics = 'http://occi-wg.org/about/specification'
        interface_name = 'eu.egi.cloud.vm-management.occi'
    endpoint_id = ("%s_%s_%s_%s" % (endpoint['compute_endpoint_url'],
        endpoint['compute_api_type'], endpoint['compute_api_version'],
        endpoint['compute_api_authn_method']))
    endpoint_name = ("%s (%s/%s) at %s" % (endpoint['compute_api_type'],
        endpoint['compute_api_version'], endpoint['compute_api_authn_method'],
        endpoint['compute_endpoint_url']
        ))
%>\
dn: GLUE2EndpointID=${endpoint_id},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${endpoint['suffix']}
objectClass: GLUE2Entity
objectClass: GLUE2Endpoint
objectClass: GLUE2CloudComputingEndpoint
GLUE2EndpointID: ${endpoint_id}
GLUE2EntityName: Cloud Computing Endpoint ${endpoint_name}
GLUE2EntityCreationTime: ${timestamp}
GLUE2EntityValidity: ${validity}
GLUE2EndpointURL: ${endpoint['compute_endpoint_url']}
GLUE2EndpointServiceForeignKey: ${compute_service_id}
% for capability in endpoint['compute_capabilities']:
GLUE2EndpointCapability: ${capability}
% endfor
GLUE2EndpointQualityLevel: ${endpoint['compute_production_level']}
GLUE2EndpointInterfaceName: ${interface_name}
GLUE2EndpointInterfaceVersion: ${endpoint['compute_api_version']}
GLUE2EndpointHealthState: ok
GLUE2EndpointHealthStateInfo: Endpoint functioning properly
GLUE2EndpointServingState: ${endpoint['compute_production_level']}
GLUE2EndpointTechnology: ${endpoint['compute_api_endpoint_technology']}
GLUE2EndpointImplementor: ${endpoint['compute_middleware_developer']}
GLUE2EndpointImplementationName: ${endpoint['compute_middleware']}
GLUE2EndpointImplementationVersion: ${endpoint['compute_middleware_version']}
GLUE2EndpointDowntimeInfo: See the GOC DB for downtimes: https://goc.egi.eu/portal/index.php?Page_Type=Downtimes_Calendar&site=${site_name}
GLUE2EndpointSemantics: ${endpoint_semantics}
GLUE2EndpointAuthentication: ${endpoint['compute_api_authn_method']}
GLUE2EndpointIssuerCA: ${endpoint['endpoint_issuer']}
% for trusted_ca in endpoint['endpoint_trusted_cas']:
GLUE2EndpointTrustedCA: ${trusted_ca}
% endfor
## XXX Missing
## GLUE2EndpointDowntimeAnnounce:
## GLUE2EndpointDowntimeStart:
## GLUE2EndpointDowntimeEnd:
## GLUE2EndpointSupportedProfile:
## GLUE2EndpointInterfaceExtension:
## GLUE2EndpointStartTime:
## GLUE2EndpointWSDL:

## End of endpoints
% endfor
##
## Computing share - GLUE2CloudComputingShare
##
## One share per VO, for all endpoints supporting this project
## Images and templates are linked to an endpont of a share
##
## OpenStack: one project per VO and two endpoints (OpenStack + native)
##
# List of all shares with endpoint-specific images, templates and policies
% for vo, share in shares.items():
<%
    share_id = ("%s_share_%s_%s" % (compute_service_id, vo, share['project']))
    share_instances = share['instances']

    share_running_instances = {instance_id: instance for instance_id, instance in share_instances.items() if instance['instance_status'] == 'ACTIVE'}
    share_suspended_instances = {instance_id: instance for instance_id, instance in share_instances.items() if instance['instance_status'] == 'SUSPENDED'}
    share_halted_instances = {instance_id: instance for instance_id, instance in share_instances.items() if instance['instance_status'] == 'SHUTOFF'}

    share_templates_cpu = [tpl['template_cpu'] for tpl_id, tpl in share['templates'].items()]
    share_template_max_cpu = max(share_templates_cpu)

    share_templates_memory = [tpl['template_memory'] for tpl_id, tpl in share['templates'].items()]
    share_template_max_memory = max(share_templates_memory)

    endpoints = share['endpoints']['endpoints']
    images = share['images']
    templates = share['templates']

    if share['instance_max_accelerators']:
      share_max_accelerators = share['instance_max_accelerators']
    else:
      share_max_accelerators = static_compute_info['compute_max_accelerators']

    quotas = share['quotas']
    if quotas.has_key('instances'):
        share_max_vm = quotas['instances']
    else:
        share_max_vm = False

    fields =  {'sla', 'network_info', 'default_network_type', 'public_network_name'}
    for field in fields:
      if field not in share or share[field] is None:
          share[field] = 'UNKNOWN'
%>\
# Share ${share_id}
dn: GLUE2ShareID=${share_id},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${suffix}
objectClass: GLUE2Entity
objectClass: GLUE2Share
objectClass: GLUE2CloudComputingShare
GLUE2ShareID: ${share_id}
GLUE2EntityName: Share in service ${compute_service_id} for VO ${vo} (Project ${share['project']})
GLUE2EntityCreationTime: ${timestamp}
GLUE2EntityValidity: ${validity}
GLUE2ShareServiceForeignKey: ${compute_service_id}
GLUE2ShareDescription: Share in service ${compute_service_id} for VO ${vo} (Project ${share['project']})
GLUE2CloudComputingShareCloudComputingServiceForeignKey: ${compute_service_id}
% for url, endpoint in endpoints.items():
<%
    endpoint_id = ("%s_%s_%s_%s" % (endpoint['compute_endpoint_url'],
        endpoint['compute_api_type'], endpoint['compute_api_version'],
        endpoint['compute_api_authn_method']))
%>\
GLUE2ShareEndpointForeignKey: ${endpoint_id}
GLUE2CloudComputingShareCloudComputingEndpointForeignKey: ${endpoint_id}
% endfor
GLUE2CloudComputingShareInstanceMaxCPU: ${share_template_max_cpu}
GLUE2CloudComputingShareInstanceMaxRAM: ${share_template_max_memory}
GLUE2CloudComputingShareSLA: ${share['sla']}
GLUE2CloudComputingShareTotalVM: ${len(share_instances)}
GLUE2CloudComputingShareRunningVM: ${len(share_running_instances)}
## XXX Missing
## GLUE2CloudComputingSharePendingVM:
GLUE2CloudComputingShareSuspendedVM: ${len(share_suspended_instances)}
GLUE2CloudComputingShareHaltedVM: ${len(share_halted_instances)}
GLUE2CloudComputingShareNetworkInfo: ${share['network_info']}
GLUE2CloudComputingShareDefaultNetworkType: ${share['default_network_type']}
GLUE2CloudComputingSharePublicNetworkName: ${share['public_network_name']}
## XXX Not in GlueSchema 2.1
## GLUE2CloudComputingShareInstanceMaxAccelerators: ${share_max_accelerators}
% if share_max_vm:
GLUE2CloudComputingShareMaxVM: ${share_max_vm}
% endif
GLUE2CloudComputingShareProjectID: ${share['project']}

## Iterate over all the endpoints of the share to display corresponding:
## images, templates and AccessPolicies
% for url, endpoint in endpoints.items():
<%
    native_endpoint = endpoint['compute_api_type'] != 'OCCI'
    endpoint_id = ("%s_%s_%s_%s" % (endpoint['compute_endpoint_url'],
        endpoint['compute_api_type'], endpoint['compute_api_version'],
        endpoint['compute_api_authn_method']))
    endpoint_name = ("%s (%s/%s) at %s" % (endpoint['compute_api_type'],
        endpoint['compute_api_version'], endpoint['compute_api_authn_method'],
        endpoint['compute_endpoint_url']
        ))
%>\
##
## List of images
##
# Images for endpoint ${endpoint_id}
# and share ${share_id}
% for image_native_id, image in images.items():
<%
    img_id = image['image_native_id'] if native_endpoint else image['image_id']

    fields =  {'image_version', 'image_os_family', 'image_os_name',
               'image_os_version', 'image_marketplace_id', 'image_size'}
    for field in fields:
      if field not in image or image[field] is None:
          image[field] = 'UNKNOWN'

    if image['image_description'] is None:
        image['image_description'] = ('%(image_name)s version '
            '%(image_version)s on '
            '%(image_os_family)s %(image_os_name)s '
            '%(image_os_version)s '
            '%(image_platform)s' % image)
%>\
dn: GLUE2CloudComputingImageID=${img_id},GLUE2ShareID=${share_id},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${suffix}
objectClass: GLUE2Entity
objectClass: GLUE2CloudComputingImage
GLUE2EntityName: ${image['image_name']}
GLUE2CloudComputingImageID: ${img_id}
GLUE2EntityCreationTime: ${timestamp}
GLUE2EntityValidity: ${validity}
GLUE2CloudComputingImageTemplateID: ${img_id}
GLUE2CloudComputingImageCloudComputingShareForeignKey: ${share_id}
GLUE2CloudComputingImageCloudComputingManagerForeignKey: ${compute_service_manager}
GLUE2CloudComputingImageCloudComputingEndpointForeignKey: ${endpoint_id}
GLUE2CloudComputingImageMarketPlaceURL: ${image['image_marketplace_id']}
GLUE2CloudComputingImageOSPlatform: ${image['image_platform']}
GLUE2CloudComputingImageOSFamily: ${image['image_os_family']}
GLUE2CloudComputingImageOSName: ${image['image_os_name']}
GLUE2CloudComputingImageOSVersion: ${image['image_os_version']}
% if image.get('image_version'):
GLUE2CloudComputingImageVersion: ${image['image_version']}
% endif
% if image.get('image_minimal_cpu'):
GLUE2CloudComputingImageMinCPU: ${image['image_minimal_cpu']}
% endif
% if image.get('image_recommended_cpu'):
GLUE2CloudComputingImageRecommendedCPU: ${image['image_recommended_cpu']}
% endif
% if image.get('image_minimal_ram'):
GLUE2CloudComputingImageMinRAM: ${image['image_minimal_ram']}
% endif
% if image.get('image_recommended_ram'):
GLUE2CloudComputingImageRecommendedRAM: ${image['image_recommended_ram']}
% endif
## XXX Not in GlueSchema2.1
## % if image.get('image_minimal_accel'):
## GLUE2CloudComputingImageMinAccelerators: ${image['image_minimal_accel']}
## % endif
## % if image.get('image_recommended_accel'):
## GLUE2CloudComputingImageRecommendedAccelerators: ${image['image_recommended_accel']}
## % endif
## % if image.get('image_accel_type'):
## GLUE2CloudComputingImageRecommendedAcceleratorType: ${image['image_accel_type']}
## % endif
GLUE2CloudComputingImageDescription: ${image['image_description']}
GLUE2CloudComputingImageDiskSize: ${image['image_size']}
GLUE2CloudComputingImageAccessInfo: ${image.get('image_access_info', 'none')}
% if image.get('image_context_format'):
GLUE2CloudComputingImageContextualizationName: context_format:${image['image_context_format']}
% endif
% for software in image.get('image_software', []):
GLUE2CloudComputingImageInstalledsoftware: ${software}
% endfor
% for other in image.get('other_info', []):
GLUE2EntityOtherInfo: ${other}
% endfor
## XXX Missing
## GLUE2CloudComputingImageContextualizationVersion:
## XXX Not exposed for security reasons
## GLUE2CloudComputingImageDefaultUsername:
## GLUE2CloudComputingImageDefaultPassword:

## All NetworkTraffic for $img_id
% for idx,network_conf in enumerate(image.get(x) for x in ['network_traffic_in', 'network_traffic_out']):
% if network_conf:
<%
    network_conf_id = "%s_%s_%s" % (network_conf['direction'], network_conf['protocol'], idx)
%>\
dn: GLUE2CloudComputingImageNetwokConfigurationID=${network_conf_id},GLUE2CloudComputingImageID=${img_id},GLUE2ShareID=${share_id},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${suffix}
objectClass: GLUE2Entity
objectClass: GLUE2CloudComputingImageNetworkConfiguration
GLUE2EntityName: ${network_conf['name']}
GLUE2CloudComputingImageNetworkConfigurationID: ${network_conf_id}
GLUE2EntityCreationTime: ${timestamp}
GLUE2EntityValidity: ${validity}
GLUE2CloudComputingImageForeignKey: ${img_id}
GLUE2CloudComputingImageNetworkConfigurationDirection: ${network_conf['direction']}
GLUE2CloudComputingImageNetworkConfigurationProtocol: ${network_conf['protocol']}
GLUE2CloudComputingImageNetworkConfigurationPort: ${network_conf['port']}
GLUE2CloudComputingImageNetworkConfigurationAddressRange: ${network_conf['address_range']}

% endif
% endfor

% endfor
##
## List of templates - GLUE2CloudComputingInstanceType
##
# Templates for endpoint ${endpoint_id}
# and share ${share_id}
% for template_native_id, template in templates.items():
<%
    tpl_id = template['template_native_id'] if native_endpoint else template['template_id']
%>\
dn: GLUE2ResourceID=${tpl_id},GLUE2ShareID=${share_id},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${template['suffix']}
objectClass: GLUE2Entity
objectClass: GLUE2Resource
objectClass: GLUE2CloudComputingInstanceType
GLUE2ResourceID: ${tpl_id}
GLUE2EntityCreationTime: ${timestamp}
GLUE2EntityValidity: ${validity}
GLUE2EntityName: ${tpl_id}
GLUE2CloudComputingInstanceTypeTemplateID: ${tpl_id}
GLUE2ResourceManagerForeignKey: ${compute_service_manager}
GLUE2CloudComputingInstanceTypeCloudComputingShareForeignKey: ${share_id}
GLUE2CloudComputingInstanceTypeCloudComputingManagerForeignKey: ${compute_service_manager}
GLUE2CloudComputingInstanceTypeCloudComputingEndpointForeignKey: ${endpoint_id}
GLUE2CloudComputingInstanceTypePlatform: ${template['template_platform']}
GLUE2CloudComputingInstanceTypeCPU: ${template['template_cpu']}
GLUE2CloudComputingInstanceTypeRAM: ${template['template_memory']}
GLUE2CloudComputingInstanceTypeNetworkIn: ${template.get('template_network_in', 'UNKNOWN')}
GLUE2CloudComputingInstanceTypeNetworkOut: ${template.get('template_network_out', 'UNKNOWN')}
GLUE2CloudComputingInstanceTypeNetworkInfo: ${share['network_info']}
GLUE2CloudComputingInstanceTypeDisk: ${template['template_disk']}
% if template.get('template_ephemeral'):
GLUE2CloudComputingInstanceTypeEphemeralStorage: ${template['template_ephemeral']}
% endif
## XXX Missing
## GLUE2CloudComputingInstanceTypeMarketplaceURL:
## GLUE2CloudComputingInstanceTypeNetworkPortsIn:
## GLUE2CloudComputingInstanceTypeNetworkPortsOut:

% endfor
##
## Access Policy - GLUE2AccessPolicy
##
# AccessPolicy for endpoint ${endpoint_id}
# and share ${share_id}
dn: GLUE2PolicyID=${endpoint_id}_${vo}_Policy,GLUE2EndpointID=${endpoint_id},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${suffix}
objectClass: GLUE2Entity
objectClass: GLUE2Policy
objectClass: GLUE2AccessPolicy
GLUE2PolicyID: ${endpoint_id}_Policy
GLUE2EntityCreationTime: ${timestamp}
GLUE2AccessPolicyEndpointForeignKey: ${endpoint_id}
GLUE2PolicyScheme: org.glite.standard
GLUE2EntityName: Access control rules for ${vo} on ${endpoint_id}
GLUE2PolicyRule: VO:${vo}

## End of endpoint-specifc info for current share
% endfor
##
## Mapping Policy - GLUE2MappingPolicy
##
# MappingPolicy for share ${share_id}
dn: GLUE2PolicyID=${share_id}_Policy,GLUE2ShareID=${share_id},GLUE2ServiceID=${compute_service_id},GLUE2GroupID=resource,${suffix}
objectClass: GLUE2Entity
objectClass: GLUE2Policy
objectClass: GLUE2MappingPolicy
GLUE2PolicyID: ${share_id}_Policy
GLUE2EntityCreationTime: ${timestamp}
GLUE2PolicyScheme: org.glite.standard
GLUE2MappingPolicyShareForeignKey: ${share_id}
% for rule in share['membership']:
GLUE2PolicyRule: ${rule}
% endfor
GLUE2PolicyUserDomainForeignKey: ${vo}

## End of share
% endfor
## vim:set ft=ldif:
