Merge pull request #12 from tgerdes/driver-alias-names

Load Interface and Firewall drivers by name
diff --git a/.kitchen.travis.yml b/.kitchen.travis.yml
new file mode 100644
index 0000000..f847543
--- /dev/null
+++ b/.kitchen.travis.yml
@@ -0,0 +1,6 @@
+suites:
+
+  - name: <%= ENV['SUITE'] %>
+    provisioner:
+      pillars-from-files:
+        neutron.sls: tests/pillar/<%= ENV['SUITE'] %>.sls
diff --git a/.travis.yml b/.travis.yml
index 7a77247..3925301 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,15 +17,35 @@
   - bundle install
 
 env:
-    - PLATFORM=trevorj/salty-whales:trusty
-    - PLATFORM=trevorj/salty-whales:xenial
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=compute_dpdk
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=compute_dpdk
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=compute_dvr
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=compute_dvr
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=compute_legacy
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=compute_legacy
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=compute_nonexternal_dvr
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=compute_nonexternal_dvr
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=compute_sriov
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=compute_sriov
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=control_cluster
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=control_cluster
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=control_dvr
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=control_dvr
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=control_nodvr
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=control_nodvr
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=control_single
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=control_single
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=gateway_dvr
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=gateway_dvr
+    - PLATFORM=trevorj/salty-whales:trusty SUITE=gateway_legacy
+    - PLATFORM=trevorj/salty-whales:xenial SUITE=gateway_legacy
 
 before_script:
   - set -o pipefail
   - make test | tail
 
 script:
-  - test ! -e .kitchen.yml || bundle exec kitchen test -t tests/integration
+  - KITCHEN_LOCAL_YAML=.kitchen.travis.yml bundle exec kitchen test -t tests/integration
 
 notifications:
   webhooks:
diff --git a/README.rst b/README.rst
index e8e633f..56f1b51 100644
--- a/README.rst
+++ b/README.rst
@@ -514,6 +514,22 @@
             use_ovs_ports:
             - float-to-ex
 
+Additonal VXLAN tenant network settings
+---------------------------------------
+
+The default multicast group of 224.0.0.1 only multicasts to a single subnet.
+Allow overriding it to allow larger underlay network topologies.
+
+Neutron Server
+
+.. code-block:: yaml
+
+    neutron:
+      server:
+        vxlan:
+          group: 239.0.0.0/8
+          vni_ranges: "2:65535"
+
 Neutron VLAN tenant networks with Network Nodes
 -----------------------------------------------
 
diff --git a/_modules/neutronng.py b/_modules/neutronng.py
index 652e612..6a3eaf8 100644
--- a/_modules/neutronng.py
+++ b/_modules/neutronng.py
@@ -34,7 +34,7 @@
         '''
         Authenticate request and format return data
         '''
-        connection_args = {'profile': kwargs.get('profile', None)}
+        connection_args = {'profile': kwargs.pop('profile', None)}
         nkwargs = {}
         for kwarg in kwargs:
             if 'connection_' in kwarg:
@@ -55,6 +55,8 @@
         neutron_interface = client.Client(
             endpoint_url=endpoint, token=token)
         return_data = func_name(neutron_interface, *args, **nkwargs)
