{%- if ipv6_override is not defined %}
{%- set ipv6_override = false %}
{%- endif %}
heat_template_version: wallaby

description: >
  {{network.name}} network definition (automatically generated).

parameters:
  # the defaults here work for static IP assignment (IPAM) only
  {{network.name}}NetCidr:
{%- if network.ipv6|default(false) or ipv6_override %}
    default: "{{network.ipv6_subnet|default(network.ip_subnet|default(""))}}"
{%- else %}
    default: "{{network.ip_subnet|default("")}}"
{%- endif %}
    description: Cidr for the {{network.name_lower}} network.
    type: string
  {{network.name}}NetValueSpecs:
    default: {'provider:physical_network': '{{network.name_lower}}', 'provider:network_type': 'flat'}
    description: Value specs for the {{network.name_lower}} network.
    type: json
  {{network.name}}NetEnableDHCP:
    default: false
    description: Whether to enable DHCP on the associated subnet.
    type: boolean
  {{network.name}}NetAdminStateUp:
    default: false
    description: The admin state of the network.
    type: boolean
  {{network.name}}NetShared:
    default: false
    description: Whether this network is shared across all tenants.
    type: boolean
  {{network.name}}NetName:
    default: {{network.name_lower}}
    description: The name of the {{network.name_lower}} network.
    type: string
  {{network.name}}SubnetName:
    default: {{network.name_lower}}_subnet
    description: The name of the {{network.name_lower}} subnet in Neutron.
    type: string
  {{network.name}}AllocationPools:
{%- if ":" in network.ip_subnet|default("") or network.ipv6|default(false) or ipv6_override %}
    default: {{network.ipv6_allocation_pools|default(network.allocation_pools|default([]))}}
{%- else %}
    default: {{network.allocation_pools|default([])}}
{%- endif %}
    description: Ip allocation pool range for the {{network.name_lower}} network.
    type: json
{%- if ":" in network.ip_subnet|default("") or network.ipv6|default(false) or ipv6_override %}
  IPv6AddressMode:
    default: dhcpv6-stateful
    description: Neutron subnet IPv6 address mode
    type: string
  IPv6RAMode:
    default: dhcpv6-stateful
    description: Neutron subnet IPv6 router advertisement mode
    type: string
{%- endif %}
  {{network.name}}InterfaceDefaultRoute:
{%- if network.ipv6|default(false) or ipv6_override %}
    default: "{{network.gateway_ipv6|default(network.gateway_ip|default(''))}}"
{%- else %}
    default: "{{network.gateway_ip|default('')}}"
{%- endif %}
    description: default route for the {{network.name_lower}} network
    type: string
  {{network.name}}NetworkVlanID:
    default: {{network.vlan|default(1)}}
    description: Vlan ID for the {{network.name_lower}} network traffic.
    type: number
  {{network.name}}Routes:
    default: {{network.routes|default([])}}
    description: >
      Routes for the {{network.name_lower}} network traffic.
      JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
      Routes are added to the host_routes property on the subnet in neutron
      when the network and subnet is created.
    type: json
  {{network.name}}Mtu:
    default: {{network.mtu|default('1500')}}
    description: The maximum transmission unit (MTU) size(in bytes) that is
      guaranteed to pass through the data path of the segments in the
      {{network.name}} network.
    type: number
{%- for subnet in network.subnets|default({}) if network.subnets[subnet].enabled|default(true) %}
  {{network.name}}SubnetCidr_{{subnet}}:
{%-     if network.ipv6|default(false) or ipv6_override %}
    default: "{{network.subnets[subnet]['ipv6_subnet']|default(network.subnets[subnet]['ip_subnet']|default(""))}}"
{%-     else %}
    default: "{{network.subnets[subnet]['ip_subnet']|default("")}}"
{%-     endif %}
    description: |
      Cidr for the {{network.name_lower}} network's {{subnet}} subnet.
    type: string
  {{network.name}}AllocationPools_{{subnet}}:
{%-     if network.ipv6|default(false) or ipv6_override or ":" in network.subnets[subnet]['ip_subnet'] %}
    default: {{network.subnets[subnet]['ipv6_allocation_pools']|default(network.subnets[subnet]['allocation_pools']|default([]))}}
{%-     else %}
    default: {{network.subnets[subnet]['allocation_pools']|default([])}}
{%-     endif %}
    description: |
      Ip allocation pool range for the {{network.name_lower}} network's {{subnet}} subnet.
    type: json
  {{network.name}}InterfaceDefaultRoute_{{subnet}}:
{%-     if network.ipv6|default(false) or ipv6_override or ":" in network.subnets[subnet]['ip_subnet'] %}
    default: "{{network.subnets[subnet]['gateway_ipv6']|default(network.subnets[subnet]['gateway_ip']|default([]))}}"
{%-     else %}
    default: "{{network.subnets[subnet]['gateway_ip']|default([])}}"
{%-     endif %}
    description: |
       default route for the {{network.name_lower}} network's {{subnet}} subnet.
    type: string
  {{network.name}}NetworkVlanID_{{subnet}}:
    default: {{network.subnets[subnet]['vlan']|default(1)}}
    description: |
      Vlan ID for the {{network.name_lower}} network's {{subnet}} subnet.
    type: number
  {{network.name}}Routes_{{subnet}}:
    default: {{network.subnets[subnet]['routes']|default([])}}
    description: >
      Routes for the {{subnet}} subnet on {{network.name_lower}} network
      traffic. JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
      Routes are added to the host_routes property on the subnet in neutron
      when the subnet is created.
    type: json
{%- endfor %}
  ManageNetworks:
    default: true
    type: boolean
    description: >
      Manage the network and related resources (subnets and segments) with
      either create, update, or delete operations (depending on the stack
      operation). Does not apply to ports which will always be managed as
      needed. Defaults to true. For multi-stack use cases where the network
      related resources have already been managed by a separate stack, this
      parameter can be set to false.
  CloudDomain:
    default: 'localdomain'
    type: string
    description: >
      The DNS domain used for the hosts. This must match the
      overcloud_domain_name configured on the undercloud.
  NetworkDeletionPolicy:
    description: >
      Whether to retain or delete network resource on deletion of the stack
    type: string
    default: delete
    constraints:
      - allowed_values: [delete, retain]


