Add oslo middleware healthcheck to Octavia API
healthcheck middleware adds a /healthcheck url that allows unauthenticated access to provide a simple check when running octavia-api behind a load balancer https://docs.openstack.org/oslo.middleware/latest/reference/healthcheck_plugins.html Co-authored-by: Michael Johnson <johnsomor@gmail.com> Change-Id: I10db6226750f7b7c703067d2ab82eea3a9875112
This commit is contained in:
parent
22fa179edc
commit
18020e6c88
599
doc/source/admin/healthcheck.rst
Normal file
599
doc/source/admin/healthcheck.rst
Normal file
@ -0,0 +1,599 @@
|
||||
..
|
||||
Copyright 2020 Red Hat, Inc. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
=============================
|
||||
Octavia API Health Monitoring
|
||||
=============================
|
||||
|
||||
The Octavia API provides a health monitoring endpoint that can be used by
|
||||
external load balancers to manage the Octavia API pool. When properly
|
||||
configured, the health monitoring endpoint will reflect the full operational
|
||||
status of the Octavia API.
|
||||
|
||||
The Octavia API health monitoring endpoint extends the `OpenStack Oslo
|
||||
middleware healthcheck <https://docs.openstack.org/oslo.middleware/latest/reference/healthcheck_plugins.html>`_ library to test the Octavia Pecan API framework and associated services.
|
||||
|
||||
Oslo Healthcheck Queries
|
||||
========================
|
||||
|
||||
Oslo middleware healthcheck supports HTTP **"GET"** and **"HEAD"** methods.
|
||||
|
||||
The response from Oslo middleware healthcheck can be customized by specifying
|
||||
the acceptable response type for the request.
|
||||
|
||||
Oslo middleware healthcheck currently supports the following types:
|
||||
|
||||
* text/plain
|
||||
* text/html
|
||||
* application/json
|
||||
|
||||
If the requested type is not one of the above, it defaults to text/plain.
|
||||
|
||||
.. note::
|
||||
|
||||
The content of the response "reasons" will vary based on the backend plugins
|
||||
enabled in Oslo middleware healthcheck. It is a best practice to only rely
|
||||
on the HTTP status code for Octavia API health monitoring.
|
||||
|
||||
Example Responses
|
||||
-----------------
|
||||
|
||||
Example passing output for text/plain with *detailed* False:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 16 Mar 2020 18:10:27 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Length: 2
|
||||
x-openstack-request-id: req-9c6f4303-63a7-4f30-8afc-39340658702f
|
||||
Connection: close
|
||||
Vary: Accept-Encoding
|
||||
|
||||
OK
|
||||
|
||||
Example failing output for text/plain with *detailed* False:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 503 Service Unavailable
|
||||
Date: Mon, 16 Mar 2020 18:42:12 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Length: 36
|
||||
x-openstack-request-id: req-84024269-2dfb-41ad-bfda-b3e1da138bba
|
||||
Connection: close
|
||||
|
||||
Example passing output for text/html with *detailed* False:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: text/html" http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 16 Mar 2020 18:25:11 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Length: 239
|
||||
x-openstack-request-id: req-b212d619-146f-4b50-91a3-5da16051badc
|
||||
Connection: close
|
||||
Vary: Accept-Encoding
|
||||
|
||||
<HTML>
|
||||
<HEAD><TITLE>Healthcheck Status</TITLE></HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>Result of 1 checks:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
|
||||
<TH>
|
||||
Reason
|
||||
</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
|
||||
<TD>OK</TD>
|
||||
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<HR></HR>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
Example failing output for text/html with *detailed* False:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: text/html" http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 503 Service Unavailable
|
||||
Date: Mon, 16 Mar 2020 18:42:22 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Length: 273
|
||||
x-openstack-request-id: req-c91dd214-85ca-4d33-9fa3-2db81566d9e5
|
||||
Connection: close
|
||||
|
||||
<HTML>
|
||||
<HEAD><TITLE>Healthcheck Status</TITLE></HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>Result of 1 checks:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
|
||||
<TH>
|
||||
Reason
|
||||
</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
|
||||
<TD>The Octavia database is unavailable.</TD>
|
||||
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<HR></HR>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
Example passing output for application/json with *detailed* False:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: application/json" http://192.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 16 Mar 2020 18:34:42 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: application/json
|
||||
Content-Length: 62
|
||||
x-openstack-request-id: req-417dc85c-e64e-496e-a461-494a3e6a5479
|
||||
Connection: close
|
||||
|
||||
{
|
||||
"detailed": false,
|
||||
"reasons": [
|
||||
"OK"
|
||||
]
|
||||
}
|
||||
|
||||
Example failing output for application/json with *detailed* False:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: application/json" http://192.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 503 Service Unavailable
|
||||
Date: Mon, 16 Mar 2020 18:46:28 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: application/json
|
||||
Content-Length: 96
|
||||
x-openstack-request-id: req-de50b057-6105-4fca-a758-c872ef28bbfa
|
||||
Connection: close
|
||||
|
||||
{
|
||||
"detailed": false,
|
||||
"reasons": [
|
||||
"The Octavia database is unavailable."
|
||||
]
|
||||
}
|
||||
|
||||
Example Detailed Responses
|
||||
--------------------------
|
||||
|
||||
Example passing output for text/plain with *detailed* True:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 16 Mar 2020 18:10:27 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Length: 2
|
||||
x-openstack-request-id: req-9c6f4303-63a7-4f30-8afc-39340658702f
|
||||
Connection: close
|
||||
Vary: Accept-Encoding
|
||||
|
||||
OK
|
||||
|
||||
Example failing output for text/plain with *detailed* True:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 503 Service Unavailable
|
||||
Date: Mon, 16 Mar 2020 23:41:23 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Length: 36
|
||||
x-openstack-request-id: req-2cd046cb-3a6c-45e3-921d-5f4a9e65c63e
|
||||
Connection: close
|
||||
|
||||
Example passing output for text/html with *detailed* True:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: text/html" http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 16 Mar 2020 22:11:54 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Length: 9927
|
||||
x-openstack-request-id: req-ae7404c9-b183-46dc-bb1b-e5f4e4984a57
|
||||
Connection: close
|
||||
Vary: Accept-Encoding
|
||||
|
||||
<HTML>
|
||||
<HEAD><TITLE>Healthcheck Status</TITLE></HEAD>
|
||||
<BODY>
|
||||
<H1>Server status</H1>
|
||||
<B>Server hostname:</B><PRE>devstack2</PRE>
|
||||
<B>Current time:</B><PRE>2020-03-16 22:11:54.320529</PRE>
|
||||
<B>Python version:</B><PRE>3.6.9 (default, Nov 7 2019, 10:44:02)
|
||||
[GCC 8.3.0]</PRE>
|
||||
<B>Platform:</B><PRE>Linux-4.15.0-88-generic-x86_64-with-Ubuntu-18.04-bionic</PRE>
|
||||
<HR></HR>
|
||||
<H2>Garbage collector:</H2>
|
||||
<B>Counts:</B><PRE>(28, 10, 4)</PRE>
|
||||
<B>Thresholds:</B><PRE>(700, 10, 10)</PRE>
|
||||
<HR></HR>
|
||||
<H2>Result of 1 checks:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TH>
|
||||
Kind
|
||||
</TH>
|
||||
<TH>
|
||||
Reason
|
||||
</TH>
|
||||
<TH>
|
||||
Details
|
||||
</TH>
|
||||
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>OctaviaDBCheckResult</TD>
|
||||
<TD>OK</TD>
|
||||
<TD></TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<HR></HR>
|
||||
<H2>1 greenthread(s) active:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD><PRE> <...> </PRE></TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<HR></HR>
|
||||
<H2>1 thread(s) active:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD><PRE> <...> </PRE></TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
Example failing output for text/html with *detailed* True:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: text/html" http://198.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 503 Service Unavailable
|
||||
Date: Mon, 16 Mar 2020 23:43:52 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Length: 10211
|
||||
x-openstack-request-id: req-39b65058-6dc3-4069-a2d5-8a9714dba61d
|
||||
Connection: close
|
||||
|
||||
<HTML>
|
||||
<HEAD><TITLE>Healthcheck Status</TITLE></HEAD>
|
||||
<BODY>
|
||||
<H1>Server status</H1>
|
||||
<B>Server hostname:</B><PRE>devstack2</PRE>
|
||||
<B>Current time:</B><PRE>2020-03-16 23:43:52.411127</PRE>
|
||||
<B>Python version:</B><PRE>3.6.9 (default, Nov 7 2019, 10:44:02)
|
||||
[GCC 8.3.0]</PRE>
|
||||
<B>Platform:</B><PRE>Linux-4.15.0-88-generic-x86_64-with-Ubuntu-18.04-bionic</PRE>
|
||||
<HR></HR>
|
||||
<H2>Garbage collector:</H2>
|
||||
<B>Counts:</B><PRE>(578, 10, 4)</PRE>
|
||||
<B>Thresholds:</B><PRE>(700, 10, 10)</PRE>
|
||||
<HR></HR>
|
||||
<H2>Result of 1 checks:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TH>
|
||||
Kind
|
||||
</TH>
|
||||
<TH>
|
||||
Reason
|
||||
</TH>
|
||||
<TH>
|
||||
Details
|
||||
</TH>
|
||||
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>OctaviaDBCheckResult</TD>
|
||||
<TD>The Octavia database is unavailable.</TD>
|
||||
<TD>Database health check failed due to: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on '127.0.0.1' ([Errno 111] Connection refused)")
|
||||
[SQL: SELECT 1]
|
||||
(Background on this error at: http://sqlalche.me/e/e3q8).</TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<HR></HR>
|
||||
<H2>1 greenthread(s) active:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD><PRE> <...> </PRE></TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<HR></HR>
|
||||
<H2>1 thread(s) active:</H2>
|
||||
<TABLE bgcolor="#ffffff" border="1">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD><PRE> <...> </PRE></TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
Example passing output for application/json with *detailed* True:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: application/json" http://192.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Date: Mon, 16 Mar 2020 22:05:26 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: application/json
|
||||
Content-Length: 9298
|
||||
x-openstack-request-id: req-d3913655-6e3f-4086-a252-8bb297ea5fd6
|
||||
Connection: close
|
||||
|
||||
{
|
||||
"detailed": true,
|
||||
"gc": {
|
||||
"counts": [
|
||||
27,
|
||||
10,
|
||||
4
|
||||
],
|
||||
"threshold": [
|
||||
700,
|
||||
10,
|
||||
10
|
||||
]
|
||||
},
|
||||
"greenthreads": [
|
||||
<...>
|
||||
],
|
||||
"now": "2020-03-16 22:05:26.431429",
|
||||
"platform": "Linux-4.15.0-88-generic-x86_64-with-Ubuntu-18.04-bionic",
|
||||
"python_version": "3.6.9 (default, Nov 7 2019, 10:44:02) \n[GCC 8.3.0]",
|
||||
"reasons": [
|
||||
{
|
||||
"class": "OctaviaDBCheckResult",
|
||||
"details": "",
|
||||
"reason": "OK"
|
||||
}
|
||||
],
|
||||
"threads": [
|
||||
<...>
|
||||
]
|
||||
}
|
||||
|
||||
Example failing output for application/json with *detailed* True:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -i -H "Accept: application/json" http://192.51.100.10/load-balancer/healthcheck
|
||||
|
||||
HTTP/1.1 503 Service Unavailable
|
||||
Date: Mon, 16 Mar 2020 23:56:43 GMT
|
||||
Server: Apache/2.4.29 (Ubuntu)
|
||||
Content-Type: application/json
|
||||
Content-Length: 9510
|
||||
x-openstack-request-id: req-3d62ea04-9bdb-4e19-b218-1a81ff7d7337
|
||||
Connection: close
|
||||
|
||||
{
|
||||
"detailed": true,
|
||||
"gc": {
|
||||
"counts": [
|
||||
178,
|
||||
0,
|
||||
5
|
||||
],
|
||||
"threshold": [
|
||||
700,
|
||||
10,
|
||||
10
|
||||
]
|
||||
},
|
||||
"greenthreads": [
|
||||
<...>
|
||||
],
|
||||
"now": "2020-03-16 23:58:23.361209",
|
||||
"platform": "Linux-4.15.0-88-generic-x86_64-with-Ubuntu-18.04-bionic",
|
||||
"python_version": "3.6.9 (default, Nov 7 2019, 10:44:02) \n[GCC 8.3.0]",
|
||||
"reasons": [
|
||||
{
|
||||
"class": "OctaviaDBCheckResult",
|
||||
"details": "(pymysql.err.OperationalError) (2003, \"Can't connect to MySQL server on '127.0.0.1' ([Errno 111] Connection refused)\")\n(Background on this error at: http://sqlalche.me/e/e3q8)",
|
||||
"reason": "The Octavia database is unavailable."
|
||||
}
|
||||
],
|
||||
"threads": [
|
||||
<...>
|
||||
]
|
||||
}
|
||||
|
||||
Oslo Healthcheck Plugins
|
||||
========================
|
||||
|
||||
The Octavia API health monitoring endpoint, implemented with Oslo middleware
|
||||
healthcheck, is extensible using optional backend plugins. There are currently
|
||||
plugins provided by the Oslo middleware library and plugins provided by
|
||||
Octavia.
|
||||
|
||||
**Oslo middleware provided plugins**
|
||||
|
||||
* `disable_by_file <https://docs.openstack.org/oslo.middleware/latest/reference/healthcheck_plugins.html#disable-by-file>`_
|
||||
* `disable_by_files_ports <https://docs.openstack.org/oslo.middleware/latest/reference/healthcheck_plugins.html#disable-by-files-ports>`_
|
||||
|
||||
**Octavia provided plugins**
|
||||
|
||||
* `octavia_db_check`_
|
||||
|
||||
.. warning::
|
||||
|
||||
Some plugins may have long timeouts. It is a best practice to configure your
|
||||
healthcheck query to have connection, read, and/or data timeouts. The
|
||||
appropriate values will be unique to each deployment depending on the cloud
|
||||
performance, number of plugins, etc.
|
||||
|
||||
Enabling Octavia API Health Monitoring
|
||||
======================================
|
||||
|
||||
To enable the Octavia API health monitoring endpoint, the proper configuration
|
||||
file settings need to be updated and the Octavia API processes need to be
|
||||
restarted.
|
||||
|
||||
Start by enabling the endpoint:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[api_settings]
|
||||
healthcheck_enabled = True
|
||||
|
||||
When the healthcheck_enabled setting is *False*, queries of the /healthcheck
|
||||
will receive an HTTP 404 Not Found response.
|
||||
|
||||
You will then need to select the desired monitoring backend plugins:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[healthcheck]
|
||||
backends = octavia_db_check
|
||||
|
||||
.. note::
|
||||
|
||||
When no plugins are configured, the behavior of Oslo middleware healthcheck
|
||||
changes. Not only does it not run any tests, it will return 204 results
|
||||
instead of 200.
|
||||
|
||||
Optionally you can enable the "detailed" mode in Oslo middleware healthcheck.
|
||||
This will cause Oslo middleware healthcheck to return additional information
|
||||
about the API instance. It will also provide exception details if one was
|
||||
raised during the health check. This setting is False and disabled by default
|
||||
in the Octavia API.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[healthcheck]
|
||||
detailed = True
|
||||
|
||||
.. warning::
|
||||
|
||||
Enabling the 'detailed' setting will expose sensitive details about
|
||||
the API process. Do not enabled this unless you are sure it will
|
||||
not pose a **security risk** to your API instances.
|
||||
We highly recommend you do not enable this.
|
||||
|
||||
Using Octavia API Health Monitoring
|
||||
===================================
|
||||
|
||||
The Octavia API health monitoring endpoint can be accessed via the
|
||||
/healthmonitor path on the `Octavia API endpoint <https://docs.openstack.org/api-ref/load-balancer/v2/index.html#service-endpoints>`_.
|
||||
|
||||
For example, if your Octavia (load-balancer) endpoint in keystone is:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
https://10.21.21.78/load-balancer
|
||||
|
||||
You would access the Octavia API health monitoring endpoint via:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
https://10.21.21.78/load-balancer/healthcheck
|
||||
|
||||
A keystone token is not required to access this endpoint.
|
||||
|
||||
Octavia Plugins
|
||||
===============
|
||||
|
||||
octavia_db_check
|
||||
----------------
|
||||
|
||||
The octavia_db_check plugin validates the API instance has a working connection
|
||||
to the Octavia database. It executes a SQL no-op query, 'SELECT 1;', against
|
||||
the database.
|
||||
|
||||
.. note::
|
||||
|
||||
Many OpenStack services and libraries, such as oslo.db and sqlalchemy, also
|
||||
use the no-op query, 'SELECT 1;' for health checks.
|
||||
|
||||
The possible octavia_db_check results are:
|
||||
|
||||
+---------+--------+-------------+--------------------------------------+
|
||||
| Request | Result | Status Code | "reason" Message |
|
||||
+=========+========+=============+======================================+
|
||||
| GET | Pass | 200 | OK |
|
||||
+---------+--------+-------------+--------------------------------------+
|
||||
| HEAD | Pass | 204 | |
|
||||
+---------+--------+-------------+--------------------------------------+
|
||||
| GET | Fail | 503 | The Octavia database is unavailable. |
|
||||
+---------+--------+-------------+--------------------------------------+
|
||||
| HEAD | Fail | 503 | |
|
||||
+---------+--------+-------------+--------------------------------------+
|
||||
|
||||
When running Oslo middleware healthcheck in "detailed" mode, the "details"
|
||||
field will have additional information about the error encountered, including
|
||||
the exception details if they were available.
|
@ -33,6 +33,7 @@ Optional Installation and Configuration Guides
|
||||
providers/index.rst
|
||||
log-offloading.rst
|
||||
api-audit.rst
|
||||
healthcheck.rst
|
||||
flavors.rst
|
||||
apache-httpd.rst
|
||||
|
||||
|
@ -53,6 +53,9 @@
|
||||
# The minimum health monitor delay interval for UDP-CONNECT Health Monitor type
|
||||
# udp_connect_min_interval_health_monitor = 3
|
||||
|
||||
# Boolean to enable/disable oslo middleware /healthcheck in the Octavia API
|
||||
# healthcheck_enabled = False
|
||||
|
||||
[database]
|
||||
# This line MUST be changed to actually run the plugin.
|
||||
# Example:
|
||||
@ -572,3 +575,21 @@
|
||||
|
||||
# List of enabled provider agents.
|
||||
# enabled_provider_agents =
|
||||
|
||||
[healthcheck]
|
||||
# WARNING: Enabling the 'detailed' setting will expose sensitive details about
|
||||
# the API process. Do not enabled this unless you are sure it will
|
||||
# not pose a security risk to your API instances.
|
||||
# We highly recommend you do not enable this.
|
||||
# detailed = False
|
||||
|
||||
# This is a list of oslo middleware healthcheck backend plugins to enable for
|
||||
# the oslo middleware health check.
|
||||
#
|
||||
# Plugins provided by oslo middleware:
|
||||
# disable_by_file
|
||||
# disable_by_files_ports
|
||||
# Plugins provided by Octavia:
|
||||
# octavia_db_check
|
||||
#
|
||||
# backends =
|
||||
|
@ -86,7 +86,7 @@ oslo.db==4.27.0
|
||||
oslo.i18n==3.15.3
|
||||
oslo.log==3.36.0
|
||||
oslo.messaging==6.3.0
|
||||
oslo.middleware==3.31.0
|
||||
oslo.middleware==4.0.1
|
||||
oslo.policy==1.30.0
|
||||
oslo.reports==1.18.0
|
||||
oslo.serialization==2.18.0
|
||||
@ -99,7 +99,7 @@ paramiko==2.4.1
|
||||
Paste==2.0.3
|
||||
PasteDeploy==1.5.2
|
||||
pbr==2.0.0
|
||||
pecan==1.0.0
|
||||
pecan==1.3.2
|
||||
pep8==1.7.1
|
||||
pika==0.10.0
|
||||
pika-pool==0.1.3
|
||||
@ -169,7 +169,7 @@ vine==1.1.4
|
||||
voluptuous==0.11.1
|
||||
waitress==1.1.0
|
||||
warlock==1.3.0
|
||||
WebOb==1.7.1
|
||||
WebOb==1.8.2
|
||||
WebTest==2.0.29
|
||||
Werkzeug==0.14.1
|
||||
wrapt==1.10.11
|
||||
|
@ -20,7 +20,8 @@ from oslo_log import log as logging
|
||||
from oslo_middleware import cors
|
||||
from oslo_middleware import http_proxy_to_wsgi
|
||||
from oslo_middleware import request_id
|
||||
import pecan
|
||||
from pecan import configuration as pecan_configuration
|
||||
from pecan import make_app as pecan_make_app
|
||||
|
||||
from octavia.api import config as app_config
|
||||
from octavia.api.drivers import driver_factory
|
||||
@ -36,7 +37,7 @@ CONF = cfg.CONF
|
||||
def get_pecan_config():
|
||||
"""Returns the pecan config."""
|
||||
filename = app_config.__file__.replace('.pyc', '.py')
|
||||
return pecan.configuration.conf_from_file(filename)
|
||||
return pecan_configuration.conf_from_file(filename)
|
||||
|
||||
|
||||
def _init_drivers():
|
||||
@ -56,9 +57,9 @@ def setup_app(pecan_config=None, debug=False, argv=None):
|
||||
|
||||
if not pecan_config:
|
||||
pecan_config = get_pecan_config()
|
||||
pecan.configuration.set_config(dict(pecan_config), overwrite=True)
|
||||
pecan_configuration.set_config(dict(pecan_config), overwrite=True)
|
||||
|
||||
return pecan.make_app(
|
||||
return pecan_make_app(
|
||||
pecan_config.app.root,
|
||||
wrap_app=_wrap_app,
|
||||
debug=debug,
|
||||
|
47
octavia/api/healthcheck/healthcheck_plugins.py
Normal file
47
octavia/api/healthcheck/healthcheck_plugins.py
Normal file
@ -0,0 +1,47 @@
|
||||
# Copyright 2020 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
from oslo_middleware.healthcheck import pluginbase
|
||||
|
||||
from octavia.db import api as db_apis
|
||||
from octavia.db import healthcheck
|
||||
|
||||
|
||||
class OctaviaDBHealthcheck(pluginbase.HealthcheckBaseExtension):
|
||||
|
||||
UNAVAILABLE_REASON = 'The Octavia database is unavailable.'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(OctaviaDBHealthcheck, self).__init__(*args, **kwargs)
|
||||
|
||||
def healthcheck(self, server_port):
|
||||
try:
|
||||
result, message = healthcheck.check_database_connection(
|
||||
db_apis.get_session())
|
||||
if result:
|
||||
return OctaviaDBCheckResult(available=True, reason="OK")
|
||||
else:
|
||||
return OctaviaDBCheckResult(available=False,
|
||||
reason=self.UNAVAILABLE_REASON,
|
||||
details=message)
|
||||
except Exception as e:
|
||||
return OctaviaDBCheckResult(available=False,
|
||||
reason=self.UNAVAILABLE_REASON,
|
||||
details=str(e))
|
||||
|
||||
|
||||
class OctaviaDBCheckResult(pluginbase.HealthcheckResult):
|
||||
"""Result sub-class to provide a unique name in detail reports."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(OctaviaDBCheckResult, self).__init__(*args, **kwargs)
|
@ -12,25 +12,41 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_middleware import healthcheck
|
||||
from pecan import abort as pecan_abort
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from pecan import rest
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
from octavia.api.v2 import controllers as v2_controller
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RootController(rest.RestController):
|
||||
class RootController(object):
|
||||
"""The controller with which the pecan wsgi app should be created."""
|
||||
|
||||
def __init__(self):
|
||||
super(RootController, self).__init__()
|
||||
setattr(self, 'v2.0', v2_controller.V2Controller())
|
||||
setattr(self, 'v2', v2_controller.V2Controller())
|
||||
if CONF.api_settings.healthcheck_enabled:
|
||||
self.healthcheck_obj = healthcheck.Healthcheck.app_factory(None)
|
||||
|
||||
# Run the oslo middleware healthcheck for /healthcheck
|
||||
@pecan_expose('json')
|
||||
@pecan_expose(content_type='plain/text')
|
||||
@pecan_expose(content_type='text/html')
|
||||
def healthcheck(self): # pylint: disable=inconsistent-return-statements
|
||||
if CONF.api_settings.healthcheck_enabled:
|
||||
if pecan_request.method not in ['GET', 'HEAD']:
|
||||
pecan_abort(405)
|
||||
return self.healthcheck_obj.process_request(pecan_request)
|
||||
pecan_abort(404)
|
||||
|
||||
def _add_a_version(self, versions, version, url_version, status,
|
||||
timestamp, base_url):
|
||||
@ -45,7 +61,7 @@ class RootController(rest.RestController):
|
||||
})
|
||||
|
||||
@wsme_pecan.wsexpose(wtypes.text)
|
||||
def get(self):
|
||||
def index(self):
|
||||
host_url = pecan_request.path_url
|
||||
|
||||
if not host_url.endswith('/'):
|
||||
|
@ -17,7 +17,8 @@ from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
from oslo_utils import excutils
|
||||
import pecan
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -41,7 +42,7 @@ class AmphoraController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, id, fields=None):
|
||||
"""Gets a single amphora's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_amp = self._get_db_amp(context.session, id, show_deleted=False)
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
@ -57,7 +58,7 @@ class AmphoraController(base.BaseController):
|
||||
ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""Gets all health monitors."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
@ -73,7 +74,7 @@ class AmphoraController(base.BaseController):
|
||||
return amp_types.AmphoraeRootResponse(
|
||||
amphorae=result, amphorae_links=links)
|
||||
|
||||
@pecan.expose()
|
||||
@pecan_expose()
|
||||
def _lookup(self, amphora_id, *remainder):
|
||||
"""Overridden pecan _lookup method for custom routing.
|
||||
|
||||
@ -107,7 +108,7 @@ class FailoverController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=202)
|
||||
def put(self):
|
||||
"""Fails over an amphora"""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
db_amp = self._get_db_amp(context.session, self.amp_id,
|
||||
show_deleted=False)
|
||||
@ -153,7 +154,7 @@ class AmphoraUpdateController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=202)
|
||||
def put(self):
|
||||
"""Update amphora agent configuration"""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
db_amp = self._get_db_amp(context.session, self.amp_id,
|
||||
show_deleted=False)
|
||||
@ -188,7 +189,7 @@ class AmphoraStatsController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(amp_types.StatisticsRootResponse, wtypes.text,
|
||||
status_code=200)
|
||||
def get(self):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_STATS)
|
||||
|
@ -17,7 +17,7 @@ from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import uuidutils
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from sqlalchemy.orm import exc as sa_exception
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
@ -43,7 +43,7 @@ class AvailabilityZoneProfileController(base.BaseController):
|
||||
wtypes.text, [wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, id, fields=None):
|
||||
"""Gets an Availability Zone Profile's detail."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ONE)
|
||||
if id == constants.NIL_UUID:
|
||||
@ -63,7 +63,7 @@ class AvailabilityZoneProfileController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""Lists all Availability Zone Profiles."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ALL)
|
||||
@ -87,7 +87,7 @@ class AvailabilityZoneProfileController(base.BaseController):
|
||||
"""Creates an Availability Zone Profile."""
|
||||
availability_zone_profile = (
|
||||
availability_zone_profile_.availability_zone_profile)
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_POST)
|
||||
# Do a basic JSON validation on the metadata
|
||||
@ -155,7 +155,7 @@ class AvailabilityZoneProfileController(base.BaseController):
|
||||
"""Updates an Availability Zone Profile."""
|
||||
availability_zone_profile = (
|
||||
availability_zone_profile_.availability_zone_profile)
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_PUT)
|
||||
|
||||
@ -216,7 +216,7 @@ class AvailabilityZoneProfileController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, availability_zone_profile_id):
|
||||
"""Deletes an Availability Zone Profile"""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_DELETE)
|
||||
|
@ -16,7 +16,7 @@ from oslo_db import api as oslo_db_api
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from sqlalchemy.orm import exc as sa_exception
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
@ -40,7 +40,7 @@ class AvailabilityZonesController(base.BaseController):
|
||||
wtypes.text, [wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, name, fields=None):
|
||||
"""Gets an Availability Zone's detail."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ONE)
|
||||
if name == constants.NIL_UUID:
|
||||
@ -60,7 +60,7 @@ class AvailabilityZonesController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""Lists all Availability Zones."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ALL)
|
||||
@ -82,7 +82,7 @@ class AvailabilityZonesController(base.BaseController):
|
||||
def post(self, availability_zone_):
|
||||
"""Creates an Availability Zone."""
|
||||
availability_zone = availability_zone_.availability_zone
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_POST)
|
||||
|
||||
@ -111,7 +111,7 @@ class AvailabilityZonesController(base.BaseController):
|
||||
body=availability_zone_types.AvailabilityZoneRootPUT)
|
||||
def put(self, name, availability_zone_):
|
||||
availability_zone = availability_zone_.availability_zone
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_PUT)
|
||||
if name == constants.NIL_UUID:
|
||||
@ -144,7 +144,7 @@ class AvailabilityZonesController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, availability_zone_name):
|
||||
"""Deletes an Availability Zone"""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_DELETE)
|
||||
|
@ -16,7 +16,8 @@ from cryptography.hazmat.backends import default_backend
|
||||
from cryptography import x509
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from pecan import rest as pecan_rest
|
||||
from stevedore import driver as stevedore_driver
|
||||
from wsme import types as wtypes
|
||||
|
||||
@ -31,7 +32,7 @@ CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseController(pecan.rest.RestController):
|
||||
class BaseController(pecan_rest.RestController):
|
||||
RBAC_TYPE = None
|
||||
|
||||
def __init__(self):
|
||||
@ -257,7 +258,7 @@ class BaseController(pecan.rest.RestController):
|
||||
return attrs
|
||||
|
||||
def _validate_tls_refs(self, tls_refs):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
bad_refs = []
|
||||
for ref in tls_refs:
|
||||
try:
|
||||
@ -272,7 +273,7 @@ class BaseController(pecan.rest.RestController):
|
||||
raise exceptions.CertificateRetrievalException(ref=bad_refs)
|
||||
|
||||
def _validate_client_ca_and_crl_refs(self, client_ca_ref, crl_ref):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
bad_refs = []
|
||||
try:
|
||||
self.cert_manager.set_acls(context, client_ca_ref)
|
||||
|
@ -18,7 +18,7 @@ from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import uuidutils
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from sqlalchemy.orm import exc as sa_exception
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
@ -44,7 +44,7 @@ class FlavorProfileController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, id, fields=None):
|
||||
"""Gets a flavor profile's detail."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ONE)
|
||||
if id == constants.NIL_UUID:
|
||||
@ -61,7 +61,7 @@ class FlavorProfileController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""Lists all flavor profiles."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ALL)
|
||||
@ -81,7 +81,7 @@ class FlavorProfileController(base.BaseController):
|
||||
def post(self, flavor_profile_):
|
||||
"""Creates a flavor Profile."""
|
||||
flavorprofile = flavor_profile_.flavorprofile
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_POST)
|
||||
# Do a basic JSON validation on the metadata
|
||||
@ -138,7 +138,7 @@ class FlavorProfileController(base.BaseController):
|
||||
def put(self, id, flavor_profile_):
|
||||
"""Updates a flavor Profile."""
|
||||
flavorprofile = flavor_profile_.flavorprofile
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_PUT)
|
||||
|
||||
@ -190,7 +190,7 @@ class FlavorProfileController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, flavor_profile_id):
|
||||
"""Deletes a Flavor Profile"""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_DELETE)
|
||||
|
@ -18,7 +18,7 @@ from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import uuidutils
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from sqlalchemy.orm import exc as sa_exception
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
@ -42,7 +42,7 @@ class FlavorsController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, id, fields=None):
|
||||
"""Gets a flavor's detail."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ONE)
|
||||
if id == constants.NIL_UUID:
|
||||
@ -58,7 +58,7 @@ class FlavorsController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""Lists all flavors."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ALL)
|
||||
@ -77,7 +77,7 @@ class FlavorsController(base.BaseController):
|
||||
def post(self, flavor_):
|
||||
"""Creates a flavor."""
|
||||
flavor = flavor_.flavor
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_POST)
|
||||
|
||||
@ -106,7 +106,7 @@ class FlavorsController(base.BaseController):
|
||||
body=flavor_types.FlavorRootPUT)
|
||||
def put(self, id, flavor_):
|
||||
flavor = flavor_.flavor
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_PUT)
|
||||
if id == constants.NIL_UUID:
|
||||
@ -134,7 +134,7 @@ class FlavorsController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, flavor_id):
|
||||
"""Deletes a Flavor"""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_DELETE)
|
||||
|
@ -17,7 +17,7 @@ from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -48,7 +48,7 @@ class HealthMonitorController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, id, fields=None):
|
||||
"""Gets a single healthmonitor's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_hm = self._get_db_hm(context.session, id, show_deleted=False)
|
||||
|
||||
self._auth_validate_action(context, db_hm.project_id,
|
||||
@ -64,7 +64,7 @@ class HealthMonitorController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, project_id=None, fields=None):
|
||||
"""Gets all health monitors."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
query_filter = self._auth_get_all(context, project_id)
|
||||
@ -196,7 +196,7 @@ class HealthMonitorController(base.BaseController):
|
||||
body=hm_types.HealthMonitorRootPOST, status_code=201)
|
||||
def post(self, health_monitor_):
|
||||
"""Creates a health monitor on a pool."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
health_monitor = health_monitor_.healthmonitor
|
||||
|
||||
if (not CONF.api_settings.allow_ping_health_monitors and
|
||||
@ -334,7 +334,7 @@ class HealthMonitorController(base.BaseController):
|
||||
body=hm_types.HealthMonitorRootPUT, status_code=200)
|
||||
def put(self, id, health_monitor_):
|
||||
"""Updates a health monitor."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
health_monitor = health_monitor_.healthmonitor
|
||||
db_hm = self._get_db_hm(context.session, id, show_deleted=False)
|
||||
|
||||
@ -393,7 +393,7 @@ class HealthMonitorController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, id):
|
||||
"""Deletes a health monitor."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_hm = self._get_db_hm(context.session, id, show_deleted=False)
|
||||
|
||||
pool = self._get_db_pool(context.session, db_hm.pool_id)
|
||||
|
@ -16,7 +16,8 @@ from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
import pecan
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -48,7 +49,7 @@ class L7PolicyController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get(self, id, fields=None):
|
||||
"""Gets a single l7policy's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_l7policy = self._get_db_l7policy(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -65,7 +66,7 @@ class L7PolicyController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, project_id=None, fields=None):
|
||||
"""Lists all l7policies of a listener."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
query_filter = self._auth_get_all(context, project_id)
|
||||
@ -115,7 +116,7 @@ class L7PolicyController(base.BaseController):
|
||||
def post(self, l7policy_):
|
||||
"""Creates a l7policy on a listener."""
|
||||
l7policy = l7policy_.l7policy
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
# Verify the parent listener exists
|
||||
listener_id = l7policy.listener_id
|
||||
listener = self._get_db_listener(
|
||||
@ -206,7 +207,7 @@ class L7PolicyController(base.BaseController):
|
||||
if val in l7policy_dict:
|
||||
l7policy_dict[attr] = l7policy_dict.pop(val)
|
||||
sanitized_l7policy = l7policy_types.L7PolicyPUT(**l7policy_dict)
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
db_l7policy = self._get_db_l7policy(context.session, id,
|
||||
show_deleted=False)
|
||||
@ -268,7 +269,7 @@ class L7PolicyController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, id):
|
||||
"""Deletes a l7policy."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_l7policy = self._get_db_l7policy(context.session, id,
|
||||
show_deleted=False)
|
||||
load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
|
||||
@ -300,14 +301,14 @@ class L7PolicyController(base.BaseController):
|
||||
driver_utils.call_provider(driver.name, driver.l7policy_delete,
|
||||
provider_l7policy)
|
||||
|
||||
@pecan.expose()
|
||||
@pecan_expose()
|
||||
def _lookup(self, l7policy_id, *remainder):
|
||||
"""Overridden pecan _lookup method for custom routing.
|
||||
|
||||
Verifies that the l7policy passed in the url exists, and if so decides
|
||||
which controller, if any, should control be passed.
|
||||
"""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
if l7policy_id and remainder and remainder[0] == 'rules':
|
||||
remainder = remainder[1:]
|
||||
db_l7policy = self.repositories.l7policy.get(
|
||||
|
@ -15,7 +15,7 @@
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -46,7 +46,7 @@ class L7RuleController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get(self, id, fields=None):
|
||||
"""Gets a single l7rule's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_l7rule = self._get_db_l7rule(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -63,7 +63,7 @@ class L7RuleController(base.BaseController):
|
||||
ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""Lists all l7rules of a l7policy."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
l7policy = self._get_db_l7policy(context.session, self.l7policy_id,
|
||||
@ -127,7 +127,7 @@ class L7RuleController(base.BaseController):
|
||||
validate.l7rule_data(l7rule)
|
||||
except Exception as e:
|
||||
raise exceptions.L7RuleValidation(error=e)
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
db_l7policy = self._get_db_l7policy(context.session, self.l7policy_id,
|
||||
show_deleted=False)
|
||||
@ -189,7 +189,7 @@ class L7RuleController(base.BaseController):
|
||||
def put(self, id, l7rule_):
|
||||
"""Updates a l7rule."""
|
||||
l7rule = l7rule_.rule
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_l7rule = self._get_db_l7rule(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -256,7 +256,7 @@ class L7RuleController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, id):
|
||||
"""Deletes a l7rule."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_l7rule = self._get_db_l7rule(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
|
@ -17,7 +17,8 @@ from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
import pecan
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -51,7 +52,7 @@ class ListenersController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, id, fields=None):
|
||||
"""Gets a single listener's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_listener = self._get_db_listener(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -72,7 +73,7 @@ class ListenersController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, project_id=None, fields=None):
|
||||
"""Lists all listeners."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
query_filter = self._auth_get_all(context, project_id)
|
||||
@ -237,7 +238,7 @@ class ListenersController(base.BaseController):
|
||||
|
||||
# Validate that the L4 protocol (UDP or TCP) is not already used for
|
||||
# the specified protocol_port in this load balancer
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
query_filter = {
|
||||
'project_id': listener_dict['project_id'],
|
||||
'load_balancer_id': listener_dict['load_balancer_id'],
|
||||
@ -310,7 +311,7 @@ class ListenersController(base.BaseController):
|
||||
def post(self, listener_):
|
||||
"""Creates a listener on a load balancer."""
|
||||
listener = listener_.listener
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
load_balancer_id = listener.loadbalancer_id
|
||||
listener.project_id, provider = self._get_lb_project_id_provider(
|
||||
@ -507,7 +508,7 @@ class ListenersController(base.BaseController):
|
||||
def put(self, id, listener_):
|
||||
"""Updates a listener on a load balancer."""
|
||||
listener = listener_.listener
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_listener = self._get_db_listener(context.session, id,
|
||||
show_deleted=False)
|
||||
load_balancer_id = db_listener.load_balancer_id
|
||||
@ -567,7 +568,7 @@ class ListenersController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, id):
|
||||
"""Deletes a listener from a load balancer."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_listener = self._get_db_listener(context.session, id,
|
||||
show_deleted=False)
|
||||
load_balancer_id = db_listener.load_balancer_id
|
||||
@ -594,7 +595,7 @@ class ListenersController(base.BaseController):
|
||||
driver_utils.call_provider(driver.name, driver.listener_delete,
|
||||
provider_listener)
|
||||
|
||||
@pecan.expose()
|
||||
@pecan_expose()
|
||||
def _lookup(self, id, *remainder):
|
||||
"""Overridden pecan _lookup method for custom routing.
|
||||
|
||||
@ -616,7 +617,7 @@ class StatisticsController(base.BaseController, stats.StatsMixin):
|
||||
@wsme_pecan.wsexpose(listener_types.StatisticsRootResponse, wtypes.text,
|
||||
status_code=200)
|
||||
def get(self):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_listener = self._get_db_listener(context.session, self.id,
|
||||
show_deleted=False)
|
||||
if not db_listener:
|
||||
|
@ -18,7 +18,8 @@ from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import strutils
|
||||
import pecan
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from sqlalchemy.orm import exc as sa_exception
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
@ -56,7 +57,7 @@ class LoadBalancersController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_one(self, id, fields=None):
|
||||
"""Gets a single load balancer's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
load_balancer = self._get_db_lb(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -78,7 +79,7 @@ class LoadBalancersController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, project_id=None, fields=None):
|
||||
"""Lists all load balancers."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
query_filter = self._auth_get_all(context, project_id)
|
||||
@ -373,7 +374,7 @@ class LoadBalancersController(base.BaseController):
|
||||
def post(self, load_balancer):
|
||||
"""Creates a load balancer."""
|
||||
load_balancer = load_balancer.loadbalancer
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
if not load_balancer.project_id and context.project_id:
|
||||
load_balancer.project_id = context.project_id
|
||||
@ -607,7 +608,7 @@ class LoadBalancersController(base.BaseController):
|
||||
def put(self, id, load_balancer):
|
||||
"""Updates a load balancer."""
|
||||
load_balancer = load_balancer.loadbalancer
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_lb = self._get_db_lb(context.session, id, show_deleted=False)
|
||||
|
||||
self._auth_validate_action(context, db_lb.project_id,
|
||||
@ -665,7 +666,7 @@ class LoadBalancersController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, wtypes.text, status_code=204)
|
||||
def delete(self, id, cascade=False):
|
||||
"""Deletes a load balancer."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
cascade = strutils.bool_from_string(cascade)
|
||||
db_lb = self._get_db_lb(context.session, id, show_deleted=False)
|
||||
|
||||
@ -692,7 +693,7 @@ class LoadBalancersController(base.BaseController):
|
||||
driver_utils.call_provider(driver.name, driver.loadbalancer_delete,
|
||||
provider_loadbalancer, cascade)
|
||||
|
||||
@pecan.expose()
|
||||
@pecan_expose()
|
||||
def _lookup(self, id, *remainder):
|
||||
"""Overridden pecan _lookup method for custom routing.
|
||||
|
||||
@ -731,7 +732,7 @@ class StatusController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(lb_types.StatusRootResponse, wtypes.text,
|
||||
status_code=200)
|
||||
def get(self):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
load_balancer = self._get_db_lb(context.session, self.id,
|
||||
show_deleted=False)
|
||||
if not load_balancer:
|
||||
@ -759,7 +760,7 @@ class StatisticsController(base.BaseController, stats.StatsMixin):
|
||||
@wsme_pecan.wsexpose(lb_types.StatisticsRootResponse, wtypes.text,
|
||||
status_code=200)
|
||||
def get(self):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
load_balancer = self._get_db_lb(context.session, self.id,
|
||||
show_deleted=False)
|
||||
if not load_balancer:
|
||||
@ -787,7 +788,7 @@ class FailoverController(LoadBalancersController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=202)
|
||||
def put(self, **kwargs):
|
||||
"""Fails over a loadbalancer"""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_lb = self._get_db_lb(context.session, self.lb_id,
|
||||
show_deleted=False)
|
||||
|
||||
|
@ -17,7 +17,7 @@ from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import strutils
|
||||
import pecan
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -48,7 +48,7 @@ class MemberController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get(self, id, fields=None):
|
||||
"""Gets a single pool member's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_member = self._get_db_member(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -67,7 +67,7 @@ class MemberController(base.BaseController):
|
||||
ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""Lists all pool members of a pool."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
pool = self._get_db_pool(context.session, self.pool_id,
|
||||
@ -144,7 +144,7 @@ class MemberController(base.BaseController):
|
||||
def post(self, member_):
|
||||
"""Creates a pool member on a pool."""
|
||||
member = member_.member
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
validate.ip_not_reserved(member.address)
|
||||
|
||||
@ -229,7 +229,7 @@ class MemberController(base.BaseController):
|
||||
def put(self, id, member_):
|
||||
"""Updates a pool member."""
|
||||
member = member_.member
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_member = self._get_db_member(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -285,7 +285,7 @@ class MemberController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, id):
|
||||
"""Deletes a pool member."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_member = self._get_db_member(context.session, id,
|
||||
show_deleted=False)
|
||||
|
||||
@ -327,7 +327,7 @@ class MembersController(MemberController):
|
||||
"""Updates all members."""
|
||||
members = members_.members
|
||||
additive_only = strutils.bool_from_string(additive_only)
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
db_pool = self._get_db_pool(context.session, self.pool_id)
|
||||
old_members = db_pool.members
|
||||
|
@ -17,7 +17,8 @@ from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
import pecan
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -51,7 +52,7 @@ class PoolsController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get(self, id, fields=None):
|
||||
"""Gets a pool's details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_pool = self._get_db_pool(context.session, id, show_deleted=False)
|
||||
|
||||
self._auth_validate_action(context, db_pool.project_id,
|
||||
@ -66,7 +67,7 @@ class PoolsController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True)
|
||||
def get_all(self, project_id=None, fields=None):
|
||||
"""Lists all pools."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
query_filter = self._auth_get_all(context, project_id)
|
||||
@ -188,7 +189,7 @@ class PoolsController(base.BaseController):
|
||||
# For some API requests the listener_id will be passed in the
|
||||
# pool_dict:
|
||||
pool = pool_.pool
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
if pool.protocol == constants.PROTOCOL_UDP:
|
||||
self._validate_pool_request_for_udp(pool)
|
||||
else:
|
||||
@ -372,7 +373,7 @@ class PoolsController(base.BaseController):
|
||||
def put(self, id, pool_):
|
||||
"""Updates a pool on a load balancer."""
|
||||
pool = pool_.pool
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_pool = self._get_db_pool(context.session, id, show_deleted=False)
|
||||
|
||||
project_id, provider = self._get_lb_project_id_provider(
|
||||
@ -429,7 +430,7 @@ class PoolsController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||
def delete(self, id):
|
||||
"""Deletes a pool from a load balancer."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
db_pool = self._get_db_pool(context.session, id, show_deleted=False)
|
||||
if db_pool.l7policies:
|
||||
raise exceptions.PoolInUseByL7Policy(
|
||||
@ -458,14 +459,14 @@ class PoolsController(base.BaseController):
|
||||
driver_utils.call_provider(driver.name, driver.pool_delete,
|
||||
provider_pool)
|
||||
|
||||
@pecan.expose()
|
||||
@pecan_expose()
|
||||
def _lookup(self, pool_id, *remainder):
|
||||
"""Overridden pecan _lookup method for custom routing.
|
||||
|
||||
Verifies that the pool passed in the url exists, and if so decides
|
||||
which controller, if any, should control be passed.
|
||||
"""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
if pool_id and remainder and remainder[0] == 'members':
|
||||
remainder = remainder[1:]
|
||||
db_pool = self.repositories.pool.get(context.session, id=pool_id)
|
||||
|
@ -14,7 +14,8 @@
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import pecan
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -39,7 +40,7 @@ class ProviderController(base.BaseController):
|
||||
ignore_extra_args=True)
|
||||
def get_all(self, fields=None):
|
||||
"""List enabled provider drivers and their descriptions."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
@ -53,7 +54,7 @@ class ProviderController(base.BaseController):
|
||||
response_list = self._filter_fields(response_list, fields)
|
||||
return provider_types.ProvidersRootResponse(providers=response_list)
|
||||
|
||||
@pecan.expose()
|
||||
@pecan_expose()
|
||||
def _lookup(self, provider, *remainder):
|
||||
"""Overridden pecan _lookup method for custom routing.
|
||||
|
||||
@ -82,7 +83,7 @@ class FlavorCapabilitiesController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True,
|
||||
status_code=200)
|
||||
def get_all(self, fields=None):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ALL)
|
||||
self.driver = driver_factory.get_driver(self.provider)
|
||||
@ -97,7 +98,7 @@ class FlavorCapabilitiesController(base.BaseController):
|
||||
# Apply any valid filters provided as URL parameters
|
||||
name_filter = None
|
||||
description_filter = None
|
||||
pagination_helper = pecan.request.context.get(
|
||||
pagination_helper = pecan_request.context.get(
|
||||
constants.PAGINATION_HELPER)
|
||||
if pagination_helper:
|
||||
name_filter = pagination_helper.params.get(constants.NAME)
|
||||
@ -132,7 +133,7 @@ class AvailabilityZoneCapabilitiesController(base.BaseController):
|
||||
[wtypes.text], ignore_extra_args=True,
|
||||
status_code=200)
|
||||
def get_all(self, fields=None):
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ALL)
|
||||
self.driver = driver_factory.get_driver(self.provider)
|
||||
@ -149,7 +150,7 @@ class AvailabilityZoneCapabilitiesController(base.BaseController):
|
||||
# Apply any valid filters provided as URL parameters
|
||||
name_filter = None
|
||||
description_filter = None
|
||||
pagination_helper = pecan.request.context.get(
|
||||
pagination_helper = pecan_request.context.get(
|
||||
constants.PAGINATION_HELPER)
|
||||
if pagination_helper:
|
||||
name_filter = pagination_helper.params.get(constants.NAME)
|
||||
|
@ -13,7 +13,8 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
import pecan
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
@ -35,7 +36,7 @@ class QuotasController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(quota_types.QuotaResponse, wtypes.text)
|
||||
def get(self, project_id):
|
||||
"""Get a single project's quota details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
self._auth_validate_action(context, project_id, constants.RBAC_GET_ONE)
|
||||
|
||||
@ -46,7 +47,7 @@ class QuotasController(base.BaseController):
|
||||
ignore_extra_args=True)
|
||||
def get_all(self, project_id=None):
|
||||
"""List all non-default quotas."""
|
||||
pcontext = pecan.request.context
|
||||
pcontext = pecan_request.context
|
||||
context = pcontext.get('octavia_context')
|
||||
|
||||
query_filter = self._auth_get_all(context, project_id)
|
||||
@ -63,7 +64,7 @@ class QuotasController(base.BaseController):
|
||||
body=quota_types.QuotaPUT, status_code=202)
|
||||
def put(self, project_id, quotas):
|
||||
"""Update any or all quotas for a project."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
if not project_id:
|
||||
raise exceptions.MissingAPIProjectID()
|
||||
@ -79,7 +80,7 @@ class QuotasController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(None, wtypes.text, status_code=202)
|
||||
def delete(self, project_id):
|
||||
"""Reset a project's quotas to the default values."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
if not project_id:
|
||||
raise exceptions.MissingAPIProjectID()
|
||||
@ -90,7 +91,7 @@ class QuotasController(base.BaseController):
|
||||
db_quotas = self._get_db_quotas(context.session, project_id)
|
||||
return self._convert_db_to_type(db_quotas, quota_types.QuotaResponse)
|
||||
|
||||
@pecan.expose()
|
||||
@pecan_expose()
|
||||
def _lookup(self, project_id, *remainder):
|
||||
"""Overridden pecan _lookup method for routing default endpoint."""
|
||||
if project_id and remainder and remainder[0] == 'default':
|
||||
@ -108,7 +109,7 @@ class QuotasDefaultController(base.BaseController):
|
||||
@wsme_pecan.wsexpose(quota_types.QuotaResponse, wtypes.text)
|
||||
def get(self):
|
||||
"""Get a project's default quota details."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
context = pecan_request.context.get('octavia_context')
|
||||
|
||||
if not self.project_id:
|
||||
raise exceptions.MissingAPIProjectID()
|
||||
|
@ -100,6 +100,9 @@ api_opts = [
|
||||
help=_("The minimum health monitor delay interval for the "
|
||||
"UDP-CONNECT Health Monitor type. A negative integer "
|
||||
"value means 'no limit'.")),
|
||||
cfg.BoolOpt('healthcheck_enabled', default=False,
|
||||
help=_("When True, the oslo middleware healthcheck endpoint "
|
||||
"is enabled in the Octavia API.")),
|
||||
]
|
||||
|
||||
# Options only used by the amphora agent
|
||||
|
@ -21,7 +21,8 @@ from octavia.common import constants
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
_NOAUTH_PATHS = ['/', '/load-balancer/']
|
||||
_NOAUTH_PATHS = ['/', '/load-balancer/', '/healthcheck',
|
||||
'/load-balancer/healthcheck']
|
||||
|
||||
|
||||
class KeystoneSession(object):
|
||||
|
37
octavia/db/healthcheck.py
Normal file
37
octavia/db/healthcheck.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright 2020 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
from oslo_log import log as logging
|
||||
|
||||
from octavia.i18n import _
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def check_database_connection(session):
|
||||
"""This is a simple database connection check function.
|
||||
|
||||
It will do a simple no-op query (low overhead) against the sqlalchemy
|
||||
session passed in.
|
||||
|
||||
:param session: A Sql Alchemy database session.
|
||||
:returns: True if the connection check is successful, False if not.
|
||||
"""
|
||||
try:
|
||||
session.execute('SELECT 1;')
|
||||
return True, None
|
||||
except Exception as e:
|
||||
message = _('Database health check failed due to: {err}.').format(
|
||||
err=str(e))
|
||||
LOG.error(message)
|
||||
return False, message
|
261
octavia/tests/functional/api/test_healthcheck.py
Normal file
261
octavia/tests/functional/api/test_healthcheck.py
Normal file
@ -0,0 +1,261 @@
|
||||
# Copyright 2020 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
from unittest import mock
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as oslo_fixture
|
||||
import pecan
|
||||
|
||||
from octavia.api import config as pconfig
|
||||
from octavia.api.healthcheck import healthcheck_plugins
|
||||
from octavia.tests.functional.db import base as base_db_test
|
||||
|
||||
|
||||
class TestHealthCheck(base_db_test.OctaviaDBTestBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestHealthCheck, self).setUp()
|
||||
|
||||
# We need to define these early as they are late loaded in oslo
|
||||
# middleware and our configuration overrides would not apply.
|
||||
# Note: These must match exactly the option definitions in
|
||||
# oslo.middleware healthcheck! If not you will get duplicate option
|
||||
# errors.
|
||||
healthcheck_opts = [
|
||||
cfg.BoolOpt(
|
||||
'detailed', default=False,
|
||||
help='Show more detailed information as part of the response. '
|
||||
'Security note: Enabling this option may expose '
|
||||
'sensitive details about the service being monitored. '
|
||||
'Be sure to verify that it will not violate your '
|
||||
'security policies.'),
|
||||
cfg.ListOpt(
|
||||
'backends', default=[],
|
||||
help='Additional backends that can perform health checks and '
|
||||
'report that information back as part of a request.'),
|
||||
]
|
||||
cfg.CONF.register_opts(healthcheck_opts, group='healthcheck')
|
||||
|
||||
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
self.conf.config(group='healthcheck', backends=['octavia_db_check'])
|
||||
self.UNAVAILABLE = (healthcheck_plugins.OctaviaDBHealthcheck.
|
||||
UNAVAILABLE_REASON)
|
||||
|
||||
def reset_pecan():
|
||||
pecan.set_config({}, overwrite=True)
|
||||
|
||||
self.addCleanup(reset_pecan)
|
||||
|
||||
def _make_app(self):
|
||||
# Note: we need to set argv=() to stop the wsgi setup_app from
|
||||
# pulling in the testing tool sys.argv
|
||||
return pecan.testing.load_test_app({'app': pconfig.app,
|
||||
'wsme': pconfig.wsme}, argv=())
|
||||
|
||||
def _get_enabled_app(self):
|
||||
self.conf.config(group='api_settings', healthcheck_enabled=True)
|
||||
return self._make_app()
|
||||
|
||||
def _get_disabled_app(self):
|
||||
self.conf.config(group='api_settings', healthcheck_enabled=False)
|
||||
return self._make_app()
|
||||
|
||||
def _get(self, app, path, params=None, headers=None, status=200,
|
||||
expect_errors=False):
|
||||
response = app.get(path, params=params, headers=headers, status=status,
|
||||
expect_errors=expect_errors)
|
||||
return response
|
||||
|
||||
def _head(self, app, path, headers=None, status=204, expect_errors=False):
|
||||
response = app.head(path, headers=headers, status=status,
|
||||
expect_errors=expect_errors)
|
||||
return response
|
||||
|
||||
def _post(self, app, path, body, headers=None, status=201,
|
||||
expect_errors=False):
|
||||
response = app.post_json(path, params=body, headers=headers,
|
||||
status=status, expect_errors=expect_errors)
|
||||
return response
|
||||
|
||||
def _put(self, app, path, body, headers=None, status=200,
|
||||
expect_errors=False):
|
||||
response = app.put_json(path, params=body, headers=headers,
|
||||
status=status, expect_errors=expect_errors)
|
||||
return response
|
||||
|
||||
def _delete(self, app, path, params=None, headers=None, status=204,
|
||||
expect_errors=False):
|
||||
response = app.delete(path, headers=headers, status=status,
|
||||
expect_errors=expect_errors)
|
||||
return response
|
||||
|
||||
def test_healthcheck_get_text(self):
|
||||
self.conf.config(group='healthcheck', detailed=False)
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck')
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertEqual('OK', response.text)
|
||||
|
||||
# Note: For whatever reason, detailed=True text has no additonal info
|
||||
def test_healthcheck_get_text_detailed(self):
|
||||
self.conf.config(group='healthcheck', detailed=True)
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck')
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertEqual('OK', response.text)
|
||||
|
||||
def test_healthcheck_get_json(self):
|
||||
self.conf.config(group='healthcheck', detailed=False)
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'application/json'})
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertFalse(response.json['detailed'])
|
||||
self.assertEqual(['OK'], response.json['reasons'])
|
||||
|
||||
def test_healthcheck_get_json_detailed(self):
|
||||
self.conf.config(group='healthcheck', detailed=True)
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'application/json'})
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertTrue(response.json['detailed'])
|
||||
self.assertEqual('OK', response.json['reasons'][0]['reason'])
|
||||
self.assertTrue(response.json['gc'])
|
||||
|
||||
def test_healthcheck_get_html(self):
|
||||
self.conf.config(group='healthcheck', detailed=False)
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'text/html'})
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn('OK', response.text)
|
||||
|
||||
def test_healthcheck_get_html_detailed(self):
|
||||
self.conf.config(group='healthcheck', detailed=True)
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'text/html'})
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn('OK', response.text)
|
||||
self.assertIn('Garbage collector', response.text)
|
||||
|
||||
def test_healthcheck_disabled_get(self):
|
||||
self._get(self._get_disabled_app(), '/healthcheck', status=404)
|
||||
|
||||
def test_healthcheck_head(self):
|
||||
response = self._head(self._get_enabled_app(), '/healthcheck')
|
||||
self.assertEqual(204, response.status_code)
|
||||
|
||||
def test_healthcheck_disabled_head(self):
|
||||
self._head(self._get_disabled_app(), '/healthcheck', status=404)
|
||||
|
||||
# These should be denied by the API
|
||||
def test_healthcheck_post(self):
|
||||
self._post(self._get_enabled_app(), '/healthcheck',
|
||||
{'foo': 'bar'}, status=405)
|
||||
|
||||
def test_healthcheck_put(self):
|
||||
self._put(self._get_enabled_app(), '/healthcheck',
|
||||
{'foo': 'bar'}, status=405)
|
||||
|
||||
def test_healthcheck_delete(self):
|
||||
self._delete(self._get_enabled_app(), '/healthcheck',
|
||||
status=405)
|
||||
|
||||
@mock.patch('octavia.db.api.get_session')
|
||||
def test_healthcheck_get_failed(self, mock_get_session):
|
||||
mock_session = mock.MagicMock()
|
||||
mock_session.execute.side_effect = [Exception('boom')]
|
||||
mock_get_session.return_value = mock_session
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
self.assertEqual(self.UNAVAILABLE, response.text)
|
||||
|
||||
@mock.patch('octavia.db.api.get_session')
|
||||
def test_healthcheck_head_failed(self, mock_get_session):
|
||||
mock_session = mock.MagicMock()
|
||||
mock_session.execute.side_effect = [Exception('boom')]
|
||||
mock_get_session.return_value = mock_session
|
||||
response = self._head(self._get_enabled_app(), '/healthcheck',
|
||||
status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
|
||||
@mock.patch('octavia.db.healthcheck.check_database_connection',
|
||||
side_effect=Exception('boom'))
|
||||
def test_healthcheck_get_failed_check(self, mock_db_check):
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
self.assertEqual(self.UNAVAILABLE, response.text)
|
||||
|
||||
@mock.patch('octavia.db.api.get_session')
|
||||
def test_healthcheck_get_json_failed(self, mock_get_session):
|
||||
self.conf.config(group='healthcheck', detailed=False)
|
||||
mock_session = mock.MagicMock()
|
||||
mock_session.execute.side_effect = [Exception('boom')]
|
||||
mock_get_session.return_value = mock_session
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'application/json'},
|
||||
status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
self.assertFalse(response.json['detailed'])
|
||||
self.assertEqual([self.UNAVAILABLE],
|
||||
response.json['reasons'])
|
||||
|
||||
@mock.patch('octavia.db.api.get_session')
|
||||
def test_healthcheck_get_json_detailed_failed(self, mock_get_session):
|
||||
self.conf.config(group='healthcheck', detailed=True)
|
||||
mock_session = mock.MagicMock()
|
||||
mock_session.execute.side_effect = [Exception('boom')]
|
||||
mock_get_session.return_value = mock_session
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'application/json'},
|
||||
status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
self.assertTrue(response.json['detailed'])
|
||||
self.assertEqual(self.UNAVAILABLE,
|
||||
response.json['reasons'][0]['reason'])
|
||||
self.assertIn('boom', response.json['reasons'][0]['details'])
|
||||
|
||||
@mock.patch('octavia.db.api.get_session')
|
||||
def test_healthcheck_get_html_failed(self, mock_get_session):
|
||||
self.conf.config(group='healthcheck', detailed=False)
|
||||
mock_session = mock.MagicMock()
|
||||
mock_session.execute.side_effect = [Exception('boom')]
|
||||
mock_get_session.return_value = mock_session
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'text/html'}, status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
self.assertIn(self.UNAVAILABLE, response.text)
|
||||
|
||||
@mock.patch('octavia.db.api.get_session')
|
||||
def test_healthcheck_get_html_detailed_failed(self, mock_get_session):
|
||||
self.conf.config(group='healthcheck', detailed=True)
|
||||
mock_session = mock.MagicMock()
|
||||
mock_session.execute.side_effect = [Exception('boom')]
|
||||
mock_get_session.return_value = mock_session
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
headers={'Accept': 'text/html'}, status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
self.assertIn(self.UNAVAILABLE, response.text)
|
||||
self.assertIn('boom', response.text)
|
||||
self.assertIn('Garbage collector', response.text)
|
||||
|
||||
# Note: For whatever reason, detailed=True text has no additonal info
|
||||
@mock.patch('octavia.db.api.get_session')
|
||||
def test_healthcheck_get_text_detailed_failed(self, mock_get_session):
|
||||
self.conf.config(group='healthcheck', detailed=True)
|
||||
mock_session = mock.MagicMock()
|
||||
mock_session.execute.side_effect = [Exception('boom')]
|
||||
mock_get_session.return_value = mock_session
|
||||
response = self._get(self._get_enabled_app(), '/healthcheck',
|
||||
status=503)
|
||||
self.assertEqual(503, response.status_code)
|
||||
self.assertEqual(self.UNAVAILABLE, response.text)
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added the oslo-middleware healthcheck app to the Octavia API.
|
||||
Hitting /healthcheck will return a 200. This is enabled via the
|
||||
[api_settings]healthcheck_enabled setting and is disabled by default.
|
@ -3,7 +3,7 @@
|
||||
# process, which may cause wedges in the gate later.
|
||||
alembic>=0.8.10 # MIT
|
||||
cotyledon>=1.3.0 # Apache-2.0
|
||||
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
||||
pecan>=1.3.2 # BSD
|
||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
||||
Babel!=2.4.0,>=2.3.4 # BSD
|
||||
@ -13,7 +13,7 @@ rfc3986>=0.3.1 # Apache-2.0
|
||||
keystoneauth1>=3.4.0 # Apache-2.0
|
||||
keystonemiddleware>=4.17.0 # Apache-2.0
|
||||
python-neutronclient>=6.7.0 # Apache-2.0
|
||||
WebOb>=1.7.1 # MIT
|
||||
WebOb>=1.8.2 # MIT
|
||||
stevedore>=1.20.0 # Apache-2.0
|
||||
oslo.config>=5.2.0 # Apache-2.0
|
||||
oslo.context>=2.19.2 # Apache-2.0
|
||||
@ -21,7 +21,7 @@ oslo.db>=4.27.0 # Apache-2.0
|
||||
oslo.i18n>=3.15.3 # Apache-2.0
|
||||
oslo.log>=3.36.0 # Apache-2.0
|
||||
oslo.messaging>=6.3.0 # Apache-2.0
|
||||
oslo.middleware>=3.31.0 # Apache-2.0
|
||||
oslo.middleware>=4.0.1 # Apache-2.0
|
||||
oslo.policy>=1.30.0 # Apache-2.0
|
||||
oslo.reports>=1.18.0 # Apache-2.0
|
||||
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
|
||||
|
@ -100,6 +100,8 @@ oslo.policy.policies =
|
||||
octavia = octavia.policies:list_rules
|
||||
oslo.policy.enforcer =
|
||||
octavia = octavia.common.policy:get_no_context_enforcer
|
||||
oslo.middleware.healthcheck =
|
||||
octavia_db_check = octavia.api.healthcheck.healthcheck_plugins:OctaviaDBHealthcheck
|
||||
|
||||
[compile_catalog]
|
||||
directory = octavia/locale
|
||||
|
Loading…
x
Reference in New Issue
Block a user