def _validate_pool_PUT(self, pool, db_pool): if db_pool.protocol == constants.PROTOCOL_UDP: self._validate_pool_request_for_udp(pool) else: if (pool.session_persistence and ( pool.session_persistence.persistence_timeout or pool.session_persistence.persistence_granularity)): raise exceptions.ValidationException(detail=_( "persistence_timeout and persistence_granularity " "is only for UDP protocol pools.")) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) crl_ref = None # If we got a crl_ref and it's not unset, use it if (pool.crl_container_ref and pool.crl_container_ref != wtypes.Unset): crl_ref = pool.crl_container_ref # If we got Unset and a CRL exists in the DB, use the DB crl_ref elif (db_pool.crl_container_id and pool.crl_container_ref == wtypes.Unset): crl_ref = db_pool.crl_container_id ca_ref = None db_ca_ref = db_pool.ca_tls_certificate_id if pool.ca_tls_container_ref != wtypes.Unset: if not pool.ca_tls_container_ref and db_ca_ref and crl_ref: raise exceptions.ValidationException(detail=_( "A CA reference cannot be removed when a " "certificate revocation list is present.")) if not pool.ca_tls_container_ref and not db_ca_ref and crl_ref: raise exceptions.ValidationException(detail=_( "A CA reference is required to " "specify a certificate revocation list.")) if pool.ca_tls_container_ref: ca_ref = pool.ca_tls_container_ref elif db_ca_ref and pool.ca_tls_container_ref == wtypes.Unset: ca_ref = db_ca_ref elif crl_ref and not db_ca_ref: raise exceptions.ValidationException(detail=_( "A CA reference is required to " "specify a certificate revocation list.")) if pool.tls_container_ref: self._validate_tls_refs([pool.tls_container_ref]) # Validate the client CA cert and optional client CRL if ca_ref: self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)
def put(self, id, pool_): """Updates a pool on a load balancer.""" pool = pool_.pool context = pecan.request.context.get('octavia_context') db_pool = self._get_db_pool(context.session, id, show_deleted=False) project_id, provider = self._get_lb_project_id_provider( context.session, db_pool.load_balancer_id) self._auth_validate_action(context, project_id, constants.RBAC_PUT) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_statuses( context.session, lb_id=db_pool.load_balancer_id, listener_ids=self._get_affected_listener_ids(db_pool)) # Prepare the data for the driver data model pool_dict = pool.to_dict(render_unsets=False) pool_dict['id'] = id provider_pool_dict = ( driver_utils.pool_dict_to_provider_dict(pool_dict)) # Also prepare the baseline object data old_provider_pool = driver_utils.db_pool_to_provider_pool(db_pool) # Dispatch to the driver LOG.info("Sending update Pool %s to provider %s", id, driver.name) driver_utils.call_provider( driver.name, driver.pool_update, old_provider_pool, driver_dm.Pool.from_dict(provider_pool_dict)) # Update the database to reflect what the driver just accepted pool.provisioning_status = constants.PENDING_UPDATE db_pool_dict = pool.to_dict(render_unsets=False) self.repositories.update_pool_and_sp(lock_session, id, db_pool_dict) # Force SQL alchemy to query the DB, otherwise we get inconsistent # results context.session.expire_all() db_pool = self._get_db_pool(context.session, id) result = self._convert_db_to_type(db_pool, pool_types.PoolResponse) return pool_types.PoolRootResponse(pool=result)
def _validate_pool_PUT(self, pool, db_pool): if db_pool.protocol == constants.PROTOCOL_UDP: self._validate_pool_request_for_udp(pool) else: if (pool.session_persistence and ( pool.session_persistence.persistence_timeout or pool.session_persistence.persistence_granularity)): raise exceptions.ValidationException(detail=_( "persistence_timeout and persistence_granularity " "is only for UDP protocol pools.")) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) crl_ref = None if (pool.crl_container_ref and pool.crl_container_ref != wtypes.Unset): crl_ref = pool.crl_container_ref elif db_pool.crl_container_id: crl_ref = db_pool.crl_container_id ca_ref = None db_ca_ref = db_pool.ca_tls_certificate_id if pool.ca_tls_container_ref != wtypes.Unset: if not pool.ca_tls_container_ref and db_ca_ref and crl_ref: raise exceptions.ValidationException(detail=_( "A CA reference cannot be removed when a " "certificate revocation list is present.")) if not pool.ca_tls_container_ref and not db_ca_ref and crl_ref: raise exceptions.ValidationException(detail=_( "A CA reference is required to " "specify a certificate revocation list.")) if pool.ca_tls_container_ref: ca_ref = pool.ca_tls_container_ref elif db_ca_ref: ca_ref = db_ca_ref elif crl_ref and not db_ca_ref: raise exceptions.ValidationException(detail=_( "A CA reference is required to " "specify a certificate revocation list.")) if pool.tls_container_ref: self._validate_tls_refs([pool.tls_container_ref]) # Validate the client CA cert and optional client CRL if ca_ref: self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)
def test_check_session_persistence(self): valid_cookie_name_dict = { 'type': 'APP_COOKIE', 'cookie_name': 'chocolate_chip' } invalid_cookie_name_dict = { 'type': 'APP_COOKIE', 'cookie_name': '@chocolate_chip' } invalid_type_HTTP_cookie_name_dict = { 'type': 'HTTP_COOKIE', 'cookie_name': 'chocolate_chip' } invalid_type_IP_cookie_name_dict = { 'type': 'SOURCE_IP', 'cookie_name': 'chocolate_chip' } invalid_missing_cookie_name_dict = {'type': 'APP_COOKIE'} # Validate that a good cookie name passes validate.check_session_persistence(valid_cookie_name_dict) # Test raises with providing an invalid cookie name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_cookie_name_dict) # Test raises type HTTP_COOKIE and providing cookie_name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_type_HTTP_cookie_name_dict) # Test raises type SOURCE_IP and providing cookie_name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_type_IP_cookie_name_dict) # Test raises when type APP_COOKIE but no cookie_name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_missing_cookie_name_dict) # Test catch all exception raises a user friendly message with mock.patch('re.compile') as compile_mock: compile_mock.side_effect = Exception self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, valid_cookie_name_dict)
def put(self, id, pool_): """Updates a pool on a load balancer.""" pool = pool_.pool context = pecan.request.context.get('octavia_context') db_pool = self._get_db_pool(context.session, id, show_deleted=False) self._auth_validate_action(context, db_pool.project_id, constants.RBAC_PUT) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) self._test_lb_and_listener_statuses( context.session, lb_id=db_pool.load_balancer_id, listener_ids=self._get_affected_listener_ids(db_pool)) self.repositories.pool.update( context.session, db_pool.id, provisioning_status=constants.PENDING_UPDATE) try: LOG.info("Sending Update of Pool %s to handler", id) self.handler.update(db_pool, pool) except Exception: with excutils.save_and_reraise_exception( reraise=False), db_api.get_lock_session() as lock_session: self._reset_lb_and_listener_statuses( lock_session, lb_id=db_pool.load_balancer_id, listener_ids=self._get_affected_listener_ids(db_pool)) # Pool now goes to ERROR self.repositories.pool.update( lock_session, db_pool.id, provisioning_status=constants.ERROR) db_pool = self._get_db_pool(context.session, id) result = self._convert_db_to_type(db_pool, pool_types.PoolResponse) return pool_types.PoolRootResponse(pool=result)
def test_check_session_persistence(self): valid_cookie_name_dict = {'type': 'APP_COOKIE', 'cookie_name': 'chocolate_chip'} invalid_cookie_name_dict = {'type': 'APP_COOKIE', 'cookie_name': '@chocolate_chip'} invalid_type_HTTP_cookie_name_dict = {'type': 'HTTP_COOKIE', 'cookie_name': 'chocolate_chip'} invalid_type_IP_cookie_name_dict = {'type': 'SOURCE_IP', 'cookie_name': 'chocolate_chip'} invalid_missing_cookie_name_dict = {'type': 'APP_COOKIE'} # Validate that a good cookie name passes validate.check_session_persistence(valid_cookie_name_dict) # Test raises with providing an invalid cookie name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_cookie_name_dict) # Test raises type HTTP_COOKIE and providing cookie_name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_type_HTTP_cookie_name_dict) # Test raises type SOURCE_IP and providing cookie_name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_type_IP_cookie_name_dict) # Test raises when type APP_COOKIE but no cookie_name self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, invalid_missing_cookie_name_dict) # Test catch all exception raises a user friendly message with mock.patch('re.compile') as compile_mock: compile_mock.side_effect = Exception self.assertRaises(exceptions.ValidationException, validate.check_session_persistence, valid_cookie_name_dict)
def post(self, pool_): """Creates a pool on a load balancer or listener. Note that this can optionally take a listener_id with which the pool should be associated as the listener's default_pool. If specified, the pool creation will fail if the listener specified already has a default_pool. """ # For some API requests the listener_id will be passed in the # pool_dict: pool = pool_.pool context = pecan.request.context.get('octavia_context') if pool.loadbalancer_id: pool.project_id, provider = self._get_lb_project_id_provider( context.session, pool.loadbalancer_id) elif pool.listener_id: listener = self.repositories.listener.get(context.session, id=pool.listener_id) pool.loadbalancer_id = listener.load_balancer_id pool.project_id, provider = self._get_lb_project_id_provider( context.session, pool.loadbalancer_id) else: msg = _("Must provide at least one of: " "loadbalancer_id, listener_id") raise exceptions.ValidationException(detail=msg) self._auth_validate_action(context, pool.project_id, constants.RBAC_POST) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) lock_session = db_api.get_session(autocommit=False) try: if self.repositories.check_quota_met(context.session, lock_session, data_models.Pool, pool.project_id): raise exceptions.QuotaException( resource=data_models.Pool._name()) listener_repo = self.repositories.listener pool_dict = db_prepare.create_pool( pool.to_dict(render_unsets=True)) listener_id = pool_dict.pop('listener_id', None) if listener_id: if listener_repo.has_default_pool(lock_session, listener_id): raise exceptions.DuplicatePoolEntry() self._test_lb_and_listener_statuses( lock_session, lb_id=pool_dict['load_balancer_id'], listener_ids=[listener_id] if listener_id else []) db_pool = self._validate_create_pool(lock_session, pool_dict, listener_id) # Prepare the data for the driver data model provider_pool = (driver_utils.db_pool_to_provider_pool(db_pool)) # Dispatch to the driver LOG.info("Sending create Pool %s to provider %s", db_pool.id, driver.name) driver_utils.call_provider(driver.name, driver.pool_create, provider_pool) lock_session.commit() except Exception: with excutils.save_and_reraise_exception(): lock_session.rollback() db_pool = self._get_db_pool(context.session, db_pool.id) result = self._convert_db_to_type(db_pool, pool_types.PoolResponse) return pool_types.PoolRootResponse(pool=result)
def _validate_pool_PUT(self, pool, db_pool): if db_pool.protocol == constants.PROTOCOL_UDP: self._validate_pool_request_for_udp(pool) else: if (pool.session_persistence and ( pool.session_persistence.persistence_timeout or pool.session_persistence.persistence_granularity)): raise exceptions.ValidationException(detail=_( "persistence_timeout and persistence_granularity " "is only for UDP protocol pools.")) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) crl_ref = None # If we got a crl_ref and it's not unset, use it if (pool.crl_container_ref and pool.crl_container_ref != wtypes.Unset): crl_ref = pool.crl_container_ref # If we got Unset and a CRL exists in the DB, use the DB crl_ref elif (db_pool.crl_container_id and pool.crl_container_ref == wtypes.Unset): crl_ref = db_pool.crl_container_id ca_ref = None db_ca_ref = db_pool.ca_tls_certificate_id if pool.ca_tls_container_ref != wtypes.Unset: if not pool.ca_tls_container_ref and db_ca_ref and crl_ref: raise exceptions.ValidationException(detail=_( "A CA reference cannot be removed when a " "certificate revocation list is present.")) if not pool.ca_tls_container_ref and not db_ca_ref and crl_ref: raise exceptions.ValidationException(detail=_( "A CA reference is required to " "specify a certificate revocation list.")) if pool.ca_tls_container_ref: ca_ref = pool.ca_tls_container_ref elif db_ca_ref and pool.ca_tls_container_ref == wtypes.Unset: ca_ref = db_ca_ref elif crl_ref and not db_ca_ref: raise exceptions.ValidationException(detail=_( "A CA reference is required to " "specify a certificate revocation list.")) if pool.tls_container_ref: self._validate_tls_refs([pool.tls_container_ref]) # Validate the client CA cert and optional client CRL if ca_ref: self._validate_client_ca_and_crl_refs(ca_ref, crl_ref) # Check TLS cipher prohibit list if pool.tls_ciphers: rejected_ciphers = validate.check_cipher_prohibit_list( pool.tls_ciphers) if rejected_ciphers: raise exceptions.ValidationException(detail=_( "The following ciphers have been prohibited by an " "administrator: " + ', '.join(rejected_ciphers))) if pool.tls_versions is not wtypes.Unset: # Validate TLS version list validate.check_tls_version_list(pool.tls_versions) # Validate TLS version against minimum validate.check_tls_version_min(pool.tls_versions)
def post(self, pool_): """Creates a pool on a load balancer or listener. Note that this can optionally take a listener_id with which the pool should be associated as the listener's default_pool. If specified, the pool creation will fail if the listener specified already has a default_pool. """ # For some API requests the listener_id will be passed in the # pool_dict: pool = pool_.pool context = pecan.request.context.get('octavia_context') if pool.loadbalancer_id: pool.project_id = self._get_lb_project_id(context.session, pool.loadbalancer_id) elif pool.listener_id: listener = self.repositories.listener.get(context.session, id=pool.listener_id) pool.project_id = listener.project_id pool.loadbalancer_id = listener.load_balancer_id else: msg = _("Must provide at least one of: " "loadbalancer_id, listener_id") raise exceptions.ValidationException(detail=msg) self._auth_validate_action(context, pool.project_id, constants.RBAC_POST) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) lock_session = db_api.get_session(autocommit=False) try: if self.repositories.check_quota_met(context.session, lock_session, data_models.Pool, pool.project_id): raise exceptions.QuotaException listener_repo = self.repositories.listener pool_dict = db_prepare.create_pool( pool.to_dict(render_unsets=True)) listener_id = pool_dict.pop('listener_id', None) if listener_id: if listener_repo.has_default_pool(lock_session, listener_id): raise exceptions.DuplicatePoolEntry() self._test_lb_and_listener_statuses( lock_session, lb_id=pool_dict['load_balancer_id'], listener_ids=[listener_id] if listener_id else []) db_pool = self._validate_create_pool(lock_session, pool_dict, listener_id) lock_session.commit() except Exception: with excutils.save_and_reraise_exception(): lock_session.rollback() return self._send_pool_to_handler(context.session, db_pool, listener_id=listener_id)
def post(self, pool_): """Creates a pool on a load balancer or listener. Note that this can optionally take a listener_id with which the pool should be associated as the listener's default_pool. If specified, the pool creation will fail if the listener specified already has a default_pool. """ # For some API requests the listener_id will be passed in the # pool_dict: pool = pool_.pool context = pecan.request.context.get('octavia_context') if pool.protocol == constants.PROTOCOL_UDP: self._validate_pool_request_for_udp(pool) else: if (pool.session_persistence and ( pool.session_persistence.persistence_timeout or pool.session_persistence.persistence_granularity)): raise exceptions.ValidationException(detail=_( "persistence_timeout and persistence_granularity " "is only for UDP protocol pools.")) if pool.loadbalancer_id: pool.project_id, provider = self._get_lb_project_id_provider( context.session, pool.loadbalancer_id) elif pool.listener_id: listener = self.repositories.listener.get( context.session, id=pool.listener_id) pool.loadbalancer_id = listener.load_balancer_id pool.project_id, provider = self._get_lb_project_id_provider( context.session, pool.loadbalancer_id) else: msg = _("Must provide at least one of: " "loadbalancer_id, listener_id") raise exceptions.ValidationException(detail=msg) self._auth_validate_action(context, pool.project_id, constants.RBAC_POST) if pool.session_persistence: sp_dict = pool.session_persistence.to_dict(render_unsets=False) validate.check_session_persistence(sp_dict) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) lock_session = db_api.get_session(autocommit=False) try: if self.repositories.check_quota_met( context.session, lock_session, data_models.Pool, pool.project_id): raise exceptions.QuotaException( resource=data_models.Pool._name()) listener_repo = self.repositories.listener pool_dict = db_prepare.create_pool( pool.to_dict(render_unsets=True)) listener_id = pool_dict.pop('listener_id', None) if listener_id: if listener_repo.has_default_pool(lock_session, listener_id): raise exceptions.DuplicatePoolEntry() self._test_lb_and_listener_statuses( lock_session, lb_id=pool_dict['load_balancer_id'], listener_ids=[listener_id] if listener_id else []) db_pool = self._validate_create_pool( lock_session, pool_dict, listener_id) # Prepare the data for the driver data model provider_pool = ( driver_utils.db_pool_to_provider_pool(db_pool)) # Dispatch to the driver LOG.info("Sending create Pool %s to provider %s", db_pool.id, driver.name) driver_utils.call_provider( driver.name, driver.pool_create, provider_pool) lock_session.commit() except Exception: with excutils.save_and_reraise_exception(): lock_session.rollback() db_pool = self._get_db_pool(context.session, db_pool.id) result = self._convert_db_to_type(db_pool, pool_types.PoolResponse) return pool_types.PoolRootResponse(pool=result)