Setup executable to use wsgiref.simple_server Simple setup of pecan Defined controllers that define the API resources Implemented all controllers to manipulate database and send to handler Added repository methods required for creating multiple items in one transaction Defined a few API exceptions based of wsme exceptions Defined the wsme types that define the resource response and request bodies Defined an abstract handler that all handlers should subclass Defined a simple handler that is responsible for sending to controller Added some wsme type tests Implements: bp/operator-api Change-Id: I0d91934db47a6e45f0c9ac22089f8689957bd239
163 lines
7.3 KiB
Python
163 lines
7.3 KiB
Python
# Copyright 2014 Rackspace
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from oslo.utils import excutils
|
|
import pecan
|
|
from wsme import types as wtypes
|
|
from wsmeext import pecan as wsme_pecan
|
|
|
|
from octavia.api.v1.controllers import base
|
|
from octavia.api.v1.controllers import listener
|
|
from octavia.api.v1.types import load_balancer as lb_types
|
|
from octavia.common import constants
|
|
from octavia.common import data_models
|
|
from octavia.common import exceptions
|
|
from octavia.db import api as db_api
|
|
from octavia.i18n import _LI
|
|
from octavia.openstack.common import log as logging
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class LoadBalancersController(base.BaseController):
|
|
|
|
def __init__(self):
|
|
super(LoadBalancersController, self).__init__()
|
|
self.handler = self.handler.load_balancer
|
|
|
|
@wsme_pecan.wsexpose(lb_types.LoadBalancerResponse, wtypes.text)
|
|
def get_one(self, id):
|
|
"""Gets a single load balancer's details."""
|
|
session = db_api.get_session()
|
|
load_balancer = self.repositories.load_balancer.get(
|
|
session, id=id)
|
|
if not load_balancer:
|
|
LOG.info(_LI("Load Balancer %s was not found.") % id)
|
|
raise exceptions.NotFound(
|
|
resource=data_models.LoadBalancer._name(), id=id)
|
|
return self._convert_db_to_type(load_balancer,
|
|
lb_types.LoadBalancerResponse)
|
|
|
|
@wsme_pecan.wsexpose([lb_types.LoadBalancerResponse], wtypes.text)
|
|
def get_all(self, tenant_id=None):
|
|
"""Lists all listeners on a load balancer."""
|
|
# tenant_id is an optional query parameter
|
|
session = db_api.get_session()
|
|
load_balancers = self.repositories.load_balancer.get_all(
|
|
session, tenant_id=tenant_id)
|
|
return self._convert_db_to_type(load_balancers,
|
|
[lb_types.LoadBalancerResponse])
|
|
|
|
@wsme_pecan.wsexpose(lb_types.LoadBalancerResponse,
|
|
body=lb_types.LoadBalancerPOST, status_code=202)
|
|
def post(self, load_balancer):
|
|
"""Creates a load balancer."""
|
|
session = db_api.get_session()
|
|
lb_dict = load_balancer.to_dict()
|
|
vip_dict = lb_dict.pop('vip')
|
|
lb_dict['provisioning_status'] = constants.PENDING_CREATE
|
|
lb_dict['operating_status'] = constants.OFFLINE
|
|
db_lb = self.repositories.create_load_balancer_and_vip(
|
|
session, lb_dict, vip_dict)
|
|
# Handler will be responsible for sending to controller
|
|
try:
|
|
LOG.info(_LI("Sending created Load Balancer %s to the handler") %
|
|
db_lb.id)
|
|
self.handler.create(db_lb)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception(reraise=False):
|
|
self.repositories.load_balancer.update(
|
|
session, db_lb.id, provisioning_status=constants.ERROR)
|
|
return self._convert_db_to_type(db_lb, lb_types.LoadBalancerResponse)
|
|
|
|
@wsme_pecan.wsexpose(lb_types.LoadBalancerResponse,
|
|
wtypes.text, status_code=202,
|
|
body=lb_types.LoadBalancerPUT)
|
|
def put(self, id, load_balancer):
|
|
"""Updates a load balancer."""
|
|
session = db_api.get_session()
|
|
# Purely to make lines smaller length
|
|
lb_repo = self.repositories.load_balancer
|
|
old_db_lb = self.repositories.load_balancer.get(session, id=id)
|
|
if not old_db_lb:
|
|
LOG.info(_LI("Load Balancer %s was not found.") % id)
|
|
raise exceptions.NotFound(
|
|
resource=data_models.LoadBalancer._name(), id=id)
|
|
# Check load balancer is in a mutable status
|
|
if not lb_repo.test_and_set_provisioning_status(
|
|
session, id, constants.PENDING_UPDATE):
|
|
LOG.info(_LI("Load Balancer %s is immutable.") % id)
|
|
raise exceptions.ImmutableObject(resource=old_db_lb._name(),
|
|
id=id)
|
|
lb_dict = load_balancer.to_dict(render_unsets=False)
|
|
lb_dict['operating_status'] = old_db_lb.operating_status
|
|
self.repositories.load_balancer.update(
|
|
session, id, **lb_dict)
|
|
db_lb = self.repositories.load_balancer.get(session, id=id)
|
|
try:
|
|
LOG.info(_LI("Sending updated Load Balancer %s to the handler") %
|
|
db_lb.id)
|
|
self.handler.update(db_lb)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception(reraise=False):
|
|
self.repositories.load_balancer.update(
|
|
session, db_lb.id, provisioning_status=constants.ERROR)
|
|
return self._convert_db_to_type(db_lb, lb_types.LoadBalancerResponse)
|
|
|
|
@wsme_pecan.wsexpose(None, wtypes.text, status_code=202)
|
|
def delete(self, id):
|
|
"""Deletes a load balancer."""
|
|
session = db_api.get_session()
|
|
# Purely to make lines smaller length
|
|
lb_repo = self.repositories.load_balancer
|
|
db_lb = self.repositories.load_balancer.get(session, id=id)
|
|
if not db_lb:
|
|
LOG.info(_LI("Load Balancer %s was not found.") % id)
|
|
raise exceptions.NotFound(
|
|
resource=data_models.LoadBalancer._name(), id=id)
|
|
# Check load balancer is in a mutable status
|
|
if not lb_repo.test_and_set_provisioning_status(
|
|
session, id, constants.PENDING_DELETE):
|
|
LOG.info(_LI("Load Balancer %s is immutable.") % id)
|
|
raise exceptions.ImmutableObject(resource=db_lb._name(),
|
|
id=id)
|
|
db_lb = self.repositories.load_balancer.get(session, id=id)
|
|
try:
|
|
LOG.info(_LI("Sending deleted Load Balancer %s to the handler") %
|
|
db_lb.id)
|
|
self.handler.delete(db_lb)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception(reraise=False):
|
|
self.repositories.load_balancer.update(
|
|
session, db_lb.id, provisioning_status=constants.ERROR)
|
|
return self._convert_db_to_type(db_lb, lb_types.LoadBalancerResponse)
|
|
|
|
@pecan.expose()
|
|
def _lookup(self, lb_id, *remainder):
|
|
"""Overriden pecan _lookup method for custom routing.
|
|
|
|
Verifies that the load balancer passed in the url exists, and if so
|
|
decides which controller, if any, should control be passed.
|
|
"""
|
|
session = db_api.get_session()
|
|
if lb_id and len(remainder) and remainder[0] == 'listeners':
|
|
remainder = remainder[1:]
|
|
db_lb = self.repositories.load_balancer.get(session, id=lb_id)
|
|
if not db_lb:
|
|
LOG.info(_LI("Load Balancer %s was not found.") % lb_id)
|
|
raise exceptions.NotFound(
|
|
resource=data_models.LoadBalancer._name(), id=lb_id)
|
|
return listener.ListenersController(
|
|
load_balancer_id=db_lb.id), remainder |