Merge "Add 'manage_service_maintenance'. Don't manage services scheduling while upgrading."
diff --git a/README.rst b/README.rst
index 8c7579f..dfd3de0 100644
--- a/README.rst
+++ b/README.rst
@@ -1291,7 +1291,7 @@
 Neutron Client
 --------------
 
-Neutron networks:
+Neutron networks and RBAC:
 
 .. code-block:: yaml
 
@@ -1300,6 +1300,18 @@
         enabled: true
         server:
           identity:
+            rbac:
+              network:
+                rule1:
+                  absent: True
+                  target_tenant:  admin
+                  action: access_as_shared
+                  network: public
+                rule2:
+                  absent: False
+                  target_tenant: service
+                  action: access_as_external
+                  network: public
             endpoint_type: internalURL
             network:
               inet1:
@@ -1509,6 +1521,7 @@
       gateway:
         of_connect_timeout: 60
         of_request_timeout: 30
+        of_inactivity_probe: 30
         ovs_vsctl_timeout: 30  # Pike
         ovsdb_timeout: 30  # Queens and beyond
         bridge_mac_table_size: 100000
diff --git a/_modules/neutronv2/__init__.py b/_modules/neutronv2/__init__.py
index 74b6fb1..c6ebe0f 100644
--- a/_modules/neutronv2/__init__.py
+++ b/_modules/neutronv2/__init__.py
@@ -14,6 +14,7 @@
 from neutronv2 import routers
 from neutronv2 import ports
 from neutronv2 import common
+from neutronv2 import rbac
 
 
 network_get_details = networks.network_get_details
@@ -69,6 +70,10 @@
 port_get_details = ports.port_get_details
 
 
+rbac_policies_list = lists.rbac_policies_list
+rbac_policies_create = rbac.rbac_policies_create
+rbac_policies_delete = rbac.rbac_policies_delete
+
 wait_for_network_services = agents.wait_for_network_services
 
 wait_for_api_ready = common.wait_for_api_ready
@@ -88,6 +93,7 @@
     'router_list', 'router_create', 'router_delete', 'router_get_details',
     'router_interface_add', 'router_interface_remove', 'router_update',
     'port_create', 'port_delete', 'port_update', 'port_list', 'port_get_details',
+    'rbac_policies_create' 'rbac_policies_delete', 'rbac_policies_list',
 )
 
 
diff --git a/_modules/neutronv2/lists.py b/_modules/neutronv2/lists.py
index eea4a7a..13958ee 100644
--- a/_modules/neutronv2/lists.py
+++ b/_modules/neutronv2/lists.py
@@ -39,4 +39,10 @@
 @send('get')
 def port_list(**kwargs):
     url = '/ports?{}'.format(urlencode(kwargs))
-    return url, {}
\ No newline at end of file
+    return url, {}
+
+
+@send('get')
+def rbac_policies_list(**kwargs):
+    url = '/rbac-policies?{}'.format(urlencode(kwargs))
+    return url, {}
diff --git a/_modules/neutronv2/rbac.py b/_modules/neutronv2/rbac.py
new file mode 100644
index 0000000..021d535
--- /dev/null
+++ b/_modules/neutronv2/rbac.py
@@ -0,0 +1,27 @@
+from neutronv2.common import send
+from neutronv2.arg_converter import get_by_name_or_uuid_multiple
+
+try:
+    from urllib.parse import urlencode
+except ImportError:
+    from urllib import urlencode
+
+
+@send('delete')
+def rbac_policies_delete(id):
+    url = '/rbac-policies/{}'.format(id)
+    return url, {}
+
+
+@get_by_name_or_uuid_multiple([('network', 'object_id')])
+@send('post')
+def rbac_policies_create(object_id,**kwargs):
+
+    url = '/rbac-policies'
+    kwargs.update({'object_type': 'network'})
+    kwargs.update({'object_id': object_id})
+    json = {
+        'rbac_policy': kwargs,
+    }
+
+    return url, {'json': json}
diff --git a/_states/neutronv2.py b/_states/neutronv2.py
index 81c8fa4..7bfa7fb 100644
--- a/_states/neutronv2.py
+++ b/_states/neutronv2.py
@@ -271,6 +271,58 @@
                              cloud_name, **kwargs)
 
 