conditions:
  manage_networks: {get_param: ManageNetworks}
  is_ipv6:
    yaql:
      expression: '":" in $.data'
      data: {get_param: {{network.name}}NetCidr}

resources:
  {{network.name}}Network:
    type: OS::Neutron::Net
    deletion_policy: {get_param: NetworkDeletionPolicy}
    condition: manage_networks
{%- if network.external_resource_network_id|default('') %}
    external_id: {{ network.external_resource_network_id }}
{%- endif %}
    properties:
      admin_state_up: {get_param: {{network.name}}NetAdminStateUp}
      name: {get_param: {{network.name}}NetName}
      dns_domain:
        list_join:
          - '.'
          - - {{network.name.lower() | replace("_", "-")}}
            - {get_param: CloudDomain}
            - ''
      shared: {get_param: {{network.name}}NetShared}
      value_specs:
        map_merge:
          - {get_param: {{network.name}}NetValueSpecs}
          - {'mtu': {get_param: {{network.name}}Mtu}}
      tags:
        - tripleo_net_idx={{network.idx}}
        - tripleo_network_name={{network.name}}
        - tripleo_vip={{network.vip|default(false)}}
{%- if network.service_net_map_replace|default('') %}
        - tripleo_service_net_map_replace={{network.service_net_map_replace}}
{%- endif %}
{%- if network.ipv6|default(false) or ipv6_override %}
        - tripleo_ipv6=true
{%- endif %}

  {{network.name}}Subnet:
    type: OS::Neutron::Subnet
    deletion_policy: {get_param: NetworkDeletionPolicy}
    condition: manage_networks
{%- if network.external_resource_subnet_id|default('') %}
    external_id: {{ network.external_resource_subnet_id }}
{%- endif %}
    properties:
      cidr: {get_param: {{network.name}}NetCidr}
      name: {get_param: {{network.name}}SubnetName}
      network: {get_resource: {{network.name}}Network}
      allocation_pools: {get_param: {{network.name}}AllocationPools}
      gateway_ip: {get_param: {{network.name}}InterfaceDefaultRoute}
      host_routes: {get_param: {{network.name}}Routes}
      # All networks have an implicit network segment when created, map this subnet to that segment.
      segment: {get_attr: [{{network.name}}Network, segments, 0, id]}
      ip_version: {if: [is_ipv6, 6, 4]}
{%- if network.ipv6|default(false) or ipv6_override or ":" in network.ip_subnet|default("") %}
      ipv6_address_mode: {get_param: IPv6AddressMode}
      ipv6_ra_mode: {get_param: IPv6RAMode}
{%- else %}
      enable_dhcp: {get_param: {{network.name}}NetEnableDHCP}
{%- endif %}
      tags:
        - str_replace:
            template: tripleo_vlan_id=$vlan_id
            params:
              $vlan_id: {get_param: {{network.name}}NetworkVlanID}


