{%- set _service_nets = {} -%}
{%- for network in networks if network.enabled|default(true) -%}
  {%- if network.service_net_map_replace is defined -%}
    {%- set _service_nets = _service_nets.update({network.service_net_map_replace:network.name_lower}) -%}
  {%- else -%}
    {%- set _service_nets = _service_nets.update({network.name_lower:network.name_lower}) -%}
  {%- endif -%}
{%- endfor -%}

heat_template_version: rocky

description: >
  Mapping of service_name_network -> network name

parameters:
  ServiceNetMap:
    description: Mapping of service_name -> network name. Typically set
                 via parameter_defaults in the resource registry.  This
                 mapping overrides those in ServiceNetMapDefaults.
                 Note that the key in this map must match the service_name
                 in the service template, e.g if the service_name is heat_api
                 the key must be either heat_api_network, or optionally
                 HeatApiNetwork (which will be internally converted to
                 transform captalization to underscores).
    default: {}
    type: json

  # Note that the key in this map must match the service_name
  # see the description above about conversion from CamelCase to
  # snake_case - the names must still match when converted
  ServiceNetMapDefaults:
    default:
      # Note the values in this map are replaced by *NetName
      # to allow for sane defaults when the network names are
      # overridden.
      ApacheNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      NeutronTenantNetwork: {{ _service_nets.get('tenant', 'ctlplane') }}
      AodhApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      BarbicanApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      GnocchiApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      MongodbNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      CinderApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      CinderIscsiNetwork: {{ _service_nets.get('storage', 'ctlplane') }}
      GlanceApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      IronicApiNetwork: ctlplane
      IronicNetwork: ctlplane
      IronicInspectorNetwork: ctlplane
      KeystoneAdminApiNetwork: ctlplane # allows undercloud to config endpoints
      KeystonePublicApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      ManilaApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      MetricsQdrNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      NeutronApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      OctaviaApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      HeatApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      HeatApiCfnNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      HeatApiCloudwatchNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      NovaApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      PlacementNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      NovaMetadataNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      NovaVncProxyNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      NovaLibvirtNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      NovajoinNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      SwiftStorageNetwork: {{ _service_nets.get('storage_mgmt', 'ctlplane') }}
      SwiftProxyNetwork: {{ _service_nets.get('storage', 'ctlplane') }}
      SaharaApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      HorizonNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      MemcachedNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      OsloMessagingRpcNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      OsloMessagingNotifyNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      RabbitmqNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      QdrNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      RedisNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      GaneshaNetwork: {{ _service_nets.get('storage_nfs', 'ctlplane') }}
      MysqlNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      SnmpdNetwork: ctlplane
      CephClusterNetwork: {{ _service_nets.get('storage_mgmt', 'ctlplane') }}
      CephGrafanaNetwork: {{ _service_nets.get('storage', 'ctlplane') }}
      CephMonNetwork: {{ _service_nets.get('storage', 'ctlplane') }}
      CephRgwNetwork: {{ _service_nets.get('storage', 'ctlplane') }}
      PublicNetwork: {{ _service_nets.get('external', 'ctlplane') }}
      OpendaylightApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      OvnDbsNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      MistralApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      ZaqarApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      DockerRegistryNetwork: ctlplane
      PacemakerNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      PacemakerRemoteNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      DesignateApiNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      BINDNetwork: {{ _service_nets.get('external', 'ctlplane') }}
      EtcdNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
      # HaproxyNetwork currently only controls the haproxy.stats network binding
      HaproxyNetwork: ctlplane
      # We special-case the default ResolveNetwork for the Ceph roles
      # for backwards compatibility, all other roles default to internal_api
{%- for role in roles if role.name.startswith('Ceph') %}
      {{role.name}}HostnameResolveNetwork: {{ _service_nets.get('storage', 'ctlplane') }}
{%- endfor %}
{%- for role in roles if not role.name.startswith('Ceph') %}
      {{role.name}}HostnameResolveNetwork: {{ _service_nets.get('internal_api', 'ctlplane') }}
{%- endfor %}
    description: Mapping of service_name -> network name. Typically set
                 via parameter_defaults in the resource registry.
    type: json

  ControlPlaneSubnet:
    description: The name of the undercloud Neutron control plane subnet
    default: ctlplane-subnet
    type: string

  VipSubnetMap:
    description: Map of (network_name or service_name) -> subnet_name that
                 defines which subnet to host the VIP.
    default: {}
    type: json

  VipSubnetMapDefaults:
    default:
      ctlplane: ctlplane-subnet
{%- for network in networks if network.vip|default(false) %}
      {{network.name}}: {{network.name_lower}}_subnet
{%- endfor %}
      redis: {{ _service_nets.get('internal_api', 'internal_api') }}_subnet
      ovn_dbs: {{ _service_nets.get('internal_api', 'internal_api') }}_subnet
    type: json

  # We define mappings to work around names that break when doing the
  # CamelCase to snake_case conversion to align with service_names
  ServiceNetMapDeprecatedMapping:
    default:
      RabbitMqNetwork: RabbitmqNetwork
      CephPublicNetwork: CephMonNetwork
      SwiftMgmtNetwork: SwiftStorageNetwork
    description: Mapping older deprecated service names, intended for
                 internal use only, this will be removed in future.
    type: json

{%- for network in networks if network.enabled|default(true) %}
  {{network.name}}NetName:
    default: {{network.name_lower}}
    description: The name of the {{network.name_lower}} network.
    type: string
{%- endfor %}

parameter_groups:
- label: deprecated
  description: Do not use deprecated params, they will be removed.
  parameters:
  - ServiceNetMapDeprecatedMapping

resources:
  ServiceNetMapValue:
    type: OS::Heat::Value
    properties:
      type: json
      value:
        map_merge:
          - map_replace:
             - {get_param: ServiceNetMapDefaults}
             - values:
{%- for network in networks if network.enabled|default(true) %}
                 {{network.name_lower}}: {get_param: {{network.name}}NetName}
{%- endfor %}
          - map_replace:
             - {get_param: ServiceNetMap}
             - keys: {get_param: ServiceNetMapDeprecatedMapping}

  VipSubnetMapValue:
    type: OS::Heat::Value
    properties:
      type: json
      value:
        map_merge:
          # (hjensas): We need to map_replace the ctlplane-subnet to support
          # legacy parameter ControlPlaneSubnet.
          - map_replace:
            - {get_param: VipSubnetMapDefaults}
            - values:
                ctlplane-subnet: {get_param: ControlPlaneSubnet}
          - {get_param: VipSubnetMap}

outputs:
  service_net_map:
    value: {get_attr: [ServiceNetMapValue, value]}

  service_net_map_lower:
    value:
      # This does a conversion from CamelCase to snake_case,
      # e.g HeatApiNetwork becomes heat_api_network so it
      # matches the service names.
      yaql:
        expression: dict($.data.map.items().select([ regex(`([a-z0-9])([A-Z])`).replace($[0], '\\1_\\2').toLower(), $[1]]))
        data:
          map: {get_attr: [ServiceNetMapValue, value]}

  vip_subnet_map:
    value: {get_attr: [VipSubnetMapValue, value]}