+def rbac_get_rule_id(cloud_name, **kwargs):
+    existing_rules = _neutronv2_call('rbac_policies_list',
+    cloud_name=cloud_name)
+
+    match_condition_fields = ['action',
+                              'target_tenant',
+                              'object_id',
+                             ]
+
+    for rule in existing_rules['rbac_policies']:
+      match = True
+      for field in match_condition_fields:
+        if rule[field] != kwargs[field]:
+          match = False
+          break
+      if match: return rule['id']
+
+
+def rbac_present(name, cloud_name, **kwargs):
+    resource = 'rbac_policies'
+    # Resolve network name to UID if needed
+    kwargs['object_id'] = __salt__['neutronv2.network_get_details'] \
+      (network_id=kwargs['object_id'],cloud_name=cloud_name)['network']['id']
+
+    if rbac_get_rule_id(cloud_name, **kwargs):
+      return _succeeded('no_changes', name, resource)
+
+    r = _neutronv2_call('{}_create'.format(resource),
+                            cloud_name=cloud_name,
+                            **kwargs)
+    if r:
+      return _succeeded('create', name, resource, changes=r)
+    else:
+      return _failed('create', name, kwargs)
+
+def rbac_absent(name, cloud_name, **kwargs):
+    resource = 'rbac_policies'
+    # Resolve network name to UID if needed
+    kwargs['object_id'] = __salt__['neutronv2.network_get_details'] \
+      (network_id=kwargs['object_id'],cloud_name=cloud_name)['network']['id']
+
+    rule_id = rbac_get_rule_id(cloud_name, **kwargs)
+
+    if rule_id:
+        r = _neutronv2_call('{}_delete'.format(resource),
+                                cloud_name=cloud_name,
+                                id=rule_id)
+        return _succeeded('delete', name, resource, changes=r)
+
+    return _succeeded('no_changes', name, resource)
+
+
 def _succeeded(op, name, resource, changes=None):
     msg_map = {
         'create': '{0} {1} created',
diff --git a/metadata/service/control/cluster.yml b/metadata/service/control/cluster.yml
index 4753725..e296c90 100644
--- a/metadata/service/control/cluster.yml
+++ b/metadata/service/control/cluster.yml
@@ -28,6 +28,7 @@
         name: neutron
         user: neutron
         password: ${_param:mysql_neutron_password}
+        max_overflow: 70
       identity:
         engine: keystone
         region: RegionOne
@@ -55,6 +56,7 @@
         user: openstack
         password: ${_param:rabbitmq_openstack_password}
         virtual_host: '/openstack'
+        executor_thread_pool_size: 70
       compute:
         host: ${_param:cluster_vip_address}
         region: RegionOne
diff --git a/metadata/service/control/container.yml b/metadata/service/control/container.yml
index 367167b..ce89d36 100644
--- a/metadata/service/control/container.yml
+++ b/metadata/service/control/container.yml
@@ -24,6 +24,7 @@
                   name: neutron
                   user: neutron
                   password: ${_param:mysql_neutron_password}
+                  max_overflow: 70
                 identity:
                   engine: keystone
                   region: RegionOne
@@ -40,6 +41,7 @@
                   user: openstack
                   password: ${_param:rabbitmq_openstack_password}
                   virtual_host: '/openstack'
+                  executor_thread_pool_size: 70
                 compute:
                   host: ${_param:nova_service_host}
                   region: RegionOne
diff --git a/metadata/service/control/single.yml b/metadata/service/control/single.yml
index 448d6fe..9275ed3 100644
--- a/metadata/service/control/single.yml
+++ b/metadata/service/control/single.yml
@@ -32,6 +32,7 @@
         name: neutron
         user: neutron
         password: ${_param:mysql_neutron_password}
+        max_overflow: 70
       identity:
         engine: keystone
         region: RegionOne
@@ -59,6 +60,7 @@
         user: openstack
         password: ${_param:rabbitmq_openstack_password}
         virtual_host: '/openstack'
+        executor_thread_pool_size: 70
       compute:
         host: ${_param:single_address}
         region: RegionOne
diff --git a/neutron/client/resources/v2.sls b/neutron/client/resources/v2.sls
index 3bd57b9..43db50e 100644
--- a/neutron/client/resources/v2.sls
+++ b/neutron/client/resources/v2.sls
@@ -118,5 +118,33 @@
   {%- endfor %}
   {%- endif %}
 
+  {%- if identity.rbac is defined %}
+  {%- for rule_name, rule in identity.rbac.network.iteritems() %}
+
+  {%- if rule.absent is defined and rule.absent %}
+neutron_openstack_rbac_network_{{ rule_name }}:
+  neutronv2.rbac_absent:
+    - name: {{ rule_name }}
+    - cloud_name: {{ identity_name }}
+    - target_tenant: {{ rule.target_tenant }}
+    - action: {{ rule.action }}
+    - object_id: {{ rule.network }}
+
+  {%- else %}
+neutron_openstack_rbac_network_{{ rule_name }}:
+  neutronv2.rbac_present:
+    - name: {{ rule_name }}
+    - cloud_name: {{ identity_name }}
+    - target_tenant: {{ rule.target_tenant }}
+    - action: {{ rule.action }}
+    - object_id: {{ rule.network }}
+
+
+  {%- endif %}
+
+  {%- endfor %}
+  {%- endif %}
+
+
 {%- endfor %}
 {%- endif %}
diff --git a/neutron/files/pike/neutron-server.conf b/neutron/files/pike/neutron-server.conf
index 0188447..bed4834 100644
--- a/neutron/files/pike/neutron-server.conf
+++ b/neutron/files/pike/neutron-server.conf
@@ -678,7 +678,9 @@
 # Size of executor thread pool. (integer value)
 # Deprecated group/name - [DEFAULT]/rpc_thread_pool_size
 #executor_thread_pool_size = 64
-executor_thread_pool_size = 70
+{%- if server.message_queue.executor_thread_pool_size is defined %}
+executor_thread_pool_size = {{ server.message_queue.executor_thread_pool_size }}
+{%- endif %}
 
 # Seconds to wait for a response from a call. (integer value)
 #rpc_response_timeout = 60
@@ -967,7 +969,9 @@
 # Deprecated group/name - [DEFAULT]/sql_max_overflow
 # Deprecated group/name - [DATABASE]/sqlalchemy_max_overflow
 #max_overflow = 50
-max_overflow = 20
+{%- if server.database.max_overflow is defined %}
+max_overflow = {{ server.database.max_overflow }}
+{%- endif %}
 
 # Verbosity of SQL debugging information: 0=None, 100=Everything. (integer
 # value)
diff --git a/neutron/files/pike/openvswitch_agent.ini b/neutron/files/pike/openvswitch_agent.ini
index 19ade98..bdf5239 100644
--- a/neutron/files/pike/openvswitch_agent.ini
+++ b/neutron/files/pike/openvswitch_agent.ini
@@ -333,6 +333,15 @@
 of_request_timeout = {{ neutron.of_request_timeout }}
 {%- endif %}
 
+# The inactivity_probe interval in seconds for the local
+# switch connection to the controller.
+# A value of 0 disables inactivity probes.
+# Used only for 'native' driver.
+#of_inactivity_probe=10
+{%- if neutron.of_inactivity_probe is defined %}
+of_inactivity_probe = {{ neutron.of_inactivity_probe }}
+{%- endif %}
+
 # The interface for interacting with the OVSDB (string value)
 # Allowed values: vsctl, native
 #ovsdb_interface = native
diff --git a/neutron/files/queens/openvswitch_agent.ini b/neutron/files/queens/openvswitch_agent.ini
index d642dec..d5703b0 100644
--- a/neutron/files/queens/openvswitch_agent.ini
+++ b/neutron/files/queens/openvswitch_agent.ini
@@ -218,6 +218,15 @@
 of_request_timeout = {{ neutron.of_request_timeout }}
 {%- endif %}
 
+# The inactivity_probe interval in seconds for the local
+# switch connection to the controller.
+# A value of 0 disables inactivity probes.
+# Used only for 'native' driver.
+#of_inactivity_probe=10
+{%- if neutron.of_inactivity_probe is defined %}
+of_inactivity_probe = {{ neutron.of_inactivity_probe }}
+{%- endif %}
+
 # DEPRECATED: The interface for interacting with the OVSDB (string value)
 # Possible values:
 # native - <No description provided>
diff --git a/neutron/files/rocky/openvswitch_agent.ini b/neutron/files/rocky/openvswitch_agent.ini
index 957af4c..3e088f8 100644
--- a/neutron/files/rocky/openvswitch_agent.ini
+++ b/neutron/files/rocky/openvswitch_agent.ini
@@ -219,6 +219,15 @@
 of_request_timeout = {{ neutron.of_request_timeout }}
 {%- endif %}
 
+# The inactivity_probe interval in seconds for the local
+# switch connection to the controller.
+# A value of 0 disables inactivity probes.
+# Used only for 'native' driver.
+#of_inactivity_probe=10
+{%- if neutron.of_inactivity_probe is defined %}
+of_inactivity_probe = {{ neutron.of_inactivity_probe }}
+{%- endif %}
+
 # DEPRECATED: The interface for interacting with the OVSDB (string value)
 # Possible values:
 # native - <No description provided>
diff --git a/neutron/gateway.sls b/neutron/gateway.sls
index b1b61f7..e51990a 100644
--- a/neutron/gateway.sls
+++ b/neutron/gateway.sls
@@ -80,6 +80,15 @@
   - require:
     - pkg: neutron_gateway_packages
 
+{%- if gateway.inactivity_probe is defined %}
+{%- set probe_ms = gateway.inactivity_probe * 1000 %}
+ovs_manager_inactivity_probe:
+  cmd.run:
+  - name: "ovs-vsctl set manager ptcp:6640:127.0.0.1 inactivity_probe={{ probe_ms }}"
+  - unless:
+    - ovs-vsctl get manager ptcp:6640:127.0.0.1 inactivity_probe | grep -qFx {{ probe_ms }}
+{%- endif %}
+
 {%- endif %}
 {%- endif %}