Add support for single-create for APIv2
Still need to fix the entry-points for each individual type, but that wasn't even in the original spec. Not sure if we even want that. I think this may not do things EXACTLY how the old one did it, we'll need to look into whether it matters, as we never published docs for it and I don't think it ever actually worked properly in neutron-lbaas. Also closing a few bugs that are only peripherally related, because we (possibly me) forgot to tag them on the individual CRs, but I'm considering them closed as of this patch. See below for my reasoning on each individual bug, and feel free to post counter-arguments. For #1673546 (single-call create): This is the obvious one! For #1673499 (lb return pool object): Rolled into this patch as a matter of course, abandoned the original fix as it is no longer relevant. For #1544214 (root tags): All existing resources now have root tags. Any new ones will also need root tags, but I would consider this bug closed. For #1596636 (tenant facing API): Every object is now creatable via the v2 API, so I would consider this to be complete. Quotas and some additional work is being finished, but it's not necessary for this IMO. For #1665446 (hm id): This was resolved in the HM patch, I just forgot to close it, and including it here will ensure it is release-tracked. For #1685789 (listener quota): Just shoving it in here as I do the single-create quotas. For #1685827 (hm quota): Same as listener quota. Closes-Bug: #1673546 Closes-Bug: #1673499 Closes-Bug: #1544214 Closes-Bug: #1596636 Closes-Bug: #1665446 Closes-Bug: #1685789 Closes-Bug: #1685827 Depends-On: I3d86482a2999197a60a81d42afc5ef7a6e71e313 Change-Id: I4ff03593e1cfd8dca00a13c0550d6cf95b93d746
This commit is contained in:
parent
8fdcb88dee
commit
fb0da76c27
@ -24,11 +24,11 @@
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
"ip_address": "'192.0.2.16'",
|
||||
"address": "192.0.2.16",
|
||||
"protocol_port": 80
|
||||
},
|
||||
{
|
||||
"ip_address": "'192.0.2.19'",
|
||||
"address": "192.0.2.19",
|
||||
"protocol_port": 80
|
||||
}
|
||||
]
|
||||
@ -69,11 +69,11 @@
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
"ip_address": "'192.0.2.16'",
|
||||
"address": "192.0.2.51",
|
||||
"protocol_port": 80
|
||||
},
|
||||
{
|
||||
"ip_address": "'192.0.2.19'",
|
||||
"address": "192.0.2.52",
|
||||
"protocol_port": 80
|
||||
}
|
||||
]
|
||||
|
@ -15,54 +15,7 @@
|
||||
"default_tls_container_ref": null,
|
||||
"admin_state_up": true,
|
||||
"default_pool": {
|
||||
"lb_algorithm": "ROUND_ROBIN",
|
||||
"protocol": "HTTP",
|
||||
"description": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"session_persistence": null,
|
||||
"healthmonitor": {
|
||||
"name": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"delay": 3,
|
||||
"expected_codes": "200,201,202",
|
||||
"max_retries": 2,
|
||||
"http_method": "GET",
|
||||
"timeout": 1,
|
||||
"max_retries_down": 3,
|
||||
"url_path": "/index.html",
|
||||
"type": "HTTP",
|
||||
"id": "a8a2aa3f-d099-4752-8265-e6472f8147f9"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.16",
|
||||
"protocol_port": 80,
|
||||
"id": "7d19ad6c-d549-453e-a5cd-05382c6be96a"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.19",
|
||||
"protocol_port": 80,
|
||||
"id": "a167402b-caa6-41d5-b4d4-bde7f2cbfa5e"
|
||||
}
|
||||
],
|
||||
"id": "c8cec227-410a-4a5b-af13-ecf38c2b0abb",
|
||||
"name": "rr_pool"
|
||||
"id": "c8cec227-410a-4a5b-af13-ecf38c2b0abb"
|
||||
},
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
@ -80,54 +33,7 @@
|
||||
"default_tls_container_ref": null,
|
||||
"admin_state_up": true,
|
||||
"default_pool": {
|
||||
"lb_algorithm": "ROUND_ROBIN",
|
||||
"protocol": "HTTPS",
|
||||
"description": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"session_persistence": null,
|
||||
"healthmonitor": {
|
||||
"name": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"delay": 3,
|
||||
"expected_codes": "200,201,202",
|
||||
"max_retries": 2,
|
||||
"http_method": "GET",
|
||||
"timeout": 1,
|
||||
"max_retries_down": 3,
|
||||
"url_path": "/index.html",
|
||||
"type": "HTTPS",
|
||||
"id": "d5bb7712-26b7-4809-8c14-3b407c0cb00d"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.16",
|
||||
"protocol_port": 80,
|
||||
"id": "f83832d5-1f22-45fa-866a-4abea36e0886"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.19",
|
||||
"protocol_port": 80,
|
||||
"id": "f83832d5-1f22-45fa-866a-4abea36e0886"
|
||||
}
|
||||
],
|
||||
"id": "b0577aff-c1f9-40c6-9a3b-7b1d2a669136",
|
||||
"name": "https_pool"
|
||||
},
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
@ -175,54 +81,104 @@
|
||||
"provider": "octavia",
|
||||
"pools": [
|
||||
{
|
||||
"lb_algorithm": "ROUND_ROBIN",
|
||||
"protocol": "HTTPS",
|
||||
"description": "",
|
||||
"lb_algorithm": "ROUND_ROBIN",
|
||||
"protocol": "HTTP",
|
||||
"description": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"session_persistence": null,
|
||||
"healthmonitor": {
|
||||
"name": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"session_persistence": null,
|
||||
"healthmonitor": {
|
||||
"delay": 3,
|
||||
"expected_codes": "200,201,202",
|
||||
"max_retries": 2,
|
||||
"http_method": "GET",
|
||||
"timeout": 1,
|
||||
"max_retries_down": 3,
|
||||
"url_path": "/index.html",
|
||||
"type": "HTTP",
|
||||
"id": "a8a2aa3f-d099-4752-8265-e6472f8147f9"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"delay": 3,
|
||||
"expected_codes": "200,201,202",
|
||||
"max_retries": 2,
|
||||
"http_method": "GET",
|
||||
"timeout": 1,
|
||||
"max_retries_down": 3,
|
||||
"url_path": "/index.html",
|
||||
"type": "HTTPS",
|
||||
"id": "d5bb7712-26b7-4809-8c14-3b407c0cb00d"
|
||||
"address": "192.0.2.16",
|
||||
"protocol_port": 80,
|
||||
"id": "7d19ad6c-d549-453e-a5cd-05382c6be96a"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.16",
|
||||
"protocol_port": 80,
|
||||
"id": "f83832d5-1f22-45fa-866a-4abea36e0886"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.19",
|
||||
"protocol_port": 80,
|
||||
"id": "f83832d5-1f22-45fa-866a-4abea36e0886"
|
||||
}
|
||||
],
|
||||
"id": "b0577aff-c1f9-40c6-9a3b-7b1d2a669136",
|
||||
"name": "https_pool"
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.19",
|
||||
"protocol_port": 80,
|
||||
"id": "a167402b-caa6-41d5-b4d4-bde7f2cbfa5e"
|
||||
}
|
||||
],
|
||||
"id": "c8cec227-410a-4a5b-af13-ecf38c2b0abb",
|
||||
"name": "rr_pool"
|
||||
},
|
||||
{
|
||||
"lb_algorithm": "ROUND_ROBIN",
|
||||
"protocol": "HTTPS",
|
||||
"description": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"session_persistence": null,
|
||||
"healthmonitor": {
|
||||
"name": "",
|
||||
"admin_state_up": true,
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"delay": 3,
|
||||
"expected_codes": "200,201,202",
|
||||
"max_retries": 2,
|
||||
"http_method": "GET",
|
||||
"timeout": 1,
|
||||
"max_retries_down": 3,
|
||||
"url_path": "/index.html",
|
||||
"type": "HTTPS",
|
||||
"id": "d5bb7712-26b7-4809-8c14-3b407c0cb00d"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.51",
|
||||
"protocol_port": 80,
|
||||
"id": "f83832d5-1f22-45fa-866a-4abea36e0886"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"weight": 1,
|
||||
"admin_state_up": true,
|
||||
"subnet_id": "bbb35f84-35cc-4b2f-84c2-a6a29bba68aa",
|
||||
"tenant_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"project_id": "e3cd678b11784734bc366148aa37580e",
|
||||
"address": "192.0.2.52",
|
||||
"protocol_port": 80,
|
||||
"id": "f83832d5-1f22-45fa-866a-4abea36e0886"
|
||||
}
|
||||
],
|
||||
"id": "b0577aff-c1f9-40c6-9a3b-7b1d2a669136",
|
||||
"name": "https_pool"
|
||||
}
|
||||
],
|
||||
"created_at": "2017-02-28T00:41:44",
|
||||
|
@ -203,8 +203,12 @@ Creating a Fully Populated Load Balancer
|
||||
----------------------------------------
|
||||
|
||||
You can configure all documented features of the load balancer at
|
||||
creation time by specifying the additional elements or attributes
|
||||
in the request.
|
||||
creation time by specifying the additional elements or attributes in the
|
||||
request.
|
||||
|
||||
Note: all pools must have names, and must only be fully defined once. To
|
||||
reference a pool from multiple objects, supply the pool name only for all
|
||||
subsequent references..
|
||||
|
||||
Request Example
|
||||
---------------
|
||||
|
@ -61,6 +61,10 @@ class URLType(wtypes.UserType):
|
||||
|
||||
|
||||
class BaseType(wtypes.Base):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def from_data_model(cls, data_model, children=False):
|
||||
"""Converts data_model to Octavia WSME type.
|
||||
@ -135,3 +139,11 @@ class BaseType(wtypes.Base):
|
||||
attr_name = renamed
|
||||
ret_dict[attr_name] = value
|
||||
return ret_dict
|
||||
|
||||
|
||||
class IdOnlyType(BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType(), mandatory=True)
|
||||
|
||||
|
||||
class NameOnlyType(BaseType):
|
||||
name = wtypes.wsattr(wtypes.StringType(max_length=255), mandatory=True)
|
||||
|
@ -64,9 +64,7 @@ class HealthMonitorController(base.BaseController):
|
||||
|
||||
@wsme_pecan.wsexpose(hm_types.HealthMonitorsRootResponse, wtypes.text)
|
||||
def get_all(self, project_id=None):
|
||||
"""Gets a single health monitor's details."""
|
||||
# NOTE(blogan): since a pool can only have one health monitor
|
||||
# we are using the get_all method to only get the single health monitor
|
||||
"""Gets all health monitors."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
if context.is_admin or CONF.auth_strategy == constants.NOAUTH:
|
||||
if project_id:
|
||||
@ -161,6 +159,13 @@ class HealthMonitorController(base.BaseController):
|
||||
health_monitor.project_id = pool.project_id
|
||||
|
||||
lock_session = db_api.get_session(autocommit=False)
|
||||
if self.repositories.check_quota_met(
|
||||
context.session,
|
||||
lock_session,
|
||||
data_models.HealthMonitor,
|
||||
health_monitor.project_id):
|
||||
lock_session.rollback()
|
||||
raise exceptions.QuotaException
|
||||
|
||||
hm_dict = db_prepare.create_health_monitor(
|
||||
health_monitor.to_dict(render_unsets=True))
|
||||
@ -175,6 +180,12 @@ class HealthMonitorController(base.BaseController):
|
||||
|
||||
return self._send_hm_to_handler(context.session, db_hm)
|
||||
|
||||
def _graph_create(self, lock_session, hm_dict):
|
||||
hm_dict = db_prepare.create_health_monitor(hm_dict)
|
||||
db_hm = self._validate_create_hm(lock_session, hm_dict)
|
||||
|
||||
return db_hm
|
||||
|
||||
@wsme_pecan.wsexpose(hm_types.HealthMonitorRootResponse, wtypes.text,
|
||||
body=hm_types.HealthMonitorRootPUT, status_code=200)
|
||||
def put(self, id, health_monitor_):
|
||||
|
@ -172,6 +172,23 @@ class L7PolicyController(base.BaseController):
|
||||
return self._send_l7policy_to_handler(context.session, db_l7policy,
|
||||
lb_id=load_balancer_id)
|
||||
|
||||
def _graph_create(self, lock_session, policy_dict):
|
||||
load_balancer_id = policy_dict.pop('load_balancer_id', None)
|
||||
listener_id = policy_dict['listener_id']
|
||||
policy_dict = db_prepare.create_l7policy(
|
||||
policy_dict, load_balancer_id, listener_id)
|
||||
rules = policy_dict.pop('l7rules', []) or []
|
||||
db_policy = self._validate_create_l7policy(lock_session, policy_dict)
|
||||
|
||||
new_rules = []
|
||||
for r in rules:
|
||||
r['project_id'] = db_policy.project_id
|
||||
new_rules.append(
|
||||
l7rule.L7RuleController(db_policy.id)._graph_create(
|
||||
lock_session, r))
|
||||
|
||||
return db_policy
|
||||
|
||||
@wsme_pecan.wsexpose(l7policy_types.L7PolicyRootResponse,
|
||||
wtypes.text, body=l7policy_types.L7PolicyRootPUT,
|
||||
status_code=200)
|
||||
|
@ -140,14 +140,6 @@ class L7RuleController(base.BaseController):
|
||||
self._check_l7policy_max_rules(context.session)
|
||||
|
||||
lock_session = db_api.get_session(autocommit=False)
|
||||
if self.repositories.check_quota_met(
|
||||
context.session,
|
||||
lock_session,
|
||||
data_models.L7Rule,
|
||||
l7rule.project_id):
|
||||
lock_session.rollback()
|
||||
raise exceptions.QuotaException
|
||||
|
||||
l7rule_dict = db_prepare.create_l7rule(
|
||||
l7rule.to_dict(render_unsets=True), self.l7policy_id)
|
||||
try:
|
||||
@ -161,6 +153,16 @@ class L7RuleController(base.BaseController):
|
||||
|
||||
return self._send_l7rule_to_handler(context.session, db_l7rule)
|
||||
|
||||
def _graph_create(self, lock_session, rule_dict):
|
||||
try:
|
||||
validate.l7rule_data(l7rule_types.L7RulePOST(**rule_dict))
|
||||
except Exception as e:
|
||||
raise exceptions.L7RuleValidation(error=e)
|
||||
rule_dict = db_prepare.create_l7rule(rule_dict, self.l7policy_id)
|
||||
db_rule = self._validate_create_l7rule(lock_session, rule_dict)
|
||||
|
||||
return db_rule
|
||||
|
||||
@wsme_pecan.wsexpose(l7rule_types.L7RuleRootResponse,
|
||||
wtypes.text, body=l7rule_types.L7RuleRootPUT,
|
||||
status_code=200)
|
||||
|
@ -23,6 +23,7 @@ from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
from octavia.api.v2.controllers import base
|
||||
from octavia.api.v2.controllers import l7policy
|
||||
from octavia.api.v2.types import listener as listener_types
|
||||
from octavia.common import constants
|
||||
from octavia.common import data_models
|
||||
@ -115,12 +116,11 @@ class ListenersController(base.BaseController):
|
||||
session, lb_id,
|
||||
provisioning_status=constants.ACTIVE)
|
||||
|
||||
def _validate_listener(self, session, lb_id, listener_dict):
|
||||
def _validate_create_listener(self, lock_session, lb_id, listener_dict):
|
||||
"""Validate listener for wrong protocol or duplicate listeners
|
||||
|
||||
Update the load balancer db when provisioning status changes.
|
||||
"""
|
||||
lb_repo = self.repositories.load_balancer
|
||||
if (listener_dict and
|
||||
listener_dict.get('insert_headers') and
|
||||
list(set(listener_dict['insert_headers'].keys()) -
|
||||
@ -132,21 +132,17 @@ class ListenersController(base.BaseController):
|
||||
try:
|
||||
sni_containers = listener_dict.pop('sni_containers', [])
|
||||
db_listener = self.repositories.listener.create(
|
||||
session, **listener_dict)
|
||||
lock_session, **listener_dict)
|
||||
if sni_containers:
|
||||
for container in sni_containers:
|
||||
sni_dict = {'listener_id': db_listener.id,
|
||||
'tls_container_id': container.get(
|
||||
'tls_container_id')}
|
||||
self.repositories.sni.create(session, **sni_dict)
|
||||
db_listener = self.repositories.listener.get(session,
|
||||
id=db_listener.id)
|
||||
self.repositories.sni.create(lock_session, **sni_dict)
|
||||
db_listener = self.repositories.listener.get(
|
||||
lock_session, id=db_listener.id)
|
||||
return db_listener
|
||||
except odb_exceptions.DBDuplicateEntry as de:
|
||||
# Setting LB back to active because this is just a validation
|
||||
# failure
|
||||
lb_repo.update(session, lb_id,
|
||||
provisioning_status=constants.ACTIVE)
|
||||
column_list = ['load_balancer_id', 'protocol_port']
|
||||
constraint_list = ['uq_listener_load_balancer_id_protocol_port']
|
||||
if ['id'] == de.columns:
|
||||
@ -156,10 +152,6 @@ class ListenersController(base.BaseController):
|
||||
raise exceptions.DuplicateListenerEntry(
|
||||
port=listener_dict.get('protocol_port'))
|
||||
except odb_exceptions.DBError:
|
||||
# Setting LB back to active because this is just a validation
|
||||
# failure
|
||||
lb_repo.update(session, lb_id,
|
||||
provisioning_status=constants.ACTIVE)
|
||||
raise exceptions.InvalidOption(value=listener_dict.get('protocol'),
|
||||
option='protocol')
|
||||
|
||||
@ -189,22 +181,69 @@ class ListenersController(base.BaseController):
|
||||
listener = listener_.listener
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
load_balancer_id = listener.loadbalancer_id
|
||||
listener.project_id = self._get_lb_project_id(
|
||||
context.session, load_balancer_id)
|
||||
|
||||
lock_session = db_api.get_session(autocommit=False)
|
||||
if self.repositories.check_quota_met(
|
||||
context.session,
|
||||
lock_session,
|
||||
data_models.Listener,
|
||||
listener.project_id):
|
||||
lock_session.rollback()
|
||||
raise exceptions.QuotaException
|
||||
|
||||
listener_dict = db_prepare.create_listener(
|
||||
listener.to_dict(render_unsets=True), None)
|
||||
load_balancer_id = listener_dict['load_balancer_id']
|
||||
listener_dict['project_id'] = self._get_lb_project_id(
|
||||
context.session, load_balancer_id)
|
||||
|
||||
if listener_dict['default_pool_id']:
|
||||
self._validate_pool(context.session, load_balancer_id,
|
||||
listener_dict['default_pool_id'])
|
||||
self._test_lb_and_listener_statuses(context.session, load_balancer_id)
|
||||
# This is the extra validation layer for wrong protocol or duplicate
|
||||
# listeners on the same load balancer.
|
||||
db_listener = self._validate_listener(
|
||||
context.session, load_balancer_id, listener_dict)
|
||||
|
||||
try:
|
||||
self._test_lb_and_listener_statuses(
|
||||
lock_session, lb_id=load_balancer_id)
|
||||
|
||||
db_listener = self._validate_create_listener(
|
||||
lock_session, load_balancer_id, listener_dict)
|
||||
lock_session.commit()
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
lock_session.rollback()
|
||||
|
||||
return self._send_listener_to_handler(context.session, db_listener)
|
||||
|
||||
def _graph_create(self, lock_session, listener_dict,
|
||||
l7policies=None, pool_name_ids=None):
|
||||
load_balancer_id = listener_dict['load_balancer_id']
|
||||
listener_dict = db_prepare.create_listener(
|
||||
listener_dict, load_balancer_id)
|
||||
l7policies = listener_dict.pop('l7policies', l7policies)
|
||||
if listener_dict.get('default_pool_id'):
|
||||
self._validate_pool(lock_session, load_balancer_id,
|
||||
listener_dict['default_pool_id'])
|
||||
db_listener = self._validate_create_listener(
|
||||
lock_session, load_balancer_id, listener_dict)
|
||||
|
||||
# Now create l7policies
|
||||
new_l7ps = []
|
||||
for l7p in l7policies:
|
||||
l7p['project_id'] = db_listener.project_id
|
||||
l7p['load_balancer_id'] = load_balancer_id
|
||||
l7p['listener_id'] = db_listener.id
|
||||
redirect_pool = l7p.pop('redirect_pool', None)
|
||||
if redirect_pool:
|
||||
pool_name = redirect_pool['name']
|
||||
pool_id = pool_name_ids.get(pool_name)
|
||||
if not pool_id:
|
||||
raise exceptions.SingleCreateDetailsMissing(
|
||||
type='Pool', name=pool_name)
|
||||
l7p['redirect_pool_id'] = pool_id
|
||||
new_l7ps.append(l7policy.L7PolicyController()._graph_create(
|
||||
lock_session, l7p))
|
||||
return db_listener, new_l7ps
|
||||
|
||||
@wsme_pecan.wsexpose(listener_types.ListenerRootResponse, wtypes.text,
|
||||
body=listener_types.ListenerRootPUT, status_code=200)
|
||||
def put(self, id, listener_):
|
||||
|
@ -22,6 +22,8 @@ from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
from octavia.api.v2.controllers import base
|
||||
from octavia.api.v2.controllers import listener
|
||||
from octavia.api.v2.controllers import pool
|
||||
from octavia.api.v2.types import load_balancer as lb_types
|
||||
from octavia.common import constants
|
||||
from octavia.common import data_models
|
||||
@ -101,7 +103,7 @@ class LoadBalancersController(base.BaseController):
|
||||
"Supplied network does not contain a subnet."
|
||||
))
|
||||
|
||||
@wsme_pecan.wsexpose(lb_types.LoadBalancerRootResponse,
|
||||
@wsme_pecan.wsexpose(lb_types.LoadBalancerFullRootResponse,
|
||||
body=lb_types.LoadBalancerRootPOST, status_code=201)
|
||||
def post(self, load_balancer):
|
||||
"""Creates a load balancer."""
|
||||
@ -147,16 +149,24 @@ class LoadBalancersController(base.BaseController):
|
||||
lock_session.rollback()
|
||||
raise exceptions.QuotaException
|
||||
|
||||
# TODO(blogan): lb graph, look at v1 code
|
||||
|
||||
db_lb, db_pools, db_lists = None, None, None
|
||||
try:
|
||||
lb_dict = db_prepare.create_load_balancer(load_balancer.to_dict(
|
||||
render_unsets=True
|
||||
render_unsets=False
|
||||
))
|
||||
vip_dict = lb_dict.pop('vip', {})
|
||||
|
||||
# NoneType can be weird here, have to force type a second time
|
||||
listeners = lb_dict.pop('listeners', []) or []
|
||||
pools = lb_dict.pop('pools', []) or []
|
||||
|
||||
db_lb = self.repositories.create_load_balancer_and_vip(
|
||||
lock_session, lb_dict, vip_dict)
|
||||
|
||||
if listeners or pools:
|
||||
db_pools, db_lists = self._graph_create(
|
||||
context.session, lock_session, db_lb, listeners, pools)
|
||||
|
||||
lock_session.commit()
|
||||
except odb_exceptions.DBDuplicateEntry:
|
||||
lock_session.rollback()
|
||||
@ -175,8 +185,118 @@ class LoadBalancersController(base.BaseController):
|
||||
self.repositories.load_balancer.update(
|
||||
context.session, db_lb.id,
|
||||
provisioning_status=constants.ERROR)
|
||||
result = self._convert_db_to_type(db_lb, lb_types.LoadBalancerResponse)
|
||||
return lb_types.LoadBalancerRootResponse(loadbalancer=result)
|
||||
|
||||
db_lb = self._get_db_lb(context.session, db_lb.id)
|
||||
|
||||
result = self._convert_db_to_type(
|
||||
db_lb, lb_types.LoadBalancerFullResponse)
|
||||
return lb_types.LoadBalancerFullRootResponse(loadbalancer=result)
|
||||
|
||||
def _graph_create(self, session, lock_session, db_lb, listeners, pools):
|
||||
# Track which pools must have a full specification
|
||||
pools_required = set()
|
||||
# Look through listeners and find any extra pools, and move them to the
|
||||
# top level so they are created first.
|
||||
for l in listeners:
|
||||
default_pool = l.get('default_pool')
|
||||
pool_name = (
|
||||
default_pool.get('name') if default_pool else None)
|
||||
# All pools need to have a name so they can be referenced
|
||||
if default_pool and not pool_name:
|
||||
raise exceptions.ValidationException(
|
||||
detail='Pools must be named when creating a fully '
|
||||
'populated loadbalancer.')
|
||||
# If a pool has more than a name, assume it's a full specification
|
||||
# (but use >2 because it will also have "enabled" as default)
|
||||
if default_pool and len(default_pool) > 2:
|
||||
pools.append(default_pool)
|
||||
l['default_pool'] = {'name': pool_name}
|
||||
# Otherwise, it's a reference and we record it and move on
|
||||
elif default_pool:
|
||||
pools_required.add(pool_name)
|
||||
# We also need to check policy redirects
|
||||
for policy in l.get('l7policies'):
|
||||
redirect_pool = policy.get('redirect_pool')
|
||||
pool_name = (
|
||||
redirect_pool.get('name') if redirect_pool else None)
|
||||
# All pools need to have a name so they can be referenced
|
||||
if default_pool and not pool_name:
|
||||
raise exceptions.ValidationException(
|
||||
detail='Pools must be named when creating a fully '
|
||||
'populated loadbalancer.')
|
||||
# If a pool has more than a name, assume it's a full spec
|
||||
# (but use >2 because it will also have "enabled" as default)
|
||||
if redirect_pool and len(redirect_pool) > 2:
|
||||
pool_name = redirect_pool['name']
|
||||
policy['redirect_pool'] = {'name': pool_name}
|
||||
pools.append(redirect_pool)
|
||||
# Otherwise, it's a reference and we record it and move on
|
||||
elif default_pool:
|
||||
pools_required.add(pool_name)
|
||||
|
||||
# Make sure all pool names are unique.
|
||||
pool_names = [p.get('name') for p in pools]
|
||||
if len(set(pool_names)) != len(pool_names):
|
||||
raise exceptions.ValidationException(
|
||||
detail="Pool names must be unique when creating a fully "
|
||||
"populated loadbalancer.")
|
||||
# Make sure every reference is present in our spec list
|
||||
for pool_ref in pools_required:
|
||||
if pool_ref not in pool_names:
|
||||
raise exceptions.ValidationException(
|
||||
detail="Pool '{name}' was referenced but no full "
|
||||
"definition was found.".format(name=pool_ref))
|
||||
|
||||
# Check quotas for pools.
|
||||
if pools and self.repositories.check_quota_met(
|
||||
session, lock_session, data_models.Pool, db_lb.project_id,
|
||||
count=len(pools)):
|
||||
raise exceptions.QuotaException
|
||||
|
||||
# Now create all of the pools ahead of the listeners.
|
||||
new_pools = []
|
||||
pool_name_ids = {}
|
||||
for p in pools:
|
||||
# Check that pools have mandatory attributes, since we have to
|
||||
# bypass the normal validation layer to allow for name-only
|
||||
for attr in ('protocol', 'lb_algorithm'):
|
||||
if attr not in p:
|
||||
raise exceptions.ValidationException(
|
||||
detail="Pool definition for '{name}' missing required "
|
||||
"attribute: {attr}".format(name=p['name'],
|
||||
attr=attr))
|
||||
p['load_balancer_id'] = db_lb.id
|
||||
p['project_id'] = db_lb.project_id
|
||||
new_pool, new_hm, new_members = (
|
||||
pool.PoolsController()._graph_create(
|
||||
session, lock_session, p))
|
||||
new_pools.append(new_pool)
|
||||
pool_name_ids[new_pool.name] = new_pool.id
|
||||
|
||||
# Now check quotas for listeners
|
||||
if listeners and self.repositories.check_quota_met(
|
||||
session, lock_session, data_models.Listener, db_lb.project_id,
|
||||
count=len(listeners)):
|
||||
raise exceptions.QuotaException
|
||||
|
||||
# Now create all of the listeners
|
||||
new_lists = []
|
||||
for l in listeners:
|
||||
default_pool = l.pop('default_pool', None)
|
||||
# If there's a default pool, replace it with the ID
|
||||
if default_pool:
|
||||
pool_name = default_pool['name']
|
||||
pool_id = pool_name_ids.get(pool_name)
|
||||
if not pool_id:
|
||||
raise exceptions.SingleCreateDetailsMissing(
|
||||
type='Pool', name=pool_name)
|
||||
l['default_pool_id'] = pool_id
|
||||
l['load_balancer_id'] = db_lb.id
|
||||
l['project_id'] = db_lb.project_id
|
||||
new_lists.append(listener.ListenersController()._graph_create(
|
||||
lock_session, l, pool_name_ids=pool_name_ids))
|
||||
|
||||
return new_pools, new_lists
|
||||
|
||||
@wsme_pecan.wsexpose(lb_types.LoadBalancerRootResponse,
|
||||
wtypes.text, status_code=200,
|
||||
|
@ -174,6 +174,14 @@ class MembersController(base.BaseController):
|
||||
|
||||
return self._send_member_to_handler(context.session, db_member)
|
||||
|
||||
def _graph_create(self, lock_session, member_dict):
|
||||
pool = self.repositories.pool.get(lock_session, id=self.pool_id)
|
||||
member_dict = db_prepare.create_member(
|
||||
member_dict, self.pool_id, bool(pool.health_monitor))
|
||||
db_member = self._validate_create_member(lock_session, member_dict)
|
||||
|
||||
return db_member
|
||||
|
||||
@wsme_pecan.wsexpose(member_types.MemberRootResponse,
|
||||
wtypes.text, body=member_types.MemberRootPUT,
|
||||
status_code=200)
|
||||
|
@ -22,8 +22,8 @@ import pecan
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
from octavia.api.v1.controllers import health_monitor
|
||||
from octavia.api.v2.controllers import base
|
||||
from octavia.api.v2.controllers import health_monitor
|
||||
from octavia.api.v2.controllers import member
|
||||
from octavia.api.v2.types import pool as pool_types
|
||||
from octavia.common import constants
|
||||
@ -195,6 +195,44 @@ class PoolsController(base.BaseController):
|
||||
return self._send_pool_to_handler(context.session, db_pool,
|
||||
listener_id=listener_id)
|
||||
|
||||
def _graph_create(self, session, lock_session, pool_dict):
|
||||
load_balancer_id = pool_dict['load_balancer_id']
|
||||
pool_dict = db_prepare.create_pool(
|
||||
pool_dict, load_balancer_id)
|
||||
members = pool_dict.pop('members', []) or []
|
||||
hm = pool_dict.pop('health_monitor', None)
|
||||
db_pool = self._validate_create_pool(
|
||||
lock_session, pool_dict)
|
||||
|
||||
# Check quotas for healthmonitors
|
||||
if hm and self.repositories.check_quota_met(
|
||||
session, lock_session, data_models.HealthMonitor,
|
||||
db_pool.project_id):
|
||||
raise exceptions.QuotaException
|
||||
|
||||
# Now possibly create a healthmonitor
|
||||
new_hm = None
|
||||
if hm:
|
||||
hm['pool_id'] = db_pool.id
|
||||
hm['project_id'] = db_pool.project_id
|
||||
new_hm = health_monitor.HealthMonitorController()._graph_create(
|
||||
lock_session, hm)
|
||||
|
||||
# Now check quotas for members
|
||||
if members and self.repositories.check_quota_met(
|
||||
session, lock_session, data_models.Member,
|
||||
db_pool.project_id, count=len(members)):
|
||||
raise exceptions.QuotaException
|
||||
|
||||
# Now create members
|
||||
new_members = []
|
||||
for m in members:
|
||||
m['project_id'] = db_pool.project_id
|
||||
new_members.append(
|
||||
member.MembersController(db_pool.id)._graph_create(
|
||||
lock_session, m))
|
||||
return db_pool, new_hm, new_members
|
||||
|
||||
@wsme_pecan.wsexpose(pool_types.PoolRootResponse, wtypes.text,
|
||||
body=pool_types.PoolRootPut, status_code=200)
|
||||
def put(self, id, pool_):
|
||||
|
@ -24,10 +24,6 @@ class BaseHealthMonitorType(types.BaseType):
|
||||
'max_retries_down': 'fall_threshold'}
|
||||
|
||||
|
||||
class MinimalPool(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class HealthMonitorResponse(BaseHealthMonitorType):
|
||||
"""Defines which attributes are to be shown on any response."""
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
@ -42,7 +38,7 @@ class HealthMonitorResponse(BaseHealthMonitorType):
|
||||
expected_codes = wtypes.wsattr(wtypes.text)
|
||||
admin_state_up = wtypes.wsattr(bool)
|
||||
project_id = wtypes.wsattr(wtypes.StringType())
|
||||
pools = wtypes.wsattr([MinimalPool])
|
||||
pools = wtypes.wsattr([types.IdOnlyType])
|
||||
provisioning_status = wtypes.wsattr(wtypes.StringType())
|
||||
operating_status = wtypes.wsattr(wtypes.StringType())
|
||||
created_at = wtypes.wsattr(wtypes.datetime.datetime)
|
||||
@ -52,12 +48,21 @@ class HealthMonitorResponse(BaseHealthMonitorType):
|
||||
def from_data_model(cls, data_model, children=False):
|
||||
healthmonitor = super(HealthMonitorResponse, cls).from_data_model(
|
||||
data_model, children=children)
|
||||
healthmonitor.pools = [
|
||||
MinimalPool.from_data_model(data_model.pool)
|
||||
]
|
||||
|
||||
if cls._full_response():
|
||||
del healthmonitor.pools
|
||||
else:
|
||||
healthmonitor.pools = [
|
||||
types.IdOnlyType.from_data_model(data_model.pool)]
|
||||
return healthmonitor
|
||||
|
||||
|
||||
class HealthMonitorFullResponse(HealthMonitorResponse):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return True
|
||||
|
||||
|
||||
class HealthMonitorRootResponse(types.BaseType):
|
||||
healthmonitor = wtypes.wsattr(HealthMonitorResponse)
|
||||
|
||||
@ -121,3 +126,30 @@ class HealthMonitorPUT(BaseHealthMonitorType):
|
||||
|
||||
class HealthMonitorRootPUT(types.BaseType):
|
||||
healthmonitor = wtypes.wsattr(HealthMonitorPUT)
|
||||
|
||||
|
||||
class HealthMonitorSingleCreate(BaseHealthMonitorType):
|
||||
"""Defines mandatory and optional attributes of a POST request."""
|
||||
name = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
type = wtypes.wsattr(
|
||||
wtypes.Enum(str, *constants.SUPPORTED_HEALTH_MONITOR_TYPES),
|
||||
mandatory=True)
|
||||
delay = wtypes.wsattr(wtypes.IntegerType(minimum=0), mandatory=True)
|
||||
timeout = wtypes.wsattr(wtypes.IntegerType(minimum=0), mandatory=True)
|
||||
max_retries_down = wtypes.wsattr(
|
||||
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
||||
maximum=constants.MAX_HM_RETRIES), default=3)
|
||||
max_retries = wtypes.wsattr(
|
||||
wtypes.IntegerType(minimum=constants.MIN_HM_RETRIES,
|
||||
maximum=constants.MAX_HM_RETRIES),
|
||||
mandatory=True)
|
||||
http_method = wtypes.wsattr(
|
||||
wtypes.Enum(str, *constants.SUPPORTED_HEALTH_MONITOR_HTTP_METHODS),
|
||||
default=constants.HEALTH_MONITOR_HTTP_DEFAULT_METHOD)
|
||||
url_path = wtypes.wsattr(
|
||||
types.URLType(require_scheme=False),
|
||||
default=constants.HEALTH_MONITOR_DEFAULT_URL_PATH)
|
||||
expected_codes = wtypes.wsattr(
|
||||
wtypes.StringType(pattern=r'^(\d{3}(\s*,\s*\d{3})*)$|^(\d{3}-\d{3})$'),
|
||||
default=constants.HEALTH_MONITOR_DEFAULT_EXPECTED_CODES)
|
||||
admin_state_up = wtypes.wsattr(bool, default=True)
|
||||
|
@ -15,6 +15,8 @@
|
||||
from wsme import types as wtypes
|
||||
|
||||
from octavia.api.common import types
|
||||
from octavia.api.v2.types import l7rule
|
||||
from octavia.api.v2.types import pool
|
||||
from octavia.common import constants
|
||||
|
||||
|
||||
@ -22,10 +24,6 @@ class BaseL7PolicyType(types.BaseType):
|
||||
_type_to_model_map = {'admin_state_up': 'enabled'}
|
||||
|
||||
|
||||
class MinimalL7Rule(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class L7PolicyResponse(BaseL7PolicyType):
|
||||
"""Defines which attributes are to be shown on any response."""
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
@ -40,7 +38,7 @@ class L7PolicyResponse(BaseL7PolicyType):
|
||||
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
|
||||
redirect_url = wtypes.wsattr(wtypes.StringType())
|
||||
position = wtypes.wsattr(wtypes.IntegerType())
|
||||
rules = wtypes.wsattr([MinimalL7Rule])
|
||||
rules = wtypes.wsattr([types.IdOnlyType])
|
||||
created_at = wtypes.wsattr(wtypes.datetime.datetime)
|
||||
updated_at = wtypes.wsattr(wtypes.datetime.datetime)
|
||||
|
||||
@ -52,11 +50,24 @@ class L7PolicyResponse(BaseL7PolicyType):
|
||||
policy.name = ""
|
||||
if not policy.description:
|
||||
policy.description = ""
|
||||
|
||||
if cls._full_response():
|
||||
rule_model = l7rule.L7RuleFullResponse
|
||||
else:
|
||||
rule_model = types.IdOnlyType
|
||||
policy.rules = [
|
||||
MinimalL7Rule.from_data_model(i) for i in data_model.l7rules]
|
||||
rule_model.from_data_model(i) for i in data_model.l7rules]
|
||||
return policy
|
||||
|
||||
|
||||
class L7PolicyFullResponse(L7PolicyResponse):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return True
|
||||
|
||||
rules = wtypes.wsattr([l7rule.L7RuleFullResponse])
|
||||
|
||||
|
||||
class L7PolicyRootResponse(types.BaseType):
|
||||
l7policy = wtypes.wsattr(L7PolicyResponse)
|
||||
|
||||
@ -82,6 +93,7 @@ class L7PolicyPOST(BaseL7PolicyType):
|
||||
maximum=constants.MAX_POLICY_POSITION),
|
||||
default=constants.MAX_POLICY_POSITION)
|
||||
listener_id = wtypes.wsattr(wtypes.UuidType(), mandatory=True)
|
||||
rules = wtypes.wsattr([l7rule.L7RuleSingleCreate])
|
||||
|
||||
|
||||
class L7PolicyRootPOST(types.BaseType):
|
||||
@ -104,3 +116,20 @@ class L7PolicyPUT(BaseL7PolicyType):
|
||||
|
||||
class L7PolicyRootPUT(types.BaseType):
|
||||
l7policy = wtypes.wsattr(L7PolicyPUT)
|
||||
|
||||
|
||||
class L7PolicySingleCreate(BaseL7PolicyType):
|
||||
"""Defines mandatory and optional attributes of a POST request."""
|
||||
name = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
description = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
admin_state_up = wtypes.wsattr(bool, default=True)
|
||||
action = wtypes.wsattr(
|
||||
wtypes.Enum(str, *constants.SUPPORTED_L7POLICY_ACTIONS),
|
||||
mandatory=True)
|
||||
redirect_pool = wtypes.wsattr(pool.PoolSingleCreate)
|
||||
redirect_url = wtypes.wsattr(types.URLType())
|
||||
position = wtypes.wsattr(wtypes.IntegerType(
|
||||
minimum=constants.MIN_POLICY_POSITION,
|
||||
maximum=constants.MAX_POLICY_POSITION),
|
||||
default=constants.MAX_POLICY_POSITION)
|
||||
rules = wtypes.wsattr([l7rule.L7RuleSingleCreate])
|
||||
|
@ -44,6 +44,12 @@ class L7RuleResponse(BaseL7Type):
|
||||
return rule
|
||||
|
||||
|
||||
class L7RuleFullResponse(L7RuleResponse):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return True
|
||||
|
||||
|
||||
class L7RuleRootResponse(types.BaseType):
|
||||
rule = wtypes.wsattr(L7RuleResponse)
|
||||
|
||||
@ -55,12 +61,10 @@ class L7RulesRootResponse(types.BaseType):
|
||||
class L7RulePOST(BaseL7Type):
|
||||
"""Defines mandatory and optional attributes of a POST request."""
|
||||
type = wtypes.wsattr(
|
||||
wtypes.Enum(str,
|
||||
*constants.SUPPORTED_L7RULE_TYPES),
|
||||
wtypes.Enum(str, *constants.SUPPORTED_L7RULE_TYPES),
|
||||
mandatory=True)
|
||||
compare_type = wtypes.wsattr(
|
||||
wtypes.Enum(str,
|
||||
*constants.SUPPORTED_L7RULE_COMPARE_TYPES),
|
||||
wtypes.Enum(str, *constants.SUPPORTED_L7RULE_COMPARE_TYPES),
|
||||
mandatory=True)
|
||||
key = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
value = wtypes.wsattr(wtypes.StringType(max_length=255), mandatory=True)
|
||||
@ -90,3 +94,17 @@ class L7RulePUT(BaseL7Type):
|
||||
|
||||
class L7RuleRootPUT(types.BaseType):
|
||||
rule = wtypes.wsattr(L7RulePUT)
|
||||
|
||||
|
||||
class L7RuleSingleCreate(BaseL7Type):
|
||||
"""Defines mandatory and optional attributes of a POST request."""
|
||||
type = wtypes.wsattr(
|
||||
wtypes.Enum(str, *constants.SUPPORTED_L7RULE_TYPES),
|
||||
mandatory=True)
|
||||
compare_type = wtypes.wsattr(
|
||||
wtypes.Enum(str, *constants.SUPPORTED_L7RULE_COMPARE_TYPES),
|
||||
mandatory=True)
|
||||
key = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
value = wtypes.wsattr(wtypes.StringType(max_length=255), mandatory=True)
|
||||
invert = wtypes.wsattr(bool, default=False)
|
||||
admin_state_up = wtypes.wsattr(bool, default=True)
|
||||
|
@ -25,14 +25,6 @@ class BaseListenerType(types.BaseType):
|
||||
'default_tls_container_ref': 'tls_certificate_id'}
|
||||
|
||||
|
||||
class MinimalLoadBalancer(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class MinimalL7Policy(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class ListenerResponse(BaseListenerType):
|
||||
"""Defines which attributes are to be shown on any response."""
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
@ -48,11 +40,11 @@ class ListenerResponse(BaseListenerType):
|
||||
sni_container_refs = [wtypes.StringType()]
|
||||
project_id = wtypes.wsattr(wtypes.StringType())
|
||||
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
||||
l7policies = wtypes.wsattr([MinimalL7Policy])
|
||||
l7policies = wtypes.wsattr([types.IdOnlyType])
|
||||
insert_headers = wtypes.wsattr(wtypes.DictType(str, str))
|
||||
created_at = wtypes.wsattr(wtypes.datetime.datetime)
|
||||
updated_at = wtypes.wsattr(wtypes.datetime.datetime)
|
||||
loadbalancers = wtypes.wsattr([MinimalLoadBalancer])
|
||||
loadbalancers = wtypes.wsattr([types.IdOnlyType])
|
||||
|
||||
@classmethod
|
||||
def from_data_model(cls, data_model, children=False):
|
||||
@ -61,10 +53,17 @@ class ListenerResponse(BaseListenerType):
|
||||
|
||||
listener.sni_container_refs = [
|
||||
sni_c.tls_container_id for sni_c in data_model.sni_containers]
|
||||
listener.loadbalancers = [
|
||||
MinimalLoadBalancer.from_data_model(data_model.load_balancer)]
|
||||
|
||||
if cls._full_response():
|
||||
del listener.loadbalancers
|
||||
l7policy_type = l7policy.L7PolicyFullResponse
|
||||
else:
|
||||
listener.loadbalancers = [
|
||||
types.IdOnlyType.from_data_model(data_model.load_balancer)]
|
||||
l7policy_type = types.IdOnlyType
|
||||
|
||||
listener.l7policies = [
|
||||
MinimalL7Policy.from_data_model(i) for i in data_model.l7policies]
|
||||
l7policy_type.from_data_model(i) for i in data_model.l7policies]
|
||||
|
||||
if not listener.description:
|
||||
listener.description = ""
|
||||
@ -74,6 +73,14 @@ class ListenerResponse(BaseListenerType):
|
||||
return listener
|
||||
|
||||
|
||||
class ListenerFullResponse(ListenerResponse):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return True
|
||||
|
||||
l7policies = wtypes.wsattr([l7policy.L7PolicyFullResponse])
|
||||
|
||||
|
||||
class ListenerRootResponse(types.BaseType):
|
||||
listener = wtypes.wsattr(ListenerResponse)
|
||||
|
||||
@ -100,8 +107,8 @@ class ListenerPOST(BaseListenerType):
|
||||
# TODO(johnsom) Remove after deprecation (R series)
|
||||
project_id = wtypes.wsattr(wtypes.StringType(max_length=36))
|
||||
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
||||
default_pool = wtypes.wsattr(pool.PoolPOST)
|
||||
l7policies = wtypes.wsattr([l7policy.L7PolicyPOST], default=[])
|
||||
default_pool = wtypes.wsattr(pool.PoolSingleCreate)
|
||||
l7policies = wtypes.wsattr([l7policy.L7PolicySingleCreate], default=[])
|
||||
insert_headers = wtypes.wsattr(
|
||||
wtypes.DictType(str, wtypes.StringType(max_length=255)))
|
||||
loadbalancer_id = wtypes.wsattr(wtypes.UuidType(), mandatory=True)
|
||||
@ -128,3 +135,25 @@ class ListenerPUT(BaseListenerType):
|
||||
|
||||
class ListenerRootPUT(types.BaseType):
|
||||
listener = wtypes.wsattr(ListenerPUT)
|
||||
|
||||
|
||||
class ListenerSingleCreate(BaseListenerType):
|
||||
"""Defines mandatory and optional attributes of a POST request."""
|
||||
name = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
description = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
admin_state_up = wtypes.wsattr(bool, default=True)
|
||||
protocol = wtypes.wsattr(wtypes.Enum(str, *constants.SUPPORTED_PROTOCOLS),
|
||||
mandatory=True)
|
||||
protocol_port = wtypes.wsattr(
|
||||
wtypes.IntegerType(minimum=constants.MIN_PORT_NUMBER,
|
||||
maximum=constants.MAX_PORT_NUMBER), mandatory=True)
|
||||
connection_limit = wtypes.wsattr(
|
||||
wtypes.IntegerType(minimum=constants.MIN_CONNECTION_LIMIT), default=-1)
|
||||
default_tls_container_ref = wtypes.wsattr(
|
||||
wtypes.StringType(max_length=255))
|
||||
sni_container_refs = [wtypes.StringType(max_length=255)]
|
||||
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
||||
default_pool = wtypes.wsattr(pool.PoolSingleCreate)
|
||||
l7policies = wtypes.wsattr([l7policy.L7PolicySingleCreate], default=[])
|
||||
insert_headers = wtypes.wsattr(
|
||||
wtypes.DictType(str, wtypes.StringType(max_length=255)))
|
||||
|
@ -16,6 +16,7 @@ from wsme import types as wtypes
|
||||
|
||||
from octavia.api.common import types
|
||||
from octavia.api.v2.types import listener
|
||||
from octavia.api.v2.types import pool
|
||||
|
||||
|
||||
class BaseLoadBalancerType(types.BaseType):
|
||||
@ -26,10 +27,6 @@ class BaseLoadBalancerType(types.BaseType):
|
||||
'admin_state_up': 'enabled'}
|
||||
|
||||
|
||||
class MinimalListener(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class LoadBalancerResponse(BaseLoadBalancerType):
|
||||
"""Defines which attributes are to be shown on any response."""
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
@ -45,8 +42,10 @@ class LoadBalancerResponse(BaseLoadBalancerType):
|
||||
vip_port_id = wtypes.wsattr(wtypes.UuidType())
|
||||
vip_subnet_id = wtypes.wsattr(wtypes.UuidType())
|
||||
vip_network_id = wtypes.wsattr(wtypes.UuidType())
|
||||
listeners = wtypes.wsattr([MinimalListener])
|
||||
# TODO(ankur-gupta-f): add pools once that has been merged
|
||||
listeners = wtypes.wsattr([types.IdOnlyType])
|
||||
pools = wtypes.wsattr([types.IdOnlyType])
|
||||
provider = wtypes.wsattr(wtypes.StringType())
|
||||
flavor = wtypes.wsattr(wtypes.StringType())
|
||||
|
||||
@classmethod
|
||||
def from_data_model(cls, data_model, children=False):
|
||||
@ -57,20 +56,47 @@ class LoadBalancerResponse(BaseLoadBalancerType):
|
||||
result.vip_port_id = data_model.vip.port_id
|
||||
result.vip_address = data_model.vip.ip_address
|
||||
result.vip_network_id = data_model.vip.network_id
|
||||
|
||||
if cls._full_response():
|
||||
listener_model = listener.ListenerFullResponse
|
||||
pool_model = pool.PoolFullResponse
|
||||
else:
|
||||
listener_model = types.IdOnlyType
|
||||
pool_model = types.IdOnlyType
|
||||
result.listeners = [
|
||||
MinimalListener.from_data_model(i) for i in data_model.listeners]
|
||||
listener_model.from_data_model(i) for i in data_model.listeners]
|
||||
result.pools = [
|
||||
pool_model.from_data_model(i) for i in data_model.pools]
|
||||
|
||||
if not result.description:
|
||||
result.description = ""
|
||||
if not result.name:
|
||||
result.name = ""
|
||||
if not result.flavor:
|
||||
result.flavor = ""
|
||||
if not result.provider:
|
||||
result.provider = "octavia"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class LoadBalancerFullResponse(LoadBalancerResponse):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return True
|
||||
|
||||
listeners = wtypes.wsattr([listener.ListenerFullResponse])
|
||||
pools = wtypes.wsattr([pool.PoolFullResponse])
|
||||
|
||||
|
||||
class LoadBalancerRootResponse(types.BaseType):
|
||||
loadbalancer = wtypes.wsattr(LoadBalancerResponse)
|
||||
|
||||
|
||||
class LoadBalancerFullRootResponse(LoadBalancerRootResponse):
|
||||
loadbalancer = wtypes.wsattr(LoadBalancerFullResponse)
|
||||
|
||||
|
||||
class LoadBalancersRootResponse(types.BaseType):
|
||||
loadbalancers = wtypes.wsattr([LoadBalancerResponse])
|
||||
|
||||
@ -86,7 +112,10 @@ class LoadBalancerPOST(BaseLoadBalancerType):
|
||||
vip_subnet_id = wtypes.wsattr(wtypes.UuidType())
|
||||
vip_network_id = wtypes.wsattr(wtypes.UuidType())
|
||||
project_id = wtypes.wsattr(wtypes.StringType(max_length=36))
|
||||
listeners = wtypes.wsattr([listener.ListenerPOST], default=[])
|
||||
listeners = wtypes.wsattr([listener.ListenerSingleCreate], default=[])
|
||||
pools = wtypes.wsattr([pool.PoolSingleCreate], default=[])
|
||||
provider = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
flavor = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
|
||||
|
||||
class LoadBalancerRootPOST(types.BaseType):
|
||||
|
@ -48,6 +48,12 @@ class MemberResponse(BaseMemberType):
|
||||
return member
|
||||
|
||||
|
||||
class MemberFullResponse(MemberResponse):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return True
|
||||
|
||||
|
||||
class MemberRootResponse(types.BaseType):
|
||||
member = wtypes.wsattr(MemberResponse)
|
||||
|
||||
@ -85,3 +91,16 @@ class MemberPUT(BaseMemberType):
|
||||
|
||||
class MemberRootPUT(types.BaseType):
|
||||
member = wtypes.wsattr(MemberPUT)
|
||||
|
||||
|
||||
class MemberSingleCreate(BaseMemberType):
|
||||
"""Defines mandatory and optional attributes of a POST request."""
|
||||
name = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
admin_state_up = wtypes.wsattr(bool, default=True)
|
||||
address = wtypes.wsattr(types.IPAddressType(), mandatory=True)
|
||||
protocol_port = wtypes.wsattr(wtypes.IntegerType(
|
||||
minimum=constants.MIN_PORT_NUMBER, maximum=constants.MAX_PORT_NUMBER),
|
||||
mandatory=True)
|
||||
weight = wtypes.wsattr(wtypes.IntegerType(
|
||||
minimum=constants.MIN_WEIGHT, maximum=constants.MAX_WEIGHT), default=1)
|
||||
subnet_id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
@ -43,22 +43,6 @@ class BasePoolType(types.BaseType):
|
||||
_type_to_model_map = {'admin_state_up': 'enabled'}
|
||||
|
||||
|
||||
class MinimalLoadBalancer(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class MinimalListener(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class MinimalMember(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class MinimalHealthmonitor(types.BaseType):
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
|
||||
|
||||
class PoolResponse(BasePoolType):
|
||||
"""Defines which attributes are to be shown on any response."""
|
||||
id = wtypes.wsattr(wtypes.UuidType())
|
||||
@ -71,12 +55,12 @@ class PoolResponse(BasePoolType):
|
||||
lb_algorithm = wtypes.wsattr(wtypes.text)
|
||||
session_persistence = wtypes.wsattr(SessionPersistenceResponse)
|
||||
project_id = wtypes.wsattr(wtypes.StringType())
|
||||
loadbalancers = wtypes.wsattr([MinimalLoadBalancer])
|
||||
listeners = wtypes.wsattr([MinimalListener])
|
||||
loadbalancers = wtypes.wsattr([types.IdOnlyType])
|
||||
listeners = wtypes.wsattr([types.IdOnlyType])
|
||||
created_at = wtypes.wsattr(wtypes.datetime.datetime)
|
||||
updated_at = wtypes.wsattr(wtypes.datetime.datetime)
|
||||
health_monitor_id = wtypes.wsattr(wtypes.UuidType())
|
||||
members = wtypes.wsattr([MinimalMember])
|
||||
members = wtypes.wsattr([types.IdOnlyType])
|
||||
|
||||
@classmethod
|
||||
def from_data_model(cls, data_model, children=False):
|
||||
@ -86,19 +70,39 @@ class PoolResponse(BasePoolType):
|
||||
pool.session_persistence = (
|
||||
SessionPersistenceResponse.from_data_model(
|
||||
data_model.session_persistence))
|
||||
if data_model.load_balancer:
|
||||
pool.loadbalancers = [
|
||||
MinimalLoadBalancer.from_data_model(data_model.load_balancer)]
|
||||
|
||||
if cls._full_response():
|
||||
del pool.loadbalancers
|
||||
member_model = member.MemberFullResponse
|
||||
if pool.health_monitor:
|
||||
pool.health_monitor = (
|
||||
health_monitor.HealthMonitorFullResponse
|
||||
.from_data_model(data_model.health_monitor))
|
||||
else:
|
||||
pool.loadbalancers = []
|
||||
if data_model.load_balancer:
|
||||
pool.loadbalancers = [
|
||||
types.IdOnlyType.from_data_model(data_model.load_balancer)]
|
||||
else:
|
||||
pool.loadbalancers = []
|
||||
member_model = types.IdOnlyType
|
||||
|
||||
pool.listeners = [
|
||||
MinimalListener.from_data_model(i) for i in data_model.listeners]
|
||||
types.IdOnlyType.from_data_model(i) for i in data_model.listeners]
|
||||
pool.members = [
|
||||
MinimalMember.from_data_model(i) for i in data_model.members]
|
||||
member_model.from_data_model(i) for i in data_model.members]
|
||||
|
||||
return pool
|
||||
|
||||
|
||||
class PoolFullResponse(PoolResponse):
|
||||
@classmethod
|
||||
def _full_response(cls):
|
||||
return True
|
||||
|
||||
members = wtypes.wsattr([member.MemberFullResponse])
|
||||
health_monitor = wtypes.wsattr(health_monitor.HealthMonitorFullResponse)
|
||||
|
||||
|
||||
class PoolRootResponse(types.BaseType):
|
||||
pool = wtypes.wsattr(PoolResponse)
|
||||
|
||||
@ -122,8 +126,8 @@ class PoolPOST(BasePoolType):
|
||||
session_persistence = wtypes.wsattr(SessionPersistencePOST)
|
||||
# TODO(johnsom) Remove after deprecation (R series)
|
||||
project_id = wtypes.wsattr(wtypes.StringType(max_length=36))
|
||||
health_monitor = wtypes.wsattr(health_monitor.HealthMonitorPOST)
|
||||
members = wtypes.wsattr([member.MemberPOST])
|
||||
health_monitor = wtypes.wsattr(health_monitor.HealthMonitorSingleCreate)
|
||||
members = wtypes.wsattr([member.MemberSingleCreate])
|
||||
|
||||
|
||||
class PoolRootPOST(types.BaseType):
|
||||
@ -142,3 +146,16 @@ class PoolPUT(BasePoolType):
|
||||
|
||||
class PoolRootPut(types.BaseType):
|
||||
pool = wtypes.wsattr(PoolPUT)
|
||||
|
||||
|
||||
class PoolSingleCreate(BasePoolType):
|
||||
"""Defines mandatory and optional attributes of a POST request."""
|
||||
name = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
description = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
admin_state_up = wtypes.wsattr(bool, default=True)
|
||||
protocol = wtypes.wsattr(wtypes.Enum(str, *constants.SUPPORTED_PROTOCOLS))
|
||||
lb_algorithm = wtypes.wsattr(
|
||||
wtypes.Enum(str, *constants.SUPPORTED_LB_ALGORITHMS))
|
||||
session_persistence = wtypes.wsattr(SessionPersistencePOST)
|
||||
health_monitor = wtypes.wsattr(health_monitor.HealthMonitorSingleCreate)
|
||||
members = wtypes.wsattr([member.MemberSingleCreate])
|
||||
|
@ -85,6 +85,11 @@ class L7RuleValidation(APIException):
|
||||
code = 400
|
||||
|
||||
|
||||
class SingleCreateDetailsMissing(APIException):
|
||||
msg = _("Missing details for %(type)s object: %(name)")
|
||||
code = 400
|
||||
|
||||
|
||||
class InvalidHMACException(OctaviaException):
|
||||
message = _("HMAC hashes didn't match")
|
||||
|
||||
|
@ -67,7 +67,8 @@ class LoadBalancerFlows(object):
|
||||
|
||||
post_amp_prefix = constants.POST_LB_AMP_ASSOCIATION_SUBFLOW
|
||||
lb_create_flow.add(
|
||||
self.get_post_lb_amp_association_flow(post_amp_prefix, topology))
|
||||
self.get_post_lb_amp_association_flow(
|
||||
post_amp_prefix, topology, mark_active=(not listeners)))
|
||||
|
||||
if listeners:
|
||||
lb_create_flow.add(*self._create_listeners_flow())
|
||||
@ -144,12 +145,14 @@ class LoadBalancerFlows(object):
|
||||
)
|
||||
flows.append(
|
||||
database_tasks.MarkLBActiveInDB(
|
||||
mark_listeners=True, requires=constants.LOADBALANCER
|
||||
mark_subobjects=True,
|
||||
requires=constants.LOADBALANCER
|
||||
)
|
||||
)
|
||||
return flows
|
||||
|
||||
def get_post_lb_amp_association_flow(self, prefix, topology):
|
||||
def get_post_lb_amp_association_flow(self, prefix, topology,
|
||||
mark_active=True):
|
||||
"""Reload the loadbalancer and create networking subflows for
|
||||
|
||||
created/allocated amphorae.
|
||||
@ -179,9 +182,10 @@ class LoadBalancerFlows(object):
|
||||
|
||||
post_create_LB_flow.add(database_tasks.UpdateLoadbalancerInDB(
|
||||
requires=[constants.LOADBALANCER, constants.UPDATE_DICT]))
|
||||
post_create_LB_flow.add(database_tasks.MarkLBActiveInDB(
|
||||
name=sf_name + '-' + constants.MARK_LB_ACTIVE_INDB,
|
||||
requires=constants.LOADBALANCER))
|
||||
if mark_active:
|
||||
post_create_LB_flow.add(database_tasks.MarkLBActiveInDB(
|
||||
name=sf_name + '-' + constants.MARK_LB_ACTIVE_INDB,
|
||||
requires=constants.LOADBALANCER))
|
||||
return post_create_LB_flow
|
||||
|
||||
def _get_delete_listeners_flow(self, lb):
|
||||
|
@ -893,27 +893,25 @@ class MarkLBActiveInDB(BaseDatabaseTask):
|
||||
Since sqlalchemy will likely retry by itself always revert if it fails
|
||||
"""
|
||||
|
||||
def __init__(self, mark_listeners=False, **kwargs):
|
||||
def __init__(self, mark_subobjects=False, **kwargs):
|
||||
super(MarkLBActiveInDB, self).__init__(**kwargs)
|
||||
self.mark_listeners = mark_listeners
|
||||
self.mark_subobjects = mark_subobjects
|
||||
|
||||
def execute(self, loadbalancer):
|
||||
"""Mark the load balancer as active in DB.
|
||||
|
||||
This also marks ACTIVE all listeners of the load balancer if
|
||||
self.mark_listeners is True.
|
||||
This also marks ACTIVE all sub-objects of the load balancer if
|
||||
self.mark_subobjects is True.
|
||||
|
||||
:param loadbalancer: Load balancer object to be updated
|
||||
:returns: None
|
||||
"""
|
||||
|
||||
if self.mark_listeners:
|
||||
if self.mark_subobjects:
|
||||
LOG.debug("Marking all listeners of loadbalancer %s ACTIVE",
|
||||
loadbalancer.id)
|
||||
for listener in loadbalancer.listeners:
|
||||
self.listener_repo.update(db_apis.get_session(),
|
||||
listener.id,
|
||||
provisioning_status=constants.ACTIVE)
|
||||
self._mark_listener_status(listener, constants.ACTIVE)
|
||||
|
||||
LOG.info("Mark ACTIVE in DB for load balancer id: %s",
|
||||
loadbalancer.id)
|
||||
@ -921,24 +919,78 @@ class MarkLBActiveInDB(BaseDatabaseTask):
|
||||
loadbalancer.id,
|
||||
provisioning_status=constants.ACTIVE)
|
||||
|
||||
def _mark_listener_status(self, listener, status):
|
||||
self.listener_repo.update(db_apis.get_session(),
|
||||
listener.id,
|
||||
provisioning_status=status)
|
||||
LOG.debug("Marking all l7policies of listener %s %s",
|
||||
listener.id, status)
|
||||
for l7policy in listener.l7policies:
|
||||
self._mark_l7policy_status(l7policy, status)
|
||||
|
||||
if listener.default_pool:
|
||||
LOG.debug("Marking default pool of listener %s %s",
|
||||
listener.id, status)
|
||||
self._mark_pool_status(listener.default_pool, status)
|
||||
|
||||
def _mark_l7policy_status(self, l7policy, status):
|
||||
self.l7policy_repo.update(
|
||||
db_apis.get_session(), l7policy.id,
|
||||
provisioning_status=status)
|
||||
|
||||
LOG.debug("Marking all l7rules of l7policy %s %s",
|
||||
l7policy.id, status)
|
||||
for l7rule in l7policy.l7rules:
|
||||
self._mark_l7rule_status(l7rule, status)
|
||||
|
||||
if l7policy.redirect_pool:
|
||||
LOG.debug("Marking redirect pool of l7policy %s %s",
|
||||
l7policy.id, status)
|
||||
self._mark_pool_status(l7policy.redirect_pool, status)
|
||||
|
||||
def _mark_l7rule_status(self, l7rule, status):
|
||||
self.l7rule_repo.update(
|
||||
db_apis.get_session(), l7rule.id,
|
||||
provisioning_status=status)
|
||||
|
||||
def _mark_pool_status(self, pool, status):
|
||||
self.pool_repo.update(
|
||||
db_apis.get_session(), pool.id,
|
||||
provisioning_status=status)
|
||||
if pool.health_monitor:
|
||||
LOG.debug("Marking health monitor of pool %s %s", pool.id, status)
|
||||
self._mark_hm_status(pool.health_monitor, status)
|
||||
|
||||
LOG.debug("Marking all members of pool %s %s", pool.id, status)
|
||||
for member in pool.members:
|
||||
self._mark_member_status(member, status)
|
||||
|
||||
def _mark_hm_status(self, hm, status):
|
||||
self.health_mon_repo.update(
|
||||
db_apis.get_session(), hm.id,
|
||||
provisioning_status=status)
|
||||
|
||||
def _mark_member_status(self, member, status):
|
||||
self.member_repo.update(
|
||||
db_apis.get_session(), member.id,
|
||||
provisioning_status=status)
|
||||
|
||||
def revert(self, loadbalancer, *args, **kwargs):
|
||||
"""Mark the load balancer as broken and ready to be cleaned up.
|
||||
|
||||
This also puts all listeners of the load balancer to ERROR state if
|
||||
self.mark_listeners is True
|
||||
This also puts all sub-objects of the load balancer to ERROR state if
|
||||
self.mark_subobjects is True
|
||||
|
||||
:param loadbalancer: Load balancer object that failed to update
|
||||
:returns: None
|
||||
"""
|
||||
|
||||
if self.mark_listeners:
|
||||
if self.mark_subobjects:
|
||||
LOG.debug("Marking all listeners of loadbalancer %s ERROR",
|
||||
loadbalancer.id)
|
||||
for listener in loadbalancer.listeners:
|
||||
try:
|
||||
self.listener_repo.update(
|
||||
db_apis.get_session(), listener.id,
|
||||
provisioning_status=constants.ERROR)
|
||||
self._mark_listener_status(listener, constants.ERROR)
|
||||
except Exception:
|
||||
LOG.warning("Error updating listener %s provisioning "
|
||||
"status", listener.id)
|
||||
|
@ -113,6 +113,9 @@ def create_l7policy(l7policy_dict, lb_id, listener_id):
|
||||
prepped_pool = create_pool(pool_dict, lb_id)
|
||||
l7policy_dict['redirect_pool'] = prepped_pool
|
||||
l7policy_dict['redirect_pool_id'] = prepped_pool['id']
|
||||
rules = l7policy_dict.pop('rules', None)
|
||||
if rules:
|
||||
l7policy_dict['l7rules'] = rules
|
||||
if l7policy_dict.get('l7rules'):
|
||||
if (len(l7policy_dict.get('l7rules')) >
|
||||
constants.MAX_L7RULES_PER_L7POLICY):
|
||||
|
@ -262,7 +262,8 @@ class Repositories(object):
|
||||
provisioning_status=lb_prov_status)
|
||||
return success
|
||||
|
||||
def check_quota_met(self, session, lock_session, _class, project_id):
|
||||
def check_quota_met(self, session, lock_session, _class, project_id,
|
||||
count=1):
|
||||
"""Checks and updates object quotas.
|
||||
|
||||
This method makes sure the project has available quota
|
||||
@ -273,6 +274,7 @@ class Repositories(object):
|
||||
:param lock_session: Locking database session (autocommit=False)
|
||||
:param _class: Data model object requesting quota
|
||||
:param project_id: Project ID requesting quota
|
||||
:param count: Number of objects we're going to create (default=1)
|
||||
:returns: True if quota is met, False if quota was available
|
||||
"""
|
||||
LOG.debug('Checking quota for project: {proj} object: {obj}'.format(
|
||||
@ -312,16 +314,16 @@ class Repositories(object):
|
||||
lb_count = session.query(models.LoadBalancer).filter(
|
||||
models.LoadBalancer.project_id == project_id,
|
||||
models.LoadBalancer.provisioning_status !=
|
||||
consts.DELETED).count() + 1
|
||||
consts.DELETED).count() + count
|
||||
else:
|
||||
lb_count = quotas.in_use_load_balancer + 1
|
||||
lb_count = quotas.in_use_load_balancer + count
|
||||
# Decide if the quota is met
|
||||
if lb_count <= lb_quota or lb_quota == consts.QUOTA_UNLIMITED:
|
||||
quotas.in_use_load_balancer = lb_count
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
if _class == data_models.Listener:
|
||||
elif _class == data_models.Listener:
|
||||
# Decide which quota to use
|
||||
if quotas.listener is None:
|
||||
listener_quota = CONF.quotas.default_listener_quota
|
||||
@ -333,9 +335,9 @@ class Repositories(object):
|
||||
listener_count = session.query(models.Listener).filter(
|
||||
models.Listener.project_id == project_id,
|
||||
models.Listener.provisioning_status !=
|
||||
consts.DELETED).count() + 1
|
||||
consts.DELETED).count() + count
|
||||
else:
|
||||
listener_count = quotas.in_use_listener + 1
|
||||
listener_count = quotas.in_use_listener + count
|
||||
# Decide if the quota is met
|
||||
if (listener_count <= listener_quota or
|
||||
listener_quota == consts.QUOTA_UNLIMITED):
|
||||
@ -343,7 +345,7 @@ class Repositories(object):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
if _class == data_models.Pool:
|
||||
elif _class == data_models.Pool:
|
||||
# Decide which quota to use
|
||||
if quotas.pool is None:
|
||||
pool_quota = CONF.quotas.default_pool_quota
|
||||
@ -355,9 +357,9 @@ class Repositories(object):
|
||||
pool_count = session.query(models.Pool).filter(
|
||||
models.Pool.project_id == project_id,
|
||||
models.Pool.provisioning_status !=
|
||||
consts.DELETED).count() + 1
|
||||
consts.DELETED).count() + count
|
||||
else:
|
||||
pool_count = quotas.in_use_pool + 1
|
||||
pool_count = quotas.in_use_pool + count
|
||||
# Decide if the quota is met
|
||||
if (pool_count <= pool_quota or
|
||||
pool_quota == consts.QUOTA_UNLIMITED):
|
||||
@ -365,7 +367,7 @@ class Repositories(object):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
if _class == data_models.HealthMonitor:
|
||||
elif _class == data_models.HealthMonitor:
|
||||
# Decide which quota to use
|
||||
if quotas.health_monitor is None:
|
||||
hm_quota = CONF.quotas.default_health_monitor_quota
|
||||
@ -377,9 +379,9 @@ class Repositories(object):
|
||||
hm_count = session.query(models.HealthMonitor).filter(
|
||||
models.HealthMonitor.project_id == project_id,
|
||||
models.HealthMonitor.provisioning_status !=
|
||||
consts.DELETED).count() + 1
|
||||
consts.DELETED).count() + count
|
||||
else:
|
||||
hm_count = quotas.in_use_health_monitor + 1
|
||||
hm_count = quotas.in_use_health_monitor + count
|
||||
# Decide if the quota is met
|
||||
if (hm_count <= hm_quota or
|
||||
hm_quota == consts.QUOTA_UNLIMITED):
|
||||
@ -387,7 +389,7 @@ class Repositories(object):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
if _class == data_models.Member:
|
||||
elif _class == data_models.Member:
|
||||
# Decide which quota to use
|
||||
if quotas.member is None:
|
||||
member_quota = CONF.quotas.default_member_quota
|
||||
@ -399,9 +401,9 @@ class Repositories(object):
|
||||
member_count = session.query(models.Member).filter(
|
||||
models.Member.project_id == project_id,
|
||||
models.Member.provisioning_status !=
|
||||
consts.DELETED).count() + 1
|
||||
consts.DELETED).count() + count
|
||||
else:
|
||||
member_count = quotas.in_use_member + 1
|
||||
member_count = quotas.in_use_member + count
|
||||
# Decide if the quota is met
|
||||
if (member_count <= member_quota or
|
||||
member_quota == consts.QUOTA_UNLIMITED):
|
||||
|
@ -82,9 +82,6 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
|
||||
patcher = mock.patch('octavia.api.handlers.controller_simulator.'
|
||||
'handler.SimulatedControllerHandler')
|
||||
self.handler_mock = patcher.start()
|
||||
self.check_quota_met_true_mock = mock.patch(
|
||||
'octavia.db.repositories.Repositories.check_quota_met',
|
||||
return_value=True)
|
||||
self.app = self._make_app()
|
||||
self.project_id = uuidutils.generate_uuid()
|
||||
|
||||
@ -94,6 +91,15 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
|
||||
|
||||
self.addCleanup(reset_pecan)
|
||||
|
||||
def start_quota_mock(self, object_type):
|
||||
def mock_quota(session, lock_session, _class, project_id, count=1):
|
||||
return _class == object_type
|
||||
check_quota_met_true_mock = mock.patch(
|
||||
'octavia.db.repositories.Repositories.check_quota_met',
|
||||
side_effect=mock_quota)
|
||||
check_quota_met_true_mock.start()
|
||||
self.addCleanup(check_quota_met_true_mock.stop)
|
||||
|
||||
def _make_app(self):
|
||||
return pecan.testing.load_test_app({'app': pconfig.app,
|
||||
'wsme': pconfig.wsme})
|
||||
|
@ -15,6 +15,7 @@
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from octavia.common import constants
|
||||
from octavia.common import data_models
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
|
||||
|
||||
@ -191,6 +192,16 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
self.pool_id, constants.HEALTH_MONITOR_HTTP, 1, 1, 1, 1,
|
||||
status=409)
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.start_quota_mock(data_models.HealthMonitor)
|
||||
hm = {'pool_id': self.pool_id,
|
||||
'type': constants.HEALTH_MONITOR_HTTP,
|
||||
'delay': 1,
|
||||
'timeout': 1,
|
||||
'max_retries_down': 1,
|
||||
'max_retries': 1}
|
||||
self.post(self.HMS_PATH, self._build_body(hm), status=403)
|
||||
|
||||
def test_update(self):
|
||||
api_hm = self.create_health_monitor(
|
||||
self.pool_with_listener_id,
|
||||
|
@ -18,6 +18,7 @@ from oslo_utils import uuidutils
|
||||
|
||||
from octavia.common import constants
|
||||
import octavia.common.context
|
||||
from octavia.common import data_models
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
|
||||
|
||||
@ -298,8 +299,7 @@ class TestL7Policy(base.BaseAPITest):
|
||||
l7policy_op_status=constants.OFFLINE)
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.check_quota_met_true_mock.start()
|
||||
self.addCleanup(self.check_quota_met_true_mock.stop)
|
||||
self.start_quota_mock(data_models.L7Policy)
|
||||
l7policy = {'listener_id': self.listener_id,
|
||||
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
|
||||
'redirect_url': 'http://a.com'}
|
||||
|
@ -260,14 +260,6 @@ class TestL7Rule(base.BaseAPITest):
|
||||
l7rule_prov_status=constants.ERROR,
|
||||
l7rule_op_status=constants.OFFLINE)
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.check_quota_met_true_mock.start()
|
||||
self.addCleanup(self.check_quota_met_true_mock.stop)
|
||||
body = {'type': constants.L7RULE_TYPE_PATH,
|
||||
'compare_type': constants.L7RULE_COMPARE_TYPE_STARTS_WITH,
|
||||
'value': '/api'}
|
||||
self.post(self.l7rules_path, self._build_body(body), status=403)
|
||||
|
||||
def test_update(self):
|
||||
api_l7rule = self.create_l7rule(
|
||||
self.l7policy_id, constants.L7RULE_TYPE_PATH,
|
||||
|
@ -19,6 +19,7 @@ from oslo_utils import uuidutils
|
||||
|
||||
from octavia.common import constants
|
||||
import octavia.common.context
|
||||
from octavia.common import data_models
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
|
||||
|
||||
@ -284,6 +285,15 @@ class TestListener(base.BaseAPITest):
|
||||
self.assert_final_lb_statuses(self.lb_id)
|
||||
self.assert_final_listener_statuses(self.lb_id, listener_api['id'])
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.start_quota_mock(data_models.Listener)
|
||||
lb_listener = {'name': 'listener1',
|
||||
'protocol': constants.PROTOCOL_HTTP,
|
||||
'protocol_port': 80,
|
||||
'loadbalancer_id': self.lb_id}
|
||||
body = self._build_body(lb_listener)
|
||||
self.post(self.LISTENERS_PATH, body, status=403)
|
||||
|
||||
def test_create_with_bad_handler(self):
|
||||
self.handler_mock().listener.create.side_effect = Exception()
|
||||
api_listener = self.create_listener(
|
||||
|
@ -16,10 +16,10 @@ import copy
|
||||
|
||||
import mock
|
||||
from oslo_utils import uuidutils
|
||||
import testtools
|
||||
|
||||
from octavia.common import constants
|
||||
import octavia.common.context
|
||||
from octavia.common import data_models
|
||||
from octavia.network import base as network_base
|
||||
from octavia.network import data_models as network_models
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
@ -361,6 +361,14 @@ class TestLoadBalancer(base.BaseAPITest):
|
||||
path = self.LB_PATH.format(lb_id='SEAN-CONNERY')
|
||||
self.get(path, status=404)
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.start_quota_mock(data_models.LoadBalancer)
|
||||
lb_json = {'name': 'test1',
|
||||
'vip_subnet_id': uuidutils.generate_uuid(),
|
||||
'project_id': self.project_id}
|
||||
body = self._build_body(lb_json)
|
||||
self.post(self.LBS_PATH, body, status=403)
|
||||
|
||||
def test_update(self):
|
||||
project_id = uuidutils.generate_uuid()
|
||||
lb = self.create_load_balancer(uuidutils.generate_uuid(),
|
||||
@ -568,18 +576,29 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
observed_graph_copy = copy.deepcopy(observed_graph)
|
||||
del observed_graph_copy['created_at']
|
||||
del observed_graph_copy['updated_at']
|
||||
obs_lb_id = observed_graph_copy.pop('id')
|
||||
|
||||
obs_lb_id = observed_graph_copy.pop('id')
|
||||
self.assertTrue(uuidutils.is_uuid_like(obs_lb_id))
|
||||
|
||||
expected_listeners = expected_graph.pop('listeners', [])
|
||||
observed_listeners = observed_graph_copy.pop('listeners', [])
|
||||
expected_pools = expected_graph.pop('pools', [])
|
||||
observed_pools = observed_graph_copy.pop('pools', [])
|
||||
self.assertEqual(expected_graph, observed_graph_copy)
|
||||
|
||||
self.assertEqual(len(expected_pools), len(observed_pools))
|
||||
|
||||
self.assertEqual(len(expected_listeners), len(observed_listeners))
|
||||
for observed_listener in observed_listeners:
|
||||
del observed_listener['created_at']
|
||||
del observed_listener['updated_at']
|
||||
|
||||
self.assertTrue(uuidutils.is_uuid_like(
|
||||
observed_listener.pop('id')))
|
||||
if observed_listener.get('default_pool_id'):
|
||||
self.assertTrue(uuidutils.is_uuid_like(
|
||||
observed_listener.pop('default_pool_id')))
|
||||
|
||||
default_pool = observed_listener.get('default_pool')
|
||||
if default_pool:
|
||||
observed_listener.pop('default_pool_id')
|
||||
@ -601,50 +620,50 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
o_l7policies = observed_listener.get('l7policies')
|
||||
if o_l7policies:
|
||||
for o_l7policy in o_l7policies:
|
||||
if o_l7policy.get('redirect_pool'):
|
||||
r_pool = o_l7policy.get('redirect_pool')
|
||||
self.assertTrue(r_pool.get('id'))
|
||||
r_pool.pop('id')
|
||||
r_pool.pop('created_at')
|
||||
r_pool.pop('updated_at')
|
||||
self.assertTrue(o_l7policy.get('redirect_pool_id'))
|
||||
o_l7policy.pop('redirect_pool_id')
|
||||
if r_pool.get('members'):
|
||||
for r_member in r_pool.get('members'):
|
||||
self.assertTrue(r_member.get('id'))
|
||||
r_member.pop('id')
|
||||
r_member.pop('created_at')
|
||||
r_member.pop('updated_at')
|
||||
self.assertTrue(o_l7policy.get('id'))
|
||||
o_l7policy.pop('id')
|
||||
l7rules = o_l7policy.get('l7rules')
|
||||
o_l7policy.pop('created_at')
|
||||
o_l7policy.pop('updated_at')
|
||||
if o_l7policy.get('redirect_pool_id'):
|
||||
r_pool_id = o_l7policy.pop('redirect_pool_id')
|
||||
self.assertTrue(uuidutils.is_uuid_like(r_pool_id))
|
||||
o_l7policy_id = o_l7policy.pop('id')
|
||||
self.assertTrue(uuidutils.is_uuid_like(o_l7policy_id))
|
||||
o_l7policy_l_id = o_l7policy.pop('listener_id')
|
||||
self.assertTrue(uuidutils.is_uuid_like(o_l7policy_l_id))
|
||||
l7rules = o_l7policy.get('rules') or []
|
||||
for l7rule in l7rules:
|
||||
self.assertTrue(l7rule.get('id'))
|
||||
l7rule.pop('id')
|
||||
l7rule.pop('created_at')
|
||||
l7rule.pop('updated_at')
|
||||
self.assertTrue(l7rule.pop('id'))
|
||||
self.assertIn(observed_listener, expected_listeners)
|
||||
|
||||
def _get_lb_bodies(self, create_listeners, expected_listeners):
|
||||
def _get_lb_bodies(self, create_listeners, expected_listeners,
|
||||
create_pools=None):
|
||||
create_lb = {
|
||||
'name': 'lb1',
|
||||
'project_id': self._project_id,
|
||||
'vip_subnet_id': None,
|
||||
'listeners': create_listeners
|
||||
'vip_subnet_id': uuidutils.generate_uuid(),
|
||||
'listeners': create_listeners,
|
||||
'pools': create_pools or []
|
||||
}
|
||||
expected_lb = {
|
||||
'description': None,
|
||||
'enabled': True,
|
||||
'description': '',
|
||||
'admin_state_up': True,
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE,
|
||||
'vip_subnet_id': None,
|
||||
'vip_address': None,
|
||||
'vip_network_id': None,
|
||||
'vip_port_id': None,
|
||||
'flavor': '',
|
||||
'provider': 'octavia'
|
||||
}
|
||||
expected_lb.update(create_lb)
|
||||
expected_lb['listeners'] = expected_listeners
|
||||
expected_lb['pools'] = create_pools or []
|
||||
return create_lb, expected_lb
|
||||
|
||||
def _get_listener_bodies(self, name='listener1', protocol_port=80,
|
||||
create_default_pool=None,
|
||||
expected_default_pool=None,
|
||||
create_default_pool_name=None,
|
||||
create_default_pool_id=None,
|
||||
create_l7policies=None,
|
||||
expected_l7policies=None,
|
||||
create_sni_containers=None,
|
||||
@ -652,36 +671,39 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
create_listener = {
|
||||
'name': name,
|
||||
'protocol_port': protocol_port,
|
||||
'protocol': constants.PROTOCOL_HTTP,
|
||||
'project_id': self._project_id
|
||||
'protocol': constants.PROTOCOL_HTTP
|
||||
}
|
||||
expected_listener = {
|
||||
'description': None,
|
||||
'tls_certificate_id': None,
|
||||
'sni_containers': [],
|
||||
'connection_limit': None,
|
||||
'enabled': True,
|
||||
'description': '',
|
||||
'default_tls_container_ref': None,
|
||||
'sni_container_refs': [],
|
||||
'connection_limit': -1,
|
||||
'admin_state_up': True,
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE,
|
||||
'insert_headers': {}
|
||||
'insert_headers': {},
|
||||
'project_id': self._project_id
|
||||
}
|
||||
if create_sni_containers:
|
||||
create_listener['sni_containers'] = create_sni_containers
|
||||
create_listener['sni_container_refs'] = create_sni_containers
|
||||
expected_listener.update(create_listener)
|
||||
if create_default_pool:
|
||||
pool = create_default_pool
|
||||
if create_default_pool_name:
|
||||
pool = {'name': create_default_pool_name}
|
||||
create_listener['default_pool'] = pool
|
||||
if pool.get('id'):
|
||||
create_listener['default_pool_id'] = pool['id']
|
||||
elif create_default_pool_id:
|
||||
create_listener['default_pool_id'] = create_default_pool_id
|
||||
expected_listener['default_pool_id'] = create_default_pool_id
|
||||
else:
|
||||
expected_listener['default_pool_id'] = None
|
||||
if create_l7policies:
|
||||
l7policies = create_l7policies
|
||||
create_listener['l7policies'] = l7policies
|
||||
if expected_default_pool:
|
||||
expected_listener['default_pool'] = expected_default_pool
|
||||
if expected_sni_containers:
|
||||
expected_listener['sni_containers'] = expected_sni_containers
|
||||
expected_listener['sni_container_refs'] = expected_sni_containers
|
||||
if expected_l7policies:
|
||||
expected_listener['l7policies'] = expected_l7policies
|
||||
else:
|
||||
expected_listener['l7policies'] = []
|
||||
return create_listener, expected_listener
|
||||
|
||||
def _get_pool_bodies(self, name='pool1', create_members=None,
|
||||
@ -692,7 +714,6 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
'name': name,
|
||||
'protocol': protocol,
|
||||
'lb_algorithm': constants.LB_ALGORITHM_ROUND_ROBIN,
|
||||
'project_id': self._project_id
|
||||
}
|
||||
if session_persistence:
|
||||
create_pool['session_persistence'] = {
|
||||
@ -707,7 +728,9 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
'session_persistence': None,
|
||||
'members': [],
|
||||
'enabled': True,
|
||||
'operating_status': constants.OFFLINE
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE,
|
||||
'project_id': self._project_id
|
||||
}
|
||||
expected_pool.update(create_pool)
|
||||
if expected_members:
|
||||
@ -718,15 +741,15 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
|
||||
def _get_member_bodies(self, protocol_port=80):
|
||||
create_member = {
|
||||
'ip_address': '10.0.0.1',
|
||||
'protocol_port': protocol_port,
|
||||
'project_id': self._project_id
|
||||
'address': '10.0.0.1',
|
||||
'protocol_port': protocol_port
|
||||
}
|
||||
expected_member = {
|
||||
'weight': 1,
|
||||
'enabled': True,
|
||||
'subnet_id': None,
|
||||
'operating_status': constants.OFFLINE
|
||||
'operating_status': constants.OFFLINE,
|
||||
'project_id': self._project_id
|
||||
}
|
||||
expected_member.update(create_member)
|
||||
return create_member, expected_member
|
||||
@ -736,15 +759,17 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
'type': constants.HEALTH_MONITOR_PING,
|
||||
'delay': 1,
|
||||
'timeout': 1,
|
||||
'fall_threshold': 1,
|
||||
'rise_threshold': 1,
|
||||
'project_id': self._project_id
|
||||
'max_retries_down': 1,
|
||||
'max_retries': 1
|
||||
}
|
||||
expected_hm = {
|
||||
'http_method': 'GET',
|
||||
'url_path': '/',
|
||||
'expected_codes': '200',
|
||||
'enabled': True
|
||||
'admin_state_up': True,
|
||||
'project_id': self._project_id,
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE
|
||||
}
|
||||
expected_hm.update(create_hm)
|
||||
return create_hm, expected_hm
|
||||
@ -758,41 +783,44 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
expected_sni_containers.sort()
|
||||
return create_sni_containers, expected_sni_containers
|
||||
|
||||
def _get_l7policies_bodies(self, create_pool=None, expected_pool=None,
|
||||
def _get_l7policies_bodies(self,
|
||||
create_pool_name=None, create_pool_id=None,
|
||||
create_l7rules=None, expected_l7rules=None):
|
||||
create_l7policies = []
|
||||
if create_pool:
|
||||
if create_pool_name:
|
||||
create_l7policy = {
|
||||
'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
|
||||
'redirect_pool': create_pool,
|
||||
'redirect_pool': {'name': create_pool_name},
|
||||
'position': 1,
|
||||
'enabled': False
|
||||
'admin_state_up': False
|
||||
}
|
||||
else:
|
||||
create_l7policy = {
|
||||
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
|
||||
'redirect_url': 'http://127.0.0.1/',
|
||||
'position': 1,
|
||||
'enabled': False
|
||||
'admin_state_up': False
|
||||
}
|
||||
create_l7policies.append(create_l7policy)
|
||||
expected_l7policy = {
|
||||
'name': None,
|
||||
'description': None,
|
||||
'name': '',
|
||||
'description': '',
|
||||
'redirect_url': None,
|
||||
'l7rules': []
|
||||
'rules': [],
|
||||
'project_id': self._project_id,
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE
|
||||
}
|
||||
expected_l7policy.update(create_l7policy)
|
||||
expected_l7policy.pop('redirect_pool', None)
|
||||
expected_l7policies = []
|
||||
if expected_pool:
|
||||
if create_pool.get('id'):
|
||||
expected_l7policy['redirect_pool_id'] = create_pool.get('id')
|
||||
expected_l7policy['redirect_pool'] = expected_pool
|
||||
if not create_pool_name:
|
||||
expected_l7policy['redirect_pool_id'] = create_pool_id
|
||||
expected_l7policies.append(expected_l7policy)
|
||||
if expected_l7rules:
|
||||
expected_l7policies[0]['l7rules'] = expected_l7rules
|
||||
expected_l7policies[0]['rules'] = expected_l7rules
|
||||
if create_l7rules:
|
||||
create_l7policies[0]['l7rules'] = create_l7rules
|
||||
create_l7policies[0]['rules'] = create_l7rules
|
||||
return create_l7policies, expected_l7policies
|
||||
|
||||
def _get_l7rules_bodies(self, value="localhost"):
|
||||
@ -800,15 +828,18 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
'type': constants.L7RULE_TYPE_HOST_NAME,
|
||||
'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO,
|
||||
'value': value,
|
||||
'invert': False
|
||||
'invert': False,
|
||||
'admin_state_up': True
|
||||
}]
|
||||
expected_l7rules = [{
|
||||
'key': None
|
||||
'key': None,
|
||||
'project_id': self._project_id,
|
||||
'provisioning_status': constants.PENDING_CREATE,
|
||||
'operating_status': constants.OFFLINE
|
||||
}]
|
||||
expected_l7rules[0].update(create_l7rules[0])
|
||||
return create_l7rules, expected_l7rules
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_one_listener(self):
|
||||
create_listener, expected_listener = self._get_listener_bodies()
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
@ -818,151 +849,139 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_many_listeners(self):
|
||||
create_listener1, expected_listener1 = self._get_listener_bodies()
|
||||
create_listener2, expected_listener2 = self._get_listener_bodies(
|
||||
name='listener2', protocol_port=81
|
||||
)
|
||||
name='listener2', protocol_port=81)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
[create_listener1, create_listener2],
|
||||
[expected_listener1, expected_listener2])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_one_listener_one_pool(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies()
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool=create_pool,
|
||||
expected_default_pool=expected_pool
|
||||
)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_default_pool_name=create_pool['name'])
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_many_listeners_one_pool(self):
|
||||
create_pool1, expected_pool1 = self._get_pool_bodies()
|
||||
create_pool2, expected_pool2 = self._get_pool_bodies(name='pool2')
|
||||
create_listener1, expected_listener1 = self._get_listener_bodies(
|
||||
create_default_pool=create_pool1,
|
||||
expected_default_pool=expected_pool1
|
||||
)
|
||||
create_default_pool_name=create_pool1['name'])
|
||||
create_listener2, expected_listener2 = self._get_listener_bodies(
|
||||
create_default_pool=create_pool2,
|
||||
expected_default_pool=expected_pool2,
|
||||
name='listener2', protocol_port=81
|
||||
)
|
||||
create_default_pool_name=create_pool2['name'],
|
||||
name='listener2', protocol_port=81)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
[create_listener1, create_listener2],
|
||||
[expected_listener1, expected_listener2])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_listeners=[create_listener1, create_listener2],
|
||||
expected_listeners=[expected_listener1, expected_listener2],
|
||||
create_pools=[create_pool1, create_pool2])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_one_listener_one_member(self):
|
||||
create_member, expected_member = self._get_member_bodies()
|
||||
create_pool, expected_pool = self._get_pool_bodies(
|
||||
create_members=[create_member],
|
||||
expected_members=[expected_member])
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool=create_pool,
|
||||
expected_default_pool=expected_pool)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_default_pool_name=create_pool['name'])
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_one_listener_one_hm(self):
|
||||
create_hm, expected_hm = self._get_hm_bodies()
|
||||
create_pool, expected_pool = self._get_pool_bodies(
|
||||
create_hm=create_hm,
|
||||
expected_hm=expected_hm)
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool=create_pool,
|
||||
expected_default_pool=expected_pool)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_default_pool_name=create_pool['name'])
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_one_listener_sni_containers(self):
|
||||
create_sni_containers, expected_sni_containers = (
|
||||
self._get_sni_container_bodies())
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_sni_containers=create_sni_containers,
|
||||
expected_sni_containers=expected_sni_containers)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_l7policy_redirect_pool_no_rule(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies(create_members=[],
|
||||
expected_members=[])
|
||||
create_l7policies, expected_l7policies = self._get_l7policies_bodies(
|
||||
create_pool=create_pool, expected_pool=expected_pool)
|
||||
create_pool_name=create_pool['name'])
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_l7policies=create_l7policies,
|
||||
expected_l7policies=expected_l7policies)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_l7policy_redirect_pool_one_rule(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies(create_members=[],
|
||||
expected_members=[])
|
||||
create_l7rules, expected_l7rules = self._get_l7rules_bodies()
|
||||
create_l7policies, expected_l7policies = self._get_l7policies_bodies(
|
||||
create_pool=create_pool, expected_pool=expected_pool,
|
||||
create_l7rules=create_l7rules, expected_l7rules=expected_l7rules)
|
||||
create_pool_name=create_pool['name'],
|
||||
create_l7rules=create_l7rules,
|
||||
expected_l7rules=expected_l7rules)
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_l7policies=create_l7policies,
|
||||
expected_l7policies=expected_l7policies)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_l7policy_redirect_pool_bad_rule(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies(create_members=[],
|
||||
expected_members=[])
|
||||
create_l7rules, expected_l7rules = self._get_l7rules_bodies(
|
||||
value="local host")
|
||||
create_l7policies, expected_l7policies = self._get_l7policies_bodies(
|
||||
create_pool=create_pool, expected_pool=expected_pool,
|
||||
create_l7rules=create_l7rules, expected_l7rules=expected_l7rules)
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_l7policies=create_l7policies,
|
||||
expected_l7policies=expected_l7policies)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
self.post(self.LBS_PATH, create_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_l7policies_one_redirect_pool_one_rule(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies(create_members=[],
|
||||
expected_members=[])
|
||||
create_l7rules, expected_l7rules = self._get_l7rules_bodies()
|
||||
create_l7policies, expected_l7policies = self._get_l7policies_bodies(
|
||||
create_pool=create_pool, expected_pool=expected_pool,
|
||||
create_l7rules=create_l7rules, expected_l7rules=expected_l7rules)
|
||||
create_pool_name=create_pool['name'],
|
||||
create_l7rules=create_l7rules,
|
||||
expected_l7rules=expected_l7rules)
|
||||
c_l7policies_url, e_l7policies_url = self._get_l7policies_bodies()
|
||||
for policy in c_l7policies_url:
|
||||
policy['position'] = 2
|
||||
@ -973,20 +992,22 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_l7policies=create_l7policies,
|
||||
expected_l7policies=expected_l7policies)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_l7policies_redirect_pools_no_rules(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies()
|
||||
create_l7policies, expected_l7policies = self._get_l7policies_bodies(
|
||||
create_pool=create_pool, expected_pool=expected_pool)
|
||||
r_create_pool, r_expected_pool = self._get_pool_bodies()
|
||||
create_pool_name=create_pool['name'])
|
||||
r_create_pool, r_expected_pool = self._get_pool_bodies(name='pool2')
|
||||
c_l7policies_url, e_l7policies_url = self._get_l7policies_bodies(
|
||||
create_pool=r_create_pool, expected_pool=r_expected_pool)
|
||||
create_pool_name=r_create_pool['name'])
|
||||
for policy in c_l7policies_url:
|
||||
policy['position'] = 2
|
||||
create_l7policies.append(policy)
|
||||
@ -996,14 +1017,37 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_l7policies=create_l7policies,
|
||||
expected_l7policies=expected_l7policies)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool, r_create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_with_one_of_everything(self):
|
||||
def test_with_l7policy_redirect_pool_bad_rule(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies(create_members=[],
|
||||
expected_members=[])
|
||||
create_l7rules, expected_l7rules = self._get_l7rules_bodies(
|
||||
value="local host")
|
||||
create_l7policies, expected_l7policies = self._get_l7policies_bodies(
|
||||
create_pool_name=create_pool['name'],
|
||||
create_l7rules=create_l7rules,
|
||||
expected_l7rules=expected_l7rules)
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_l7policies=create_l7policies,
|
||||
expected_l7policies=expected_l7policies)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body, status=400)
|
||||
self.assertIn('L7Rule: Invalid characters',
|
||||
response.json.get('faultstring'))
|
||||
|
||||
def _test_with_one_of_everything_helper(self):
|
||||
create_member, expected_member = self._get_member_bodies()
|
||||
create_hm, expected_hm = self._get_hm_bodies()
|
||||
create_pool, expected_pool = self._get_pool_bodies(
|
||||
@ -1021,27 +1065,106 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||
create_members=[r_create_member],
|
||||
expected_members=[r_expected_member])
|
||||
create_l7policies, expected_l7policies = self._get_l7policies_bodies(
|
||||
create_pool=r_create_pool, expected_pool=r_expected_pool,
|
||||
create_l7rules=create_l7rules, expected_l7rules=expected_l7rules)
|
||||
create_pool_name=r_create_pool['name'],
|
||||
create_l7rules=create_l7rules,
|
||||
expected_l7rules=expected_l7rules)
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool=create_pool,
|
||||
expected_default_pool=expected_pool,
|
||||
create_default_pool_name=create_pool['name'],
|
||||
create_l7policies=create_l7policies,
|
||||
expected_l7policies=expected_l7policies,
|
||||
create_sni_containers=create_sni_containers,
|
||||
expected_sni_containers=expected_sni_containers)
|
||||
create_lb, expected_lb = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
response = self.post(self.LBS_PATH, create_lb)
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
return body, expected_lb
|
||||
|
||||
def test_with_one_of_everything(self):
|
||||
body, expected_lb = self._test_with_one_of_everything_helper()
|
||||
response = self.post(self.LBS_PATH, body)
|
||||
api_lb = response.json.get(self.root_tag)
|
||||
self._assert_graphs_equal(expected_lb, api_lb)
|
||||
|
||||
@testtools.skip('Skip until complete v2 merge')
|
||||
def test_db_create_failure(self):
|
||||
create_listener, expected_listener = self._get_listener_bodies()
|
||||
create_lb, _ = self._get_lb_bodies([create_listener],
|
||||
[expected_listener])
|
||||
body = self._build_body(create_lb)
|
||||
with mock.patch('octavia.db.repositories.Repositories.'
|
||||
'create_load_balancer_tree') as repo_mock:
|
||||
'create_load_balancer_and_vip') as repo_mock:
|
||||
repo_mock.side_effect = Exception('I am a DB Error')
|
||||
self.post(self.LBS_PATH, create_lb, status=500)
|
||||
self.post(self.LBS_PATH, body, status=500)
|
||||
|
||||
def test_pool_names_not_unique(self):
|
||||
create_pool1, expected_pool1 = self._get_pool_bodies()
|
||||
create_pool2, expected_pool2 = self._get_pool_bodies()
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool_name=create_pool1['name'])
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool1, create_pool2])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body, status=400)
|
||||
self.assertIn("Pool names must be unique",
|
||||
response.json.get('faultstring'))
|
||||
|
||||
def test_pool_names_must_have_specs(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies()
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool_name="my_nonexistent_pool")
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body, status=400)
|
||||
self.assertIn("referenced but no full definition",
|
||||
response.json.get('faultstring'))
|
||||
|
||||
def test_pool_mandatory_attributes(self):
|
||||
create_pool, expected_pool = self._get_pool_bodies()
|
||||
create_pool.pop('protocol')
|
||||
create_listener, expected_listener = self._get_listener_bodies(
|
||||
create_default_pool_name=create_pool['name'])
|
||||
create_lb, expected_lb = self._get_lb_bodies(
|
||||
create_listeners=[create_listener],
|
||||
expected_listeners=[expected_listener],
|
||||
create_pools=[create_pool])
|
||||
body = self._build_body(create_lb)
|
||||
response = self.post(self.LBS_PATH, body, status=400)
|
||||
self.assertIn("missing required attribute: protocol",
|
||||
response.json.get('faultstring'))
|
||||
|
||||
def test_create_over_quota_lb(self):
|
||||
body, _ = self._test_with_one_of_everything_helper()
|
||||
self.start_quota_mock(data_models.LoadBalancer)
|
||||
self.post(self.LBS_PATH, body, status=403)
|
||||
|
||||
def test_create_over_quota_pools(self):
|
||||
body, _ = self._test_with_one_of_everything_helper()
|
||||
self.start_quota_mock(data_models.Pool)
|
||||
self.post(self.LBS_PATH, body, status=403)
|
||||
|
||||
def test_create_over_quota_listeners(self):
|
||||
body, _ = self._test_with_one_of_everything_helper()
|
||||
self.start_quota_mock(data_models.Listener)
|
||||
self.post(self.LBS_PATH, body, status=403)
|
||||
|
||||
def test_create_over_quota_members(self):
|
||||
body, _ = self._test_with_one_of_everything_helper()
|
||||
self.start_quota_mock(data_models.Member)
|
||||
self.post(self.LBS_PATH, body, status=403)
|
||||
|
||||
def test_create_over_quota_hms(self):
|
||||
body, _ = self._test_with_one_of_everything_helper()
|
||||
self.start_quota_mock(data_models.HealthMonitor)
|
||||
self.post(self.LBS_PATH, body, status=403)
|
||||
|
||||
def test_create_over_quota_sanity_check(self):
|
||||
# This one should create, as we don't check quotas on L7Policies
|
||||
body, _ = self._test_with_one_of_everything_helper()
|
||||
self.start_quota_mock(data_models.L7Policy)
|
||||
self.post(self.LBS_PATH, body)
|
||||
|
@ -16,6 +16,7 @@ import mock
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from octavia.common import constants
|
||||
from octavia.common import data_models
|
||||
from octavia.network import base as network_base
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
|
||||
@ -232,8 +233,7 @@ class TestMember(base.BaseAPITest):
|
||||
resp.json.get('faultstring'))
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.check_quota_met_true_mock.start()
|
||||
self.addCleanup(self.check_quota_met_true_mock.stop)
|
||||
self.start_quota_mock(data_models.Member)
|
||||
member = {'address': '10.0.0.3', 'protocol_port': 81}
|
||||
self.post(self.members_path, self._build_body(member), status=403)
|
||||
|
||||
|
@ -18,6 +18,7 @@ from oslo_utils import uuidutils
|
||||
|
||||
from octavia.common import constants
|
||||
import octavia.common.context
|
||||
from octavia.common import data_models
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
|
||||
import testtools
|
||||
@ -368,8 +369,7 @@ class TestPool(base.BaseAPITest):
|
||||
pool_op_status=constants.OFFLINE)
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.check_quota_met_true_mock.start()
|
||||
self.addCleanup(self.check_quota_met_true_mock.stop)
|
||||
self.start_quota_mock(data_models.Pool)
|
||||
lb_pool = {
|
||||
'loadbalancer_id': self.lb_id,
|
||||
'protocol': constants.PROTOCOL_HTTP,
|
||||
|
@ -1104,7 +1104,7 @@ class TestDatabaseTasks(base.TestCase):
|
||||
listeners = [data_models.Listener(id='listener1'),
|
||||
data_models.Listener(id='listener2')]
|
||||
lb = data_models.LoadBalancer(id=LB_ID, listeners=listeners)
|
||||
mark_lb_active = database_tasks.MarkLBActiveInDB(mark_listeners=True)
|
||||
mark_lb_active = database_tasks.MarkLBActiveInDB(mark_subobjects=True)
|
||||
mark_lb_active.execute(lb)
|
||||
|
||||
repo.LoadBalancerRepository.update.assert_called_once_with(
|
||||
@ -1133,6 +1133,140 @@ class TestDatabaseTasks(base.TestCase):
|
||||
mock.call('TEST', listeners[1].id,
|
||||
provisioning_status=constants.ERROR)])
|
||||
|
||||
@mock.patch('octavia.db.repositories.PoolRepository.update')
|
||||
@mock.patch('octavia.db.repositories.MemberRepository.update')
|
||||
@mock.patch('octavia.db.repositories.HealthMonitorRepository.update')
|
||||
@mock.patch('octavia.db.repositories.L7PolicyRepository.update')
|
||||
@mock.patch('octavia.db.repositories.L7RuleRepository.update')
|
||||
def test_mark_LB_active_in_db_full_graph(self,
|
||||
mock_l7r_repo_update,
|
||||
mock_l7p_repo_update,
|
||||
mock_hm_repo_update,
|
||||
mock_member_repo_update,
|
||||
mock_pool_repo_update,
|
||||
mock_generate_uuid,
|
||||
mock_LOG,
|
||||
mock_get_session,
|
||||
mock_loadbalancer_repo_update,
|
||||
mock_listener_repo_update,
|
||||
mock_amphora_repo_update,
|
||||
mock_amphora_repo_delete):
|
||||
unused_pool = data_models.Pool(id='unused_pool')
|
||||
members1 = [data_models.Member(id='member1'),
|
||||
data_models.Member(id='member2')]
|
||||
health_monitor = data_models.HealthMonitor(id='hm1')
|
||||
default_pool = data_models.Pool(id='default_pool',
|
||||
members=members1,
|
||||
health_monitor=health_monitor)
|
||||
listener1 = data_models.Listener(id='listener1',
|
||||
default_pool=default_pool)
|
||||
members2 = [data_models.Member(id='member3'),
|
||||
data_models.Member(id='member4')]
|
||||
redirect_pool = data_models.Pool(id='redirect_pool',
|
||||
members=members2)
|
||||
l7rules = [data_models.L7Rule(id='rule1')]
|
||||
redirect_policy = data_models.L7Policy(id='redirect_policy',
|
||||
redirect_pool=redirect_pool,
|
||||
l7rules=l7rules)
|
||||
l7policies = [redirect_policy]
|
||||
listener2 = data_models.Listener(id='listener2',
|
||||
l7policies=l7policies)
|
||||
listener2.l7policies = l7policies
|
||||
listeners = [listener1, listener2]
|
||||
pools = [default_pool, redirect_pool, unused_pool]
|
||||
|
||||
lb = data_models.LoadBalancer(id=LB_ID, listeners=listeners,
|
||||
pools=pools)
|
||||
mark_lb_active = database_tasks.MarkLBActiveInDB(mark_subobjects=True)
|
||||
mark_lb_active.execute(lb)
|
||||
|
||||
repo.LoadBalancerRepository.update.assert_called_once_with(
|
||||
'TEST',
|
||||
lb.id,
|
||||
provisioning_status=constants.ACTIVE)
|
||||
self.assertEqual(2, repo.ListenerRepository.update.call_count)
|
||||
repo.ListenerRepository.update.has_calls(
|
||||
[mock.call('TEST', listeners[0].id,
|
||||
provisioning_status=constants.ACTIVE),
|
||||
mock.call('TEST', listeners[1].id,
|
||||
provisioning_status=constants.ACTIVE)])
|
||||
self.assertEqual(2, repo.PoolRepository.update.call_count)
|
||||
repo.PoolRepository.update.has_calls(
|
||||
[mock.call('TEST', default_pool.id,
|
||||
provisioning_status=constants.ACTIVE),
|
||||
mock.call('TEST', redirect_pool.id,
|
||||
provisioning_status=constants.ACTIVE)])
|
||||
self.assertEqual(4, repo.MemberRepository.update.call_count)
|
||||
repo.MemberRepository.update.has_calls(
|
||||
[mock.call('TEST', members1[0].id,
|
||||
provisioning_status=constants.ACTIVE),
|
||||
mock.call('TEST', members1[1].id,
|
||||
provisioning_status=constants.ACTIVE),
|
||||
mock.call('TEST', members2[0].id,
|
||||
provisioning_status=constants.ACTIVE),
|
||||
mock.call('TEST', members2[1].id,
|
||||
provisioning_status=constants.ACTIVE)])
|
||||
self.assertEqual(1, repo.HealthMonitorRepository.update.call_count)
|
||||
repo.HealthMonitorRepository.update.has_calls(
|
||||
[mock.call('TEST', health_monitor.id,
|
||||
provisioning_status=constants.ACTIVE)])
|
||||
self.assertEqual(1, repo.L7PolicyRepository.update.call_count)
|
||||
repo.L7PolicyRepository.update.has_calls(
|
||||
[mock.call('TEST', l7policies[0].id,
|
||||
provisioning_status=constants.ACTIVE)])
|
||||
self.assertEqual(1, repo.L7RuleRepository.update.call_count)
|
||||
repo.L7RuleRepository.update.has_calls(
|
||||
[mock.call('TEST', l7rules[0].id,
|
||||
provisioning_status=constants.ACTIVE)])
|
||||
|
||||
mock_loadbalancer_repo_update.reset_mock()
|
||||
mock_listener_repo_update.reset_mock()
|
||||
mock_pool_repo_update.reset_mock()
|
||||
mock_member_repo_update.reset_mock()
|
||||
mock_hm_repo_update.reset_mock()
|
||||
mock_l7p_repo_update.reset_mock()
|
||||
mock_l7r_repo_update.reset_mock()
|
||||
mark_lb_active.revert(lb)
|
||||
|
||||
repo.LoadBalancerRepository.update.assert_called_once_with(
|
||||
'TEST',
|
||||
id=lb.id,
|
||||
provisioning_status=constants.ERROR)
|
||||
self.assertEqual(2, repo.ListenerRepository.update.call_count)
|
||||
repo.ListenerRepository.update.has_calls(
|
||||
[mock.call('TEST', listeners[0].id,
|
||||
provisioning_status=constants.ERROR),
|
||||
mock.call('TEST', listeners[1].id,
|
||||
provisioning_status=constants.ERROR)])
|
||||
self.assertEqual(2, repo.PoolRepository.update.call_count)
|
||||
repo.PoolRepository.update.has_calls(
|
||||
[mock.call('TEST', default_pool.id,
|
||||
provisioning_status=constants.ERROR),
|
||||
mock.call('TEST', redirect_pool.id,
|
||||
provisioning_status=constants.ERROR)])
|
||||
self.assertEqual(4, repo.MemberRepository.update.call_count)
|
||||
repo.MemberRepository.update.has_calls(
|
||||
[mock.call('TEST', members1[0].id,
|
||||
provisioning_status=constants.ERROR),
|
||||
mock.call('TEST', members1[1].id,
|
||||
provisioning_status=constants.ERROR),
|
||||
mock.call('TEST', members2[0].id,
|
||||
provisioning_status=constants.ERROR),
|
||||
mock.call('TEST', members2[1].id,
|
||||
provisioning_status=constants.ERROR)])
|
||||
self.assertEqual(1, repo.HealthMonitorRepository.update.call_count)
|
||||
repo.HealthMonitorRepository.update.has_calls(
|
||||
[mock.call('TEST', health_monitor.id,
|
||||
provisioning_status=constants.ERROR)])
|
||||
self.assertEqual(1, repo.L7PolicyRepository.update.call_count)
|
||||
repo.L7PolicyRepository.update.has_calls(
|
||||
[mock.call('TEST', l7policies[0].id,
|
||||
provisioning_status=constants.ERROR)])
|
||||
self.assertEqual(1, repo.L7RuleRepository.update.call_count)
|
||||
repo.L7RuleRepository.update.has_calls(
|
||||
[mock.call('TEST', l7rules[0].id,
|
||||
provisioning_status=constants.ERROR)])
|
||||
|
||||
def test_mark_LB_deleted_in_db(self,
|
||||
mock_generate_uuid,
|
||||
mock_LOG,
|
||||
|
Loading…
Reference in New Issue
Block a user