{% for subnet in network.subnets|default({}) if network.subnets[subnet].enabled|default(true) %}
  {{network.name}}Segment_{{subnet}}:
    type: OS::Neutron::Segment
    deletion_policy: {get_param: NetworkDeletionPolicy}
    condition: manage_networks
    # NOTE(hjensas): Depends-On here to ensure we always create the base subnet
    #   first. We can only set the segment for existing subnet if there is only
    #   one segment and only one existing subnet on the network.
{%- if network.subnets[subnet].external_resource_segment_id|default('') %}
    external_id: {{ network.subnets[subnet].external_resource_segment_id }}
{%- else %}
    depends_on: {{network.name}}Subnet
{%- endif %}
    properties:
      name: {{network.name_lower}}_{{subnet}}
      network: {get_resource: {{network.name}}Network}
      network_type: flat
      physical_network: {{network.name_lower}}_{{subnet}}

  {{network.name}}Subnet_{{subnet}}:
    type: OS::Neutron::Subnet
    deletion_policy: {get_param: NetworkDeletionPolicy}
    condition: manage_networks
{%- if network.subnets[subnet].external_resource_subnet_id|default('') %}
    external_id: {{ network.subnets[subnet].external_resource_subnet_id }}
{%- endif %}
    properties:
      cidr: {get_param: {{network.name}}SubnetCidr_{{subnet}}}
      name: {{subnet}}
      network: {get_resource: {{network.name}}Network}
      allocation_pools: {get_param: {{network.name}}AllocationPools_{{subnet}}}
      gateway_ip: {get_param: {{network.name}}InterfaceDefaultRoute_{{subnet}}}
      host_routes: {get_param: {{network.name}}Routes_{{subnet}}}
      segment: {get_resource: {{network.name}}Segment_{{subnet}}}
      ip_version: {if: [is_ipv6, 6, 4]}
{%- if network.ipv6|default(false) or ipv6_override or ":" in network.ip_subnet|default("") %}
      ipv6_address_mode: {get_param: IPv6AddressMode}
      ipv6_ra_mode: {get_param: IPv6RAMode}
{%- else %}
      enable_dhcp: {get_param: {{network.name}}NetEnableDHCP}
{%- endif %}
      tags:
        - str_replace:
            template: tripleo_vlan_id=$vlan_id
            params:
              $vlan_id: {get_param: {{network.name}}NetworkVlanID_{{subnet}}}

{% endfor %}

outputs:
  OS::stack_id:
    description: {{network.name_lower}} network
    value: {get_resource: {{network.name}}Network}
  ip_version:
    description: IP version of {{network.name}} network.
    value: {if: [is_ipv6, 6, 4]}
  network_cidrs:
    description: List of {{network.name}} network's subnets in CIDR notation.
    value:
      if:
        - manage_networks
        - - {get_attr: [{{network.name}}Subnet, cidr]}
{%- for subnet in network.subnets|default({}) if network.subnets[subnet].enabled|default(true) %}
          - {get_attr: [{{network.name}}Subnet_{{subnet}}, cidr]}
{%- endfor %}
        - - {get_param: {{network.name}}NetCidr}
{%- for subnet in network.subnets|default({}) if network.subnets[subnet].enabled|default(true) %}
          - {get_param: {{network.name}}SubnetCidr_{{subnet}}}
{%- endfor %}

  network_attrs:
    description: {{network.name}} network's attributes
    value:
      if:
        - manage_networks
        - {get_attr: [{{network.name}}Network, show]}
        - name: {{network.name_lower}}
          dns_domain:
            list_join:
            - '.'
            - - {{network.name.lower() | replace("_", "-")}}
              - {get_param: CloudDomain}
              - ''
          mtu: {{network.mtu|default('1500')}}

  subnet_attrs:
    description: Map of attributes for subnets in the {{network.name}} network
    value:
      if:
        - manage_networks
        - {{network.name_lower}}_subnet: {get_attr: [{{network.name}}Subnet, show]}
{%- for subnet in network.subnets|default({}) if network.subnets[subnet].enabled|default(true) %}
          {{subnet}}: {get_attr: [{{network.name}}Subnet_{{subnet}}, show]}
{%- endfor %}
        - {{network.name_lower}}_subnet:
            name: {{network.name_lower}}_subnet
            cidr: {get_param: {{network.name}}NetCidr}
            dns_nameservers: []
            gateway_ip: {get_param: {{network.name}}InterfaceDefaultRoute}
            host_routes: {get_param: {{network.name}}Routes}
            ip_version: {if: [is_ipv6, 6, 4]}
{%- for subnet in network.subnets|default({}) if network.subnets[subnet].enabled|default(true) %}
          {{subnet}}:
            name: {{subnet}}
            cidr: {get_param: {{network.name}}SubnetCidr_{{subnet}}}
            dns_nameservers: []
            gateway_ip: {get_param: {{network.name}}InterfaceDefaultRoute_{{subnet}}}
            host_routes: {get_param: {{network.name}}Routes_{{subnet}}}
            ip_version: {if: [is_ipv6, 6, 4]}
{%- endfor %}