+        # TODO(vsaienko) drop this formatting when all commands are updated
+        # to return dictionary
         if isinstance(return_data, list):
             # format list as a dict for rendering
             return {data.get('name', None) or data['id']: data
@@ -69,7 +71,7 @@
     list all floatingips
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.list_floatingips
+        salt '*' neutronng.list_floatingips
     '''
     return neutron_interface.list_floatingips(**kwargs)['floatingips']
 
@@ -80,7 +82,7 @@
     list all security_groups
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.list_security_groups
+        salt '*' neutronng.list_security_groups
     '''
     return neutron_interface.list_security_groups(**kwargs)['security_groups']
 
@@ -91,9 +93,9 @@
     list all subnets
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.list_subnets
+        salt '*' neutronng.list_subnets
     '''
-    return neutron_interface.list_subnets(**kwargs)['subnets']
+    return neutron_interface.list_subnets(**kwargs)
 
 
 @_autheticate
@@ -102,9 +104,9 @@
     list all networks
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.list_networks
+        salt '*' neutronng.list_networks
     '''
-    return neutron_interface.list_networks(**kwargs)['networks']
+    return neutron_interface.list_networks(**kwargs)
 
 
 @_autheticate
@@ -113,7 +115,7 @@
     list all ports
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.list_ports
+        salt '*' neutronng.list_ports
     '''
     return neutron_interface.list_ports(**kwargs)['ports']
 
@@ -124,7 +126,7 @@
     list all routers
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.list_routers
+        salt '*' neutronng.list_routers
     '''
     return neutron_interface.list_routers(**kwargs)['routers']
 
@@ -136,9 +138,9 @@
     CLI Example:
     .. code-block:: bash
         to associate with an instance's port
-        salt '*' neutron.update_floatingip openstack-floatingip-id port-id
+        salt '*' neutronng.update_floatingip openstack-floatingip-id port-id
         to disassociate from an instance's port
-        salt '*' neutron.update_floatingip openstack-floatingip-id
+        salt '*' neutronng.update_floatingip openstack-floatingip-id
     '''
     neutron_interface.update_floatingip(fip, {"floatingip":
                                               {"port_id": port_id}})
@@ -150,9 +152,9 @@
     update given subnet
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.update_subnet openstack-subnet-id name='new_name'
+        salt '*' neutronng.update_subnet openstack-subnet-id name='new_name'
     '''
-    neutron_interface.update_subnet(subnet_id, {'subnet': subnet_params})
+    return neutron_interface.update_subnet(subnet_id, {'subnet': subnet_params})
 
 
 @_autheticate
@@ -161,7 +163,7 @@
     Update give network
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.update_network openstack-net-id admin_state_up=false
+        salt '*' neutronng.update_network openstack-net-id admin_state_up=false
     '''
     network_params = {}
     for param in net_params:
@@ -170,7 +172,7 @@
         else:
             network_params[param] = net_params[param]
     LOG.info('ATTRIBUTES ' + str(network_params))
-    neutron_interface.update_network(network_id, {'network': network_params})
+    return neutron_interface.update_network(network_id, {'network': network_params})
 
 
 @_autheticate
@@ -179,7 +181,7 @@
     update given router
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.update_router openstack-router-id name='new_name'
+        salt '*' neutronng.update_router openstack-router-id name='new_name'
             external_gateway='openstack-network-id' administrative_state=true
     '''
     neutron_interface.update_router(router_id, {'router': router_params})
@@ -191,7 +193,7 @@
     Set external gateway for a router
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.update_router openstack-router-id openstack-network-id
+        salt '*' neutronng.update_router openstack-router-id openstack-network-id
     '''
     neutron_interface.update_router(
         router_id, {'router': {'external_gateway_info':
@@ -204,7 +206,7 @@
     Clear external gateway for a router
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.update_router openstack-router-id
+        salt '*' neutronng.update_router openstack-router-id
     '''
     neutron_interface.update_router(
         router_id, {'router': {'external_gateway_info': None}})
@@ -216,7 +218,7 @@
     Create OpenStack Neutron router
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.create_router name=R1
+        salt '*' neutronng.create_router name=R1
     '''
     response = neutron_interface.create_router({'router': router_params})
     if 'router' in response and 'id' in response['router']:
@@ -229,7 +231,7 @@
     Attach router to a subnet
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.router_add_interface openstack-router-id subnet-id
+        salt '*' neutronng.router_add_interface openstack-router-id subnet-id
     '''
     neutron_interface.add_interface_router(router_id, {'subnet_id': subnet_id})
 
@@ -240,7 +242,7 @@
     Dettach router from a subnet
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.router_rem_interface openstack-router-id subnet-id
+        salt '*' neutronng.router_rem_interface openstack-router-id subnet-id
     '''
     neutron_interface.remove_interface_router(
         router_id, {'subnet_id': subnet_id})
@@ -252,7 +254,7 @@
     Create a new security group
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.create_security_group name='new_rule'
+        salt '*' neutronng.create_security_group name='new_rule'
             description='test rule'
     '''
     response = neutron_interface.create_security_group(
@@ -267,7 +269,7 @@
     Create a rule entry for a security group
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.create_security_group_rule
+        salt '*' neutronng.create_security_group_rule
     '''
     neutron_interface.create_security_group_rule(
         {'security_group_rule': rule_params})
@@ -279,7 +281,7 @@
     Create a new floating IP
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.create_floatingip floating_network_id=ext-net-id
+        salt '*' neutronng.create_floatingip floating_network_id=ext-net-id
     '''
     response = neutron_interface.create_floatingip(
         {'floatingip': floatingip_params})
@@ -293,18 +295,11 @@
     Create a new subnet in OpenStack
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.create_subnet name='subnet name'
+        salt '*' neutronng.create_subnet name='subnet name'
             network_id='openstack-network-id' cidr='192.168.10.0/24' \\
-            gateway_ip='192.168.10.1' ip_version='4' enable_dhcp=false \\
-            start_ip='192.168.10.10' end_ip='192.168.10.20'
+            gateway_ip='192.168.10.1' ip_version='4' enable_dhcp=false
     '''
-    if 'start_ip' in subnet_params:
-        subnet_params.update(
-            {'allocation_pools': [{'start': subnet_params.pop('start_ip'),
-                                   'end': subnet_params.pop('end_ip', None)}]})
-    response = neutron_interface.create_subnet({'subnet': subnet_params})
-    if 'subnet' in response and 'id' in response['subnet']:
-        return response['subnet']['id']
+    return neutron_interface.create_subnet({'subnet': subnet_params})
 
 
 @_autheticate
@@ -313,7 +308,7 @@
     Create a new network segment in OpenStack
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.create_network name=External
+        salt '*' neutronng.create_network name=External
             provider_network_type=flat provider_physical_network=ext
     '''
     network_params = {}
@@ -322,9 +317,7 @@
             network_params[param.replace('_', ':', 1)] = net_params[param]
         else:
             network_params[param] = net_params[param]
-    response = neutron_interface.create_network({'network': network_params})
-    if 'network' in response and 'id' in response['network']:
-        return response['network']['id']
+    return neutron_interface.create_network({'network': network_params})
 
 
 @_autheticate
@@ -333,7 +326,7 @@
     Create a new port in OpenStack
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.create_port network_id='openstack-network-id'
+        salt '*' neutronng.create_port network_id='openstack-network-id'
     '''
     response = neutron_interface.create_port({'port': port_params})
     if 'port' in response and 'id' in response['port']:
@@ -346,7 +339,7 @@
     Create a new port in OpenStack
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.update_port name='new_port_name'
+        salt '*' neutronng.update_port name='new_port_name'
     '''
     neutron_interface.update_port(port_id, {'port': port_params})
 
@@ -357,7 +350,7 @@
     delete a floating IP
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.delete_floatingip openstack-floating-ip-id
+        salt '*' neutronng.delete_floatingip openstack-floating-ip-id
     '''
     neutron_interface.delete_floatingip(floating_ip_id)
 
@@ -368,7 +361,7 @@
     delete a security group
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.delete_security_group openstack-security-group-id
+        salt '*' neutronng.delete_security_group openstack-security-group-id
     '''
     neutron_interface.delete_security_group(sg_id)
 
@@ -380,7 +373,7 @@
     to be deleted
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.delete_security_group_rule direction='ingress'
+        salt '*' neutronng.delete_security_group_rule direction='ingress'
             ethertype='ipv4' security_group_id='openstack-security-group-id'
             port_range_min=100 port_range_max=4096 protocol='tcp'
             remote_group_id='default'
@@ -399,7 +392,7 @@
     delete given subnet
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.delete_subnet openstack-subnet-id
+        salt '*' neutronng.delete_subnet openstack-subnet-id
     '''
     neutron_interface.delete_subnet(subnet_id)
 
@@ -410,7 +403,7 @@
     delete given network
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.delete_network openstack-network-id
+        salt '*' neutronng.delete_network openstack-network-id
     '''
     neutron_interface.delete_network(network_id)
 
@@ -421,6 +414,7 @@
     delete given router
     CLI Example:
     .. code-block:: bash
-        salt '*' neutron.delete_router openstack-router-id
+        salt '*' neutronng.delete_router openstack-router-id
     '''
-    neutron_interface.delete_router(router_id)
\ No newline at end of file
+    neutron_interface.delete_router(router_id)
+
diff --git a/_states/neutronng.py b/_states/neutronng.py
index 67a088c..89e0011 100644
--- a/_states/neutronng.py
+++ b/_states/neutronng.py
@@ -5,8 +5,8 @@
 :depends:   - neutronclient Python module
 :configuration: See :py:mod:`salt.modules.neutron` for setup instructions.
 .. code-block:: yaml
-    neutron network present:
-      neutron.network_present:
+    neutronng network present:
+      neutronng.network_present:
         - name: Netone
         - provider_physical_network: PHysnet1
         - provider_network_type: vlan
@@ -41,6 +41,15 @@
 def _neutron_module_call(method, *args, **kwargs):
     return __salt__['neutronng.{0}'.format(method)](*args, **kwargs)
 
+def _get_tenant_id(tenant_name, *args, **kwargs):
+    try:
+        tenant_id = __salt__['keystone.tenant_get'](
+            name=tenant_name, **kwargs)[tenant_name]['id']
+    except:
+        tenant_id = None
+        LOG.debug('Cannot get the tenant id. User {0} is not an admin.'.format(
+            kwargs.get('connection_user')))
+    return tenant_id
 
 def _auth(profile=None, endpoint_type=None):
     '''
@@ -57,13 +66,15 @@
         'connection_password': password,
         'connection_tenant': tenant,
         'connection_auth_url': auth_url,
-        'connection_endpoint_type': endpoint_type
+        'connection_endpoint_type': endpoint_type,
+        'profile': profile
     }
 
     return kwargs
 
 @_test_call
 def network_present(name=None,
+                    network_id=None,
                     tenant=None,
                     provider_network_type=None,
                     provider_physical_network=None,
@@ -78,17 +89,12 @@
     name
         The name of the network to manage
     '''
-    tenant_name = tenant
     connection_args = _auth(profile, endpoint_type)
-    try:
-        tenant_id = __salt__['keystone.tenant_get'](
-            name=tenant_name, **connection_args)[tenant_name]['id']
-    except:
-        tenant_id = None
-        LOG.debug('Cannot get the tenant id. User {0} is not an admin.'.format(
-            connection_args['connection_user']))
-    existing_network = _neutron_module_call(
-        'list_networks', name=name, **connection_args)
+    tenant_id = _get_tenant_id(tenant_name=tenant, **connection_args)
+
+    existing_networks = _neutron_module_call(
+        'list_networks', name=name, tenant_id=tenant_id,
+        **connection_args)['networks']
     network_arguments = _get_non_null_args(
         name=name,
         provider_network_type=provider_network_type,
@@ -99,64 +105,63 @@
         tenant_id=tenant_id,
         provider_segmentation_id=provider_segmentation_id)
 
-    if not existing_network:
+    if len(existing_networks) == 0:
         network_arguments.update(connection_args)
-        _neutron_module_call('create_network', **network_arguments)
-        existing_networks = _neutron_module_call(
-            'list_networks',name=name, **connection_args)
-        for network in existing_networks:
-            if network.get(name) == name:
-                existing_network = network
-        if existing_network:
-            return _created(name, 'network', existing_network[name])
-        return _update_failed(name, 'network')
+        res = _neutron_module_call(
+            'create_network', **network_arguments)['network']
 
-    LOG.info('CONNECTION STRINGS' + str(connection_args))
-    LOG.info('existing ' + str(existing_network))
-    LOG.info('new ' + str(network_arguments))
-    existing_network = dict((key.replace(':', '_', 1), value)
-                            for key, value in
-                            existing_network[name].iteritems())
-    # generate differential
-    diff = dict((key, value) for key, value in network_arguments.iteritems()
-                if existing_network.get(key, None) != value)
-    if diff:
-        # update the changes
-        network_arguments = diff.copy()
-        network_arguments.update(connection_args)
-        try:
-            LOG.debug('updating network {0} with changes {1}'.format(
-                name, str(diff)))
-            _neutron_module_call('update_network',
-                                 existing_network['id'],
-                                 **network_arguments)
-            changes_dict = _created(name, 'network', diff)
-            changes_dict['comment'] = '{1} {0} updated'.format(name, 'network')
-            return changes_dict
-        except:
-            LOG.exception('Could not update network {0}'.format(name))
-            return _update_failed(name, 'network')
-    return _no_change(name, 'network')
+        if res.get('name') == name:
+            return _created(name, 'network', res['name'])
+
+    elif len(existing_networks) > 1:
+        LOG.error("More than one network found with the name: {0}".format(
+                  name))
+
+    elif len(existing_networks) == 1:
+        existing_network = existing_networks[0]
+        LOG.info('CONNECTION STRINGS' + str(connection_args))
+        LOG.info('existing ' + str(existing_network))
+        LOG.info('new ' + str(network_arguments))
+        existing_network = dict((key.replace(':', '_', 1), value)
+                                for key, value in
+                                existing_network.iteritems())
+        # generate differential
+        diff = dict((key, value) for key, value in network_arguments.iteritems()
+                    if existing_network.get(key, None) != value)
+        if diff:
+            # update the changes
+            network_arguments = diff.copy()
+            network_arguments.update(connection_args)
+            try:
+                LOG.debug('updating network {0} with changes {1}'.format(
+                    name, str(diff)))
+                _neutron_module_call('update_network',
+                                     existing_network['id'],
+                                     **network_arguments)
+                changes_dict = _created(name, 'network', diff)
+                changes_dict['comment'] = '{1} {0} updated'.format(name, 'network')
+                return changes_dict
+            except:
+                LOG.error('Could not update network {0}'.format(name))
+                return _update_failed(name, 'network')
+        return _no_change(name, 'network')
+    return _create_failed(name, 'network')
 
 
 @_test_call
-def network_absent(name, profile=None,endpoint_type=None):
+def network_absent(name, network_id=None, profile=None, endpoint_type=None):
     connection_args = _auth(profile, endpoint_type)
-    existing_network = _neutron_module_call(
-        'list_networks', name=name, **connection_args)
-    if existing_network:
-        _neutron_module_call(
-            'delete_network', existing_network[name]['id'], **connection_args)
-        if _neutron_module_call('list_networks', name=name, **connection_args):
-            return _delete_failed(name, 'network')
-        return _deleted(name, 'network', existing_network[name])
-    return _absent(name, 'network')
+    identifier = network_id or name
+    _neutron_module_call(
+        'delete_network', identifier, **connection_args)
+    return _absent(identifier, 'network')
 
 
 @_test_call
-def subnet_present(name=None,
+def subnet_present(name,
+                   network_name=None,
+                   network_id=None,
                    tenant=None,
-                   network=None,
                    cidr=None,
                    ip_version=4,
                    enable_dhcp=True,
@@ -171,20 +176,19 @@
     name
         The name of the subnet to manage
     '''
+    if network_name is None and network_id is None:
+        LOG.error("Network identificator name or uuid should be provided.")
+        return _create_failed(name, 'subnet')
+
     connection_args = _auth(profile, endpoint_type)
-    tenant_name = tenant
-    try:
-        tenant_id = __salt__['keystone.tenant_get'](
-            name=tenant_name, **connection_args)[tenant_name]['id']
-    except:
-        tenant_id = None
-        LOG.debug('Cannot get the tenant id. User {0} is not an admin.'.format(
-            connection_args['connection_user']))
-    existing_subnet = _neutron_module_call(
-        'list_subnets', tenant_id=tenant_id, name=name, **connection_args)
+    tenant_id = _get_tenant_id(tenant_name=tenant, **connection_args)
+
+    existing_subnets = _neutron_module_call(
+        'list_subnets', tenant_id=tenant_id, name=name,
+         **connection_args)['subnets']
+
     subnet_arguments = _get_non_null_args(
         name=name,
-        network=network,
         cidr=cidr,
         ip_version=ip_version,
         enable_dhcp=enable_dhcp,
@@ -192,29 +196,43 @@
         gateway_ip=gateway_ip,
         dns_nameservers=dns_nameservers,
         host_routes=host_routes)
-    # replace network with network_id
-    if 'network' in subnet_arguments:
-        network = subnet_arguments.pop('network', None)
-        existing_network = _neutron_module_call(
-            'list_networks', tenant_id=tenant_id, name=network, **connection_args)
-        if existing_network:
-            subnet_arguments['network_id'] = existing_network[network]['id']
-    if not existing_subnet:
+
+    if network_id is None and network_name:
+        existing_networks = _neutron_module_call(
+            'list_networks', tenant_id=tenant_id, name=network_name,
+            **connection_args)['networks']
+        if len(existing_networks) == 0:
+            LOG.error("Can't find network with name: {0}".format(network_name))
+        elif len(existing_networks) == 1:
+            network_id = existing_networks[0]['id']
+        elif len(existing_networks) > 1:
+            LOG.error("Multiple networks with name: {0} found.".format(
+                      network_name))
+
+    if network_id is None:
+        return _create_failed(name, 'subnet')
+
+    subnet_arguments['network_id'] = network_id
+
+    if len(existing_subnets) == 0:
         subnet_arguments.update(connection_args)
-        _neutron_module_call('create_subnet', tenant_id=tenant_id, **subnet_arguments)
-        existing_subnet = _neutron_module_call(
-            'list_subnets', tenant_id=tenant_id, name=name, **connection_args)
-        if existing_subnet:
-            return _created(name, 'subnet', existing_subnet[name])
-        return _update_failed(name, 'subnet')
-    # change from internal representation
-    existing_subnet = existing_subnet[name]
-    # create differential
-    LOG.error('existing ' + str(existing_subnet))
-    LOG.error('new ' + str(subnet_arguments))
-    diff = dict((key, value) for key, value in subnet_arguments.iteritems()
-                if existing_subnet.get(key, None) != value)
-    if diff:
+        res = _neutron_module_call('create_subnet', tenant_id=tenant_id,
+                                   **subnet_arguments)['subnet']
+        if res.get('name') == name:
+            return _created(name, 'subnet', res)
+        return _create_failed(name, 'subnet')
+
+    elif len(existing_subnets) == 1:
+        existing_subnet = existing_subnets[0]
+
+        # create differential
+        LOG.error('existing ' + str(existing_subnet))
+        LOG.error('new ' + str(subnet_arguments))
+        diff = dict((key, value) for key, value in subnet_arguments.iteritems()
+                    if existing_subnet.get(key, None) != value)
+        if not diff:
+            return _no_change(name, 'subnet')
+
         # update the changes
         subnet_arguments = diff.copy()
         subnet_arguments.update(connection_args)
@@ -228,24 +246,22 @@
             changes_dict['comment'] = '{1} {0} updated'.format(name, 'subnet')
             return changes_dict
         except:
-            LOG.exception('Could not update subnet {0}'.format(name))
+            LOG.error('Could not update subnet {0}'.format(name))
             return _update_failed(name, 'subnet')
-    return _no_change(name, 'subnet')
+
+    elif len(existing_subnets) > 1:
+        LOG.error("Multiple subnets with name: {0} found".format(
+                  name))
+        return _create_failed(name, 'network')
 
 
 @_test_call
-def subnet_absent(name, profile=None, endpoint_type=None):
+def subnet_absent(name, subnet_id=None, profile=None, endpoint_type=None):
     connection_args = _auth(profile, endpoint_type)
-    existing_subnet = _neutron_module_call(
-        'list_subnets', tenant_id=tenant_id, name=name, **connection_args)
-    if existing_subnet:
-        _neutron_module_call(
-            'delete_subnet', existing_subnet[name]['id'], **connection_args)
-        if _neutron_module_call('list_subnets', name=name, **connection_args):
-            return _delete_failed(name, 'subnet')
-        return _deleted(name, 'subnet', existing_subnet[name])
+    identifier = subnet_id or name
+    _neutron_module_call(
+        'delete_subnet', identifier, **connection_args)
     return _absent(name, 'subnet')
-    return _absent(name, 'network')
 
 
 @_test_call
@@ -390,6 +406,7 @@
     else:
         return _no_change('for instance {0}'.format(name), 'floatingip')
 
+
 def security_group_present(name=None,
                            tenant=None,
                            description=None,
@@ -583,4 +600,4 @@
     Return those kwargs which are not null
     '''
     return dict((key, value,) for key, value in kwargs.iteritems()
-                if value is not None)
\ No newline at end of file
+                if value is not None)
diff --git a/neutron/client.sls b/neutron/client.sls
index 91f81e8..e31e969 100644
--- a/neutron/client.sls
+++ b/neutron/client.sls
@@ -45,7 +45,7 @@
 neutron_openstack_subnet_{{ subnet_name }}:
   neutronng.subnet_present:
     - name: {{ subnet_name }}
-    - network: {{ network_name }}
+    - network_name: {{ network_name }}
     - profile: {{ identity_name }}
     - tenant: {{ network.tenant }}
     {%- if identity.endpoint_type is defined %}
diff --git a/neutron/compute.sls b/neutron/compute.sls
index bfefb53..cb02136 100644
--- a/neutron/compute.sls
+++ b/neutron/compute.sls
@@ -32,13 +32,15 @@
   service.running:
   - name: neutron-sriov-agent
   - enable: true
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - watch_in:
     - service: neutron_compute_services
   - watch:
     - file: /etc/neutron/neutron.conf
     - file: /etc/neutron/plugins/ml2/openvswitch_agent.ini
     - file: /etc/neutron/plugins/ml2/sriov_agent.ini
-  - unless: grains.get('noservices', False)
 
 {% endif %}
 
diff --git a/neutron/files/mitaka/ml2_conf.ini b/neutron/files/mitaka/ml2_conf.ini
index e29d8de..9a8e79c 100644
--- a/neutron/files/mitaka/ml2_conf.ini
+++ b/neutron/files/mitaka/ml2_conf.ini
@@ -180,12 +180,12 @@
 # Comma-separated list of <vni_min>:<vni_max> tuples enumerating ranges of VXLAN VNI IDs that are available for tenant network allocation
 # (list value)
 #vni_ranges =
-vni_ranges =2:65535
+vni_ranges = {{ server.get('vxlan', {}).vni_ranges|default('2:65535') }}
 
 # Multicast group for VXLAN. When configured, will enable sending all broadcast traffic to this multicast group. When left unconfigured,
 # will disable multicast VXLAN mode. (string value)
 #vxlan_group = <None>
-vxlan_group = 224.0.0.1
+vxlan_group = {{ server.get('vxlan', {}).group|default('224.0.0.1') }}
 
 
 [securitygroup]
diff --git a/neutron/files/mitaka/neutron-server.conf.Debian b/neutron/files/mitaka/neutron-server.conf.Debian
index ae5cddc..f36b5fa 100644
--- a/neutron/files/mitaka/neutron-server.conf.Debian
+++ b/neutron/files/mitaka/neutron-server.conf.Debian
@@ -28,14 +28,11 @@
 
 {% if server.backend.engine == "contrail" %}
 
-# TEMPORARY - until neutron v2 contrail package would be supported
-#api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions:/usr/lib/python2.7/dist-packages/neutron_lbaas/extensions
-api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions
+api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions:/usr/lib/python2.7/dist-packages/neutron_lbaas/extensions
 # The core plugin Neutron will use (string value)
 core_plugin = neutron_plugin_contrail.plugins.opencontrail.contrail_plugin.NeutronPluginContrailCoreV2
 
-# TEMPORARY - until neutron v2 contrail package would be supported
-#service_plugins = neutron_plugin_contrail.plugins.opencontrail.loadbalancer.v2.plugin.LoadBalancerPluginV2
+service_plugins = neutron_plugin_contrail.plugins.opencontrail.loadbalancer.v2.plugin.LoadBalancerPluginV2
 {% elif server.backend.engine == "ml2" %}
 
 core_plugin = neutron.plugins.ml2.plugin.Ml2Plugin
@@ -842,7 +839,19 @@
 auth_region={{ server.identity.region }}
 auth_protocol=http
 revocation_cache_time = 10
+{% if server.backend.engine == "contrail" %}
+# LBaaS contrail neutron plugin for versions 3.x expects auth_type to be 
+# 'keystone' or 'noauth'
+# This behaviour is fixed after the release MCP1.0 by using auth_strategy
+# instead of auth_type, until this is backported to MCP1.0 auth_type must be
+# set to keystone, noauth or commented out.
+#
+# When not defined, contrail defaults to 'keystone'
+#
+#auth_type=keystone
+{% else %}
 auth_type = password
+{% endif %}
 auth_host = {{ server.identity.host }}
 auth_port = 35357
 user_domain_id = {{ server.identity.get('domain', 'default') }}
@@ -1656,7 +1665,7 @@
 {%- for lbaas_name, lbaas in server.lbaas.providers.iteritems() %}
 
 {%- if lbaas.engine == "avinetworks" -%}
-service_provider=LOADBALANCERV2:{{ lbaas_name }}:neutron_lbaas.drivers.avi.avi_driver.AviDriver
+service_provider=LOADBALANCERV2:{{ lbaas_name }}:{{ lbaas.get('driver_path', 'avi_lbaasv2.avi_driver.AviDriver') }}:default
 
 [{{ lbaas_name }}]
 address={{ lbaas.controller_address }}
@@ -1671,7 +1680,7 @@
 
 {% elif server.backend.engine == "contrail" %}
 
-service_provider = LOADBALANCER:Opencontrail:neutron_plugin_contrail.plugins.opencontrail.loadbalancer.driver.OpencontrailLoadbalancerDriver:default
+service_provider = LOADBALANCERV2:Opencontrail:neutron_plugin_contrail.plugins.opencontrail.loadbalancer.driver.OpencontrailLoadbalancerDummyDriver:default
 
 {% include "neutron/files/"+server.version+"/ContrailPlugin.ini" %}
 
diff --git a/neutron/files/newton/l3_agent.ini b/neutron/files/newton/l3_agent.ini
index ad79623..56bf297 100644
--- a/neutron/files/newton/l3_agent.ini
+++ b/neutron/files/newton/l3_agent.ini
@@ -90,10 +90,12 @@
 # be used. (string value)
 #external_ingress_mark = 0x2
 
-# Name of bridge used for external network traffic. This should be set to an empty value for the Linux Bridge. When this parameter is set,
-# each L3 agent can be associated with no more than one external network. (string value)
-#external_network_bridge = br-ex
-external_network_bridge = 
+# DEPRECATED: Name of bridge used for external network traffic. When this parameter is set, the L3 agent will plug an interface directly
+# into an external bridge which will not allow any wiring by the L2 agent. Using this will result in incorrect port statuses. This option is
+# deprecated and will be removed in Ocata. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+#external_network_bridge =
 
 # Seconds between running periodic tasks (integer value)
 #periodic_interval = 40
diff --git a/neutron/files/newton/ml2_conf.ini b/neutron/files/newton/ml2_conf.ini
index e29d8de..9a8e79c 100644
--- a/neutron/files/newton/ml2_conf.ini
+++ b/neutron/files/newton/ml2_conf.ini
@@ -180,12 +180,12 @@
 # Comma-separated list of <vni_min>:<vni_max> tuples enumerating ranges of VXLAN VNI IDs that are available for tenant network allocation
 # (list value)
 #vni_ranges =
-vni_ranges =2:65535
+vni_ranges = {{ server.get('vxlan', {}).vni_ranges|default('2:65535') }}
 
 # Multicast group for VXLAN. When configured, will enable sending all broadcast traffic to this multicast group. When left unconfigured,
 # will disable multicast VXLAN mode. (string value)
 #vxlan_group = <None>
-vxlan_group = 224.0.0.1
+vxlan_group = {{ server.get('vxlan', {}).group|default('224.0.0.1') }}
 
 
 [securitygroup]
diff --git a/neutron/files/newton/neutron-generic.conf.Debian b/neutron/files/newton/neutron-generic.conf.Debian
index 2f4b89e..f521546 100644
--- a/neutron/files/newton/neutron-generic.conf.Debian
+++ b/neutron/files/newton/neutron-generic.conf.Debian
@@ -537,7 +537,6 @@
 # The messaging driver to use, defaults to rabbit. Other drivers include amqp
 # and zmq. (string value)
 #rpc_backend = rabbit
-rpc_backend = rabbit
 
 # The default exchange under which topics are scoped. May be overridden by an
 # exchange name specified in the transport_url option. (string value)
@@ -1316,7 +1315,6 @@
 # count). (integer value)
 # Deprecated group/name - [DEFAULT]/rabbit_max_retries
 #rabbit_max_retries = 0
-rabbit_max_retries = 0
 
 # Try to use HA queues in RabbitMQ (x-ha-policy: all). If you change this
 # option, you must wipe the RabbitMQ database. In RabbitMQ 3.0, queue mirroring
diff --git a/neutron/files/newton/neutron-server.conf.Debian b/neutron/files/newton/neutron-server.conf.Debian
index 13d30c1..34aaa06 100644
--- a/neutron/files/newton/neutron-server.conf.Debian
+++ b/neutron/files/newton/neutron-server.conf.Debian
@@ -28,14 +28,11 @@
 
 {% if server.backend.engine == "contrail" %}
 
-# TEMPORARY - until neutron v2 contrail package would be supported
-#api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions:/usr/lib/python2.7/dist-packages/neutron_lbaas/extensions
-api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions
+api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions:/usr/lib/python2.7/dist-packages/neutron_lbaas/extensions
 # The core plugin Neutron will use (string value)
 core_plugin = neutron_plugin_contrail.plugins.opencontrail.contrail_plugin.NeutronPluginContrailCoreV2
 
-# TEMPORARY - until neutron v2 contrail package would be supported
-#service_plugins = neutron_plugin_contrail.plugins.opencontrail.loadbalancer.v2.plugin.LoadBalancerPluginV2
+service_plugins = neutron_plugin_contrail.plugins.opencontrail.loadbalancer.v2.plugin.LoadBalancerPluginV2
 {% elif server.backend.engine == "ml2" %}
 
 core_plugin = neutron.plugins.ml2.plugin.Ml2Plugin
@@ -550,12 +547,6 @@
 # not set, we fall back to the rpc_backend option and driver specific
 # configuration. (string value)
 #transport_url = <None>
-
-# The messaging driver to use, defaults to rabbit. Other drivers include amqp
-# and zmq. (string value)
-#rpc_backend = rabbit
-rpc_backend = rabbit
-
 {%- if server.message_queue.members is defined %}
 transport_url = rabbit://{% for member in server.message_queue.members -%}
                              {{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ member.host }}:{{ member.get('port', 5672) }}
@@ -566,6 +557,11 @@
 transport_url = rabbit://{{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ server.message_queue.host }}:{{ server.message_queue.port }}/{{ server.message_queue.virtual_host }}
 {%- endif %}
 
+# The messaging driver to use, defaults to rabbit. Other drivers include amqp
+# and zmq. (string value)
+#rpc_backend = rabbit
+
+
 # The default exchange under which topics are scoped. May be overridden by an
 # exchange name specified in the transport_url option. (string value)
 #control_exchange = neutron
@@ -1401,7 +1397,6 @@
 # count). (integer value)
 # Deprecated group/name - [DEFAULT]/rabbit_max_retries
 #rabbit_max_retries = 0
-rabbit_max_retries = 0
 
 # Try to use HA queues in RabbitMQ (x-ha-policy: all). If you change this
 # option, you must wipe the RabbitMQ database. In RabbitMQ 3.0, queue mirroring
@@ -1654,7 +1649,7 @@
 {%- for lbaas_name, lbaas in server.lbaas.providers.iteritems() %}
 
 {%- if lbaas.engine == "avinetworks" -%}
-service_provider=LOADBALANCERV2:{{ lbaas_name }}:neutron_lbaas.drivers.avi.avi_driver.AviDriver
+service_provider=LOADBALANCERV2:{{ lbaas_name }}:{{ lbaas.get('driver_path', 'avi_lbaasv2.avi_driver.AviDriver') }}:default
 
 [{{ lbaas_name }}]
 address={{ lbaas.controller_address }}
@@ -1669,7 +1664,7 @@
 
 {% elif server.backend.engine == "contrail" %}
 
-service_provider = LOADBALANCER:Opencontrail:neutron_plugin_contrail.plugins.opencontrail.loadbalancer.driver.OpencontrailLoadbalancerDriver:default
+service_provider = LOADBALANCERV2:Opencontrail:neutron_plugin_contrail.plugins.opencontrail.loadbalancer.driver.OpencontrailLoadbalancerDummyDriver:default
 
 {% include "neutron/files/"+server.version+"/ContrailPlugin.ini" %}
 
diff --git a/neutron/files/ocata/l3_agent.ini b/neutron/files/ocata/l3_agent.ini
index b2f3bf1..41b87e6 100644
--- a/neutron/files/ocata/l3_agent.ini
+++ b/neutron/files/ocata/l3_agent.ini
@@ -106,7 +106,6 @@
 # This option is deprecated for removal.
 # Its value may be silently ignored in the future.
 #external_network_bridge =
-external_network_bridge = 
 
 # Seconds between running periodic tasks. (integer value)
 #periodic_interval = 40
diff --git a/neutron/files/ocata/ml2_conf.ini b/neutron/files/ocata/ml2_conf.ini
index 944c52a..c32a470 100644
--- a/neutron/files/ocata/ml2_conf.ini
+++ b/neutron/files/ocata/ml2_conf.ini
@@ -232,13 +232,13 @@
 # Comma-separated list of <vni_min>:<vni_max> tuples enumerating ranges of
 # VXLAN VNI IDs that are available for tenant network allocation (list value)
 #vni_ranges =
-vni_ranges =2:65535
+vni_ranges = {{ server.get('vxlan', {}).vni_ranges|default('2:65535') }}
 
 # Multicast group for VXLAN. When configured, will enable sending all broadcast
 # traffic to this multicast group. When left unconfigured, will disable
 # multicast VXLAN mode. (string value)
 #vxlan_group = <None>
-vxlan_group = 224.0.0.1
+vxlan_group = {{ server.get('vxlan', {}).group|default('224.0.0.1') }}
 
 
 [securitygroup]
diff --git a/neutron/files/ocata/neutron-generic.conf.Debian b/neutron/files/ocata/neutron-generic.conf.Debian
index 6275974..5b7058d 100644
--- a/neutron/files/ocata/neutron-generic.conf.Debian
+++ b/neutron/files/ocata/neutron-generic.conf.Debian
@@ -605,7 +605,6 @@
 # Its value may be silently ignored in the future.
 # Reason: Replaced by [DEFAULT]/transport_url
 #rpc_backend = rabbit
-rpc_backend = rabbit
 
 # The default exchange under which topics are scoped. May be overridden by an
 # exchange name specified in the transport_url option. (string value)
@@ -1646,7 +1645,6 @@
 # This option is deprecated for removal.
 # Its value may be silently ignored in the future.
 #rabbit_max_retries = 0
-rabbit_max_retries = 0
 
 # Try to use HA queues in RabbitMQ (x-ha-policy: all). If you change this
 # option, you must wipe the RabbitMQ database. In RabbitMQ 3.0, queue mirroring
diff --git a/neutron/files/ocata/neutron-server.conf.Debian b/neutron/files/ocata/neutron-server.conf.Debian
index fa1382d..7b38a77 100644
--- a/neutron/files/ocata/neutron-server.conf.Debian
+++ b/neutron/files/ocata/neutron-server.conf.Debian
@@ -34,14 +34,11 @@
 
 {% if server.backend.engine == "contrail" %}
 
-# TEMPORARY - until neutron v2 contrail package would be supported
-#api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions:/usr/lib/python2.7/dist-packages/neutron_lbaas/extensions
-api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions
+api_extensions_path = extensions:/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions:/usr/lib/python2.7/dist-packages/neutron_lbaas/extensions
 # The core plugin Neutron will use (string value)
 core_plugin = neutron_plugin_contrail.plugins.opencontrail.contrail_plugin.NeutronPluginContrailCoreV2
 
-# TEMPORARY - until neutron v2 contrail package would be supported
-#service_plugins = neutron_plugin_contrail.plugins.opencontrail.loadbalancer.v2.plugin.LoadBalancerPluginV2
+service_plugins = neutron_plugin_contrail.plugins.opencontrail.loadbalancer.v2.plugin.LoadBalancerPluginV2
 {% elif server.backend.engine == "ml2" %}
 
 core_plugin = neutron.plugins.ml2.plugin.Ml2Plugin
@@ -627,7 +624,6 @@
 # Its value may be silently ignored in the future.
 # Reason: Replaced by [DEFAULT]/transport_url
 #rpc_backend = rabbit
-rpc_backend = rabbit
 
 # The default exchange under which topics are scoped. May be overridden by an
 # exchange name specified in the transport_url option. (string value)
@@ -1724,7 +1720,6 @@
 # This option is deprecated for removal.
 # Its value may be silently ignored in the future.
 #rabbit_max_retries = 0
-rabbit_max_retries = 0
 
 # Try to use HA queues in RabbitMQ (x-ha-policy: all). If you change this
 # option, you must wipe the RabbitMQ database. In RabbitMQ 3.0, queue mirroring
@@ -2164,7 +2159,7 @@
 {%- for lbaas_name, lbaas in server.lbaas.providers.iteritems() %}
 
 {%- if lbaas.engine == "avinetworks" -%}
-service_provider=LOADBALANCERV2:{{ lbaas_name }}:neutron_lbaas.drivers.avi.avi_driver.AviDriver
+service_provider=LOADBALANCERV2:{{ lbaas_name }}:{{ lbaas.get('driver_path', 'avi_lbaasv2.avi_driver.AviDriver') }}:default
 
 [{{ lbaas_name }}]
 address={{ lbaas.controller_address }}
@@ -2179,7 +2174,7 @@
 
 {% elif server.backend.engine == "contrail" %}
 
-service_provider = LOADBALANCER:Opencontrail:neutron_plugin_contrail.plugins.opencontrail.loadbalancer.driver.OpencontrailLoadbalancerDriver:default
+service_provider = LOADBALANCERV2:Opencontrail:neutron_plugin_contrail.plugins.opencontrail.loadbalancer.driver.OpencontrailLoadbalancerDummyDriver:default
 
 {% include "neutron/files/"+server.version+"/ContrailPlugin.ini" %}
 
diff --git a/neutron/server.sls b/neutron/server.sls
index 5bf73e3..b652193 100644
--- a/neutron/server.sls
+++ b/neutron/server.sls
@@ -27,14 +27,15 @@
   pkg.installed:
   - name: neutron-plugin-contrail
 
-{%- if not grains.get('noservices', False) %}
 neutron_server_service:
   service.running:
   - name: neutron-server
   - enable: true
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - watch:
     - file: /etc/neutron/neutron.conf
-{%- endif %}
 
 {%- endif %}
 
@@ -55,14 +56,15 @@
   - require:
     - file: /etc/neutron/plugins/ml2/ml2_conf.ini
 
-{%- if not grains.get('noservices', False) %}
 neutron_db_manage:
   cmd.run:
   - name: neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - file: /etc/neutron/neutron.conf
     - file: /etc/neutron/plugins/ml2/ml2_conf.ini
-{%- endif %}
 
 {%- endif %}
 
@@ -112,14 +114,11 @@
   - template: jinja
   - require:
     - pkg: neutron_server_packages
-{%- if not grains.get('noservices', False) %}
   - watch_in:
     - service: neutron_server_services
 
 {%- endif %}
 
-{%- endif %}
-
 {%- if server.backend.engine == "midonet" %}
 
 /etc/neutron/plugins/midonet/midonet.ini:
@@ -132,14 +131,15 @@
     - dir_mode: 755
     - template: jinja
 
-{%- if not grains.get('noservices', False) %}
 neutron_db_manage:
   cmd.run:
   - name: neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/midonet/midonet.ini upgrade head
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - file: /etc/neutron/neutron.conf
     - file: /etc/neutron/plugins/midonet/midonet.ini
-{%- endif %}
 
 {%- if server.version == "kilo" %}
 
@@ -162,29 +162,29 @@
     - python-neutron-lbaas
     - python-neutron-fwaas
 
-{%- if not grains.get('noservices', False) %}
 neutron_db_manage:
   cmd.run:
   - name: neutron-db-manage --subproject networking-midonet upgrade head
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - file: /etc/neutron/neutron.conf
     - file: /etc/neutron/plugins/midonet/midonet.ini
-{%- endif %}
 
 {%- endif %}
 {%- endif %}
 
-{%- if not grains.get('noservices', False) %}
-
 neutron_server_services:
   service.running:
   - names: {{ server.services }}
   - enable: true
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - watch:
     - file: /etc/neutron/neutron.conf
 
-{%- endif %}
-
 {%- if grains.get('virtual_subtype', None) == "Docker" %}
 
 neutron_entrypoint: