Fix Octavia v1 API project_id for POST
This patch corrects the project_id handling for POST calls to the Octavia v1 API. For load balancer create calls we use the specified project_id if the user is an admin or noauth is specified. If no project_id is specified in the request we use the project_id from the context. If no project_id can be found we raise an exception. For the other object POST methods we use the project_id from the parent load balancer. Change-Id: Ibf59541b8811e3bbe36cfec039f91e20036102e4 Closes-Bug: #1624145
This commit is contained in:
parent
9cd1bab382
commit
108ab27952
@ -135,3 +135,9 @@ class BaseController(rest.RestController):
|
||||
if db_quotas.member is None:
|
||||
db_quotas.member = CONF.quotas.default_member_quota
|
||||
return db_quotas
|
||||
|
||||
def _get_lb_project_id(self, session, id):
|
||||
"""Get the project_id of the load balancer from the database."""
|
||||
lb = self._get_db_obj(session, self.repositories.load_balancer,
|
||||
data_models.LoadBalancer, id)
|
||||
return lb.project_id
|
||||
|
@ -96,6 +96,9 @@ class HealthMonitorController(base.BaseController):
|
||||
"""Creates a health monitor on a pool."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
health_monitor.project_id = self._get_lb_project_id(
|
||||
context.session, self.load_balancer_id)
|
||||
|
||||
try:
|
||||
db_hm = self.repositories.health_monitor.get(
|
||||
context.session, pool_id=self.pool_id)
|
||||
|
@ -77,6 +77,7 @@ class L7PolicyController(base.BaseController):
|
||||
def post(self, l7policy):
|
||||
"""Creates a l7policy on a listener."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
l7policy_dict = validate.sanitize_l7policy_api_args(
|
||||
l7policy.to_dict(render_unsets=True), create=True)
|
||||
# Make sure any pool specified by redirect_pool_id exists
|
||||
|
@ -88,6 +88,7 @@ class L7RuleController(base.BaseController):
|
||||
except Exception as e:
|
||||
raise exceptions.L7RuleValidation(error=e)
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
self._check_l7policy_max_rules(context.session)
|
||||
l7rule_dict = db_prepare.create_l7rule(
|
||||
l7rule.to_dict(render_unsets=True), self.l7policy_id)
|
||||
|
@ -162,6 +162,9 @@ class ListenersController(base.BaseController):
|
||||
"""Creates a listener on a load balancer."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
listener.project_id = self._get_lb_project_id(context.session,
|
||||
self.load_balancer_id)
|
||||
|
||||
lock_session = db_api.get_session(autocommit=False)
|
||||
if self.repositories.check_quota_met(
|
||||
context.session,
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
@ -33,7 +34,7 @@ from octavia.db import api as db_api
|
||||
from octavia.db import prepare as db_prepare
|
||||
from octavia.i18n import _LI
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -103,6 +104,17 @@ class LoadBalancersController(base.BaseController):
|
||||
def post(self, load_balancer):
|
||||
"""Creates a load balancer."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
project_id = context.project_id
|
||||
if context.is_admin or CONF.auth_strategy == constants.NOAUTH:
|
||||
if load_balancer.project_id:
|
||||
project_id = load_balancer.project_id
|
||||
|
||||
if not project_id:
|
||||
raise exceptions.MissingAPIProjectID()
|
||||
|
||||
load_balancer.project_id = project_id
|
||||
|
||||
# Validate the subnet id
|
||||
if load_balancer.vip.subnet_id:
|
||||
if not validate.subnet_exists(load_balancer.vip.subnet_id):
|
||||
|
@ -94,6 +94,10 @@ class MembersController(base.BaseController):
|
||||
def post(self, member):
|
||||
"""Creates a pool member on a pool."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
member.project_id = self._get_lb_project_id(context.session,
|
||||
self.load_balancer_id)
|
||||
|
||||
# Validate member subnet
|
||||
if member.subnet_id and not validate.subnet_exists(member.subnet_id):
|
||||
raise exceptions.NotFound(resource='Subnet',
|
||||
|
@ -134,6 +134,9 @@ class PoolsController(base.BaseController):
|
||||
# pool_dict:
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
pool.project_id = self._get_lb_project_id(context.session,
|
||||
self.load_balancer_id)
|
||||
|
||||
lock_session = db_api.get_session(autocommit=False)
|
||||
if self.repositories.check_quota_met(
|
||||
context.session,
|
||||
|
@ -21,6 +21,8 @@ from wsmeext import pecan as wsme_pecan
|
||||
|
||||
from octavia.api.v1.controllers import base
|
||||
from octavia.api.v1.types import quotas as quota_types
|
||||
from octavia.common import constants
|
||||
from octavia.common import exceptions
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_group('quotas', 'octavia.common.config')
|
||||
@ -52,6 +54,17 @@ class QuotasController(base.BaseController):
|
||||
def put(self, project_id, quotas):
|
||||
"""Update any or all quotas for a project."""
|
||||
context = pecan.request.context.get('octavia_context')
|
||||
|
||||
new_project_id = context.project_id
|
||||
if context.is_admin or CONF.auth_strategy == constants.NOAUTH:
|
||||
if project_id:
|
||||
new_project_id = project_id
|
||||
|
||||
if not new_project_id:
|
||||
raise exceptions.MissingAPIProjectID()
|
||||
|
||||
project_id = new_project_id
|
||||
|
||||
quotas_dict = quotas.to_dict()
|
||||
self.repositories.quotas.update(context.session, project_id,
|
||||
**quotas_dict)
|
||||
|
@ -48,6 +48,7 @@ class HealthMonitorPOST(base.BaseType):
|
||||
expected_codes = wtypes.wsattr(
|
||||
wtypes.text, default=constants.HEALTH_MONITOR_DEFAULT_EXPECTED_CODES)
|
||||
enabled = wtypes.wsattr(bool, default=True)
|
||||
# TODO(johnsom) Remove after deprecation (R series)
|
||||
project_id = wtypes.wsattr(wtypes.StringType(max_length=36))
|
||||
|
||||
|
||||
|
@ -89,6 +89,7 @@ class ListenerPOST(base.BaseType):
|
||||
tls_certificate_id = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||
tls_termination = wtypes.wsattr(TLSTermination)
|
||||
sni_containers = [wtypes.StringType(max_length=255)]
|
||||
# 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)
|
||||
|
@ -39,6 +39,7 @@ class MemberPOST(base.BaseType):
|
||||
protocol_port = wtypes.wsattr(wtypes.IntegerType(), mandatory=True)
|
||||
weight = wtypes.wsattr(wtypes.IntegerType(), default=1)
|
||||
subnet_id = wtypes.wsattr(wtypes.UuidType())
|
||||
# TODO(johnsom) Remove after deprecation (R series)
|
||||
project_id = wtypes.wsattr(wtypes.StringType(max_length=36))
|
||||
|
||||
|
||||
|
@ -97,6 +97,7 @@ class PoolPOST(base.BaseType):
|
||||
wtypes.Enum(str, *constants.SUPPORTED_LB_ALGORITHMS),
|
||||
mandatory=True)
|
||||
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])
|
||||
|
@ -253,3 +253,8 @@ class ProjectBusyException(APIException):
|
||||
|
||||
class MissingProjectID(OctaviaException):
|
||||
message = _('Missing project ID in request where one is required.')
|
||||
|
||||
|
||||
class MissingAPIProjectID(APIException):
|
||||
msg = _('Missing project ID in request where one is required.')
|
||||
code = 400
|
||||
|
@ -117,7 +117,7 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
self.pool.get('id'),
|
||||
constants.HEALTH_MONITOR_HTTP,
|
||||
1, 1, 1, 1, project_id=pid)
|
||||
self.assertEqual(pid, api_hm.get('project_id'))
|
||||
self.assertEqual(self.project_id, api_hm.get('project_id'))
|
||||
|
||||
def test_create_over_quota(self):
|
||||
self.check_quota_met_true_mock.start()
|
||||
|
@ -113,6 +113,7 @@ class TestListener(base.BaseAPITest):
|
||||
self.assertIn(sni, sni_ex)
|
||||
self.assertIsNotNone(listener_api.pop('created_at'))
|
||||
self.assertIsNone(listener_api.pop('updated_at'))
|
||||
lb_listener['project_id'] = self.project_id
|
||||
self.assertEqual(lb_listener, listener_api)
|
||||
self.assert_correct_lb_status(self.lb.get('id'),
|
||||
constants.PENDING_UPDATE,
|
||||
|
@ -123,7 +123,7 @@ class TestMember(base.BaseAPITest):
|
||||
api_member = self.create_member(self.lb.get('id'),
|
||||
self.pool.get('id'),
|
||||
'10.0.0.1', 80, project_id=pid)
|
||||
self.assertEqual(pid, api_member.get('project_id'))
|
||||
self.assertEqual(self.project_id, api_member.get('project_id'))
|
||||
|
||||
def test_create_with_duplicate_id(self):
|
||||
member = self.create_member(self.lb.get('id'),
|
||||
|
@ -166,7 +166,7 @@ class TestPool(base.BaseAPITest):
|
||||
constants.PROTOCOL_HTTP,
|
||||
constants.LB_ALGORITHM_ROUND_ROBIN,
|
||||
project_id=pid)
|
||||
self.assertEqual(pid, api_pool.get('project_id'))
|
||||
self.assertEqual(self.project_id, api_pool.get('project_id'))
|
||||
|
||||
def test_create_with_duplicate_id(self):
|
||||
pool = self.create_pool(self.lb.get('id'),
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
deprecations:
|
||||
- |
|
||||
The project_id attribute of the POST method on the following objects
|
||||
is now deprecated\: listener, pool, health monitor, and member.
|
||||
These objects will use the parent load balancer's project_id.
|
||||
Values passed into the project_id on those objects will be ignored
|
||||
until the deprecation cycle has expired, at which point they will
|
||||
cause an error.
|
Loading…
Reference in New Issue
Block a user