#!/bin/bash

# Idempotent script to apply heat configuration to the running network
# environment.
#
# NOTE: this script uses Heat parameters to define the physical
# network setup for TripleO. If 'os_net_config' metadata is detected
# it is assumed that Heat metadata is modeling the configuration directly
# and this script does nothing. This is meant to provide an easy way
# to select between the two configuration methods via Heat (parameters vs
# os-net-config modeling).
#
# If a public_interface_raw_device is defined in metadata and public_interface
# does not exist, the public_interface is used to derived a vlan id and a vlan
# interface is configured.
#
# If a bootstrap public_interface_ip is defined in metadata and not attached to
# any device then it will be added to the public_interface device if one is
# defined.
#
# An integration bridge for neutron-ovs-agent is created.
#
# If no physical bridge is defined in metadata, the script will have no
# further effect.
#
# If a physical bridge is defined then os-net-config is called to set it up.
#
# If there is configuration (tag + IP) for an access port, one is created on
# top of the bridge, again by os-net-config.

set -eux

PATH=/usr/local/bin:$PATH

EXTERNAL_BRIDGE=$(os-apply-config --key neutron.ovs.physical_bridge --type raw --key-default '')
PHYSICAL_INTERFACE=$(os-apply-config --key neutron.ovs.public_interface --type raw  --key-default '')
PHYSICAL_INTERFACE_IP=$(os-apply-config --key bootstack.public_interface_ip --type netaddress  --key-default '')
PUBLIC_INTERFACE_ROUTE=$(os-apply-config --key neutron.ovs.public_interface_route --type netaddress --key-default '')
# TAG is type raw because we can't do an absent key as a default in Heat, and '' is not an int.
PUBLIC_INTERFACE_TAG=$(os-apply-config --key neutron.ovs.public_interface_tag --type raw --key-default '')
PUBLIC_INTERFACE_TAG_IP=$(os-apply-config --key neutron.ovs.public_interface_tag_ip --type netaddress --key-default '')
PHYSICAL_ROUTE_PREFIX=$(os-apply-config --key neutron.ovs.physical_bridge_route.prefix --type netaddress --key-default '')
PHYSICAL_ROUTE_VIA=$(os-apply-config --key neutron.ovs.physical_bridge_route.via --type netaddress --key-default '')
NET_CONFIG=$(os-apply-config --key os_net_config --type raw --key-default '')

if [ -n "$NET_CONFIG" ]; then
    echo "Skipping init-neutron-ovs because os-net-config data detected."
    exit 0
fi

if [ -z "$EXTERNAL_BRIDGE" ] ; then
    exit 0
fi

cat > /etc/os-net-config/neutron-openvswitch-agent.conf <<EOF_CAT
# This file is autogenerated by init-neutron-ovs (an os-refresh-config script).
# Users should use os-apply-config parameters (provided by Heat parameters) to
# control these settings.
network_config:
  - type: ovs_bridge
    name: br-int
    ovs_extra:
      - br-set-external-id br-int bridge-id br-int
  - type: ovs_bridge
    name: $EXTERNAL_BRIDGE
    ovs_extra:
      - br-set-external-id $EXTERNAL_BRIDGE bridge-id $EXTERNAL_BRIDGE
    members:
      - type: interface
        name: $PHYSICAL_INTERFACE
        # force the MAC address of the bridge to this interface
        primary: true
EOF_CAT

function append_config {
    echo "$1" >> /etc/os-net-config/neutron-openvswitch-agent.conf
}

if [ -n "$PHYSICAL_INTERFACE_IP" ]; then
    append_config "    addresses:"
    append_config "      - ip_netmask: $PHYSICAL_INTERFACE_IP"
fi

if [ -n "$PUBLIC_INTERFACE_TAG" -a -n "$PUBLIC_INTERFACE_TAG_IP" ]; then
    # handle tagged (public VLAN) traffic to the bridge
cat >> /etc/os-net-config/neutron-openvswitch-agent.conf <<EOF_CAT
      - type: vlan
        vlan_id: $PUBLIC_INTERFACE_TAG
        addresses:
          - ip_netmask: $PUBLIC_INTERFACE_TAG_IP
EOF_CAT
fi

if [ -z "$PHYSICAL_INTERFACE_IP" ]; then
    append_config "    use_dhcp: true"
fi

# begin routes for the EXTERNAL_BRIDGE
append_config "    routes:"

if [ -n "$PHYSICAL_ROUTE_PREFIX" -a -n "$PHYSICAL_ROUTE_VIA" ]; then
    # Add a route to the bridge, e.g. to the IPMI network.
    append_config "      - next_hop: $PHYSICAL_ROUTE_VIA"
    append_config "        ip_netmask: $PHYSICAL_ROUTE_PREFIX"
fi

if [ -n "$PUBLIC_INTERFACE_ROUTE" ]; then
    # A default route for the bridge
    append_config "      - next_hop: $PUBLIC_INTERFACE_ROUTE"
    append_config "        default: true"

    METADATA_ROUTE_VIA=$(ip route show 169.254.169.254 | awk '{ print $3 }')
    if [ -n $"METADATA_ROUTE_VIA" ]; then
        # an explicit route for 169.254.169.254 (metadata server)
        append_config "      - next_hop: $METADATA_ROUTE_VIA"
        append_config "        ip_netmask: 169.254.169.254/32"
    fi
fi

os-net-config -c /etc/os-net-config/neutron-openvswitch-agent.conf -v
