Merge "Fix multi-listener load balancers"
This commit is contained in:
commit
37799137a3
|
@ -29,9 +29,7 @@ communication is limited to fail-over protocols.)
|
||||||
Versioning
|
Versioning
|
||||||
----------
|
----------
|
||||||
All Octavia APIs (including internal APIs like this one) are versioned. For the
|
All Octavia APIs (including internal APIs like this one) are versioned. For the
|
||||||
purposes of this document, the initial version of this API shall be v0.5. (So,
|
purposes of this document, the initial version of this API shall be 1.0.
|
||||||
any reference to a *:version* variable should be replaced with the literal
|
|
||||||
string 'v0.5'.)
|
|
||||||
|
|
||||||
Response codes
|
Response codes
|
||||||
--------------
|
--------------
|
||||||
|
@ -74,136 +72,6 @@ a secure way (ex. memory filesystem).
|
||||||
API
|
API
|
||||||
===
|
===
|
||||||
|
|
||||||
Get amphora topology
|
|
||||||
--------------------
|
|
||||||
* **URL:** /*:version*/topology
|
|
||||||
* **Method:** GET
|
|
||||||
* **URL params:** none
|
|
||||||
* **Data params:** none
|
|
||||||
* **Success Response:**
|
|
||||||
|
|
||||||
* Code: 200
|
|
||||||
|
|
||||||
* Content: JSON formatted listing of this amphora's configured topology.
|
|
||||||
|
|
||||||
* **Error Response:**
|
|
||||||
|
|
||||||
* none
|
|
||||||
|
|
||||||
JSON Response attributes:
|
|
||||||
|
|
||||||
* *hostname* - hostname of amphora
|
|
||||||
* *uuid* - uuid of amphora
|
|
||||||
* *topology* - One of: SINGLE, ACTIVE-STANDBY, ACTIVE-ACTIVE
|
|
||||||
* *role* - One of ACTIVE, STANDBY (only applicable to ACTIVE-STANDBY)
|
|
||||||
* *ha_ip* - only applicable to ACTIVE-STANDBY topology: Highly-available
|
|
||||||
routing IP address for the ACTIVE-STANDBY pair.
|
|
||||||
|
|
||||||
**Examples**
|
|
||||||
|
|
||||||
* Success code 200:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
JSON response:
|
|
||||||
{
|
|
||||||
'hostname': 'octavia-haproxy-img-00328',
|
|
||||||
'uuid': '6e2bc8a0-2548-4fb7-a5f0-fb1ef4a696ce',
|
|
||||||
'topology': 'SINGLE',
|
|
||||||
'role': 'ACTIVE',
|
|
||||||
'ha_ip': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
Set amphora topology
|
|
||||||
--------------------
|
|
||||||
* **URL:** /*:version*/topology
|
|
||||||
* **Method:** POST
|
|
||||||
* **URL params:** none
|
|
||||||
* **Data params:**
|
|
||||||
|
|
||||||
* *topology*: One of: SINGLE, ACTIVE-STANDBY, ACTIVE-ACTIVE
|
|
||||||
* *role*: One of: ACTIVE, STANDBY (only applicable to ACTIVE-STANDBY)
|
|
||||||
* *ha_ip*: (only applicable to ACTIVE-STANDBY) Highly-available IP for the
|
|
||||||
HA pair
|
|
||||||
* *secret*: (only applicable to ACTIVE-STANDBY topology) Shared secret used
|
|
||||||
for authentication with other HA pair member
|
|
||||||
|
|
||||||
* **Success Response:**
|
|
||||||
|
|
||||||
* Code: 200
|
|
||||||
|
|
||||||
* Content: OK
|
|
||||||
|
|
||||||
* Code: 202
|
|
||||||
|
|
||||||
* Content: OK
|
|
||||||
|
|
||||||
* **Error Response:**
|
|
||||||
|
|
||||||
* Code: 400
|
|
||||||
|
|
||||||
* Content: Invalid request.
|
|
||||||
* *(Response will also include information on which parameters did not*
|
|
||||||
*pass either a syntax check or other topology logic test)*
|
|
||||||
|
|
||||||
* Code: 503
|
|
||||||
|
|
||||||
* Content: Topology transition in progress
|
|
||||||
|
|
||||||
* **Response:**
|
|
||||||
|
|
||||||
| OK
|
|
||||||
|
|
||||||
**Notes:** In an ACTIVE-STANDBY configuration, the 'role' parameter might
|
|
||||||
change spontaneously due to a failure of one node. In other topologies, the
|
|
||||||
role is not used.
|
|
||||||
|
|
||||||
Also note that some topology changes can take several minutes to enact, yet
|
|
||||||
we want all API commands to return in a matter of seconds. In this case, a
|
|
||||||
topology change is initiated, and the amphora status changes from "OK" to
|
|
||||||
"TOPOLOGY-CHANGE". The controller should not try to change any resources during
|
|
||||||
this transition. (Any attempts will be met with an error.) Once the
|
|
||||||
topology change is complete, amphora status should return to "OK". (When the
|
|
||||||
UDP communication from amphorae to controller is defined, a 'transition
|
|
||||||
complete' message is probably one good candidate for this type of UDP
|
|
||||||
communication.)
|
|
||||||
|
|
||||||
**Examples**
|
|
||||||
|
|
||||||
* Success code 200:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
JSON POST parameters:
|
|
||||||
{
|
|
||||||
'topology': 'ACTIVE-STANDBY',
|
|
||||||
'role': 'ACTIVE',
|
|
||||||
'ha_ip': ' 203.0.113.2',
|
|
||||||
'secret': 'b20e06cf1abcf29c708d3b437f4a29892a0921d0',
|
|
||||||
}
|
|
||||||
|
|
||||||
Response:
|
|
||||||
OK
|
|
||||||
|
|
||||||
* Error code 400:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
Response:
|
|
||||||
{
|
|
||||||
'message': 'Invalid request',
|
|
||||||
'details': 'Unknown topology: BAD_TEST_DATA',
|
|
||||||
}
|
|
||||||
|
|
||||||
* Error code 503:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
Response:
|
|
||||||
{
|
|
||||||
'message': 'Topology transition in progress',
|
|
||||||
}
|
|
||||||
|
|
||||||
Get amphora info
|
Get amphora info
|
||||||
----------------
|
----------------
|
||||||
* **URL:** /info
|
* **URL:** /info
|
||||||
|
@ -249,7 +117,7 @@ version string prepended to it.
|
||||||
Get amphora details
|
Get amphora details
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/details
|
* **URL:** /1.0/details
|
||||||
* **Method:** GET
|
* **Method:** GET
|
||||||
* **URL params:** none
|
* **URL params:** none
|
||||||
* **Data params:** none
|
* **Data params:** none
|
||||||
|
@ -372,7 +240,7 @@ health of the amphora, currently-configured topology and role, etc.
|
||||||
Get interface
|
Get interface
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
* **URL:** /*:version*/interface/*:ip*
|
* **URL:** /1.0/interface/*:ip*
|
||||||
* **Method:** GET
|
* **Method:** GET
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
|
@ -408,7 +276,7 @@ Get interface
|
||||||
::
|
::
|
||||||
|
|
||||||
GET URL:
|
GET URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/interface/10.0.0.1
|
https://octavia-haproxy-img-00328.local/1.0/interface/10.0.0.1
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -422,7 +290,7 @@ Get interface
|
||||||
::
|
::
|
||||||
|
|
||||||
GET URL:
|
GET URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/interface/10.5.0.1
|
https://octavia-haproxy-img-00328.local/1.0/interface/10.5.0.1
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -435,7 +303,7 @@ Get interface
|
||||||
::
|
::
|
||||||
|
|
||||||
GET URL:
|
GET URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/interface/10.6.0.1.1
|
https://octavia-haproxy-img-00328.local/1.0/interface/10.6.0.1.1
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -446,7 +314,7 @@ Get interface
|
||||||
Get all listeners' statuses
|
Get all listeners' statuses
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners
|
* **URL:** /1.0/listeners
|
||||||
* **Method:** GET
|
* **Method:** GET
|
||||||
* **URL params:** none
|
* **URL params:** none
|
||||||
* **Data params:** none
|
* **Data params:** none
|
||||||
|
@ -492,91 +360,14 @@ a valid haproxy configuration).
|
||||||
'type': 'TERMINATED_HTTPS',
|
'type': 'TERMINATED_HTTPS',
|
||||||
}]
|
}]
|
||||||
|
|
||||||
Get a listener's status
|
Start or Stop a load balancer
|
||||||
-----------------------
|
-----------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:listener*
|
* **URL:** /1.0/loadbalancer/*:object_id*/*:action*
|
||||||
* **Method:** GET
|
|
||||||
* **URL params:**
|
|
||||||
|
|
||||||
* *:listener* = Listener UUID
|
|
||||||
|
|
||||||
* **Data params:** none
|
|
||||||
* **Success Response:**
|
|
||||||
|
|
||||||
* Code: 200
|
|
||||||
|
|
||||||
* Content: JSON-formatted listener status
|
|
||||||
|
|
||||||
* **Error Response:**
|
|
||||||
|
|
||||||
* Code: 404
|
|
||||||
|
|
||||||
* Content: Not Found
|
|
||||||
|
|
||||||
JSON Response attributes:
|
|
||||||
|
|
||||||
* *status* - One of the operational status: ACTIVE, STOPPED, ERROR -
|
|
||||||
future versions might support provisioning status:
|
|
||||||
PENDING_CREATE, PENDING_UPDATE, PENDING_DELETE, DELETED
|
|
||||||
* *uuid* - Listener UUID
|
|
||||||
* *type* - One of: TCP, HTTP, TERMINATED_HTTPS
|
|
||||||
* *pools* - Map of pool UUIDs and their overall UP / DOWN / DEGRADED status
|
|
||||||
* *members* - Map of member UUIDs and their overall UP / DOWN status
|
|
||||||
|
|
||||||
|
|
||||||
**Notes:** Note that this returns a status if: the pid file exists,
|
|
||||||
the stats socket exists, or an haproxy configuration is present (not
|
|
||||||
just if there is a valid haproxy configuration).
|
|
||||||
|
|
||||||
**Examples**
|
|
||||||
|
|
||||||
* Success code 200:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
JSON Response:
|
|
||||||
{
|
|
||||||
'status': 'ACTIVE',
|
|
||||||
'uuid': 'e2dfddc0-5b9e-11e4-8ed6-0800200c9a66',
|
|
||||||
'type': 'HTTP',
|
|
||||||
'pools':[
|
|
||||||
{
|
|
||||||
'uuid': '399bbf4b-5f6c-4370-a61e-ed2ff2fc9387',
|
|
||||||
'status': 'UP',
|
|
||||||
'members':[
|
|
||||||
{'73f6d278-ae1c-4248-ad02-0bfd50d69aab': 'UP'},
|
|
||||||
{'2edca57c-5890-4bcb-ae67-4ef75776cc67': 'DOWN'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'uuid': '2250eb21-16ca-44bd-9b12-0b4eb3d18140',
|
|
||||||
'status': 'DOWN',
|
|
||||||
'members':[
|
|
||||||
{'130dff11-4aab-4ba8-a39b-8d77caa7a1ad': 'DOWN'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
* Error code 404:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
JSON Response:
|
|
||||||
{
|
|
||||||
'message': 'Listener Not Found',
|
|
||||||
'details': 'No listener with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
|
||||||
}
|
|
||||||
|
|
||||||
Start or Stop a listener
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:listener*/*:action*
|
|
||||||
* **Method:** PUT
|
* **Method:** PUT
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
* *:listener* = Listener UUID
|
* *:object_id* = Object UUID
|
||||||
* *:action* = One of: start, stop, reload
|
* *:action* = One of: start, stop, reload
|
||||||
|
|
||||||
* **Data params:** none
|
* **Data params:** none
|
||||||
|
@ -612,7 +403,7 @@ Start or Stop a listener
|
||||||
|
|
||||||
| OK
|
| OK
|
||||||
| Configuration file is valid
|
| Configuration file is valid
|
||||||
| haproxy daemon for 7e9f91eb-b3e6-4e3b-a1a7-d6f7fdc1de7c started (pid 32428)
|
| haproxy daemon for 85e2111b-29c4-44be-94f3-e72045805801 started (pid 32428)
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
|
@ -621,12 +412,12 @@ Start or Stop a listener
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/start
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/start
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
'message': 'OK',
|
'message': 'OK',
|
||||||
'details': 'Configuration file is valid\nhaproxy daemon for 04bff5c3-5862-4a13-b9e3-9b440d0ed50a started',
|
'details': 'Configuration file is valid\nhaproxy daemon for 85e2111b-29c4-44be-94f3-e72045805801 started',
|
||||||
}
|
}
|
||||||
|
|
||||||
* Error code 400:
|
* Error code 400:
|
||||||
|
@ -634,7 +425,7 @@ Start or Stop a listener
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/BAD_TEST_DATA
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/BAD_TEST_DATA
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -647,12 +438,12 @@ Start or Stop a listener
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/stop
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/stop
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
'message': 'Listener Not Found',
|
'message': 'Listener Not Found',
|
||||||
'details': 'No listener with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
'details': 'No loadbalancer with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
||||||
}
|
}
|
||||||
|
|
||||||
* Error code 500:
|
* Error code 500:
|
||||||
|
@ -660,7 +451,7 @@ Start or Stop a listener
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/stop
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/stop
|
||||||
|
|
||||||
Response:
|
Response:
|
||||||
{
|
{
|
||||||
|
@ -680,7 +471,7 @@ Start or Stop a listener
|
||||||
Delete a listener
|
Delete a listener
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:listener*
|
* **URL:** /1.0/listeners/*:listener*
|
||||||
* **Method:** DELETE
|
* **Method:** DELETE
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
|
@ -724,7 +515,7 @@ Delete a listener
|
||||||
::
|
::
|
||||||
|
|
||||||
DELETE URL:
|
DELETE URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a
|
https://octavia-haproxy-img-00328.local/1.0/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -736,7 +527,7 @@ Delete a listener
|
||||||
::
|
::
|
||||||
|
|
||||||
DELETE URL:
|
DELETE URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a
|
https://octavia-haproxy-img-00328.local/1.0/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -756,11 +547,11 @@ Delete a listener
|
||||||
Upload SSL certificate PEM file
|
Upload SSL certificate PEM file
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:listener*/certificates/*:filename.pem*
|
* **URL:** /1.0/loadbalancer/*:loadbalancer_id*/certificates/*:filename.pem*
|
||||||
* **Method:** PUT
|
* **Method:** PUT
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
* *:listener* = Listener UUID
|
* *:loadbalancer_id* = Load balancer UUID
|
||||||
* *:filename* = PEM filename (see notes below for naming convention)
|
* *:filename* = PEM filename (see notes below for naming convention)
|
||||||
|
|
||||||
* **Data params:** Certificate data. (PEM file should be a concatenation of
|
* **Data params:** Certificate data. (PEM file should be a concatenation of
|
||||||
|
@ -812,7 +603,7 @@ explicitly restarted
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/certificates/www.example.com.pem
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/certificates/www.example.com.pem
|
||||||
(Put data should contain the certificate information, concatenated as
|
(Put data should contain the certificate information, concatenated as
|
||||||
described above)
|
described above)
|
||||||
|
|
||||||
|
@ -826,7 +617,7 @@ explicitly restarted
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/certificates/www.example.com.pem
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/certificates/www.example.com.pem
|
||||||
(If PUT data does not contain a certificate)
|
(If PUT data does not contain a certificate)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
@ -839,7 +630,7 @@ explicitly restarted
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/certificates/www.example.com.pem
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/certificates/www.example.com.pem
|
||||||
(If PUT data does not contain an RSA key)
|
(If PUT data does not contain an RSA key)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
@ -852,7 +643,7 @@ explicitly restarted
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/certificates/www.example.com.pem
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/certificates/www.example.com.pem
|
||||||
(If the first certificate and the RSA key do not have the same modulus.)
|
(If the first certificate and the RSA key do not have the same modulus.)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
@ -865,15 +656,14 @@ explicitly restarted
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/certificates/www.example.com.pem
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/certificates/www.example.com.pem
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
'message': 'Listener Not Found',
|
'message': 'Listener Not Found',
|
||||||
'details': 'No listener with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
'details': 'No loadbalancer with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
* Error code 503:
|
* Error code 503:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -883,15 +673,14 @@ explicitly restarted
|
||||||
'message': 'Topology transition in progress',
|
'message': 'Topology transition in progress',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Get SSL certificate md5sum
|
Get SSL certificate md5sum
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:listener*/certificates/*:filename.pem*
|
* **URL:** /1.0/loadbalancer/*:loadbalancer_id*/certificates/*:filename.pem*
|
||||||
* **Method:** GET
|
* **Method:** GET
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
* *:listener* = Listener UUID
|
* *:loadbalancer_id* = Load balancer UUID
|
||||||
* *:filename* = PEM filename (see notes below for naming convention)
|
* *:filename* = PEM filename (see notes below for naming convention)
|
||||||
|
|
||||||
* **Data params:** none
|
* **Data params:** none
|
||||||
|
@ -937,7 +726,7 @@ disclosing it over the wire from the amphora is a security risk.
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
'message': 'Listener Not Found',
|
'message': 'Listener Not Found',
|
||||||
'details': 'No listener with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
'details': 'No loadbalancer with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
||||||
}
|
}
|
||||||
|
|
||||||
* Error code 404:
|
* Error code 404:
|
||||||
|
@ -953,11 +742,11 @@ disclosing it over the wire from the amphora is a security risk.
|
||||||
Delete SSL certificate PEM file
|
Delete SSL certificate PEM file
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:listener*/certificates/*:filename.pem*
|
* **URL:** /1.0/loadbalancer/*:loadbalancer_id*/certificates/*:filename.pem*
|
||||||
* **Method:** DELETE
|
* **Method:** DELETE
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
* *:listener* = Listener UUID
|
* *:loadbalancer_id* = Load balancer UUID
|
||||||
* *:filename* = PEM filename (see notes below for naming convention)
|
* *:filename* = PEM filename (see notes below for naming convention)
|
||||||
|
|
||||||
* **Data params:** none
|
* **Data params:** none
|
||||||
|
@ -988,7 +777,7 @@ Delete SSL certificate PEM file
|
||||||
::
|
::
|
||||||
|
|
||||||
DELETE URL:
|
DELETE URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/certificates/www.example.com.pem
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/certificates/www.example.com.pem
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -1000,7 +789,7 @@ Delete SSL certificate PEM file
|
||||||
::
|
::
|
||||||
|
|
||||||
DELETE URL:
|
DELETE URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/certificates/www.example.com.pem
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/certificates/www.example.com.pem
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -1017,14 +806,14 @@ Delete SSL certificate PEM file
|
||||||
'message': 'Topology transition in progress',
|
'message': 'Topology transition in progress',
|
||||||
}
|
}
|
||||||
|
|
||||||
Upload listener haproxy configuration
|
Upload load balancer haproxy configuration
|
||||||
-------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:amphora_id*/*:listener*/haproxy
|
* **URL:** /1.0/loadbalancer/*:amphora_id*/*:loadbalancer_id*/haproxy
|
||||||
* **Method:** PUT
|
* **Method:** PUT
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
* *:listener* = Listener UUID
|
* *:loadbalancer_id* = Load Balancer UUID
|
||||||
* *:amphora_id* = Amphora UUID
|
* *:amphora_id* = Amphora UUID
|
||||||
|
|
||||||
* **Data params:** haproxy configuration file for the listener
|
* **Data params:** haproxy configuration file for the listener
|
||||||
|
@ -1071,7 +860,7 @@ out of the haproxy daemon status interface for tracking health and stats).
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/d459b1c8-54b0-4030-9bec-4f449e73b1ef/04bff5c3-5862-4a13-b9e3-9b440d0ed50a/haproxy
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/d459b1c8-54b0-4030-9bec-4f449e73b1ef/85e2111b-29c4-44be-94f3-e72045805801/haproxy
|
||||||
(Upload PUT data should be a raw haproxy.conf file.)
|
(Upload PUT data should be a raw haproxy.conf file.)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
@ -1098,14 +887,14 @@ out of the haproxy daemon status interface for tracking health and stats).
|
||||||
'message': 'Topology transition in progress',
|
'message': 'Topology transition in progress',
|
||||||
}
|
}
|
||||||
|
|
||||||
Get listener haproxy configuration
|
Get loadbalancer haproxy configuration
|
||||||
----------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/listeners/*:listener*/haproxy
|
* **URL:** /1.0/loadbalancer/*:loadbalancer_id*/haproxy
|
||||||
* **Method:** GET
|
* **Method:** GET
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
* *:listener* = Listener UUID
|
* *:loadbalancer_id* = Load balancer UUID
|
||||||
|
|
||||||
* **Data params:** none
|
* **Data params:** none
|
||||||
* **Success Response:**
|
* **Success Response:**
|
||||||
|
@ -1122,7 +911,7 @@ Get listener haproxy configuration
|
||||||
|
|
||||||
* **Response:**
|
* **Response:**
|
||||||
|
|
||||||
| # Config file for 7e9f91eb-b3e6-4e3b-a1a7-d6f7fdc1de7c
|
| # Config file for 85e2111b-29c4-44be-94f3-e72045805801
|
||||||
| (cut for brevity)
|
| (cut for brevity)
|
||||||
|
|
||||||
* **Implied actions:** none
|
* **Implied actions:** none
|
||||||
|
@ -1134,11 +923,11 @@ Get listener haproxy configuration
|
||||||
::
|
::
|
||||||
|
|
||||||
GET URL:
|
GET URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/listeners/7e9f91eb-b3e6-4e3b-a1a7-d6f7fdc1de7c/haproxy
|
https://octavia-haproxy-img-00328.local/1.0/loadbalancer/85e2111b-29c4-44be-94f3-e72045805801/haproxy
|
||||||
|
|
||||||
Response is the raw haproxy.cfg:
|
Response is the raw haproxy.cfg:
|
||||||
|
|
||||||
# Config file for 7e9f91eb-b3e6-4e3b-a1a7-d6f7fdc1de7c
|
# Config file for 85e2111b-29c4-44be-94f3-e72045805801
|
||||||
(cut for brevity)
|
(cut for brevity)
|
||||||
|
|
||||||
* Error code 404:
|
* Error code 404:
|
||||||
|
@ -1147,15 +936,14 @@ Get listener haproxy configuration
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
'message': 'Listener Not Found',
|
'message': 'Loadbalancer Not Found',
|
||||||
'details': 'No listener with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
'details': 'No loadbalancer with UUID: 04bff5c3-5862-4a13-b9e3-9b440d0ed50a',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Plug VIP
|
Plug VIP
|
||||||
--------
|
--------
|
||||||
|
|
||||||
* **URL:** /*:version*/plug/vip/*:ip*
|
* **URL:** /1.0/plug/vip/*:ip*
|
||||||
* **Method:** Post
|
* **Method:** Post
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
|
@ -1210,7 +998,7 @@ Plug VIP
|
||||||
::
|
::
|
||||||
|
|
||||||
POST URL:
|
POST URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/plug/vip/203.0.113.2
|
https://octavia-haproxy-img-00328.local/1.0/plug/vip/203.0.113.2
|
||||||
|
|
||||||
JSON POST parameters:
|
JSON POST parameters:
|
||||||
{
|
{
|
||||||
|
@ -1225,10 +1013,6 @@ Plug VIP
|
||||||
'details': 'VIP 203.0.113.2 plugged on interface eth1'
|
'details': 'VIP 203.0.113.2 plugged on interface eth1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* Error code 400:
|
* Error code 400:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -1251,7 +1035,7 @@ Plug VIP
|
||||||
Plug Network
|
Plug Network
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* **URL:** /*:version*/plug/network/
|
* **URL:** /1.0/plug/network/
|
||||||
* **Method:** POST
|
* **Method:** POST
|
||||||
* **URL params:** none
|
* **URL params:** none
|
||||||
|
|
||||||
|
@ -1292,7 +1076,7 @@ Plug Network
|
||||||
::
|
::
|
||||||
|
|
||||||
POST URL:
|
POST URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/plug/network/
|
https://octavia-haproxy-img-00328.local/1.0/plug/network/
|
||||||
|
|
||||||
JSON POST parameters:
|
JSON POST parameters:
|
||||||
{
|
{
|
||||||
|
@ -1319,7 +1103,7 @@ Plug Network
|
||||||
Upload SSL server certificate PEM file for Controller Communication
|
Upload SSL server certificate PEM file for Controller Communication
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/certificate
|
* **URL:** /1.0/certificate
|
||||||
* **Method:** PUT
|
* **Method:** PUT
|
||||||
|
|
||||||
* **Data params:** Certificate data. (PEM file should be a concatenation of
|
* **Data params:** Certificate data. (PEM file should be a concatenation of
|
||||||
|
@ -1362,7 +1146,7 @@ not be available for some time.
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/certificate
|
https://octavia-haproxy-img-00328.local/1.0/certificate
|
||||||
(Put data should contain the certificate information, concatenated as
|
(Put data should contain the certificate information, concatenated as
|
||||||
described above)
|
described above)
|
||||||
|
|
||||||
|
@ -1376,7 +1160,7 @@ not be available for some time.
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/certificates
|
https://octavia-haproxy-img-00328.local/1.0/certificates
|
||||||
(If PUT data does not contain a certificate)
|
(If PUT data does not contain a certificate)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
@ -1389,7 +1173,7 @@ not be available for some time.
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/certificate
|
https://octavia-haproxy-img-00328.local/1.0/certificate
|
||||||
(If PUT data does not contain an RSA key)
|
(If PUT data does not contain an RSA key)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
@ -1402,7 +1186,7 @@ not be available for some time.
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/certificate
|
https://octavia-haproxy-img-00328.local/1.0/certificate
|
||||||
(If the first certificate and the RSA key do not have the same modulus.)
|
(If the first certificate and the RSA key do not have the same modulus.)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
@ -1414,7 +1198,7 @@ not be available for some time.
|
||||||
Upload keepalived configuration
|
Upload keepalived configuration
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/vrrp/upload
|
* **URL:** /1.0/vrrp/upload
|
||||||
* **Method:** PUT
|
* **Method:** PUT
|
||||||
* **URL params:** none
|
* **URL params:** none
|
||||||
* **Data params:** none
|
* **Data params:** none
|
||||||
|
@ -1441,7 +1225,7 @@ OK
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URI:
|
PUT URI:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/vrrp/upload
|
https://octavia-haproxy-img-00328.local/1.0/vrrp/upload
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -1452,7 +1236,7 @@ OK
|
||||||
Start, Stop, or Reload keepalived
|
Start, Stop, or Reload keepalived
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/vrrp/*:action*
|
* **URL:** /1.0/vrrp/*:action*
|
||||||
* **Method:** PUT
|
* **Method:** PUT
|
||||||
* **URL params:**
|
* **URL params:**
|
||||||
|
|
||||||
|
@ -1489,7 +1273,7 @@ Start, Stop, or Reload keepalived
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/vrrp/start
|
https://octavia-haproxy-img-00328.local/1.0/vrrp/start
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -1502,7 +1286,7 @@ Start, Stop, or Reload keepalived
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/vrrp/BAD_TEST_DATA
|
https://octavia-haproxy-img-00328.local/1.0/vrrp/BAD_TEST_DATA
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -1515,7 +1299,7 @@ Start, Stop, or Reload keepalived
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/vrrp/stop
|
https://octavia-haproxy-img-00328.local/1.0/vrrp/stop
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
{
|
{
|
||||||
|
@ -1526,7 +1310,7 @@ Start, Stop, or Reload keepalived
|
||||||
Update the amphora agent configuration
|
Update the amphora agent configuration
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
* **URL:** /*:version*/config
|
* **URL:** /1.0/config
|
||||||
* **Method:** PUT
|
* **Method:** PUT
|
||||||
|
|
||||||
* **Data params:** A amphora-agent configuration file
|
* **Data params:** A amphora-agent configuration file
|
||||||
|
@ -1561,7 +1345,7 @@ will be updated.
|
||||||
::
|
::
|
||||||
|
|
||||||
PUT URL:
|
PUT URL:
|
||||||
https://octavia-haproxy-img-00328.local/v0.5/config
|
https://octavia-haproxy-img-00328.local/1.0/config
|
||||||
(Upload PUT data should be a raw amphora-agent.conf file.)
|
(Upload PUT data should be a raw amphora-agent.conf file.)
|
||||||
|
|
||||||
JSON Response:
|
JSON Response:
|
||||||
|
|
|
@ -12,4 +12,4 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
VERSION = '0.5'
|
VERSION = '1.0'
|
||||||
|
|
|
@ -46,7 +46,7 @@ class AmphoraInfo(object):
|
||||||
return webob.Response(json=body)
|
return webob.Response(json=body)
|
||||||
|
|
||||||
def compile_amphora_details(self, extend_udp_driver=None):
|
def compile_amphora_details(self, extend_udp_driver=None):
|
||||||
haproxy_listener_list = util.get_listeners()
|
haproxy_listener_list = sorted(util.get_listeners())
|
||||||
extend_body = {}
|
extend_body = {}
|
||||||
udp_listener_list = []
|
udp_listener_list = []
|
||||||
if extend_udp_driver:
|
if extend_udp_driver:
|
||||||
|
@ -87,8 +87,8 @@ class AmphoraInfo(object):
|
||||||
'load': self._load(),
|
'load': self._load(),
|
||||||
'topology': consts.TOPOLOGY_SINGLE,
|
'topology': consts.TOPOLOGY_SINGLE,
|
||||||
'topology_status': consts.TOPOLOGY_STATUS_OK,
|
'topology_status': consts.TOPOLOGY_STATUS_OK,
|
||||||
'listeners': list(
|
'listeners': sorted(list(
|
||||||
set(haproxy_listener_list + udp_listener_list))
|
set(haproxy_listener_list + udp_listener_list)))
|
||||||
if udp_listener_list else haproxy_listener_list,
|
if udp_listener_list else haproxy_listener_list,
|
||||||
'packages': {}}
|
'packages': {}}
|
||||||
if extend_body:
|
if extend_body:
|
||||||
|
@ -101,10 +101,10 @@ class AmphoraInfo(object):
|
||||||
version = subprocess.check_output(cmd.split())
|
version = subprocess.check_output(cmd.split())
|
||||||
return version
|
return version
|
||||||
|
|
||||||
def _count_haproxy_processes(self, listener_list):
|
def _count_haproxy_processes(self, lb_list):
|
||||||
num = 0
|
num = 0
|
||||||
for listener_id in listener_list:
|
for lb_id in lb_list:
|
||||||
if util.is_listener_running(listener_id):
|
if util.is_lb_running(lb_id):
|
||||||
# optional check if it's still running
|
# optional check if it's still running
|
||||||
num += 1
|
num += 1
|
||||||
return num
|
return num
|
||||||
|
|
|
@ -22,7 +22,7 @@ from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from octavia.amphorae.backends.agent.api_server import listener
|
from octavia.amphorae.backends.agent.api_server import loadbalancer
|
||||||
from octavia.amphorae.backends.agent.api_server import util
|
from octavia.amphorae.backends.agent.api_server import util
|
||||||
from octavia.common import constants as consts
|
from octavia.common import constants as consts
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ check_script_template = j2_env.get_template(consts.CHECK_SCRIPT_CONF)
|
||||||
class Keepalived(object):
|
class Keepalived(object):
|
||||||
|
|
||||||
def upload_keepalived_config(self):
|
def upload_keepalived_config(self):
|
||||||
stream = listener.Wrapped(flask.request.stream)
|
stream = loadbalancer.Wrapped(flask.request.stream)
|
||||||
|
|
||||||
if not os.path.exists(util.keepalived_dir()):
|
if not os.path.exists(util.keepalived_dir()):
|
||||||
os.makedirs(util.keepalived_dir())
|
os.makedirs(util.keepalived_dir())
|
||||||
|
|
|
@ -25,10 +25,9 @@ from oslo_log import log as logging
|
||||||
import webob
|
import webob
|
||||||
from werkzeug import exceptions
|
from werkzeug import exceptions
|
||||||
|
|
||||||
from octavia.amphorae.backends.agent.api_server import listener
|
from octavia.amphorae.backends.agent.api_server import loadbalancer
|
||||||
from octavia.amphorae.backends.agent.api_server import udp_listener_base
|
from octavia.amphorae.backends.agent.api_server import udp_listener_base
|
||||||
from octavia.amphorae.backends.agent.api_server import util
|
from octavia.amphorae.backends.agent.api_server import util
|
||||||
from octavia.amphorae.backends.utils import keepalivedlvs_query
|
|
||||||
from octavia.common import constants as consts
|
from octavia.common import constants as consts
|
||||||
|
|
||||||
BUFFER = 100
|
BUFFER = 100
|
||||||
|
@ -51,7 +50,7 @@ class KeepalivedLvs(udp_listener_base.UdpListenerApiServerBase):
|
||||||
_SUBSCRIBED_AMP_COMPILE = ['keepalived', 'ipvsadm']
|
_SUBSCRIBED_AMP_COMPILE = ['keepalived', 'ipvsadm']
|
||||||
|
|
||||||
def upload_udp_listener_config(self, listener_id):
|
def upload_udp_listener_config(self, listener_id):
|
||||||
stream = listener.Wrapped(flask.request.stream)
|
stream = loadbalancer.Wrapped(flask.request.stream)
|
||||||
NEED_CHECK = True
|
NEED_CHECK = True
|
||||||
|
|
||||||
if not os.path.exists(util.keepalived_lvs_dir()):
|
if not os.path.exists(util.keepalived_lvs_dir()):
|
||||||
|
@ -256,45 +255,6 @@ class KeepalivedLvs(udp_listener_base.UdpListenerApiServerBase):
|
||||||
})
|
})
|
||||||
return listeners
|
return listeners
|
||||||
|
|
||||||
def get_udp_listener_status(self, listener_id):
|
|
||||||
"""Gets the status of a UDP listener
|
|
||||||
|
|
||||||
This method will consult the stats socket
|
|
||||||
so calling this method will interfere with
|
|
||||||
the health daemon with the risk of the amphora
|
|
||||||
shut down
|
|
||||||
|
|
||||||
:param listener_id: The id of the listener
|
|
||||||
"""
|
|
||||||
self._check_udp_listener_exists(listener_id)
|
|
||||||
|
|
||||||
status = self._check_udp_listener_status(listener_id)
|
|
||||||
|
|
||||||
if status != consts.ACTIVE:
|
|
||||||
stats = dict(
|
|
||||||
status=status,
|
|
||||||
uuid=listener_id,
|
|
||||||
type='UDP'
|
|
||||||
)
|
|
||||||
return webob.Response(json=stats)
|
|
||||||
|
|
||||||
stats = dict(
|
|
||||||
status=status,
|
|
||||||
uuid=listener_id,
|
|
||||||
type='UDP'
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
pool = keepalivedlvs_query.get_udp_listener_pool_status(
|
|
||||||
listener_id)
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
return webob.Response(json=dict(
|
|
||||||
message="Error getting kernel lvs status for udp listener "
|
|
||||||
"{}".format(listener_id),
|
|
||||||
details=e.output), status=500)
|
|
||||||
stats['pools'] = [pool]
|
|
||||||
return webob.Response(json=stats)
|
|
||||||
|
|
||||||
def delete_udp_listener(self, listener_id):
|
def delete_udp_listener(self, listener_id):
|
||||||
try:
|
try:
|
||||||
self._check_udp_listener_exists(listener_id)
|
self._check_udp_listener_exists(listener_id)
|
||||||
|
|
|
@ -31,7 +31,6 @@ from werkzeug import exceptions
|
||||||
from octavia.amphorae.backends.agent.api_server import haproxy_compatibility
|
from octavia.amphorae.backends.agent.api_server import haproxy_compatibility
|
||||||
from octavia.amphorae.backends.agent.api_server import osutils
|
from octavia.amphorae.backends.agent.api_server import osutils
|
||||||
from octavia.amphorae.backends.agent.api_server import util
|
from octavia.amphorae.backends.agent.api_server import util
|
||||||
from octavia.amphorae.backends.utils import haproxy_query as query
|
|
||||||
from octavia.common import constants as consts
|
from octavia.common import constants as consts
|
||||||
from octavia.common import utils as octavia_utils
|
from octavia.common import utils as octavia_utils
|
||||||
|
|
||||||
|
@ -54,10 +53,6 @@ SYSVINIT_TEMPLATE = JINJA_ENV.get_template(SYSVINIT_CONF)
|
||||||
SYSTEMD_TEMPLATE = JINJA_ENV.get_template(SYSTEMD_CONF)
|
SYSTEMD_TEMPLATE = JINJA_ENV.get_template(SYSTEMD_CONF)
|
||||||
|
|
||||||
|
|
||||||
class ParsingError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# Wrap a stream so we can compute the md5 while reading
|
# Wrap a stream so we can compute the md5 while reading
|
||||||
class Wrapped(object):
|
class Wrapped(object):
|
||||||
def __init__(self, stream_):
|
def __init__(self, stream_):
|
||||||
|
@ -77,37 +72,37 @@ class Wrapped(object):
|
||||||
return getattr(self.stream, attr)
|
return getattr(self.stream, attr)
|
||||||
|
|
||||||
|
|
||||||
class Listener(object):
|
class Loadbalancer(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._osutils = osutils.BaseOS.get_os_util()
|
self._osutils = osutils.BaseOS.get_os_util()
|
||||||
|
|
||||||
def get_haproxy_config(self, listener_id):
|
def get_haproxy_config(self, lb_id):
|
||||||
"""Gets the haproxy config
|
"""Gets the haproxy config
|
||||||
|
|
||||||
:param listener_id: the id of the listener
|
:param listener_id: the id of the listener
|
||||||
"""
|
"""
|
||||||
self._check_listener_exists(listener_id)
|
self._check_lb_exists(lb_id)
|
||||||
with open(util.config_path(listener_id), 'r') as file:
|
with open(util.config_path(lb_id), 'r') as file:
|
||||||
cfg = file.read()
|
cfg = file.read()
|
||||||
resp = webob.Response(cfg, content_type='text/plain')
|
resp = webob.Response(cfg, content_type='text/plain')
|
||||||
resp.headers['ETag'] = hashlib.md5(six.b(cfg)).hexdigest() # nosec
|
resp.headers['ETag'] = hashlib.md5(six.b(cfg)).hexdigest() # nosec
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def upload_haproxy_config(self, amphora_id, listener_id):
|
def upload_haproxy_config(self, amphora_id, lb_id):
|
||||||
"""Upload the haproxy config
|
"""Upload the haproxy config
|
||||||
|
|
||||||
:param amphora_id: The id of the amphora to update
|
:param amphora_id: The id of the amphora to update
|
||||||
:param listener_id: The id of the listener
|
:param lb_id: The id of the loadbalancer
|
||||||
"""
|
"""
|
||||||
stream = Wrapped(flask.request.stream)
|
stream = Wrapped(flask.request.stream)
|
||||||
# We have to hash here because HAProxy has a string length limitation
|
# We have to hash here because HAProxy has a string length limitation
|
||||||
# in the configuration file "peer <peername>" lines
|
# in the configuration file "peer <peername>" lines
|
||||||
peer_name = octavia_utils.base64_sha1_string(amphora_id).rstrip('=')
|
peer_name = octavia_utils.base64_sha1_string(amphora_id).rstrip('=')
|
||||||
if not os.path.exists(util.haproxy_dir(listener_id)):
|
if not os.path.exists(util.haproxy_dir(lb_id)):
|
||||||
os.makedirs(util.haproxy_dir(listener_id))
|
os.makedirs(util.haproxy_dir(lb_id))
|
||||||
|
|
||||||
name = os.path.join(util.haproxy_dir(listener_id), 'haproxy.cfg.new')
|
name = os.path.join(util.haproxy_dir(lb_id), 'haproxy.cfg.new')
|
||||||
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||||
# mode 00600
|
# mode 00600
|
||||||
mode = stat.S_IRUSR | stat.S_IWUSR
|
mode = stat.S_IRUSR | stat.S_IWUSR
|
||||||
|
@ -148,7 +143,7 @@ class Listener(object):
|
||||||
status=400)
|
status=400)
|
||||||
|
|
||||||
# file ok - move it
|
# file ok - move it
|
||||||
os.rename(name, util.config_path(listener_id))
|
os.rename(name, util.config_path(lb_id))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
@ -156,7 +151,7 @@ class Listener(object):
|
||||||
|
|
||||||
LOG.debug('Found init system: %s', init_system)
|
LOG.debug('Found init system: %s', init_system)
|
||||||
|
|
||||||
init_path = util.init_path(listener_id, init_system)
|
init_path = util.init_path(lb_id, init_system)
|
||||||
|
|
||||||
if init_system == consts.INIT_SYSTEMD:
|
if init_system == consts.INIT_SYSTEMD:
|
||||||
template = SYSTEMD_TEMPLATE
|
template = SYSTEMD_TEMPLATE
|
||||||
|
@ -194,9 +189,9 @@ class Listener(object):
|
||||||
|
|
||||||
text = template.render(
|
text = template.render(
|
||||||
peer_name=peer_name,
|
peer_name=peer_name,
|
||||||
haproxy_pid=util.pid_path(listener_id),
|
haproxy_pid=util.pid_path(lb_id),
|
||||||
haproxy_cmd=util.CONF.haproxy_amphora.haproxy_cmd,
|
haproxy_cmd=util.CONF.haproxy_amphora.haproxy_cmd,
|
||||||
haproxy_cfg=util.config_path(listener_id),
|
haproxy_cfg=util.config_path(lb_id),
|
||||||
haproxy_user_group_cfg=consts.HAPROXY_USER_GROUP_CFG,
|
haproxy_user_group_cfg=consts.HAPROXY_USER_GROUP_CFG,
|
||||||
respawn_count=util.CONF.haproxy_amphora.respawn_count,
|
respawn_count=util.CONF.haproxy_amphora.respawn_count,
|
||||||
respawn_interval=(util.CONF.haproxy_amphora.
|
respawn_interval=(util.CONF.haproxy_amphora.
|
||||||
|
@ -212,25 +207,25 @@ class Listener(object):
|
||||||
# Make sure the new service is enabled on boot
|
# Make sure the new service is enabled on boot
|
||||||
if init_system == consts.INIT_SYSTEMD:
|
if init_system == consts.INIT_SYSTEMD:
|
||||||
util.run_systemctl_command(
|
util.run_systemctl_command(
|
||||||
consts.ENABLE, "haproxy-{list}".format(list=listener_id))
|
consts.ENABLE, "haproxy-{lb_id}".format(lb_id=lb_id))
|
||||||
elif init_system == consts.INIT_SYSVINIT:
|
elif init_system == consts.INIT_SYSVINIT:
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(init_enable_cmd.split(),
|
subprocess.check_output(init_enable_cmd.split(),
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
LOG.error("Failed to enable haproxy-%(list)s service: "
|
LOG.error("Failed to enable haproxy-%(lb_id)s service: "
|
||||||
"%(err)s %(out)s", {'list': listener_id, 'err': e,
|
"%(err)s %(out)s", {'lb_id': lb_id, 'err': e,
|
||||||
'out': e.output})
|
'out': e.output})
|
||||||
return webob.Response(json=dict(
|
return webob.Response(json=dict(
|
||||||
message="Error enabling haproxy-{0} service".format(
|
message="Error enabling haproxy-{0} service".format(
|
||||||
listener_id), details=e.output), status=500)
|
lb_id), details=e.output), status=500)
|
||||||
|
|
||||||
res = webob.Response(json={'message': 'OK'}, status=202)
|
res = webob.Response(json={'message': 'OK'}, status=202)
|
||||||
res.headers['ETag'] = stream.get_md5()
|
res.headers['ETag'] = stream.get_md5()
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def start_stop_listener(self, listener_id, action):
|
def start_stop_lb(self, lb_id, action):
|
||||||
action = action.lower()
|
action = action.lower()
|
||||||
if action not in [consts.AMP_ACTION_START,
|
if action not in [consts.AMP_ACTION_START,
|
||||||
consts.AMP_ACTION_STOP,
|
consts.AMP_ACTION_STOP,
|
||||||
|
@ -239,30 +234,30 @@ class Listener(object):
|
||||||
message='Invalid Request',
|
message='Invalid Request',
|
||||||
details="Unknown action: {0}".format(action)), status=400)
|
details="Unknown action: {0}".format(action)), status=400)
|
||||||
|
|
||||||
self._check_listener_exists(listener_id)
|
self._check_lb_exists(lb_id)
|
||||||
|
|
||||||
# Since this script should be created at LB create time
|
# Since this script should be created at LB create time
|
||||||
# we can check for this path to see if VRRP is enabled
|
# we can check for this path to see if VRRP is enabled
|
||||||
# on this amphora and not write the file if VRRP is not in use
|
# on this amphora and not write the file if VRRP is not in use
|
||||||
if os.path.exists(util.keepalived_check_script_path()):
|
if os.path.exists(util.keepalived_check_script_path()):
|
||||||
self.vrrp_check_script_update(listener_id, action)
|
self.vrrp_check_script_update(lb_id, action)
|
||||||
|
|
||||||
# HAProxy does not start the process when given a reload
|
# HAProxy does not start the process when given a reload
|
||||||
# so start it if haproxy is not already running
|
# so start it if haproxy is not already running
|
||||||
if action == consts.AMP_ACTION_RELOAD:
|
if action == consts.AMP_ACTION_RELOAD:
|
||||||
if consts.OFFLINE == self._check_haproxy_status(listener_id):
|
if consts.OFFLINE == self._check_haproxy_status(lb_id):
|
||||||
action = consts.AMP_ACTION_START
|
action = consts.AMP_ACTION_START
|
||||||
|
|
||||||
cmd = ("/usr/sbin/service haproxy-{listener_id} {action}".format(
|
cmd = ("/usr/sbin/service haproxy-{lb_id} {action}".format(
|
||||||
listener_id=listener_id, action=action))
|
lb_id=lb_id, action=action))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
if b'Job is already running' not in e.output:
|
if b'Job is already running' not in e.output:
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Failed to %(action)s haproxy-%(list)s service: %(err)s "
|
"Failed to %(action)s haproxy-%(lb_id)s service: %(err)s "
|
||||||
"%(out)s", {'action': action, 'list': listener_id,
|
"%(out)s", {'action': action, 'lb_id': lb_id,
|
||||||
'err': e, 'out': e.output})
|
'err': e, 'out': e.output})
|
||||||
return webob.Response(json=dict(
|
return webob.Response(json=dict(
|
||||||
message="Error {0}ing haproxy".format(action),
|
message="Error {0}ing haproxy".format(action),
|
||||||
|
@ -271,40 +266,40 @@ class Listener(object):
|
||||||
consts.AMP_ACTION_RELOAD]:
|
consts.AMP_ACTION_RELOAD]:
|
||||||
return webob.Response(json=dict(
|
return webob.Response(json=dict(
|
||||||
message='OK',
|
message='OK',
|
||||||
details='Listener {listener_id} {action}ed'.format(
|
details='Listener {lb_id} {action}ed'.format(
|
||||||
listener_id=listener_id, action=action)), status=202)
|
lb_id=lb_id, action=action)), status=202)
|
||||||
|
|
||||||
details = (
|
details = (
|
||||||
'Configuration file is valid\n'
|
'Configuration file is valid\n'
|
||||||
'haproxy daemon for {0} started'.format(listener_id)
|
'haproxy daemon for {0} started'.format(lb_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
return webob.Response(json=dict(message='OK', details=details),
|
return webob.Response(json=dict(message='OK', details=details),
|
||||||
status=202)
|
status=202)
|
||||||
|
|
||||||
def delete_listener(self, listener_id):
|
def delete_lb(self, lb_id):
|
||||||
try:
|
try:
|
||||||
self._check_listener_exists(listener_id)
|
self._check_lb_exists(lb_id)
|
||||||
except exceptions.HTTPException:
|
except exceptions.HTTPException:
|
||||||
return webob.Response(json={'message': 'OK'})
|
return webob.Response(json={'message': 'OK'})
|
||||||
|
|
||||||
# check if that haproxy is still running and if stop it
|
# check if that haproxy is still running and if stop it
|
||||||
if os.path.exists(util.pid_path(listener_id)) and os.path.exists(
|
if os.path.exists(util.pid_path(lb_id)) and os.path.exists(
|
||||||
os.path.join('/proc', util.get_haproxy_pid(listener_id))):
|
os.path.join('/proc', util.get_haproxy_pid(lb_id))):
|
||||||
cmd = "/usr/sbin/service haproxy-{0} stop".format(listener_id)
|
cmd = "/usr/sbin/service haproxy-{0} stop".format(lb_id)
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
LOG.error("Failed to stop haproxy-%s service: %s %s",
|
LOG.error("Failed to stop haproxy-%s service: %s %s",
|
||||||
listener_id, e, e.output)
|
lb_id, e, e.output)
|
||||||
return webob.Response(json=dict(
|
return webob.Response(json=dict(
|
||||||
message="Error stopping haproxy",
|
message="Error stopping haproxy",
|
||||||
details=e.output), status=500)
|
details=e.output), status=500)
|
||||||
|
|
||||||
# parse config and delete stats socket
|
# parse config and delete stats socket
|
||||||
try:
|
try:
|
||||||
cfg = self._parse_haproxy_file(listener_id)
|
stats_socket = util.parse_haproxy_file(lb_id)[0]
|
||||||
os.remove(cfg['stats_socket'])
|
os.remove(stats_socket)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -313,22 +308,22 @@ class Listener(object):
|
||||||
# on this amphora and not write the file if VRRP is not in use
|
# on this amphora and not write the file if VRRP is not in use
|
||||||
if os.path.exists(util.keepalived_check_script_path()):
|
if os.path.exists(util.keepalived_check_script_path()):
|
||||||
self.vrrp_check_script_update(
|
self.vrrp_check_script_update(
|
||||||
listener_id, action=consts.AMP_ACTION_STOP)
|
lb_id, action=consts.AMP_ACTION_STOP)
|
||||||
|
|
||||||
# delete the ssl files
|
# delete the ssl files
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(self._cert_dir(listener_id))
|
shutil.rmtree(self._cert_dir(lb_id))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# disable the service
|
# disable the service
|
||||||
init_system = util.get_os_init_system()
|
init_system = util.get_os_init_system()
|
||||||
init_path = util.init_path(listener_id, init_system)
|
init_path = util.init_path(lb_id, init_system)
|
||||||
|
|
||||||
if init_system == consts.INIT_SYSTEMD:
|
if init_system == consts.INIT_SYSTEMD:
|
||||||
util.run_systemctl_command(
|
util.run_systemctl_command(
|
||||||
consts.DISABLE, "haproxy-{list}".format(
|
consts.DISABLE, "haproxy-{lb_id}".format(
|
||||||
list=listener_id))
|
lb_id=lb_id))
|
||||||
elif init_system == consts.INIT_SYSVINIT:
|
elif init_system == consts.INIT_SYSVINIT:
|
||||||
init_disable_cmd = "insserv -r {file}".format(file=init_path)
|
init_disable_cmd = "insserv -r {file}".format(file=init_path)
|
||||||
elif init_system != consts.INIT_UPSTART:
|
elif init_system != consts.INIT_UPSTART:
|
||||||
|
@ -339,15 +334,15 @@ class Listener(object):
|
||||||
subprocess.check_output(init_disable_cmd.split(),
|
subprocess.check_output(init_disable_cmd.split(),
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
LOG.error("Failed to disable haproxy-%(list)s service: "
|
LOG.error("Failed to disable haproxy-%(lb_id)s service: "
|
||||||
"%(err)s %(out)s", {'list': listener_id, 'err': e,
|
"%(err)s %(out)s", {'lb_id': lb_id, 'err': e,
|
||||||
'out': e.output})
|
'out': e.output})
|
||||||
return webob.Response(json=dict(
|
return webob.Response(json=dict(
|
||||||
message="Error disabling haproxy-{0} service".format(
|
message="Error disabling haproxy-{0} service".format(
|
||||||
listener_id), details=e.output), status=500)
|
lb_id), details=e.output), status=500)
|
||||||
|
|
||||||
# delete the directory + init script for that listener
|
# delete the directory + init script for that listener
|
||||||
shutil.rmtree(util.haproxy_dir(listener_id))
|
shutil.rmtree(util.haproxy_dir(lb_id))
|
||||||
if os.path.exists(init_path):
|
if os.path.exists(init_path):
|
||||||
os.remove(init_path)
|
os.remove(init_path)
|
||||||
|
|
||||||
|
@ -364,68 +359,29 @@ class Listener(object):
|
||||||
"""
|
"""
|
||||||
listeners = list()
|
listeners = list()
|
||||||
|
|
||||||
for listener in util.get_listeners():
|
for lb in util.get_loadbalancers():
|
||||||
status = self._check_listener_status(listener)
|
stats_socket, listeners_on_lb = util.parse_haproxy_file(lb)
|
||||||
listener_type = ''
|
|
||||||
|
|
||||||
if status == consts.ACTIVE:
|
for listener_id, listener in listeners_on_lb.items():
|
||||||
listener_type = self._parse_haproxy_file(listener)['mode']
|
listeners.append({
|
||||||
|
'status': consts.ACTIVE,
|
||||||
listeners.append({
|
'uuid': listener_id,
|
||||||
'status': status,
|
'type': listener['mode'],
|
||||||
'uuid': listener,
|
})
|
||||||
'type': listener_type,
|
|
||||||
})
|
|
||||||
|
|
||||||
if other_listeners:
|
if other_listeners:
|
||||||
listeners = listeners + other_listeners
|
listeners = listeners + other_listeners
|
||||||
return webob.Response(json=listeners, content_type='application/json')
|
return webob.Response(json=listeners, content_type='application/json')
|
||||||
|
|
||||||
def get_listener_status(self, listener_id):
|
def upload_certificate(self, lb_id, filename):
|
||||||
"""Gets the status of a listener
|
|
||||||
|
|
||||||
This method will consult the stats socket
|
|
||||||
so calling this method will interfere with
|
|
||||||
the health daemon with the risk of the amphora
|
|
||||||
shut down
|
|
||||||
|
|
||||||
Currently type==SSL is not detected
|
|
||||||
:param listener_id: The id of the listener
|
|
||||||
"""
|
|
||||||
self._check_listener_exists(listener_id)
|
|
||||||
|
|
||||||
status = self._check_listener_status(listener_id)
|
|
||||||
|
|
||||||
if status != consts.ACTIVE:
|
|
||||||
stats = dict(
|
|
||||||
status=status,
|
|
||||||
uuid=listener_id,
|
|
||||||
type=''
|
|
||||||
)
|
|
||||||
return webob.Response(json=stats)
|
|
||||||
|
|
||||||
cfg = self._parse_haproxy_file(listener_id)
|
|
||||||
stats = dict(
|
|
||||||
status=status,
|
|
||||||
uuid=listener_id,
|
|
||||||
type=cfg['mode']
|
|
||||||
)
|
|
||||||
|
|
||||||
# read stats socket
|
|
||||||
q = query.HAProxyQuery(cfg['stats_socket'])
|
|
||||||
servers = q.get_pool_status()
|
|
||||||
stats['pools'] = list(servers.values())
|
|
||||||
return webob.Response(json=stats)
|
|
||||||
|
|
||||||
def upload_certificate(self, listener_id, filename):
|
|
||||||
self._check_ssl_filename_format(filename)
|
self._check_ssl_filename_format(filename)
|
||||||
|
|
||||||
# create directory if not already there
|
# create directory if not already there
|
||||||
if not os.path.exists(self._cert_dir(listener_id)):
|
if not os.path.exists(self._cert_dir(lb_id)):
|
||||||
os.makedirs(self._cert_dir(listener_id))
|
os.makedirs(self._cert_dir(lb_id))
|
||||||
|
|
||||||
stream = Wrapped(flask.request.stream)
|
stream = Wrapped(flask.request.stream)
|
||||||
file = self._cert_file_path(listener_id, filename)
|
file = self._cert_file_path(lb_id, filename)
|
||||||
flags = os.O_WRONLY | os.O_CREAT
|
flags = os.O_WRONLY | os.O_CREAT
|
||||||
# mode 00600
|
# mode 00600
|
||||||
mode = stat.S_IRUSR | stat.S_IWUSR
|
mode = stat.S_IRUSR | stat.S_IWUSR
|
||||||
|
@ -439,10 +395,10 @@ class Listener(object):
|
||||||
resp.headers['ETag'] = stream.get_md5()
|
resp.headers['ETag'] = stream.get_md5()
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def get_certificate_md5(self, listener_id, filename):
|
def get_certificate_md5(self, lb_id, filename):
|
||||||
self._check_ssl_filename_format(filename)
|
self._check_ssl_filename_format(filename)
|
||||||
|
|
||||||
cert_path = self._cert_file_path(listener_id, filename)
|
cert_path = self._cert_file_path(lb_id, filename)
|
||||||
path_exists = os.path.exists(cert_path)
|
path_exists = os.path.exists(cert_path)
|
||||||
if not path_exists:
|
if not path_exists:
|
||||||
return webob.Response(json=dict(
|
return webob.Response(json=dict(
|
||||||
|
@ -457,60 +413,34 @@ class Listener(object):
|
||||||
resp.headers['ETag'] = md5
|
resp.headers['ETag'] = md5
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def delete_certificate(self, listener_id, filename):
|
def delete_certificate(self, lb_id, filename):
|
||||||
self._check_ssl_filename_format(filename)
|
self._check_ssl_filename_format(filename)
|
||||||
if os.path.exists(self._cert_file_path(listener_id, filename)):
|
if os.path.exists(self._cert_file_path(lb_id, filename)):
|
||||||
os.remove(self._cert_file_path(listener_id, filename))
|
os.remove(self._cert_file_path(lb_id, filename))
|
||||||
return webob.Response(json=dict(message='OK'))
|
return webob.Response(json=dict(message='OK'))
|
||||||
|
|
||||||
def _check_listener_status(self, listener_id):
|
def _get_listeners_on_lb(self, lb_id):
|
||||||
if os.path.exists(util.pid_path(listener_id)):
|
if os.path.exists(util.pid_path(lb_id)):
|
||||||
if os.path.exists(
|
if os.path.exists(
|
||||||
os.path.join('/proc', util.get_haproxy_pid(listener_id))):
|
os.path.join('/proc', util.get_haproxy_pid(lb_id))):
|
||||||
# Check if the listener is disabled
|
# Check if the listener is disabled
|
||||||
with open(util.config_path(listener_id), 'r') as file:
|
with open(util.config_path(lb_id), 'r') as file:
|
||||||
cfg = file.read()
|
cfg = file.read()
|
||||||
m = re.search('frontend {}'.format(listener_id), cfg)
|
m = re.findall('^frontend (.*)$', cfg, re.MULTILINE)
|
||||||
if m:
|
return m or []
|
||||||
return consts.ACTIVE
|
|
||||||
return consts.OFFLINE
|
|
||||||
else: # pid file but no process...
|
else: # pid file but no process...
|
||||||
return consts.ERROR
|
return []
|
||||||
else:
|
else:
|
||||||
return consts.OFFLINE
|
return []
|
||||||
|
|
||||||
def _parse_haproxy_file(self, listener_id):
|
def _check_lb_exists(self, lb_id):
|
||||||
with open(util.config_path(listener_id), 'r') as file:
|
# check if we know about that lb
|
||||||
cfg = file.read()
|
if lb_id not in util.get_loadbalancers():
|
||||||
|
|
||||||
m = re.search(r'mode\s+(http|tcp)', cfg)
|
|
||||||
if not m:
|
|
||||||
raise ParsingError()
|
|
||||||
mode = m.group(1).upper()
|
|
||||||
|
|
||||||
m = re.search(r'stats socket\s+(\S+)', cfg)
|
|
||||||
if not m:
|
|
||||||
raise ParsingError()
|
|
||||||
stats_socket = m.group(1)
|
|
||||||
|
|
||||||
m = re.search(r'ssl crt\s+(\S+)', cfg)
|
|
||||||
ssl_crt = None
|
|
||||||
if m:
|
|
||||||
ssl_crt = m.group(1)
|
|
||||||
mode = 'TERMINATED_HTTPS'
|
|
||||||
|
|
||||||
return dict(mode=mode,
|
|
||||||
stats_socket=stats_socket,
|
|
||||||
ssl_crt=ssl_crt)
|
|
||||||
|
|
||||||
def _check_listener_exists(self, listener_id):
|
|
||||||
# check if we know about that listener
|
|
||||||
if not os.path.exists(util.config_path(listener_id)):
|
|
||||||
raise exceptions.HTTPException(
|
raise exceptions.HTTPException(
|
||||||
response=webob.Response(json=dict(
|
response=webob.Response(json=dict(
|
||||||
message='Listener Not Found',
|
message='Loadbalancer Not Found',
|
||||||
details="No listener with UUID: {0}".format(
|
details="No loadbalancer with UUID: {0}".format(
|
||||||
listener_id)), status=404))
|
lb_id)), status=404))
|
||||||
|
|
||||||
def _check_ssl_filename_format(self, filename):
|
def _check_ssl_filename_format(self, filename):
|
||||||
# check if the format is (xxx.)*xxx.pem
|
# check if the format is (xxx.)*xxx.pem
|
||||||
|
@ -519,20 +449,19 @@ class Listener(object):
|
||||||
response=webob.Response(json=dict(
|
response=webob.Response(json=dict(
|
||||||
message='Filename has wrong format'), status=400))
|
message='Filename has wrong format'), status=400))
|
||||||
|
|
||||||
def _cert_dir(self, listener_id):
|
def _cert_dir(self, lb_id):
|
||||||
return os.path.join(util.CONF.haproxy_amphora.base_cert_dir,
|
return os.path.join(util.CONF.haproxy_amphora.base_cert_dir, lb_id)
|
||||||
listener_id)
|
|
||||||
|
|
||||||
def _cert_file_path(self, listener_id, filename):
|
def _cert_file_path(self, lb_id, filename):
|
||||||
return os.path.join(self._cert_dir(listener_id), filename)
|
return os.path.join(self._cert_dir(lb_id), filename)
|
||||||
|
|
||||||
def vrrp_check_script_update(self, listener_id, action):
|
def vrrp_check_script_update(self, lb_id, action):
|
||||||
listener_ids = util.get_listeners()
|
lb_ids = util.get_loadbalancers()
|
||||||
if action == consts.AMP_ACTION_STOP:
|
if action == consts.AMP_ACTION_STOP:
|
||||||
listener_ids.remove(listener_id)
|
lb_ids.remove(lb_id)
|
||||||
args = []
|
args = []
|
||||||
for lid in listener_ids:
|
for lbid in lb_ids:
|
||||||
args.append(util.haproxy_sock_path(lid))
|
args.append(util.haproxy_sock_path(lbid))
|
||||||
|
|
||||||
if not os.path.exists(util.keepalived_dir()):
|
if not os.path.exists(util.keepalived_dir()):
|
||||||
os.makedirs(util.keepalived_dir())
|
os.makedirs(util.keepalived_dir())
|
||||||
|
@ -542,9 +471,9 @@ class Listener(object):
|
||||||
with open(util.haproxy_check_script_path(), 'w') as text_file:
|
with open(util.haproxy_check_script_path(), 'w') as text_file:
|
||||||
text_file.write(cmd)
|
text_file.write(cmd)
|
||||||
|
|
||||||
def _check_haproxy_status(self, listener_id):
|
def _check_haproxy_status(self, lb_id):
|
||||||
if os.path.exists(util.pid_path(listener_id)):
|
if os.path.exists(util.pid_path(lb_id)):
|
||||||
if os.path.exists(
|
if os.path.exists(
|
||||||
os.path.join('/proc', util.get_haproxy_pid(listener_id))):
|
os.path.join('/proc', util.get_haproxy_pid(lb_id))):
|
||||||
return consts.ACTIVE
|
return consts.ACTIVE
|
||||||
return consts.OFFLINE
|
return consts.OFFLINE
|
|
@ -26,7 +26,7 @@ from octavia.amphorae.backends.agent import api_server
|
||||||
from octavia.amphorae.backends.agent.api_server import amphora_info
|
from octavia.amphorae.backends.agent.api_server import amphora_info
|
||||||
from octavia.amphorae.backends.agent.api_server import certificate_update
|
from octavia.amphorae.backends.agent.api_server import certificate_update
|
||||||
from octavia.amphorae.backends.agent.api_server import keepalived
|
from octavia.amphorae.backends.agent.api_server import keepalived
|
||||||
from octavia.amphorae.backends.agent.api_server import listener
|
from octavia.amphorae.backends.agent.api_server import loadbalancer
|
||||||
from octavia.amphorae.backends.agent.api_server import osutils
|
from octavia.amphorae.backends.agent.api_server import osutils
|
||||||
from octavia.amphorae.backends.agent.api_server import plug
|
from octavia.amphorae.backends.agent.api_server import plug
|
||||||
from octavia.amphorae.backends.agent.api_server import udp_listener_base
|
from octavia.amphorae.backends.agent.api_server import udp_listener_base
|
||||||
|
@ -56,7 +56,7 @@ class Server(object):
|
||||||
self.app = flask.Flask(__name__)
|
self.app = flask.Flask(__name__)
|
||||||
self._osutils = osutils.BaseOS.get_os_util()
|
self._osutils = osutils.BaseOS.get_os_util()
|
||||||
self._keepalived = keepalived.Keepalived()
|
self._keepalived = keepalived.Keepalived()
|
||||||
self._listener = listener.Listener()
|
self._loadbalancer = loadbalancer.Loadbalancer()
|
||||||
self._udp_listener = (udp_listener_base.UdpListenerApiServerBase.
|
self._udp_listener = (udp_listener_base.UdpListenerApiServerBase.
|
||||||
get_server_driver())
|
get_server_driver())
|
||||||
self._plug = plug.Plug(self._osutils)
|
self._plug = plug.Plug(self._osutils)
|
||||||
|
@ -64,8 +64,10 @@ class Server(object):
|
||||||
|
|
||||||
register_app_error_handler(self.app)
|
register_app_error_handler(self.app)
|
||||||
|
|
||||||
|
self.app.add_url_rule(rule='/', view_func=self.version_discovery,
|
||||||
|
methods=['GET'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX +
|
self.app.add_url_rule(rule=PATH_PREFIX +
|
||||||
'/listeners/<amphora_id>/<listener_id>/haproxy',
|
'/loadbalancer/<amphora_id>/<lb_id>/haproxy',
|
||||||
view_func=self.upload_haproxy_config,
|
view_func=self.upload_haproxy_config,
|
||||||
methods=['PUT'])
|
methods=['PUT'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX +
|
self.app.add_url_rule(rule=PATH_PREFIX +
|
||||||
|
@ -74,7 +76,7 @@ class Server(object):
|
||||||
view_func=self.upload_udp_listener_config,
|
view_func=self.upload_udp_listener_config,
|
||||||
methods=['PUT'])
|
methods=['PUT'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX +
|
self.app.add_url_rule(rule=PATH_PREFIX +
|
||||||
'/listeners/<listener_id>/haproxy',
|
'/loadbalancer/<lb_id>/haproxy',
|
||||||
view_func=self.get_haproxy_config,
|
view_func=self.get_haproxy_config,
|
||||||
methods=['GET'])
|
methods=['GET'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX +
|
self.app.add_url_rule(rule=PATH_PREFIX +
|
||||||
|
@ -82,11 +84,11 @@ class Server(object):
|
||||||
view_func=self.get_udp_listener_config,
|
view_func=self.get_udp_listener_config,
|
||||||
methods=['GET'])
|
methods=['GET'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX +
|
self.app.add_url_rule(rule=PATH_PREFIX +
|
||||||
'/listeners/<listener_id>/<action>',
|
'/loadbalancer/<object_id>/<action>',
|
||||||
view_func=self.start_stop_listener,
|
view_func=self.start_stop_lb_object,
|
||||||
methods=['PUT'])
|
methods=['PUT'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners/<listener_id>',
|
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners/<object_id>',
|
||||||
view_func=self.delete_listener,
|
view_func=self.delete_lb_object,
|
||||||
methods=['DELETE'])
|
methods=['DELETE'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX + '/config',
|
self.app.add_url_rule(rule=PATH_PREFIX + '/config',
|
||||||
view_func=self.upload_config,
|
view_func=self.upload_config,
|
||||||
|
@ -100,18 +102,15 @@ class Server(object):
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners',
|
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners',
|
||||||
view_func=self.get_all_listeners_status,
|
view_func=self.get_all_listeners_status,
|
||||||
methods=['GET'])
|
methods=['GET'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners/<listener_id>',
|
self.app.add_url_rule(rule=PATH_PREFIX + '/loadbalancer/<lb_id>'
|
||||||
view_func=self.get_listener_status,
|
|
||||||
methods=['GET'])
|
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners/<listener_id>'
|
|
||||||
'/certificates/<filename>',
|
'/certificates/<filename>',
|
||||||
view_func=self.upload_certificate,
|
view_func=self.upload_certificate,
|
||||||
methods=['PUT'])
|
methods=['PUT'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners/<listener_id>'
|
self.app.add_url_rule(rule=PATH_PREFIX + '/loadbalancer/<lb_id>'
|
||||||
'/certificates/<filename>',
|
'/certificates/<filename>',
|
||||||
view_func=self.get_certificate_md5,
|
view_func=self.get_certificate_md5,
|
||||||
methods=['GET'])
|
methods=['GET'])
|
||||||
self.app.add_url_rule(rule=PATH_PREFIX + '/listeners/<listener_id>'
|
self.app.add_url_rule(rule=PATH_PREFIX + '/loadbalancer/<lb_id>'
|
||||||
'/certificates/<filename>',
|
'/certificates/<filename>',
|
||||||
view_func=self.delete_certificate,
|
view_func=self.delete_certificate,
|
||||||
methods=['DELETE'])
|
methods=['DELETE'])
|
||||||
|
@ -133,30 +132,30 @@ class Server(object):
|
||||||
view_func=self.get_interface,
|
view_func=self.get_interface,
|
||||||
methods=['GET'])
|
methods=['GET'])
|
||||||
|
|
||||||
def upload_haproxy_config(self, amphora_id, listener_id):
|
def upload_haproxy_config(self, amphora_id, lb_id):
|
||||||
return self._listener.upload_haproxy_config(amphora_id, listener_id)
|
return self._loadbalancer.upload_haproxy_config(amphora_id, lb_id)
|
||||||
|
|
||||||
def upload_udp_listener_config(self, amphora_id, listener_id):
|
def upload_udp_listener_config(self, amphora_id, listener_id):
|
||||||
return self._udp_listener.upload_udp_listener_config(listener_id)
|
return self._udp_listener.upload_udp_listener_config(listener_id)
|
||||||
|
|
||||||
def get_haproxy_config(self, listener_id):
|
def get_haproxy_config(self, lb_id):
|
||||||
return self._listener.get_haproxy_config(listener_id)
|
return self._loadbalancer.get_haproxy_config(lb_id)
|
||||||
|
|
||||||
def get_udp_listener_config(self, listener_id):
|
def get_udp_listener_config(self, listener_id):
|
||||||
return self._udp_listener.get_udp_listener_config(listener_id)
|
return self._udp_listener.get_udp_listener_config(listener_id)
|
||||||
|
|
||||||
def start_stop_listener(self, listener_id, action):
|
def start_stop_lb_object(self, object_id, action):
|
||||||
protocol = util.get_listener_protocol(listener_id)
|
protocol = util.get_protocol_for_lb_object(object_id)
|
||||||
if protocol == 'UDP':
|
if protocol == 'UDP':
|
||||||
return self._udp_listener.manage_udp_listener(
|
return self._udp_listener.manage_udp_listener(
|
||||||
listener_id, action)
|
listener_id=object_id, action=action)
|
||||||
return self._listener.start_stop_listener(listener_id, action)
|
return self._loadbalancer.start_stop_lb(lb_id=object_id, action=action)
|
||||||
|
|
||||||
def delete_listener(self, listener_id):
|
def delete_lb_object(self, object_id):
|
||||||
protocol = util.get_listener_protocol(listener_id)
|
protocol = util.get_protocol_for_lb_object(object_id)
|
||||||
if protocol == 'UDP':
|
if protocol == 'UDP':
|
||||||
return self._udp_listener.delete_udp_listener(listener_id)
|
return self._udp_listener.delete_udp_listener(object_id)
|
||||||
return self._listener.delete_listener(listener_id)
|
return self._loadbalancer.delete_lb(object_id)
|
||||||
|
|
||||||
def get_details(self):
|
def get_details(self):
|
||||||
return self._amphora_info.compile_amphora_details(
|
return self._amphora_info.compile_amphora_details(
|
||||||
|
@ -168,23 +167,17 @@ class Server(object):
|
||||||
|
|
||||||
def get_all_listeners_status(self):
|
def get_all_listeners_status(self):
|
||||||
udp_listeners = self._udp_listener.get_all_udp_listeners_status()
|
udp_listeners = self._udp_listener.get_all_udp_listeners_status()
|
||||||
return self._listener.get_all_listeners_status(
|
return self._loadbalancer.get_all_listeners_status(
|
||||||
other_listeners=udp_listeners)
|
other_listeners=udp_listeners)
|
||||||
|
|
||||||
def get_listener_status(self, listener_id):
|
def upload_certificate(self, lb_id, filename):
|
||||||
protocol = util.get_listener_protocol(listener_id)
|
return self._loadbalancer.upload_certificate(lb_id, filename)
|
||||||
if protocol == 'UDP':
|
|
||||||
return self._udp_listener.get_udp_listener_status(listener_id)
|
|
||||||
return self._listener.get_listener_status(listener_id)
|
|
||||||
|
|
||||||
def upload_certificate(self, listener_id, filename):
|
def get_certificate_md5(self, lb_id, filename):
|
||||||
return self._listener.upload_certificate(listener_id, filename)
|
return self._loadbalancer.get_certificate_md5(lb_id, filename)
|
||||||
|
|
||||||
def get_certificate_md5(self, listener_id, filename):
|
def delete_certificate(self, lb_id, filename):
|
||||||
return self._listener.get_certificate_md5(listener_id, filename)
|
return self._loadbalancer.delete_certificate(lb_id, filename)
|
||||||
|
|
||||||
def delete_certificate(self, listener_id, filename):
|
|
||||||
return self._listener.delete_certificate(listener_id, filename)
|
|
||||||
|
|
||||||
def plug_vip(self, vip):
|
def plug_vip(self, vip):
|
||||||
# Catch any issues with the subnet info json
|
# Catch any issues with the subnet info json
|
||||||
|
@ -251,3 +244,6 @@ class Server(object):
|
||||||
details=str(e)), status=500)
|
details=str(e)), status=500)
|
||||||
|
|
||||||
return webob.Response(json={'message': 'OK'}, status=202)
|
return webob.Response(json={'message': 'OK'}, status=202)
|
||||||
|
|
||||||
|
def version_discovery(self):
|
||||||
|
return webob.Response(json={'api_version': api_server.VERSION})
|
||||||
|
|
|
@ -94,17 +94,6 @@ class UdpListenerApiServerBase(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_udp_listener_status(self, listener_id):
|
|
||||||
"""Gets the status of a UDP listener
|
|
||||||
|
|
||||||
:param listener_id: The id of the listener
|
|
||||||
|
|
||||||
:returns: HTTP response with status code.
|
|
||||||
:raises Exception: If the listener is failed to find.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def delete_udp_listener(self, listener_id):
|
def delete_udp_listener(self, listener_id):
|
||||||
"""Delete a UDP Listener from a amphora
|
"""Delete a UDP Listener from a amphora
|
||||||
|
|
|
@ -28,21 +28,31 @@ from octavia.common import constants as consts
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
FRONTEND_BACKEND_PATTERN = re.compile(r'\n(frontend|backend)\s+(\S+)\n')
|
||||||
|
LISTENER_MODE_PATTERN = re.compile(r'^\s+mode\s+(.*)$', re.MULTILINE)
|
||||||
|
TLS_CERT_PATTERN = re.compile(r'^\s+bind\s+\S+\s+ssl crt\s+(.*)$',
|
||||||
|
re.MULTILINE)
|
||||||
|
STATS_SOCKET_PATTERN = re.compile(r'stats socket\s+(\S+)')
|
||||||
|
|
||||||
|
|
||||||
|
class ParsingError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UnknownInitError(Exception):
|
class UnknownInitError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def init_path(listener_id, init_system):
|
def init_path(lb_id, init_system):
|
||||||
if init_system == consts.INIT_SYSTEMD:
|
if init_system == consts.INIT_SYSTEMD:
|
||||||
return os.path.join(consts.SYSTEMD_DIR,
|
return os.path.join(consts.SYSTEMD_DIR,
|
||||||
'haproxy-{0}.service'.format(listener_id))
|
'haproxy-{0}.service'.format(lb_id))
|
||||||
if init_system == consts.INIT_UPSTART:
|
if init_system == consts.INIT_UPSTART:
|
||||||
return os.path.join(consts.UPSTART_DIR,
|
return os.path.join(consts.UPSTART_DIR,
|
||||||
'haproxy-{0}.conf'.format(listener_id))
|
'haproxy-{0}.conf'.format(lb_id))
|
||||||
if init_system == consts.INIT_SYSVINIT:
|
if init_system == consts.INIT_SYSVINIT:
|
||||||
return os.path.join(consts.SYSVINIT_DIR,
|
return os.path.join(consts.SYSVINIT_DIR,
|
||||||
'haproxy-{0}'.format(listener_id))
|
'haproxy-{0}'.format(lb_id))
|
||||||
raise UnknownInitError()
|
raise UnknownInitError()
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,20 +101,20 @@ def keepalived_lvs_cfg_path(listener_id):
|
||||||
str(listener_id))
|
str(listener_id))
|
||||||
|
|
||||||
|
|
||||||
def haproxy_dir(listener_id):
|
def haproxy_dir(lb_id):
|
||||||
return os.path.join(CONF.haproxy_amphora.base_path, listener_id)
|
return os.path.join(CONF.haproxy_amphora.base_path, lb_id)
|
||||||
|
|
||||||
|
|
||||||
def pid_path(listener_id):
|
def pid_path(lb_id):
|
||||||
return os.path.join(haproxy_dir(listener_id), listener_id + '.pid')
|
return os.path.join(haproxy_dir(lb_id), lb_id + '.pid')
|
||||||
|
|
||||||
|
|
||||||
def config_path(listener_id):
|
def config_path(lb_id):
|
||||||
return os.path.join(haproxy_dir(listener_id), 'haproxy.cfg')
|
return os.path.join(haproxy_dir(lb_id), 'haproxy.cfg')
|
||||||
|
|
||||||
|
|
||||||
def get_haproxy_pid(listener_id):
|
def get_haproxy_pid(lb_id):
|
||||||
with open(pid_path(listener_id), 'r') as f:
|
with open(pid_path(lb_id), 'r') as f:
|
||||||
return f.readline().rstrip()
|
return f.readline().rstrip()
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,8 +124,8 @@ def get_keepalivedlvs_pid(listener_id):
|
||||||
return f.readline().rstrip()
|
return f.readline().rstrip()
|
||||||
|
|
||||||
|
|
||||||
def haproxy_sock_path(listener_id):
|
def haproxy_sock_path(lb_id):
|
||||||
return os.path.join(CONF.haproxy_amphora.base_path, listener_id + '.sock')
|
return os.path.join(CONF.haproxy_amphora.base_path, lb_id + '.sock')
|
||||||
|
|
||||||
|
|
||||||
def haproxy_check_script_path():
|
def haproxy_check_script_path():
|
||||||
|
@ -168,16 +178,28 @@ def get_listeners():
|
||||||
:returns: An array with the ids of all listeners, e.g. ['123', '456', ...]
|
:returns: An array with the ids of all listeners, e.g. ['123', '456', ...]
|
||||||
or [] if no listeners exist
|
or [] if no listeners exist
|
||||||
"""
|
"""
|
||||||
|
listeners = []
|
||||||
|
for lb_id in get_loadbalancers():
|
||||||
|
listeners_on_lb = parse_haproxy_file(lb_id)[1]
|
||||||
|
listeners.extend(list(listeners_on_lb.keys()))
|
||||||
|
return listeners
|
||||||
|
|
||||||
|
|
||||||
|
def get_loadbalancers():
|
||||||
|
"""Get Load balancers
|
||||||
|
|
||||||
|
:returns: An array with the ids of all load balancers,
|
||||||
|
e.g. ['123', '456', ...] or [] if no loadbalancers exist
|
||||||
|
"""
|
||||||
if os.path.exists(CONF.haproxy_amphora.base_path):
|
if os.path.exists(CONF.haproxy_amphora.base_path):
|
||||||
return [f for f in os.listdir(CONF.haproxy_amphora.base_path)
|
return [f for f in os.listdir(CONF.haproxy_amphora.base_path)
|
||||||
if os.path.exists(config_path(f))]
|
if os.path.exists(config_path(f))]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def is_listener_running(listener_id):
|
def is_lb_running(lb_id):
|
||||||
return os.path.exists(pid_path(listener_id)) and os.path.exists(
|
return os.path.exists(pid_path(lb_id)) and os.path.exists(
|
||||||
os.path.join('/proc', get_haproxy_pid(listener_id)))
|
os.path.join('/proc', get_haproxy_pid(lb_id)))
|
||||||
|
|
||||||
|
|
||||||
def get_udp_listeners():
|
def get_udp_listeners():
|
||||||
|
@ -251,7 +273,7 @@ def run_systemctl_command(command, service):
|
||||||
'err': e, 'out': e.output})
|
'err': e, 'out': e.output})
|
||||||
|
|
||||||
|
|
||||||
def get_listener_protocol(listener_id):
|
def get_protocol_for_lb_object(object_id):
|
||||||
"""Returns the L4 protocol for a listener.
|
"""Returns the L4 protocol for a listener.
|
||||||
|
|
||||||
If the listener is a TCP based listener (haproxy) return TCP.
|
If the listener is a TCP based listener (haproxy) return TCP.
|
||||||
|
@ -261,8 +283,52 @@ def get_listener_protocol(listener_id):
|
||||||
:param listener_id: The ID of the listener to identify.
|
:param listener_id: The ID of the listener to identify.
|
||||||
:returns: TCP, UDP, or None
|
:returns: TCP, UDP, or None
|
||||||
"""
|
"""
|
||||||
if os.path.exists(config_path(listener_id)):
|
if os.path.exists(config_path(object_id)):
|
||||||
return consts.PROTOCOL_TCP
|
return consts.PROTOCOL_TCP
|
||||||
if os.path.exists(keepalived_lvs_cfg_path(listener_id)):
|
if os.path.exists(keepalived_lvs_cfg_path(object_id)):
|
||||||
return consts.PROTOCOL_UDP
|
return consts.PROTOCOL_UDP
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_haproxy_file(lb_id):
|
||||||
|
with open(config_path(lb_id), 'r') as file:
|
||||||
|
cfg = file.read()
|
||||||
|
|
||||||
|
listeners = {}
|
||||||
|
|
||||||
|
m = FRONTEND_BACKEND_PATTERN.split(cfg)
|
||||||
|
last_token = None
|
||||||
|
last_id = None
|
||||||
|
for section in m:
|
||||||
|
if last_token is None:
|
||||||
|
# We aren't in a section yet, see if this line starts one
|
||||||
|
if section == 'frontend':
|
||||||
|
last_token = section
|
||||||
|
elif last_token == 'frontend':
|
||||||
|
# We're in a frontend section, save the id for later
|
||||||
|
last_token = last_token + "_id"
|
||||||
|
last_id = section
|
||||||
|
elif last_token == 'frontend_id':
|
||||||
|
# We're in a frontend section and already have the id
|
||||||
|
# Look for the mode
|
||||||
|
mode_matcher = LISTENER_MODE_PATTERN.search(section)
|
||||||
|
if not mode_matcher:
|
||||||
|
raise ParsingError()
|
||||||
|
listeners[last_id] = {
|
||||||
|
'mode': mode_matcher.group(1).upper(),
|
||||||
|
}
|
||||||
|
# Now see if this is a TLS frontend
|
||||||
|
tls_matcher = TLS_CERT_PATTERN.search(section)
|
||||||
|
if tls_matcher:
|
||||||
|
# TODO(rm_work): Can't we have terminated tcp?
|
||||||
|
listeners[last_id]['mode'] = 'TERMINATED_HTTPS'
|
||||||
|
listeners[last_id]['ssl_crt'] = tls_matcher.group(1)
|
||||||
|
# Clear out the token and id and start over
|
||||||
|
last_token = last_id = None
|
||||||
|
|
||||||
|
m = STATS_SOCKET_PATTERN.search(cfg)
|
||||||
|
if not m:
|
||||||
|
raise ParsingError()
|
||||||
|
stats_socket = m.group(1)
|
||||||
|
|
||||||
|
return stats_socket, listeners
|
||||||
|
|
|
@ -43,18 +43,19 @@ SEQ = 0
|
||||||
# incompatible changes.
|
# incompatible changes.
|
||||||
#
|
#
|
||||||
# ver 1 - Adds UDP listener status when no pool or members are present
|
# ver 1 - Adds UDP listener status when no pool or members are present
|
||||||
|
# ver 2 - Switch to all listeners in a single combined haproxy config
|
||||||
#
|
#
|
||||||
MSG_VER = 1
|
MSG_VER = 2
|
||||||
|
|
||||||
|
|
||||||
def list_sock_stat_files(hadir=None):
|
def list_sock_stat_files(hadir=None):
|
||||||
stat_sock_files = {}
|
stat_sock_files = {}
|
||||||
if hadir is None:
|
if hadir is None:
|
||||||
hadir = CONF.haproxy_amphora.base_path
|
hadir = CONF.haproxy_amphora.base_path
|
||||||
listener_ids = util.get_listeners()
|
lb_ids = util.get_loadbalancers()
|
||||||
for listener_id in listener_ids:
|
for lb_id in lb_ids:
|
||||||
sock_file = listener_id + ".sock"
|
sock_file = lb_id + ".sock"
|
||||||
stat_sock_files[listener_id] = os.path.join(hadir, sock_file)
|
stat_sock_files[lb_id] = os.path.join(hadir, sock_file)
|
||||||
return stat_sock_files
|
return stat_sock_files
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,39 +116,55 @@ def get_stats(stat_sock_file):
|
||||||
|
|
||||||
|
|
||||||
def build_stats_message():
|
def build_stats_message():
|
||||||
|
# Example version 2 message without UDP:
|
||||||
|
# {
|
||||||
|
# "id": "<amphora_id>",
|
||||||
|
# "seq": 67,
|
||||||
|
# "listeners": {
|
||||||
|
# "<listener_id>": {
|
||||||
|
# "status": "OPEN",
|
||||||
|
# "stats": {
|
||||||
|
# "tx": 0,
|
||||||
|
# "rx": 0,
|
||||||
|
# "conns": 0,
|
||||||
|
# "totconns": 0,
|
||||||
|
# "ereq": 0
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# },
|
||||||
|
# "pools": {
|
||||||
|
# "<pool_id>:<listener_id>": {
|
||||||
|
# "status": "UP",
|
||||||
|
# "members": {
|
||||||
|
# "<member_id>": "no check"
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# },
|
||||||
|
# "ver": 2
|
||||||
|
# }
|
||||||
global SEQ
|
global SEQ
|
||||||
msg = {'id': CONF.amphora_agent.amphora_id,
|
msg = {'id': CONF.amphora_agent.amphora_id,
|
||||||
'seq': SEQ, "listeners": {},
|
'seq': SEQ, 'listeners': {}, 'pools': {},
|
||||||
'ver': MSG_VER}
|
'ver': MSG_VER}
|
||||||
SEQ += 1
|
SEQ += 1
|
||||||
stat_sock_files = list_sock_stat_files()
|
stat_sock_files = list_sock_stat_files()
|
||||||
for listener_id, stat_sock_file in stat_sock_files.items():
|
# TODO(rm_work) There should only be one of these in the new config system
|
||||||
listener_dict = {'pools': {},
|
for lb_id, stat_sock_file in stat_sock_files.items():
|
||||||
'status': 'DOWN',
|
if util.is_lb_running(lb_id):
|
||||||
'stats': {
|
|
||||||
'tx': 0,
|
|
||||||
'rx': 0,
|
|
||||||
'conns': 0,
|
|
||||||
'totconns': 0,
|
|
||||||
'ereq': 0}}
|
|
||||||
msg['listeners'][listener_id] = listener_dict
|
|
||||||
if util.is_listener_running(listener_id):
|
|
||||||
(stats, pool_status) = get_stats(stat_sock_file)
|
(stats, pool_status) = get_stats(stat_sock_file)
|
||||||
listener_dict = msg['listeners'][listener_id]
|
|
||||||
for row in stats:
|
for row in stats:
|
||||||
if row['svname'] == 'FRONTEND':
|
if row['svname'] == 'FRONTEND':
|
||||||
listener_dict['stats']['tx'] = int(row['bout'])
|
listener_id = row['pxname']
|
||||||
listener_dict['stats']['rx'] = int(row['bin'])
|
msg['listeners'][listener_id] = {
|
||||||
listener_dict['stats']['conns'] = int(row['scur'])
|
'status': row['status'],
|
||||||
listener_dict['stats']['totconns'] = int(row['stot'])
|
'stats': {'tx': int(row['bout']),
|
||||||
listener_dict['stats']['ereq'] = int(row['ereq'])
|
'rx': int(row['bin']),
|
||||||
listener_dict['status'] = row['status']
|
'conns': int(row['scur']),
|
||||||
for oid, pool in pool_status.items():
|
'totconns': int(row['stot']),
|
||||||
if oid != listener_id:
|
'ereq': int(row['ereq'])}}
|
||||||
pool_id = oid
|
for pool_id, pool in pool_status.items():
|
||||||
pools = listener_dict['pools']
|
msg['pools'][pool_id] = {"status": pool['status'],
|
||||||
pools[pool_id] = {"status": pool['status'],
|
"members": pool['members']}
|
||||||
"members": pool['members']}
|
|
||||||
|
|
||||||
# UDP listener part
|
# UDP listener part
|
||||||
udp_listener_ids = util.get_udp_listeners()
|
udp_listener_ids = util.get_udp_listeners()
|
||||||
|
|
|
@ -124,7 +124,9 @@ class HAProxyQuery(object):
|
||||||
final_results[line['pxname']] = dict(members={})
|
final_results[line['pxname']] = dict(members={})
|
||||||
|
|
||||||
if line['svname'] == 'BACKEND':
|
if line['svname'] == 'BACKEND':
|
||||||
final_results[line['pxname']]['uuid'] = line['pxname']
|
pool_id, listener_id = line['pxname'].split(':')
|
||||||
|
final_results[line['pxname']]['pool_uuid'] = pool_id
|
||||||
|
final_results[line['pxname']]['listener_uuid'] = listener_id
|
||||||
final_results[line['pxname']]['status'] = line['status']
|
final_results[line['pxname']]['status'] = line['status']
|
||||||
else:
|
else:
|
||||||
final_results[line['pxname']]['members'][line['svname']] = (
|
final_results[line['pxname']]['members'][line['svname']] = (
|
||||||
|
|
|
@ -22,17 +22,19 @@ import six
|
||||||
class AmphoraLoadBalancerDriver(object):
|
class AmphoraLoadBalancerDriver(object):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def update_amphora_listeners(self, listeners, amphora_id, timeout_dict):
|
def update_amphora_listeners(self, loadbalancer, amphora,
|
||||||
|
timeout_dict):
|
||||||
"""Update the amphora with a new configuration.
|
"""Update the amphora with a new configuration.
|
||||||
|
|
||||||
:param listeners: List of listeners to update.
|
:param loadbalancer: List of listeners to update.
|
||||||
:type listener: list
|
:type loadbalancer: list(octavia.db.models.Listener)
|
||||||
:param amphora_id: The ID of the amphora to update
|
:param amphora: The index of the specific amphora to update
|
||||||
:type amphora_id: string
|
:type amphora: octavia.db.models.Amphora
|
||||||
:param timeout_dict: Dictionary of timeout values for calls to the
|
:param timeout_dict: Dictionary of timeout values for calls to the
|
||||||
amphora. May contain: req_conn_timeout,
|
amphora. May contain: req_conn_timeout,
|
||||||
req_read_timeout, conn_max_retries,
|
req_read_timeout, conn_max_retries,
|
||||||
conn_retry_interval
|
conn_retry_interval
|
||||||
|
:type timeout_dict: dict
|
||||||
:returns: None
|
:returns: None
|
||||||
|
|
||||||
Builds a new configuration, pushes it to the amphora, and reloads
|
Builds a new configuration, pushes it to the amphora, and reloads
|
||||||
|
@ -40,14 +42,12 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def update(self, listener, vip):
|
def update(self, loadbalancer):
|
||||||
"""Update the amphora with a new configuration.
|
"""Update the amphora with a new configuration.
|
||||||
|
|
||||||
:param listener: listener object,
|
:param loadbalancer: loadbalancer object, need to use its
|
||||||
need to use its protocol_port property
|
vip.ip_address property
|
||||||
:type listener: object
|
:type loadbalancer: octavia.db.models.LoadBalancer
|
||||||
:param vip: vip object, need to use its ip_address property
|
|
||||||
:type vip: object
|
|
||||||
:returns: None
|
:returns: None
|
||||||
|
|
||||||
At this moment, we just build the basic structure for testing, will
|
At this moment, we just build the basic structure for testing, will
|
||||||
|
@ -55,31 +55,13 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def stop(self, listener, vip):
|
def start(self, loadbalancer, amphora):
|
||||||
"""Stop the listener on the vip.
|
"""Start the listeners on the amphora.
|
||||||
|
|
||||||
:param listener: listener object,
|
:param loadbalancer: loadbalancer object to start listeners
|
||||||
need to use its protocol_port property
|
:type loadbalancer: octavia.db.models.LoadBalancer
|
||||||
:type listener: object
|
|
||||||
:param vip: vip object, need to use its ip_address property
|
|
||||||
:type vip: object
|
|
||||||
:returns: return a value list (listener, vip, status flag--suspend)
|
|
||||||
|
|
||||||
At this moment, we just build the basic structure for testing, will
|
|
||||||
add more function along with the development.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def start(self, listener, vip, amphora):
|
|
||||||
"""Start the listener on the vip.
|
|
||||||
|
|
||||||
:param listener: listener object,
|
|
||||||
need to use its protocol_port property
|
|
||||||
:type listener: object
|
|
||||||
:param vip: vip object, need to use its ip_address property
|
|
||||||
:type vip: object
|
|
||||||
:param amphora: Amphora to start. If None, start on all amphora
|
:param amphora: Amphora to start. If None, start on all amphora
|
||||||
:type amphora: object
|
:type amphora: octavia.db.models.Amphora
|
||||||
:returns: return a value list (listener, vip, status flag--enable)
|
:returns: return a value list (listener, vip, status flag--enable)
|
||||||
|
|
||||||
At this moment, we just build the basic structure for testing, will
|
At this moment, we just build the basic structure for testing, will
|
||||||
|
@ -87,14 +69,12 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def delete(self, listener, vip):
|
def delete(self, listener):
|
||||||
"""Delete the listener on the vip.
|
"""Delete the listener on the vip.
|
||||||
|
|
||||||
:param listener: listener object,
|
:param listener: listener object,
|
||||||
need to use its protocol_port property
|
need to use its protocol_port property
|
||||||
:type listener: object
|
:type listener: octavia.db.models.Listener
|
||||||
:param vip: vip object, need to use its ip_address property
|
|
||||||
:type vip: object
|
|
||||||
:returns: return a value list (listener, vip, status flag--delete)
|
:returns: return a value list (listener, vip, status flag--delete)
|
||||||
|
|
||||||
At this moment, we just build the basic structure for testing, will
|
At this moment, we just build the basic structure for testing, will
|
||||||
|
@ -106,7 +86,7 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""Returns information about the amphora.
|
"""Returns information about the amphora.
|
||||||
|
|
||||||
:param amphora: amphora object, need to use its id property
|
:param amphora: amphora object, need to use its id property
|
||||||
:type amphora: object
|
:type amphora: octavia.db.models.Amphora
|
||||||
:returns: return a value list (amphora.id, status flag--'info')
|
:returns: return a value list (amphora.id, status flag--'info')
|
||||||
|
|
||||||
At this moment, we just build the basic structure for testing, will
|
At this moment, we just build the basic structure for testing, will
|
||||||
|
@ -122,7 +102,7 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""Return ceilometer ready diagnostic data.
|
"""Return ceilometer ready diagnostic data.
|
||||||
|
|
||||||
:param amphora: amphora object, need to use its id property
|
:param amphora: amphora object, need to use its id property
|
||||||
:type amphora: object
|
:type amphora: octavia.db.models.Amphora
|
||||||
:returns: return a value list (amphora.id, status flag--'ge
|
:returns: return a value list (amphora.id, status flag--'ge
|
||||||
t_diagnostics')
|
t_diagnostics')
|
||||||
|
|
||||||
|
@ -138,7 +118,7 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""Finalize the amphora before any listeners are configured.
|
"""Finalize the amphora before any listeners are configured.
|
||||||
|
|
||||||
:param amphora: amphora object, need to use its id property
|
:param amphora: amphora object, need to use its id property
|
||||||
:type amphora: object
|
:type amphora: octavia.db.models.Amphora
|
||||||
:returns: None
|
:returns: None
|
||||||
|
|
||||||
At this moment, we just build the basic structure for testing, will
|
At this moment, we just build the basic structure for testing, will
|
||||||
|
@ -151,6 +131,8 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
def post_vip_plug(self, amphora, load_balancer, amphorae_network_config):
|
def post_vip_plug(self, amphora, load_balancer, amphorae_network_config):
|
||||||
"""Called after network driver has allocated and plugged the VIP
|
"""Called after network driver has allocated and plugged the VIP
|
||||||
|
|
||||||
|
:param amphora:
|
||||||
|
:type amphora: octavia.db.models.Amphora
|
||||||
:param load_balancer: A load balancer that just had its vip allocated
|
:param load_balancer: A load balancer that just had its vip allocated
|
||||||
and plugged in the network driver.
|
and plugged in the network driver.
|
||||||
:type load_balancer: octavia.common.data_models.LoadBalancer
|
:type load_balancer: octavia.common.data_models.LoadBalancer
|
||||||
|
@ -168,7 +150,7 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""Called after amphora added to network
|
"""Called after amphora added to network
|
||||||
|
|
||||||
:param amphora: amphora object, needs id and network ip(s)
|
:param amphora: amphora object, needs id and network ip(s)
|
||||||
:type amphora: object
|
:type amphora: octavia.db.models.Amphora
|
||||||
:param port: contains information of the plugged port
|
:param port: contains information of the plugged port
|
||||||
:type port: octavia.network.data_models.Port
|
:type port: octavia.network.data_models.Port
|
||||||
|
|
||||||
|
@ -182,7 +164,7 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""Start health checks.
|
"""Start health checks.
|
||||||
|
|
||||||
:param health_mixin: health mixin object
|
:param health_mixin: health mixin object
|
||||||
:type amphora: object
|
:type health_mixin: HealthMixin
|
||||||
|
|
||||||
Starts listener process and calls HealthMixin to update
|
Starts listener process and calls HealthMixin to update
|
||||||
databases information.
|
databases information.
|
||||||
|
@ -199,7 +181,7 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""Upload cert info to the amphora.
|
"""Upload cert info to the amphora.
|
||||||
|
|
||||||
:param amphora: amphora object, needs id and network ip(s)
|
:param amphora: amphora object, needs id and network ip(s)
|
||||||
:type amphora: object
|
:type amphora: octavia.db.models.Amphora
|
||||||
:param pem_file: a certificate file
|
:param pem_file: a certificate file
|
||||||
:type pem_file: file object
|
:type pem_file: file object
|
||||||
|
|
||||||
|
@ -210,7 +192,7 @@ class AmphoraLoadBalancerDriver(object):
|
||||||
"""Upload and update the amphora agent configuration.
|
"""Upload and update the amphora agent configuration.
|
||||||
|
|
||||||
:param amphora: amphora object, needs id and network ip(s)
|
:param amphora: amphora object, needs id and network ip(s)
|
||||||
:type amphora: object
|
:type amphora: octavia.db.models.Amphora
|
||||||
:param agent_config: The new amphora agent configuration file.
|
:param agent_config: The new amphora agent configuration file.
|
||||||
:type agent_config: string
|
:type agent_config: string
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -32,7 +32,8 @@ from octavia.amphorae.drivers.haproxy import exceptions as exc
|
||||||
from octavia.amphorae.drivers.keepalived import vrrp_rest_driver
|
from octavia.amphorae.drivers.keepalived import vrrp_rest_driver
|
||||||
from octavia.common.config import cfg
|
from octavia.common.config import cfg
|
||||||
from octavia.common import constants as consts
|
from octavia.common import constants as consts
|
||||||
from octavia.common.jinja.haproxy import jinja_cfg
|
import octavia.common.jinja.haproxy.combined_listeners.jinja_cfg as jinja_combo
|
||||||
|
import octavia.common.jinja.haproxy.split_listeners.jinja_cfg as jinja_split
|
||||||
from octavia.common.jinja.lvs import jinja_cfg as jinja_udp_cfg
|
from octavia.common.jinja.lvs import jinja_cfg as jinja_udp_cfg
|
||||||
from octavia.common.tls_utils import cert_parser
|
from octavia.common.tls_utils import cert_parser
|
||||||
from octavia.common import utils
|
from octavia.common import utils
|
||||||
|
@ -51,14 +52,23 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(HaproxyAmphoraLoadBalancerDriver, self).__init__()
|
super(HaproxyAmphoraLoadBalancerDriver, self).__init__()
|
||||||
self.client = AmphoraAPIClient()
|
self.clients = {
|
||||||
|
'base': AmphoraAPIClientBase(),
|
||||||
|
'0.5': AmphoraAPIClient0_5(),
|
||||||
|
'1.0': AmphoraAPIClient1_0(),
|
||||||
|
}
|
||||||
self.cert_manager = stevedore_driver.DriverManager(
|
self.cert_manager = stevedore_driver.DriverManager(
|
||||||
namespace='octavia.cert_manager',
|
namespace='octavia.cert_manager',
|
||||||
name=CONF.certificates.cert_manager,
|
name=CONF.certificates.cert_manager,
|
||||||
invoke_on_load=True,
|
invoke_on_load=True,
|
||||||
).driver
|
).driver
|
||||||
|
|
||||||
self.jinja = jinja_cfg.JinjaTemplater(
|
self.jinja_combo = jinja_combo.JinjaTemplater(
|
||||||
|
base_amp_path=CONF.haproxy_amphora.base_path,
|
||||||
|
base_crt_dir=CONF.haproxy_amphora.base_cert_dir,
|
||||||
|
haproxy_template=CONF.haproxy_amphora.haproxy_template,
|
||||||
|
connection_logging=CONF.haproxy_amphora.connection_logging)
|
||||||
|
self.jinja_split = jinja_split.JinjaTemplater(
|
||||||
base_amp_path=CONF.haproxy_amphora.base_path,
|
base_amp_path=CONF.haproxy_amphora.base_path,
|
||||||
base_crt_dir=CONF.haproxy_amphora.base_cert_dir,
|
base_crt_dir=CONF.haproxy_amphora.base_cert_dir,
|
||||||
haproxy_template=CONF.haproxy_amphora.haproxy_template,
|
haproxy_template=CONF.haproxy_amphora.haproxy_template,
|
||||||
|
@ -72,21 +82,39 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
|
|
||||||
:returns version_list: A list with the major and minor numbers
|
:returns version_list: A list with the major and minor numbers
|
||||||
"""
|
"""
|
||||||
|
self._populate_amphora_api_version(amphora)
|
||||||
|
amp_info = self.clients[amphora.api_version].get_info(amphora)
|
||||||
|
haproxy_version_string = amp_info['haproxy_version']
|
||||||
|
|
||||||
version_string = self.client.get_info(amphora)['haproxy_version']
|
return haproxy_version_string.split('.')[:2]
|
||||||
|
|
||||||
return version_string.split('.')[:2]
|
def _populate_amphora_api_version(self, amphora):
|
||||||
|
"""Populate the amphora object with the api_version
|
||||||
|
|
||||||
def update_amphora_listeners(self, listeners, amphora_index,
|
This will query the amphora for version discovery and populate
|
||||||
amphorae, timeout_dict=None):
|
the api_version string attribute on the amphora object.
|
||||||
|
|
||||||
|
:returns: None
|
||||||
|
"""
|
||||||
|
if not getattr(amphora, 'api_version', None):
|
||||||
|
try:
|
||||||
|
amphora.api_version = self.clients['base'].get_api_version(
|
||||||
|
amphora)['api_version']
|
||||||
|
except exc.NotFound:
|
||||||
|
# Amphora is too old for version discovery, default to 0.5
|
||||||
|
amphora.api_version = '0.5'
|
||||||
|
LOG.debug('Amphora %s has API version %s',
|
||||||
|
amphora.id, amphora.api_version)
|
||||||
|
return list(map(int, amphora.api_version.split('.')))
|
||||||
|
|
||||||
|
def update_amphora_listeners(self, loadbalancer, amphora,
|
||||||
|
timeout_dict=None):
|
||||||
"""Update the amphora with a new configuration.
|
"""Update the amphora with a new configuration.
|
||||||
|
|
||||||
:param listeners: List of listeners to update.
|
:param loadbalancer: The load balancer to update
|
||||||
:type listener: list
|
:type loadbalancer: object
|
||||||
:param amphora_index: The index of the amphora to update
|
:param amphora: The amphora to update
|
||||||
:type amphora_index: integer
|
:type amphora: object
|
||||||
:param amphorae: List of amphorae
|
|
||||||
:type amphorae: list
|
|
||||||
:param timeout_dict: Dictionary of timeout values for calls to the
|
:param timeout_dict: Dictionary of timeout values for calls to the
|
||||||
amphora. May contain: req_conn_timeout,
|
amphora. May contain: req_conn_timeout,
|
||||||
req_read_timeout, conn_max_retries,
|
req_read_timeout, conn_max_retries,
|
||||||
|
@ -96,46 +124,82 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
Updates the configuration of the listeners on a single amphora.
|
Updates the configuration of the listeners on a single amphora.
|
||||||
"""
|
"""
|
||||||
# if the amphora does not yet have listeners, no need to update them.
|
# if the amphora does not yet have listeners, no need to update them.
|
||||||
if not listeners:
|
if not loadbalancer.listeners:
|
||||||
LOG.debug('No listeners found to update.')
|
LOG.debug('No listeners found to update.')
|
||||||
return
|
return
|
||||||
amp = amphorae[amphora_index]
|
if amphora is None or amphora.status == consts.DELETED:
|
||||||
if amp is None or amp.status == consts.DELETED:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
haproxy_versions = self._get_haproxy_versions(amp)
|
# Check which HAProxy version is on the amp
|
||||||
|
haproxy_versions = self._get_haproxy_versions(amphora)
|
||||||
|
# Check which config style to use
|
||||||
|
api_version = self._populate_amphora_api_version(amphora)
|
||||||
|
if api_version[0] == 0 and api_version[1] <= 5: # 0.5 or earlier
|
||||||
|
split_config = True
|
||||||
|
LOG.warning(
|
||||||
|
'Amphora %s for loadbalancer %s needs upgrade to single '
|
||||||
|
'process mode.', amphora.id, loadbalancer.id)
|
||||||
|
else:
|
||||||
|
split_config = False
|
||||||
|
LOG.debug('Amphora %s for loadbalancer %s is already in single '
|
||||||
|
'process mode.', amphora.id, loadbalancer.id)
|
||||||
|
|
||||||
# TODO(johnsom) remove when we don't have a process per listener
|
has_tcp = False
|
||||||
for listener in listeners:
|
for listener in loadbalancer.listeners:
|
||||||
LOG.debug("%s updating listener %s on amphora %s",
|
LOG.debug("%s updating listener %s on amphora %s",
|
||||||
self.__class__.__name__, listener.id, amp.id)
|
self.__class__.__name__, listener.id, amphora.id)
|
||||||
if listener.protocol == 'UDP':
|
if listener.protocol == 'UDP':
|
||||||
# Generate Keepalived LVS configuration from listener object
|
# Generate Keepalived LVS configuration from listener object
|
||||||
config = self.udp_jinja.build_config(listener=listener)
|
config = self.udp_jinja.build_config(listener=listener)
|
||||||
self.client.upload_udp_config(amp, listener.id, config,
|
self.clients[amphora.api_version].upload_udp_config(
|
||||||
timeout_dict=timeout_dict)
|
amphora, listener.id, config, timeout_dict=timeout_dict)
|
||||||
self.client.reload_listener(amp, listener.id,
|
self.clients[amphora.api_version].reload_listener(
|
||||||
timeout_dict=timeout_dict)
|
amphora, listener.id, timeout_dict=timeout_dict)
|
||||||
else:
|
else:
|
||||||
certs = self._process_tls_certificates(listener)
|
has_tcp = True
|
||||||
client_ca_filename = self._process_secret(
|
if split_config:
|
||||||
listener, listener.client_ca_tls_certificate_id)
|
obj_id = listener.id
|
||||||
crl_filename = self._process_secret(
|
else:
|
||||||
listener, listener.client_crl_container_id)
|
obj_id = loadbalancer.id
|
||||||
pool_tls_certs = self._process_listener_pool_certs(listener)
|
|
||||||
|
|
||||||
# Generate HaProxy configuration from listener object
|
certs = self._process_tls_certificates(
|
||||||
config = self.jinja.build_config(
|
listener, amphora, obj_id)
|
||||||
host_amphora=amp, listener=listener,
|
client_ca_filename = self._process_secret(
|
||||||
tls_cert=certs['tls_cert'],
|
listener, listener.client_ca_tls_certificate_id,
|
||||||
haproxy_versions=haproxy_versions,
|
amphora, obj_id)
|
||||||
client_ca_filename=client_ca_filename,
|
crl_filename = self._process_secret(
|
||||||
client_crl=crl_filename,
|
listener, listener.client_crl_container_id,
|
||||||
pool_tls_certs=pool_tls_certs)
|
amphora, obj_id)
|
||||||
self.client.upload_config(amp, listener.id, config,
|
pool_tls_certs = self._process_listener_pool_certs(
|
||||||
timeout_dict=timeout_dict)
|
listener, amphora, obj_id)
|
||||||
self.client.reload_listener(amp, listener.id,
|
|
||||||
timeout_dict=timeout_dict)
|
if split_config:
|
||||||
|
config = self.jinja_split.build_config(
|
||||||
|
host_amphora=amphora, listener=listener,
|
||||||
|
tls_cert=certs['tls_cert'],
|
||||||
|
haproxy_versions=haproxy_versions,
|
||||||
|
client_ca_filename=client_ca_filename,
|
||||||
|
client_crl=crl_filename,
|
||||||
|
pool_tls_certs=pool_tls_certs)
|
||||||
|
self.clients[amphora.api_version].upload_config(
|
||||||
|
amphora, listener.id, config,
|
||||||
|
timeout_dict=timeout_dict)
|
||||||
|
self.clients[amphora.api_version].reload_listener(
|
||||||
|
amphora, listener.id, timeout_dict=timeout_dict)
|
||||||
|
|
||||||
|
if has_tcp and not split_config:
|
||||||
|
# Generate HaProxy configuration from listener object
|
||||||
|
config = self.jinja_combo.build_config(
|
||||||
|
host_amphora=amphora, listeners=loadbalancer.listeners,
|
||||||
|
tls_cert=certs['tls_cert'],
|
||||||
|
haproxy_versions=haproxy_versions,
|
||||||
|
client_ca_filename=client_ca_filename,
|
||||||
|
client_crl=crl_filename,
|
||||||
|
pool_tls_certs=pool_tls_certs)
|
||||||
|
self.clients[amphora.api_version].upload_config(
|
||||||
|
amphora, loadbalancer.id, config, timeout_dict=timeout_dict)
|
||||||
|
self.clients[amphora.api_version].reload_listener(
|
||||||
|
amphora, loadbalancer.id, timeout_dict=timeout_dict)
|
||||||
|
|
||||||
def _udp_update(self, listener, vip):
|
def _udp_update(self, listener, vip):
|
||||||
LOG.debug("Amphora %s keepalivedlvs, updating "
|
LOG.debug("Amphora %s keepalivedlvs, updating "
|
||||||
|
@ -146,69 +210,132 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
for amp in listener.load_balancer.amphorae:
|
for amp in listener.load_balancer.amphorae:
|
||||||
if amp.status != consts.DELETED:
|
if amp.status != consts.DELETED:
|
||||||
# Generate Keepalived LVS configuration from listener object
|
# Generate Keepalived LVS configuration from listener object
|
||||||
|
self._populate_amphora_api_version(amp)
|
||||||
config = self.udp_jinja.build_config(listener=listener)
|
config = self.udp_jinja.build_config(listener=listener)
|
||||||
self.client.upload_udp_config(amp, listener.id, config)
|
self.clients[amp.api_version].upload_udp_config(
|
||||||
self.client.reload_listener(amp, listener.id)
|
amp, listener.id, config)
|
||||||
|
self.clients[amp.api_version].reload_listener(
|
||||||
|
amp, listener.id)
|
||||||
|
|
||||||
def update(self, listener, vip):
|
def update(self, loadbalancer):
|
||||||
if listener.protocol == 'UDP':
|
for amphora in loadbalancer.amphorae:
|
||||||
self._udp_update(listener, vip)
|
if amphora.status != consts.DELETED:
|
||||||
else:
|
self.update_amphora_listeners(loadbalancer, amphora)
|
||||||
LOG.debug("Amphora %s haproxy, updating listener %s, "
|
|
||||||
"vip %s", self.__class__.__name__,
|
|
||||||
listener.protocol_port,
|
|
||||||
vip.ip_address)
|
|
||||||
|
|
||||||
# Process listener certificate info
|
|
||||||
certs = self._process_tls_certificates(listener)
|
|
||||||
client_ca_filename = self._process_secret(
|
|
||||||
listener, listener.client_ca_tls_certificate_id)
|
|
||||||
crl_filename = self._process_secret(
|
|
||||||
listener, listener.client_crl_container_id)
|
|
||||||
pool_tls_certs = self._process_listener_pool_certs(listener)
|
|
||||||
|
|
||||||
for amp in listener.load_balancer.amphorae:
|
|
||||||
if amp.status != consts.DELETED:
|
|
||||||
|
|
||||||
haproxy_versions = self._get_haproxy_versions(amp)
|
|
||||||
|
|
||||||
# Generate HaProxy configuration from listener object
|
|
||||||
config = self.jinja.build_config(
|
|
||||||
host_amphora=amp, listener=listener,
|
|
||||||
tls_cert=certs['tls_cert'],
|
|
||||||
haproxy_versions=haproxy_versions,
|
|
||||||
client_ca_filename=client_ca_filename,
|
|
||||||
client_crl=crl_filename,
|
|
||||||
pool_tls_certs=pool_tls_certs)
|
|
||||||
self.client.upload_config(amp, listener.id, config)
|
|
||||||
self.client.reload_listener(amp, listener.id)
|
|
||||||
|
|
||||||
def upload_cert_amp(self, amp, pem):
|
def upload_cert_amp(self, amp, pem):
|
||||||
LOG.debug("Amphora %s updating cert in REST driver "
|
LOG.debug("Amphora %s updating cert in REST driver "
|
||||||
"with amphora id %s,",
|
"with amphora id %s,",
|
||||||
self.__class__.__name__, amp.id)
|
self.__class__.__name__, amp.id)
|
||||||
self.client.update_cert_for_rotation(amp, pem)
|
self._populate_amphora_api_version(amp)
|
||||||
|
self.clients[amp.api_version].update_cert_for_rotation(amp, pem)
|
||||||
|
|
||||||
def _apply(self, func, listener=None, amphora=None, *args):
|
def _apply(self, func_name, loadbalancer, amphora=None, *args):
|
||||||
if amphora is None:
|
if amphora is None:
|
||||||
for amp in listener.load_balancer.amphorae:
|
amphorae = loadbalancer.amphorae
|
||||||
if amp.status != consts.DELETED:
|
|
||||||
func(amp, listener.id, *args)
|
|
||||||
else:
|
else:
|
||||||
if amphora.status != consts.DELETED:
|
amphorae = [amphora]
|
||||||
func(amphora, listener.id, *args)
|
|
||||||
|
|
||||||
def stop(self, listener, vip):
|
for amp in amphorae:
|
||||||
self._apply(self.client.stop_listener, listener)
|
if amp.status != consts.DELETED:
|
||||||
|
api_version = self._populate_amphora_api_version(amp)
|
||||||
|
# Check which config style to use
|
||||||
|
if api_version[0] == 0 and api_version[1] <= 5:
|
||||||
|
# 0.5 or earlier
|
||||||
|
LOG.warning(
|
||||||
|
'Amphora %s for loadbalancer %s needs upgrade to '
|
||||||
|
'single process mode.', amp.id, loadbalancer.id)
|
||||||
|
for listener in loadbalancer.listeners:
|
||||||
|
getattr(self.clients[amp.api_version], func_name)(
|
||||||
|
amp, listener.id, *args)
|
||||||
|
else:
|
||||||
|
LOG.debug(
|
||||||
|
'Amphora %s for loadbalancer %s is already in single '
|
||||||
|
'process mode.', amp.id, loadbalancer.id)
|
||||||
|
has_tcp = False
|
||||||
|
for listener in loadbalancer.listeners:
|
||||||
|
if listener.protocol == consts.PROTOCOL_UDP:
|
||||||
|
getattr(self.clients[amp.api_version], func_name)(
|
||||||
|
amp, listener.id, *args)
|
||||||
|
else:
|
||||||
|
has_tcp = True
|
||||||
|
if has_tcp:
|
||||||
|
getattr(self.clients[amp.api_version], func_name)(
|
||||||
|
amp, loadbalancer.id, *args)
|
||||||
|
|
||||||
def start(self, listener, vip, amphora=None):
|
def start(self, loadbalancer, amphora=None):
|
||||||
self._apply(self.client.start_listener, listener, amphora)
|
self._apply('start_listener', loadbalancer, amphora)
|
||||||
|
|
||||||
def delete(self, listener, vip):
|
def delete(self, listener):
|
||||||
self._apply(self.client.delete_listener, listener)
|
# Delete any UDP listeners the old way (we didn't update the way they
|
||||||
|
# are configured)
|
||||||
|
loadbalancer = listener.load_balancer
|
||||||
|
if listener.protocol == consts.PROTOCOL_UDP:
|
||||||
|
for amp in loadbalancer.amphorae:
|
||||||
|
if amp.status != consts.DELETED:
|
||||||
|
self._populate_amphora_api_version(amp)
|
||||||
|
self.clients[amp.api_version].delete_listener(
|
||||||
|
amp, listener.id)
|
||||||
|
return
|
||||||
|
|
||||||
|
# In case the listener is not UDP, things get more complicated.
|
||||||
|
# We need to do this individually for each amphora in case some are
|
||||||
|
# using split config and others are using combined config.
|
||||||
|
for amp in loadbalancer.amphorae:
|
||||||
|
if amp.status != consts.DELETED:
|
||||||
|
api_version = self._populate_amphora_api_version(amp)
|
||||||
|
# Check which config style to use
|
||||||
|
if api_version[0] == 0 and api_version[1] <= 5:
|
||||||
|
# 0.5 or earlier
|
||||||
|
LOG.warning(
|
||||||
|
'Amphora %s for loadbalancer %s needs upgrade to '
|
||||||
|
'single process mode.', amp.id, loadbalancer.id)
|
||||||
|
self.clients[amp.api_version].delete_listener(
|
||||||
|
amp, listener.id)
|
||||||
|
else:
|
||||||
|
LOG.debug(
|
||||||
|
'Amphora %s for loadbalancer %s is already in single '
|
||||||
|
'process mode.', amp.id, loadbalancer.id)
|
||||||
|
self._combined_config_delete(amp, listener)
|
||||||
|
|
||||||
|
def _combined_config_delete(self, amphora, listener):
|
||||||
|
# Remove the listener from the listener list on the LB before
|
||||||
|
# passing the whole thing over to update (so it'll actually delete)
|
||||||
|
listener.load_balancer.listeners.remove(listener)
|
||||||
|
|
||||||
|
# Check if there's any certs that we need to delete
|
||||||
|
certs = self._process_tls_certificates(listener)
|
||||||
|
certs_to_delete = set()
|
||||||
|
if certs['tls_cert']:
|
||||||
|
certs_to_delete.add(certs['tls_cert'].id)
|
||||||
|
for sni_cert in certs['sni_certs']:
|
||||||
|
certs_to_delete.add(sni_cert.id)
|
||||||
|
|
||||||
|
# Delete them (they'll be recreated before the reload if they are
|
||||||
|
# needed for other listeners anyway)
|
||||||
|
self._populate_amphora_api_version(amphora)
|
||||||
|
for cert_id in certs_to_delete:
|
||||||
|
self.clients[amphora.api_version].delete_cert_pem(
|
||||||
|
amphora, listener.load_balancer.id,
|
||||||
|
'{id}.pem'.format(id=cert_id))
|
||||||
|
|
||||||
|
# See how many non-UDP listeners we have left
|
||||||
|
non_udp_listener_count = len([
|
||||||
|
1 for l in listener.load_balancer.listeners
|
||||||
|
if l.protocol != consts.PROTOCOL_UDP])
|
||||||
|
if non_udp_listener_count > 0:
|
||||||
|
# We have other listeners, so just update is fine.
|
||||||
|
# TODO(rm_work): This is a little inefficient since this duplicates
|
||||||
|
# a lot of the detection logic that has already been done, but it
|
||||||
|
# is probably safer to re-use the existing code-path.
|
||||||
|
self.update_amphora_listeners(listener.load_balancer, amphora)
|
||||||
|
else:
|
||||||
|
# Deleting the last listener, so really do the delete
|
||||||
|
self.clients[amphora.api_version].delete_listener(
|
||||||
|
amphora, listener.load_balancer.id)
|
||||||
|
|
||||||
def get_info(self, amphora):
|
def get_info(self, amphora):
|
||||||
return self.client.get_info(amphora)
|
self._populate_amphora_api_version(amphora)
|
||||||
|
return self.clients[amphora.api_version].get_info(amphora)
|
||||||
|
|
||||||
def get_diagnostics(self, amphora):
|
def get_diagnostics(self, amphora):
|
||||||
pass
|
pass
|
||||||
|
@ -218,6 +345,7 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
|
|
||||||
def post_vip_plug(self, amphora, load_balancer, amphorae_network_config):
|
def post_vip_plug(self, amphora, load_balancer, amphorae_network_config):
|
||||||
if amphora.status != consts.DELETED:
|
if amphora.status != consts.DELETED:
|
||||||
|
self._populate_amphora_api_version(amphora)
|
||||||
subnet = amphorae_network_config.get(amphora.id).vip_subnet
|
subnet = amphorae_network_config.get(amphora.id).vip_subnet
|
||||||
# NOTE(blogan): using the vrrp port here because that
|
# NOTE(blogan): using the vrrp port here because that
|
||||||
# is what the allowed address pairs network driver sets
|
# is what the allowed address pairs network driver sets
|
||||||
|
@ -242,9 +370,8 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
'mtu': port.network.mtu,
|
'mtu': port.network.mtu,
|
||||||
'host_routes': host_routes}
|
'host_routes': host_routes}
|
||||||
try:
|
try:
|
||||||
self.client.plug_vip(amphora,
|
self.clients[amphora.api_version].plug_vip(
|
||||||
load_balancer.vip.ip_address,
|
amphora, load_balancer.vip.ip_address, net_info)
|
||||||
net_info)
|
|
||||||
except exc.Conflict:
|
except exc.Conflict:
|
||||||
LOG.warning('VIP with MAC %(mac)s already exists on amphora, '
|
LOG.warning('VIP with MAC %(mac)s already exists on amphora, '
|
||||||
'skipping post_vip_plug',
|
'skipping post_vip_plug',
|
||||||
|
@ -264,13 +391,14 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
'fixed_ips': fixed_ips,
|
'fixed_ips': fixed_ips,
|
||||||
'mtu': port.network.mtu}
|
'mtu': port.network.mtu}
|
||||||
try:
|
try:
|
||||||
self.client.plug_network(amphora, port_info)
|
self._populate_amphora_api_version(amphora)
|
||||||
|
self.clients[amphora.api_version].plug_network(amphora, port_info)
|
||||||
except exc.Conflict:
|
except exc.Conflict:
|
||||||
LOG.warning('Network with MAC %(mac)s already exists on amphora, '
|
LOG.warning('Network with MAC %(mac)s already exists on amphora, '
|
||||||
'skipping post_network_plug',
|
'skipping post_network_plug',
|
||||||
{'mac': port.mac_address})
|
{'mac': port.mac_address})
|
||||||
|
|
||||||
def _process_tls_certificates(self, listener):
|
def _process_tls_certificates(self, listener, amphora=None, obj_id=None):
|
||||||
"""Processes TLS data from the listener.
|
"""Processes TLS data from the listener.
|
||||||
|
|
||||||
Converts and uploads PEM data to the Amphora API
|
Converts and uploads PEM data to the Amphora API
|
||||||
|
@ -290,15 +418,15 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
sni_certs = data['sni_certs']
|
sni_certs = data['sni_certs']
|
||||||
certs.extend(sni_certs)
|
certs.extend(sni_certs)
|
||||||
|
|
||||||
for cert in certs:
|
if amphora and obj_id:
|
||||||
pem = cert_parser.build_pem(cert)
|
for cert in certs:
|
||||||
md5 = hashlib.md5(pem).hexdigest() # nosec
|
pem = cert_parser.build_pem(cert)
|
||||||
name = '{id}.pem'.format(id=cert.id)
|
md5 = hashlib.md5(pem).hexdigest() # nosec
|
||||||
self._apply(self._upload_cert, listener, None, pem, md5, name)
|
name = '{id}.pem'.format(id=cert.id)
|
||||||
|
self._upload_cert(amphora, obj_id, pem, md5, name)
|
||||||
return {'tls_cert': tls_cert, 'sni_certs': sni_certs}
|
return {'tls_cert': tls_cert, 'sni_certs': sni_certs}
|
||||||
|
|
||||||
def _process_secret(self, listener, secret_ref):
|
def _process_secret(self, listener, secret_ref, amphora=None, obj_id=None):
|
||||||
"""Get the secret from the cert manager and upload it to the amp.
|
"""Get the secret from the cert manager and upload it to the amp.
|
||||||
|
|
||||||
:returns: The filename of the secret in the amp.
|
:returns: The filename of the secret in the amp.
|
||||||
|
@ -314,10 +442,14 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
md5 = hashlib.md5(secret).hexdigest() # nosec
|
md5 = hashlib.md5(secret).hexdigest() # nosec
|
||||||
id = hashlib.sha1(secret).hexdigest() # nosec
|
id = hashlib.sha1(secret).hexdigest() # nosec
|
||||||
name = '{id}.pem'.format(id=id)
|
name = '{id}.pem'.format(id=id)
|
||||||
self._apply(self._upload_cert, listener, None, secret, md5, name)
|
|
||||||
|
if amphora and obj_id:
|
||||||
|
self._upload_cert(
|
||||||
|
amphora, obj_id, pem=secret, md5=md5, name=name)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def _process_listener_pool_certs(self, listener):
|
def _process_listener_pool_certs(self, listener, amphora=None,
|
||||||
|
obj_id=None):
|
||||||
# {'POOL-ID': {
|
# {'POOL-ID': {
|
||||||
# 'client_cert': client_full_filename,
|
# 'client_cert': client_full_filename,
|
||||||
# 'ca_cert': ca_cert_full_filename,
|
# 'ca_cert': ca_cert_full_filename,
|
||||||
|
@ -325,19 +457,20 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
pool_certs_dict = dict()
|
pool_certs_dict = dict()
|
||||||
for pool in listener.pools:
|
for pool in listener.pools:
|
||||||
if pool.id not in pool_certs_dict:
|
if pool.id not in pool_certs_dict:
|
||||||
pool_certs_dict[pool.id] = self._process_pool_certs(listener,
|
pool_certs_dict[pool.id] = self._process_pool_certs(
|
||||||
pool)
|
listener, pool, amphora, obj_id)
|
||||||
for l7policy in listener.l7policies:
|
for l7policy in listener.l7policies:
|
||||||
if (l7policy.redirect_pool and
|
if (l7policy.redirect_pool and
|
||||||
l7policy.redirect_pool.id not in pool_certs_dict):
|
l7policy.redirect_pool.id not in pool_certs_dict):
|
||||||
pool_certs_dict[l7policy.redirect_pool.id] = (
|
pool_certs_dict[l7policy.redirect_pool.id] = (
|
||||||
self._process_pool_certs(listener, l7policy.redirect_pool))
|
self._process_pool_certs(listener, l7policy.redirect_pool,
|
||||||
|
amphora, obj_id))
|
||||||
return pool_certs_dict
|
return pool_certs_dict
|
||||||
|
|
||||||
def _process_pool_certs(self, listener, pool):
|
def _process_pool_certs(self, listener, pool, amphora=None, obj_id=None):
|
||||||
pool_cert_dict = dict()
|
pool_cert_dict = dict()
|
||||||
|
|
||||||
# Handle the cleint cert(s) and key
|
# Handle the client cert(s) and key
|
||||||
if pool.tls_certificate_id:
|
if pool.tls_certificate_id:
|
||||||
data = cert_parser.load_certificates_data(self.cert_manager, pool)
|
data = cert_parser.load_certificates_data(self.cert_manager, pool)
|
||||||
pem = cert_parser.build_pem(data)
|
pem = cert_parser.build_pem(data)
|
||||||
|
@ -347,15 +480,18 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
pass
|
pass
|
||||||
md5 = hashlib.md5(pem).hexdigest() # nosec
|
md5 = hashlib.md5(pem).hexdigest() # nosec
|
||||||
name = '{id}.pem'.format(id=data.id)
|
name = '{id}.pem'.format(id=data.id)
|
||||||
self._apply(self._upload_cert, listener, None, pem, md5, name)
|
if amphora and obj_id:
|
||||||
|
self._upload_cert(amphora, obj_id, pem=pem, md5=md5, name=name)
|
||||||
pool_cert_dict['client_cert'] = os.path.join(
|
pool_cert_dict['client_cert'] = os.path.join(
|
||||||
CONF.haproxy_amphora.base_cert_dir, listener.id, name)
|
CONF.haproxy_amphora.base_cert_dir, listener.id, name)
|
||||||
if pool.ca_tls_certificate_id:
|
if pool.ca_tls_certificate_id:
|
||||||
name = self._process_secret(listener, pool.ca_tls_certificate_id)
|
name = self._process_secret(listener, pool.ca_tls_certificate_id,
|
||||||
|
amphora, obj_id)
|
||||||
pool_cert_dict['ca_cert'] = os.path.join(
|
pool_cert_dict['ca_cert'] = os.path.join(
|
||||||
CONF.haproxy_amphora.base_cert_dir, listener.id, name)
|
CONF.haproxy_amphora.base_cert_dir, listener.id, name)
|
||||||
if pool.crl_container_id:
|
if pool.crl_container_id:
|
||||||
name = self._process_secret(listener, pool.crl_container_id)
|
name = self._process_secret(listener, pool.crl_container_id,
|
||||||
|
amphora, obj_id)
|
||||||
pool_cert_dict['crl'] = os.path.join(
|
pool_cert_dict['crl'] = os.path.join(
|
||||||
CONF.haproxy_amphora.base_cert_dir, listener.id, name)
|
CONF.haproxy_amphora.base_cert_dir, listener.id, name)
|
||||||
|
|
||||||
|
@ -363,13 +499,14 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
|
|
||||||
def _upload_cert(self, amp, listener_id, pem, md5, name):
|
def _upload_cert(self, amp, listener_id, pem, md5, name):
|
||||||
try:
|
try:
|
||||||
if self.client.get_cert_md5sum(
|
if self.clients[amp.api_version].get_cert_md5sum(
|
||||||
amp, listener_id, name, ignore=(404,)) == md5:
|
amp, listener_id, name, ignore=(404,)) == md5:
|
||||||
return
|
return
|
||||||
except exc.NotFound:
|
except exc.NotFound:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.client.upload_cert_pem(amp, listener_id, name, pem)
|
self.clients[amp.api_version].upload_cert_pem(
|
||||||
|
amp, listener_id, name, pem)
|
||||||
|
|
||||||
def update_amphora_agent_config(self, amphora, agent_config,
|
def update_amphora_agent_config(self, amphora, agent_config,
|
||||||
timeout_dict=None):
|
timeout_dict=None):
|
||||||
|
@ -389,8 +526,9 @@ class HaproxyAmphoraLoadBalancerDriver(
|
||||||
new values.
|
new values.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.client.update_agent_config(amphora, agent_config,
|
self._populate_amphora_api_version(amphora)
|
||||||
timeout_dict=timeout_dict)
|
self.clients[amphora.api_version].update_agent_config(
|
||||||
|
amphora, agent_config, timeout_dict=timeout_dict)
|
||||||
except exc.NotFound:
|
except exc.NotFound:
|
||||||
LOG.debug('Amphora {} does not support the update_agent_config '
|
LOG.debug('Amphora {} does not support the update_agent_config '
|
||||||
'API.'.format(amphora.id))
|
'API.'.format(amphora.id))
|
||||||
|
@ -411,10 +549,9 @@ class CustomHostNameCheckingAdapter(requests.adapters.HTTPAdapter):
|
||||||
self).init_poolmanager(*pool_args, **pool_kwargs)
|
self).init_poolmanager(*pool_args, **pool_kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AmphoraAPIClient(object):
|
class AmphoraAPIClientBase(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(AmphoraAPIClient, self).__init__()
|
super(AmphoraAPIClientBase, self).__init__()
|
||||||
self.secure = False
|
|
||||||
|
|
||||||
self.get = functools.partial(self.request, 'get')
|
self.get = functools.partial(self.request, 'get')
|
||||||
self.post = functools.partial(self.request, 'post')
|
self.post = functools.partial(self.request, 'post')
|
||||||
|
@ -422,38 +559,29 @@ class AmphoraAPIClient(object):
|
||||||
self.delete = functools.partial(self.request, 'delete')
|
self.delete = functools.partial(self.request, 'delete')
|
||||||
self.head = functools.partial(self.request, 'head')
|
self.head = functools.partial(self.request, 'head')
|
||||||
|
|
||||||
self.start_listener = functools.partial(self._action,
|
|
||||||
consts.AMP_ACTION_START)
|
|
||||||
self.stop_listener = functools.partial(self._action,
|
|
||||||
consts.AMP_ACTION_STOP)
|
|
||||||
self.reload_listener = functools.partial(self._action,
|
|
||||||
consts.AMP_ACTION_RELOAD)
|
|
||||||
|
|
||||||
self.start_vrrp = functools.partial(self._vrrp_action,
|
|
||||||
consts.AMP_ACTION_START)
|
|
||||||
self.stop_vrrp = functools.partial(self._vrrp_action,
|
|
||||||
consts.AMP_ACTION_STOP)
|
|
||||||
self.reload_vrrp = functools.partial(self._vrrp_action,
|
|
||||||
consts.AMP_ACTION_RELOAD)
|
|
||||||
|
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
self.session.cert = CONF.haproxy_amphora.client_cert
|
self.session.cert = CONF.haproxy_amphora.client_cert
|
||||||
self.ssl_adapter = CustomHostNameCheckingAdapter()
|
self.ssl_adapter = CustomHostNameCheckingAdapter()
|
||||||
self.session.mount('https://', self.ssl_adapter)
|
self.session.mount('https://', self.ssl_adapter)
|
||||||
|
|
||||||
def _base_url(self, ip):
|
def _base_url(self, ip, api_version=None):
|
||||||
if utils.is_ipv6_lla(ip):
|
if utils.is_ipv6_lla(ip):
|
||||||
ip = '[{ip}%{interface}]'.format(
|
ip = '[{ip}%{interface}]'.format(
|
||||||
ip=ip,
|
ip=ip,
|
||||||
interface=CONF.haproxy_amphora.lb_network_interface)
|
interface=CONF.haproxy_amphora.lb_network_interface)
|
||||||
elif utils.is_ipv6(ip):
|
elif utils.is_ipv6(ip):
|
||||||
ip = '[{ip}]'.format(ip=ip)
|
ip = '[{ip}]'.format(ip=ip)
|
||||||
return "https://{ip}:{port}/{version}/".format(
|
if api_version:
|
||||||
|
return "https://{ip}:{port}/{version}/".format(
|
||||||
|
ip=ip,
|
||||||
|
port=CONF.haproxy_amphora.bind_port,
|
||||||
|
version=api_version)
|
||||||
|
return "https://{ip}:{port}/".format(
|
||||||
ip=ip,
|
ip=ip,
|
||||||
port=CONF.haproxy_amphora.bind_port,
|
port=CONF.haproxy_amphora.bind_port)
|
||||||
version=API_VERSION)
|
|
||||||
|
|
||||||
def request(self, method, amp, path='/', timeout_dict=None, **kwargs):
|
def request(self, method, amp, path='/', timeout_dict=None,
|
||||||
|
retry_404=True, **kwargs):
|
||||||
cfg_ha_amp = CONF.haproxy_amphora
|
cfg_ha_amp = CONF.haproxy_amphora
|
||||||
if timeout_dict is None:
|
if timeout_dict is None:
|
||||||
timeout_dict = {}
|
timeout_dict = {}
|
||||||
|
@ -468,7 +596,7 @@ class AmphoraAPIClient(object):
|
||||||
|
|
||||||
LOG.debug("request url %s", path)
|
LOG.debug("request url %s", path)
|
||||||
_request = getattr(self.session, method.lower())
|
_request = getattr(self.session, method.lower())
|
||||||
_url = self._base_url(amp.lb_network_ip) + path
|
_url = self._base_url(amp.lb_network_ip, amp.api_version) + path
|
||||||
LOG.debug("request url %s", _url)
|
LOG.debug("request url %s", _url)
|
||||||
reqargs = {
|
reqargs = {
|
||||||
'verify': CONF.haproxy_amphora.server_ca,
|
'verify': CONF.haproxy_amphora.server_ca,
|
||||||
|
@ -481,7 +609,7 @@ class AmphoraAPIClient(object):
|
||||||
self.ssl_adapter.uuid = amp.id
|
self.ssl_adapter.uuid = amp.id
|
||||||
exception = None
|
exception = None
|
||||||
# Keep retrying
|
# Keep retrying
|
||||||
for a in six.moves.xrange(conn_max_retries):
|
for dummy in six.moves.xrange(conn_max_retries):
|
||||||
try:
|
try:
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.filterwarnings(
|
warnings.filterwarnings(
|
||||||
|
@ -497,6 +625,8 @@ class AmphoraAPIClient(object):
|
||||||
# amphora is not yet up, in which case retry.
|
# amphora is not yet up, in which case retry.
|
||||||
# Otherwise return the response quickly.
|
# Otherwise return the response quickly.
|
||||||
if r.status_code == 404:
|
if r.status_code == 404:
|
||||||
|
if not retry_404:
|
||||||
|
raise exc.NotFound()
|
||||||
LOG.debug('Got a 404 (content-type: %(content_type)s) -- '
|
LOG.debug('Got a 404 (content-type: %(content_type)s) -- '
|
||||||
'connection data: %(content)s',
|
'connection data: %(content)s',
|
||||||
{'content_type': content_type,
|
{'content_type': content_type,
|
||||||
|
@ -524,6 +654,32 @@ class AmphoraAPIClient(object):
|
||||||
'exception': exception})
|
'exception': exception})
|
||||||
raise driver_except.TimeOutException()
|
raise driver_except.TimeOutException()
|
||||||
|
|
||||||
|
def get_api_version(self, amp):
|
||||||
|
amp.api_version = None
|
||||||
|
r = self.get(amp, retry_404=False)
|
||||||
|
# Handle 404 special as we don't want to log an ERROR on 404
|
||||||
|
exc.check_exception(r, (404,))
|
||||||
|
if r.status_code == 404:
|
||||||
|
raise exc.NotFound()
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
class AmphoraAPIClient0_5(AmphoraAPIClientBase):
|
||||||
|
def __init__(self):
|
||||||
|
super(AmphoraAPIClient0_5, self).__init__()
|
||||||
|
|
||||||
|
self.start_listener = functools.partial(self._action,
|
||||||
|
consts.AMP_ACTION_START)
|
||||||
|
self.reload_listener = functools.partial(self._action,
|
||||||
|
consts.AMP_ACTION_RELOAD)
|
||||||
|
|
||||||
|
self.start_vrrp = functools.partial(self._vrrp_action,
|
||||||
|
consts.AMP_ACTION_START)
|
||||||
|
self.stop_vrrp = functools.partial(self._vrrp_action,
|
||||||
|
consts.AMP_ACTION_STOP)
|
||||||
|
self.reload_vrrp = functools.partial(self._vrrp_action,
|
||||||
|
consts.AMP_ACTION_RELOAD)
|
||||||
|
|
||||||
def upload_config(self, amp, listener_id, config, timeout_dict=None):
|
def upload_config(self, amp, listener_id, config, timeout_dict=None):
|
||||||
r = self.put(
|
r = self.put(
|
||||||
amp,
|
amp,
|
||||||
|
@ -532,14 +688,6 @@ class AmphoraAPIClient(object):
|
||||||
data=config)
|
data=config)
|
||||||
return exc.check_exception(r)
|
return exc.check_exception(r)
|
||||||
|
|
||||||
def get_listener_status(self, amp, listener_id):
|
|
||||||
r = self.get(
|
|
||||||
amp,
|
|
||||||
'listeners/{listener_id}'.format(listener_id=listener_id))
|
|
||||||
if exc.check_exception(r):
|
|
||||||
return r.json()
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _action(self, action, amp, listener_id, timeout_dict=None):
|
def _action(self, action, amp, listener_id, timeout_dict=None):
|
||||||
r = self.put(amp, 'listeners/{listener_id}/{action}'.format(
|
r = self.put(amp, 'listeners/{listener_id}/{action}'.format(
|
||||||
listener_id=listener_id, action=action), timeout_dict=timeout_dict)
|
listener_id=listener_id, action=action), timeout_dict=timeout_dict)
|
||||||
|
@ -630,3 +778,133 @@ class AmphoraAPIClient(object):
|
||||||
def update_agent_config(self, amp, agent_config, timeout_dict=None):
|
def update_agent_config(self, amp, agent_config, timeout_dict=None):
|
||||||
r = self.put(amp, 'config', timeout_dict, data=agent_config)
|
r = self.put(amp, 'config', timeout_dict, data=agent_config)
|
||||||
return exc.check_exception(r)
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
|
||||||
|
class AmphoraAPIClient1_0(AmphoraAPIClientBase):
|
||||||
|
def __init__(self):
|
||||||
|
super(AmphoraAPIClient1_0, self).__init__()
|
||||||
|
|
||||||
|
self.start_listener = functools.partial(self._action,
|
||||||
|
consts.AMP_ACTION_START)
|
||||||
|
self.reload_listener = functools.partial(self._action,
|
||||||
|
consts.AMP_ACTION_RELOAD)
|
||||||
|
|
||||||
|
self.start_vrrp = functools.partial(self._vrrp_action,
|
||||||
|
consts.AMP_ACTION_START)
|
||||||
|
self.stop_vrrp = functools.partial(self._vrrp_action,
|
||||||
|
consts.AMP_ACTION_STOP)
|
||||||
|
self.reload_vrrp = functools.partial(self._vrrp_action,
|
||||||
|
consts.AMP_ACTION_RELOAD)
|
||||||
|
|
||||||
|
def upload_config(self, amp, loadbalancer_id, config, timeout_dict=None):
|
||||||
|
r = self.put(
|
||||||
|
amp,
|
||||||
|
'loadbalancer/{amphora_id}/{loadbalancer_id}/haproxy'.format(
|
||||||
|
amphora_id=amp.id, loadbalancer_id=loadbalancer_id),
|
||||||
|
timeout_dict, data=config)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def get_listener_status(self, amp, listener_id):
|
||||||
|
r = self.get(
|
||||||
|
amp,
|
||||||
|
'listeners/{listener_id}'.format(listener_id=listener_id))
|
||||||
|
if exc.check_exception(r):
|
||||||
|
return r.json()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _action(self, action, amp, object_id, timeout_dict=None):
|
||||||
|
r = self.put(
|
||||||
|
amp, 'loadbalancer/{object_id}/{action}'.format(
|
||||||
|
object_id=object_id, action=action),
|
||||||
|
timeout_dict=timeout_dict)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def upload_cert_pem(self, amp, loadbalancer_id, pem_filename, pem_file):
|
||||||
|
r = self.put(
|
||||||
|
amp,
|
||||||
|
'loadbalancer/{loadbalancer_id}/certificates/{filename}'.format(
|
||||||
|
loadbalancer_id=loadbalancer_id, filename=pem_filename),
|
||||||
|
data=pem_file)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def get_cert_md5sum(self, amp, loadbalancer_id, pem_filename,
|
||||||
|
ignore=tuple()):
|
||||||
|
r = self.get(
|
||||||
|
amp,
|
||||||
|
'loadbalancer/{loadbalancer_id}/certificates/{filename}'.format(
|
||||||
|
loadbalancer_id=loadbalancer_id, filename=pem_filename))
|
||||||
|
if exc.check_exception(r, ignore):
|
||||||
|
return r.json().get("md5sum")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def delete_cert_pem(self, amp, loadbalancer_id, pem_filename):
|
||||||
|
r = self.delete(
|
||||||
|
amp,
|
||||||
|
'loadbalancer/{loadbalancer_id}/certificates/{filename}'.format(
|
||||||
|
loadbalancer_id=loadbalancer_id, filename=pem_filename))
|
||||||
|
return exc.check_exception(r, (404,))
|
||||||
|
|
||||||
|
def update_cert_for_rotation(self, amp, pem_file):
|
||||||
|
r = self.put(amp, 'certificate', data=pem_file)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def delete_listener(self, amp, object_id):
|
||||||
|
r = self.delete(
|
||||||
|
amp, 'listeners/{object_id}'.format(object_id=object_id))
|
||||||
|
return exc.check_exception(r, (404,))
|
||||||
|
|
||||||
|
def get_info(self, amp):
|
||||||
|
r = self.get(amp, "info")
|
||||||
|
if exc.check_exception(r):
|
||||||
|
return r.json()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_details(self, amp):
|
||||||
|
r = self.get(amp, "details")
|
||||||
|
if exc.check_exception(r):
|
||||||
|
return r.json()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_all_listeners(self, amp):
|
||||||
|
r = self.get(amp, "listeners")
|
||||||
|
if exc.check_exception(r):
|
||||||
|
return r.json()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def plug_network(self, amp, port):
|
||||||
|
r = self.post(amp, 'plug/network',
|
||||||
|
json=port)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def plug_vip(self, amp, vip, net_info):
|
||||||
|
r = self.post(amp,
|
||||||
|
'plug/vip/{vip}'.format(vip=vip),
|
||||||
|
json=net_info)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def upload_vrrp_config(self, amp, config):
|
||||||
|
r = self.put(amp, 'vrrp/upload', data=config)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def _vrrp_action(self, action, amp):
|
||||||
|
r = self.put(amp, 'vrrp/{action}'.format(action=action))
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def get_interface(self, amp, ip_addr, timeout_dict=None):
|
||||||
|
r = self.get(amp, 'interface/{ip_addr}'.format(ip_addr=ip_addr),
|
||||||
|
timeout_dict=timeout_dict)
|
||||||
|
if exc.check_exception(r):
|
||||||
|
return r.json()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def upload_udp_config(self, amp, listener_id, config, timeout_dict=None):
|
||||||
|
r = self.put(
|
||||||
|
amp,
|
||||||
|
'listeners/{amphora_id}/{listener_id}/udp_listener'.format(
|
||||||
|
amphora_id=amp.id, listener_id=listener_id), timeout_dict,
|
||||||
|
data=config)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
||||||
|
def update_agent_config(self, amp, agent_config, timeout_dict=None):
|
||||||
|
r = self.put(amp, 'config', timeout_dict, data=agent_config)
|
||||||
|
return exc.check_exception(r)
|
||||||
|
|
|
@ -45,13 +45,14 @@ class KeepalivedAmphoraDriverMixin(driver_base.VRRPDriverMixin):
|
||||||
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
|
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
|
||||||
loadbalancer.amphorae):
|
loadbalancer.amphorae):
|
||||||
|
|
||||||
|
self._populate_amphora_api_version(amp)
|
||||||
# Get the VIP subnet prefix for the amphora
|
# Get the VIP subnet prefix for the amphora
|
||||||
vip_cidr = amphorae_network_config[amp.id].vip_subnet.cidr
|
vip_cidr = amphorae_network_config[amp.id].vip_subnet.cidr
|
||||||
|
|
||||||
# Generate Keepalived configuration from loadbalancer object
|
# Generate Keepalived configuration from loadbalancer object
|
||||||
config = templater.build_keepalived_config(
|
config = templater.build_keepalived_config(
|
||||||
loadbalancer, amp, vip_cidr)
|
loadbalancer, amp, vip_cidr)
|
||||||
self.client.upload_vrrp_config(amp, config)
|
self.clients[amp.api_version].upload_vrrp_config(amp, config)
|
||||||
|
|
||||||
def stop_vrrp_service(self, loadbalancer):
|
def stop_vrrp_service(self, loadbalancer):
|
||||||
"""Stop the vrrp services running on the loadbalancer's amphorae
|
"""Stop the vrrp services running on the loadbalancer's amphorae
|
||||||
|
@ -65,7 +66,8 @@ class KeepalivedAmphoraDriverMixin(driver_base.VRRPDriverMixin):
|
||||||
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
|
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
|
||||||
loadbalancer.amphorae):
|
loadbalancer.amphorae):
|
||||||
|
|
||||||
self.client.stop_vrrp(amp)
|
self._populate_amphora_api_version(amp)
|
||||||
|
self.clients[amp.api_version].stop_vrrp(amp)
|
||||||
|
|
||||||
def start_vrrp_service(self, loadbalancer):
|
def start_vrrp_service(self, loadbalancer):
|
||||||
"""Start the VRRP services of all amphorae of the loadbalancer
|
"""Start the VRRP services of all amphorae of the loadbalancer
|
||||||
|
@ -80,7 +82,8 @@ class KeepalivedAmphoraDriverMixin(driver_base.VRRPDriverMixin):
|
||||||
loadbalancer.amphorae):
|
loadbalancer.amphorae):
|
||||||
|
|
||||||
LOG.debug("Start VRRP Service on amphora %s .", amp.lb_network_ip)
|
LOG.debug("Start VRRP Service on amphora %s .", amp.lb_network_ip)
|
||||||
self.client.start_vrrp(amp)
|
self._populate_amphora_api_version(amp)
|
||||||
|
self.clients[amp.api_version].start_vrrp(amp)
|
||||||
|
|
||||||
def reload_vrrp_service(self, loadbalancer):
|
def reload_vrrp_service(self, loadbalancer):
|
||||||
"""Reload the VRRP services of all amphorae of the loadbalancer
|
"""Reload the VRRP services of all amphorae of the loadbalancer
|
||||||
|
@ -94,8 +97,10 @@ class KeepalivedAmphoraDriverMixin(driver_base.VRRPDriverMixin):
|
||||||
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
|
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
|
||||||
loadbalancer.amphorae):
|
loadbalancer.amphorae):
|
||||||
|
|
||||||
self.client.reload_vrrp(amp)
|
self._populate_amphora_api_version(amp)
|
||||||
|
self.clients[amp.api_version].reload_vrrp(amp)
|
||||||
|
|
||||||
def get_vrrp_interface(self, amphora, timeout_dict=None):
|
def get_vrrp_interface(self, amphora, timeout_dict=None):
|
||||||
return self.client.get_interface(
|
self._populate_amphora_api_version(amphora)
|
||||||
|
return self.clients[amphora.api_version].get_interface(
|
||||||
amphora, amphora.vrrp_ip, timeout_dict=timeout_dict)['interface']
|
amphora, amphora.vrrp_ip, timeout_dict=timeout_dict)['interface']
|
||||||
|
|
|
@ -37,44 +37,41 @@ class NoopManager(object):
|
||||||
super(NoopManager, self).__init__()
|
super(NoopManager, self).__init__()
|
||||||
self.amphoraconfig = {}
|
self.amphoraconfig = {}
|
||||||
|
|
||||||
def update_amphora_listeners(self, listeners, amphora_index,
|
def update_amphora_listeners(self, loadbalancer, amphora, timeout_dict):
|
||||||
amphorae, timeout_dict):
|
amphora_id = amphora.id
|
||||||
amphora_id = amphorae[amphora_index].id
|
for listener in loadbalancer.listeners:
|
||||||
for listener in listeners:
|
|
||||||
LOG.debug("Amphora noop driver update_amphora_listeners, "
|
LOG.debug("Amphora noop driver update_amphora_listeners, "
|
||||||
"listener %s, amphora %s, timeouts %s", listener.id,
|
"listener %s, amphora %s, timeouts %s", listener.id,
|
||||||
amphora_id, timeout_dict)
|
amphora_id, timeout_dict)
|
||||||
self.amphoraconfig[(listener.id, amphora_id)] = (
|
self.amphoraconfig[(listener.id, amphora_id)] = (
|
||||||
listener, amphora_id, timeout_dict, "update_amp")
|
listener, amphora_id, timeout_dict, "update_amp")
|
||||||
|
|
||||||
def update(self, listener, vip):
|
def update(self, loadbalancer):
|
||||||
LOG.debug("Amphora %s no-op, update listener %s, vip %s",
|
LOG.debug("Amphora %s no-op, update listener %s, vip %s",
|
||||||
self.__class__.__name__, listener.protocol_port,
|
|
||||||
vip.ip_address)
|
|
||||||
self.amphoraconfig[(listener.protocol_port,
|
|
||||||
vip.ip_address)] = (listener, vip, 'active')
|
|
||||||
|
|
||||||
def stop(self, listener, vip):
|
|
||||||
LOG.debug("Amphora %s no-op, stop listener %s, vip %s",
|
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
listener.protocol_port, vip.ip_address)
|
tuple(l.protocol_port for l in loadbalancer.listeners),
|
||||||
self.amphoraconfig[(listener.protocol_port,
|
loadbalancer.vip.ip_address)
|
||||||
vip.ip_address)] = (listener, vip, 'stop')
|
self.amphoraconfig[
|
||||||
|
(tuple(l.protocol_port for l in loadbalancer.listeners),
|
||||||
|
loadbalancer.vip.ip_address)] = (loadbalancer.listeners,
|
||||||
|
loadbalancer.vip,
|
||||||
|
'active')
|
||||||
|
|
||||||
def start(self, listener, vip, amphora=None):
|
def start(self, loadbalancer, amphora=None):
|
||||||
LOG.debug("Amphora %s no-op, start listener %s, vip %s, amp %s",
|
LOG.debug("Amphora %s no-op, start listeners, lb %s, amp %s",
|
||||||
self.__class__.__name__,
|
self.__class__.__name__, loadbalancer.id, amphora)
|
||||||
listener.protocol_port, vip.ip_address, amphora)
|
self.amphoraconfig[
|
||||||
self.amphoraconfig[(listener.protocol_port,
|
(loadbalancer.id, amphora.id)] = (loadbalancer, amphora,
|
||||||
vip.ip_address, amphora)] = (listener, vip,
|
'start')
|
||||||
amphora, 'start')
|
|
||||||
|
|
||||||
def delete(self, listener, vip):
|
def delete(self, listener):
|
||||||
LOG.debug("Amphora %s no-op, delete listener %s, vip %s",
|
LOG.debug("Amphora %s no-op, delete listener %s, vip %s",
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
listener.protocol_port, vip.ip_address)
|
listener.protocol_port,
|
||||||
|
listener.load_balancer.vip.ip_address)
|
||||||
self.amphoraconfig[(listener.protocol_port,
|
self.amphoraconfig[(listener.protocol_port,
|
||||||
vip.ip_address)] = (listener, vip, 'delete')
|
listener.load_balancer.vip.ip_address)] = (
|
||||||
|
listener, listener.load_balancer.vip, 'delete')
|
||||||
|
|
||||||
def get_info(self, amphora):
|
def get_info(self, amphora):
|
||||||
LOG.debug("Amphora %s no-op, info amphora %s",
|
LOG.debug("Amphora %s no-op, info amphora %s",
|
||||||
|
@ -124,27 +121,22 @@ class NoopAmphoraLoadBalancerDriver(
|
||||||
super(NoopAmphoraLoadBalancerDriver, self).__init__()
|
super(NoopAmphoraLoadBalancerDriver, self).__init__()
|
||||||
self.driver = NoopManager()
|
self.driver = NoopManager()
|
||||||
|
|
||||||
def update_amphora_listeners(self, listeners, amphora_index,
|
def update_amphora_listeners(self, loadbalancer, amphora, timeout_dict):
|
||||||
amphorae, timeout_dict):
|
|
||||||
|
|
||||||
self.driver.update_amphora_listeners(listeners, amphora_index,
|
self.driver.update_amphora_listeners(loadbalancer, amphora,
|
||||||
amphorae, timeout_dict)
|
timeout_dict)
|
||||||
|
|
||||||
def update(self, listener, vip):
|
def update(self, loadbalancer):
|
||||||
|
|
||||||
self.driver.update(listener, vip)
|
self.driver.update(loadbalancer)
|
||||||
|
|
||||||
def stop(self, listener, vip):
|
def start(self, loadbalancer, amphora=None):
|
||||||
|
|
||||||
self.driver.stop(listener, vip)
|
self.driver.start(loadbalancer, amphora)
|
||||||
|
|
||||||
def start(self, listener, vip, amphora=None):
|
def delete(self, listener):
|
||||||
|
|
||||||
self.driver.start(listener, vip, amphora)
|
self.driver.delete(listener)
|
||||||
|
|
||||||
def delete(self, listener, vip):
|
|
||||||
|
|
||||||
self.driver.delete(listener, vip)
|
|
||||||
|
|
||||||
def get_info(self, amphora):
|
def get_info(self, amphora):
|
||||||
|
|
||||||
|
|
|
@ -122,3 +122,6 @@ def main():
|
||||||
process.join()
|
process.join()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
process_cleanup()
|
process_cleanup()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -39,3 +39,6 @@ def main():
|
||||||
workers=CONF.controller_worker.workers, args=(CONF,))
|
workers=CONF.controller_worker.workers, args=(CONF,))
|
||||||
oslo_config_glue.setup(sm, CONF, reload_method="mutate")
|
oslo_config_glue.setup(sm, CONF, reload_method="mutate")
|
||||||
sm.run()
|
sm.run()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,499 @@
|
||||||
|
# Copyright (c) 2015 Rackspace
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
import jinja2
|
||||||
|
import six
|
||||||
|
|
||||||
|
from octavia.common.config import cfg
|
||||||
|
from octavia.common import constants
|
||||||
|
from octavia.common import utils as octavia_utils
|
||||||
|
|
||||||
|
PROTOCOL_MAP = {
|
||||||
|
constants.PROTOCOL_TCP: 'tcp',
|
||||||
|
constants.PROTOCOL_HTTP: 'http',
|
||||||
|
constants.PROTOCOL_HTTPS: 'tcp',
|
||||||
|
constants.PROTOCOL_PROXY: 'proxy',
|
||||||
|
constants.PROTOCOL_TERMINATED_HTTPS: 'http'
|
||||||
|
}
|
||||||
|
|
||||||
|
BALANCE_MAP = {
|
||||||
|
constants.LB_ALGORITHM_ROUND_ROBIN: 'roundrobin',
|
||||||
|
constants.LB_ALGORITHM_LEAST_CONNECTIONS: 'leastconn',
|
||||||
|
constants.LB_ALGORITHM_SOURCE_IP: 'source'
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIENT_AUTH_MAP = {constants.CLIENT_AUTH_NONE: 'none',
|
||||||
|
constants.CLIENT_AUTH_OPTIONAL: 'optional',
|
||||||
|
constants.CLIENT_AUTH_MANDATORY: 'required'}
|
||||||
|
|
||||||
|
ACTIVE_PENDING_STATUSES = constants.SUPPORTED_PROVISIONING_STATUSES + (
|
||||||
|
constants.DEGRADED,)
|
||||||
|
|
||||||
|
BASE_PATH = '/var/lib/octavia'
|
||||||
|
BASE_CRT_DIR = BASE_PATH + '/certs'
|
||||||
|
|
||||||
|
HAPROXY_TEMPLATE = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
'templates/haproxy.cfg.j2'))
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
JINJA_ENV = None
|
||||||
|
|
||||||
|
|
||||||
|
class JinjaTemplater(object):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
base_amp_path=None,
|
||||||
|
base_crt_dir=None,
|
||||||
|
haproxy_template=None,
|
||||||
|
log_http=None,
|
||||||
|
log_server=None,
|
||||||
|
connection_logging=True):
|
||||||
|
"""HaProxy configuration generation
|
||||||
|
|
||||||
|
:param base_amp_path: Base path for amphora data
|
||||||
|
:param base_crt_dir: Base directory for certificate storage
|
||||||
|
:param haproxy_template: Absolute path to Jinja template
|
||||||
|
:param log_http: Haproxy HTTP logging path
|
||||||
|
:param log_server: Haproxy Server logging path
|
||||||
|
:param connection_logging: enable logging connections in haproxy
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.base_amp_path = base_amp_path or BASE_PATH
|
||||||
|
self.base_crt_dir = base_crt_dir or BASE_CRT_DIR
|
||||||
|
self.haproxy_template = haproxy_template or HAPROXY_TEMPLATE
|
||||||
|
self.log_http = log_http
|
||||||
|
self.log_server = log_server
|
||||||
|
self.connection_logging = connection_logging
|
||||||
|
|
||||||
|
def build_config(self, host_amphora, listeners, tls_cert,
|
||||||
|
haproxy_versions, socket_path=None,
|
||||||
|
client_ca_filename=None, client_crl=None,
|
||||||
|
pool_tls_certs=None):
|
||||||
|
"""Convert a logical configuration to the HAProxy version
|
||||||
|
|
||||||
|
:param host_amphora: The Amphora this configuration is hosted on
|
||||||
|
:param listener: The listener configuration
|
||||||
|
:param tls_cert: The TLS certificates for the listener
|
||||||
|
:param socket_path: The socket path for Haproxy process
|
||||||
|
:return: Rendered configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Check for any backward compatibility items we need to check
|
||||||
|
# This is done here for upgrade scenarios where one amp in a
|
||||||
|
# pair might be running an older amphora version.
|
||||||
|
|
||||||
|
feature_compatibility = {}
|
||||||
|
# Is it newer than haproxy 1.5?
|
||||||
|
if not (int(haproxy_versions[0]) < 2 and int(haproxy_versions[1]) < 6):
|
||||||
|
feature_compatibility[constants.HTTP_REUSE] = True
|
||||||
|
|
||||||
|
return self.render_loadbalancer_obj(
|
||||||
|
host_amphora, listeners, tls_cert=tls_cert,
|
||||||
|
socket_path=socket_path,
|
||||||
|
feature_compatibility=feature_compatibility,
|
||||||
|
client_ca_filename=client_ca_filename, client_crl=client_crl,
|
||||||
|
pool_tls_certs=pool_tls_certs)
|
||||||
|
|
||||||
|
def _get_template(self):
|
||||||
|
"""Returns the specified Jinja configuration template."""
|
||||||
|
global JINJA_ENV
|
||||||
|
if not JINJA_ENV:
|
||||||
|
template_loader = jinja2.FileSystemLoader(
|
||||||
|
searchpath=os.path.dirname(self.haproxy_template))
|
||||||
|
JINJA_ENV = jinja2.Environment(
|
||||||
|
autoescape=True,
|
||||||
|
loader=template_loader,
|
||||||
|
trim_blocks=True,
|
||||||
|
lstrip_blocks=True)
|
||||||
|
JINJA_ENV.filters['hash_amp_id'] = octavia_utils.base64_sha1_string
|
||||||
|
return JINJA_ENV.get_template(os.path.basename(self.haproxy_template))
|
||||||
|
|
||||||
|
def _format_log_string(self, load_balancer, protocol):
|
||||||
|
log_format = CONF.haproxy_amphora.user_log_format.replace(
|
||||||
|
'{project_id}', load_balancer.project_id)
|
||||||
|
log_format = log_format.replace('{lb_id}', load_balancer.id)
|
||||||
|
|
||||||
|
# Order of these filters matter.
|
||||||
|
# TODO(johnsom) Remove when HAProxy handles the format string
|
||||||
|
# with HTTP variables in TCP listeners.
|
||||||
|
# Currently it either throws an error or just fails
|
||||||
|
# to log the message.
|
||||||
|
if protocol not in constants.HAPROXY_HTTP_PROTOCOLS:
|
||||||
|
log_format = log_format.replace('%{+Q}r', '-')
|
||||||
|
log_format = log_format.replace('%r', '-')
|
||||||
|
log_format = log_format.replace('%{+Q}ST', '-')
|
||||||
|
log_format = log_format.replace('%ST', '-')
|
||||||
|
|
||||||
|
log_format = log_format.replace(' ', '\ ')
|
||||||
|
return log_format
|
||||||
|
|
||||||
|
def render_loadbalancer_obj(self, host_amphora, listeners,
|
||||||
|
tls_cert=None, socket_path=None,
|
||||||
|
feature_compatibility=None,
|
||||||
|
client_ca_filename=None, client_crl=None,
|
||||||
|
pool_tls_certs=None):
|
||||||
|
"""Renders a templated configuration from a load balancer object
|
||||||
|
|
||||||
|
:param host_amphora: The Amphora this configuration is hosted on
|
||||||
|
:param listener: The listener configuration
|
||||||
|
:param tls_cert: The TLS certificates for the listener
|
||||||
|
:param client_ca_filename: The CA certificate for client authorization
|
||||||
|
:param socket_path: The socket path for Haproxy process
|
||||||
|
:return: Rendered configuration
|
||||||
|
"""
|
||||||
|
feature_compatibility = feature_compatibility or {}
|
||||||
|
loadbalancer = self._transform_loadbalancer(
|
||||||
|
host_amphora,
|
||||||
|
listeners[0].load_balancer,
|
||||||
|
listeners,
|
||||||
|
tls_cert,
|
||||||
|
feature_compatibility,
|
||||||
|
client_ca_filename=client_ca_filename,
|
||||||
|
client_crl=client_crl,
|
||||||
|
pool_tls_certs=pool_tls_certs)
|
||||||
|
if not socket_path:
|
||||||
|
socket_path = '%s/%s.sock' % (self.base_amp_path,
|
||||||
|
listeners[0].load_balancer.id)
|
||||||
|
return self._get_template().render(
|
||||||
|
{'loadbalancer': loadbalancer,
|
||||||
|
'stats_sock': socket_path,
|
||||||
|
'log_http': self.log_http,
|
||||||
|
'log_server': self.log_server,
|
||||||
|
'administrative_log_facility':
|
||||||
|
CONF.amphora_agent.administrative_log_facility,
|
||||||
|
'user_log_facility': CONF.amphora_agent.user_log_facility,
|
||||||
|
'connection_logging': self.connection_logging},
|
||||||
|
constants=constants)
|
||||||
|
|
||||||
|
def _transform_loadbalancer(self, host_amphora, loadbalancer, listeners,
|
||||||
|
tls_cert, feature_compatibility,
|
||||||
|
client_ca_filename=None, client_crl=None,
|
||||||
|
pool_tls_certs=None):
|
||||||
|
"""Transforms a load balancer into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
listener_transforms = []
|
||||||
|
for listener in listeners:
|
||||||
|
if listener.protocol == constants.PROTOCOL_UDP:
|
||||||
|
continue
|
||||||
|
listener_transforms.append(self._transform_listener(
|
||||||
|
listener, tls_cert, feature_compatibility, loadbalancer,
|
||||||
|
client_ca_filename=client_ca_filename, client_crl=client_crl,
|
||||||
|
pool_tls_certs=pool_tls_certs))
|
||||||
|
|
||||||
|
ret_value = {
|
||||||
|
'id': loadbalancer.id,
|
||||||
|
'vip_address': loadbalancer.vip.ip_address,
|
||||||
|
'listeners': listener_transforms,
|
||||||
|
'topology': loadbalancer.topology,
|
||||||
|
'enabled': loadbalancer.enabled,
|
||||||
|
'peer_port': listeners[0].peer_port,
|
||||||
|
'host_amphora': self._transform_amphora(
|
||||||
|
host_amphora, feature_compatibility),
|
||||||
|
'amphorae': loadbalancer.amphorae
|
||||||
|
}
|
||||||
|
# NOTE(sbalukoff): Global connection limit should be a sum of all
|
||||||
|
# listeners' connection limits.
|
||||||
|
connection_limit_sum = 0
|
||||||
|
for listener in listeners:
|
||||||
|
if listener.protocol == constants.PROTOCOL_UDP:
|
||||||
|
continue
|
||||||
|
if listener.connection_limit and listener.connection_limit > -1:
|
||||||
|
connection_limit_sum += listener.connection_limit
|
||||||
|
else:
|
||||||
|
# If *any* listener has no connection limit, global = MAX
|
||||||
|
connection_limit_sum = constants.HAPROXY_MAX_MAXCONN
|
||||||
|
# If there's a limit between 0 and MAX, set it, otherwise just set MAX
|
||||||
|
if 0 < connection_limit_sum < constants.HAPROXY_MAX_MAXCONN:
|
||||||
|
ret_value['global_connection_limit'] = connection_limit_sum
|
||||||
|
else:
|
||||||
|
ret_value['global_connection_limit'] = (
|
||||||
|
constants.HAPROXY_MAX_MAXCONN)
|
||||||
|
return ret_value
|
||||||
|
|
||||||
|
def _transform_amphora(self, amphora, feature_compatibility):
|
||||||
|
"""Transform an amphora into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'id': amphora.id,
|
||||||
|
'lb_network_ip': amphora.lb_network_ip,
|
||||||
|
'vrrp_ip': amphora.vrrp_ip,
|
||||||
|
'ha_ip': amphora.ha_ip,
|
||||||
|
'vrrp_port_id': amphora.vrrp_port_id,
|
||||||
|
'ha_port_id': amphora.ha_port_id,
|
||||||
|
'role': amphora.role,
|
||||||
|
'status': amphora.status,
|
||||||
|
'vrrp_interface': amphora.vrrp_interface,
|
||||||
|
'vrrp_priority': amphora.vrrp_priority
|
||||||
|
}
|
||||||
|
|
||||||
|
def _transform_listener(self, listener, tls_cert, feature_compatibility,
|
||||||
|
loadbalancer, client_ca_filename=None,
|
||||||
|
client_crl=None, pool_tls_certs=None):
|
||||||
|
"""Transforms a listener into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
ret_value = {
|
||||||
|
'id': listener.id,
|
||||||
|
'protocol_port': listener.protocol_port,
|
||||||
|
'protocol_mode': PROTOCOL_MAP[listener.protocol],
|
||||||
|
'protocol': listener.protocol,
|
||||||
|
'insert_headers': listener.insert_headers,
|
||||||
|
'enabled': listener.enabled,
|
||||||
|
'user_log_format': self._format_log_string(loadbalancer,
|
||||||
|
listener.protocol),
|
||||||
|
'timeout_client_data': (
|
||||||
|
listener.timeout_client_data or
|
||||||
|
CONF.haproxy_amphora.timeout_client_data),
|
||||||
|
'timeout_member_connect': (
|
||||||
|
listener.timeout_member_connect or
|
||||||
|
CONF.haproxy_amphora.timeout_member_connect),
|
||||||
|
'timeout_member_data': (
|
||||||
|
listener.timeout_member_data or
|
||||||
|
CONF.haproxy_amphora.timeout_member_data),
|
||||||
|
'timeout_tcp_inspect': (listener.timeout_tcp_inspect or
|
||||||
|
CONF.haproxy_amphora.timeout_tcp_inspect),
|
||||||
|
}
|
||||||
|
if listener.connection_limit and listener.connection_limit > -1:
|
||||||
|
ret_value['connection_limit'] = listener.connection_limit
|
||||||
|
else:
|
||||||
|
ret_value['connection_limit'] = constants.HAPROXY_MAX_MAXCONN
|
||||||
|
if listener.tls_certificate_id:
|
||||||
|
ret_value['default_tls_path'] = '%s.pem' % (
|
||||||
|
os.path.join(self.base_crt_dir,
|
||||||
|
loadbalancer.id,
|
||||||
|
tls_cert.id))
|
||||||
|
if listener.sni_containers:
|
||||||
|
ret_value['crt_dir'] = os.path.join(
|
||||||
|
self.base_crt_dir, loadbalancer.id)
|
||||||
|
if listener.client_ca_tls_certificate_id:
|
||||||
|
ret_value['client_ca_tls_path'] = '%s' % (
|
||||||
|
os.path.join(self.base_crt_dir, loadbalancer.id,
|
||||||
|
client_ca_filename))
|
||||||
|
ret_value['client_auth'] = CLIENT_AUTH_MAP.get(
|
||||||
|
listener.client_authentication)
|
||||||
|
if listener.client_crl_container_id:
|
||||||
|
ret_value['client_crl_path'] = '%s' % (
|
||||||
|
os.path.join(self.base_crt_dir, loadbalancer.id, client_crl))
|
||||||
|
|
||||||
|
pools = []
|
||||||
|
for x in listener.pools:
|
||||||
|
kwargs = {}
|
||||||
|
if pool_tls_certs and pool_tls_certs.get(x.id):
|
||||||
|
kwargs = {'pool_tls_certs': pool_tls_certs.get(x.id)}
|
||||||
|
pools.append(self._transform_pool(
|
||||||
|
x, feature_compatibility, **kwargs))
|
||||||
|
ret_value['pools'] = pools
|
||||||
|
if listener.default_pool:
|
||||||
|
for pool in pools:
|
||||||
|
if pool['id'] == listener.default_pool.id:
|
||||||
|
ret_value['default_pool'] = pool
|
||||||
|
break
|
||||||
|
|
||||||
|
l7policies = [self._transform_l7policy(
|
||||||
|
x, feature_compatibility, pool_tls_certs)
|
||||||
|
for x in listener.l7policies]
|
||||||
|
ret_value['l7policies'] = l7policies
|
||||||
|
return ret_value
|
||||||
|
|
||||||
|
def _transform_pool(self, pool, feature_compatibility,
|
||||||
|
pool_tls_certs=None):
|
||||||
|
"""Transforms a pool into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
ret_value = {
|
||||||
|
'id': pool.id,
|
||||||
|
'protocol': PROTOCOL_MAP[pool.protocol],
|
||||||
|
'proxy_protocol': pool.protocol == constants.PROTOCOL_PROXY,
|
||||||
|
'lb_algorithm': BALANCE_MAP.get(pool.lb_algorithm, 'roundrobin'),
|
||||||
|
'members': [],
|
||||||
|
'health_monitor': '',
|
||||||
|
'session_persistence': '',
|
||||||
|
'enabled': pool.enabled,
|
||||||
|
'operating_status': pool.operating_status,
|
||||||
|
'stick_size': CONF.haproxy_amphora.haproxy_stick_size,
|
||||||
|
constants.HTTP_REUSE: feature_compatibility.get(
|
||||||
|
constants.HTTP_REUSE, False),
|
||||||
|
'ca_tls_path': '',
|
||||||
|
'crl_path': '',
|
||||||
|
'tls_enabled': pool.tls_enabled
|
||||||
|
}
|
||||||
|
members = [self._transform_member(x, feature_compatibility)
|
||||||
|
for x in pool.members]
|
||||||
|
ret_value['members'] = members
|
||||||
|
if pool.health_monitor:
|
||||||
|
ret_value['health_monitor'] = self._transform_health_monitor(
|
||||||
|
pool.health_monitor, feature_compatibility)
|
||||||
|
if pool.session_persistence:
|
||||||
|
ret_value[
|
||||||
|
'session_persistence'] = self._transform_session_persistence(
|
||||||
|
pool.session_persistence, feature_compatibility)
|
||||||
|
if (pool.tls_certificate_id and pool_tls_certs and
|
||||||
|
pool_tls_certs.get('client_cert')):
|
||||||
|
ret_value['client_cert'] = pool_tls_certs.get('client_cert')
|
||||||
|
if (pool.ca_tls_certificate_id and pool_tls_certs and
|
||||||
|
pool_tls_certs.get('ca_cert')):
|
||||||
|
ret_value['ca_cert'] = pool_tls_certs.get('ca_cert')
|
||||||
|
if (pool.crl_container_id and pool_tls_certs and
|
||||||
|
pool_tls_certs.get('crl')):
|
||||||
|
ret_value['crl'] = pool_tls_certs.get('crl')
|
||||||
|
|
||||||
|
return ret_value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _transform_session_persistence(persistence, feature_compatibility):
|
||||||
|
"""Transforms session persistence into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'type': persistence.type,
|
||||||
|
'cookie_name': persistence.cookie_name
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _transform_member(member, feature_compatibility):
|
||||||
|
"""Transforms a member into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'id': member.id,
|
||||||
|
'address': member.ip_address,
|
||||||
|
'protocol_port': member.protocol_port,
|
||||||
|
'weight': member.weight,
|
||||||
|
'enabled': member.enabled,
|
||||||
|
'subnet_id': member.subnet_id,
|
||||||
|
'operating_status': member.operating_status,
|
||||||
|
'monitor_address': member.monitor_address,
|
||||||
|
'monitor_port': member.monitor_port,
|
||||||
|
'backup': member.backup
|
||||||
|
}
|
||||||
|
|
||||||
|
def _transform_health_monitor(self, monitor, feature_compatibility):
|
||||||
|
"""Transforms a health monitor into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
codes = None
|
||||||
|
if monitor.expected_codes:
|
||||||
|
codes = '|'.join(self._expand_expected_codes(
|
||||||
|
monitor.expected_codes))
|
||||||
|
return {
|
||||||
|
'id': monitor.id,
|
||||||
|
'type': monitor.type,
|
||||||
|
'delay': monitor.delay,
|
||||||
|
'timeout': monitor.timeout,
|
||||||
|
'fall_threshold': monitor.fall_threshold,
|
||||||
|
'rise_threshold': monitor.rise_threshold,
|
||||||
|
'http_method': monitor.http_method,
|
||||||
|
'url_path': monitor.url_path,
|
||||||
|
'expected_codes': codes,
|
||||||
|
'enabled': monitor.enabled,
|
||||||
|
'http_version': monitor.http_version,
|
||||||
|
'domain_name': monitor.domain_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _transform_l7policy(self, l7policy, feature_compatibility,
|
||||||
|
pool_tls_certs=None):
|
||||||
|
"""Transforms an L7 policy into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
ret_value = {
|
||||||
|
'id': l7policy.id,
|
||||||
|
'action': l7policy.action,
|
||||||
|
'redirect_url': l7policy.redirect_url,
|
||||||
|
'redirect_prefix': l7policy.redirect_prefix,
|
||||||
|
'enabled': l7policy.enabled
|
||||||
|
}
|
||||||
|
if l7policy.redirect_pool:
|
||||||
|
kwargs = {}
|
||||||
|
if pool_tls_certs and pool_tls_certs.get(
|
||||||
|
l7policy.redirect_pool.id):
|
||||||
|
kwargs = {'pool_tls_certs':
|
||||||
|
pool_tls_certs.get(l7policy.redirect_pool.id)}
|
||||||
|
ret_value['redirect_pool'] = self._transform_pool(
|
||||||
|
l7policy.redirect_pool, feature_compatibility, **kwargs)
|
||||||
|
else:
|
||||||
|
ret_value['redirect_pool'] = None
|
||||||
|
if (l7policy.action in [constants.L7POLICY_ACTION_REDIRECT_TO_URL,
|
||||||
|
constants.L7POLICY_ACTION_REDIRECT_PREFIX] and
|
||||||
|
l7policy.redirect_http_code):
|
||||||
|
ret_value['redirect_http_code'] = l7policy.redirect_http_code
|
||||||
|
else:
|
||||||
|
ret_value['redirect_http_code'] = None
|
||||||
|
l7rules = [self._transform_l7rule(x, feature_compatibility)
|
||||||
|
for x in l7policy.l7rules if x.enabled]
|
||||||
|
ret_value['l7rules'] = l7rules
|
||||||
|
return ret_value
|
||||||
|
|
||||||
|
def _transform_l7rule(self, l7rule, feature_compatibility):
|
||||||
|
"""Transforms an L7 rule into an object that will
|
||||||
|
|
||||||
|
be processed by the templating system
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'id': l7rule.id,
|
||||||
|
'type': l7rule.type,
|
||||||
|
'compare_type': l7rule.compare_type,
|
||||||
|
'key': l7rule.key,
|
||||||
|
'value': self._escape_haproxy_config_string(l7rule.value),
|
||||||
|
'invert': l7rule.invert,
|
||||||
|
'enabled': l7rule.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _escape_haproxy_config_string(value):
|
||||||
|
"""Escapes certain characters in a given string such that
|
||||||
|
|
||||||
|
haproxy will parse the string as a single value
|
||||||
|
"""
|
||||||
|
# Escape backslashes first
|
||||||
|
value = re.sub(r'\\', r'\\\\', value)
|
||||||
|
# Spaces next
|
||||||
|
value = re.sub(' ', '\\ ', value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _expand_expected_codes(codes):
|
||||||
|
"""Expand the expected code string in set of codes.
|
||||||
|
|
||||||
|
200-204 -> 200, 201, 202, 204
|
||||||
|
200, 203 -> 200, 203
|
||||||
|
"""
|
||||||
|
|
||||||
|
retval = set()
|
||||||
|
for code in codes.replace(',', ' ').split(' '):
|
||||||
|
code = code.strip()
|
||||||
|
|
||||||
|
if not code:
|
||||||
|
continue
|
||||||
|
elif '-' in code:
|
||||||
|
low, hi = code.split('-')[:2]
|
||||||
|
retval.update(
|
||||||
|
str(i) for i in six.moves.xrange(int(low), int(hi) + 1))
|
||||||
|
else:
|
||||||
|
retval.add(code)
|
||||||
|
return sorted(retval)
|
|
@ -0,0 +1,52 @@
|
||||||
|
{# Copyright (c) 2015 Rackspace
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#}
|
||||||
|
# Configuration for loadbalancer {{ loadbalancer_id }}
|
||||||
|
global
|
||||||
|
daemon
|
||||||
|
user nobody
|
||||||
|
log {{ log_http | default('/dev/log', true)}} local{{ user_log_facility }}
|
||||||
|
log {{ log_server | default('/dev/log', true)}} local{{ administrative_log_facility }} notice
|
||||||
|
stats socket {{ sock_path }} mode 0666 level user
|
||||||
|
{% if loadbalancer.global_connection_limit is defined %}
|
||||||
|
maxconn {{ loadbalancer.global_connection_limit }}
|
||||||
|
{% endif %}
|
||||||
|
{% set found_ns = namespace(found=false) %}
|
||||||
|
{% for listener in loadbalancer.listeners if listener.enabled %}
|
||||||
|
{% for pool in listener.pools if pool.enabled %}
|
||||||
|
{% if pool.health_monitor and pool.health_monitor.enabled and
|
||||||
|
pool.health_monitor.type == constants.HEALTH_MONITOR_PING and
|
||||||
|
found_ns.found == false %}
|
||||||
|
{% set found_ns.found = true %}
|
||||||
|
external-check
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
defaults
|
||||||
|
{% if connection_logging %}
|
||||||
|
log global
|
||||||
|
{% else %}
|
||||||
|
no log
|
||||||
|
{% endif %}
|
||||||
|
retries 3
|
||||||
|
option redispatch
|
||||||
|
option splice-request
|
||||||
|
option splice-response
|
||||||
|
option http-keep-alive
|
||||||
|
|
||||||
|
{% block peers %}{% endblock peers %}
|
||||||
|
|
||||||
|
{% block proxies %}{% endblock proxies %}
|
|
@ -0,0 +1,40 @@
|
||||||
|
{# Copyright (c) 2015 Rackspace
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#}
|
||||||
|
{% extends 'base.j2' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% from 'macros.j2' import frontend_macro, backend_macro %}
|
||||||
|
{% from 'macros.j2' import peers_macro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% set loadbalancer_id = loadbalancer.id %}
|
||||||
|
{% set sock_path = stats_sock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block peers %}
|
||||||
|
{{ peers_macro(constants, loadbalancer) }}
|
||||||
|
{% endblock peers %}
|
||||||
|
|
||||||
|
{% block proxies %}
|
||||||
|
{% if loadbalancer.enabled %}
|
||||||
|
{% for listener in loadbalancer.listeners if listener.enabled %}
|
||||||
|
{{- frontend_macro(constants, listener, loadbalancer.vip_address) }}
|
||||||
|
{% for pool in listener.pools if pool.enabled %}
|
||||||
|
{{- backend_macro(constants, listener, pool, loadbalancer) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock proxies %}
|
|
@ -0,0 +1,370 @@
|
||||||
|
{# Copyright (c) 2015 Rackspace
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#}
|
||||||
|
{% macro peers_macro(constants, loadbalancer) %}
|
||||||
|
{% if loadbalancer.topology == constants.TOPOLOGY_ACTIVE_STANDBY %}
|
||||||
|
peers {{ "%s_peers"|format(loadbalancer.id.replace("-", ""))|trim() }}
|
||||||
|
{% for amp in loadbalancer.amphorae if (
|
||||||
|
amp.status == constants.AMPHORA_ALLOCATED) %}
|
||||||
|
{# HAProxy has peer name limitations, thus the hash filter #}
|
||||||
|
peer {{ amp.id|hash_amp_id|replace('=', '') }} {{
|
||||||
|
amp.vrrp_ip }}:{{ constants.HAPROXY_BASE_PEER_PORT }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro bind_macro(constants, listener, lb_vip_address) %}
|
||||||
|
{% if listener.default_tls_path %}
|
||||||
|
{% set def_crt_opt = ("ssl crt %s"|format(
|
||||||
|
listener.default_tls_path)|trim()) %}
|
||||||
|
{% else %}
|
||||||
|
{% set def_crt_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.crt_dir %}
|
||||||
|
{% set crt_dir_opt = "crt %s"|format(listener.crt_dir)|trim() %}
|
||||||
|
{% else %}
|
||||||
|
{% set crt_dir_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.client_ca_tls_path and listener.client_auth %}
|
||||||
|
{% set client_ca_opt = "ca-file %s verify %s"|format(listener.client_ca_tls_path, listener.client_auth)|trim() %}
|
||||||
|
{% else %}
|
||||||
|
{% set client_ca_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.client_crl_path and listener.client_ca_tls_path %}
|
||||||
|
{% set ca_crl_opt = "crl-file %s"|format(listener.client_crl_path)|trim() %}
|
||||||
|
{% else %}
|
||||||
|
{% set ca_crl_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
|
||||||
|
"%s %s %s %s"|format(def_crt_opt, crt_dir_opt, client_ca_opt, ca_crl_opt)|trim() }}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro l7rule_compare_type_macro(constants, ctype) %}
|
||||||
|
{% if ctype == constants.L7RULE_COMPARE_TYPE_REGEX %}
|
||||||
|
{{- "-m reg" -}}
|
||||||
|
{% elif ctype == constants.L7RULE_COMPARE_TYPE_STARTS_WITH %}
|
||||||
|
{{- "-m beg" -}}
|
||||||
|
{% elif ctype == constants.L7RULE_COMPARE_TYPE_ENDS_WITH %}
|
||||||
|
{{- "-m end" -}}
|
||||||
|
{% elif ctype == constants.L7RULE_COMPARE_TYPE_CONTAINS %}
|
||||||
|
{{- "-m sub" -}}
|
||||||
|
{% elif ctype == constants.L7RULE_COMPARE_TYPE_EQUAL_TO %}
|
||||||
|
{{- "-m str" -}}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro l7rule_macro(constants, l7rule) %}
|
||||||
|
{% if l7rule.type == constants.L7RULE_TYPE_HOST_NAME %}
|
||||||
|
acl {{ l7rule.id }} req.hdr(host) -i {{ l7rule_compare_type_macro(
|
||||||
|
constants, l7rule.compare_type) }} {{ l7rule.value }}
|
||||||
|
{% elif l7rule.type == constants.L7RULE_TYPE_PATH %}
|
||||||
|
acl {{ l7rule.id }} path {{ l7rule_compare_type_macro(
|
||||||
|
constants, l7rule.compare_type) }} {{ l7rule.value }}
|
||||||
|
{% elif l7rule.type == constants.L7RULE_TYPE_FILE_TYPE %}
|
||||||
|
acl {{ l7rule.id }} path_end {{ l7rule_compare_type_macro(
|
||||||
|
constants, l7rule.compare_type) }} {{ l7rule.value }}
|
||||||
|
{% elif l7rule.type == constants.L7RULE_TYPE_HEADER %}
|
||||||
|
acl {{ l7rule.id }} req.hdr({{ l7rule.key }}) {{
|
||||||
|
l7rule_compare_type_macro(
|
||||||
|
constants, l7rule.compare_type) }} {{ l7rule.value }}
|
||||||
|
{% elif l7rule.type == constants.L7RULE_TYPE_COOKIE %}
|
||||||
|
acl {{ l7rule.id }} req.cook({{ l7rule.key }}) {{
|
||||||
|
l7rule_compare_type_macro(
|
||||||
|
constants, l7rule.compare_type) }} {{ l7rule.value }}
|
||||||
|
{% elif l7rule.type == constants.L7RULE_TYPE_SSL_CONN_HAS_CERT %}
|
||||||
|
acl {{ l7rule.id }} ssl_c_used
|
||||||
|
{% elif l7rule.type == constants.L7RULE_TYPE_SSL_VERIFY_RESULT %}
|
||||||
|
acl {{ l7rule.id }} ssl_c_verify eq {{ l7rule.value }}
|
||||||
|
{% elif l7rule.type == constants.L7RULE_TYPE_SSL_DN_FIELD %}
|
||||||
|
acl {{ l7rule.id }} ssl_c_s_dn({{ l7rule.key }}) {{
|
||||||
|
l7rule_compare_type_macro(
|
||||||
|
constants, l7rule.compare_type) }} {{ l7rule.value }}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro l7rule_invert_macro(invert) %}
|
||||||
|
{% if invert %}
|
||||||
|
{{- "!" -}}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro l7rule_list_macro(l7policy) %}
|
||||||
|
{% for l7rule in l7policy.l7rules %}
|
||||||
|
{{- " " -}}{{- l7rule_invert_macro(l7rule.invert) -}}{{- l7rule.id -}}
|
||||||
|
{% endfor %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro l7policy_macro(constants, l7policy, listener) %}
|
||||||
|
{% for l7rule in l7policy.l7rules %}
|
||||||
|
{{- l7rule_macro(constants, l7rule) -}}
|
||||||
|
{% endfor %}
|
||||||
|
{% if l7policy.redirect_http_code %}
|
||||||
|
{% set redirect_http_code_opt = " code %s"|format(
|
||||||
|
l7policy.redirect_http_code) %}
|
||||||
|
{% else %}
|
||||||
|
{% set redirect_http_code_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if l7policy.action == constants.L7POLICY_ACTION_REJECT %}
|
||||||
|
http-request deny if{{ l7rule_list_macro(l7policy) }}
|
||||||
|
{% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_TO_URL %}
|
||||||
|
redirect {{- redirect_http_code_opt }} location {{ l7policy.redirect_url }} if{{ l7rule_list_macro(l7policy) }}
|
||||||
|
{% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_TO_POOL and l7policy.redirect_pool.enabled %}
|
||||||
|
use_backend {{ l7policy.redirect_pool.id }}:{{ listener.id }} if{{ l7rule_list_macro(l7policy) }}
|
||||||
|
{% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_PREFIX %}
|
||||||
|
redirect {{- redirect_http_code_opt }} prefix {{ l7policy.redirect_prefix }} if{{ l7rule_list_macro(l7policy) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro frontend_macro(constants, listener, lb_vip_address) %}
|
||||||
|
frontend {{ listener.id }}
|
||||||
|
log-format {{ listener.user_log_format }}
|
||||||
|
{% if listener.connection_limit is defined %}
|
||||||
|
maxconn {{ listener.connection_limit }}
|
||||||
|
{% endif %}
|
||||||
|
{% if (listener.protocol.lower() ==
|
||||||
|
constants.PROTOCOL_TERMINATED_HTTPS.lower()) %}
|
||||||
|
redirect scheme https if !{ ssl_fc }
|
||||||
|
{% endif %}
|
||||||
|
{{ bind_macro(constants, listener, lb_vip_address)|trim() }}
|
||||||
|
mode {{ listener.protocol_mode }}
|
||||||
|
{% for l7policy in listener.l7policies if (l7policy.enabled and
|
||||||
|
l7policy.l7rules|length > 0) %}
|
||||||
|
{{- l7policy_macro(constants, l7policy, listener) -}}
|
||||||
|
{% endfor %}
|
||||||
|
{% if listener.default_pool and listener.default_pool.enabled %}
|
||||||
|
default_backend {{ listener.default_pool.id }}:{{ listener.id }}
|
||||||
|
{% endif %}
|
||||||
|
timeout client {{ listener.timeout_client_data }}
|
||||||
|
{% if listener.timeout_tcp_inspect %}
|
||||||
|
tcp-request inspect-delay {{ listener.timeout_tcp_inspect }}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro member_macro(constants, pool, member) %}
|
||||||
|
{% if pool.health_monitor and pool.health_monitor.enabled %}
|
||||||
|
{% if member.monitor_address %}
|
||||||
|
{% set monitor_addr_opt = " addr %s"|format(member.monitor_address) %}
|
||||||
|
{% else %}
|
||||||
|
{% set monitor_addr_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if member.monitor_port %}
|
||||||
|
{% set monitor_port_opt = " port %s"|format(member.monitor_port) %}
|
||||||
|
{% else %}
|
||||||
|
{% set monitor_port_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.health_monitor.type == constants.HEALTH_MONITOR_HTTPS %}
|
||||||
|
{% set monitor_ssl_opt = " check-ssl verify none" %}
|
||||||
|
{% else %}
|
||||||
|
{% set monitor_ssl_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% set hm_opt = " check%s inter %ds fall %d rise %d%s%s"|format(
|
||||||
|
monitor_ssl_opt, pool.health_monitor.delay,
|
||||||
|
pool.health_monitor.fall_threshold,
|
||||||
|
pool.health_monitor.rise_threshold, monitor_addr_opt,
|
||||||
|
monitor_port_opt) %}
|
||||||
|
{% else %}
|
||||||
|
{% set hm_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if (pool.session_persistence.type ==
|
||||||
|
constants.SESSION_PERSISTENCE_HTTP_COOKIE) %}
|
||||||
|
{% set persistence_opt = " cookie %s"|format(member.id) %}
|
||||||
|
{% else %}
|
||||||
|
{% set persistence_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.proxy_protocol %}
|
||||||
|
{% set proxy_protocol_opt = " send-proxy" %}
|
||||||
|
{% else %}
|
||||||
|
{% set proxy_protocol_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if member.backup %}
|
||||||
|
{% set member_backup_opt = " backup" %}
|
||||||
|
{% else %}
|
||||||
|
{% set member_backup_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if member.enabled %}
|
||||||
|
{% set member_enabled_opt = "" %}
|
||||||
|
{% else %}
|
||||||
|
{% set member_enabled_opt = " disabled" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.tls_enabled %}
|
||||||
|
{% set def_opt_prefix = " ssl" %}
|
||||||
|
{% set def_sni_opt = " sni ssl_fc_sni" %}
|
||||||
|
{% else %}
|
||||||
|
{% set def_opt_prefix = "" %}
|
||||||
|
{% set def_sni_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.client_cert and pool.tls_enabled %}
|
||||||
|
{% set def_crt_opt = " crt %s"|format(pool.client_cert) %}
|
||||||
|
{% else %}
|
||||||
|
{% set def_crt_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.ca_cert and pool.tls_enabled %}
|
||||||
|
{% set ca_opt = " ca-file %s"|format(pool.ca_cert) %}
|
||||||
|
{% set def_verify_opt = " verify required" %}
|
||||||
|
{% if pool.crl %}
|
||||||
|
{% set crl_opt = " crl-file %s"|format(pool.crl) %}
|
||||||
|
{% else %}
|
||||||
|
{% set def_verify_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
|
{% elif pool.tls_enabled %}
|
||||||
|
{% set def_verify_opt = " verify none" %}
|
||||||
|
{% endif %}
|
||||||
|
{{ "server %s %s:%d weight %s%s%s%s%s%s%s%s%s%s%s%s"|e|format(
|
||||||
|
member.id, member.address, member.protocol_port, member.weight,
|
||||||
|
hm_opt, persistence_opt, proxy_protocol_opt, member_backup_opt,
|
||||||
|
member_enabled_opt, def_opt_prefix, def_crt_opt, ca_opt, crl_opt,
|
||||||
|
def_verify_opt, def_sni_opt)|trim() }}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro backend_macro(constants, listener, pool, loadbalancer) %}
|
||||||
|
backend {{ pool.id }}:{{ listener.id }}
|
||||||
|
{% if pool.protocol.lower() == constants.PROTOCOL_PROXY.lower() %}
|
||||||
|
mode {{ listener.protocol_mode }}
|
||||||
|
{% else %}
|
||||||
|
mode {{ pool.protocol }}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.get(constants.HTTP_REUSE, False) and (
|
||||||
|
pool.protocol.lower() == constants.PROTOCOL_HTTP.lower() or
|
||||||
|
(pool.protocol.lower() == constants.PROTOCOL_PROXY.lower() and
|
||||||
|
listener.protocol_mode.lower() ==
|
||||||
|
constants.PROTOCOL_HTTP.lower()))%}
|
||||||
|
http-reuse safe
|
||||||
|
{% endif %}
|
||||||
|
balance {{ pool.lb_algorithm }}
|
||||||
|
{% if pool.session_persistence %}
|
||||||
|
{% if (pool.session_persistence.type ==
|
||||||
|
constants.SESSION_PERSISTENCE_SOURCE_IP) %}
|
||||||
|
{% if loadbalancer.topology == constants.TOPOLOGY_ACTIVE_STANDBY %}
|
||||||
|
stick-table type ip size {{ pool.stick_size }} peers {{
|
||||||
|
"%s_peers"|format(loadbalancer.id.replace("-", ""))|trim() }}
|
||||||
|
{% else %}
|
||||||
|
stick-table type ip size {{ pool.stick_size }}
|
||||||
|
{% endif %}
|
||||||
|
stick on src
|
||||||
|
{% elif (pool.session_persistence.type ==
|
||||||
|
constants.SESSION_PERSISTENCE_APP_COOKIE) %}
|
||||||
|
{% if loadbalancer.topology == constants.TOPOLOGY_ACTIVE_STANDBY %}
|
||||||
|
stick-table type string len 64 size {{
|
||||||
|
pool.stick_size }} peers {{
|
||||||
|
"%s_peers"|format(loadbalancer.id.replace("-", ""))|trim() }}
|
||||||
|
{% else %}
|
||||||
|
stick-table type string len 64 size {{ pool.stick_size }}
|
||||||
|
{% endif %}
|
||||||
|
stick store-response res.cook({{ pool.session_persistence.cookie_name }})
|
||||||
|
stick match req.cook({{ pool.session_persistence.cookie_name }})
|
||||||
|
{% elif (pool.session_persistence.type ==
|
||||||
|
constants.SESSION_PERSISTENCE_HTTP_COOKIE) %}
|
||||||
|
cookie SRV insert indirect nocache
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.health_monitor and pool.health_monitor.enabled %}
|
||||||
|
timeout check {{ pool.health_monitor.timeout }}s
|
||||||
|
{% if (pool.health_monitor.type ==
|
||||||
|
constants.HEALTH_MONITOR_HTTP or pool.health_monitor.type ==
|
||||||
|
constants.HEALTH_MONITOR_HTTPS) %}
|
||||||
|
{% if (pool.health_monitor.http_version and
|
||||||
|
pool.health_monitor.http_version == 1.1 and
|
||||||
|
pool.health_monitor.domain_name) %}
|
||||||
|
option httpchk {{ pool.health_monitor.http_method }} {{ pool.health_monitor.url_path }} HTTP/
|
||||||
|
{{- pool.health_monitor.http_version -}}{{- "\\r\\n" | safe -}}
|
||||||
|
Host:\ {{ pool.health_monitor.domain_name }}
|
||||||
|
{% elif pool.health_monitor.http_version %}
|
||||||
|
option httpchk {{ pool.health_monitor.http_method }} {{ pool.health_monitor.url_path }} HTTP/
|
||||||
|
{{- pool.health_monitor.http_version -}}{{- "\\r\\n" | safe }}
|
||||||
|
{% else %}
|
||||||
|
option httpchk {{ pool.health_monitor.http_method }} {{ pool.health_monitor.url_path }}
|
||||||
|
{% endif %}
|
||||||
|
http-check expect rstatus {{ pool.health_monitor.expected_codes }}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.health_monitor.type == constants.HEALTH_MONITOR_TLS_HELLO %}
|
||||||
|
option ssl-hello-chk
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.health_monitor.type == constants.HEALTH_MONITOR_PING %}
|
||||||
|
option external-check
|
||||||
|
external-check command /var/lib/octavia/ping-wrapper.sh
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if pool.protocol.lower() == constants.PROTOCOL_HTTP.lower() %}
|
||||||
|
{% if listener.insert_headers.get('X-Forwarded-For',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
option forwardfor
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-Forwarded-Port',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-Forwarded-Proto',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
{% if listener.protocol.lower() == constants.PROTOCOL_HTTP.lower() %}
|
||||||
|
http-request set-header X-Forwarded-Proto http
|
||||||
|
{% elif listener.protocol.lower() ==
|
||||||
|
constants.PROTOCOL_TERMINATED_HTTPS.lower() %}
|
||||||
|
http-request set-header X-Forwarded-Proto https
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.protocol.lower() == constants.PROTOCOL_TERMINATED_HTTPS.lower() %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Client-Verify',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Client-Verify %[ssl_c_verify]
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Client-Has-Cert',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Client-Has-Cert %[ssl_c_used]
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Client-DN',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Client-DN %{+Q}[ssl_c_s_dn]
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Client-CN',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Client-CN %{+Q}[ssl_c_s_dn(cn)]
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Issuer',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Issuer %{+Q}[ssl_c_i_dn]
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Client-SHA1',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Client-SHA1 %{+Q}[ssl_c_sha1,hex]
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Client-Not-Before',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Client-Not-Before %{+Q}[ssl_c_notbefore]
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-SSL-Client-Not-After',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-SSL-Client-Not-After %{+Q}[ssl_c_notafter]
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.connection_limit is defined %}
|
||||||
|
fullconn {{ listener.connection_limit }}
|
||||||
|
{% endif %}
|
||||||
|
option allbackups
|
||||||
|
timeout connect {{ listener.timeout_member_connect }}
|
||||||
|
timeout server {{ listener.timeout_member_data }}
|
||||||
|
{% for member in pool.members %}
|
||||||
|
{{- member_macro(constants, pool, member) -}}
|
||||||
|
{% endfor %}
|
||||||
|
{% endmacro %}
|
|
@ -110,7 +110,7 @@ class UpdateHealthDb(update_base.HealthUpdateBase):
|
||||||
:type map: string
|
:type map: string
|
||||||
:returns: null
|
:returns: null
|
||||||
|
|
||||||
The input health data structure is shown as below::
|
The input v1 health data structure is shown as below::
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
@ -125,6 +125,33 @@ class UpdateHealthDb(update_base.HealthUpdateBase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Example V2 message::
|
||||||
|
|
||||||
|
{"id": "<amphora_id>",
|
||||||
|
"seq": 67,
|
||||||
|
"listeners": {
|
||||||
|
"<listener_id>": {
|
||||||
|
"status": "OPEN",
|
||||||
|
"stats": {
|
||||||
|
"tx": 0,
|
||||||
|
"rx": 0,
|
||||||
|
"conns": 0,
|
||||||
|
"totconns": 0,
|
||||||
|
"ereq": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pools": {
|
||||||
|
"<pool_id>:<listener_id>": {
|
||||||
|
"status": "UP",
|
||||||
|
"members": {
|
||||||
|
"<member_id>": "no check"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ver": 2
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
session = db_api.get_session()
|
session = db_api.get_session()
|
||||||
|
|
||||||
|
@ -134,10 +161,15 @@ class UpdateHealthDb(update_base.HealthUpdateBase):
|
||||||
ignore_listener_count = False
|
ignore_listener_count = False
|
||||||
|
|
||||||
if db_lb:
|
if db_lb:
|
||||||
expected_listener_count = len(db_lb.get('listeners', {}))
|
expected_listener_count = 0
|
||||||
if 'PENDING' in db_lb['provisioning_status']:
|
if 'PENDING' in db_lb['provisioning_status']:
|
||||||
ignore_listener_count = True
|
ignore_listener_count = True
|
||||||
else:
|
else:
|
||||||
|
for key, listener in db_lb.get('listeners', {}).items():
|
||||||
|
# disabled listeners don't report from the amphora
|
||||||
|
if listener['enabled']:
|
||||||
|
expected_listener_count += 1
|
||||||
|
|
||||||
# If this is a heartbeat older than versioning, handle
|
# If this is a heartbeat older than versioning, handle
|
||||||
# UDP special for backward compatibility.
|
# UDP special for backward compatibility.
|
||||||
if 'ver' not in health:
|
if 'ver' not in health:
|
||||||
|
@ -231,6 +263,8 @@ class UpdateHealthDb(update_base.HealthUpdateBase):
|
||||||
else:
|
else:
|
||||||
lb_status = constants.ONLINE
|
lb_status = constants.ONLINE
|
||||||
|
|
||||||
|
health_msg_version = health.get('ver', 0)
|
||||||
|
|
||||||
for listener_id in db_lb.get('listeners', {}):
|
for listener_id in db_lb.get('listeners', {}):
|
||||||
db_op_status = db_lb['listeners'][listener_id]['operating_status']
|
db_op_status = db_lb['listeners'][listener_id]['operating_status']
|
||||||
listener_status = None
|
listener_status = None
|
||||||
|
@ -267,11 +301,36 @@ class UpdateHealthDb(update_base.HealthUpdateBase):
|
||||||
if not listener:
|
if not listener:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
pools = listener['pools']
|
if health_msg_version < 2:
|
||||||
|
raw_pools = listener['pools']
|
||||||
|
|
||||||
|
# normalize the pool IDs. Single process listener pools
|
||||||
|
# have the listener id appended with an ':' seperator.
|
||||||
|
# Old multi-process listener pools only have a pool ID.
|
||||||
|
# This makes sure the keys are only pool IDs.
|
||||||
|
pools = {(k + ' ')[:k.rfind(':')]: v for k, v in
|
||||||
|
raw_pools.items()}
|
||||||
|
|
||||||
|
for db_pool_id in db_lb.get('pools', {}):
|
||||||
|
# If we saw this pool already on another listener, skip it.
|
||||||
|
if db_pool_id in processed_pools:
|
||||||
|
continue
|
||||||
|
db_pool_dict = db_lb['pools'][db_pool_id]
|
||||||
|
lb_status = self._process_pool_status(
|
||||||
|
session, db_pool_id, db_pool_dict, pools,
|
||||||
|
lb_status, processed_pools, potential_offline_pools)
|
||||||
|
|
||||||
|
if health_msg_version >= 2:
|
||||||
|
raw_pools = health['pools']
|
||||||
|
|
||||||
|
# normalize the pool IDs. Single process listener pools
|
||||||
|
# have the listener id appended with an ':' seperator.
|
||||||
|
# Old multi-process listener pools only have a pool ID.
|
||||||
|
# This makes sure the keys are only pool IDs.
|
||||||
|
pools = {(k + ' ')[:k.rfind(':')]: v for k, v in raw_pools.items()}
|
||||||
|
|
||||||
for db_pool_id in db_lb.get('pools', {}):
|
for db_pool_id in db_lb.get('pools', {}):
|
||||||
# If we saw this pool already on another listener
|
# If we saw this pool already, skip it.
|
||||||
# skip it.
|
|
||||||
if db_pool_id in processed_pools:
|
if db_pool_id in processed_pools:
|
||||||
continue
|
continue
|
||||||
db_pool_dict = db_lb['pools'][db_pool_id]
|
db_pool_dict = db_lb['pools'][db_pool_id]
|
||||||
|
@ -416,7 +475,7 @@ class UpdateStatsDb(update_base.StatsUpdateBase, stats.StatsMixin):
|
||||||
:type map: string
|
:type map: string
|
||||||
:returns: null
|
:returns: null
|
||||||
|
|
||||||
Example::
|
Example V1 message::
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
@ -440,6 +499,33 @@ class UpdateStatsDb(update_base.StatsUpdateBase, stats.StatsMixin):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Example V2 message::
|
||||||
|
|
||||||
|
{"id": "<amphora_id>",
|
||||||
|
"seq": 67,
|
||||||
|
"listeners": {
|
||||||
|
"<listener_id>": {
|
||||||
|
"status": "OPEN",
|
||||||
|
"stats": {
|
||||||
|
"tx": 0,
|
||||||
|
"rx": 0,
|
||||||
|
"conns": 0,
|
||||||
|
"totconns": 0,
|
||||||
|
"ereq": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pools": {
|
||||||
|
"<pool_id>:<listener_id>": {
|
||||||
|
"status": "UP",
|
||||||
|
"members": {
|
||||||
|
"<member_id>": "no check"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ver": 2
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
session = db_api.get_session()
|
session = db_api.get_session()
|
||||||
|
|
||||||
|
|
|
@ -235,13 +235,14 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
|
||||||
raise db_exceptions.NoResultFound
|
raise db_exceptions.NoResultFound
|
||||||
|
|
||||||
load_balancer = listener.load_balancer
|
load_balancer = listener.load_balancer
|
||||||
|
listeners = load_balancer.listeners
|
||||||
|
|
||||||
create_listener_tf = self._taskflow_load(self._listener_flows.
|
create_listener_tf = self._taskflow_load(self._listener_flows.
|
||||||
get_create_listener_flow(),
|
get_create_listener_flow(),
|
||||||
store={constants.LOADBALANCER:
|
store={constants.LOADBALANCER:
|
||||||
load_balancer,
|
load_balancer,
|
||||||
constants.LISTENERS:
|
constants.LISTENERS:
|
||||||
[listener]})
|
listeners})
|
||||||
with tf_logging.DynamicLoggingListener(create_listener_tf,
|
with tf_logging.DynamicLoggingListener(create_listener_tf,
|
||||||
log=LOG):
|
log=LOG):
|
||||||
create_listener_tf.run()
|
create_listener_tf.run()
|
||||||
|
|
|
@ -470,7 +470,7 @@ class AmphoraFlows(object):
|
||||||
update_amps_subflow.add(
|
update_amps_subflow.add(
|
||||||
amphora_driver_tasks.AmpListenersUpdate(
|
amphora_driver_tasks.AmpListenersUpdate(
|
||||||
name=constants.AMP_LISTENER_UPDATE + '-' + str(amp_index),
|
name=constants.AMP_LISTENER_UPDATE + '-' + str(amp_index),
|
||||||
requires=(constants.LISTENERS, constants.AMPHORAE),
|
requires=(constants.LOADBALANCER, constants.AMPHORAE),
|
||||||
inject={constants.AMPHORA_INDEX: amp_index,
|
inject={constants.AMPHORA_INDEX: amp_index,
|
||||||
constants.TIMEOUT_DICT: timeout_dict}))
|
constants.TIMEOUT_DICT: timeout_dict}))
|
||||||
amp_index += 1
|
amp_index += 1
|
||||||
|
@ -514,8 +514,7 @@ class AmphoraFlows(object):
|
||||||
requires=constants.AMPHORA))
|
requires=constants.AMPHORA))
|
||||||
|
|
||||||
failover_amphora_flow.add(amphora_driver_tasks.ListenersStart(
|
failover_amphora_flow.add(amphora_driver_tasks.ListenersStart(
|
||||||
requires=(constants.LOADBALANCER, constants.LISTENERS,
|
requires=(constants.LOADBALANCER, constants.AMPHORA)))
|
||||||
constants.AMPHORA)))
|
|
||||||
failover_amphora_flow.add(
|
failover_amphora_flow.add(
|
||||||
database_tasks.DisableAmphoraHealthMonitoring(
|
database_tasks.DisableAmphoraHealthMonitoring(
|
||||||
rebind={constants.AMPHORA: constants.FAILED_AMPHORA},
|
rebind={constants.AMPHORA: constants.FAILED_AMPHORA},
|
||||||
|
|
|
@ -37,7 +37,7 @@ class HealthMonitorFlows(object):
|
||||||
create_hm_flow.add(database_tasks.MarkHealthMonitorPendingCreateInDB(
|
create_hm_flow.add(database_tasks.MarkHealthMonitorPendingCreateInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
create_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
create_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
create_hm_flow.add(database_tasks.MarkPoolActiveInDB(
|
create_hm_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
@ -63,7 +63,7 @@ class HealthMonitorFlows(object):
|
||||||
DeleteModelObject(rebind={constants.OBJECT:
|
DeleteModelObject(rebind={constants.OBJECT:
|
||||||
constants.HEALTH_MON}))
|
constants.HEALTH_MON}))
|
||||||
delete_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_hm_flow.add(database_tasks.DeleteHealthMonitorInDB(
|
delete_hm_flow.add(database_tasks.DeleteHealthMonitorInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
delete_hm_flow.add(database_tasks.DecrementHealthMonitorQuota(
|
delete_hm_flow.add(database_tasks.DecrementHealthMonitorQuota(
|
||||||
|
@ -92,7 +92,7 @@ class HealthMonitorFlows(object):
|
||||||
update_hm_flow.add(database_tasks.MarkHealthMonitorPendingUpdateInDB(
|
update_hm_flow.add(database_tasks.MarkHealthMonitorPendingUpdateInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
update_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_hm_flow.add(database_tasks.UpdateHealthMonInDB(
|
update_hm_flow.add(database_tasks.UpdateHealthMonInDB(
|
||||||
requires=[constants.HEALTH_MON, constants.UPDATE_DICT]))
|
requires=[constants.HEALTH_MON, constants.UPDATE_DICT]))
|
||||||
update_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
update_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
||||||
|
|
|
@ -37,7 +37,7 @@ class L7PolicyFlows(object):
|
||||||
create_l7policy_flow.add(database_tasks.MarkL7PolicyPendingCreateInDB(
|
create_l7policy_flow.add(database_tasks.MarkL7PolicyPendingCreateInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
create_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
create_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
create_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
create_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
||||||
|
@ -60,7 +60,7 @@ class L7PolicyFlows(object):
|
||||||
delete_l7policy_flow.add(model_tasks.DeleteModelObject(
|
delete_l7policy_flow.add(model_tasks.DeleteModelObject(
|
||||||
rebind={constants.OBJECT: constants.L7POLICY}))
|
rebind={constants.OBJECT: constants.L7POLICY}))
|
||||||
delete_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB(
|
delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
||||||
|
@ -81,7 +81,7 @@ class L7PolicyFlows(object):
|
||||||
update_l7policy_flow.add(database_tasks.MarkL7PolicyPendingUpdateInDB(
|
update_l7policy_flow.add(database_tasks.MarkL7PolicyPendingUpdateInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
update_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_l7policy_flow.add(database_tasks.UpdateL7PolicyInDB(
|
update_l7policy_flow.add(database_tasks.UpdateL7PolicyInDB(
|
||||||
requires=[constants.L7POLICY, constants.UPDATE_DICT]))
|
requires=[constants.L7POLICY, constants.UPDATE_DICT]))
|
||||||
update_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
update_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
|
|
|
@ -37,7 +37,7 @@ class L7RuleFlows(object):
|
||||||
create_l7rule_flow.add(database_tasks.MarkL7RulePendingCreateInDB(
|
create_l7rule_flow.add(database_tasks.MarkL7RulePendingCreateInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
create_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
create_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
create_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
create_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
|
@ -62,7 +62,7 @@ class L7RuleFlows(object):
|
||||||
delete_l7rule_flow.add(model_tasks.DeleteModelObject(
|
delete_l7rule_flow.add(model_tasks.DeleteModelObject(
|
||||||
rebind={constants.OBJECT: constants.L7RULE}))
|
rebind={constants.OBJECT: constants.L7RULE}))
|
||||||
delete_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB(
|
delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
|
@ -85,7 +85,7 @@ class L7RuleFlows(object):
|
||||||
update_l7rule_flow.add(database_tasks.MarkL7RulePendingUpdateInDB(
|
update_l7rule_flow.add(database_tasks.MarkL7RulePendingUpdateInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
update_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_l7rule_flow.add(database_tasks.UpdateL7RuleInDB(
|
update_l7rule_flow.add(database_tasks.UpdateL7RuleInDB(
|
||||||
requires=[constants.L7RULE, constants.UPDATE_DICT]))
|
requires=[constants.L7RULE, constants.UPDATE_DICT]))
|
||||||
update_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
update_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
||||||
|
|
|
@ -33,7 +33,7 @@ class ListenerFlows(object):
|
||||||
create_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
create_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
||||||
create_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_listener_flow.add(network_tasks.UpdateVIP(
|
create_listener_flow.add(network_tasks.UpdateVIP(
|
||||||
requires=constants.LOADBALANCER))
|
requires=constants.LOADBALANCER))
|
||||||
create_listener_flow.add(database_tasks.
|
create_listener_flow.add(database_tasks.
|
||||||
|
@ -57,7 +57,7 @@ class ListenerFlows(object):
|
||||||
requires=constants.LOADBALANCER_ID,
|
requires=constants.LOADBALANCER_ID,
|
||||||
provides=constants.LOADBALANCER))
|
provides=constants.LOADBALANCER))
|
||||||
create_all_listeners_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_all_listeners_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_all_listeners_flow.add(network_tasks.UpdateVIP(
|
create_all_listeners_flow.add(network_tasks.UpdateVIP(
|
||||||
requires=constants.LOADBALANCER))
|
requires=constants.LOADBALANCER))
|
||||||
return create_all_listeners_flow
|
return create_all_listeners_flow
|
||||||
|
@ -71,7 +71,7 @@ class ListenerFlows(object):
|
||||||
delete_listener_flow.add(lifecycle_tasks.ListenerToErrorOnRevertTask(
|
delete_listener_flow.add(lifecycle_tasks.ListenerToErrorOnRevertTask(
|
||||||
requires=constants.LISTENER))
|
requires=constants.LISTENER))
|
||||||
delete_listener_flow.add(amphora_driver_tasks.ListenerDelete(
|
delete_listener_flow.add(amphora_driver_tasks.ListenerDelete(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENER]))
|
requires=constants.LISTENER))
|
||||||
delete_listener_flow.add(network_tasks.UpdateVIPForDelete(
|
delete_listener_flow.add(network_tasks.UpdateVIPForDelete(
|
||||||
requires=constants.LOADBALANCER))
|
requires=constants.LOADBALANCER))
|
||||||
delete_listener_flow.add(database_tasks.DeleteListenerInDB(
|
delete_listener_flow.add(database_tasks.DeleteListenerInDB(
|
||||||
|
@ -115,7 +115,7 @@ class ListenerFlows(object):
|
||||||
update_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
update_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
||||||
update_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_listener_flow.add(database_tasks.UpdateListenerInDB(
|
update_listener_flow.add(database_tasks.UpdateListenerInDB(
|
||||||
requires=[constants.LISTENER, constants.UPDATE_DICT]))
|
requires=[constants.LISTENER, constants.UPDATE_DICT]))
|
||||||
update_listener_flow.add(database_tasks.
|
update_listener_flow.add(database_tasks.
|
||||||
|
|
|
@ -332,7 +332,7 @@ class LoadBalancerFlows(object):
|
||||||
update_LB_flow.add(network_tasks.ApplyQos(
|
update_LB_flow.add(network_tasks.ApplyQos(
|
||||||
requires=(constants.LOADBALANCER, constants.UPDATE_DICT)))
|
requires=(constants.LOADBALANCER, constants.UPDATE_DICT)))
|
||||||
update_LB_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_LB_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_LB_flow.add(database_tasks.UpdateLoadbalancerInDB(
|
update_LB_flow.add(database_tasks.UpdateLoadbalancerInDB(
|
||||||
requires=[constants.LOADBALANCER, constants.UPDATE_DICT]))
|
requires=[constants.LOADBALANCER, constants.UPDATE_DICT]))
|
||||||
update_LB_flow.add(database_tasks.MarkLBActiveInDB(
|
update_LB_flow.add(database_tasks.MarkLBActiveInDB(
|
||||||
|
|
|
@ -48,7 +48,7 @@ class MemberFlows(object):
|
||||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
||||||
))
|
))
|
||||||
create_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=(constants.LOADBALANCER, constants.LISTENERS)))
|
requires=constants.LOADBALANCER))
|
||||||
create_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
create_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
create_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
create_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
@ -79,7 +79,7 @@ class MemberFlows(object):
|
||||||
delete_member_flow.add(database_tasks.DeleteMemberInDB(
|
delete_member_flow.add(database_tasks.DeleteMemberInDB(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
delete_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_member_flow.add(database_tasks.DecrementMemberQuota(
|
delete_member_flow.add(database_tasks.DecrementMemberQuota(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
delete_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
delete_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
@ -105,7 +105,7 @@ class MemberFlows(object):
|
||||||
update_member_flow.add(database_tasks.MarkMemberPendingUpdateInDB(
|
update_member_flow.add(database_tasks.MarkMemberPendingUpdateInDB(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
update_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_member_flow.add(database_tasks.UpdateMemberInDB(
|
update_member_flow.add(database_tasks.UpdateMemberInDB(
|
||||||
requires=[constants.MEMBER, constants.UPDATE_DICT]))
|
requires=[constants.MEMBER, constants.UPDATE_DICT]))
|
||||||
update_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
update_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
||||||
|
@ -195,7 +195,7 @@ class MemberFlows(object):
|
||||||
|
|
||||||
# Update the Listener (this makes the changes active on the Amp)
|
# Update the Listener (this makes the changes active on the Amp)
|
||||||
batch_update_members_flow.add(amphora_driver_tasks.ListenersUpdate(
|
batch_update_members_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=(constants.LOADBALANCER, constants.LISTENERS)))
|
requires=constants.LOADBALANCER))
|
||||||
|
|
||||||
# Mark all the members ACTIVE here, then pool then LB/Listeners
|
# Mark all the members ACTIVE here, then pool then LB/Listeners
|
||||||
batch_update_members_flow.add(unordered_members_active_flow)
|
batch_update_members_flow.add(unordered_members_active_flow)
|
||||||
|
|
|
@ -37,7 +37,7 @@ class PoolFlows(object):
|
||||||
create_pool_flow.add(database_tasks.MarkPoolPendingCreateInDB(
|
create_pool_flow.add(database_tasks.MarkPoolPendingCreateInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
create_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
create_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
create_pool_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
create_pool_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
||||||
|
@ -62,7 +62,7 @@ class PoolFlows(object):
|
||||||
delete_pool_flow.add(model_tasks.DeleteModelObject(
|
delete_pool_flow.add(model_tasks.DeleteModelObject(
|
||||||
rebind={constants.OBJECT: constants.POOL}))
|
rebind={constants.OBJECT: constants.POOL}))
|
||||||
delete_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_pool_flow.add(database_tasks.DeletePoolInDB(
|
delete_pool_flow.add(database_tasks.DeletePoolInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
delete_pool_flow.add(database_tasks.DecrementPoolQuota(
|
delete_pool_flow.add(database_tasks.DecrementPoolQuota(
|
||||||
|
@ -116,7 +116,7 @@ class PoolFlows(object):
|
||||||
update_pool_flow.add(database_tasks.MarkPoolPendingUpdateInDB(
|
update_pool_flow.add(database_tasks.MarkPoolPendingUpdateInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
update_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_pool_flow.add(database_tasks.UpdatePoolInDB(
|
update_pool_flow.add(database_tasks.UpdatePoolInDB(
|
||||||
requires=[constants.POOL, constants.UPDATE_DICT]))
|
requires=[constants.POOL, constants.UPDATE_DICT]))
|
||||||
update_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
update_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
|
|
@ -52,13 +52,13 @@ class BaseAmphoraTask(task.Task):
|
||||||
class AmpListenersUpdate(BaseAmphoraTask):
|
class AmpListenersUpdate(BaseAmphoraTask):
|
||||||
"""Task to update the listeners on one amphora."""
|
"""Task to update the listeners on one amphora."""
|
||||||
|
|
||||||
def execute(self, listeners, amphora_index, amphorae, timeout_dict=()):
|
def execute(self, loadbalancer, amphora_index, amphorae, timeout_dict=()):
|
||||||
# Note, we don't want this to cause a revert as it may be used
|
# Note, we don't want this to cause a revert as it may be used
|
||||||
# in a failover flow with both amps failing. Skip it and let
|
# in a failover flow with both amps failing. Skip it and let
|
||||||
# health manager fix it.
|
# health manager fix it.
|
||||||
try:
|
try:
|
||||||
self.amphora_driver.update_amphora_listeners(
|
self.amphora_driver.update_amphora_listeners(
|
||||||
listeners, amphora_index, amphorae, timeout_dict)
|
loadbalancer, amphorae[amphora_index], timeout_dict)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
amphora_id = amphorae[amphora_index].id
|
amphora_id = amphorae[amphora_index].id
|
||||||
LOG.error('Failed to update listeners on amphora %s. Skipping '
|
LOG.error('Failed to update listeners on amphora %s. Skipping '
|
||||||
|
@ -71,11 +71,9 @@ class AmpListenersUpdate(BaseAmphoraTask):
|
||||||
class ListenersUpdate(BaseAmphoraTask):
|
class ListenersUpdate(BaseAmphoraTask):
|
||||||
"""Task to update amphora with all specified listeners' configurations."""
|
"""Task to update amphora with all specified listeners' configurations."""
|
||||||
|
|
||||||
def execute(self, loadbalancer, listeners):
|
def execute(self, loadbalancer):
|
||||||
"""Execute updates per listener for an amphora."""
|
"""Execute updates per listener for an amphora."""
|
||||||
for listener in listeners:
|
self.amphora_driver.update(loadbalancer)
|
||||||
listener.load_balancer = loadbalancer
|
|
||||||
self.amphora_driver.update(listener, loadbalancer.vip)
|
|
||||||
|
|
||||||
def revert(self, loadbalancer, *args, **kwargs):
|
def revert(self, loadbalancer, *args, **kwargs):
|
||||||
"""Handle failed listeners updates."""
|
"""Handle failed listeners updates."""
|
||||||
|
@ -86,61 +84,30 @@ class ListenersUpdate(BaseAmphoraTask):
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
self.task_utils.mark_listener_prov_status_error(listener.id)
|
||||||
|
|
||||||
|
|
||||||
class ListenerStop(BaseAmphoraTask):
|
|
||||||
"""Task to stop the listener on the vip."""
|
|
||||||
|
|
||||||
def execute(self, loadbalancer, listener):
|
|
||||||
"""Execute listener stop routines for an amphora."""
|
|
||||||
self.amphora_driver.stop(listener, loadbalancer.vip)
|
|
||||||
LOG.debug("Stopped the listener on the vip")
|
|
||||||
|
|
||||||
def revert(self, listener, *args, **kwargs):
|
|
||||||
"""Handle a failed listener stop."""
|
|
||||||
|
|
||||||
LOG.warning("Reverting listener stop.")
|
|
||||||
|
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
|
||||||
|
|
||||||
|
|
||||||
class ListenerStart(BaseAmphoraTask):
|
|
||||||
"""Task to start the listener on the vip."""
|
|
||||||
|
|
||||||
def execute(self, loadbalancer, listener):
|
|
||||||
"""Execute listener start routines for an amphora."""
|
|
||||||
self.amphora_driver.start(listener, loadbalancer.vip)
|
|
||||||
LOG.debug("Started the listener on the vip")
|
|
||||||
|
|
||||||
def revert(self, listener, *args, **kwargs):
|
|
||||||
"""Handle a failed listener start."""
|
|
||||||
|
|
||||||
LOG.warning("Reverting listener start.")
|
|
||||||
|
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
|
||||||
|
|
||||||
|
|
||||||
class ListenersStart(BaseAmphoraTask):
|
class ListenersStart(BaseAmphoraTask):
|
||||||
"""Task to start all listeners on the vip."""
|
"""Task to start all listeners on the vip."""
|
||||||
|
|
||||||
def execute(self, loadbalancer, listeners, amphora=None):
|
def execute(self, loadbalancer, amphora=None):
|
||||||
"""Execute listener start routines for listeners on an amphora."""
|
"""Execute listener start routines for listeners on an amphora."""
|
||||||
for listener in listeners:
|
if loadbalancer.listeners:
|
||||||
self.amphora_driver.start(listener, loadbalancer.vip, amphora)
|
self.amphora_driver.start(loadbalancer, amphora)
|
||||||
LOG.debug("Started the listeners on the vip")
|
LOG.debug("Started the listeners on the vip")
|
||||||
|
|
||||||
def revert(self, listeners, *args, **kwargs):
|
def revert(self, loadbalancer, *args, **kwargs):
|
||||||
"""Handle failed listeners starts."""
|
"""Handle failed listeners starts."""
|
||||||
|
|
||||||
LOG.warning("Reverting listeners starts.")
|
LOG.warning("Reverting listeners starts.")
|
||||||
for listener in listeners:
|
for listener in loadbalancer.listeners:
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
self.task_utils.mark_listener_prov_status_error(listener.id)
|
||||||
|
|
||||||
|
|
||||||
class ListenerDelete(BaseAmphoraTask):
|
class ListenerDelete(BaseAmphoraTask):
|
||||||
"""Task to delete the listener on the vip."""
|
"""Task to delete the listener on the vip."""
|
||||||
|
|
||||||
def execute(self, loadbalancer, listener):
|
def execute(self, listener):
|
||||||
"""Execute listener delete routines for an amphora."""
|
"""Execute listener delete routines for an amphora."""
|
||||||
self.amphora_driver.delete(listener, loadbalancer.vip)
|
# TODO(rm_work): This is only relevant because of UDP listeners now.
|
||||||
|
self.amphora_driver.delete(listener)
|
||||||
LOG.debug("Deleted the listener on the vip")
|
LOG.debug("Deleted the listener on the vip")
|
||||||
|
|
||||||
def revert(self, listener, *args, **kwargs):
|
def revert(self, listener, *args, **kwargs):
|
||||||
|
|
|
@ -235,13 +235,14 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
|
||||||
raise db_exceptions.NoResultFound
|
raise db_exceptions.NoResultFound
|
||||||
|
|
||||||
load_balancer = listener.load_balancer
|
load_balancer = listener.load_balancer
|
||||||
|
listeners = load_balancer.listeners
|
||||||
|
|
||||||
create_listener_tf = self._taskflow_load(self._listener_flows.
|
create_listener_tf = self._taskflow_load(self._listener_flows.
|
||||||
get_create_listener_flow(),
|
get_create_listener_flow(),
|
||||||
store={constants.LOADBALANCER:
|
store={constants.LOADBALANCER:
|
||||||
load_balancer,
|
load_balancer,
|
||||||
constants.LISTENERS:
|
constants.LISTENERS:
|
||||||
[listener]})
|
listeners})
|
||||||
with tf_logging.DynamicLoggingListener(create_listener_tf,
|
with tf_logging.DynamicLoggingListener(create_listener_tf,
|
||||||
log=LOG):
|
log=LOG):
|
||||||
create_listener_tf.run()
|
create_listener_tf.run()
|
||||||
|
|
|
@ -470,7 +470,7 @@ class AmphoraFlows(object):
|
||||||
update_amps_subflow.add(
|
update_amps_subflow.add(
|
||||||
amphora_driver_tasks.AmpListenersUpdate(
|
amphora_driver_tasks.AmpListenersUpdate(
|
||||||
name=constants.AMP_LISTENER_UPDATE + '-' + str(amp_index),
|
name=constants.AMP_LISTENER_UPDATE + '-' + str(amp_index),
|
||||||
requires=(constants.LISTENERS, constants.AMPHORAE),
|
requires=(constants.LOADBALANCER, constants.AMPHORAE),
|
||||||
inject={constants.AMPHORA_INDEX: amp_index,
|
inject={constants.AMPHORA_INDEX: amp_index,
|
||||||
constants.TIMEOUT_DICT: timeout_dict}))
|
constants.TIMEOUT_DICT: timeout_dict}))
|
||||||
amp_index += 1
|
amp_index += 1
|
||||||
|
@ -514,8 +514,7 @@ class AmphoraFlows(object):
|
||||||
requires=constants.AMPHORA))
|
requires=constants.AMPHORA))
|
||||||
|
|
||||||
failover_amphora_flow.add(amphora_driver_tasks.ListenersStart(
|
failover_amphora_flow.add(amphora_driver_tasks.ListenersStart(
|
||||||
requires=(constants.LOADBALANCER, constants.LISTENERS,
|
requires=(constants.LOADBALANCER, constants.AMPHORA)))
|
||||||
constants.AMPHORA)))
|
|
||||||
failover_amphora_flow.add(
|
failover_amphora_flow.add(
|
||||||
database_tasks.DisableAmphoraHealthMonitoring(
|
database_tasks.DisableAmphoraHealthMonitoring(
|
||||||
rebind={constants.AMPHORA: constants.FAILED_AMPHORA},
|
rebind={constants.AMPHORA: constants.FAILED_AMPHORA},
|
||||||
|
|
|
@ -37,7 +37,7 @@ class HealthMonitorFlows(object):
|
||||||
create_hm_flow.add(database_tasks.MarkHealthMonitorPendingCreateInDB(
|
create_hm_flow.add(database_tasks.MarkHealthMonitorPendingCreateInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
create_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
create_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
create_hm_flow.add(database_tasks.MarkPoolActiveInDB(
|
create_hm_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
@ -63,7 +63,7 @@ class HealthMonitorFlows(object):
|
||||||
DeleteModelObject(rebind={constants.OBJECT:
|
DeleteModelObject(rebind={constants.OBJECT:
|
||||||
constants.HEALTH_MON}))
|
constants.HEALTH_MON}))
|
||||||
delete_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_hm_flow.add(database_tasks.DeleteHealthMonitorInDB(
|
delete_hm_flow.add(database_tasks.DeleteHealthMonitorInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
delete_hm_flow.add(database_tasks.DecrementHealthMonitorQuota(
|
delete_hm_flow.add(database_tasks.DecrementHealthMonitorQuota(
|
||||||
|
@ -92,7 +92,7 @@ class HealthMonitorFlows(object):
|
||||||
update_hm_flow.add(database_tasks.MarkHealthMonitorPendingUpdateInDB(
|
update_hm_flow.add(database_tasks.MarkHealthMonitorPendingUpdateInDB(
|
||||||
requires=constants.HEALTH_MON))
|
requires=constants.HEALTH_MON))
|
||||||
update_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_hm_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_hm_flow.add(database_tasks.UpdateHealthMonInDB(
|
update_hm_flow.add(database_tasks.UpdateHealthMonInDB(
|
||||||
requires=[constants.HEALTH_MON, constants.UPDATE_DICT]))
|
requires=[constants.HEALTH_MON, constants.UPDATE_DICT]))
|
||||||
update_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
update_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB(
|
||||||
|
|
|
@ -37,7 +37,7 @@ class L7PolicyFlows(object):
|
||||||
create_l7policy_flow.add(database_tasks.MarkL7PolicyPendingCreateInDB(
|
create_l7policy_flow.add(database_tasks.MarkL7PolicyPendingCreateInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
create_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
create_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
create_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
create_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
||||||
|
@ -60,7 +60,7 @@ class L7PolicyFlows(object):
|
||||||
delete_l7policy_flow.add(model_tasks.DeleteModelObject(
|
delete_l7policy_flow.add(model_tasks.DeleteModelObject(
|
||||||
rebind={constants.OBJECT: constants.L7POLICY}))
|
rebind={constants.OBJECT: constants.L7POLICY}))
|
||||||
delete_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB(
|
delete_l7policy_flow.add(database_tasks.DeleteL7PolicyInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
delete_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
||||||
|
@ -81,7 +81,7 @@ class L7PolicyFlows(object):
|
||||||
update_l7policy_flow.add(database_tasks.MarkL7PolicyPendingUpdateInDB(
|
update_l7policy_flow.add(database_tasks.MarkL7PolicyPendingUpdateInDB(
|
||||||
requires=constants.L7POLICY))
|
requires=constants.L7POLICY))
|
||||||
update_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_l7policy_flow.add(database_tasks.UpdateL7PolicyInDB(
|
update_l7policy_flow.add(database_tasks.UpdateL7PolicyInDB(
|
||||||
requires=[constants.L7POLICY, constants.UPDATE_DICT]))
|
requires=[constants.L7POLICY, constants.UPDATE_DICT]))
|
||||||
update_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
update_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
|
|
|
@ -37,7 +37,7 @@ class L7RuleFlows(object):
|
||||||
create_l7rule_flow.add(database_tasks.MarkL7RulePendingCreateInDB(
|
create_l7rule_flow.add(database_tasks.MarkL7RulePendingCreateInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
create_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
create_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
create_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
create_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
|
@ -62,7 +62,7 @@ class L7RuleFlows(object):
|
||||||
delete_l7rule_flow.add(model_tasks.DeleteModelObject(
|
delete_l7rule_flow.add(model_tasks.DeleteModelObject(
|
||||||
rebind={constants.OBJECT: constants.L7RULE}))
|
rebind={constants.OBJECT: constants.L7RULE}))
|
||||||
delete_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB(
|
delete_l7rule_flow.add(database_tasks.DeleteL7RuleInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
delete_l7rule_flow.add(database_tasks.MarkL7PolicyActiveInDB(
|
||||||
|
@ -85,7 +85,7 @@ class L7RuleFlows(object):
|
||||||
update_l7rule_flow.add(database_tasks.MarkL7RulePendingUpdateInDB(
|
update_l7rule_flow.add(database_tasks.MarkL7RulePendingUpdateInDB(
|
||||||
requires=constants.L7RULE))
|
requires=constants.L7RULE))
|
||||||
update_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_l7rule_flow.add(database_tasks.UpdateL7RuleInDB(
|
update_l7rule_flow.add(database_tasks.UpdateL7RuleInDB(
|
||||||
requires=[constants.L7RULE, constants.UPDATE_DICT]))
|
requires=[constants.L7RULE, constants.UPDATE_DICT]))
|
||||||
update_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
update_l7rule_flow.add(database_tasks.MarkL7RuleActiveInDB(
|
||||||
|
|
|
@ -33,7 +33,7 @@ class ListenerFlows(object):
|
||||||
create_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
create_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
||||||
create_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_listener_flow.add(network_tasks.UpdateVIP(
|
create_listener_flow.add(network_tasks.UpdateVIP(
|
||||||
requires=constants.LOADBALANCER))
|
requires=constants.LOADBALANCER))
|
||||||
create_listener_flow.add(database_tasks.
|
create_listener_flow.add(database_tasks.
|
||||||
|
@ -57,7 +57,7 @@ class ListenerFlows(object):
|
||||||
requires=constants.LOADBALANCER_ID,
|
requires=constants.LOADBALANCER_ID,
|
||||||
provides=constants.LOADBALANCER))
|
provides=constants.LOADBALANCER))
|
||||||
create_all_listeners_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_all_listeners_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_all_listeners_flow.add(network_tasks.UpdateVIP(
|
create_all_listeners_flow.add(network_tasks.UpdateVIP(
|
||||||
requires=constants.LOADBALANCER))
|
requires=constants.LOADBALANCER))
|
||||||
return create_all_listeners_flow
|
return create_all_listeners_flow
|
||||||
|
@ -71,7 +71,7 @@ class ListenerFlows(object):
|
||||||
delete_listener_flow.add(lifecycle_tasks.ListenerToErrorOnRevertTask(
|
delete_listener_flow.add(lifecycle_tasks.ListenerToErrorOnRevertTask(
|
||||||
requires=constants.LISTENER))
|
requires=constants.LISTENER))
|
||||||
delete_listener_flow.add(amphora_driver_tasks.ListenerDelete(
|
delete_listener_flow.add(amphora_driver_tasks.ListenerDelete(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENER]))
|
requires=constants.LISTENER))
|
||||||
delete_listener_flow.add(network_tasks.UpdateVIPForDelete(
|
delete_listener_flow.add(network_tasks.UpdateVIPForDelete(
|
||||||
requires=constants.LOADBALANCER))
|
requires=constants.LOADBALANCER))
|
||||||
delete_listener_flow.add(database_tasks.DeleteListenerInDB(
|
delete_listener_flow.add(database_tasks.DeleteListenerInDB(
|
||||||
|
@ -115,7 +115,7 @@ class ListenerFlows(object):
|
||||||
update_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
update_listener_flow.add(lifecycle_tasks.ListenersToErrorOnRevertTask(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
||||||
update_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_listener_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_listener_flow.add(database_tasks.UpdateListenerInDB(
|
update_listener_flow.add(database_tasks.UpdateListenerInDB(
|
||||||
requires=[constants.LISTENER, constants.UPDATE_DICT]))
|
requires=[constants.LISTENER, constants.UPDATE_DICT]))
|
||||||
update_listener_flow.add(database_tasks.
|
update_listener_flow.add(database_tasks.
|
||||||
|
|
|
@ -332,7 +332,7 @@ class LoadBalancerFlows(object):
|
||||||
update_LB_flow.add(network_tasks.ApplyQos(
|
update_LB_flow.add(network_tasks.ApplyQos(
|
||||||
requires=(constants.LOADBALANCER, constants.UPDATE_DICT)))
|
requires=(constants.LOADBALANCER, constants.UPDATE_DICT)))
|
||||||
update_LB_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_LB_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_LB_flow.add(database_tasks.UpdateLoadbalancerInDB(
|
update_LB_flow.add(database_tasks.UpdateLoadbalancerInDB(
|
||||||
requires=[constants.LOADBALANCER, constants.UPDATE_DICT]))
|
requires=[constants.LOADBALANCER, constants.UPDATE_DICT]))
|
||||||
update_LB_flow.add(database_tasks.MarkLBActiveInDB(
|
update_LB_flow.add(database_tasks.MarkLBActiveInDB(
|
||||||
|
|
|
@ -48,7 +48,7 @@ class MemberFlows(object):
|
||||||
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
requires=(constants.LOADBALANCER, constants.ADDED_PORTS)
|
||||||
))
|
))
|
||||||
create_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=(constants.LOADBALANCER, constants.LISTENERS)))
|
requires=constants.LOADBALANCER))
|
||||||
create_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
create_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
create_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
create_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
@ -79,7 +79,7 @@ class MemberFlows(object):
|
||||||
delete_member_flow.add(database_tasks.DeleteMemberInDB(
|
delete_member_flow.add(database_tasks.DeleteMemberInDB(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
delete_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_member_flow.add(database_tasks.DecrementMemberQuota(
|
delete_member_flow.add(database_tasks.DecrementMemberQuota(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
delete_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
delete_member_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
@ -105,7 +105,7 @@ class MemberFlows(object):
|
||||||
update_member_flow.add(database_tasks.MarkMemberPendingUpdateInDB(
|
update_member_flow.add(database_tasks.MarkMemberPendingUpdateInDB(
|
||||||
requires=constants.MEMBER))
|
requires=constants.MEMBER))
|
||||||
update_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_member_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_member_flow.add(database_tasks.UpdateMemberInDB(
|
update_member_flow.add(database_tasks.UpdateMemberInDB(
|
||||||
requires=[constants.MEMBER, constants.UPDATE_DICT]))
|
requires=[constants.MEMBER, constants.UPDATE_DICT]))
|
||||||
update_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
update_member_flow.add(database_tasks.MarkMemberActiveInDB(
|
||||||
|
@ -195,7 +195,7 @@ class MemberFlows(object):
|
||||||
|
|
||||||
# Update the Listener (this makes the changes active on the Amp)
|
# Update the Listener (this makes the changes active on the Amp)
|
||||||
batch_update_members_flow.add(amphora_driver_tasks.ListenersUpdate(
|
batch_update_members_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=(constants.LOADBALANCER, constants.LISTENERS)))
|
requires=constants.LOADBALANCER))
|
||||||
|
|
||||||
# Mark all the members ACTIVE here, then pool then LB/Listeners
|
# Mark all the members ACTIVE here, then pool then LB/Listeners
|
||||||
batch_update_members_flow.add(unordered_members_active_flow)
|
batch_update_members_flow.add(unordered_members_active_flow)
|
||||||
|
|
|
@ -37,7 +37,7 @@ class PoolFlows(object):
|
||||||
create_pool_flow.add(database_tasks.MarkPoolPendingCreateInDB(
|
create_pool_flow.add(database_tasks.MarkPoolPendingCreateInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
create_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
create_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
create_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
create_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
create_pool_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
create_pool_flow.add(database_tasks.MarkLBAndListenersActiveInDB(
|
||||||
|
@ -62,7 +62,7 @@ class PoolFlows(object):
|
||||||
delete_pool_flow.add(model_tasks.DeleteModelObject(
|
delete_pool_flow.add(model_tasks.DeleteModelObject(
|
||||||
rebind={constants.OBJECT: constants.POOL}))
|
rebind={constants.OBJECT: constants.POOL}))
|
||||||
delete_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
delete_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
delete_pool_flow.add(database_tasks.DeletePoolInDB(
|
delete_pool_flow.add(database_tasks.DeletePoolInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
delete_pool_flow.add(database_tasks.DecrementPoolQuota(
|
delete_pool_flow.add(database_tasks.DecrementPoolQuota(
|
||||||
|
@ -116,7 +116,7 @@ class PoolFlows(object):
|
||||||
update_pool_flow.add(database_tasks.MarkPoolPendingUpdateInDB(
|
update_pool_flow.add(database_tasks.MarkPoolPendingUpdateInDB(
|
||||||
requires=constants.POOL))
|
requires=constants.POOL))
|
||||||
update_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
update_pool_flow.add(amphora_driver_tasks.ListenersUpdate(
|
||||||
requires=[constants.LOADBALANCER, constants.LISTENERS]))
|
requires=constants.LOADBALANCER))
|
||||||
update_pool_flow.add(database_tasks.UpdatePoolInDB(
|
update_pool_flow.add(database_tasks.UpdatePoolInDB(
|
||||||
requires=[constants.POOL, constants.UPDATE_DICT]))
|
requires=[constants.POOL, constants.UPDATE_DICT]))
|
||||||
update_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
update_pool_flow.add(database_tasks.MarkPoolActiveInDB(
|
||||||
|
|
|
@ -52,13 +52,13 @@ class BaseAmphoraTask(task.Task):
|
||||||
class AmpListenersUpdate(BaseAmphoraTask):
|
class AmpListenersUpdate(BaseAmphoraTask):
|
||||||
"""Task to update the listeners on one amphora."""
|
"""Task to update the listeners on one amphora."""
|
||||||
|
|
||||||
def execute(self, listeners, amphora_index, amphorae, timeout_dict=()):
|
def execute(self, loadbalancer, amphora_index, amphorae, timeout_dict=()):
|
||||||
# Note, we don't want this to cause a revert as it may be used
|
# Note, we don't want this to cause a revert as it may be used
|
||||||
# in a failover flow with both amps failing. Skip it and let
|
# in a failover flow with both amps failing. Skip it and let
|
||||||
# health manager fix it.
|
# health manager fix it.
|
||||||
try:
|
try:
|
||||||
self.amphora_driver.update_amphora_listeners(
|
self.amphora_driver.update_amphora_listeners(
|
||||||
listeners, amphora_index, amphorae, timeout_dict)
|
loadbalancer, amphorae[amphora_index], timeout_dict)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
amphora_id = amphorae[amphora_index].id
|
amphora_id = amphorae[amphora_index].id
|
||||||
LOG.error('Failed to update listeners on amphora %s. Skipping '
|
LOG.error('Failed to update listeners on amphora %s. Skipping '
|
||||||
|
@ -71,11 +71,9 @@ class AmpListenersUpdate(BaseAmphoraTask):
|
||||||
class ListenersUpdate(BaseAmphoraTask):
|
class ListenersUpdate(BaseAmphoraTask):
|
||||||
"""Task to update amphora with all specified listeners' configurations."""
|
"""Task to update amphora with all specified listeners' configurations."""
|
||||||
|
|
||||||
def execute(self, loadbalancer, listeners):
|
def execute(self, loadbalancer):
|
||||||
"""Execute updates per listener for an amphora."""
|
"""Execute updates per listener for an amphora."""
|
||||||
for listener in listeners:
|
self.amphora_driver.update(loadbalancer)
|
||||||
listener.load_balancer = loadbalancer
|
|
||||||
self.amphora_driver.update(listener, loadbalancer.vip)
|
|
||||||
|
|
||||||
def revert(self, loadbalancer, *args, **kwargs):
|
def revert(self, loadbalancer, *args, **kwargs):
|
||||||
"""Handle failed listeners updates."""
|
"""Handle failed listeners updates."""
|
||||||
|
@ -86,61 +84,30 @@ class ListenersUpdate(BaseAmphoraTask):
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
self.task_utils.mark_listener_prov_status_error(listener.id)
|
||||||
|
|
||||||
|
|
||||||
class ListenerStop(BaseAmphoraTask):
|
|
||||||
"""Task to stop the listener on the vip."""
|
|
||||||
|
|
||||||
def execute(self, loadbalancer, listener):
|
|
||||||
"""Execute listener stop routines for an amphora."""
|
|
||||||
self.amphora_driver.stop(listener, loadbalancer.vip)
|
|
||||||
LOG.debug("Stopped the listener on the vip")
|
|
||||||
|
|
||||||
def revert(self, listener, *args, **kwargs):
|
|
||||||
"""Handle a failed listener stop."""
|
|
||||||
|
|
||||||
LOG.warning("Reverting listener stop.")
|
|
||||||
|
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
|
||||||
|
|
||||||
|
|
||||||
class ListenerStart(BaseAmphoraTask):
|
|
||||||
"""Task to start the listener on the vip."""
|
|
||||||
|
|
||||||
def execute(self, loadbalancer, listener):
|
|
||||||
"""Execute listener start routines for an amphora."""
|
|
||||||
self.amphora_driver.start(listener, loadbalancer.vip)
|
|
||||||
LOG.debug("Started the listener on the vip")
|
|
||||||
|
|
||||||
def revert(self, listener, *args, **kwargs):
|
|
||||||
"""Handle a failed listener start."""
|
|
||||||
|
|
||||||
LOG.warning("Reverting listener start.")
|
|
||||||
|
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
|
||||||
|
|
||||||
|
|
||||||
class ListenersStart(BaseAmphoraTask):
|
class ListenersStart(BaseAmphoraTask):
|
||||||
"""Task to start all listeners on the vip."""
|
"""Task to start all listeners on the vip."""
|
||||||
|
|
||||||
def execute(self, loadbalancer, listeners, amphora=None):
|
def execute(self, loadbalancer, amphora=None):
|
||||||
"""Execute listener start routines for listeners on an amphora."""
|
"""Execute listener start routines for listeners on an amphora."""
|
||||||
for listener in listeners:
|
if loadbalancer.listeners:
|
||||||
self.amphora_driver.start(listener, loadbalancer.vip, amphora)
|
self.amphora_driver.start(loadbalancer, amphora)
|
||||||
LOG.debug("Started the listeners on the vip")
|
LOG.debug("Started the listeners on the vip")
|
||||||
|
|
||||||
def revert(self, listeners, *args, **kwargs):
|
def revert(self, loadbalancer, *args, **kwargs):
|
||||||
"""Handle failed listeners starts."""
|
"""Handle failed listeners starts."""
|
||||||
|
|
||||||
LOG.warning("Reverting listeners starts.")
|
LOG.warning("Reverting listeners starts.")
|
||||||
for listener in listeners:
|
for listener in loadbalancer.listeners:
|
||||||
self.task_utils.mark_listener_prov_status_error(listener.id)
|
self.task_utils.mark_listener_prov_status_error(listener.id)
|
||||||
|
|
||||||
|
|
||||||
class ListenerDelete(BaseAmphoraTask):
|
class ListenerDelete(BaseAmphoraTask):
|
||||||
"""Task to delete the listener on the vip."""
|
"""Task to delete the listener on the vip."""
|
||||||
|
|
||||||
def execute(self, loadbalancer, listener):
|
def execute(self, listener):
|
||||||
"""Execute listener delete routines for an amphora."""
|
"""Execute listener delete routines for an amphora."""
|
||||||
self.amphora_driver.delete(listener, loadbalancer.vip)
|
# TODO(rm_work): This is only relevant because of UDP listeners now.
|
||||||
|
self.amphora_driver.delete(listener)
|
||||||
LOG.debug("Deleted the listener on the vip")
|
LOG.debug("Deleted the listener on the vip")
|
||||||
|
|
||||||
def revert(self, listener, *args, **kwargs):
|
def revert(self, listener, *args, **kwargs):
|
||||||
|
|
|
@ -1253,6 +1253,7 @@ class AmphoraRepository(BaseRepository):
|
||||||
"load_balancer.operating_status AS lb_op_status, "
|
"load_balancer.operating_status AS lb_op_status, "
|
||||||
"listener.id AS list_id, "
|
"listener.id AS list_id, "
|
||||||
"listener.operating_status AS list_op_status, "
|
"listener.operating_status AS list_op_status, "
|
||||||
|
"listener.enabled AS list_enabled, "
|
||||||
"listener.protocol AS list_protocol, "
|
"listener.protocol AS list_protocol, "
|
||||||
"pool.id AS pool_id, "
|
"pool.id AS pool_id, "
|
||||||
"pool.operating_status AS pool_op_status, "
|
"pool.operating_status AS pool_op_status, "
|
||||||
|
@ -1278,7 +1279,8 @@ class AmphoraRepository(BaseRepository):
|
||||||
lb['operating_status'] = row['lb_op_status']
|
lb['operating_status'] = row['lb_op_status']
|
||||||
if row['list_id'] and row['list_id'] not in listeners:
|
if row['list_id'] and row['list_id'] not in listeners:
|
||||||
listener = {'operating_status': row['list_op_status'],
|
listener = {'operating_status': row['list_op_status'],
|
||||||
'protocol': row['list_protocol']}
|
'protocol': row['list_protocol'],
|
||||||
|
'enabled': row['list_enabled']}
|
||||||
listeners[row['list_id']] = listener
|
listeners[row['list_id']] = listener
|
||||||
if row['pool_id']:
|
if row['pool_id']:
|
||||||
if row['pool_id'] in pools and row['member_id']:
|
if row['pool_id'] in pools and row['member_id']:
|
||||||
|
|
|
@ -18,7 +18,6 @@ import subprocess
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import mock
|
import mock
|
||||||
from werkzeug import exceptions
|
|
||||||
|
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
@ -315,67 +314,6 @@ class KeepalivedLvsTestCase(base.TestCase):
|
||||||
'start')
|
'start')
|
||||||
self.assertEqual(500, res.status_code)
|
self.assertEqual(500, res.status_code)
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.utils.keepalivedlvs_query.'
|
|
||||||
'get_listener_realserver_mapping')
|
|
||||||
@mock.patch('subprocess.check_output', return_value=PROC_CONTENT)
|
|
||||||
@mock.patch('os.path.exists')
|
|
||||||
def test_get_udp_listener_status(self, m_exist, m_check_output,
|
|
||||||
mget_mapping):
|
|
||||||
mget_mapping.return_value = (
|
|
||||||
True, {'10.0.0.99:82': {'status': 'UP',
|
|
||||||
'Weight': '13',
|
|
||||||
'InActConn': '0',
|
|
||||||
'ActiveConn': '0'},
|
|
||||||
'10.0.0.98:82': {'status': 'UP',
|
|
||||||
'Weight': '13',
|
|
||||||
'InActConn': '0',
|
|
||||||
'ActiveConn': '0'}})
|
|
||||||
pid_path = ('/var/lib/octavia/lvs/octavia-'
|
|
||||||
'keepalivedlvs-%s.pid' % self.FAKE_ID)
|
|
||||||
self.useFixture(test_utils.OpenFixture(pid_path,
|
|
||||||
self.NORMAL_PID_CONTENT))
|
|
||||||
|
|
||||||
cfg_path = ('/var/lib/octavia/lvs/octavia-'
|
|
||||||
'keepalivedlvs-%s.conf' % self.FAKE_ID)
|
|
||||||
self.useFixture(test_utils.OpenFixture(cfg_path,
|
|
||||||
self.NORMAL_CFG_CONTENT))
|
|
||||||
|
|
||||||
m_exist.return_value = True
|
|
||||||
expected = {'status': 'ACTIVE',
|
|
||||||
'pools': [{'lvs': {
|
|
||||||
'members': {self.MEMBER_ID1: 'UP',
|
|
||||||
self.MEMBER_ID2: 'UP'},
|
|
||||||
'status': 'UP',
|
|
||||||
'uuid': self.POOL_ID}}],
|
|
||||||
'type': 'UDP', 'uuid': self.FAKE_ID}
|
|
||||||
res = self.test_keepalivedlvs.get_udp_listener_status(self.FAKE_ID)
|
|
||||||
self.assertEqual(200, res.status_code)
|
|
||||||
self.assertEqual(expected, res.json)
|
|
||||||
|
|
||||||
@mock.patch('os.path.exists')
|
|
||||||
def test_get_udp_listener_status_no_exists(self, m_exist):
|
|
||||||
m_exist.return_value = False
|
|
||||||
self.assertRaises(exceptions.HTTPException,
|
|
||||||
self.test_keepalivedlvs.get_udp_listener_status,
|
|
||||||
self.FAKE_ID)
|
|
||||||
|
|
||||||
@mock.patch('os.path.exists')
|
|
||||||
def test_get_udp_listener_status_offline_status(self, m_exist):
|
|
||||||
m_exist.return_value = True
|
|
||||||
pid_path = ('/var/lib/octavia/lvs/octavia-'
|
|
||||||
'keepalivedlvs-%s.pid' % self.FAKE_ID)
|
|
||||||
self.useFixture(test_utils.OpenFixture(pid_path,
|
|
||||||
self.NORMAL_PID_CONTENT))
|
|
||||||
cfg_path = ('/var/lib/octavia/lvs/octavia-'
|
|
||||||
'keepalivedlvs-%s.conf' % self.FAKE_ID)
|
|
||||||
self.useFixture(test_utils.OpenFixture(cfg_path, 'NO VS CONFIG'))
|
|
||||||
expected = {'status': 'OFFLINE',
|
|
||||||
'type': 'UDP',
|
|
||||||
'uuid': self.FAKE_ID}
|
|
||||||
res = self.test_keepalivedlvs.get_udp_listener_status(self.FAKE_ID)
|
|
||||||
self.assertEqual(200, res.status_code)
|
|
||||||
self.assertEqual(expected, res.json)
|
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_udp_listeners', return_value=[LISTENER_ID])
|
'get_udp_listeners', return_value=[LISTENER_ID])
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
|
|
|
@ -118,11 +118,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_distro_id.return_value = distro
|
mock_distro_id.return_value = distro
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
mode = stat.S_IRUSR | stat.S_IWUSR
|
mode = stat.S_IRUSR | stat.S_IWUSR
|
||||||
mock_open.assert_called_with(file_name, flags, mode)
|
mock_open.assert_called_with(file_name, flags, mode)
|
||||||
|
@ -159,11 +159,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_distro_id.return_value = distro
|
mock_distro_id.return_value = distro
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
self.assertEqual(500, rv.status_code)
|
self.assertEqual(500, rv.status_code)
|
||||||
|
|
||||||
|
@ -188,11 +188,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
|
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
|
|
||||||
self.assertEqual(202, rv.status_code)
|
self.assertEqual(202, rv.status_code)
|
||||||
|
@ -220,11 +220,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_distro_id.return_value = distro
|
mock_distro_id.return_value = distro
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
self.assertEqual(400, rv.status_code)
|
self.assertEqual(400, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -255,11 +255,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_distro_id.return_value = distro
|
mock_distro_id.return_value = distro
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/amp_123/123/haproxy',
|
'/loadbalancer/amp_123/123/haproxy',
|
||||||
data='test')
|
data='test')
|
||||||
self.assertEqual(500, rv.status_code)
|
self.assertEqual(500, rv.status_code)
|
||||||
|
|
||||||
|
@ -269,45 +269,49 @@ class TestServerTestCase(base.TestCase):
|
||||||
def test_centos_start(self):
|
def test_centos_start(self):
|
||||||
self._test_start(consts.CENTOS)
|
self._test_start(consts.CENTOS)
|
||||||
|
|
||||||
|
@mock.patch('os.listdir')
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'vrrp_check_script_update')
|
'Loadbalancer.vrrp_check_script_update')
|
||||||
@mock.patch('subprocess.check_output')
|
@mock.patch('subprocess.check_output')
|
||||||
def _test_start(self, distro, mock_subprocess, mock_vrrp, mock_exists):
|
def _test_start(self, distro, mock_subprocess, mock_vrrp, mock_exists,
|
||||||
|
mock_listdir):
|
||||||
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/error')
|
'/loadbalancer/123/error')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/error')
|
'/loadbalancer/123/error')
|
||||||
self.assertEqual(400, rv.status_code)
|
self.assertEqual(400, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{'message': 'Invalid Request',
|
{'message': 'Invalid Request',
|
||||||
'details': 'Unknown action: error', },
|
'details': 'Unknown action: error', },
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
|
||||||
|
mock_exists.reset_mock()
|
||||||
mock_exists.return_value = False
|
mock_exists.return_value = False
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/start')
|
'/loadbalancer/123/start')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/start')
|
'/loadbalancer/123/start')
|
||||||
self.assertEqual(404, rv.status_code)
|
self.assertEqual(404, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{'message': 'Listener Not Found',
|
{'message': 'Loadbalancer Not Found',
|
||||||
'details': 'No listener with UUID: 123'},
|
'details': 'No loadbalancer with UUID: 123'},
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
mock_exists.assert_called_with('/var/lib/octavia/123/haproxy.cfg')
|
mock_exists.assert_called_with('/var/lib/octavia')
|
||||||
|
|
||||||
mock_exists.return_value = True
|
mock_exists.return_value = True
|
||||||
|
mock_listdir.return_value = ['123']
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/start')
|
'/loadbalancer/123/start')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/start')
|
'/loadbalancer/123/start')
|
||||||
self.assertEqual(202, rv.status_code)
|
self.assertEqual(202, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{'message': 'OK',
|
{'message': 'OK',
|
||||||
|
@ -322,10 +326,10 @@ class TestServerTestCase(base.TestCase):
|
||||||
7, 'test', RANDOM_ERROR)
|
7, 'test', RANDOM_ERROR)
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/start')
|
'/loadbalancer/123/start')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/start')
|
'/loadbalancer/123/start')
|
||||||
self.assertEqual(500, rv.status_code)
|
self.assertEqual(500, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{
|
{
|
||||||
|
@ -341,26 +345,28 @@ class TestServerTestCase(base.TestCase):
|
||||||
def test_centos_reload(self):
|
def test_centos_reload(self):
|
||||||
self._test_reload(consts.CENTOS)
|
self._test_reload(consts.CENTOS)
|
||||||
|
|
||||||
|
@mock.patch('os.listdir')
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'vrrp_check_script_update')
|
'Loadbalancer.vrrp_check_script_update')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'_check_haproxy_status')
|
'Loadbalancer._check_haproxy_status')
|
||||||
@mock.patch('subprocess.check_output')
|
@mock.patch('subprocess.check_output')
|
||||||
def _test_reload(self, distro, mock_subprocess, mock_haproxy_status,
|
def _test_reload(self, distro, mock_subprocess, mock_haproxy_status,
|
||||||
mock_vrrp, mock_exists):
|
mock_vrrp, mock_exists, mock_listdir):
|
||||||
|
|
||||||
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
||||||
|
|
||||||
# Process running so reload
|
# Process running so reload
|
||||||
mock_exists.return_value = True
|
mock_exists.return_value = True
|
||||||
|
mock_listdir.return_value = ['123']
|
||||||
mock_haproxy_status.return_value = consts.ACTIVE
|
mock_haproxy_status.return_value = consts.ACTIVE
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/reload')
|
'/loadbalancer/123/reload')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/reload')
|
'/loadbalancer/123/reload')
|
||||||
self.assertEqual(202, rv.status_code)
|
self.assertEqual(202, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{'message': 'OK',
|
{'message': 'OK',
|
||||||
|
@ -374,10 +380,10 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_haproxy_status.return_value = consts.OFFLINE
|
mock_haproxy_status.return_value = consts.OFFLINE
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/reload')
|
'/loadbalancer/123/reload')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/reload')
|
'/loadbalancer/123/reload')
|
||||||
self.assertEqual(202, rv.status_code)
|
self.assertEqual(202, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{'message': 'OK',
|
{'message': 'OK',
|
||||||
|
@ -411,13 +417,13 @@ class TestServerTestCase(base.TestCase):
|
||||||
|
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(dict(
|
self.assertEqual(dict(
|
||||||
api_version='0.5',
|
api_version='1.0',
|
||||||
haproxy_version='9.9.99-9',
|
haproxy_version='9.9.99-9',
|
||||||
hostname='test-host'),
|
hostname='test-host'),
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_listener_protocol', return_value='TCP')
|
'get_protocol_for_lb_object', return_value='TCP')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_os_init_system', return_value=consts.INIT_SYSTEMD)
|
'get_os_init_system', return_value=consts.INIT_SYSTEMD)
|
||||||
def test_delete_ubuntu_listener_systemd(self, mock_init_system,
|
def test_delete_ubuntu_listener_systemd(self, mock_init_system,
|
||||||
|
@ -426,7 +432,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_init_system)
|
mock_init_system)
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_listener_protocol', return_value='TCP')
|
'get_protocol_for_lb_object', return_value='TCP')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_os_init_system', return_value=consts.INIT_SYSTEMD)
|
'get_os_init_system', return_value=consts.INIT_SYSTEMD)
|
||||||
def test_delete_centos_listener_systemd(self, mock_init_system,
|
def test_delete_centos_listener_systemd(self, mock_init_system,
|
||||||
|
@ -435,7 +441,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_init_system)
|
mock_init_system)
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_listener_protocol', return_value='TCP')
|
'get_protocol_for_lb_object', return_value='TCP')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_os_init_system', return_value=consts.INIT_SYSVINIT)
|
'get_os_init_system', return_value=consts.INIT_SYSVINIT)
|
||||||
def test_delete_ubuntu_listener_sysvinit(self, mock_init_system,
|
def test_delete_ubuntu_listener_sysvinit(self, mock_init_system,
|
||||||
|
@ -444,7 +450,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_init_system)
|
mock_init_system)
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_listener_protocol', return_value='TCP')
|
'get_protocol_for_lb_object', return_value='TCP')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_os_init_system', return_value=consts.INIT_UPSTART)
|
'get_os_init_system', return_value=consts.INIT_UPSTART)
|
||||||
def test_delete_ubuntu_listener_upstart(self, mock_init_system,
|
def test_delete_ubuntu_listener_upstart(self, mock_init_system,
|
||||||
|
@ -452,20 +458,22 @@ class TestServerTestCase(base.TestCase):
|
||||||
self._test_delete_listener(consts.INIT_UPSTART, consts.UBUNTU,
|
self._test_delete_listener(consts.INIT_UPSTART, consts.UBUNTU,
|
||||||
mock_init_system)
|
mock_init_system)
|
||||||
|
|
||||||
|
@mock.patch('os.listdir')
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
@mock.patch('subprocess.check_output')
|
@mock.patch('subprocess.check_output')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'vrrp_check_script_update')
|
'Loadbalancer.vrrp_check_script_update')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.' +
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.' +
|
||||||
'get_haproxy_pid')
|
'get_haproxy_pid')
|
||||||
@mock.patch('shutil.rmtree')
|
@mock.patch('shutil.rmtree')
|
||||||
@mock.patch('os.remove')
|
@mock.patch('os.remove')
|
||||||
def _test_delete_listener(self, init_system, distro, mock_init_system,
|
def _test_delete_listener(self, init_system, distro, mock_init_system,
|
||||||
mock_remove, mock_rmtree, mock_pid, mock_vrrp,
|
mock_remove, mock_rmtree, mock_pid, mock_vrrp,
|
||||||
mock_check_output, mock_exists):
|
mock_check_output, mock_exists, mock_listdir):
|
||||||
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
||||||
# no listener
|
# no listener
|
||||||
mock_exists.return_value = False
|
mock_exists.return_value = False
|
||||||
|
mock_listdir.return_value = ['123']
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
||||||
'/listeners/123')
|
'/listeners/123')
|
||||||
|
@ -474,10 +482,10 @@ class TestServerTestCase(base.TestCase):
|
||||||
'/listeners/123')
|
'/listeners/123')
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
mock_exists.assert_called_with('/var/lib/octavia/123/haproxy.cfg')
|
mock_exists.assert_called_once_with('/var/lib/octavia')
|
||||||
|
|
||||||
# service is stopped + no upstart script + no vrrp
|
# service is stopped + no upstart script + no vrrp
|
||||||
mock_exists.side_effect = [True, False, False, False]
|
mock_exists.side_effect = [True, True, False, False, False]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
||||||
'/listeners/123')
|
'/listeners/123')
|
||||||
|
@ -504,7 +512,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_exists.assert_any_call('/var/lib/octavia/123/123.pid')
|
mock_exists.assert_any_call('/var/lib/octavia/123/123.pid')
|
||||||
|
|
||||||
# service is stopped + no upstart script + vrrp
|
# service is stopped + no upstart script + vrrp
|
||||||
mock_exists.side_effect = [True, False, True, False]
|
mock_exists.side_effect = [True, True, False, True, False]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
||||||
'/listeners/123')
|
'/listeners/123')
|
||||||
|
@ -531,7 +539,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_exists.assert_any_call('/var/lib/octavia/123/123.pid')
|
mock_exists.assert_any_call('/var/lib/octavia/123/123.pid')
|
||||||
|
|
||||||
# service is stopped + upstart script + no vrrp
|
# service is stopped + upstart script + no vrrp
|
||||||
mock_exists.side_effect = [True, False, False, True]
|
mock_exists.side_effect = [True, True, False, False, True]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
||||||
'/listeners/123')
|
'/listeners/123')
|
||||||
|
@ -555,7 +563,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||||
|
|
||||||
# service is stopped + upstart script + vrrp
|
# service is stopped + upstart script + vrrp
|
||||||
mock_exists.side_effect = [True, False, True, True]
|
mock_exists.side_effect = [True, True, False, True, True]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
||||||
'/listeners/123')
|
'/listeners/123')
|
||||||
|
@ -579,7 +587,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||||
|
|
||||||
# service is running + upstart script + no vrrp
|
# service is running + upstart script + no vrrp
|
||||||
mock_exists.side_effect = [True, True, True, False, True]
|
mock_exists.side_effect = [True, True, True, True, False, True]
|
||||||
mock_pid.return_value = '456'
|
mock_pid.return_value = '456'
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
||||||
|
@ -609,7 +617,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||||
|
|
||||||
# service is running + upstart script + vrrp
|
# service is running + upstart script + vrrp
|
||||||
mock_exists.side_effect = [True, True, True, True, True]
|
mock_exists.side_effect = [True, True, True, True, True, True]
|
||||||
mock_pid.return_value = '456'
|
mock_pid.return_value = '456'
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
||||||
|
@ -639,7 +647,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||||
|
|
||||||
# service is running + stopping fails
|
# service is running + stopping fails
|
||||||
mock_exists.side_effect = [True, True, True]
|
mock_exists.side_effect = [True, True, True, True]
|
||||||
mock_check_output.side_effect = subprocess.CalledProcessError(
|
mock_check_output.side_effect = subprocess.CalledProcessError(
|
||||||
7, 'test', RANDOM_ERROR)
|
7, 'test', RANDOM_ERROR)
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
|
@ -661,8 +669,9 @@ class TestServerTestCase(base.TestCase):
|
||||||
def test_centos_get_haproxy(self):
|
def test_centos_get_haproxy(self):
|
||||||
self._test_get_haproxy(consts.CENTOS)
|
self._test_get_haproxy(consts.CENTOS)
|
||||||
|
|
||||||
|
@mock.patch('os.listdir')
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
def _test_get_haproxy(self, distro, mock_exists):
|
def _test_get_haproxy(self, distro, mock_exists, mock_listdir):
|
||||||
|
|
||||||
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
||||||
|
|
||||||
|
@ -670,23 +679,24 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_exists.side_effect = [False]
|
mock_exists.side_effect = [False]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/haproxy')
|
'/loadbalancer/123/haproxy')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.get('/' + api_server.VERSION +
|
rv = self.centos_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/haproxy')
|
'/loadbalancer/123/haproxy')
|
||||||
self.assertEqual(404, rv.status_code)
|
self.assertEqual(404, rv.status_code)
|
||||||
|
|
||||||
mock_exists.side_effect = [True]
|
mock_exists.side_effect = [True, True]
|
||||||
|
|
||||||
path = util.config_path('123')
|
path = util.config_path('123')
|
||||||
self.useFixture(test_utils.OpenFixture(path, CONTENT))
|
self.useFixture(test_utils.OpenFixture(path, CONTENT))
|
||||||
|
|
||||||
|
mock_listdir.return_value = ['123']
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/haproxy')
|
'/loadbalancer/123/haproxy')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.get('/' + api_server.VERSION +
|
rv = self.centos_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/haproxy')
|
'/loadbalancer/123/haproxy')
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(six.b(CONTENT), rv.data)
|
self.assertEqual(six.b(CONTENT), rv.data)
|
||||||
self.assertEqual('text/plain; charset=utf-8',
|
self.assertEqual('text/plain; charset=utf-8',
|
||||||
|
@ -699,17 +709,17 @@ class TestServerTestCase(base.TestCase):
|
||||||
self._test_get_all_listeners(consts.CENTOS)
|
self._test_get_all_listeners(consts.CENTOS)
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_listeners')
|
'get_loadbalancers')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'_check_listener_status')
|
'Loadbalancer._check_haproxy_status')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'_parse_haproxy_file')
|
'parse_haproxy_file')
|
||||||
def _test_get_all_listeners(self, distro, mock_parse, mock_status,
|
def _test_get_all_listeners(self, distro, mock_parse, mock_status,
|
||||||
mock_listener):
|
mock_lbs):
|
||||||
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
||||||
|
|
||||||
# no listeners
|
# no listeners
|
||||||
mock_listener.side_effect = [[]]
|
mock_lbs.side_effect = [[]]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION + '/listeners')
|
rv = self.ubuntu_app.get('/' + api_server.VERSION + '/listeners')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
|
@ -719,8 +729,8 @@ class TestServerTestCase(base.TestCase):
|
||||||
self.assertFalse(jsonutils.loads(rv.data.decode('utf-8')))
|
self.assertFalse(jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
|
||||||
# one listener ACTIVE
|
# one listener ACTIVE
|
||||||
mock_listener.side_effect = [['123']]
|
mock_lbs.side_effect = [['123']]
|
||||||
mock_parse.side_effect = [{'mode': 'test'}]
|
mock_parse.side_effect = [['fake_socket', {'123': {'mode': 'test'}}]]
|
||||||
mock_status.side_effect = [consts.ACTIVE]
|
mock_status.side_effect = [consts.ACTIVE]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION + '/listeners')
|
rv = self.ubuntu_app.get('/' + api_server.VERSION + '/listeners')
|
||||||
|
@ -732,10 +742,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
[{'status': consts.ACTIVE, 'type': 'test', 'uuid': '123'}],
|
[{'status': consts.ACTIVE, 'type': 'test', 'uuid': '123'}],
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
|
||||||
# two listener one ACTIVE, one ERROR
|
# two listeners, two modes
|
||||||
mock_listener.side_effect = [['123', '456']]
|
mock_lbs.side_effect = [['123', '456']]
|
||||||
mock_parse.side_effect = [{'mode': 'test'}, {'mode': 'http'}]
|
mock_parse.side_effect = [['fake_socket', {'123': {'mode': 'test'}}],
|
||||||
mock_status.side_effect = [consts.ACTIVE, consts.ERROR]
|
['fake_socket', {'456': {'mode': 'http'}}]]
|
||||||
|
mock_status.return_value = consts.ACTIVE
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION + '/listeners')
|
rv = self.ubuntu_app.get('/' + api_server.VERSION + '/listeners')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
|
@ -744,86 +755,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[{'status': consts.ACTIVE, 'type': 'test', 'uuid': '123'},
|
[{'status': consts.ACTIVE, 'type': 'test', 'uuid': '123'},
|
||||||
{'status': consts.ERROR, 'type': '', 'uuid': '456'}],
|
{'status': consts.ACTIVE, 'type': 'http', 'uuid': '456'}],
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
|
||||||
|
|
||||||
def test_ubuntu_get_listener(self):
|
|
||||||
self._test_get_listener(consts.UBUNTU)
|
|
||||||
|
|
||||||
def test_centos_get_listener(self):
|
|
||||||
self._test_get_listener(consts.CENTOS)
|
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
|
||||||
'get_listener_protocol', return_value='TCP')
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
|
||||||
'_check_listener_status')
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
|
||||||
'_parse_haproxy_file')
|
|
||||||
@mock.patch('octavia.amphorae.backends.utils.haproxy_query.HAProxyQuery')
|
|
||||||
@mock.patch('os.path.exists')
|
|
||||||
def _test_get_listener(self, distro, mock_exists, mock_query, mock_parse,
|
|
||||||
mock_status, mock_get_proto):
|
|
||||||
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
|
||||||
# Listener not found
|
|
||||||
mock_exists.side_effect = [False]
|
|
||||||
if distro == consts.UBUNTU:
|
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
|
||||||
'/listeners/123')
|
|
||||||
elif distro == consts.CENTOS:
|
|
||||||
rv = self.centos_app.get('/' + api_server.VERSION +
|
|
||||||
'/listeners/123')
|
|
||||||
self.assertEqual(404, rv.status_code)
|
|
||||||
self.assertEqual(
|
|
||||||
{'message': 'Listener Not Found',
|
|
||||||
'details': 'No listener with UUID: 123'},
|
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
|
||||||
|
|
||||||
# Listener not ACTIVE
|
|
||||||
mock_parse.side_effect = [dict(mode='test')]
|
|
||||||
mock_status.side_effect = [consts.ERROR]
|
|
||||||
mock_exists.side_effect = [True]
|
|
||||||
if distro == consts.UBUNTU:
|
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
|
||||||
'/listeners/123')
|
|
||||||
elif distro == consts.CENTOS:
|
|
||||||
rv = self.centos_app.get('/' + api_server.VERSION +
|
|
||||||
'/listeners/123')
|
|
||||||
self.assertEqual(200, rv.status_code)
|
|
||||||
self.assertEqual(dict(
|
|
||||||
status=consts.ERROR,
|
|
||||||
type='',
|
|
||||||
uuid='123'), jsonutils.loads(rv.data.decode('utf-8')))
|
|
||||||
|
|
||||||
# Listener ACTIVE
|
|
||||||
mock_parse.side_effect = [dict(mode='test', stats_socket='blah')]
|
|
||||||
mock_status.side_effect = [consts.ACTIVE]
|
|
||||||
mock_exists.side_effect = [True]
|
|
||||||
mock_pool = mock.Mock()
|
|
||||||
mock_query.side_effect = [mock_pool]
|
|
||||||
mock_pool.get_pool_status.side_effect = [
|
|
||||||
{'tcp-servers': {
|
|
||||||
'status': 'DOWN',
|
|
||||||
'uuid': 'tcp-servers',
|
|
||||||
'members': [
|
|
||||||
{'id-34833': 'DOWN'},
|
|
||||||
{'id-34836': 'DOWN'}]}}]
|
|
||||||
if distro == consts.UBUNTU:
|
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
|
||||||
'/listeners/123')
|
|
||||||
elif distro == consts.CENTOS:
|
|
||||||
rv = self.centos_app.get('/' + api_server.VERSION +
|
|
||||||
'/listeners/123')
|
|
||||||
self.assertEqual(200, rv.status_code)
|
|
||||||
self.assertEqual(dict(
|
|
||||||
status=consts.ACTIVE,
|
|
||||||
type='test',
|
|
||||||
uuid='123',
|
|
||||||
pools=[dict(
|
|
||||||
status=consts.DOWN,
|
|
||||||
uuid='tcp-servers',
|
|
||||||
members=[
|
|
||||||
{u'id-34833': u'DOWN'},
|
|
||||||
{u'id-34836': u'DOWN'}])]),
|
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
|
||||||
def test_ubuntu_delete_cert(self):
|
def test_ubuntu_delete_cert(self):
|
||||||
|
@ -838,11 +770,13 @@ class TestServerTestCase(base.TestCase):
|
||||||
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
self.assertIn(distro, [consts.UBUNTU, consts.CENTOS])
|
||||||
mock_exists.side_effect = [False]
|
mock_exists.side_effect = [False]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete(
|
||||||
'/listeners/123/certificates/test.pem')
|
'/' + api_server.VERSION +
|
||||||
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.delete('/' + api_server.VERSION +
|
rv = self.centos_app.delete(
|
||||||
'/listeners/123/certificates/test.pem')
|
'/' + api_server.VERSION +
|
||||||
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
mock_exists.assert_called_once_with(
|
mock_exists.assert_called_once_with(
|
||||||
|
@ -851,20 +785,24 @@ class TestServerTestCase(base.TestCase):
|
||||||
# wrong file name
|
# wrong file name
|
||||||
mock_exists.side_effect = [True]
|
mock_exists.side_effect = [True]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete(
|
||||||
'/listeners/123/certificates/test.bla')
|
'/' + api_server.VERSION +
|
||||||
|
'/loadbalancer/123/certificates/test.bla')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.delete('/' + api_server.VERSION +
|
rv = self.centos_app.delete(
|
||||||
'/listeners/123/certificates/test.bla')
|
'/' + api_server.VERSION +
|
||||||
|
'/loadbalancer/123/certificates/test.bla')
|
||||||
self.assertEqual(400, rv.status_code)
|
self.assertEqual(400, rv.status_code)
|
||||||
|
|
||||||
mock_exists.side_effect = [True]
|
mock_exists.side_effect = [True]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.delete('/' + api_server.VERSION +
|
rv = self.ubuntu_app.delete(
|
||||||
'/listeners/123/certificates/test.pem')
|
'/' + api_server.VERSION +
|
||||||
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.delete('/' + api_server.VERSION +
|
rv = self.centos_app.delete(
|
||||||
'/listeners/123/certificates/test.pem')
|
'/' + api_server.VERSION +
|
||||||
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
mock_remove.assert_called_once_with(
|
mock_remove.assert_called_once_with(
|
||||||
|
@ -886,10 +824,10 @@ class TestServerTestCase(base.TestCase):
|
||||||
|
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.pem')
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.get('/' + api_server.VERSION +
|
rv = self.centos_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.pem')
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
self.assertEqual(404, rv.status_code)
|
self.assertEqual(404, rv.status_code)
|
||||||
self.assertEqual(dict(
|
self.assertEqual(dict(
|
||||||
details='No certificate with filename: test.pem',
|
details='No certificate with filename: test.pem',
|
||||||
|
@ -901,29 +839,29 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_exists.side_effect = [True]
|
mock_exists.side_effect = [True]
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.bla',
|
'/loadbalancer/123/certificates/test.bla',
|
||||||
data='TestTest')
|
data='TestTest')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.bla',
|
'/loadbalancer/123/certificates/test.bla',
|
||||||
data='TestTest')
|
data='TestTest')
|
||||||
self.assertEqual(400, rv.status_code)
|
self.assertEqual(400, rv.status_code)
|
||||||
|
|
||||||
mock_exists.return_value = True
|
mock_exists.return_value = True
|
||||||
mock_exists.side_effect = None
|
mock_exists.side_effect = None
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
path = self.ubuntu_test_server._listener._cert_file_path(
|
path = self.ubuntu_test_server._loadbalancer._cert_file_path(
|
||||||
'123', 'test.pem')
|
'123', 'test.pem')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
path = self.centos_test_server._listener._cert_file_path(
|
path = self.centos_test_server._loadbalancer._cert_file_path(
|
||||||
'123', 'test.pem')
|
'123', 'test.pem')
|
||||||
self.useFixture(test_utils.OpenFixture(path, CONTENT))
|
self.useFixture(test_utils.OpenFixture(path, CONTENT))
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
rv = self.ubuntu_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.pem')
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.get('/' + api_server.VERSION +
|
rv = self.centos_app.get('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.pem')
|
'/loadbalancer/123/certificates/test.pem')
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(dict(md5sum=hashlib.md5(six.b(CONTENT)).hexdigest()),
|
self.assertEqual(dict(md5sum=hashlib.md5(six.b(CONTENT)).hexdigest()),
|
||||||
jsonutils.loads(rv.data.decode('utf-8')))
|
jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
@ -942,20 +880,20 @@ class TestServerTestCase(base.TestCase):
|
||||||
# wrong file name
|
# wrong file name
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.bla',
|
'/loadbalancer/123/certificates/test.bla',
|
||||||
data='TestTest')
|
data='TestTest')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/test.bla',
|
'/loadbalancer/123/certificates/test.bla',
|
||||||
data='TestTest')
|
data='TestTest')
|
||||||
self.assertEqual(400, rv.status_code)
|
self.assertEqual(400, rv.status_code)
|
||||||
|
|
||||||
mock_exists.return_value = True
|
mock_exists.return_value = True
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
path = self.ubuntu_test_server._listener._cert_file_path(
|
path = self.ubuntu_test_server._loadbalancer._cert_file_path(
|
||||||
'123', 'test.pem')
|
'123', 'test.pem')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
path = self.centos_test_server._listener._cert_file_path(
|
path = self.centos_test_server._loadbalancer._cert_file_path(
|
||||||
'123', 'test.pem')
|
'123', 'test.pem')
|
||||||
|
|
||||||
m = self.useFixture(test_utils.OpenFixture(path)).mock_open
|
m = self.useFixture(test_utils.OpenFixture(path)).mock_open
|
||||||
|
@ -963,11 +901,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
|
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/'
|
'/loadbalancer/123/certificates/'
|
||||||
'test.pem', data='TestTest')
|
'test.pem', data='TestTest')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/'
|
'/loadbalancer/123/certificates/'
|
||||||
'test.pem', data='TestTest')
|
'test.pem', data='TestTest')
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
@ -980,11 +918,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
with mock.patch('os.open'), mock.patch.object(os, 'fdopen', m):
|
with mock.patch('os.open'), mock.patch.object(os, 'fdopen', m):
|
||||||
if distro == consts.UBUNTU:
|
if distro == consts.UBUNTU:
|
||||||
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
rv = self.ubuntu_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/'
|
'/loadbalancer/123/certificates/'
|
||||||
'test.pem', data='TestTest')
|
'test.pem', data='TestTest')
|
||||||
elif distro == consts.CENTOS:
|
elif distro == consts.CENTOS:
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/listeners/123/certificates/'
|
'/loadbalancer/123/certificates/'
|
||||||
'test.pem', data='TestTest')
|
'test.pem', data='TestTest')
|
||||||
self.assertEqual(200, rv.status_code)
|
self.assertEqual(200, rv.status_code)
|
||||||
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
self.assertEqual(OK, jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
@ -2626,7 +2564,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
haproxy_count = random.randrange(0, 100)
|
haproxy_count = random.randrange(0, 100)
|
||||||
mock_count_haproxy.return_value = haproxy_count
|
mock_count_haproxy.return_value = haproxy_count
|
||||||
|
|
||||||
expected_dict = {'active': True, 'api_version': '0.5',
|
expected_dict = {'active': True, 'api_version': '1.0',
|
||||||
'cpu': {'soft_irq': cpu_softirq, 'system': cpu_system,
|
'cpu': {'soft_irq': cpu_softirq, 'system': cpu_system,
|
||||||
'total': cpu_total, 'user': cpu_user},
|
'total': cpu_total, 'user': cpu_user},
|
||||||
'disk': {'available': disk_available,
|
'disk': {'available': disk_available,
|
||||||
|
@ -2699,3 +2637,11 @@ class TestServerTestCase(base.TestCase):
|
||||||
rv = self.centos_app.put('/' + api_server.VERSION +
|
rv = self.centos_app.put('/' + api_server.VERSION +
|
||||||
'/config', data='TestTest')
|
'/config', data='TestTest')
|
||||||
self.assertEqual(500, rv.status_code)
|
self.assertEqual(500, rv.status_code)
|
||||||
|
|
||||||
|
def test_version_discovery(self):
|
||||||
|
self.test_client = server.Server().app.test_client()
|
||||||
|
expected_dict = {'api_version': api_server.VERSION}
|
||||||
|
rv = self.test_client.get('/')
|
||||||
|
self.assertEqual(200, rv.status_code)
|
||||||
|
self.assertEqual(expected_dict,
|
||||||
|
jsonutils.loads(rv.data.decode('utf-8')))
|
||||||
|
|
|
@ -3274,7 +3274,8 @@ class AmphoraRepositoryTest(BaseRepositoryTest):
|
||||||
enabled=True, peer_port=1025, default_pool_id=pool.id)
|
enabled=True, peer_port=1025, default_pool_id=pool.id)
|
||||||
|
|
||||||
listener_ref = {listener.id: {'operating_status': constants.ONLINE,
|
listener_ref = {listener.id: {'operating_status': constants.ONLINE,
|
||||||
'protocol': constants.PROTOCOL_HTTP}}
|
'protocol': constants.PROTOCOL_HTTP,
|
||||||
|
'enabled': 1}}
|
||||||
lb_ref['listeners'] = listener_ref
|
lb_ref['listeners'] = listener_ref
|
||||||
|
|
||||||
# Test with an LB, pool, and listener (no members)
|
# Test with an LB, pool, and listener (no members)
|
||||||
|
|
|
@ -19,13 +19,18 @@ from oslo_utils import uuidutils
|
||||||
|
|
||||||
from octavia.amphorae.backends.agent import api_server
|
from octavia.amphorae.backends.agent import api_server
|
||||||
from octavia.amphorae.backends.agent.api_server import amphora_info
|
from octavia.amphorae.backends.agent.api_server import amphora_info
|
||||||
|
from octavia.amphorae.backends.agent.api_server import util
|
||||||
|
from octavia.common.jinja.haproxy.combined_listeners import jinja_cfg
|
||||||
from octavia.tests.common import utils as test_utils
|
from octavia.tests.common import utils as test_utils
|
||||||
import octavia.tests.unit.base as base
|
import octavia.tests.unit.base as base
|
||||||
|
from octavia.tests.unit.common.sample_configs import sample_configs_combined
|
||||||
|
|
||||||
|
|
||||||
class TestAmphoraInfo(base.TestCase):
|
class TestAmphoraInfo(base.TestCase):
|
||||||
|
|
||||||
API_VERSION = random.randrange(0, 10000)
|
API_VERSION = random.randrange(0, 10000)
|
||||||
|
BASE_AMP_PATH = '/var/lib/octavia'
|
||||||
|
BASE_CRT_PATH = BASE_AMP_PATH + '/certs'
|
||||||
HAPROXY_VERSION = random.randrange(0, 10000)
|
HAPROXY_VERSION = random.randrange(0, 10000)
|
||||||
KEEPALIVED_VERSION = random.randrange(0, 10000)
|
KEEPALIVED_VERSION = random.randrange(0, 10000)
|
||||||
IPVSADM_VERSION = random.randrange(0, 10000)
|
IPVSADM_VERSION = random.randrange(0, 10000)
|
||||||
|
@ -33,6 +38,7 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
FAKE_LISTENER_ID_2 = uuidutils.generate_uuid()
|
FAKE_LISTENER_ID_2 = uuidutils.generate_uuid()
|
||||||
FAKE_LISTENER_ID_3 = uuidutils.generate_uuid()
|
FAKE_LISTENER_ID_3 = uuidutils.generate_uuid()
|
||||||
FAKE_LISTENER_ID_4 = uuidutils.generate_uuid()
|
FAKE_LISTENER_ID_4 = uuidutils.generate_uuid()
|
||||||
|
LB_ID_1 = uuidutils.generate_uuid()
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestAmphoraInfo, self).setUp()
|
super(TestAmphoraInfo, self).setUp()
|
||||||
|
@ -40,6 +46,23 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
self.amp_info = amphora_info.AmphoraInfo(self.osutils_mock)
|
self.amp_info = amphora_info.AmphoraInfo(self.osutils_mock)
|
||||||
self.udp_driver = mock.MagicMock()
|
self.udp_driver = mock.MagicMock()
|
||||||
|
|
||||||
|
# setup a fake haproxy config file
|
||||||
|
templater = jinja_cfg.JinjaTemplater(
|
||||||
|
base_amp_path=self.BASE_AMP_PATH,
|
||||||
|
base_crt_dir=self.BASE_CRT_PATH)
|
||||||
|
tls_tupel = sample_configs_combined.sample_tls_container_tuple(
|
||||||
|
id='tls_container_id',
|
||||||
|
certificate='imaCert1', private_key='imaPrivateKey1',
|
||||||
|
primary_cn='FakeCN')
|
||||||
|
self.rendered_haproxy_cfg = templater.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple(
|
||||||
|
proto='TERMINATED_HTTPS', tls=True, sni=True)],
|
||||||
|
tls_tupel)
|
||||||
|
path = util.config_path(self.LB_ID_1)
|
||||||
|
self.useFixture(test_utils.OpenFixture(path,
|
||||||
|
self.rendered_haproxy_cfg))
|
||||||
|
|
||||||
def _return_version(self, package_name):
|
def _return_version(self, package_name):
|
||||||
if package_name == 'ipvsadm':
|
if package_name == 'ipvsadm':
|
||||||
return self.IPVSADM_VERSION
|
return self.IPVSADM_VERSION
|
||||||
|
@ -138,8 +161,8 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
u'haproxy_count': 5,
|
u'haproxy_count': 5,
|
||||||
u'haproxy_version': self.HAPROXY_VERSION,
|
u'haproxy_version': self.HAPROXY_VERSION,
|
||||||
u'hostname': u'FAKE_HOST',
|
u'hostname': u'FAKE_HOST',
|
||||||
u'listeners': [self.FAKE_LISTENER_ID_1,
|
u'listeners': sorted([self.FAKE_LISTENER_ID_1,
|
||||||
self.FAKE_LISTENER_ID_2],
|
self.FAKE_LISTENER_ID_2]),
|
||||||
u'load': [u'0.09', u'0.11', u'0.10'],
|
u'load': [u'0.09', u'0.11', u'0.10'],
|
||||||
u'memory': {u'buffers': 344792,
|
u'memory': {u'buffers': 344792,
|
||||||
u'cached': 4271856,
|
u'cached': 4271856,
|
||||||
|
@ -163,8 +186,7 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
'get_udp_listeners',
|
'get_udp_listeners',
|
||||||
return_value=[FAKE_LISTENER_ID_3, FAKE_LISTENER_ID_4])
|
return_value=[FAKE_LISTENER_ID_3, FAKE_LISTENER_ID_4])
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_listeners', return_value=[FAKE_LISTENER_ID_1,
|
'get_loadbalancers')
|
||||||
FAKE_LISTENER_ID_2])
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
||||||
'amphora_info.AmphoraInfo._get_meminfo')
|
'amphora_info.AmphoraInfo._get_meminfo')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
||||||
|
@ -182,7 +204,7 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
def test_compile_amphora_details_for_udp(self, mhostname, m_count,
|
def test_compile_amphora_details_for_udp(self, mhostname, m_count,
|
||||||
m_pkg_version, m_load, m_get_nets,
|
m_pkg_version, m_load, m_get_nets,
|
||||||
m_os, m_cpu, mget_mem,
|
m_os, m_cpu, mget_mem,
|
||||||
mget_listener, mget_udp_listener):
|
mock_get_lb, mget_udp_listener):
|
||||||
mget_mem.return_value = {'SwapCached': 0, 'Buffers': 344792,
|
mget_mem.return_value = {'SwapCached': 0, 'Buffers': 344792,
|
||||||
'MemTotal': 21692784, 'Cached': 4271856,
|
'MemTotal': 21692784, 'Cached': 4271856,
|
||||||
'Slab': 534384, 'MemFree': 12685624,
|
'Slab': 534384, 'MemFree': 12685624,
|
||||||
|
@ -205,6 +227,7 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
self.udp_driver.get_subscribed_amp_compile_info.return_value = [
|
self.udp_driver.get_subscribed_amp_compile_info.return_value = [
|
||||||
'keepalived', 'ipvsadm']
|
'keepalived', 'ipvsadm']
|
||||||
self.udp_driver.is_listener_running.side_effect = [True, False]
|
self.udp_driver.is_listener_running.side_effect = [True, False]
|
||||||
|
mock_get_lb.return_value = [self.LB_ID_1]
|
||||||
original_version = api_server.VERSION
|
original_version = api_server.VERSION
|
||||||
api_server.VERSION = self.API_VERSION
|
api_server.VERSION = self.API_VERSION
|
||||||
expected_dict = {u'active': True,
|
expected_dict = {u'active': True,
|
||||||
|
@ -221,10 +244,10 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
u'ipvsadm_version': self.IPVSADM_VERSION,
|
u'ipvsadm_version': self.IPVSADM_VERSION,
|
||||||
u'udp_listener_process_count': 1,
|
u'udp_listener_process_count': 1,
|
||||||
u'hostname': u'FAKE_HOST',
|
u'hostname': u'FAKE_HOST',
|
||||||
u'listeners': list(set([self.FAKE_LISTENER_ID_1,
|
u'listeners': sorted(list(set(
|
||||||
self.FAKE_LISTENER_ID_2,
|
[self.FAKE_LISTENER_ID_3,
|
||||||
self.FAKE_LISTENER_ID_3,
|
self.FAKE_LISTENER_ID_4,
|
||||||
self.FAKE_LISTENER_ID_4])),
|
'sample_listener_id_1']))),
|
||||||
u'load': [u'0.09', u'0.11', u'0.10'],
|
u'load': [u'0.09', u'0.11', u'0.10'],
|
||||||
u'memory': {u'buffers': 344792,
|
u'memory': {u'buffers': 344792,
|
||||||
u'cached': 4271856,
|
u'cached': 4271856,
|
||||||
|
@ -245,7 +268,7 @@ class TestAmphoraInfo(base.TestCase):
|
||||||
api_server.VERSION = original_version
|
api_server.VERSION = original_version
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'is_listener_running')
|
'is_lb_running')
|
||||||
def test__count_haproxy_process(self, mock_is_running):
|
def test__count_haproxy_process(self, mock_is_running):
|
||||||
|
|
||||||
# Test no listeners passed in
|
# Test no listeners passed in
|
||||||
|
|
|
@ -17,7 +17,7 @@ import mock
|
||||||
from octavia.amphorae.backends.agent.api_server import haproxy_compatibility
|
from octavia.amphorae.backends.agent.api_server import haproxy_compatibility
|
||||||
from octavia.common import constants
|
from octavia.common import constants
|
||||||
import octavia.tests.unit.base as base
|
import octavia.tests.unit.base as base
|
||||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
from octavia.tests.unit.common.sample_configs import sample_configs_combined
|
||||||
|
|
||||||
|
|
||||||
class HAProxyCompatTestCase(base.TestCase):
|
class HAProxyCompatTestCase(base.TestCase):
|
||||||
|
@ -30,7 +30,7 @@ class HAProxyCompatTestCase(base.TestCase):
|
||||||
" user nobody\n"
|
" user nobody\n"
|
||||||
" log /dev/log local0\n"
|
" log /dev/log local0\n"
|
||||||
" log /dev/log local1 notice\n"
|
" log /dev/log local1 notice\n"
|
||||||
" stats socket /var/lib/octavia/sample_listener_id_1.sock"
|
" stats socket /var/lib/octavia/sample_loadbalancer_id_1.sock"
|
||||||
" mode 0666 level user\n"
|
" mode 0666 level user\n"
|
||||||
" maxconn {maxconn}\n\n"
|
" maxconn {maxconn}\n\n"
|
||||||
"defaults\n"
|
"defaults\n"
|
||||||
|
@ -47,11 +47,11 @@ class HAProxyCompatTestCase(base.TestCase):
|
||||||
" maxconn {maxconn}\n"
|
" maxconn {maxconn}\n"
|
||||||
" bind 10.0.0.2:80\n"
|
" bind 10.0.0.2:80\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" default_backend sample_pool_id_1\n"
|
" default_backend sample_pool_id_1:sample_listener_id_1\n"
|
||||||
" timeout client 50000\n\n").format(
|
" timeout client 50000\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
self.backend_without_external = (
|
self.backend_without_external = (
|
||||||
"backend sample_pool_id_1\n"
|
"backend sample_pool_id_1:sample_listener_id_1\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" balance roundrobin\n"
|
" balance roundrobin\n"
|
||||||
" cookie SRV insert indirect nocache\n"
|
" cookie SRV insert indirect nocache\n"
|
||||||
|
@ -69,7 +69,7 @@ class HAProxyCompatTestCase(base.TestCase):
|
||||||
"sample_member_id_2\n").format(
|
"sample_member_id_2\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
self.backend_with_external = (
|
self.backend_with_external = (
|
||||||
"backend sample_pool_id_1\n"
|
"backend sample_pool_id_1:sample_listener_id_1\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" balance roundrobin\n"
|
" balance roundrobin\n"
|
||||||
" cookie SRV insert indirect nocache\n"
|
" cookie SRV insert indirect nocache\n"
|
||||||
|
@ -103,7 +103,7 @@ class HAProxyCompatTestCase(base.TestCase):
|
||||||
def test_process_cfg_for_version_compat(self, mock_get_version):
|
def test_process_cfg_for_version_compat(self, mock_get_version):
|
||||||
# Test 1.6 version path, no change to config expected
|
# Test 1.6 version path, no change to config expected
|
||||||
mock_get_version.return_value = [1, 6]
|
mock_get_version.return_value = [1, 6]
|
||||||
test_config = sample_configs.sample_base_expected_config(
|
test_config = sample_configs_combined.sample_base_expected_config(
|
||||||
backend=self.backend_with_external)
|
backend=self.backend_with_external)
|
||||||
result_config = haproxy_compatibility.process_cfg_for_version_compat(
|
result_config = haproxy_compatibility.process_cfg_for_version_compat(
|
||||||
test_config)
|
test_config)
|
||||||
|
@ -111,7 +111,7 @@ class HAProxyCompatTestCase(base.TestCase):
|
||||||
|
|
||||||
# Test 1.5 version path, external-check should be removed
|
# Test 1.5 version path, external-check should be removed
|
||||||
mock_get_version.return_value = [1, 5]
|
mock_get_version.return_value = [1, 5]
|
||||||
test_config = sample_configs.sample_base_expected_config(
|
test_config = sample_configs_combined.sample_base_expected_config(
|
||||||
backend=self.backend_with_external)
|
backend=self.backend_with_external)
|
||||||
result_config = haproxy_compatibility.process_cfg_for_version_compat(
|
result_config = haproxy_compatibility.process_cfg_for_version_compat(
|
||||||
test_config)
|
test_config)
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from werkzeug import exceptions
|
|
||||||
|
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
@ -29,13 +28,6 @@ class KeepalivedLvsTestCase(base.TestCase):
|
||||||
super(KeepalivedLvsTestCase, self).setUp()
|
super(KeepalivedLvsTestCase, self).setUp()
|
||||||
self.test_keepalivedlvs = keepalivedlvs.KeepalivedLvs()
|
self.test_keepalivedlvs = keepalivedlvs.KeepalivedLvs()
|
||||||
|
|
||||||
@mock.patch('os.path.exists')
|
|
||||||
def test_get_udp_listener_status_no_exists(self, m_exist):
|
|
||||||
m_exist.return_value = False
|
|
||||||
self.assertRaises(exceptions.HTTPException,
|
|
||||||
self.test_keepalivedlvs.get_udp_listener_status,
|
|
||||||
self.FAKE_ID)
|
|
||||||
|
|
||||||
@mock.patch.object(keepalivedlvs, "webob")
|
@mock.patch.object(keepalivedlvs, "webob")
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
def test_delete_udp_listener_not_exist(self, m_exist, m_webob):
|
def test_delete_udp_listener_not_exist(self, m_exist, m_webob):
|
||||||
|
|
|
@ -17,141 +17,35 @@ import subprocess
|
||||||
import mock
|
import mock
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from octavia.amphorae.backends.agent.api_server import listener
|
from octavia.amphorae.backends.agent.api_server import loadbalancer
|
||||||
from octavia.amphorae.backends.agent.api_server import util as agent_util
|
from octavia.amphorae.backends.agent.api_server import util as agent_util
|
||||||
from octavia.common import constants as consts
|
from octavia.common import constants as consts
|
||||||
from octavia.common.jinja.haproxy import jinja_cfg
|
|
||||||
from octavia.tests.common import utils as test_utils
|
from octavia.tests.common import utils as test_utils
|
||||||
import octavia.tests.unit.base as base
|
import octavia.tests.unit.base as base
|
||||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
|
||||||
|
|
||||||
BASE_AMP_PATH = '/var/lib/octavia'
|
|
||||||
BASE_CRT_PATH = BASE_AMP_PATH + '/certs'
|
|
||||||
LISTENER_ID1 = uuidutils.generate_uuid()
|
LISTENER_ID1 = uuidutils.generate_uuid()
|
||||||
|
LB_ID1 = uuidutils.generate_uuid()
|
||||||
|
|
||||||
|
|
||||||
class ListenerTestCase(base.TestCase):
|
class ListenerTestCase(base.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ListenerTestCase, self).setUp()
|
super(ListenerTestCase, self).setUp()
|
||||||
self.jinja_cfg = jinja_cfg.JinjaTemplater(
|
|
||||||
base_amp_path=BASE_AMP_PATH,
|
|
||||||
base_crt_dir=BASE_CRT_PATH)
|
|
||||||
self.mock_platform = mock.patch("distro.id").start()
|
self.mock_platform = mock.patch("distro.id").start()
|
||||||
self.mock_platform.return_value = "ubuntu"
|
self.mock_platform.return_value = "ubuntu"
|
||||||
self.test_listener = listener.Listener()
|
self.test_loadbalancer = loadbalancer.Loadbalancer()
|
||||||
|
|
||||||
def test_parse_haproxy_config(self):
|
|
||||||
# template_tls
|
|
||||||
tls_tupe = sample_configs.sample_tls_container_tuple(
|
|
||||||
id='tls_container_id',
|
|
||||||
certificate='imaCert1', private_key='imaPrivateKey1',
|
|
||||||
primary_cn='FakeCN')
|
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
|
||||||
sample_configs.sample_amphora_tuple(),
|
|
||||||
sample_configs.sample_listener_tuple(proto='TERMINATED_HTTPS',
|
|
||||||
tls=True, sni=True),
|
|
||||||
tls_tupe)
|
|
||||||
|
|
||||||
path = agent_util.config_path(LISTENER_ID1)
|
|
||||||
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
|
||||||
|
|
||||||
res = self.test_listener._parse_haproxy_file(LISTENER_ID1)
|
|
||||||
self.assertEqual('TERMINATED_HTTPS', res['mode'])
|
|
||||||
self.assertEqual('/var/lib/octavia/sample_listener_id_1.sock',
|
|
||||||
res['stats_socket'])
|
|
||||||
self.assertEqual(
|
|
||||||
'/var/lib/octavia/certs/sample_listener_id_1/tls_container_id.pem',
|
|
||||||
res['ssl_crt'])
|
|
||||||
|
|
||||||
# render_template_tls_no_sni
|
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
|
||||||
sample_configs.sample_amphora_tuple(),
|
|
||||||
sample_configs.sample_listener_tuple(
|
|
||||||
proto='TERMINATED_HTTPS', tls=True),
|
|
||||||
tls_cert=sample_configs.sample_tls_container_tuple(
|
|
||||||
id='tls_container_id',
|
|
||||||
certificate='ImAalsdkfjCert',
|
|
||||||
private_key='ImAsdlfksdjPrivateKey',
|
|
||||||
primary_cn="FakeCN"))
|
|
||||||
|
|
||||||
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
|
||||||
|
|
||||||
res = self.test_listener._parse_haproxy_file(LISTENER_ID1)
|
|
||||||
self.assertEqual('TERMINATED_HTTPS', res['mode'])
|
|
||||||
self.assertEqual(BASE_AMP_PATH + '/sample_listener_id_1.sock',
|
|
||||||
res['stats_socket'])
|
|
||||||
self.assertEqual(
|
|
||||||
BASE_CRT_PATH + '/sample_listener_id_1/tls_container_id.pem',
|
|
||||||
res['ssl_crt'])
|
|
||||||
|
|
||||||
# render_template_http
|
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
|
||||||
sample_configs.sample_amphora_tuple(),
|
|
||||||
sample_configs.sample_listener_tuple())
|
|
||||||
|
|
||||||
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
|
||||||
|
|
||||||
res = self.test_listener._parse_haproxy_file(LISTENER_ID1)
|
|
||||||
self.assertEqual('HTTP', res['mode'])
|
|
||||||
self.assertEqual(BASE_AMP_PATH + '/sample_listener_id_1.sock',
|
|
||||||
res['stats_socket'])
|
|
||||||
self.assertIsNone(res['ssl_crt'])
|
|
||||||
|
|
||||||
# template_https
|
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
|
||||||
sample_configs.sample_amphora_tuple(),
|
|
||||||
sample_configs.sample_listener_tuple(proto='HTTPS'))
|
|
||||||
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
|
||||||
|
|
||||||
res = self.test_listener._parse_haproxy_file(LISTENER_ID1)
|
|
||||||
self.assertEqual('TCP', res['mode'])
|
|
||||||
self.assertEqual(BASE_AMP_PATH + '/sample_listener_id_1.sock',
|
|
||||||
res['stats_socket'])
|
|
||||||
self.assertIsNone(res['ssl_crt'])
|
|
||||||
|
|
||||||
# Bogus format
|
|
||||||
self.useFixture(test_utils.OpenFixture(path, 'Bogus'))
|
|
||||||
try:
|
|
||||||
res = self.test_listener._parse_haproxy_file(LISTENER_ID1)
|
|
||||||
self.fail("No Exception?")
|
|
||||||
except listener.ParsingError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@mock.patch('os.path.exists')
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server' +
|
|
||||||
'.util.get_haproxy_pid')
|
|
||||||
def test_check_listener_status(self, mock_pid, mock_exists):
|
|
||||||
mock_pid.return_value = '1245'
|
|
||||||
mock_exists.side_effect = [True, True]
|
|
||||||
config_path = agent_util.config_path(LISTENER_ID1)
|
|
||||||
file_contents = 'frontend {}'.format(LISTENER_ID1)
|
|
||||||
self.useFixture(test_utils.OpenFixture(config_path, file_contents))
|
|
||||||
self.assertEqual(
|
|
||||||
consts.ACTIVE,
|
|
||||||
self.test_listener._check_listener_status(LISTENER_ID1))
|
|
||||||
|
|
||||||
mock_exists.side_effect = [True, False]
|
|
||||||
self.assertEqual(
|
|
||||||
consts.ERROR,
|
|
||||||
self.test_listener._check_listener_status(LISTENER_ID1))
|
|
||||||
|
|
||||||
mock_exists.side_effect = [False]
|
|
||||||
self.assertEqual(
|
|
||||||
consts.OFFLINE,
|
|
||||||
self.test_listener._check_listener_status(LISTENER_ID1))
|
|
||||||
|
|
||||||
@mock.patch('os.makedirs')
|
@mock.patch('os.makedirs')
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
@mock.patch('os.listdir')
|
@mock.patch('os.listdir')
|
||||||
@mock.patch('os.path.join')
|
@mock.patch('os.path.join')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
'get_listeners')
|
'get_loadbalancers')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util'
|
||||||
'.haproxy_sock_path')
|
'.haproxy_sock_path')
|
||||||
def test_vrrp_check_script_update(self, mock_sock_path, mock_get_listeners,
|
def test_vrrp_check_script_update(self, mock_sock_path, mock_get_lbs,
|
||||||
mock_join, mock_listdir, mock_exists,
|
mock_join, mock_listdir, mock_exists,
|
||||||
mock_makedirs):
|
mock_makedirs):
|
||||||
mock_get_listeners.return_value = ['abc', LISTENER_ID1]
|
mock_get_lbs.return_value = ['abc', LB_ID1]
|
||||||
mock_sock_path.return_value = 'listener.sock'
|
mock_sock_path.return_value = 'listener.sock'
|
||||||
mock_exists.return_value = False
|
mock_exists.return_value = False
|
||||||
cmd = 'haproxy-vrrp-check ' + ' '.join(['listener.sock']) + '; exit $?'
|
cmd = 'haproxy-vrrp-check ' + ' '.join(['listener.sock']) + '; exit $?'
|
||||||
|
@ -159,17 +53,17 @@ class ListenerTestCase(base.TestCase):
|
||||||
path = agent_util.keepalived_dir()
|
path = agent_util.keepalived_dir()
|
||||||
m = self.useFixture(test_utils.OpenFixture(path)).mock_open
|
m = self.useFixture(test_utils.OpenFixture(path)).mock_open
|
||||||
|
|
||||||
self.test_listener.vrrp_check_script_update(LISTENER_ID1, 'stop')
|
self.test_loadbalancer.vrrp_check_script_update(LB_ID1, 'stop')
|
||||||
handle = m()
|
handle = m()
|
||||||
handle.write.assert_called_once_with(cmd)
|
handle.write.assert_called_once_with(cmd)
|
||||||
|
|
||||||
mock_get_listeners.return_value = ['abc', LISTENER_ID1]
|
mock_get_lbs.return_value = ['abc', LB_ID1]
|
||||||
cmd = ('haproxy-vrrp-check ' + ' '.join(['listener.sock',
|
cmd = ('haproxy-vrrp-check ' + ' '.join(['listener.sock',
|
||||||
'listener.sock']) + '; exit '
|
'listener.sock']) + '; exit '
|
||||||
'$?')
|
'$?')
|
||||||
|
|
||||||
m = self.useFixture(test_utils.OpenFixture(path)).mock_open
|
m = self.useFixture(test_utils.OpenFixture(path)).mock_open
|
||||||
self.test_listener.vrrp_check_script_update(LISTENER_ID1, 'start')
|
self.test_loadbalancer.vrrp_check_script_update(LB_ID1, 'start')
|
||||||
handle = m()
|
handle = m()
|
||||||
handle.write.assert_called_once_with(cmd)
|
handle.write.assert_called_once_with(cmd)
|
||||||
|
|
||||||
|
@ -181,29 +75,29 @@ class ListenerTestCase(base.TestCase):
|
||||||
mock_exists.side_effect = [True, True]
|
mock_exists.side_effect = [True, True]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
consts.ACTIVE,
|
consts.ACTIVE,
|
||||||
self.test_listener._check_haproxy_status(LISTENER_ID1))
|
self.test_loadbalancer._check_haproxy_status(LISTENER_ID1))
|
||||||
|
|
||||||
mock_exists.side_effect = [True, False]
|
mock_exists.side_effect = [True, False]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
consts.OFFLINE,
|
consts.OFFLINE,
|
||||||
self.test_listener._check_haproxy_status(LISTENER_ID1))
|
self.test_loadbalancer._check_haproxy_status(LISTENER_ID1))
|
||||||
|
|
||||||
mock_exists.side_effect = [False]
|
mock_exists.side_effect = [False]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
consts.OFFLINE,
|
consts.OFFLINE,
|
||||||
self.test_listener._check_haproxy_status(LISTENER_ID1))
|
self.test_loadbalancer._check_haproxy_status(LISTENER_ID1))
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'_check_haproxy_status')
|
'Loadbalancer._check_haproxy_status')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'vrrp_check_script_update')
|
'Loadbalancer.vrrp_check_script_update')
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.loadbalancer.'
|
||||||
'_check_listener_exists')
|
'Loadbalancer._check_lb_exists')
|
||||||
@mock.patch('subprocess.check_output')
|
@mock.patch('subprocess.check_output')
|
||||||
def test_start_stop_listener(self, mock_check_output, mock_list_exists,
|
def test_start_stop_lb(self, mock_check_output, mock_lb_exists,
|
||||||
mock_path_exists, mock_vrrp_update,
|
mock_path_exists, mock_vrrp_update,
|
||||||
mock_check_status):
|
mock_check_status):
|
||||||
listener_id = uuidutils.generate_uuid()
|
listener_id = uuidutils.generate_uuid()
|
||||||
|
|
||||||
mock_path_exists.side_effect = [False, True, True, False, False]
|
mock_path_exists.side_effect = [False, True, True, False, False]
|
||||||
|
@ -214,12 +108,12 @@ class ListenerTestCase(base.TestCase):
|
||||||
ref_command_split.append('haproxy-{}'.format(listener_id))
|
ref_command_split.append('haproxy-{}'.format(listener_id))
|
||||||
ref_command_split.append(consts.AMP_ACTION_START)
|
ref_command_split.append(consts.AMP_ACTION_START)
|
||||||
|
|
||||||
result = self.test_listener.start_stop_listener(
|
result = self.test_loadbalancer.start_stop_lb(
|
||||||
listener_id, consts.AMP_ACTION_START)
|
listener_id, consts.AMP_ACTION_START)
|
||||||
|
|
||||||
mock_check_output.assert_called_once_with(ref_command_split,
|
mock_check_output.assert_called_once_with(ref_command_split,
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
mock_list_exists.assert_called_once_with(listener_id)
|
mock_lb_exists.assert_called_once_with(listener_id)
|
||||||
mock_vrrp_update.assert_not_called()
|
mock_vrrp_update.assert_not_called()
|
||||||
self.assertEqual(202, result.status_code)
|
self.assertEqual(202, result.status_code)
|
||||||
self.assertEqual('OK', result.json['message'])
|
self.assertEqual('OK', result.json['message'])
|
||||||
|
@ -228,7 +122,7 @@ class ListenerTestCase(base.TestCase):
|
||||||
self.assertEqual(ref_details, result.json['details'])
|
self.assertEqual(ref_details, result.json['details'])
|
||||||
|
|
||||||
# Happy path - VRRP - RELOAD
|
# Happy path - VRRP - RELOAD
|
||||||
mock_list_exists.reset_mock()
|
mock_lb_exists.reset_mock()
|
||||||
mock_vrrp_update.reset_mock()
|
mock_vrrp_update.reset_mock()
|
||||||
mock_check_output.reset_mock()
|
mock_check_output.reset_mock()
|
||||||
|
|
||||||
|
@ -236,12 +130,12 @@ class ListenerTestCase(base.TestCase):
|
||||||
ref_command_split.append('haproxy-{}'.format(listener_id))
|
ref_command_split.append('haproxy-{}'.format(listener_id))
|
||||||
ref_command_split.append(consts.AMP_ACTION_RELOAD)
|
ref_command_split.append(consts.AMP_ACTION_RELOAD)
|
||||||
|
|
||||||
result = self.test_listener.start_stop_listener(
|
result = self.test_loadbalancer.start_stop_lb(
|
||||||
listener_id, consts.AMP_ACTION_RELOAD)
|
listener_id, consts.AMP_ACTION_RELOAD)
|
||||||
|
|
||||||
mock_check_output.assert_called_once_with(ref_command_split,
|
mock_check_output.assert_called_once_with(ref_command_split,
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
mock_list_exists.assert_called_once_with(listener_id)
|
mock_lb_exists.assert_called_once_with(listener_id)
|
||||||
mock_vrrp_update.assert_called_once_with(listener_id,
|
mock_vrrp_update.assert_called_once_with(listener_id,
|
||||||
consts.AMP_ACTION_RELOAD)
|
consts.AMP_ACTION_RELOAD)
|
||||||
self.assertEqual(202, result.status_code)
|
self.assertEqual(202, result.status_code)
|
||||||
|
@ -251,7 +145,7 @@ class ListenerTestCase(base.TestCase):
|
||||||
self.assertEqual(ref_details, result.json['details'])
|
self.assertEqual(ref_details, result.json['details'])
|
||||||
|
|
||||||
# Happy path - VRRP - RELOAD - OFFLINE
|
# Happy path - VRRP - RELOAD - OFFLINE
|
||||||
mock_list_exists.reset_mock()
|
mock_lb_exists.reset_mock()
|
||||||
mock_vrrp_update.reset_mock()
|
mock_vrrp_update.reset_mock()
|
||||||
mock_check_output.reset_mock()
|
mock_check_output.reset_mock()
|
||||||
|
|
||||||
|
@ -259,12 +153,12 @@ class ListenerTestCase(base.TestCase):
|
||||||
ref_command_split.append('haproxy-{}'.format(listener_id))
|
ref_command_split.append('haproxy-{}'.format(listener_id))
|
||||||
ref_command_split.append(consts.AMP_ACTION_START)
|
ref_command_split.append(consts.AMP_ACTION_START)
|
||||||
|
|
||||||
result = self.test_listener.start_stop_listener(
|
result = self.test_loadbalancer.start_stop_lb(
|
||||||
listener_id, consts.AMP_ACTION_RELOAD)
|
listener_id, consts.AMP_ACTION_RELOAD)
|
||||||
|
|
||||||
mock_check_output.assert_called_once_with(ref_command_split,
|
mock_check_output.assert_called_once_with(ref_command_split,
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
mock_list_exists.assert_called_once_with(listener_id)
|
mock_lb_exists.assert_called_once_with(listener_id)
|
||||||
mock_vrrp_update.assert_called_once_with(listener_id,
|
mock_vrrp_update.assert_called_once_with(listener_id,
|
||||||
consts.AMP_ACTION_RELOAD)
|
consts.AMP_ACTION_RELOAD)
|
||||||
self.assertEqual(202, result.status_code)
|
self.assertEqual(202, result.status_code)
|
||||||
|
@ -274,7 +168,7 @@ class ListenerTestCase(base.TestCase):
|
||||||
self.assertEqual(ref_details, result.json['details'])
|
self.assertEqual(ref_details, result.json['details'])
|
||||||
|
|
||||||
# Unhappy path - Not already running
|
# Unhappy path - Not already running
|
||||||
mock_list_exists.reset_mock()
|
mock_lb_exists.reset_mock()
|
||||||
mock_vrrp_update.reset_mock()
|
mock_vrrp_update.reset_mock()
|
||||||
mock_check_output.reset_mock()
|
mock_check_output.reset_mock()
|
||||||
|
|
||||||
|
@ -285,12 +179,12 @@ class ListenerTestCase(base.TestCase):
|
||||||
mock_check_output.side_effect = subprocess.CalledProcessError(
|
mock_check_output.side_effect = subprocess.CalledProcessError(
|
||||||
output=b'bogus', returncode=-2, cmd='sit')
|
output=b'bogus', returncode=-2, cmd='sit')
|
||||||
|
|
||||||
result = self.test_listener.start_stop_listener(
|
result = self.test_loadbalancer.start_stop_lb(
|
||||||
listener_id, consts.AMP_ACTION_START)
|
listener_id, consts.AMP_ACTION_START)
|
||||||
|
|
||||||
mock_check_output.assert_called_once_with(ref_command_split,
|
mock_check_output.assert_called_once_with(ref_command_split,
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
mock_list_exists.assert_called_once_with(listener_id)
|
mock_lb_exists.assert_called_once_with(listener_id)
|
||||||
mock_vrrp_update.assert_not_called()
|
mock_vrrp_update.assert_not_called()
|
||||||
self.assertEqual(500, result.status_code)
|
self.assertEqual(500, result.status_code)
|
||||||
self.assertEqual('Error {}ing haproxy'.format(consts.AMP_ACTION_START),
|
self.assertEqual('Error {}ing haproxy'.format(consts.AMP_ACTION_START),
|
||||||
|
@ -298,7 +192,7 @@ class ListenerTestCase(base.TestCase):
|
||||||
self.assertEqual('bogus', result.json['details'])
|
self.assertEqual('bogus', result.json['details'])
|
||||||
|
|
||||||
# Unhappy path - Already running
|
# Unhappy path - Already running
|
||||||
mock_list_exists.reset_mock()
|
mock_lb_exists.reset_mock()
|
||||||
mock_vrrp_update.reset_mock()
|
mock_vrrp_update.reset_mock()
|
||||||
mock_check_output.reset_mock()
|
mock_check_output.reset_mock()
|
||||||
|
|
||||||
|
@ -309,12 +203,12 @@ class ListenerTestCase(base.TestCase):
|
||||||
mock_check_output.side_effect = subprocess.CalledProcessError(
|
mock_check_output.side_effect = subprocess.CalledProcessError(
|
||||||
output=b'Job is already running', returncode=-2, cmd='sit')
|
output=b'Job is already running', returncode=-2, cmd='sit')
|
||||||
|
|
||||||
result = self.test_listener.start_stop_listener(
|
result = self.test_loadbalancer.start_stop_lb(
|
||||||
listener_id, consts.AMP_ACTION_START)
|
listener_id, consts.AMP_ACTION_START)
|
||||||
|
|
||||||
mock_check_output.assert_called_once_with(ref_command_split,
|
mock_check_output.assert_called_once_with(ref_command_split,
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
mock_list_exists.assert_called_once_with(listener_id)
|
mock_lb_exists.assert_called_once_with(listener_id)
|
||||||
mock_vrrp_update.assert_not_called()
|
mock_vrrp_update.assert_not_called()
|
||||||
self.assertEqual(202, result.status_code)
|
self.assertEqual(202, result.status_code)
|
||||||
self.assertEqual('OK', result.json['message'])
|
self.assertEqual('OK', result.json['message'])
|
||||||
|
@ -324,14 +218,62 @@ class ListenerTestCase(base.TestCase):
|
||||||
|
|
||||||
# Invalid action
|
# Invalid action
|
||||||
mock_check_output.reset_mock()
|
mock_check_output.reset_mock()
|
||||||
mock_list_exists.reset_mock()
|
mock_lb_exists.reset_mock()
|
||||||
mock_path_exists.reset_mock()
|
mock_path_exists.reset_mock()
|
||||||
mock_vrrp_update.reset_mock()
|
mock_vrrp_update.reset_mock()
|
||||||
result = self.test_listener.start_stop_listener(listener_id, 'bogus')
|
result = self.test_loadbalancer.start_stop_lb(listener_id, 'bogus')
|
||||||
self.assertEqual(400, result.status_code)
|
self.assertEqual(400, result.status_code)
|
||||||
self.assertEqual('Invalid Request', result.json['message'])
|
self.assertEqual('Invalid Request', result.json['message'])
|
||||||
self.assertEqual('Unknown action: bogus', result.json['details'])
|
self.assertEqual('Unknown action: bogus', result.json['details'])
|
||||||
mock_list_exists.assert_not_called()
|
mock_lb_exists.assert_not_called()
|
||||||
mock_path_exists.assert_not_called()
|
mock_path_exists.assert_not_called()
|
||||||
mock_vrrp_update.assert_not_called()
|
mock_vrrp_update.assert_not_called()
|
||||||
mock_check_output.assert_not_called()
|
mock_check_output.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
|
'config_path')
|
||||||
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||||
|
'get_haproxy_pid')
|
||||||
|
@mock.patch('os.path.exists')
|
||||||
|
def test_get_listeners_on_lb(self, mock_exists, mock_get_haproxy_pid,
|
||||||
|
mock_config_path):
|
||||||
|
|
||||||
|
fake_cfg_path = '/some/fake/cfg/file.cfg'
|
||||||
|
mock_config_path.return_value = fake_cfg_path
|
||||||
|
mock_get_haproxy_pid.return_value = 'fake_pid'
|
||||||
|
|
||||||
|
# Finds two listeners
|
||||||
|
mock_exists.side_effect = [True, True]
|
||||||
|
fake_cfg_data = 'frontend list1\nbackend foo\nfrontend list2'
|
||||||
|
self.useFixture(
|
||||||
|
test_utils.OpenFixture(fake_cfg_path, fake_cfg_data)).mock_open
|
||||||
|
result = self.test_loadbalancer._get_listeners_on_lb(LB_ID1)
|
||||||
|
self.assertEqual(['list1', 'list2'], result)
|
||||||
|
mock_exists.assert_has_calls([mock.call(agent_util.pid_path(LB_ID1)),
|
||||||
|
mock.call('/proc/fake_pid')])
|
||||||
|
|
||||||
|
# No PID file, no listeners
|
||||||
|
mock_exists.reset_mock()
|
||||||
|
mock_exists.side_effect = [False]
|
||||||
|
result = self.test_loadbalancer._get_listeners_on_lb(LB_ID1)
|
||||||
|
self.assertEqual([], result)
|
||||||
|
mock_exists.assert_called_once_with(agent_util.pid_path(LB_ID1))
|
||||||
|
|
||||||
|
# PID file, no running process, no listeners
|
||||||
|
mock_exists.reset_mock()
|
||||||
|
mock_exists.side_effect = [True, False]
|
||||||
|
result = self.test_loadbalancer._get_listeners_on_lb(LB_ID1)
|
||||||
|
self.assertEqual([], result)
|
||||||
|
mock_exists.assert_has_calls([mock.call(agent_util.pid_path(LB_ID1)),
|
||||||
|
mock.call('/proc/fake_pid')])
|
||||||
|
|
||||||
|
# PID file, running process, no listeners
|
||||||
|
mock_exists.reset_mock()
|
||||||
|
mock_exists.side_effect = [True, True]
|
||||||
|
fake_cfg_data = 'backend only'
|
||||||
|
self.useFixture(
|
||||||
|
test_utils.OpenFixture(fake_cfg_path, fake_cfg_data)).mock_open
|
||||||
|
result = self.test_loadbalancer._get_listeners_on_lb(LB_ID1)
|
||||||
|
self.assertEqual([], result)
|
||||||
|
mock_exists.assert_has_calls([mock.call(agent_util.pid_path(LB_ID1)),
|
||||||
|
mock.call('/proc/fake_pid')])
|
|
@ -22,11 +22,15 @@ from oslo_utils import uuidutils
|
||||||
|
|
||||||
from octavia.amphorae.backends.agent.api_server import util
|
from octavia.amphorae.backends.agent.api_server import util
|
||||||
from octavia.common import constants as consts
|
from octavia.common import constants as consts
|
||||||
|
from octavia.common.jinja.haproxy.combined_listeners import jinja_cfg
|
||||||
from octavia.tests.common import utils as test_utils
|
from octavia.tests.common import utils as test_utils
|
||||||
import octavia.tests.unit.base as base
|
import octavia.tests.unit.base as base
|
||||||
|
from octavia.tests.unit.common.sample_configs import sample_configs_combined
|
||||||
|
|
||||||
|
BASE_AMP_PATH = '/var/lib/octavia'
|
||||||
|
BASE_CRT_PATH = BASE_AMP_PATH + '/certs'
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
LISTENER_ID1 = uuidutils.generate_uuid()
|
||||||
|
|
||||||
|
|
||||||
class TestUtil(base.TestCase):
|
class TestUtil(base.TestCase):
|
||||||
|
@ -34,6 +38,9 @@ class TestUtil(base.TestCase):
|
||||||
super(TestUtil, self).setUp()
|
super(TestUtil, self).setUp()
|
||||||
self.CONF = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
self.CONF = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||||
self.listener_id = uuidutils.generate_uuid()
|
self.listener_id = uuidutils.generate_uuid()
|
||||||
|
self.jinja_cfg = jinja_cfg.JinjaTemplater(
|
||||||
|
base_amp_path=BASE_AMP_PATH,
|
||||||
|
base_crt_dir=BASE_CRT_PATH)
|
||||||
|
|
||||||
def test_keepalived_lvs_dir(self):
|
def test_keepalived_lvs_dir(self):
|
||||||
fake_path = '/fake/path'
|
fake_path = '/fake/path'
|
||||||
|
@ -171,7 +178,7 @@ class TestUtil(base.TestCase):
|
||||||
mock_cfg_path.return_value = '/there'
|
mock_cfg_path.return_value = '/there'
|
||||||
mock_path_exists.side_effect = [True, False, True, False, False]
|
mock_path_exists.side_effect = [True, False, True, False, False]
|
||||||
|
|
||||||
result = util.get_listener_protocol('1')
|
result = util.get_protocol_for_lb_object('1')
|
||||||
|
|
||||||
mock_cfg_path.assert_called_once_with('1')
|
mock_cfg_path.assert_called_once_with('1')
|
||||||
mock_path_exists.assert_called_once_with('/there')
|
mock_path_exists.assert_called_once_with('/there')
|
||||||
|
@ -180,7 +187,7 @@ class TestUtil(base.TestCase):
|
||||||
|
|
||||||
mock_cfg_path.reset_mock()
|
mock_cfg_path.reset_mock()
|
||||||
|
|
||||||
result = util.get_listener_protocol('2')
|
result = util.get_protocol_for_lb_object('2')
|
||||||
|
|
||||||
mock_cfg_path.assert_called_once_with('2')
|
mock_cfg_path.assert_called_once_with('2')
|
||||||
mock_lvs_path.assert_called_once_with('2')
|
mock_lvs_path.assert_called_once_with('2')
|
||||||
|
@ -189,8 +196,97 @@ class TestUtil(base.TestCase):
|
||||||
mock_cfg_path.reset_mock()
|
mock_cfg_path.reset_mock()
|
||||||
mock_lvs_path.reset_mock()
|
mock_lvs_path.reset_mock()
|
||||||
|
|
||||||
result = util.get_listener_protocol('3')
|
result = util.get_protocol_for_lb_object('3')
|
||||||
|
|
||||||
mock_cfg_path.assert_called_once_with('3')
|
mock_cfg_path.assert_called_once_with('3')
|
||||||
mock_lvs_path.assert_called_once_with('3')
|
mock_lvs_path.assert_called_once_with('3')
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
def test_parse_haproxy_config(self):
|
||||||
|
# template_tls
|
||||||
|
tls_tupe = sample_configs_combined.sample_tls_container_tuple(
|
||||||
|
id='tls_container_id',
|
||||||
|
certificate='imaCert1', private_key='imaPrivateKey1',
|
||||||
|
primary_cn='FakeCN')
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple(
|
||||||
|
proto='TERMINATED_HTTPS', tls=True, sni=True)],
|
||||||
|
tls_tupe)
|
||||||
|
|
||||||
|
path = util.config_path(LISTENER_ID1)
|
||||||
|
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
||||||
|
|
||||||
|
res = util.parse_haproxy_file(LISTENER_ID1)
|
||||||
|
listener_dict = res[1]['sample_listener_id_1']
|
||||||
|
self.assertEqual('TERMINATED_HTTPS', listener_dict['mode'])
|
||||||
|
self.assertEqual('/var/lib/octavia/sample_loadbalancer_id_1.sock',
|
||||||
|
res[0])
|
||||||
|
self.assertEqual(
|
||||||
|
'/var/lib/octavia/certs/sample_loadbalancer_id_1/'
|
||||||
|
'tls_container_id.pem crt /var/lib/octavia/certs/'
|
||||||
|
'sample_loadbalancer_id_1',
|
||||||
|
listener_dict['ssl_crt'])
|
||||||
|
|
||||||
|
# render_template_tls_no_sni
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple(
|
||||||
|
proto='TERMINATED_HTTPS', tls=True)],
|
||||||
|
tls_cert=sample_configs_combined.sample_tls_container_tuple(
|
||||||
|
id='tls_container_id',
|
||||||
|
certificate='ImAalsdkfjCert',
|
||||||
|
private_key='ImAsdlfksdjPrivateKey',
|
||||||
|
primary_cn="FakeCN"))
|
||||||
|
|
||||||
|
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
||||||
|
|
||||||
|
res = util.parse_haproxy_file(LISTENER_ID1)
|
||||||
|
listener_dict = res[1]['sample_listener_id_1']
|
||||||
|
self.assertEqual('TERMINATED_HTTPS', listener_dict['mode'])
|
||||||
|
self.assertEqual(BASE_AMP_PATH + '/sample_loadbalancer_id_1.sock',
|
||||||
|
res[0])
|
||||||
|
self.assertEqual(
|
||||||
|
BASE_CRT_PATH + '/sample_loadbalancer_id_1/tls_container_id.pem',
|
||||||
|
listener_dict['ssl_crt'])
|
||||||
|
|
||||||
|
# render_template_http
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple()])
|
||||||
|
|
||||||
|
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
||||||
|
|
||||||
|
res = util.parse_haproxy_file(LISTENER_ID1)
|
||||||
|
listener_dict = res[1]['sample_listener_id_1']
|
||||||
|
self.assertEqual('HTTP', listener_dict['mode'])
|
||||||
|
self.assertEqual(BASE_AMP_PATH + '/sample_loadbalancer_id_1.sock',
|
||||||
|
res[0])
|
||||||
|
self.assertIsNone(listener_dict.get('ssl_crt', None))
|
||||||
|
|
||||||
|
# template_https
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple(proto='HTTPS')])
|
||||||
|
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
|
||||||
|
|
||||||
|
res = util.parse_haproxy_file(LISTENER_ID1)
|
||||||
|
listener_dict = res[1]['sample_listener_id_1']
|
||||||
|
self.assertEqual('TCP', listener_dict['mode'])
|
||||||
|
self.assertEqual(BASE_AMP_PATH + '/sample_loadbalancer_id_1.sock',
|
||||||
|
res[0])
|
||||||
|
self.assertIsNone(listener_dict.get('ssl_crt', None))
|
||||||
|
|
||||||
|
# Bogus format
|
||||||
|
self.useFixture(test_utils.OpenFixture(path, 'Bogus'))
|
||||||
|
try:
|
||||||
|
res = util.parse_haproxy_file(LISTENER_ID1)
|
||||||
|
self.fail("No Exception?")
|
||||||
|
except util.ParsingError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Bad listener mode
|
||||||
|
fake_cfg = 'stats socket foo\nfrontend {}\nmode\n'.format(LISTENER_ID1)
|
||||||
|
self.useFixture(test_utils.OpenFixture(path, fake_cfg))
|
||||||
|
self.assertRaises(util.ParsingError, util.parse_haproxy_file,
|
||||||
|
LISTENER_ID1)
|
||||||
|
|
|
@ -52,7 +52,7 @@ SAMPLE_STATS = ({'': '', 'status': 'OPEN', 'lastchg': '',
|
||||||
'rate': '0', 'req_rate': '0', 'check_status': '',
|
'rate': '0', 'req_rate': '0', 'check_status': '',
|
||||||
'econ': '', 'comp_out': '0', 'wredis': '', 'dresp': '0',
|
'econ': '', 'comp_out': '0', 'wredis': '', 'dresp': '0',
|
||||||
'ereq': '0', 'tracked': '', 'comp_in': '0',
|
'ereq': '0', 'tracked': '', 'comp_in': '0',
|
||||||
'pxname': '490b6ae7-21aa-43f1-b82a-68ddcd2ca2fb',
|
'pxname': LISTENER_ID1,
|
||||||
'dreq': '0', 'hrsp_5xx': '0', 'last_chk': '',
|
'dreq': '0', 'hrsp_5xx': '0', 'last_chk': '',
|
||||||
'check_code': '', 'sid': '0', 'bout': '0', 'hrsp_1xx': '0',
|
'check_code': '', 'sid': '0', 'bout': '0', 'hrsp_1xx': '0',
|
||||||
'qlimit': '', 'hrsp_other': '0', 'bin': '0', 'rtime': '',
|
'qlimit': '', 'hrsp_other': '0', 'bin': '0', 'rtime': '',
|
||||||
|
@ -107,25 +107,16 @@ SAMPLE_STATS = ({'': '', 'status': 'OPEN', 'lastchg': '',
|
||||||
SAMPLE_STATS_MSG = {
|
SAMPLE_STATS_MSG = {
|
||||||
'listeners': {
|
'listeners': {
|
||||||
LISTENER_ID1: {
|
LISTENER_ID1: {
|
||||||
'pools': {
|
|
||||||
'432fc8b3-d446-48d4-bb64-13beb90e22bc': {
|
|
||||||
'members': {
|
|
||||||
'302e33d9-dee1-4de9-98d5-36329a06fb58': 'DOWN'},
|
|
||||||
'status': 'UP'}},
|
|
||||||
'stats': {
|
'stats': {
|
||||||
'totconns': 0, 'conns': 0,
|
'totconns': 0, 'conns': 0,
|
||||||
'tx': 0, 'rx': 0, 'ereq': 0},
|
'tx': 0, 'rx': 0, 'ereq': 0},
|
||||||
'status': 'OPEN'},
|
'status': 'OPEN'},
|
||||||
LISTENER_ID2: {
|
},
|
||||||
'pools': {
|
'pools': {'432fc8b3-d446-48d4-bb64-13beb90e22bc': {
|
||||||
'432fc8b3-d446-48d4-bb64-13beb90e22bc': {
|
'members': {'302e33d9-dee1-4de9-98d5-36329a06fb58': 'DOWN'},
|
||||||
'members': {
|
'status': 'UP'}, '432fc8b3-d446-48d4-bb64-13beb90e22bc': {
|
||||||
'302e33d9-dee1-4de9-98d5-36329a06fb58': 'DOWN'},
|
'members': {'302e33d9-dee1-4de9-98d5-36329a06fb58': 'DOWN'},
|
||||||
'status': 'UP'}},
|
'status': 'UP'},
|
||||||
'stats': {
|
|
||||||
'totconns': 0, 'conns': 0,
|
|
||||||
'tx': 0, 'rx': 0, 'ereq': 0},
|
|
||||||
'status': 'OPEN'}
|
|
||||||
},
|
},
|
||||||
'id': None,
|
'id': None,
|
||||||
'seq': 0,
|
'seq': 0,
|
||||||
|
@ -141,7 +132,7 @@ class TestHealthDaemon(base.TestCase):
|
||||||
conf.config(group="haproxy_amphora", base_path=BASE_PATH)
|
conf.config(group="haproxy_amphora", base_path=BASE_PATH)
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.'
|
@mock.patch('octavia.amphorae.backends.agent.'
|
||||||
'api_server.util.get_listeners')
|
'api_server.util.get_loadbalancers')
|
||||||
def test_list_sock_stat_files(self, mock_get_listener):
|
def test_list_sock_stat_files(self, mock_get_listener):
|
||||||
mock_get_listener.return_value = LISTENER_IDS
|
mock_get_listener.return_value = LISTENER_IDS
|
||||||
|
|
||||||
|
@ -297,7 +288,7 @@ class TestHealthDaemon(base.TestCase):
|
||||||
stats_query_mock.get_pool_status.assert_called_once_with()
|
stats_query_mock.get_pool_status.assert_called_once_with()
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
||||||
'util.is_listener_running')
|
'util.is_lb_running')
|
||||||
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
||||||
'health_daemon.get_stats')
|
'health_daemon.get_stats')
|
||||||
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
||||||
|
@ -318,7 +309,7 @@ class TestHealthDaemon(base.TestCase):
|
||||||
mock_get_stats.assert_any_call('TEST2')
|
mock_get_stats.assert_any_call('TEST2')
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
||||||
'util.is_listener_running')
|
'util.is_lb_running')
|
||||||
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
||||||
'health_daemon.get_stats')
|
'health_daemon.get_stats')
|
||||||
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
||||||
|
@ -336,25 +327,6 @@ class TestHealthDaemon(base.TestCase):
|
||||||
|
|
||||||
self.assertEqual(1, mock_get_stats.call_count)
|
self.assertEqual(1, mock_get_stats.call_count)
|
||||||
|
|
||||||
@mock.patch('octavia.amphorae.backends.agent.api_server.'
|
|
||||||
'util.is_listener_running')
|
|
||||||
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
|
||||||
'health_daemon.get_stats')
|
|
||||||
@mock.patch('octavia.amphorae.backends.health_daemon.'
|
|
||||||
'health_daemon.list_sock_stat_files')
|
|
||||||
def test_build_stats_message_mismatch_pool(self, mock_list_files,
|
|
||||||
mock_get_stats,
|
|
||||||
mock_is_running):
|
|
||||||
mock_list_files.return_value = {LISTENER_ID1: 'TEST',
|
|
||||||
LISTENER_ID2: 'TEST2'}
|
|
||||||
|
|
||||||
mock_is_running.return_value = True
|
|
||||||
mock_get_stats.return_value = SAMPLE_STATS, SAMPLE_BOGUS_POOL_STATUS
|
|
||||||
|
|
||||||
msg = health_daemon.build_stats_message()
|
|
||||||
|
|
||||||
self.assertEqual({}, msg['listeners'][LISTENER_ID1]['pools'])
|
|
||||||
|
|
||||||
@mock.patch("octavia.amphorae.backends.utils.keepalivedlvs_query."
|
@mock.patch("octavia.amphorae.backends.utils.keepalivedlvs_query."
|
||||||
"get_udp_listener_pool_status")
|
"get_udp_listener_pool_status")
|
||||||
@mock.patch("octavia.amphorae.backends.utils.keepalivedlvs_query."
|
@mock.patch("octavia.amphorae.backends.utils.keepalivedlvs_query."
|
||||||
|
@ -411,7 +383,7 @@ class TestHealthDaemon(base.TestCase):
|
||||||
'status': constants.DOWN,
|
'status': constants.DOWN,
|
||||||
'pools': {},
|
'pools': {},
|
||||||
'stats': {'conns': 0, 'totconns': 0, 'ereq': 0,
|
'stats': {'conns': 0, 'totconns': 0, 'ereq': 0,
|
||||||
'rx': 0, 'tx': 0}}}, 'id': None,
|
'rx': 0, 'tx': 0}}}, 'pools': {}, 'id': None,
|
||||||
'seq': mock.ANY, 'ver': health_daemon.MSG_VER}
|
'seq': mock.ANY, 'ver': health_daemon.MSG_VER}
|
||||||
msg = health_daemon.build_stats_message()
|
msg = health_daemon.build_stats_message()
|
||||||
self.assertEqual(expected, msg)
|
self.assertEqual(expected, msg)
|
||||||
|
|
|
@ -29,22 +29,29 @@ STATS_SOCKET_SAMPLE = (
|
||||||
"_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot"
|
"_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot"
|
||||||
",cli_abrt,srv_abrt,comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,"
|
",cli_abrt,srv_abrt,comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,"
|
||||||
"last_agt,qtime,ctime,rtime,ttime,\n"
|
"last_agt,qtime,ctime,rtime,ttime,\n"
|
||||||
"http-servers,id-34821,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,1,1,575,575"
|
"http-servers:listener-id,id-34821,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,"
|
||||||
",,1,3,1,,0,,2,0,,0,L4TOUT,,30001,0,0,0,0,0,0,0,,,,0,0,,,,,-1,,,0,0,0,0,\n"
|
"1,1,575,575,,1,3,1,,0,,2,0,,0,L4TOUT,,30001,0,0,0,0,0,0,0,,,,0,0,,,,,-1,,"
|
||||||
"http-servers,id-34824,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,1,1,567,567,"
|
",0,0,0,0,\n"
|
||||||
",1,3,2,,0,,2,0,,0,L4TOUT,,30001,0,0,0,0,0,0,0,,,,0,0,,,,,-1,,,0,0,0,0,\n"
|
"http-servers:listener-id,id-34824,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,"
|
||||||
"http-servers,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,DOWN,0,0,0,,1,567,567"
|
"1,1,567,567,,1,3,2,,0,,2,0,,0,L4TOUT,,30001,0,0,0,0,0,0,0,,,,0,0,,,,,-1,,"
|
||||||
",,1,3,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,0,0,0,0,-1,,,0,0,0,0,\n"
|
",0,0,0,0,\n"
|
||||||
"tcp-servers,id-34833,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,1,1,560,560,,"
|
"http-servers:listener-id,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,DOWN,0,0,"
|
||||||
"1,5,1,,0,,2,0,,0,L4TOUT,,30000,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,\n"
|
"0,,1,567,567,,1,3,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,0,0,0,0,-1,,,0,0,0,"
|
||||||
"tcp-servers,id-34836,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,1,1,552,552,,"
|
"0,\n"
|
||||||
"1,5,2,,0,,2,0,,0,L4TOUT,,30001,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,\n"
|
"tcp-servers:listener-id,id-34833,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,1,1,"
|
||||||
"tcp-servers,id-34839,0,0,0,0,,0,0,0,,0,,0,0,0,0,DRAIN,0,1,0,0,0,552,0,,"
|
"560,560,,1,5,1,,0,,2,0,,0,L4TOUT,,30000,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,"
|
||||||
"1,5,2,,0,,2,0,,0,L7OK,,30001,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,\n"
|
"\n"
|
||||||
"tcp-servers,id-34842,0,0,0,0,,0,0,0,,0,,0,0,0,0,MAINT,0,1,0,0,0,552,0,,"
|
"tcp-servers:listener-id,id-34836,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,1,1,"
|
||||||
"1,5,2,,0,,2,0,,0,L7OK,,30001,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,\n"
|
"552,552,,1,5,2,,0,,2,0,,0,L4TOUT,,30001,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,"
|
||||||
"tcp-servers,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,1,552,552"
|
"\n"
|
||||||
",,1,5,0,,0,,1,0,,0,,,,,,,,,,,,,,0,0,0,0,0,0,-1,,,0,0,0,0,"
|
"tcp-servers:listener-id,id-34839,0,0,0,0,,0,0,0,,0,,0,0,0,0,DRAIN,0,1,0,"
|
||||||
|
"0,0,552,0,,1,5,2,,0,,2,0,,0,L7OK,,30001,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,"
|
||||||
|
"\n"
|
||||||
|
"tcp-servers:listener-id,id-34842,0,0,0,0,,0,0,0,,0,,0,0,0,0,MAINT,0,1,0,"
|
||||||
|
"0,0,552,0,,1,5,2,,0,,2,0,,0,L7OK,,30001,,,,,,,0,,,,0,0,,,,,-1,,,0,0,0,0,"
|
||||||
|
"\n"
|
||||||
|
"tcp-servers:listener-id,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,"
|
||||||
|
"1,552,552,,1,5,0,,0,,1,0,,0,,,,,,,,,,,,,,0,0,0,0,0,0,-1,,,0,0,0,0,"
|
||||||
)
|
)
|
||||||
|
|
||||||
INFO_SOCKET_SAMPLE = (
|
INFO_SOCKET_SAMPLE = (
|
||||||
|
@ -94,17 +101,19 @@ class QueryTestCase(base.TestCase):
|
||||||
self.q._query = query_mock
|
self.q._query = query_mock
|
||||||
query_mock.return_value = STATS_SOCKET_SAMPLE
|
query_mock.return_value = STATS_SOCKET_SAMPLE
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{'tcp-servers': {
|
{'tcp-servers:listener-id': {
|
||||||
'status': constants.UP,
|
'status': constants.UP,
|
||||||
'uuid': 'tcp-servers',
|
'listener_uuid': 'listener-id',
|
||||||
|
'pool_uuid': 'tcp-servers',
|
||||||
'members':
|
'members':
|
||||||
{'id-34833': constants.UP,
|
{'id-34833': constants.UP,
|
||||||
'id-34836': constants.UP,
|
'id-34836': constants.UP,
|
||||||
'id-34839': constants.DRAIN,
|
'id-34839': constants.DRAIN,
|
||||||
'id-34842': constants.MAINT}},
|
'id-34842': constants.MAINT}},
|
||||||
'http-servers': {
|
'http-servers:listener-id': {
|
||||||
'status': constants.DOWN,
|
'status': constants.DOWN,
|
||||||
'uuid': 'http-servers',
|
'listener_uuid': 'listener-id',
|
||||||
|
'pool_uuid': 'http-servers',
|
||||||
'members':
|
'members':
|
||||||
{'id-34821': constants.DOWN,
|
{'id-34821': constants.DOWN,
|
||||||
'id-34824': constants.DOWN}}},
|
'id-34824': constants.DOWN}}},
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -20,18 +20,25 @@ from octavia.amphorae.drivers.keepalived import vrrp_rest_driver
|
||||||
from octavia.common import constants
|
from octavia.common import constants
|
||||||
import octavia.tests.unit.base as base
|
import octavia.tests.unit.base as base
|
||||||
|
|
||||||
|
# Version 1.0 is functionally identical to all versions before it
|
||||||
|
API_VERSION = '1.0'
|
||||||
|
|
||||||
|
|
||||||
class TestVRRPRestDriver(base.TestCase):
|
class TestVRRPRestDriver(base.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.keepalived_mixin = vrrp_rest_driver.KeepalivedAmphoraDriverMixin()
|
self.keepalived_mixin = vrrp_rest_driver.KeepalivedAmphoraDriverMixin()
|
||||||
self.keepalived_mixin.client = mock.MagicMock()
|
self.keepalived_mixin.clients = {
|
||||||
self.client = self.keepalived_mixin.client
|
'base': mock.MagicMock(),
|
||||||
|
API_VERSION: mock.MagicMock()}
|
||||||
|
self.keepalived_mixin._populate_amphora_api_version = mock.MagicMock()
|
||||||
|
self.clients = self.keepalived_mixin.clients
|
||||||
self.FAKE_CONFIG = 'FAKE CONFIG'
|
self.FAKE_CONFIG = 'FAKE CONFIG'
|
||||||
self.lb_mock = mock.MagicMock()
|
self.lb_mock = mock.MagicMock()
|
||||||
self.amphora_mock = mock.MagicMock()
|
self.amphora_mock = mock.MagicMock()
|
||||||
self.amphora_mock.id = uuidutils.generate_uuid()
|
self.amphora_mock.id = uuidutils.generate_uuid()
|
||||||
self.amphora_mock.status = constants.AMPHORA_ALLOCATED
|
self.amphora_mock.status = constants.AMPHORA_ALLOCATED
|
||||||
|
self.amphora_mock.api_version = API_VERSION
|
||||||
self.lb_mock.amphorae = [self.amphora_mock]
|
self.lb_mock.amphorae = [self.amphora_mock]
|
||||||
self.amphorae_network_config = {}
|
self.amphorae_network_config = {}
|
||||||
vip_subnet = mock.MagicMock()
|
vip_subnet = mock.MagicMock()
|
||||||
|
@ -49,7 +56,7 @@ class TestVRRPRestDriver(base.TestCase):
|
||||||
self.keepalived_mixin.update_vrrp_conf(self.lb_mock,
|
self.keepalived_mixin.update_vrrp_conf(self.lb_mock,
|
||||||
self.amphorae_network_config)
|
self.amphorae_network_config)
|
||||||
|
|
||||||
self.client.upload_vrrp_config.assert_called_once_with(
|
self.clients[API_VERSION].upload_vrrp_config.assert_called_once_with(
|
||||||
self.amphora_mock,
|
self.amphora_mock,
|
||||||
self.FAKE_CONFIG)
|
self.FAKE_CONFIG)
|
||||||
|
|
||||||
|
@ -57,16 +64,19 @@ class TestVRRPRestDriver(base.TestCase):
|
||||||
|
|
||||||
self.keepalived_mixin.stop_vrrp_service(self.lb_mock)
|
self.keepalived_mixin.stop_vrrp_service(self.lb_mock)
|
||||||
|
|
||||||
self.client.stop_vrrp.assert_called_once_with(self.amphora_mock)
|
self.clients[API_VERSION].stop_vrrp.assert_called_once_with(
|
||||||
|
self.amphora_mock)
|
||||||
|
|
||||||
def test_start_vrrp_service(self):
|
def test_start_vrrp_service(self):
|
||||||
|
|
||||||
self.keepalived_mixin.start_vrrp_service(self.lb_mock)
|
self.keepalived_mixin.start_vrrp_service(self.lb_mock)
|
||||||
|
|
||||||
self.client.start_vrrp.assert_called_once_with(self.amphora_mock)
|
self.clients[API_VERSION].start_vrrp.assert_called_once_with(
|
||||||
|
self.amphora_mock)
|
||||||
|
|
||||||
def test_reload_vrrp_service(self):
|
def test_reload_vrrp_service(self):
|
||||||
|
|
||||||
self.keepalived_mixin.reload_vrrp_service(self.lb_mock)
|
self.keepalived_mixin.reload_vrrp_service(self.lb_mock)
|
||||||
|
|
||||||
self.client.reload_vrrp.assert_called_once_with(self.amphora_mock)
|
self.clients[API_VERSION].reload_vrrp.assert_called_once_with(
|
||||||
|
self.amphora_mock)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from octavia.amphorae.drivers.noop_driver import driver
|
from octavia.amphorae.drivers.noop_driver import driver
|
||||||
|
@ -54,6 +55,7 @@ class TestNoopAmphoraLoadBalancerDriver(base.TestCase):
|
||||||
self.load_balancer = data_models.LoadBalancer(
|
self.load_balancer = data_models.LoadBalancer(
|
||||||
id=FAKE_UUID_1, amphorae=[self.amphora], vip=self.vip,
|
id=FAKE_UUID_1, amphorae=[self.amphora], vip=self.vip,
|
||||||
listeners=[self.listener])
|
listeners=[self.listener])
|
||||||
|
self.listener.load_balancer = self.load_balancer
|
||||||
self.network = network_models.Network(id=self.FAKE_UUID_1)
|
self.network = network_models.Network(id=self.FAKE_UUID_1)
|
||||||
self.port = network_models.Port(id=uuidutils.generate_uuid())
|
self.port = network_models.Port(id=uuidutils.generate_uuid())
|
||||||
self.amphorae_net_configs = {
|
self.amphorae_net_configs = {
|
||||||
|
@ -70,8 +72,7 @@ class TestNoopAmphoraLoadBalancerDriver(base.TestCase):
|
||||||
constants.CONN_RETRY_INTERVAL: 4}
|
constants.CONN_RETRY_INTERVAL: 4}
|
||||||
|
|
||||||
def test_update_amphora_listeners(self):
|
def test_update_amphora_listeners(self):
|
||||||
amphorae = [self.amphora]
|
self.driver.update_amphora_listeners(self.load_balancer, self.amphora,
|
||||||
self.driver.update_amphora_listeners([self.listener], 0, amphorae,
|
|
||||||
self.timeout_dict)
|
self.timeout_dict)
|
||||||
self.assertEqual((self.listener, self.amphora.id, self.timeout_dict,
|
self.assertEqual((self.listener, self.amphora.id, self.timeout_dict,
|
||||||
'update_amp'),
|
'update_amp'),
|
||||||
|
@ -80,28 +81,22 @@ class TestNoopAmphoraLoadBalancerDriver(base.TestCase):
|
||||||
self.amphora.id)])
|
self.amphora.id)])
|
||||||
|
|
||||||
def test_update(self):
|
def test_update(self):
|
||||||
self.driver.update(self.listener, self.vip)
|
self.driver.update(self.load_balancer)
|
||||||
self.assertEqual((self.listener, self.vip, 'active'),
|
self.assertEqual(([self.listener], self.vip, 'active'),
|
||||||
self.driver.driver.amphoraconfig[(
|
self.driver.driver.amphoraconfig[(
|
||||||
self.listener.protocol_port,
|
(self.listener.protocol_port,),
|
||||||
self.vip.ip_address)])
|
|
||||||
|
|
||||||
def test_stop(self):
|
|
||||||
self.driver.stop(self.listener, self.vip)
|
|
||||||
self.assertEqual((self.listener, self.vip, 'stop'),
|
|
||||||
self.driver.driver.amphoraconfig[(
|
|
||||||
self.listener.protocol_port,
|
|
||||||
self.vip.ip_address)])
|
self.vip.ip_address)])
|
||||||
|
|
||||||
def test_start(self):
|
def test_start(self):
|
||||||
self.driver.start(self.listener, self.vip, amphora='amp1')
|
mock_amphora = mock.MagicMock()
|
||||||
self.assertEqual((self.listener, self.vip, 'amp1', 'start'),
|
mock_amphora.id = '321'
|
||||||
|
self.driver.start(self.load_balancer, amphora=mock_amphora)
|
||||||
|
self.assertEqual((self.load_balancer, mock_amphora, 'start'),
|
||||||
self.driver.driver.amphoraconfig[(
|
self.driver.driver.amphoraconfig[(
|
||||||
self.listener.protocol_port,
|
self.load_balancer.id, '321')])
|
||||||
self.vip.ip_address, 'amp1')])
|
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
self.driver.delete(self.listener, self.vip)
|
self.driver.delete(self.listener)
|
||||||
self.assertEqual((self.listener, self.vip, 'delete'),
|
self.assertEqual((self.listener, self.vip, 'delete'),
|
||||||
self.driver.driver.amphoraconfig[(
|
self.driver.driver.amphoraconfig[(
|
||||||
self.listener.protocol_port,
|
self.listener.protocol_port,
|
||||||
|
|
|
@ -134,7 +134,8 @@ class TestBarbicanManager(base.TestCase):
|
||||||
self.assertIsInstance(data, cert.Cert)
|
self.assertIsInstance(data, cert.Cert)
|
||||||
self.assertEqual(sample.X509_CERT_KEY, data.get_private_key())
|
self.assertEqual(sample.X509_CERT_KEY, data.get_private_key())
|
||||||
self.assertEqual(sample.X509_CERT, data.get_certificate())
|
self.assertEqual(sample.X509_CERT, data.get_certificate())
|
||||||
self.assertItemsEqual(sample.X509_IMDS_LIST, data.get_intermediates())
|
self.assertEqual(sorted(sample.X509_IMDS_LIST),
|
||||||
|
sorted(data.get_intermediates()))
|
||||||
self.assertIsNone(data.get_private_key_passphrase())
|
self.assertIsNone(data.get_private_key_passphrase())
|
||||||
|
|
||||||
def test_delete_cert_legacy(self):
|
def test_delete_cert_legacy(self):
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,9 +17,9 @@ import copy
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from octavia.common import constants
|
from octavia.common import constants
|
||||||
from octavia.common.jinja.haproxy import jinja_cfg
|
from octavia.common.jinja.haproxy.split_listeners import jinja_cfg
|
||||||
from octavia.tests.unit import base
|
from octavia.tests.unit import base
|
||||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
from octavia.tests.unit.common.sample_configs import sample_configs_split
|
||||||
|
|
||||||
|
|
||||||
class TestHaproxyCfg(base.TestCase):
|
class TestHaproxyCfg(base.TestCase):
|
||||||
|
@ -70,20 +70,19 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"weight 13 check inter 30s fall 3 rise 2 cookie "
|
"weight 13 check inter 30s fall 3 rise 2 cookie "
|
||||||
"sample_member_id_2\n\n").format(
|
"sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
tls_tupe = sample_configs.sample_tls_container_tuple(
|
tls_tupe = sample_configs_split.sample_tls_container_tuple(
|
||||||
id='tls_container_id',
|
id='tls_container_id',
|
||||||
certificate='imaCert1', private_key='imaPrivateKey1',
|
certificate='imaCert1', private_key='imaPrivateKey1',
|
||||||
primary_cn='FakeCN')
|
primary_cn='FakeCN')
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='TERMINATED_HTTPS',
|
sample_configs_split.sample_listener_tuple(
|
||||||
tls=True, sni=True,
|
proto='TERMINATED_HTTPS', tls=True, sni=True,
|
||||||
client_ca_cert=True,
|
client_ca_cert=True, client_crl_cert=True),
|
||||||
client_crl_cert=True),
|
|
||||||
tls_tupe, client_ca_filename='client_ca.pem',
|
tls_tupe, client_ca_filename='client_ca.pem',
|
||||||
client_crl='SHA_ID.pem')
|
client_crl='SHA_ID.pem')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(
|
sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be),
|
frontend=fe, backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
|
@ -121,16 +120,16 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
proto='TERMINATED_HTTPS', tls=True),
|
proto='TERMINATED_HTTPS', tls=True),
|
||||||
tls_cert=sample_configs.sample_tls_container_tuple(
|
tls_cert=sample_configs_split.sample_tls_container_tuple(
|
||||||
id='tls_container_id',
|
id='tls_container_id',
|
||||||
certificate='ImAalsdkfjCert',
|
certificate='ImAalsdkfjCert',
|
||||||
private_key='ImAsdlfksdjPrivateKey',
|
private_key='ImAsdlfksdjPrivateKey',
|
||||||
primary_cn="FakeCN"))
|
primary_cn="FakeCN"))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(
|
sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be),
|
frontend=fe, backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
|
@ -154,10 +153,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple())
|
sample_configs_split.sample_listener_tuple())
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_member_backup(self):
|
def test_render_template_member_backup(self):
|
||||||
|
@ -182,11 +181,11 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2 backup\n\n").format(
|
"cookie sample_member_id_2 backup\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(monitor_ip_port=True,
|
sample_configs_split.sample_listener_tuple(
|
||||||
backup_member=True))
|
monitor_ip_port=True, backup_member=True))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_custom_timeouts(self):
|
def test_render_template_custom_timeouts(self):
|
||||||
|
@ -219,13 +218,13 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"sample_member_id_2\n\n").format(
|
"sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(timeout_member_connect=1,
|
sample_configs_split.sample_listener_tuple(
|
||||||
timeout_client_data=2,
|
timeout_member_connect=1, timeout_client_data=2,
|
||||||
timeout_member_data=3))
|
timeout_member_data=3))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(frontend=fe,
|
sample_configs_split.sample_base_expected_config(
|
||||||
backend=be),
|
frontend=fe, backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_null_timeouts(self):
|
def test_render_template_null_timeouts(self):
|
||||||
|
@ -258,13 +257,13 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"sample_member_id_2\n\n").format(
|
"sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(timeout_member_connect=None,
|
sample_configs_split.sample_listener_tuple(
|
||||||
timeout_client_data=None,
|
timeout_member_connect=None, timeout_client_data=None,
|
||||||
timeout_member_data=None))
|
timeout_member_data=None))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(frontend=fe,
|
sample_configs_split.sample_base_expected_config(
|
||||||
backend=be),
|
frontend=fe, backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_member_monitor_addr_port(self):
|
def test_render_template_member_monitor_addr_port(self):
|
||||||
|
@ -289,10 +288,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(monitor_ip_port=True))
|
sample_configs_split.sample_listener_tuple(monitor_ip_port=True))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_https_real_monitor(self):
|
def test_render_template_https_real_monitor(self):
|
||||||
|
@ -326,9 +325,9 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTPS'))
|
sample_configs_split.sample_listener_tuple(proto='HTTPS'))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be), rendered_obj)
|
frontend=fe, backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_https_hello_monitor(self):
|
def test_render_template_https_hello_monitor(self):
|
||||||
|
@ -361,10 +360,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
proto='HTTPS', monitor_proto='TLS-HELLO'))
|
proto='HTTPS', monitor_proto='TLS-HELLO'))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be), rendered_obj)
|
frontend=fe, backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_no_monitor_http(self):
|
def test_render_template_no_monitor_http(self):
|
||||||
|
@ -382,9 +381,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTP', monitor=False))
|
sample_configs_split.sample_listener_tuple(
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
proto='HTTP', monitor=False))
|
||||||
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
backend=be), rendered_obj)
|
backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_disabled_member(self):
|
def test_render_template_disabled_member(self):
|
||||||
|
@ -402,10 +402,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2 disabled\n\n").format(
|
"cookie sample_member_id_2 disabled\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTP', monitor=False,
|
sample_configs_split.sample_listener_tuple(
|
||||||
disabled_member=True))
|
proto='HTTP', monitor=False, disabled_member=True))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
backend=be), rendered_obj)
|
backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_ping_monitor_http(self):
|
def test_render_template_ping_monitor_http(self):
|
||||||
|
@ -430,10 +430,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
go = " maxconn {maxconn}\n external-check\n\n".format(
|
go = " maxconn {maxconn}\n external-check\n\n".format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTP',
|
sample_configs_split.sample_listener_tuple(
|
||||||
monitor_proto='PING'))
|
proto='HTTP', monitor_proto='PING'))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
backend=be, global_opts=go), rendered_obj)
|
backend=be, global_opts=go), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_no_monitor_https(self):
|
def test_render_template_no_monitor_https(self):
|
||||||
|
@ -462,9 +462,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False))
|
sample_configs_split.sample_listener_tuple(
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
proto='HTTPS', monitor=False))
|
||||||
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be), rendered_obj)
|
frontend=fe, backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_health_monitor_http_check(self):
|
def test_render_template_health_monitor_http_check(self):
|
||||||
|
@ -488,11 +489,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTP',
|
sample_configs_split.sample_listener_tuple(
|
||||||
monitor_proto='HTTP',
|
proto='HTTP', monitor_proto='HTTP', hm_host_http_check=True))
|
||||||
hm_host_http_check=True))
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
|
||||||
backend=be), rendered_obj)
|
backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_no_persistence_https(self):
|
def test_render_template_no_persistence_https(self):
|
||||||
|
@ -518,10 +518,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" server sample_member_id_2 10.0.0.98:82 "
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
"weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN)
|
"weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False,
|
sample_configs_split.sample_listener_tuple(
|
||||||
persistence=False))
|
proto='HTTPS', monitor=False, persistence=False))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be), rendered_obj)
|
frontend=fe, backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_no_persistence_http(self):
|
def test_render_template_no_persistence_http(self):
|
||||||
|
@ -536,10 +536,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" server sample_member_id_2 10.0.0.98:82 "
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
"weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN)
|
"weight 13\n\n").format(maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTP', monitor=False,
|
sample_configs_split.sample_listener_tuple(
|
||||||
persistence=False))
|
proto='HTTP', monitor=False, persistence=False))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
backend=be), rendered_obj)
|
backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_sourceip_persistence(self):
|
def test_render_template_sourceip_persistence(self):
|
||||||
|
@ -561,11 +561,11 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"weight 13 check inter 30s fall 3 rise 2\n\n").format(
|
"weight 13 check inter 30s fall 3 rise 2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
persistence_type='SOURCE_IP'))
|
persistence_type='SOURCE_IP'))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_appcookie_persistence(self):
|
def test_render_template_appcookie_persistence(self):
|
||||||
|
@ -588,12 +588,12 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"weight 13 check inter 30s fall 3 rise 2\n\n").format(
|
"weight 13 check inter 30s fall 3 rise 2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
persistence_type='APP_COOKIE',
|
persistence_type='APP_COOKIE',
|
||||||
persistence_cookie='JSESSIONID'))
|
persistence_cookie='JSESSIONID'))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_unlimited_connections(self):
|
def test_render_template_unlimited_connections(self):
|
||||||
|
@ -622,9 +622,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False))
|
sample_configs_split.sample_listener_tuple(
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
proto='HTTPS', monitor=False))
|
||||||
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be), rendered_obj)
|
frontend=fe, backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_limited_connections(self):
|
def test_render_template_limited_connections(self):
|
||||||
|
@ -652,10 +653,10 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n")
|
"cookie sample_member_id_2\n\n")
|
||||||
g_opts = " maxconn 2014\n\n"
|
g_opts = " maxconn 2014\n\n"
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False,
|
sample_configs_split.sample_listener_tuple(
|
||||||
connection_limit=2014))
|
proto='HTTPS', monitor=False, connection_limit=2014))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be, global_opts=g_opts), rendered_obj)
|
frontend=fe, backend=be, global_opts=g_opts), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_l7policies(self):
|
def test_render_template_l7policies(self):
|
||||||
|
@ -720,9 +721,9 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n").format(
|
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(l7=True))
|
sample_configs_split.sample_listener_tuple(l7=True))
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be), rendered_obj)
|
frontend=fe, backend=be), rendered_obj)
|
||||||
|
|
||||||
def test_render_template_http_xff(self):
|
def test_render_template_http_xff(self):
|
||||||
|
@ -746,11 +747,11 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
insert_headers={'X-Forwarded-For': 'true'}))
|
insert_headers={'X-Forwarded-For': 'true'}))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_http_xff_xfport(self):
|
def test_render_template_http_xff_xfport(self):
|
||||||
|
@ -775,12 +776,12 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2\n\n").format(
|
"cookie sample_member_id_2\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
insert_headers={'X-Forwarded-For': 'true',
|
insert_headers={'X-Forwarded-For': 'true',
|
||||||
'X-Forwarded-Port': 'true'}))
|
'X-Forwarded-Port': 'true'}))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_pool_proxy_protocol(self):
|
def test_render_template_pool_proxy_protocol(self):
|
||||||
|
@ -801,11 +802,11 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2 send-proxy\n\n").format(
|
"cookie sample_member_id_2 send-proxy\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
be_proto='PROXY'))
|
be_proto='PROXY'))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_pool_cert(self):
|
def test_render_template_pool_cert(self):
|
||||||
|
@ -831,15 +832,15 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
||||||
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path)
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path)
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
pool_cert=True, tls_enabled=True),
|
pool_cert=True, tls_enabled=True),
|
||||||
pool_tls_certs={
|
pool_tls_certs={
|
||||||
'sample_pool_id_1':
|
'sample_pool_id_1':
|
||||||
{'client_cert': cert_file_path,
|
{'client_cert': cert_file_path,
|
||||||
'ca_cert': None, 'crl': None}})
|
'ca_cert': None, 'crl': None}})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_with_full_pool_cert(self):
|
def test_render_template_with_full_pool_cert(self):
|
||||||
|
@ -870,8 +871,8 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"crl-file %s" % pool_crl,
|
"crl-file %s" % pool_crl,
|
||||||
"verify required sni ssl_fc_sni"))
|
"verify required sni ssl_fc_sni"))
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_split.sample_listener_tuple(
|
||||||
pool_cert=True, pool_ca_cert=True, pool_crl=True,
|
pool_cert=True, pool_ca_cert=True, pool_crl=True,
|
||||||
tls_enabled=True),
|
tls_enabled=True),
|
||||||
pool_tls_certs={
|
pool_tls_certs={
|
||||||
|
@ -880,107 +881,109 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
'ca_cert': pool_ca_cert,
|
'ca_cert': pool_ca_cert,
|
||||||
'crl': pool_crl}})
|
'crl': pool_crl}})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_transform_session_persistence(self):
|
def test_transform_session_persistence(self):
|
||||||
in_persistence = sample_configs.sample_session_persistence_tuple()
|
in_persistence = (
|
||||||
ret = self.jinja_cfg._transform_session_persistence(in_persistence, {})
|
sample_configs_split.sample_session_persistence_tuple())
|
||||||
self.assertEqual(sample_configs.RET_PERSISTENCE, ret)
|
ret = self.jinja_cfg._transform_session_persistence(
|
||||||
|
in_persistence, {})
|
||||||
|
self.assertEqual(sample_configs_split.RET_PERSISTENCE, ret)
|
||||||
|
|
||||||
def test_transform_health_monitor(self):
|
def test_transform_health_monitor(self):
|
||||||
in_persistence = sample_configs.sample_health_monitor_tuple()
|
in_persistence = sample_configs_split.sample_health_monitor_tuple()
|
||||||
ret = self.jinja_cfg._transform_health_monitor(in_persistence, {})
|
ret = self.jinja_cfg._transform_health_monitor(in_persistence, {})
|
||||||
self.assertEqual(sample_configs.RET_MONITOR_1, ret)
|
self.assertEqual(sample_configs_split.RET_MONITOR_1, ret)
|
||||||
|
|
||||||
def test_transform_member(self):
|
def test_transform_member(self):
|
||||||
in_member = sample_configs.sample_member_tuple('sample_member_id_1',
|
in_member = sample_configs_split.sample_member_tuple(
|
||||||
'10.0.0.99')
|
'sample_member_id_1', '10.0.0.99')
|
||||||
ret = self.jinja_cfg._transform_member(in_member, {})
|
ret = self.jinja_cfg._transform_member(in_member, {})
|
||||||
self.assertEqual(sample_configs.RET_MEMBER_1, ret)
|
self.assertEqual(sample_configs_split.RET_MEMBER_1, ret)
|
||||||
|
|
||||||
def test_transform_pool(self):
|
def test_transform_pool(self):
|
||||||
in_pool = sample_configs.sample_pool_tuple()
|
in_pool = sample_configs_split.sample_pool_tuple()
|
||||||
ret = self.jinja_cfg._transform_pool(in_pool, {})
|
ret = self.jinja_cfg._transform_pool(in_pool, {})
|
||||||
self.assertEqual(sample_configs.RET_POOL_1, ret)
|
self.assertEqual(sample_configs_split.RET_POOL_1, ret)
|
||||||
|
|
||||||
def test_transform_pool_2(self):
|
def test_transform_pool_2(self):
|
||||||
in_pool = sample_configs.sample_pool_tuple(sample_pool=2)
|
in_pool = sample_configs_split.sample_pool_tuple(sample_pool=2)
|
||||||
ret = self.jinja_cfg._transform_pool(in_pool, {})
|
ret = self.jinja_cfg._transform_pool(in_pool, {})
|
||||||
self.assertEqual(sample_configs.RET_POOL_2, ret)
|
self.assertEqual(sample_configs_split.RET_POOL_2, ret)
|
||||||
|
|
||||||
def test_transform_pool_http_reuse(self):
|
def test_transform_pool_http_reuse(self):
|
||||||
in_pool = sample_configs.sample_pool_tuple(sample_pool=2)
|
in_pool = sample_configs_split.sample_pool_tuple(sample_pool=2)
|
||||||
ret = self.jinja_cfg._transform_pool(
|
ret = self.jinja_cfg._transform_pool(
|
||||||
in_pool, {constants.HTTP_REUSE: True})
|
in_pool, {constants.HTTP_REUSE: True})
|
||||||
expected_config = copy.copy(sample_configs.RET_POOL_2)
|
expected_config = copy.copy(sample_configs_split.RET_POOL_2)
|
||||||
expected_config[constants.HTTP_REUSE] = True
|
expected_config[constants.HTTP_REUSE] = True
|
||||||
self.assertEqual(expected_config, ret)
|
self.assertEqual(expected_config, ret)
|
||||||
|
|
||||||
def test_transform_pool_cert(self):
|
def test_transform_pool_cert(self):
|
||||||
in_pool = sample_configs.sample_pool_tuple(pool_cert=True)
|
in_pool = sample_configs_split.sample_pool_tuple(pool_cert=True)
|
||||||
cert_path = os.path.join(self.jinja_cfg.base_crt_dir,
|
cert_path = os.path.join(self.jinja_cfg.base_crt_dir,
|
||||||
'test_listener_id', 'pool_cert.pem')
|
'test_listener_id', 'pool_cert.pem')
|
||||||
ret = self.jinja_cfg._transform_pool(
|
ret = self.jinja_cfg._transform_pool(
|
||||||
in_pool, {}, pool_tls_certs={'client_cert': cert_path})
|
in_pool, {}, pool_tls_certs={'client_cert': cert_path})
|
||||||
expected_config = copy.copy(sample_configs.RET_POOL_1)
|
expected_config = copy.copy(sample_configs_split.RET_POOL_1)
|
||||||
expected_config['client_cert'] = cert_path
|
expected_config['client_cert'] = cert_path
|
||||||
self.assertEqual(expected_config, ret)
|
self.assertEqual(expected_config, ret)
|
||||||
|
|
||||||
def test_transform_listener(self):
|
def test_transform_listener(self):
|
||||||
in_listener = sample_configs.sample_listener_tuple()
|
in_listener = sample_configs_split.sample_listener_tuple()
|
||||||
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
|
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
|
||||||
in_listener.load_balancer)
|
in_listener.load_balancer)
|
||||||
self.assertEqual(sample_configs.RET_LISTENER, ret)
|
self.assertEqual(sample_configs_split.RET_LISTENER, ret)
|
||||||
|
|
||||||
def test_transform_listener_with_l7(self):
|
def test_transform_listener_with_l7(self):
|
||||||
in_listener = sample_configs.sample_listener_tuple(l7=True)
|
in_listener = sample_configs_split.sample_listener_tuple(l7=True)
|
||||||
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
|
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
|
||||||
in_listener.load_balancer)
|
in_listener.load_balancer)
|
||||||
self.assertEqual(sample_configs.RET_LISTENER_L7, ret)
|
self.assertEqual(sample_configs_split.RET_LISTENER_L7, ret)
|
||||||
|
|
||||||
def test_transform_loadbalancer(self):
|
def test_transform_loadbalancer(self):
|
||||||
in_amphora = sample_configs.sample_amphora_tuple()
|
in_amphora = sample_configs_split.sample_amphora_tuple()
|
||||||
in_listener = sample_configs.sample_listener_tuple()
|
in_listener = sample_configs_split.sample_listener_tuple()
|
||||||
ret = self.jinja_cfg._transform_loadbalancer(
|
ret = self.jinja_cfg._transform_loadbalancer(
|
||||||
in_amphora, in_listener.load_balancer, in_listener, None, {})
|
in_amphora, in_listener.load_balancer, in_listener, None, {})
|
||||||
self.assertEqual(sample_configs.RET_LB, ret)
|
self.assertEqual(sample_configs_split.RET_LB, ret)
|
||||||
|
|
||||||
def test_transform_amphora(self):
|
def test_transform_amphora(self):
|
||||||
in_amphora = sample_configs.sample_amphora_tuple()
|
in_amphora = sample_configs_split.sample_amphora_tuple()
|
||||||
ret = self.jinja_cfg._transform_amphora(in_amphora, {})
|
ret = self.jinja_cfg._transform_amphora(in_amphora, {})
|
||||||
self.assertEqual(sample_configs.RET_AMPHORA, ret)
|
self.assertEqual(sample_configs_split.RET_AMPHORA, ret)
|
||||||
|
|
||||||
def test_transform_loadbalancer_with_l7(self):
|
def test_transform_loadbalancer_with_l7(self):
|
||||||
in_amphora = sample_configs.sample_amphora_tuple()
|
in_amphora = sample_configs_split.sample_amphora_tuple()
|
||||||
in_listener = sample_configs.sample_listener_tuple(l7=True)
|
in_listener = sample_configs_split.sample_listener_tuple(l7=True)
|
||||||
ret = self.jinja_cfg._transform_loadbalancer(
|
ret = self.jinja_cfg._transform_loadbalancer(
|
||||||
in_amphora, in_listener.load_balancer, in_listener, None, {})
|
in_amphora, in_listener.load_balancer, in_listener, None, {})
|
||||||
self.assertEqual(sample_configs.RET_LB_L7, ret)
|
self.assertEqual(sample_configs_split.RET_LB_L7, ret)
|
||||||
|
|
||||||
def test_transform_l7policy(self):
|
def test_transform_l7policy(self):
|
||||||
in_l7policy = sample_configs.sample_l7policy_tuple(
|
in_l7policy = sample_configs_split.sample_l7policy_tuple(
|
||||||
'sample_l7policy_id_1')
|
'sample_l7policy_id_1')
|
||||||
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
||||||
self.assertEqual(sample_configs.RET_L7POLICY_1, ret)
|
self.assertEqual(sample_configs_split.RET_L7POLICY_1, ret)
|
||||||
|
|
||||||
def test_transform_l7policy_2_8(self):
|
def test_transform_l7policy_2_8(self):
|
||||||
in_l7policy = sample_configs.sample_l7policy_tuple(
|
in_l7policy = sample_configs_split.sample_l7policy_tuple(
|
||||||
'sample_l7policy_id_2', sample_policy=2)
|
'sample_l7policy_id_2', sample_policy=2)
|
||||||
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
||||||
self.assertEqual(sample_configs.RET_L7POLICY_2, ret)
|
self.assertEqual(sample_configs_split.RET_L7POLICY_2, ret)
|
||||||
|
|
||||||
# test invalid action without redirect_http_code
|
# test invalid action without redirect_http_code
|
||||||
in_l7policy = sample_configs.sample_l7policy_tuple(
|
in_l7policy = sample_configs_split.sample_l7policy_tuple(
|
||||||
'sample_l7policy_id_8', sample_policy=2, redirect_http_code=None)
|
'sample_l7policy_id_8', sample_policy=2, redirect_http_code=None)
|
||||||
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
||||||
self.assertEqual(sample_configs.RET_L7POLICY_8, ret)
|
self.assertEqual(sample_configs_split.RET_L7POLICY_8, ret)
|
||||||
|
|
||||||
def test_transform_l7policy_disabled_rule(self):
|
def test_transform_l7policy_disabled_rule(self):
|
||||||
in_l7policy = sample_configs.sample_l7policy_tuple(
|
in_l7policy = sample_configs_split.sample_l7policy_tuple(
|
||||||
'sample_l7policy_id_6', sample_policy=6)
|
'sample_l7policy_id_6', sample_policy=6)
|
||||||
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
|
||||||
self.assertEqual(sample_configs.RET_L7POLICY_6, ret)
|
self.assertEqual(sample_configs_split.RET_L7POLICY_6, ret)
|
||||||
|
|
||||||
def test_escape_haproxy_config_string(self):
|
def test_escape_haproxy_config_string(self):
|
||||||
self.assertEqual(self.jinja_cfg._escape_haproxy_config_string(
|
self.assertEqual(self.jinja_cfg._escape_haproxy_config_string(
|
||||||
|
@ -1034,11 +1037,12 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" option splice-response\n"
|
" option splice-response\n"
|
||||||
" option http-keep-alive\n\n")
|
" option http-keep-alive\n\n")
|
||||||
rendered_obj = j_cfg.render_loadbalancer_obj(
|
rendered_obj = j_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple()
|
sample_configs_split.sample_listener_tuple()
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(defaults=defaults),
|
sample_configs_split.sample_base_expected_config(
|
||||||
|
defaults=defaults),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_http_reuse(self):
|
def test_http_reuse(self):
|
||||||
|
@ -1065,12 +1069,12 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2 send-proxy\n\n").format(
|
"cookie sample_member_id_2 send-proxy\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = j_cfg.build_config(
|
rendered_obj = j_cfg.build_config(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(be_proto='PROXY'),
|
sample_configs_split.sample_listener_tuple(be_proto='PROXY'),
|
||||||
tls_cert=None,
|
tls_cert=None,
|
||||||
haproxy_versions=("1", "8", "1"))
|
haproxy_versions=("1", "8", "1"))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
# Without http-reuse
|
# Without http-reuse
|
||||||
|
@ -1091,12 +1095,12 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
"cookie sample_member_id_2 send-proxy\n\n").format(
|
"cookie sample_member_id_2 send-proxy\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
rendered_obj = j_cfg.build_config(
|
rendered_obj = j_cfg.build_config(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(be_proto='PROXY'),
|
sample_configs_split.sample_listener_tuple(be_proto='PROXY'),
|
||||||
tls_cert=None,
|
tls_cert=None,
|
||||||
haproxy_versions=("1", "5", "18"))
|
haproxy_versions=("1", "5", "18"))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(backend=be),
|
sample_configs_split.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_ssl_types_l7rules(self):
|
def test_ssl_types_l7rules(self):
|
||||||
|
@ -1172,15 +1176,15 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout server 50000\n"
|
" timeout server 50000\n"
|
||||||
" server sample_member_id_3 10.0.0.97:82 weight 13 check "
|
" server sample_member_id_3 10.0.0.97:82 weight 13 check "
|
||||||
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n")
|
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n")
|
||||||
sample_listener = sample_configs.sample_listener_tuple(
|
sample_listener = sample_configs_split.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_TERMINATED_HTTPS, l7=True,
|
proto=constants.PROTOCOL_TERMINATED_HTTPS, l7=True,
|
||||||
ssl_type_l7=True)
|
ssl_type_l7=True)
|
||||||
rendered_obj = j_cfg.build_config(
|
rendered_obj = j_cfg.build_config(
|
||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs_split.sample_amphora_tuple(),
|
||||||
sample_listener,
|
sample_listener,
|
||||||
tls_cert=None,
|
tls_cert=None,
|
||||||
haproxy_versions=("1", "5", "18"))
|
haproxy_versions=("1", "5", "18"))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(
|
sample_configs_split.sample_base_expected_config(
|
||||||
frontend=fe, backend=be),
|
frontend=fe, backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
|
@ -16,7 +16,7 @@
|
||||||
from octavia.common import constants
|
from octavia.common import constants
|
||||||
from octavia.common.jinja.lvs import jinja_cfg
|
from octavia.common.jinja.lvs import jinja_cfg
|
||||||
from octavia.tests.unit import base
|
from octavia.tests.unit import base
|
||||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
from octavia.tests.unit.common.sample_configs import sample_configs_combined
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_config import fixture as oslo_fixture
|
from oslo_config import fixture as oslo_fixture
|
||||||
|
@ -76,7 +76,7 @@ class TestLvsCfg(base.TestCase):
|
||||||
" }\n\n"
|
" }\n\n"
|
||||||
"}\n\n")
|
"}\n\n")
|
||||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_combined.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
persistence_timeout=33,
|
persistence_timeout=33,
|
||||||
|
@ -124,7 +124,7 @@ class TestLvsCfg(base.TestCase):
|
||||||
" }\n\n"
|
" }\n\n"
|
||||||
"}\n\n")
|
"}\n\n")
|
||||||
|
|
||||||
listener = sample_configs.sample_listener_tuple(
|
listener = sample_configs_combined.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||||
connection_limit=98,
|
connection_limit=98,
|
||||||
|
@ -172,7 +172,7 @@ class TestLvsCfg(base.TestCase):
|
||||||
"}\n\n")
|
"}\n\n")
|
||||||
|
|
||||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_combined.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||||
persistence=False,
|
persistence=False,
|
||||||
|
@ -185,56 +185,57 @@ class TestLvsCfg(base.TestCase):
|
||||||
"net_namespace amphora-haproxy\n\n\n")
|
"net_namespace amphora-haproxy\n\n\n")
|
||||||
|
|
||||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs.sample_listener_tuple(
|
sample_configs_combined.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_UDP, monitor=False,
|
proto=constants.PROTOCOL_UDP, monitor=False,
|
||||||
persistence=False, alloc_default_pool=False))
|
persistence=False, alloc_default_pool=False))
|
||||||
self.assertEqual(exp, rendered_obj)
|
self.assertEqual(exp, rendered_obj)
|
||||||
|
|
||||||
def test_udp_transform_session_persistence(self):
|
def test_udp_transform_session_persistence(self):
|
||||||
persistence_src_ip = sample_configs.sample_session_persistence_tuple(
|
persistence_src_ip = (
|
||||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
sample_configs_combined.sample_session_persistence_tuple(
|
||||||
persistence_cookie=None,
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
persistence_timeout=33,
|
persistence_cookie=None,
|
||||||
persistence_granularity='255.0.0.0'
|
persistence_timeout=33,
|
||||||
)
|
persistence_granularity='255.0.0.0'
|
||||||
exp = sample_configs.UDP_SOURCE_IP_BODY
|
))
|
||||||
|
exp = sample_configs_combined.UDP_SOURCE_IP_BODY
|
||||||
ret = self.udp_jinja_cfg._transform_session_persistence(
|
ret = self.udp_jinja_cfg._transform_session_persistence(
|
||||||
persistence_src_ip)
|
persistence_src_ip)
|
||||||
self.assertEqual(exp, ret)
|
self.assertEqual(exp, ret)
|
||||||
|
|
||||||
def test_udp_transform_health_monitor(self):
|
def test_udp_transform_health_monitor(self):
|
||||||
in_hm = sample_configs.sample_health_monitor_tuple(
|
in_hm = sample_configs_combined.sample_health_monitor_tuple(
|
||||||
proto=constants.HEALTH_MONITOR_UDP_CONNECT
|
proto=constants.HEALTH_MONITOR_UDP_CONNECT
|
||||||
)
|
)
|
||||||
ret = self.udp_jinja_cfg._transform_health_monitor(in_hm)
|
ret = self.udp_jinja_cfg._transform_health_monitor(in_hm)
|
||||||
self.assertEqual(sample_configs.RET_UDP_HEALTH_MONITOR, ret)
|
self.assertEqual(sample_configs_combined.RET_UDP_HEALTH_MONITOR, ret)
|
||||||
|
|
||||||
def test_udp_transform_member(self):
|
def test_udp_transform_member(self):
|
||||||
in_member = sample_configs.sample_member_tuple('member_id_1',
|
in_member = sample_configs_combined.sample_member_tuple(
|
||||||
'192.0.2.10')
|
'member_id_1', '192.0.2.10')
|
||||||
ret = self.udp_jinja_cfg._transform_member(in_member)
|
ret = self.udp_jinja_cfg._transform_member(in_member)
|
||||||
self.assertEqual(sample_configs.RET_UDP_MEMBER, ret)
|
self.assertEqual(sample_configs_combined.RET_UDP_MEMBER, ret)
|
||||||
|
|
||||||
def test_udp_transform_pool(self):
|
def test_udp_transform_pool(self):
|
||||||
in_pool = sample_configs.sample_pool_tuple(
|
in_pool = sample_configs_combined.sample_pool_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
persistence_timeout=33, persistence_granularity='255.0.0.0',
|
persistence_timeout=33, persistence_granularity='255.0.0.0',
|
||||||
)
|
)
|
||||||
ret = self.udp_jinja_cfg._transform_pool(in_pool)
|
ret = self.udp_jinja_cfg._transform_pool(in_pool)
|
||||||
self.assertEqual(sample_configs.RET_UDP_POOL, ret)
|
self.assertEqual(sample_configs_combined.RET_UDP_POOL, ret)
|
||||||
|
|
||||||
in_pool = sample_configs.sample_pool_tuple(
|
in_pool = sample_configs_combined.sample_pool_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
persistence_timeout=33, persistence_granularity='255.0.0.0',
|
persistence_timeout=33, persistence_granularity='255.0.0.0',
|
||||||
monitor=False)
|
monitor=False)
|
||||||
sample_configs.RET_UDP_POOL['health_monitor'] = ''
|
sample_configs_combined.RET_UDP_POOL['health_monitor'] = ''
|
||||||
ret = self.udp_jinja_cfg._transform_pool(in_pool)
|
ret = self.udp_jinja_cfg._transform_pool(in_pool)
|
||||||
self.assertEqual(sample_configs.RET_UDP_POOL, ret)
|
self.assertEqual(sample_configs_combined.RET_UDP_POOL, ret)
|
||||||
|
|
||||||
def test_udp_transform_listener(self):
|
def test_udp_transform_listener(self):
|
||||||
in_listener = sample_configs.sample_listener_tuple(
|
in_listener = sample_configs_combined.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
persistence_timeout=33,
|
persistence_timeout=33,
|
||||||
|
@ -243,9 +244,9 @@ class TestLvsCfg(base.TestCase):
|
||||||
connection_limit=98
|
connection_limit=98
|
||||||
)
|
)
|
||||||
ret = self.udp_jinja_cfg._transform_listener(in_listener)
|
ret = self.udp_jinja_cfg._transform_listener(in_listener)
|
||||||
self.assertEqual(sample_configs.RET_UDP_LISTENER, ret)
|
self.assertEqual(sample_configs_combined.RET_UDP_LISTENER, ret)
|
||||||
|
|
||||||
in_listener = sample_configs.sample_listener_tuple(
|
in_listener = sample_configs_combined.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
persistence_timeout=33,
|
persistence_timeout=33,
|
||||||
|
@ -254,5 +255,5 @@ class TestLvsCfg(base.TestCase):
|
||||||
connection_limit=-1)
|
connection_limit=-1)
|
||||||
|
|
||||||
ret = self.udp_jinja_cfg._transform_listener(in_listener)
|
ret = self.udp_jinja_cfg._transform_listener(in_listener)
|
||||||
sample_configs.RET_UDP_LISTENER.pop('connection_limit')
|
sample_configs_combined.RET_UDP_LISTENER.pop('connection_limit')
|
||||||
self.assertEqual(sample_configs.RET_UDP_LISTENER, ret)
|
self.assertEqual(sample_configs_combined.RET_UDP_LISTENER, ret)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,11 +27,11 @@ def sample_amphora_tuple(id='sample_amphora_id_1', lb_network_ip='10.0.1.1',
|
||||||
vrrp_ip='10.1.1.1', ha_ip='192.168.10.1',
|
vrrp_ip='10.1.1.1', ha_ip='192.168.10.1',
|
||||||
vrrp_port_id='1234', ha_port_id='1234', role=None,
|
vrrp_port_id='1234', ha_port_id='1234', role=None,
|
||||||
status='ACTIVE', vrrp_interface=None,
|
status='ACTIVE', vrrp_interface=None,
|
||||||
vrrp_priority=None):
|
vrrp_priority=None, api_version='0.5'):
|
||||||
in_amphora = collections.namedtuple(
|
in_amphora = collections.namedtuple(
|
||||||
'amphora', 'id, lb_network_ip, vrrp_ip, ha_ip, vrrp_port_id, '
|
'amphora', 'id, lb_network_ip, vrrp_ip, ha_ip, vrrp_port_id, '
|
||||||
'ha_port_id, role, status, vrrp_interface,'
|
'ha_port_id, role, status, vrrp_interface,'
|
||||||
'vrrp_priority')
|
'vrrp_priority, api_version')
|
||||||
return in_amphora(
|
return in_amphora(
|
||||||
id=id,
|
id=id,
|
||||||
lb_network_ip=lb_network_ip,
|
lb_network_ip=lb_network_ip,
|
||||||
|
@ -42,7 +42,8 @@ def sample_amphora_tuple(id='sample_amphora_id_1', lb_network_ip='10.0.1.1',
|
||||||
role=role,
|
role=role,
|
||||||
status=status,
|
status=status,
|
||||||
vrrp_interface=vrrp_interface,
|
vrrp_interface=vrrp_interface,
|
||||||
vrrp_priority=vrrp_priority)
|
vrrp_priority=vrrp_priority,
|
||||||
|
api_version=api_version)
|
||||||
|
|
||||||
|
|
||||||
RET_PERSISTENCE = {
|
RET_PERSISTENCE = {
|
||||||
|
@ -510,7 +511,7 @@ def sample_listener_loadbalancer_tuple(proto=None, topology=None,
|
||||||
topology = constants.TOPOLOGY_SINGLE
|
topology = constants.TOPOLOGY_SINGLE
|
||||||
in_lb = collections.namedtuple(
|
in_lb = collections.namedtuple(
|
||||||
'load_balancer', 'id, name, protocol, vip, amphorae, topology, '
|
'load_balancer', 'id, name, protocol, vip, amphorae, topology, '
|
||||||
'enabled, project_id')
|
'listeners, enabled, project_id')
|
||||||
return in_lb(
|
return in_lb(
|
||||||
id='sample_loadbalancer_id_1',
|
id='sample_loadbalancer_id_1',
|
||||||
name='test-lb',
|
name='test-lb',
|
||||||
|
@ -524,6 +525,45 @@ def sample_listener_loadbalancer_tuple(proto=None, topology=None,
|
||||||
role=constants.ROLE_BACKUP)]
|
role=constants.ROLE_BACKUP)]
|
||||||
if more_amp else [sample_amphora_tuple()],
|
if more_amp else [sample_amphora_tuple()],
|
||||||
topology=topology,
|
topology=topology,
|
||||||
|
listeners=[],
|
||||||
|
enabled=enabled,
|
||||||
|
project_id='12345'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def sample_lb_with_udp_listener_tuple(
|
||||||
|
proto=None, topology=None, enabled=True, pools=None):
|
||||||
|
proto = 'HTTP' if proto is None else proto
|
||||||
|
if topology and topology in ['ACTIVE_STANDBY', 'ACTIVE_ACTIVE']:
|
||||||
|
more_amp = True
|
||||||
|
else:
|
||||||
|
more_amp = False
|
||||||
|
topology = constants.TOPOLOGY_SINGLE
|
||||||
|
listeners = [sample_listener_tuple(
|
||||||
|
proto=constants.PROTOCOL_UDP,
|
||||||
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
|
persistence_timeout=33,
|
||||||
|
persistence_granularity='255.255.0.0',
|
||||||
|
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT)]
|
||||||
|
|
||||||
|
in_lb = collections.namedtuple(
|
||||||
|
'load_balancer', 'id, name, protocol, vip, amphorae, topology, '
|
||||||
|
'pools, enabled, project_id, listeners')
|
||||||
|
return in_lb(
|
||||||
|
id='sample_loadbalancer_id_1',
|
||||||
|
name='test-lb',
|
||||||
|
protocol=proto,
|
||||||
|
vip=sample_vip_tuple(),
|
||||||
|
amphorae=[sample_amphora_tuple(role=constants.ROLE_MASTER),
|
||||||
|
sample_amphora_tuple(
|
||||||
|
id='sample_amphora_id_2',
|
||||||
|
lb_network_ip='10.0.1.2',
|
||||||
|
vrrp_ip='10.1.1.2',
|
||||||
|
role=constants.ROLE_BACKUP)]
|
||||||
|
if more_amp else [sample_amphora_tuple()],
|
||||||
|
topology=topology,
|
||||||
|
listeners=listeners,
|
||||||
|
pools=pools or [],
|
||||||
enabled=enabled,
|
enabled=enabled,
|
||||||
project_id='12345'
|
project_id='12345'
|
||||||
)
|
)
|
||||||
|
@ -565,7 +605,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||||
client_ca_cert=False, client_crl_cert=False,
|
client_ca_cert=False, client_crl_cert=False,
|
||||||
ssl_type_l7=False, pool_cert=False,
|
ssl_type_l7=False, pool_cert=False,
|
||||||
pool_ca_cert=False, pool_crl=False,
|
pool_ca_cert=False, pool_crl=False,
|
||||||
tls_enabled=False, hm_host_http_check=False):
|
tls_enabled=False, hm_host_http_check=False,
|
||||||
|
id='sample_listener_id_1', recursive_nest=False):
|
||||||
proto = 'HTTP' if proto is None else proto
|
proto = 'HTTP' if proto is None else proto
|
||||||
if be_proto is None:
|
if be_proto is None:
|
||||||
be_proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
|
be_proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
|
||||||
|
@ -624,8 +665,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||||
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
||||||
hm_host_http_check=hm_host_http_check)]
|
hm_host_http_check=hm_host_http_check)]
|
||||||
l7policies = []
|
l7policies = []
|
||||||
return in_listener(
|
listener = in_listener(
|
||||||
id='sample_listener_id_1',
|
id=id,
|
||||||
project_id='12345',
|
project_id='12345',
|
||||||
protocol_port=port,
|
protocol_port=port,
|
||||||
protocol=proto,
|
protocol=proto,
|
||||||
|
@ -689,6 +730,9 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||||
constants.CLIENT_AUTH_NONE),
|
constants.CLIENT_AUTH_NONE),
|
||||||
client_crl_container_id='cont_id_crl' if client_crl_cert else '',
|
client_crl_container_id='cont_id_crl' if client_crl_cert else '',
|
||||||
)
|
)
|
||||||
|
if recursive_nest:
|
||||||
|
listener.load_balancer.listeners.append(listener)
|
||||||
|
return listener
|
||||||
|
|
||||||
|
|
||||||
def sample_tls_sni_container_tuple(tls_container_id=None, tls_container=None):
|
def sample_tls_sni_container_tuple(tls_container_id=None, tls_container=None):
|
|
@ -22,7 +22,7 @@ import octavia.common.exceptions as exceptions
|
||||||
import octavia.common.tls_utils.cert_parser as cert_parser
|
import octavia.common.tls_utils.cert_parser as cert_parser
|
||||||
from octavia.tests.unit import base
|
from octavia.tests.unit import base
|
||||||
from octavia.tests.unit.common.sample_configs import sample_certs
|
from octavia.tests.unit.common.sample_configs import sample_certs
|
||||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
from octavia.tests.unit.common.sample_configs import sample_configs_combined
|
||||||
|
|
||||||
|
|
||||||
class TestTLSParseUtils(base.TestCase):
|
class TestTLSParseUtils(base.TestCase):
|
||||||
|
@ -144,8 +144,8 @@ class TestTLSParseUtils(base.TestCase):
|
||||||
|
|
||||||
@mock.patch('oslo_context.context.RequestContext')
|
@mock.patch('oslo_context.context.RequestContext')
|
||||||
def test_load_certificates(self, mock_oslo):
|
def test_load_certificates(self, mock_oslo):
|
||||||
listener = sample_configs.sample_listener_tuple(tls=True, sni=True,
|
listener = sample_configs_combined.sample_listener_tuple(
|
||||||
client_ca_cert=True)
|
tls=True, sni=True, client_ca_cert=True)
|
||||||
client = mock.MagicMock()
|
client = mock.MagicMock()
|
||||||
context = mock.Mock()
|
context = mock.Mock()
|
||||||
context.project_id = '12345'
|
context.project_id = '12345'
|
||||||
|
@ -165,8 +165,8 @@ class TestTLSParseUtils(base.TestCase):
|
||||||
client.assert_has_calls(calls_cert_mngr)
|
client.assert_has_calls(calls_cert_mngr)
|
||||||
|
|
||||||
# Test asking for nothing
|
# Test asking for nothing
|
||||||
listener = sample_configs.sample_listener_tuple(tls=False, sni=False,
|
listener = sample_configs_combined.sample_listener_tuple(
|
||||||
client_ca_cert=False)
|
tls=False, sni=False, client_ca_cert=False)
|
||||||
client = mock.MagicMock()
|
client = mock.MagicMock()
|
||||||
with mock.patch.object(cert_parser,
|
with mock.patch.object(cert_parser,
|
||||||
'_map_cert_tls_container') as mock_map:
|
'_map_cert_tls_container') as mock_map:
|
||||||
|
@ -211,7 +211,7 @@ class TestTLSParseUtils(base.TestCase):
|
||||||
|
|
||||||
def test_build_pem(self):
|
def test_build_pem(self):
|
||||||
expected = b'imacert\nimakey\nimainter\nimainter2\n'
|
expected = b'imacert\nimakey\nimainter\nimainter2\n'
|
||||||
tls_tuple = sample_configs.sample_tls_container_tuple(
|
tls_tuple = sample_configs_combined.sample_tls_container_tuple(
|
||||||
certificate=b'imacert', private_key=b'imakey',
|
certificate=b'imacert', private_key=b'imakey',
|
||||||
intermediates=[b'imainter', b'imainter2'])
|
intermediates=[b'imainter', b'imainter2'])
|
||||||
self.assertEqual(expected, cert_parser.build_pem(tls_tuple))
|
self.assertEqual(expected, cert_parser.build_pem(tls_tuple))
|
||||||
|
|
|
@ -136,7 +136,8 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
if listener:
|
if listener:
|
||||||
listener_ref = {'listener-id-1': {
|
listener_ref = {'listener-id-1': {
|
||||||
constants.OPERATING_STATUS: 'bogus',
|
constants.OPERATING_STATUS: 'bogus',
|
||||||
'protocol': listener_protocol}}
|
'protocol': listener_protocol,
|
||||||
|
'enabled': True}}
|
||||||
lb_ref['listeners'] = listener_ref
|
lb_ref['listeners'] = listener_ref
|
||||||
|
|
||||||
return lb_ref
|
return lb_ref
|
||||||
|
@ -145,6 +146,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {},
|
"listeners": {},
|
||||||
"recv_time": time.time()
|
"recv_time": time.time()
|
||||||
}
|
}
|
||||||
|
@ -161,6 +163,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {},
|
"listeners": {},
|
||||||
"recv_time": time.time()
|
"recv_time": time.time()
|
||||||
}
|
}
|
||||||
|
@ -178,6 +181,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {},
|
"listeners": {},
|
||||||
"recv_time": time.time()
|
"recv_time": time.time()
|
||||||
}
|
}
|
||||||
|
@ -194,6 +198,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
hb_interval = cfg.CONF.health_manager.heartbeat_interval
|
hb_interval = cfg.CONF.health_manager.heartbeat_interval
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {},
|
"listeners": {},
|
||||||
"recv_time": time.time() - hb_interval - 1 # extra -1 for buffer
|
"recv_time": time.time() - hb_interval - 1 # extra -1 for buffer
|
||||||
}
|
}
|
||||||
|
@ -211,6 +216,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -233,9 +239,9 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
self.session_mock.rollback.assert_called_once()
|
self.session_mock.rollback.assert_called_once()
|
||||||
|
|
||||||
def test_update_health_online(self):
|
def test_update_health_online(self):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -281,10 +287,53 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
self.hm.update_health(health, '192.0.2.1')
|
self.hm.update_health(health, '192.0.2.1')
|
||||||
self.assertTrue(not self.amphora_health_repo.replace.called)
|
self.assertTrue(not self.amphora_health_repo.replace.called)
|
||||||
|
|
||||||
|
def test_update_health_listener_disabled(self):
|
||||||
|
health = {
|
||||||
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
|
"listeners": {
|
||||||
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
"members": {"member-id-1": constants.UP}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"recv_time": time.time()
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_ref = self._make_fake_lb_health_dict()
|
||||||
|
lb_ref['listeners']['listener-id-2'] = {
|
||||||
|
'enabled': False, constants.OPERATING_STATUS: constants.OFFLINE}
|
||||||
|
self.amphora_repo.get_lb_for_health_update.return_value = lb_ref
|
||||||
|
self.hm.update_health(health, '192.0.2.1')
|
||||||
|
self.assertTrue(self.amphora_health_repo.replace.called)
|
||||||
|
|
||||||
|
# test listener, member
|
||||||
|
for listener_id, listener in six.iteritems(
|
||||||
|
health.get('listeners', {})):
|
||||||
|
|
||||||
|
self.listener_repo.update.assert_any_call(
|
||||||
|
self.session_mock, listener_id,
|
||||||
|
operating_status=constants.ONLINE)
|
||||||
|
|
||||||
|
for pool_id, pool in six.iteritems(listener.get('pools', {})):
|
||||||
|
|
||||||
|
self.hm.pool_repo.update.assert_any_call(
|
||||||
|
self.session_mock, pool_id,
|
||||||
|
operating_status=constants.ONLINE)
|
||||||
|
|
||||||
|
for member_id, member in six.iteritems(
|
||||||
|
pool.get('members', {})):
|
||||||
|
self.member_repo.update.assert_any_call(
|
||||||
|
self.session_mock, member_id,
|
||||||
|
operating_status=constants.ONLINE)
|
||||||
|
|
||||||
def test_update_lb_pool_health_offline(self):
|
def test_update_lb_pool_health_offline(self):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {}}
|
"listener-id-1": {"status": constants.OPEN, "pools": {}}
|
||||||
},
|
},
|
||||||
|
@ -312,6 +361,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
def test_update_lb_multiple_listeners_one_error_pool(self):
|
def test_update_lb_multiple_listeners_one_error_pool(self):
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.DOWN,
|
"pool-id-1": {"status": constants.DOWN,
|
||||||
|
@ -333,7 +383,8 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
lb_ref['listeners']['listener-id-2'] = {
|
lb_ref['listeners']['listener-id-2'] = {
|
||||||
constants.OPERATING_STATUS: 'bogus',
|
constants.OPERATING_STATUS: 'bogus',
|
||||||
'protocol': constants.PROTOCOL_TCP}
|
'protocol': constants.PROTOCOL_TCP,
|
||||||
|
'enabled': True}
|
||||||
|
|
||||||
self.amphora_repo.get_lb_for_health_update.return_value = lb_ref
|
self.amphora_repo.get_lb_for_health_update.return_value = lb_ref
|
||||||
self.hm.update_health(health, '192.0.2.1')
|
self.hm.update_health(health, '192.0.2.1')
|
||||||
|
@ -359,6 +410,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -396,10 +448,54 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
self.session_mock, member_id,
|
self.session_mock, member_id,
|
||||||
operating_status=constants.ONLINE)
|
operating_status=constants.ONLINE)
|
||||||
|
|
||||||
|
def test_update_v2_lb_and_list_pool_health_online(self):
|
||||||
|
|
||||||
|
health = {
|
||||||
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 2,
|
||||||
|
"listeners": {
|
||||||
|
"listener-id-1": {"status": constants.OPEN}
|
||||||
|
},
|
||||||
|
"pools": {
|
||||||
|
"pool-id-1:listener-id-1": {
|
||||||
|
"status": constants.UP,
|
||||||
|
"members": {"member-id-1": constants.UP}},
|
||||||
|
"pool-id-1:listener-id-1": {
|
||||||
|
"status": constants.UP,
|
||||||
|
"members": {"member-id-1": constants.UP}}},
|
||||||
|
"recv_time": time.time()
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_ref = self._make_fake_lb_health_dict()
|
||||||
|
self.amphora_repo.get_lb_for_health_update.return_value = lb_ref
|
||||||
|
self.hm.update_health(health, '192.0.2.1')
|
||||||
|
self.assertTrue(self.amphora_health_repo.replace.called)
|
||||||
|
|
||||||
|
# test listener, member
|
||||||
|
for listener_id, listener in six.iteritems(
|
||||||
|
health.get('listeners', {})):
|
||||||
|
|
||||||
|
self.listener_repo.update.assert_any_call(
|
||||||
|
self.session_mock, listener_id,
|
||||||
|
operating_status=constants.ONLINE)
|
||||||
|
|
||||||
|
for pool_id, pool in six.iteritems(health.get('pools', {})):
|
||||||
|
# We should not double process a shared pool
|
||||||
|
self.hm.pool_repo.update.assert_called_once_with(
|
||||||
|
self.session_mock, 'pool-id-1',
|
||||||
|
operating_status=constants.ONLINE)
|
||||||
|
|
||||||
|
for member_id, member in six.iteritems(
|
||||||
|
pool.get('members', {})):
|
||||||
|
self.member_repo.update.assert_any_call(
|
||||||
|
self.session_mock, member_id,
|
||||||
|
operating_status=constants.ONLINE)
|
||||||
|
|
||||||
def test_update_pool_offline(self):
|
def test_update_pool_offline(self):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-5": {"status": constants.UP,
|
"pool-id-5": {"status": constants.UP,
|
||||||
|
@ -436,6 +532,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {
|
"listener-id-1": {
|
||||||
"status": constants.OPEN,
|
"status": constants.OPEN,
|
||||||
|
@ -475,6 +572,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {
|
"listener-id-1": {
|
||||||
"status": constants.OPEN,
|
"status": constants.OPEN,
|
||||||
|
@ -514,6 +612,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {
|
"listener-id-1": {
|
||||||
"status": constants.OPEN,
|
"status": constants.OPEN,
|
||||||
|
@ -547,6 +646,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -589,6 +689,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -626,6 +727,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -668,6 +770,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -710,6 +813,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {
|
"listener-id-1": {
|
||||||
"status": constants.OPEN,
|
"status": constants.OPEN,
|
||||||
|
@ -755,6 +859,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.FULL, "pools": {
|
"listener-id-1": {"status": constants.FULL, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -804,6 +909,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.DOWN,
|
"pool-id-1": {"status": constants.DOWN,
|
||||||
|
@ -847,6 +953,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.FULL, "pools": {
|
"listener-id-1": {"status": constants.FULL, "pools": {
|
||||||
"pool-id-1": {"status": constants.DOWN,
|
"pool-id-1": {"status": constants.DOWN,
|
||||||
|
@ -895,7 +1002,8 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
lb_ref['listeners']['listener-id-%s' % i] = {
|
lb_ref['listeners']['listener-id-%s' % i] = {
|
||||||
constants.OPERATING_STATUS: 'bogus',
|
constants.OPERATING_STATUS: 'bogus',
|
||||||
'protocol': constants.PROTOCOL_TCP}
|
'protocol': constants.PROTOCOL_TCP,
|
||||||
|
'enabled': True}
|
||||||
|
|
||||||
if i == 3:
|
if i == 3:
|
||||||
members_dict = {'member-id-3': {
|
members_dict = {'member-id-3': {
|
||||||
|
@ -936,6 +1044,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {"status": constants.OPEN, "pools": {
|
"listener-id-1": {"status": constants.OPEN, "pools": {
|
||||||
"pool-id-1": {"status": constants.UP,
|
"pool-id-1": {"status": constants.UP,
|
||||||
|
@ -1000,6 +1109,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
def test_update_health_no_status_change(self):
|
def test_update_health_no_status_change(self):
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
"listener-id-1": {
|
"listener-id-1": {
|
||||||
"status": constants.OPEN, "pools": {
|
"status": constants.OPEN, "pools": {
|
||||||
|
@ -1036,6 +1146,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
def test_update_health_lb_admin_down(self):
|
def test_update_health_lb_admin_down(self):
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {},
|
"listeners": {},
|
||||||
"recv_time": time.time()}
|
"recv_time": time.time()}
|
||||||
|
|
||||||
|
@ -1118,10 +1229,12 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
listener_protocol=constants.PROTOCOL_UDP)
|
listener_protocol=constants.PROTOCOL_UDP)
|
||||||
lb_ref['listeners']['listener-id-2'] = {
|
lb_ref['listeners']['listener-id-2'] = {
|
||||||
constants.OPERATING_STATUS: 'bogus',
|
constants.OPERATING_STATUS: 'bogus',
|
||||||
'protocol': constants.PROTOCOL_UDP}
|
'protocol': constants.PROTOCOL_UDP,
|
||||||
|
'enabled': True}
|
||||||
lb_ref['listeners']['listener-id-3'] = {
|
lb_ref['listeners']['listener-id-3'] = {
|
||||||
constants.OPERATING_STATUS: 'bogus',
|
constants.OPERATING_STATUS: 'bogus',
|
||||||
'protocol': constants.PROTOCOL_UDP}
|
'protocol': constants.PROTOCOL_UDP,
|
||||||
|
'enabled': True}
|
||||||
|
|
||||||
self.amphora_repo.get_lb_for_health_update.return_value = lb_ref
|
self.amphora_repo.get_lb_for_health_update.return_value = lb_ref
|
||||||
self.hm.update_health(health, '192.0.2.1')
|
self.hm.update_health(health, '192.0.2.1')
|
||||||
|
@ -1132,6 +1245,7 @@ class TestUpdateHealthDb(base.TestCase):
|
||||||
def test_update_health_no_db_lb(self):
|
def test_update_health_no_db_lb(self):
|
||||||
health = {
|
health = {
|
||||||
"id": self.FAKE_UUID_1,
|
"id": self.FAKE_UUID_1,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {},
|
"listeners": {},
|
||||||
"recv_time": time.time()
|
"recv_time": time.time()
|
||||||
}
|
}
|
||||||
|
@ -1288,6 +1402,7 @@ class TestUpdateStatsDb(base.TestCase):
|
||||||
|
|
||||||
health = {
|
health = {
|
||||||
"id": self.amphora_id,
|
"id": self.amphora_id,
|
||||||
|
"ver": 1,
|
||||||
"listeners": {
|
"listeners": {
|
||||||
self.listener_id: {
|
self.listener_id: {
|
||||||
"status": constants.OPEN,
|
"status": constants.OPEN,
|
||||||
|
|
|
@ -128,9 +128,10 @@ class TestLoadBalancerFlows(base.TestCase):
|
||||||
self.assertIsInstance(lb_flow, flow.Flow)
|
self.assertIsInstance(lb_flow, flow.Flow)
|
||||||
|
|
||||||
self.assertIn(constants.LOADBALANCER, lb_flow.requires)
|
self.assertIn(constants.LOADBALANCER, lb_flow.requires)
|
||||||
|
self.assertIn(constants.UPDATE_DICT, lb_flow.requires)
|
||||||
|
|
||||||
self.assertEqual(0, len(lb_flow.provides))
|
self.assertEqual(0, len(lb_flow.provides))
|
||||||
self.assertEqual(3, len(lb_flow.requires))
|
self.assertEqual(2, len(lb_flow.requires))
|
||||||
|
|
||||||
def test_get_post_lb_amp_association_flow(self, mock_get_net_driver):
|
def test_get_post_lb_amp_association_flow(self, mock_get_net_driver):
|
||||||
amp_flow = self.LBFlow.get_post_lb_amp_association_flow(
|
amp_flow = self.LBFlow.get_post_lb_amp_association_flow(
|
||||||
|
|
|
@ -93,15 +93,15 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
constants.CONN_RETRY_INTERVAL: 4}
|
constants.CONN_RETRY_INTERVAL: 4}
|
||||||
|
|
||||||
amp_list_update_obj = amphora_driver_tasks.AmpListenersUpdate()
|
amp_list_update_obj = amphora_driver_tasks.AmpListenersUpdate()
|
||||||
amp_list_update_obj.execute([_listener_mock], 0,
|
amp_list_update_obj.execute(_load_balancer_mock, 0,
|
||||||
[_amphora_mock], timeout_dict)
|
[_amphora_mock], timeout_dict)
|
||||||
|
|
||||||
mock_driver.update_amphora_listeners.assert_called_once_with(
|
mock_driver.update_amphora_listeners.assert_called_once_with(
|
||||||
[_listener_mock], 0, [_amphora_mock], timeout_dict)
|
_load_balancer_mock, _amphora_mock, timeout_dict)
|
||||||
|
|
||||||
mock_driver.update_amphora_listeners.side_effect = Exception('boom')
|
mock_driver.update_amphora_listeners.side_effect = Exception('boom')
|
||||||
|
|
||||||
amp_list_update_obj.execute([_listener_mock], 0,
|
amp_list_update_obj.execute(_load_balancer_mock, 0,
|
||||||
[_amphora_mock], timeout_dict)
|
[_amphora_mock], timeout_dict)
|
||||||
|
|
||||||
mock_amphora_repo_update.assert_called_once_with(
|
mock_amphora_repo_update.assert_called_once_with(
|
||||||
|
@ -117,9 +117,9 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
mock_amphora_repo_update):
|
mock_amphora_repo_update):
|
||||||
|
|
||||||
listener_update_obj = amphora_driver_tasks.ListenersUpdate()
|
listener_update_obj = amphora_driver_tasks.ListenersUpdate()
|
||||||
listener_update_obj.execute(_load_balancer_mock, [_listener_mock])
|
listener_update_obj.execute(_load_balancer_mock)
|
||||||
|
|
||||||
mock_driver.update.assert_called_once_with(_listener_mock, _vip_mock)
|
mock_driver.update.assert_called_once_with(_load_balancer_mock)
|
||||||
|
|
||||||
# Test the revert
|
# Test the revert
|
||||||
amp = listener_update_obj.revert(_load_balancer_mock)
|
amp = listener_update_obj.revert(_load_balancer_mock)
|
||||||
|
@ -152,12 +152,9 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
data_models.Listener(id='listener2')]
|
data_models.Listener(id='listener2')]
|
||||||
vip = data_models.Vip(ip_address='10.0.0.1')
|
vip = data_models.Vip(ip_address='10.0.0.1')
|
||||||
lb = data_models.LoadBalancer(id='lb1', listeners=listeners, vip=vip)
|
lb = data_models.LoadBalancer(id='lb1', listeners=listeners, vip=vip)
|
||||||
listeners_update_obj.execute(lb, listeners)
|
listeners_update_obj.execute(lb)
|
||||||
mock_driver.update.assert_has_calls([mock.call(listeners[0], vip),
|
mock_driver.update.assert_called_once_with(lb)
|
||||||
mock.call(listeners[1], vip)])
|
self.assertEqual(1, mock_driver.update.call_count)
|
||||||
self.assertEqual(2, mock_driver.update.call_count)
|
|
||||||
self.assertIsNotNone(listeners[0].load_balancer)
|
|
||||||
self.assertIsNotNone(listeners[1].load_balancer)
|
|
||||||
|
|
||||||
# Test the revert
|
# Test the revert
|
||||||
amp = listeners_update_obj.revert(lb)
|
amp = listeners_update_obj.revert(lb)
|
||||||
|
@ -171,69 +168,37 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
self.assertEqual(2, repo.ListenerRepository.update.call_count)
|
self.assertEqual(2, repo.ListenerRepository.update.call_count)
|
||||||
self.assertIsNone(amp)
|
self.assertIsNone(amp)
|
||||||
|
|
||||||
def test_listener_stop(self,
|
@mock.patch('octavia.controller.worker.task_utils.TaskUtils.'
|
||||||
mock_driver,
|
'mark_listener_prov_status_error')
|
||||||
mock_generate_uuid,
|
def test_listeners_start(self,
|
||||||
mock_log,
|
mock_prov_status_error,
|
||||||
mock_get_session,
|
mock_driver,
|
||||||
mock_listener_repo_get,
|
mock_generate_uuid,
|
||||||
mock_listener_repo_update,
|
mock_log,
|
||||||
mock_amphora_repo_update):
|
mock_get_session,
|
||||||
|
mock_listener_repo_get,
|
||||||
|
mock_listener_repo_update,
|
||||||
|
mock_amphora_repo_update):
|
||||||
|
listeners_start_obj = amphora_driver_tasks.ListenersStart()
|
||||||
|
mock_lb = mock.MagicMock()
|
||||||
|
mock_listener = mock.MagicMock()
|
||||||
|
mock_listener.id = '12345'
|
||||||
|
|
||||||
listener_stop_obj = amphora_driver_tasks.ListenerStop()
|
# Test no listeners
|
||||||
listener_stop_obj.execute(_load_balancer_mock, _listener_mock)
|
mock_lb.listeners = None
|
||||||
|
listeners_start_obj.execute(mock_lb)
|
||||||
|
mock_driver.start.assert_not_called()
|
||||||
|
|
||||||
mock_driver.stop.assert_called_once_with(_listener_mock, _vip_mock)
|
# Test with listeners
|
||||||
|
mock_driver.start.reset_mock()
|
||||||
|
mock_lb.listeners = [mock_listener]
|
||||||
|
listeners_start_obj.execute(mock_lb)
|
||||||
|
mock_driver.start.assert_called_once_with(mock_lb, None)
|
||||||
|
|
||||||
# Test the revert
|
# Test revert
|
||||||
amp = listener_stop_obj.revert(_listener_mock)
|
mock_lb.listeners = [mock_listener]
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
listeners_start_obj.revert(mock_lb)
|
||||||
_session_mock,
|
mock_prov_status_error.assert_called_once_with('12345')
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
# Test the revert with exception
|
|
||||||
repo.ListenerRepository.update.reset_mock()
|
|
||||||
mock_listener_repo_update.side_effect = Exception('fail')
|
|
||||||
amp = listener_stop_obj.revert(_listener_mock)
|
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
|
||||||
_session_mock,
|
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
def test_listener_start(self,
|
|
||||||
mock_driver,
|
|
||||||
mock_generate_uuid,
|
|
||||||
mock_log,
|
|
||||||
mock_get_session,
|
|
||||||
mock_listener_repo_get,
|
|
||||||
mock_listener_repo_update,
|
|
||||||
mock_amphora_repo_update):
|
|
||||||
|
|
||||||
listener_start_obj = amphora_driver_tasks.ListenerStart()
|
|
||||||
listener_start_obj.execute(_load_balancer_mock, _listener_mock)
|
|
||||||
|
|
||||||
mock_driver.start.assert_called_once_with(_listener_mock, _vip_mock)
|
|
||||||
|
|
||||||
# Test the revert
|
|
||||||
amp = listener_start_obj.revert(_listener_mock)
|
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
|
||||||
_session_mock,
|
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
# Test the revert with exception
|
|
||||||
repo.ListenerRepository.update.reset_mock()
|
|
||||||
mock_listener_repo_update.side_effect = Exception('fail')
|
|
||||||
amp = listener_start_obj.revert(_listener_mock)
|
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
|
||||||
_session_mock,
|
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
def test_listener_delete(self,
|
def test_listener_delete(self,
|
||||||
mock_driver,
|
mock_driver,
|
||||||
|
@ -245,9 +210,9 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
mock_amphora_repo_update):
|
mock_amphora_repo_update):
|
||||||
|
|
||||||
listener_delete_obj = amphora_driver_tasks.ListenerDelete()
|
listener_delete_obj = amphora_driver_tasks.ListenerDelete()
|
||||||
listener_delete_obj.execute(_load_balancer_mock, _listener_mock)
|
listener_delete_obj.execute(_listener_mock)
|
||||||
|
|
||||||
mock_driver.delete.assert_called_once_with(_listener_mock, _vip_mock)
|
mock_driver.delete.assert_called_once_with(_listener_mock)
|
||||||
|
|
||||||
# Test the revert
|
# Test the revert
|
||||||
amp = listener_delete_obj.revert(_listener_mock)
|
amp = listener_delete_obj.revert(_listener_mock)
|
||||||
|
|
|
@ -49,6 +49,7 @@ _health_mon_mock = mock.MagicMock()
|
||||||
_vip_mock = mock.MagicMock()
|
_vip_mock = mock.MagicMock()
|
||||||
_listener_mock = mock.MagicMock()
|
_listener_mock = mock.MagicMock()
|
||||||
_load_balancer_mock = mock.MagicMock()
|
_load_balancer_mock = mock.MagicMock()
|
||||||
|
_load_balancer_mock.listeners = [_listener_mock]
|
||||||
_member_mock = mock.MagicMock()
|
_member_mock = mock.MagicMock()
|
||||||
_pool_mock = mock.MagicMock()
|
_pool_mock = mock.MagicMock()
|
||||||
_l7policy_mock = mock.MagicMock()
|
_l7policy_mock = mock.MagicMock()
|
||||||
|
@ -324,7 +325,7 @@ class TestControllerWorker(base.TestCase):
|
||||||
store={constants.LOADBALANCER:
|
store={constants.LOADBALANCER:
|
||||||
_load_balancer_mock,
|
_load_balancer_mock,
|
||||||
constants.LISTENERS:
|
constants.LISTENERS:
|
||||||
[_listener_mock]}))
|
_load_balancer_mock.listeners}))
|
||||||
|
|
||||||
_flow_mock.run.assert_called_once_with()
|
_flow_mock.run.assert_called_once_with()
|
||||||
self.assertEqual(2, mock_listener_repo_get.call_count)
|
self.assertEqual(2, mock_listener_repo_get.call_count)
|
||||||
|
|
|
@ -128,9 +128,10 @@ class TestLoadBalancerFlows(base.TestCase):
|
||||||
self.assertIsInstance(lb_flow, flow.Flow)
|
self.assertIsInstance(lb_flow, flow.Flow)
|
||||||
|
|
||||||
self.assertIn(constants.LOADBALANCER, lb_flow.requires)
|
self.assertIn(constants.LOADBALANCER, lb_flow.requires)
|
||||||
|
self.assertIn(constants.UPDATE_DICT, lb_flow.requires)
|
||||||
|
|
||||||
self.assertEqual(0, len(lb_flow.provides))
|
self.assertEqual(0, len(lb_flow.provides))
|
||||||
self.assertEqual(3, len(lb_flow.requires))
|
self.assertEqual(2, len(lb_flow.requires))
|
||||||
|
|
||||||
def test_get_post_lb_amp_association_flow(self, mock_get_net_driver):
|
def test_get_post_lb_amp_association_flow(self, mock_get_net_driver):
|
||||||
amp_flow = self.LBFlow.get_post_lb_amp_association_flow(
|
amp_flow = self.LBFlow.get_post_lb_amp_association_flow(
|
||||||
|
|
|
@ -93,15 +93,15 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
constants.CONN_RETRY_INTERVAL: 4}
|
constants.CONN_RETRY_INTERVAL: 4}
|
||||||
|
|
||||||
amp_list_update_obj = amphora_driver_tasks.AmpListenersUpdate()
|
amp_list_update_obj = amphora_driver_tasks.AmpListenersUpdate()
|
||||||
amp_list_update_obj.execute([_listener_mock], 0,
|
amp_list_update_obj.execute(_load_balancer_mock, 0,
|
||||||
[_amphora_mock], timeout_dict)
|
[_amphora_mock], timeout_dict)
|
||||||
|
|
||||||
mock_driver.update_amphora_listeners.assert_called_once_with(
|
mock_driver.update_amphora_listeners.assert_called_once_with(
|
||||||
[_listener_mock], 0, [_amphora_mock], timeout_dict)
|
_load_balancer_mock, _amphora_mock, timeout_dict)
|
||||||
|
|
||||||
mock_driver.update_amphora_listeners.side_effect = Exception('boom')
|
mock_driver.update_amphora_listeners.side_effect = Exception('boom')
|
||||||
|
|
||||||
amp_list_update_obj.execute([_listener_mock], 0,
|
amp_list_update_obj.execute(_load_balancer_mock, 0,
|
||||||
[_amphora_mock], timeout_dict)
|
[_amphora_mock], timeout_dict)
|
||||||
|
|
||||||
mock_amphora_repo_update.assert_called_once_with(
|
mock_amphora_repo_update.assert_called_once_with(
|
||||||
|
@ -117,9 +117,9 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
mock_amphora_repo_update):
|
mock_amphora_repo_update):
|
||||||
|
|
||||||
listener_update_obj = amphora_driver_tasks.ListenersUpdate()
|
listener_update_obj = amphora_driver_tasks.ListenersUpdate()
|
||||||
listener_update_obj.execute(_load_balancer_mock, [_listener_mock])
|
listener_update_obj.execute(_load_balancer_mock)
|
||||||
|
|
||||||
mock_driver.update.assert_called_once_with(_listener_mock, _vip_mock)
|
mock_driver.update.assert_called_once_with(_load_balancer_mock)
|
||||||
|
|
||||||
# Test the revert
|
# Test the revert
|
||||||
amp = listener_update_obj.revert(_load_balancer_mock)
|
amp = listener_update_obj.revert(_load_balancer_mock)
|
||||||
|
@ -152,12 +152,9 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
data_models.Listener(id='listener2')]
|
data_models.Listener(id='listener2')]
|
||||||
vip = data_models.Vip(ip_address='10.0.0.1')
|
vip = data_models.Vip(ip_address='10.0.0.1')
|
||||||
lb = data_models.LoadBalancer(id='lb1', listeners=listeners, vip=vip)
|
lb = data_models.LoadBalancer(id='lb1', listeners=listeners, vip=vip)
|
||||||
listeners_update_obj.execute(lb, listeners)
|
listeners_update_obj.execute(lb)
|
||||||
mock_driver.update.assert_has_calls([mock.call(listeners[0], vip),
|
mock_driver.update.assert_called_once_with(lb)
|
||||||
mock.call(listeners[1], vip)])
|
self.assertEqual(1, mock_driver.update.call_count)
|
||||||
self.assertEqual(2, mock_driver.update.call_count)
|
|
||||||
self.assertIsNotNone(listeners[0].load_balancer)
|
|
||||||
self.assertIsNotNone(listeners[1].load_balancer)
|
|
||||||
|
|
||||||
# Test the revert
|
# Test the revert
|
||||||
amp = listeners_update_obj.revert(lb)
|
amp = listeners_update_obj.revert(lb)
|
||||||
|
@ -171,69 +168,37 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
self.assertEqual(2, repo.ListenerRepository.update.call_count)
|
self.assertEqual(2, repo.ListenerRepository.update.call_count)
|
||||||
self.assertIsNone(amp)
|
self.assertIsNone(amp)
|
||||||
|
|
||||||
def test_listener_stop(self,
|
@mock.patch('octavia.controller.worker.task_utils.TaskUtils.'
|
||||||
mock_driver,
|
'mark_listener_prov_status_error')
|
||||||
mock_generate_uuid,
|
def test_listeners_start(self,
|
||||||
mock_log,
|
mock_prov_status_error,
|
||||||
mock_get_session,
|
mock_driver,
|
||||||
mock_listener_repo_get,
|
mock_generate_uuid,
|
||||||
mock_listener_repo_update,
|
mock_log,
|
||||||
mock_amphora_repo_update):
|
mock_get_session,
|
||||||
|
mock_listener_repo_get,
|
||||||
|
mock_listener_repo_update,
|
||||||
|
mock_amphora_repo_update):
|
||||||
|
listeners_start_obj = amphora_driver_tasks.ListenersStart()
|
||||||
|
mock_lb = mock.MagicMock()
|
||||||
|
mock_listener = mock.MagicMock()
|
||||||
|
mock_listener.id = '12345'
|
||||||
|
|
||||||
listener_stop_obj = amphora_driver_tasks.ListenerStop()
|
# Test no listeners
|
||||||
listener_stop_obj.execute(_load_balancer_mock, _listener_mock)
|
mock_lb.listeners = None
|
||||||
|
listeners_start_obj.execute(mock_lb)
|
||||||
|
mock_driver.start.assert_not_called()
|
||||||
|
|
||||||
mock_driver.stop.assert_called_once_with(_listener_mock, _vip_mock)
|
# Test with listeners
|
||||||
|
mock_driver.start.reset_mock()
|
||||||
|
mock_lb.listeners = [mock_listener]
|
||||||
|
listeners_start_obj.execute(mock_lb)
|
||||||
|
mock_driver.start.assert_called_once_with(mock_lb, None)
|
||||||
|
|
||||||
# Test the revert
|
# Test revert
|
||||||
amp = listener_stop_obj.revert(_listener_mock)
|
mock_lb.listeners = [mock_listener]
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
listeners_start_obj.revert(mock_lb)
|
||||||
_session_mock,
|
mock_prov_status_error.assert_called_once_with('12345')
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
# Test the revert with exception
|
|
||||||
repo.ListenerRepository.update.reset_mock()
|
|
||||||
mock_listener_repo_update.side_effect = Exception('fail')
|
|
||||||
amp = listener_stop_obj.revert(_listener_mock)
|
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
|
||||||
_session_mock,
|
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
def test_listener_start(self,
|
|
||||||
mock_driver,
|
|
||||||
mock_generate_uuid,
|
|
||||||
mock_log,
|
|
||||||
mock_get_session,
|
|
||||||
mock_listener_repo_get,
|
|
||||||
mock_listener_repo_update,
|
|
||||||
mock_amphora_repo_update):
|
|
||||||
|
|
||||||
listener_start_obj = amphora_driver_tasks.ListenerStart()
|
|
||||||
listener_start_obj.execute(_load_balancer_mock, _listener_mock)
|
|
||||||
|
|
||||||
mock_driver.start.assert_called_once_with(_listener_mock, _vip_mock)
|
|
||||||
|
|
||||||
# Test the revert
|
|
||||||
amp = listener_start_obj.revert(_listener_mock)
|
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
|
||||||
_session_mock,
|
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
# Test the revert with exception
|
|
||||||
repo.ListenerRepository.update.reset_mock()
|
|
||||||
mock_listener_repo_update.side_effect = Exception('fail')
|
|
||||||
amp = listener_start_obj.revert(_listener_mock)
|
|
||||||
repo.ListenerRepository.update.assert_called_once_with(
|
|
||||||
_session_mock,
|
|
||||||
id=LISTENER_ID,
|
|
||||||
provisioning_status=constants.ERROR)
|
|
||||||
self.assertIsNone(amp)
|
|
||||||
|
|
||||||
def test_listener_delete(self,
|
def test_listener_delete(self,
|
||||||
mock_driver,
|
mock_driver,
|
||||||
|
@ -245,9 +210,9 @@ class TestAmphoraDriverTasks(base.TestCase):
|
||||||
mock_amphora_repo_update):
|
mock_amphora_repo_update):
|
||||||
|
|
||||||
listener_delete_obj = amphora_driver_tasks.ListenerDelete()
|
listener_delete_obj = amphora_driver_tasks.ListenerDelete()
|
||||||
listener_delete_obj.execute(_load_balancer_mock, _listener_mock)
|
listener_delete_obj.execute(_listener_mock)
|
||||||
|
|
||||||
mock_driver.delete.assert_called_once_with(_listener_mock, _vip_mock)
|
mock_driver.delete.assert_called_once_with(_listener_mock)
|
||||||
|
|
||||||
# Test the revert
|
# Test the revert
|
||||||
amp = listener_delete_obj.revert(_listener_mock)
|
amp = listener_delete_obj.revert(_listener_mock)
|
||||||
|
|
|
@ -49,6 +49,7 @@ _health_mon_mock = mock.MagicMock()
|
||||||
_vip_mock = mock.MagicMock()
|
_vip_mock = mock.MagicMock()
|
||||||
_listener_mock = mock.MagicMock()
|
_listener_mock = mock.MagicMock()
|
||||||
_load_balancer_mock = mock.MagicMock()
|
_load_balancer_mock = mock.MagicMock()
|
||||||
|
_load_balancer_mock.listeners = [_listener_mock]
|
||||||
_member_mock = mock.MagicMock()
|
_member_mock = mock.MagicMock()
|
||||||
_pool_mock = mock.MagicMock()
|
_pool_mock = mock.MagicMock()
|
||||||
_l7policy_mock = mock.MagicMock()
|
_l7policy_mock = mock.MagicMock()
|
||||||
|
@ -324,7 +325,7 @@ class TestControllerWorker(base.TestCase):
|
||||||
store={constants.LOADBALANCER:
|
store={constants.LOADBALANCER:
|
||||||
_load_balancer_mock,
|
_load_balancer_mock,
|
||||||
constants.LISTENERS:
|
constants.LISTENERS:
|
||||||
[_listener_mock]}))
|
_load_balancer_mock.listeners}))
|
||||||
|
|
||||||
_flow_mock.run.assert_called_once_with()
|
_flow_mock.run.assert_called_once_with()
|
||||||
self.assertEqual(2, mock_listener_repo_get.call_count)
|
self.assertEqual(2, mock_listener_repo_get.call_count)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
A new amphora image is required to resolve the amphora memory issues when
|
||||||
|
a load balancer has multiple listeners and the amphora image uses
|
||||||
|
haproxy 1.8 or newer.
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixed an issue with load balancers that have multiple listeners when using
|
||||||
|
an amphora image that contains HAProxy 1.8 or newer. An updated amphora
|
||||||
|
image is required to apply this fix.
|
Loading…
Reference in New Issue