Adds policy based routing for the amphora
1. Creates a new element for pyroute2 2. Adds this element to the amphora image 3. Updates the amphora REST interface to pass additional network information 4. Creates the policy based routes and rules on the amp during plug vip 5. Updates the REST API spec Change-Id: Ibd622ec302cf78c12ae2bd5d76d012ab619939a6
This commit is contained in:
parent
adfc6977c6
commit
fcc5dcf6e0
@ -330,6 +330,9 @@ fi
|
||||
# Add the Octavia Amphora agent.py element
|
||||
AMP_element_sequence="$AMP_element_sequence amphora-agent"
|
||||
|
||||
# Add pyroute2 element
|
||||
AMP_element_sequence="$AMP_element_sequence pyroute2"
|
||||
|
||||
# Add the vrrp Octacia element
|
||||
AMP_element_sequence="$AMP_element_sequence vrrp-octavia"
|
||||
|
||||
|
@ -35,6 +35,7 @@ virt-df -a $AMP_IMAGE_LOCATION | \
|
||||
grep -q "amphora-x64-haproxy.qcow2:/dev/sda1[ \t]*5015940[ \t]*.*"
|
||||
if [ $? != 0 ]; then
|
||||
echo "ERROR: Amphora image did not pass the default size test"
|
||||
echo "On Ubuntu you may need to run 'sudo chmod 0644 /boot/vmlinuz*' for libguestfs"
|
||||
exit 1
|
||||
else
|
||||
echo "Amphora image size is correct"
|
||||
|
@ -1,3 +1,4 @@
|
||||
Babel>=1.3
|
||||
dib-utils
|
||||
PyYAML
|
||||
six>=1.9.0
|
||||
|
@ -1084,7 +1084,11 @@ Plug VIP
|
||||
|
||||
* *:ip* = the vip's ip address
|
||||
|
||||
* **Data params:** none
|
||||
* **Data params:**
|
||||
|
||||
* *subnet_cidr*: The vip subnet in cidr notation
|
||||
* *gateway*: The vip subnet gateway address
|
||||
|
||||
* **Success Response:**
|
||||
|
||||
* Code: 202
|
||||
@ -1095,6 +1099,7 @@ Plug VIP
|
||||
* Code: 400
|
||||
|
||||
* Content: Invalid IP
|
||||
* Content: Invalid subnet information
|
||||
|
||||
* Code: 404
|
||||
|
||||
@ -1129,6 +1134,12 @@ Plug VIP
|
||||
POST URL:
|
||||
https://octavia-haproxy-img-00328.local/v0.1/plug/vip/203.0.113.2
|
||||
|
||||
JSON POST parameters:
|
||||
{
|
||||
'subnet_cidr': '203.0.113.0/24',
|
||||
'gateway': '203.0.113.1'
|
||||
}
|
||||
|
||||
JSON Response:
|
||||
{
|
||||
'message': 'OK',
|
||||
|
3
elements/pyroute2/README.rst
Normal file
3
elements/pyroute2/README.rst
Normal file
@ -0,0 +1,3 @@
|
||||
This element installs the pyroute2 python library.
|
||||
|
||||
Pyroute2 is a pure Python netlink and Linux network configuration library.
|
5
elements/pyroute2/install.d/10-pyroute2
Executable file
5
elements/pyroute2/install.d/10-pyroute2
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
pip install -U 'pyroute2>=0.3.10'
|
@ -20,6 +20,7 @@ import subprocess
|
||||
import flask
|
||||
import jinja2
|
||||
import netifaces
|
||||
import pyroute2
|
||||
from werkzeug import exceptions
|
||||
|
||||
from octavia.amphorae.backends.agent.api_server import util
|
||||
@ -37,7 +38,7 @@ template_port = j2_env.get_template(ETH_X_VIP_CONF)
|
||||
template_vip = j2_env.get_template(ETH_PORT_CONF)
|
||||
|
||||
|
||||
def plug_vip(vip):
|
||||
def plug_vip(vip, subnet_cidr, gateway):
|
||||
# validate vip
|
||||
try:
|
||||
socket.inet_aton(vip)
|
||||
@ -68,6 +69,41 @@ def plug_vip(vip):
|
||||
_bring_if_up("{interface}".format(interface=interface), 'VIP')
|
||||
_bring_if_up("{interface}:0".format(interface=interface), 'VIP')
|
||||
|
||||
# Setup policy based routes for the amphora
|
||||
|
||||
ip = pyroute2.IPRoute()
|
||||
|
||||
cidr_split = subnet_cidr.split('/')
|
||||
|
||||
num_interface = ip.link_lookup(ifname=interface)
|
||||
|
||||
ip.route('add',
|
||||
dst=cidr_split[0],
|
||||
mask=int(cidr_split[1]),
|
||||
oif=num_interface,
|
||||
table=1,
|
||||
rtproto='RTPROT_BOOT',
|
||||
rtscope='RT_SCOPE_LINK')
|
||||
|
||||
ip.route('add',
|
||||
dst='0.0.0.0',
|
||||
gateway=gateway,
|
||||
oif=num_interface,
|
||||
table=1,
|
||||
rtproto='RTPROT_BOOT')
|
||||
|
||||
ip.rule('add',
|
||||
table=1,
|
||||
action='FR_ACT_TO_TBL',
|
||||
src=cidr_split[0],
|
||||
src_len=int(cidr_split[1]))
|
||||
|
||||
ip.rule('add',
|
||||
table=1,
|
||||
action='FR_ACT_TO_TBL',
|
||||
dst=cidr_split[0],
|
||||
dst_len=int(cidr_split[1]))
|
||||
|
||||
return flask.make_response(flask.jsonify(dict(
|
||||
message="OK",
|
||||
details="VIP {vip} plugged on interface {interface}".format(
|
||||
|
@ -12,6 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
import flask
|
||||
@ -111,7 +112,17 @@ def delete_certificate(listener_id, filename):
|
||||
|
||||
@app.route('/' + api_server.VERSION + '/plug/vip/<vip>', methods=['POST'])
|
||||
def plug_vip(vip):
|
||||
return plug.plug_vip(vip)
|
||||
# Catch any issues with the subnet info json
|
||||
try:
|
||||
request_json = flask.request.data.decode('utf8')
|
||||
subnet_info = json.loads(request_json)
|
||||
assert 'subnet_cidr' in subnet_info
|
||||
assert 'gateway' in subnet_info
|
||||
except Exception:
|
||||
raise exceptions.BadRequest(description='Invalid subnet information')
|
||||
return plug.plug_vip(vip,
|
||||
subnet_info['subnet_cidr'],
|
||||
subnet_info['gateway'])
|
||||
|
||||
|
||||
@app.route('/' + api_server.VERSION + '/plug/network', methods=['POST'])
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
import functools
|
||||
import hashlib
|
||||
import json
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
@ -101,7 +102,12 @@ class HaproxyAmphoraLoadBalancerDriver(driver_base.AmphoraLoadBalancerDriver):
|
||||
|
||||
def post_vip_plug(self, load_balancer, amphorae_network_config):
|
||||
for amp in load_balancer.amphorae:
|
||||
self.client.plug_vip(amp, load_balancer.vip.ip_address)
|
||||
subnet = amphorae_network_config.get(amp.id).vip_subnet
|
||||
subnet_info = {'subnet_cidr': subnet.cidr,
|
||||
'gateway': subnet.gateway_ip}
|
||||
self.client.plug_vip(amp,
|
||||
load_balancer.vip.ip_address,
|
||||
subnet_info)
|
||||
|
||||
def post_network_plug(self, amphora):
|
||||
self.client.plug_network(amphora)
|
||||
@ -296,6 +302,8 @@ class AmphoraAPIClient(object):
|
||||
r = self.post(amp, 'plug/network')
|
||||
return exc.check_exception(r)
|
||||
|
||||
def plug_vip(self, amp, vip):
|
||||
r = self.post(amp, 'plug/vip/{vip}'.format(vip=vip))
|
||||
def plug_vip(self, amp, vip, subnet_info):
|
||||
r = self.post(amp,
|
||||
'plug/vip/{vip}'.format(vip=vip),
|
||||
json=json.dumps(subnet_info))
|
||||
return exc.check_exception(r)
|
||||
|
@ -508,15 +508,27 @@ class ServerTestCase(base.TestCase):
|
||||
@mock.patch('netifaces.interfaces')
|
||||
@mock.patch('netifaces.ifaddresses')
|
||||
@mock.patch('subprocess.check_output')
|
||||
def test_plug_VIP(self, mock_check_output, mock_ifaddress,
|
||||
@mock.patch('pyroute2.IPRoute')
|
||||
def test_plug_VIP(self, mock_pyroute2, mock_check_output, mock_ifaddress,
|
||||
mock_interfaces):
|
||||
|
||||
subnet_info = {'subnet_cidr': '10.0.0.0/24', 'gateway': '10.0.0.1'}
|
||||
|
||||
# malformated ip
|
||||
rv = self.app.post('/' + api_server.VERSION + '/plug/vip/error',
|
||||
data=json.dumps(subnet_info),
|
||||
content_type='application/json')
|
||||
self.assertEqual(400, rv.status_code)
|
||||
|
||||
# No subnet info
|
||||
rv = self.app.post('/' + api_server.VERSION + '/plug/vip/error')
|
||||
self.assertEqual(400, rv.status_code)
|
||||
|
||||
# No interface at all
|
||||
mock_interfaces.side_effect = [[]]
|
||||
rv = self.app.post('/' + api_server.VERSION + "/plug/vip/203.0.113.2")
|
||||
rv = self.app.post('/' + api_server.VERSION + "/plug/vip/203.0.113.2",
|
||||
content_type='application/json',
|
||||
data=json.dumps(subnet_info))
|
||||
self.assertEqual(404, rv.status_code)
|
||||
self.assertEqual(dict(details="No suitable network interface found"),
|
||||
json.loads(rv.data.decode('utf-8')))
|
||||
@ -524,7 +536,9 @@ class ServerTestCase(base.TestCase):
|
||||
# Two interfaces down
|
||||
mock_interfaces.side_effect = [['blah', 'blah2']]
|
||||
mock_ifaddress.side_effect = [['blabla'], ['blabla']]
|
||||
rv = self.app.post('/' + api_server.VERSION + "/plug/vip/203.0.113.2")
|
||||
rv = self.app.post('/' + api_server.VERSION + "/plug/vip/203.0.113.2",
|
||||
content_type='application/json',
|
||||
data=json.dumps(subnet_info))
|
||||
self.assertEqual(404, rv.status_code)
|
||||
self.assertEqual(dict(details="No suitable network interface found"),
|
||||
json.loads(rv.data.decode('utf-8')))
|
||||
@ -535,7 +549,9 @@ class ServerTestCase(base.TestCase):
|
||||
m = mock.mock_open()
|
||||
with mock.patch('%s.open' % BUILTINS, m, create=True):
|
||||
rv = self.app.post('/' + api_server.VERSION +
|
||||
"/plug/vip/203.0.113.2")
|
||||
"/plug/vip/203.0.113.2",
|
||||
content_type='application/json',
|
||||
data=json.dumps(subnet_info))
|
||||
self.assertEqual(202, rv.status_code)
|
||||
m.assert_called_once_with(
|
||||
'/etc/network/interfaces.d/blah.cfg', 'w')
|
||||
@ -561,7 +577,9 @@ class ServerTestCase(base.TestCase):
|
||||
m = mock.mock_open()
|
||||
with mock.patch('%s.open' % BUILTINS, m, create=True):
|
||||
rv = self.app.post('/' + api_server.VERSION +
|
||||
"/plug/vip/203.0.113.2")
|
||||
"/plug/vip/203.0.113.2",
|
||||
content_type='application/json',
|
||||
data=json.dumps(subnet_info))
|
||||
self.assertEqual(500, rv.status_code)
|
||||
self.assertEqual(
|
||||
{'details': RANDOM_ERROR,
|
||||
|
@ -24,9 +24,16 @@ from octavia.db import models
|
||||
from octavia.tests.unit import base as base
|
||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
||||
|
||||
FAKE_CIDR = '10.0.0.0/24'
|
||||
FAKE_GATEWAY = '10.0.0.1'
|
||||
FAKE_IP = 'fake'
|
||||
FAKE_PEM_FILENAME = "file_name"
|
||||
FAKE_SUBNET_INFO = {'subnet_cidr': FAKE_CIDR,
|
||||
'gateway': FAKE_GATEWAY}
|
||||
FAKE_UUID_1 = uuidutils.generate_uuid()
|
||||
|
||||
|
||||
class HaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
||||
FAKE_UUID_1 = uuidutils.generate_uuid()
|
||||
|
||||
def setUp(self):
|
||||
super(HaproxyAmphoraLoadBalancerDriverTest, self).setUp()
|
||||
@ -109,9 +116,12 @@ class HaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
||||
pass
|
||||
|
||||
def test_post_vip_plug(self):
|
||||
self.driver.post_vip_plug(self.lb, mock.Mock())
|
||||
amphorae_network_config = mock.MagicMock()
|
||||
amphorae_network_config.get().vip_subnet.cidr = FAKE_CIDR
|
||||
amphorae_network_config.get().vip_subnet.gateway_ip = FAKE_GATEWAY
|
||||
self.driver.post_vip_plug(self.lb, amphorae_network_config)
|
||||
self.driver.client.plug_vip.assert_called_once_with(
|
||||
self.amp, self.lb.vip.ip_address)
|
||||
self.amp, self.lb.vip.ip_address, FAKE_SUBNET_INFO)
|
||||
|
||||
def test_post_network_plug(self):
|
||||
self.driver.post_network_plug(self.amp)
|
||||
@ -119,8 +129,6 @@ class HaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
||||
|
||||
|
||||
class AmphoraAPIClientTest(base.TestCase):
|
||||
FAKE_UUID_1 = uuidutils.generate_uuid()
|
||||
FAKE_PEM_FILENAME = "file_name"
|
||||
|
||||
def setUp(self):
|
||||
super(AmphoraAPIClientTest, self).setUp()
|
||||
@ -131,7 +139,7 @@ class AmphoraAPIClientTest(base.TestCase):
|
||||
@requests_mock.mock()
|
||||
def test_get_info(self, m):
|
||||
info = {"hostname": "some_hostname", "version": "some_version",
|
||||
"api_version": "0.5", "uuid": self.FAKE_UUID_1}
|
||||
"api_version": "0.5", "uuid": FAKE_UUID_1}
|
||||
m.get("{base}/info".format(base=self.base_url),
|
||||
json=info)
|
||||
information = self.driver.get_info(self.amp)
|
||||
@ -166,7 +174,7 @@ class AmphoraAPIClientTest(base.TestCase):
|
||||
@requests_mock.mock()
|
||||
def test_get_details(self, m):
|
||||
details = {"hostname": "some_hostname", "version": "some_version",
|
||||
"api_version": "0.5", "uuid": self.FAKE_UUID_1,
|
||||
"api_version": "0.5", "uuid": FAKE_UUID_1,
|
||||
"network_tx": "some_tx", "network_rx": "some_rx",
|
||||
"active": True, "haproxy_count": 10}
|
||||
m.get("{base}/details".format(base=self.base_url),
|
||||
@ -203,7 +211,7 @@ class AmphoraAPIClientTest(base.TestCase):
|
||||
@requests_mock.mock()
|
||||
def test_get_all_listeners(self, m):
|
||||
listeners = [{"status": "ONLINE", "provisioning_status": "ACTIVE",
|
||||
"type": "PASSIVE", "uuid": self.FAKE_UUID_1}]
|
||||
"type": "PASSIVE", "uuid": FAKE_UUID_1}]
|
||||
m.get("{base}/listeners".format(base=self.base_url),
|
||||
json=listeners)
|
||||
all_listeners = self.driver.get_all_listeners(self.amp)
|
||||
@ -240,308 +248,308 @@ class AmphoraAPIClientTest(base.TestCase):
|
||||
@requests_mock.mock()
|
||||
def test_get_listener_status(self, m):
|
||||
listener = {"status": "ONLINE", "provisioning_status": "ACTIVE",
|
||||
"type": "PASSIVE", "uuid": self.FAKE_UUID_1}
|
||||
"type": "PASSIVE", "uuid": FAKE_UUID_1}
|
||||
m.get("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
json=listener)
|
||||
status = self.driver.get_listener_status(self.amp, self.FAKE_UUID_1)
|
||||
status = self.driver.get_listener_status(self.amp, FAKE_UUID_1)
|
||||
self.assertEqual(listener, status)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_listener_status_unauthorized(self, m):
|
||||
m.get("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=401)
|
||||
self.assertRaises(exc.Unauthorized,
|
||||
self.driver.get_listener_status, self.amp,
|
||||
self.FAKE_UUID_1)
|
||||
FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_listener_status_missing(self, m):
|
||||
m.get("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=404)
|
||||
self.assertRaises(exc.NotFound,
|
||||
self.driver.get_listener_status, self.amp,
|
||||
self.FAKE_UUID_1)
|
||||
FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_listener_status_server_error(self, m):
|
||||
m.get("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=500)
|
||||
self.assertRaises(exc.InternalServerError,
|
||||
self.driver.get_listener_status, self.amp,
|
||||
self.FAKE_UUID_1)
|
||||
FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_listener_status_service_unavailable(self, m):
|
||||
m.get("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable,
|
||||
self.driver.get_listener_status, self.amp,
|
||||
self.FAKE_UUID_1)
|
||||
FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_start_listener(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/start".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1))
|
||||
self.driver.start_listener(self.amp, self.FAKE_UUID_1)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1))
|
||||
self.driver.start_listener(self.amp, FAKE_UUID_1)
|
||||
self.assertTrue(m.called)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_start_listener_missing(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/start".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=404)
|
||||
self.assertRaises(exc.NotFound, self.driver.start_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_start_listener_unauthorized(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/start".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=401)
|
||||
self.assertRaises(exc.Unauthorized, self.driver.start_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_start_listener_server_error(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/start".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=500)
|
||||
self.assertRaises(exc.InternalServerError, self.driver.start_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_start_listener_service_unavailable(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/start".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable, self.driver.start_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_stop_listener(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/stop".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1))
|
||||
self.driver.stop_listener(self.amp, self.FAKE_UUID_1)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1))
|
||||
self.driver.stop_listener(self.amp, FAKE_UUID_1)
|
||||
self.assertTrue(m.called)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_stop_listener_missing(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/stop".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=404)
|
||||
self.assertRaises(exc.NotFound, self.driver.stop_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_stop_listener_unauthorized(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/stop".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=401)
|
||||
self.assertRaises(exc.Unauthorized, self.driver.stop_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_stop_listener_server_error(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/stop".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=500)
|
||||
self.assertRaises(exc.InternalServerError, self.driver.stop_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_stop_listener_service_unavailable(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/stop".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable, self.driver.stop_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_listener(self, m):
|
||||
m.delete("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1), json={})
|
||||
self.driver.delete_listener(self.amp, self.FAKE_UUID_1)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1), json={})
|
||||
self.driver.delete_listener(self.amp, FAKE_UUID_1)
|
||||
self.assertTrue(m.called)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_listener_missing(self, m):
|
||||
m.delete("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=404)
|
||||
self.assertRaises(exc.NotFound, self.driver.delete_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_listener_unauthorized(self, m):
|
||||
m.delete("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=401)
|
||||
self.assertRaises(exc.Unauthorized, self.driver.delete_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_listener_server_error(self, m):
|
||||
m.delete("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=500)
|
||||
self.assertRaises(exc.InternalServerError, self.driver.delete_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_listener_service_unavailable(self, m):
|
||||
m.delete("{base}/listeners/{listener_id}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable, self.driver.delete_listener,
|
||||
self.amp, self.FAKE_UUID_1)
|
||||
self.amp, FAKE_UUID_1)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_cert_pem(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME))
|
||||
self.driver.upload_cert_pem(self.amp, self.FAKE_UUID_1,
|
||||
self.FAKE_PEM_FILENAME,
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME))
|
||||
self.driver.upload_cert_pem(self.amp, FAKE_UUID_1,
|
||||
FAKE_PEM_FILENAME,
|
||||
"some_file")
|
||||
self.assertTrue(m.called)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_invalid_cert_pem(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=403)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=403)
|
||||
self.assertRaises(exc.InvalidRequest, self.driver.upload_cert_pem,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME,
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
|
||||
"some_file")
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_cert_pem_unauthorized(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=401)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=401)
|
||||
self.assertRaises(exc.Unauthorized, self.driver.upload_cert_pem,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME,
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
|
||||
"some_file")
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_cert_pem_server_error(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=500)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=500)
|
||||
self.assertRaises(exc.InternalServerError, self.driver.upload_cert_pem,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME,
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
|
||||
"some_file")
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_cert_pem_service_unavailable(self, m):
|
||||
m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=503)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable, self.driver.upload_cert_pem,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME,
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
|
||||
"some_file")
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_cert_5sum(self, m):
|
||||
md5sum = {"md5sum": "some_real_sum"}
|
||||
m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), json=md5sum)
|
||||
sum_test = self.driver.get_cert_md5sum(self.amp, self.FAKE_UUID_1,
|
||||
self.FAKE_PEM_FILENAME)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), json=md5sum)
|
||||
sum_test = self.driver.get_cert_md5sum(self.amp, FAKE_UUID_1,
|
||||
FAKE_PEM_FILENAME)
|
||||
self.assertIsNotNone(sum_test)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_cert_5sum_missing(self, m):
|
||||
m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=404)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=404)
|
||||
self.assertRaises(exc.NotFound, self.driver.get_cert_md5sum,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_cert_5sum_unauthorized(self, m):
|
||||
m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=401)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=401)
|
||||
self.assertRaises(exc.Unauthorized, self.driver.get_cert_md5sum,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_cert_5sum_server_error(self, m):
|
||||
m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=500)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=500)
|
||||
self.assertRaises(exc.InternalServerError, self.driver.get_cert_md5sum,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_get_cert_5sum_service_unavailable(self, m):
|
||||
m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=503)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable, self.driver.get_cert_md5sum,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_cert_pem(self, m):
|
||||
m.delete(
|
||||
"{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME))
|
||||
self.driver.delete_cert_pem(self.amp, self.FAKE_UUID_1,
|
||||
self.FAKE_PEM_FILENAME)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME))
|
||||
self.driver.delete_cert_pem(self.amp, FAKE_UUID_1,
|
||||
FAKE_PEM_FILENAME)
|
||||
self.assertTrue(m.called)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_cert_pem_missing(self, m):
|
||||
m.delete(
|
||||
"{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=404)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=404)
|
||||
self.assertRaises(exc.NotFound, self.driver.delete_cert_pem, self.amp,
|
||||
self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_cert_pem_unauthorized(self, m):
|
||||
m.delete(
|
||||
"{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=401)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=401)
|
||||
self.assertRaises(exc.Unauthorized, self.driver.delete_cert_pem,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_cert_pem_server_error(self, m):
|
||||
m.delete(
|
||||
"{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=500)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=500)
|
||||
self.assertRaises(exc.InternalServerError, self.driver.delete_cert_pem,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_delete_cert_pem_service_unavailable(self, m):
|
||||
m.delete(
|
||||
"{base}/listeners/{listener_id}/certificates/{filename}".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1,
|
||||
filename=self.FAKE_PEM_FILENAME), status_code=503)
|
||||
base=self.base_url, listener_id=FAKE_UUID_1,
|
||||
filename=FAKE_PEM_FILENAME), status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable, self.driver.delete_cert_pem,
|
||||
self.amp, self.FAKE_UUID_1, self.FAKE_PEM_FILENAME)
|
||||
self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_config(self, m):
|
||||
config = {"name": "fake_config"}
|
||||
m.put(
|
||||
"{base}/listeners/{listener_id}/haproxy".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
json=config)
|
||||
self.driver.upload_config(self.amp, self.FAKE_UUID_1, config)
|
||||
self.driver.upload_config(self.amp, FAKE_UUID_1, config)
|
||||
self.assertTrue(m.called)
|
||||
|
||||
@requests_mock.mock()
|
||||
@ -549,48 +557,47 @@ class AmphoraAPIClientTest(base.TestCase):
|
||||
config = '{"name": "bad_config"}'
|
||||
m.put(
|
||||
"{base}/listeners/{listener_id}/haproxy".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=403)
|
||||
self.assertRaises(exc.InvalidRequest, self.driver.upload_config,
|
||||
self.amp, self.FAKE_UUID_1, config)
|
||||
self.amp, FAKE_UUID_1, config)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_config_unauthorized(self, m):
|
||||
config = '{"name": "bad_config"}'
|
||||
m.put(
|
||||
"{base}/listeners/{listener_id}/haproxy".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=401)
|
||||
self.assertRaises(exc.Unauthorized, self.driver.upload_config,
|
||||
self.amp, self.FAKE_UUID_1, config)
|
||||
self.amp, FAKE_UUID_1, config)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_config_server_error(self, m):
|
||||
config = '{"name": "bad_config"}'
|
||||
m.put(
|
||||
"{base}/listeners/{listener_id}/haproxy".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=500)
|
||||
self.assertRaises(exc.InternalServerError, self.driver.upload_config,
|
||||
self.amp, self.FAKE_UUID_1, config)
|
||||
self.amp, FAKE_UUID_1, config)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_upload_config_service_unavailable(self, m):
|
||||
config = '{"name": "bad_config"}'
|
||||
m.put(
|
||||
"{base}/listeners/{listener_id}/haproxy".format(
|
||||
base=self.base_url, listener_id=self.FAKE_UUID_1),
|
||||
base=self.base_url, listener_id=FAKE_UUID_1),
|
||||
status_code=503)
|
||||
self.assertRaises(exc.ServiceUnavailable, self.driver.upload_config,
|
||||
self.amp, self.FAKE_UUID_1, config)
|
||||
self.amp, FAKE_UUID_1, config)
|
||||
|
||||
@requests_mock.mock()
|
||||
def test_plug_vip(self, m):
|
||||
FAKE_IP = 'fake'
|
||||
m.post("{base}/plug/vip/{vip}".format(
|
||||
base=self.base_url, vip=FAKE_IP)
|
||||
)
|
||||
self.driver.plug_vip(self.amp, FAKE_IP)
|
||||
self.driver.plug_vip(self.amp, FAKE_IP, FAKE_SUBNET_INFO)
|
||||
self.assertTrue(m.called)
|
||||
|
||||
@requests_mock.mock()
|
||||
|
@ -8,6 +8,7 @@ coverage>=3.6
|
||||
discover
|
||||
fixtures>=1.3.1
|
||||
mock>=1.2
|
||||
pyroute2>=0.3.10 # Apache-2.0
|
||||
python-subunit>=0.0.18
|
||||
ordereddict
|
||||
oslotest>=1.9.0 # Apache-2.0
|
||||
|
Loading…
Reference in New Issue
Block a user