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:
Michael Johnson 2015-08-03 16:39:09 +00:00
parent adfc6977c6
commit fcc5dcf6e0
12 changed files with 226 additions and 121 deletions

View File

@ -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"

View File

@ -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"

View File

@ -1,3 +1,4 @@
Babel>=1.3
dib-utils
PyYAML
six>=1.9.0

View File

@ -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',

View File

@ -0,0 +1,3 @@
This element installs the pyroute2 python library.
Pyroute2 is a pure Python netlink and Linux network configuration library.

View File

@ -0,0 +1,5 @@
#!/bin/bash
set -eux
pip install -U 'pyroute2>=0.3.10'

View File

@ -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(

View File

@ -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'])

View File

@ -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)

View File

@ -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,

View File

@ -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()

View File

@ -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