heat_template_version: rocky
description: 'Generates the relevant service principals for a {{role.name}} server'

parameters:
  RoleData:
     type: json
     description: the list containing the 'role_data' output for the ServiceChain
{%- for network in networks if network.vip|default(false) and network.name in role.networks %}
{%- if network.name == 'External' %}
  # Special case the External hostname param, which is CloudName
  CloudName:
    default: overcloud.localdomain
    description: The DNS name of this cloud. E.g. ci-overcloud.tripleo.org
    type: string
{%- elif network.name == 'InternalApi' %}
  # Special case the Internal API hostname param, which is CloudNameInternal
  CloudNameInternal:
    default: overcloud.{{network.name.lower()}}.localdomain
    description: >
      The DNS name of this cloud's {{network.name_lower}} endpoint. E.g.
      'ci-overcloud.{{network.name.lower()}}.tripleo.org'.
    type: string
{%- elif network.name == 'StorageMgmt' %}
  # Special case StorageMgmt hostname param, which is CloudNameStorageManagement
  CloudNameStorageManagement:
    default: overcloud.{{network.name.lower()}}.localdomain
    description: >
      The DNS name of this cloud's {{network.name_lower}} endpoint. E.g.
      'ci-overcloud.{{network.name.lower()}}.tripleo.org'.
    type: string
{%- else %}
  CloudName{{network.name}}:
    default: overcloud.{{network.name.lower()}}.localdomain
    description: >
      The DNS name of this cloud's {{network.name_lower}} endpoint. E.g.
      'ci-overcloud.{{network.name.lower()}}.tripleo.org'.
    type: string
{%- endif %}
{%- endfor %}
  CloudNameCtlplane:
    default: overcloud.ctlplane.localdomain
    description: >
      The DNS name of this cloud's provisioning network endpoint. E.g.
      'ci-overcloud.ctlplane.tripleo.org'.
    type: string

resources:

  IncomingMetadataSettings:
    type: OS::Heat::Value
    properties:
      value:
        yaql:
          # Filter null values and values that contain don't contain
          # 'metadata_settings', get the values from that key and get the
          # unique ones. Also, filter values for networks not associated with
          # this role.
          expression: let(role_networks => $.data.role_networks) -> list(coalesce($.data.role_data, []).where($ != null).where($.containsKey('metadata_settings')).metadata_settings.flatten().distinct().where($ != null and $.containsKey('network')).where($role_networks.contains($.network)))
          data:
            role_data: {get_param: RoleData}
            role_networks:
              - ctlplane
{%- for network in networks if network.vip|default(false) and network.name in role.networks %}
  {%- if network.service_net_map_replace is defined %}
              - {{network.service_net_map_replace}}
  {%- else %}
              - {{network.name_lower}}
  {%- endif %}
{%- endfor %}

  # Generates entries for nova metadata with the following format:
  #   'managed_service_<id>' : <service>/<fqdn>
  # Depending on the requested network
  IndividualServices:
    type: OS::Heat::Value
    properties:
      value:
        yaql:
          expression: let(fqdns => $.data.fqdns) -> dict(coalesce($.data.metadata, []).where($ != null and $.type = 'vip').select([concat('managed_service_', $.service, $.network), concat($.service, '/', $fqdns.get($.network))]))
          data:
            metadata: {get_attr: [IncomingMetadataSettings, value]}
            fqdns:
{%- for network in networks if network.vip|default(false) and network.name in role.networks %}
{%- if network.name == 'External' %}
  {%- if network.service_net_map_replace is defined %}
              {{network.service_net_map_replace}}: {get_param: CloudName}
  {%- else %}
              {{network.name_lower}}: {get_param: CloudName}
  {%- endif %}
{%- elif network.name == 'InternalApi' %}
  {%- if network.service_net_map_replace is defined %}
              {{network.service_net_map_replace}}: {get_param: CloudNameInternal}
  {%- else %}
              {{network.name_lower}}: {get_param: CloudNameInternal}
  {%- endif %}
{%- elif network.name == 'StorageMgmt' %}
  {%- if network.service_net_map_replace is defined %}
              {{network.service_net_map_replace}}: {get_param: CloudNameStorageManagement}
  {%- else %}
              {{network.name_lower}}: {get_param: CloudNameStorageManagement}
  {%- endif %}
{%- else %}
  {%- if network.service_net_map_replace is defined %}
              {{network.service_net_map_replace}}: {get_param: CloudNameStorageManagement}
  {%- else %}
              {{network.name_lower}}: {get_param: CloudName{{network.name}}}
  {%- endif %}
{%- endif %}
{%- endfor %}
              ctlplane: {get_param: CloudNameCtlplane}

  CompactServices:
    type: OS::Heat::Value
    properties:
      value:
        yaql:
          expression: dict(coalesce($.data, []).where($ != null and $.type = 'node').groupBy(concat('compact_service_', $.service), $.network.replace('_', '')))
          data: {get_attr: [IncomingMetadataSettings, value]}

outputs:
  metadata:
    description: actual metadata entries that will be passed to the server.
    value:
      map_merge:
        - {get_attr: [IndividualServices, value]}
        - {get_attr: [CompactServices, value]}
