#  Licensed under the Apache License, Version 2.0 (the "License"); you may
#  not use this file except in compliance with the License. You may obtain
#  a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#  License for the specific language governing permissions and limitations
#  under the License.

Namespaces:
  =: io.murano.resources
  std: io.murano
  sys: io.murano.system

Name: NeutronNetwork

Extends: NeutronNetworkBase

Properties:
  name:
    Contract: $.string().notNull()

  externalRouterId:
    Contract: $.string()
    Usage: InOut

  autoUplink:
    Contract: $.bool().notNull()
    Default: true

  autogenerateSubnet:
    Contract: $.bool().notNull()
    Default: true

  openstackId:
    Contract: $.string()
    Usage: Out

  subnetCidr:
    Contract: $.string()
    Usage: InOut

  dnsNameservers:
    # This property is optional,
    # since neutron default dns will be used in case of empty
    Contract: [$.string()]
    Usage: InOut

Methods:
  initialize:
    Body:
      - $._environment: $.find(std:Environment).require()
      - $._netExplorer: new(sys:NetworkExplorer, $._environment)


  deploy:
    Body:
      - If: not $.getAttr(deployed, false)
        Then:
          - If: len($.dnsNameservers) = 0
            Then:
              - $.dnsNameservers: $._netExplorer.getDefaultDns()
          - $template: $._createNetwork()
          - If: $.autoUplink and (not bool($.externalRouterId))
            Then:
              - $.externalRouterId: $._netExplorer.getDefaultRouter()
          - If: $.autogenerateSubnet and (not bool($.subnetCidr))
            Then:
              - $.subnetCidr: $._netExplorer.getAvailableCidr($.externalRouterId, $.id())

          - $template: $template.mergeWith($._createSubnet())
          - If: $.externalRouterId != null
            Then:
              - $template: $template.mergeWith($._createRouterInterface())

          - $._environment.stack.updateTemplate($template)
          - $._environment.stack.push()
          - $outputs: $._environment.stack.output()
          - $.openstackId: $outputs.get(format('{0}-id', $this.name))
          - $.setAttr(deployed, true)


  _createNetwork:
    Body:
      - $netName: $._getNetworkName()
      - $template:
          resources:
            $netName:
              type: 'OS::Neutron::Net'
              properties:
                name: format('{0}-{1}', $.name, $.id())
          outputs:
            format('{0}-id', $.name):
              description: format('ID of {0} network', $.name)
              value:
                get_resource: $netName
      - Return: $template


  _createSubnet:
    Body:
      - Return:
          resources:
            $._getSubnetName():
              type: 'OS::Neutron::Subnet'
              properties:
                network: { get_resource: $._getNetworkName() }
                ip_version: 4
                dns_nameservers: $.dnsNameservers
                cidr: $.subnetCidr


  _createRouterInterface:
    Body:
      - Return:
          resources:
            $._getRouterInterfaceName():
              type: 'OS::Neutron::RouterInterface'
              properties:
                router_id: $.externalRouterId
                subnet: { get_resource: $._getSubnetName() }


  joinInstance:
    Arguments:
      - instance:
          Contract: $.class(Instance).notNull()
      - securityGroupName:
          Contract: $.string()
      - assignFloatingIp:
          Contract: $.bool().notNull()
      - sharedIps:
          Contract:
            - $.class(std:SharedIp)
    Body:
      - $.deploy()
      - $netRef: { get_resource: $._getNetworkName() }
      - $subnetRef: { get_resource: $._getSubnetName() }
      - $extNetId: null
      - $fipName: null
      - If: $assignFloatingIp
        Then:
          - $extNetId: $._getExternalNetId()
          - $fipName: format('fip-{0}-{1}', $.id(), $instance.name)

      - $result: $.joinInstanceToNetwork(
            instance => $instance,
            securityGroupName => $securityGroupName,
            sharedIps => $sharedIps,
            netRef => $netRef,
            subnetRef => $subnetRef,
            floatingIpResourceName => $fipName,
            floatingIpNetRef => $extNetId
          )

      # (sjmc7) This is a workaround for https://bugs.launchpad.net/heat/+bug/1299259
      - If: $externalRouterId != null
        Then:
          - $template:
              resources:
                $fipName:
                  depends_on:
                    - $._getRouterInterfaceName()
          - $result.template: $result.template.mergeWith($template)

      - Return: $result


  describe:
    Body:
      - $.deploy()
      - $subnet: $._netExplorer.listSubnetworks().where(
            $.network_id = $this.openstackId).first()
      - Return:
          provider: Neutron
          netName: $.name
          netId: $.openstackId
          subnetId: $subnet.id
          cidr: $subnet.cidr
          dns: $subnet.dns_nameservers
          gateway: $subnet.gateway_ip
          floatingIpNetId: $._getExternalNetId()

  releaseResources:
    Body:
      - $template: $.environment.stack.current()

      - $template.resources: $template.resources.delete(format('{0}-{1}', $.name, $.id()))
      - $template.resources: $template.resources.delete($._getSubnetName())

      - $template.outputs: $template.outputs.delete(format('{0}-id', $.name))

      - If: $.externalRouterId != null
        Then:
          $template.resources: $template.resources.delete($._getRouterInterfaceName())

      - $._environment.stack.setTemplate($template)
      - $._environment.stack.push()
      - $.openstackId: null


  _getRouterInterfaceName:
    Body:
      Return: format('ri-{0}', $.id())


  _getNetworkName:
    Body:
      Return: format('network-{0}', $.id())


  _getSubnetName:
    Body:
      Return: format('subnet-{0}', $.id())


  _getExternalNetId:
    Body:
      Return: $._netExplorer.getExternalNetworkIdForRouter($.externalRouterId)
