API: More work on the API server
* Improved error handling * VirtualIPs function added * Limits function added * Limits checked in create * Other cleanups/fixes Change-Id: Idf5abc1d9a568d8193aee9bc7b60c3224c8c331c
This commit is contained in:
parent
cbe623c226
commit
1c490c7bfb
@ -13,17 +13,14 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from pecan import expose, response
|
from pecan import response
|
||||||
from pecan.rest import RestController
|
from pecan.rest import RestController
|
||||||
|
|
||||||
from libra.api.model.responses import Responses
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionThrottleController(RestController):
|
class ConnectionThrottleController(RestController):
|
||||||
"""functions for /loadbalancers/{loadBalancerId}/connectionthrottle/*
|
"""functions for /loadbalancers/{loadBalancerId}/connectionthrottle/*
|
||||||
routing"""
|
routing"""
|
||||||
|
|
||||||
@expose('json')
|
|
||||||
def get(self, load_balancer_id):
|
def get(self, load_balancer_id):
|
||||||
"""List connection throttling configuration.
|
"""List connection throttling configuration.
|
||||||
|
|
||||||
@ -35,9 +32,8 @@ class ConnectionThrottleController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.ConnectionThrottle.get
|
return None
|
||||||
|
|
||||||
@expose('json')
|
|
||||||
def post(self, load_balancer_id, *args):
|
def post(self, load_balancer_id, *args):
|
||||||
"""Update throttling configuration.
|
"""Update throttling configuration.
|
||||||
|
|
||||||
@ -50,9 +46,8 @@ class ConnectionThrottleController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.ConnectionThrottle.get
|
return None
|
||||||
|
|
||||||
@expose()
|
|
||||||
def delete(self, loadbalancer_id):
|
def delete(self, loadbalancer_id):
|
||||||
"""Remove connection throttling configurations.
|
"""Remove connection throttling configurations.
|
||||||
|
|
||||||
|
@ -13,16 +13,13 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from pecan import expose, response
|
from pecan import response
|
||||||
from pecan.rest import RestController
|
from pecan.rest import RestController
|
||||||
|
|
||||||
from libra.api.model.responses import Responses
|
|
||||||
|
|
||||||
|
|
||||||
class HealthMonitorController(RestController):
|
class HealthMonitorController(RestController):
|
||||||
"""functions for /loadbalancers/{loadBalancerId}/healthmonitor/* routing"""
|
"""functions for /loadbalancers/{loadBalancerId}/healthmonitor/* routing"""
|
||||||
|
|
||||||
@expose('json')
|
|
||||||
def get(self, load_balancer_id):
|
def get(self, load_balancer_id):
|
||||||
"""Retrieve the health monitor configuration, if one exists.
|
"""Retrieve the health monitor configuration, if one exists.
|
||||||
|
|
||||||
@ -34,9 +31,8 @@ class HealthMonitorController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.get
|
return None
|
||||||
|
|
||||||
@expose('json')
|
|
||||||
def post(self, load_balancer_id, *args):
|
def post(self, load_balancer_id, *args):
|
||||||
"""Update the settings for a health monitor.
|
"""Update the settings for a health monitor.
|
||||||
|
|
||||||
@ -49,9 +45,8 @@ class HealthMonitorController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.get
|
return None
|
||||||
|
|
||||||
@expose()
|
|
||||||
def delete(self, load_balancer_id):
|
def delete(self, load_balancer_id):
|
||||||
"""Remove the health monitor.
|
"""Remove the health monitor.
|
||||||
|
|
||||||
|
30
libra/api/controllers/limits.py
Normal file
30
libra/api/controllers/limits.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# 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 pecan import expose
|
||||||
|
from pecan.rest import RestController
|
||||||
|
from libra.api.model.lbaas import Limits, session
|
||||||
|
|
||||||
|
|
||||||
|
class LimitsController(RestController):
|
||||||
|
@expose('json')
|
||||||
|
def get(self):
|
||||||
|
resp = {}
|
||||||
|
limits = session.query(Limits).all()
|
||||||
|
for limit in limits:
|
||||||
|
resp[limit.name] = limit.value
|
||||||
|
|
||||||
|
resp = {"limits": {"absolute": {"values": resp}}}
|
||||||
|
return resp
|
@ -1,4 +1,3 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
@ -13,41 +12,27 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
#import gearman.errors
|
|
||||||
import logging
|
import logging
|
||||||
# pecan imports
|
# pecan imports
|
||||||
from pecan import expose, abort, response, request
|
from pecan import expose, abort, response, request
|
||||||
from pecan.rest import RestController
|
from pecan.rest import RestController
|
||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
from wsme.exc import ClientSideError
|
from wsme.exc import ClientSideError, InvalidInput
|
||||||
|
from wsme import Unset
|
||||||
# other controllers
|
# other controllers
|
||||||
from nodes import NodesController
|
from nodes import NodesController
|
||||||
from health_monitor import HealthMonitorController
|
from health_monitor import HealthMonitorController
|
||||||
from session_persistence import SessionPersistenceController
|
from session_persistence import SessionPersistenceController
|
||||||
from connection_throttle import ConnectionThrottleController
|
from connection_throttle import ConnectionThrottleController
|
||||||
#from sqlalchemy.orm import aliased
|
|
||||||
# default response objects
|
|
||||||
from libra.api.model.responses import Responses
|
|
||||||
# models
|
# models
|
||||||
from libra.api.model.lbaas import LoadBalancer, Device, Node, session
|
from libra.api.model.lbaas import LoadBalancer, Device, Node, session
|
||||||
from libra.api.model.lbaas import loadbalancers_devices
|
from libra.api.model.lbaas import loadbalancers_devices, Limits
|
||||||
from libra.api.model.validators import LBPost, LBResp, LBVipResp, LBNode
|
from libra.api.model.validators import LBPost, LBResp, LBVipResp, LBNode
|
||||||
from libra.api.library.gearman_client import submit_job
|
from libra.api.library.gearman_client import submit_job
|
||||||
from libra.api.acl import get_limited_to_project
|
from libra.api.acl import get_limited_to_project
|
||||||
|
|
||||||
|
|
||||||
class LoadBalancersController(RestController):
|
class LoadBalancersController(RestController):
|
||||||
"""functions for /loadbalancer routing"""
|
|
||||||
loadbalancer_status = (
|
|
||||||
'ACTIVE',
|
|
||||||
'BUILD',
|
|
||||||
'PENDING_UPDATE',
|
|
||||||
'PENDING_DELETE',
|
|
||||||
'DELETED',
|
|
||||||
'SUSPENDED',
|
|
||||||
'ERROR'
|
|
||||||
)
|
|
||||||
|
|
||||||
"""nodes subclass linking
|
"""nodes subclass linking
|
||||||
controller class for urls that look like
|
controller class for urls that look like
|
||||||
/loadbalancers/{loadBalancerId}/nodes/*
|
/loadbalancers/{loadBalancerId}/nodes/*
|
||||||
@ -73,7 +58,7 @@ class LoadBalancersController(RestController):
|
|||||||
connectionthrottle = ConnectionThrottleController()
|
connectionthrottle = ConnectionThrottleController()
|
||||||
|
|
||||||
@expose('json')
|
@expose('json')
|
||||||
def get(self, load_balancer_id=None):
|
def get(self, load_balancer_id=None, command=None):
|
||||||
"""Fetches a list of load balancers or the details of one balancer if
|
"""Fetches a list of load balancers or the details of one balancer if
|
||||||
load_balancer_id is not empty.
|
load_balancer_id is not empty.
|
||||||
|
|
||||||
@ -90,11 +75,15 @@ class LoadBalancersController(RestController):
|
|||||||
|
|
||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
|
if command == 'virtualips':
|
||||||
|
return self.virtualips(load_balancer_id)
|
||||||
|
elif command:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
tenant_id = get_limited_to_project(request.headers)
|
tenant_id = get_limited_to_project(request.headers)
|
||||||
|
|
||||||
# if we don't have an id then we want a list of them own by this tenent
|
# if we don't have an id then we want a list of them own by this tenent
|
||||||
if not load_balancer_id:
|
if not load_balancer_id:
|
||||||
#return Responses.LoadBalancers.get
|
|
||||||
load_balancers = {'loadBalancers': session.query(
|
load_balancers = {'loadBalancers': session.query(
|
||||||
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
||||||
LoadBalancer.port, LoadBalancer.algorithm,
|
LoadBalancer.port, LoadBalancer.algorithm,
|
||||||
@ -102,7 +91,6 @@ class LoadBalancersController(RestController):
|
|||||||
LoadBalancer.updated
|
LoadBalancer.updated
|
||||||
).filter_by(tenantid=tenant_id).all()}
|
).filter_by(tenantid=tenant_id).all()}
|
||||||
else:
|
else:
|
||||||
#return Responses.LoadBalancers.detail
|
|
||||||
load_balancers = session.query(
|
load_balancers = session.query(
|
||||||
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
||||||
LoadBalancer.port, LoadBalancer.algorithm,
|
LoadBalancer.port, LoadBalancer.algorithm,
|
||||||
@ -116,7 +104,10 @@ class LoadBalancersController(RestController):
|
|||||||
if not load_balancers:
|
if not load_balancers:
|
||||||
response.status = 400
|
response.status = 400
|
||||||
session.rollback()
|
session.rollback()
|
||||||
return dict(status=400, message="load balancer not found")
|
return dict(
|
||||||
|
faultcode='Client',
|
||||||
|
faultstring="Load Balancer ID not found"
|
||||||
|
)
|
||||||
|
|
||||||
load_balancers = load_balancers._asdict()
|
load_balancers = load_balancers._asdict()
|
||||||
virtualIps = session.query(
|
virtualIps = session.query(
|
||||||
@ -174,9 +165,30 @@ class LoadBalancersController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
tenant_id = get_limited_to_project(request.headers)
|
tenant_id = get_limited_to_project(request.headers)
|
||||||
|
if body.nodes == Unset:
|
||||||
|
raise ClientSideError(
|
||||||
|
'At least one backend node needs to be supplied'
|
||||||
|
)
|
||||||
|
|
||||||
|
lblimit = session.query(Limits.value).\
|
||||||
|
filter(Limits.name == 'maxLoadBalancers').scalar()
|
||||||
|
nodelimit = session.query(Limits.value).\
|
||||||
|
filter(Limits.name == 'maxNodesPerLoadBalancer').scalar()
|
||||||
|
count = session.query(LoadBalancer).\
|
||||||
|
filter(LoadBalancer.tenantid == tenant_id).count()
|
||||||
|
|
||||||
|
# TODO: this should probably be a 413, not sure how to do that yet
|
||||||
|
if count >= lblimit:
|
||||||
|
raise ClientSideError(
|
||||||
|
'Account has hit limit of {0} Load Balancers'.
|
||||||
|
format(lblimit)
|
||||||
|
)
|
||||||
|
if len(body.nodes) > nodelimit:
|
||||||
|
raise ClientSideError(
|
||||||
|
'Too many backend nodes supplied (limit is {0}'.
|
||||||
|
format(nodelimit)
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: check if tenant is overlimit (return a 413 for that)
|
|
||||||
# TODO: check if we have been supplied with too many nodes
|
|
||||||
device = None
|
device = None
|
||||||
old_lb = None
|
old_lb = None
|
||||||
# if we don't have an id then we want to create a new lb
|
# if we don't have an id then we want to create a new lb
|
||||||
@ -203,22 +215,39 @@ class LoadBalancersController(RestController):
|
|||||||
filter(Device.id == virtual_id).\
|
filter(Device.id == virtual_id).\
|
||||||
first()
|
first()
|
||||||
if old_lb is None:
|
if old_lb is None:
|
||||||
response.status = 400
|
raise InvalidInput(
|
||||||
return Responses.service_unavailable
|
'virtualIps', virtual_id, 'Invalid virtual IP provided'
|
||||||
if old_lb.protocol == 'HTTP' and (
|
)
|
||||||
body.protocol is None or body.protocol == 'HTTP'
|
|
||||||
):
|
if body.protocol == Unset or body.protocol.lower() == 'HTTP':
|
||||||
|
old_count = session.query(
|
||||||
|
LoadBalancer
|
||||||
|
).join(LoadBalancer.devices).\
|
||||||
|
filter(LoadBalancer.tenantid == tenant_id).\
|
||||||
|
filter(Device.id == virtual_id).\
|
||||||
|
filter(LoadBalancer.protocol == 'HTTP').\
|
||||||
|
count()
|
||||||
|
if old_count:
|
||||||
# Error here, can have only one HTTP
|
# Error here, can have only one HTTP
|
||||||
response.status = 400
|
raise ClientSideError(
|
||||||
return Responses.service_unavailable
|
'Only one HTTP load balancer allowed per device'
|
||||||
elif old_lb.protocol == 'TCP' and body.protocol == 'TCP':
|
)
|
||||||
|
elif body.protocol.lower() == 'TCP':
|
||||||
|
old_count = session.query(
|
||||||
|
LoadBalancer
|
||||||
|
).join(LoadBalancer.devices).\
|
||||||
|
filter(LoadBalancer.tenantid == tenant_id).\
|
||||||
|
filter(Device.id == virtual_id).\
|
||||||
|
filter(LoadBalancer.protocol == 'TCP').\
|
||||||
|
count()
|
||||||
|
if old_count:
|
||||||
# Error here, can have only one TCP
|
# Error here, can have only one TCP
|
||||||
response.status = 400
|
raise ClientSideError(
|
||||||
return Responses.service_unavailable
|
'Only one TCP load balancer allowed per device'
|
||||||
|
)
|
||||||
|
|
||||||
if device is None:
|
if device is None:
|
||||||
response.status = 503
|
raise RuntimeError('No devices available')
|
||||||
return Responses.service_unavailable
|
|
||||||
|
|
||||||
lb.tenantid = tenant_id
|
lb.tenantid = tenant_id
|
||||||
lb.name = body.name
|
lb.name = body.name
|
||||||
@ -265,7 +294,6 @@ class LoadBalancersController(RestController):
|
|||||||
device.status = "ONLINE"
|
device.status = "ONLINE"
|
||||||
|
|
||||||
session.flush()
|
session.flush()
|
||||||
# TODO: write nodes to table too
|
|
||||||
|
|
||||||
job_data = {
|
job_data = {
|
||||||
'hpcs_action': 'UPDATE',
|
'hpcs_action': 'UPDATE',
|
||||||
@ -356,6 +384,8 @@ class LoadBalancersController(RestController):
|
|||||||
|
|
||||||
Returns: None
|
Returns: None
|
||||||
"""
|
"""
|
||||||
|
# TODO: send gearman message (use PENDING_DELETE), make it an update
|
||||||
|
# message when more than one device per LB
|
||||||
tenant_id = get_limited_to_project(request.headers)
|
tenant_id = get_limited_to_project(request.headers)
|
||||||
# grab the lb
|
# grab the lb
|
||||||
lb = session.query(LoadBalancer).\
|
lb = session.query(LoadBalancer).\
|
||||||
@ -364,8 +394,10 @@ class LoadBalancersController(RestController):
|
|||||||
|
|
||||||
if lb is None:
|
if lb is None:
|
||||||
response.status = 400
|
response.status = 400
|
||||||
return Responses.not_found
|
return dict(
|
||||||
|
faultcode="Client",
|
||||||
|
faultstring="Load Balancer ID is not valid"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
session.query(Node).filter(Node.lbid == load_balancer_id).delete()
|
session.query(Node).filter(Node.lbid == load_balancer_id).delete()
|
||||||
lb.status = 'DELETED'
|
lb.status = 'DELETED'
|
||||||
@ -377,21 +409,25 @@ class LoadBalancersController(RestController):
|
|||||||
session.execute(loadbalancers_devices.delete().where(
|
session.execute(loadbalancers_devices.delete().where(
|
||||||
loadbalancers_devices.c.loadbalancer == load_balancer_id
|
loadbalancers_devices.c.loadbalancer == load_balancer_id
|
||||||
))
|
))
|
||||||
|
if device:
|
||||||
device.status = 'OFFLINE'
|
device.status = 'OFFLINE'
|
||||||
session.flush()
|
session.flush()
|
||||||
# trigger gearman client to create new lb
|
# trigger gearman client to create new lb
|
||||||
#result = gearman_client.submit_job('DELETE', lb.output_to_json())
|
#result = gearman_client.submit_job('DELETE', lb.output_to_json())
|
||||||
|
|
||||||
response.status = 200
|
response.status = 202
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
return self.get()
|
return None
|
||||||
except:
|
except:
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.exception('Error communicating with load balancer pool')
|
logger.exception('Error communicating with load balancer pool')
|
||||||
response.status = 503
|
response.status = 500
|
||||||
return Responses.service_unavailable
|
return dict(
|
||||||
|
faultcode="Server",
|
||||||
|
faultstring="Error communication with load balancer pool"
|
||||||
|
)
|
||||||
|
|
||||||
def virtualips(self, load_balancer_id):
|
def virtualips(self, load_balancer_id):
|
||||||
"""Returns a list of virtual ips attached to a specific Load Balancer.
|
"""Returns a list of virtual ips attached to a specific Load Balancer.
|
||||||
@ -403,7 +439,35 @@ class LoadBalancersController(RestController):
|
|||||||
|
|
||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
return Responses.LoadBalancers.virtualips
|
tenant_id = get_limited_to_project(request.headers)
|
||||||
|
if not load_balancer_id:
|
||||||
|
response.status = 400
|
||||||
|
return dict(
|
||||||
|
faultcode="Client",
|
||||||
|
faultstring="Load Balancer ID not provided"
|
||||||
|
)
|
||||||
|
device = session.query(
|
||||||
|
Device.id, Device.floatingIpAddr
|
||||||
|
).join(LoadBalancer.devices).\
|
||||||
|
filter(LoadBalancer.id == load_balancer_id).\
|
||||||
|
filter(LoadBalancer.tenantid == tenant_id).first()
|
||||||
|
|
||||||
|
if not device:
|
||||||
|
response.status = 400
|
||||||
|
return dict(
|
||||||
|
faultcode="Client",
|
||||||
|
faultstring="Load Balancer ID not valid"
|
||||||
|
)
|
||||||
|
resp = {
|
||||||
|
"virtualIps": [{
|
||||||
|
"id": device.id,
|
||||||
|
"address": device.floatingIpAddr,
|
||||||
|
"type": "PUBLIC",
|
||||||
|
"ipVersion": "IPV4"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
def usage(self, load_balancer_id):
|
def usage(self, load_balancer_id):
|
||||||
"""List current and historical usage.
|
"""List current and historical usage.
|
||||||
@ -416,7 +480,7 @@ class LoadBalancersController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.usage
|
return None
|
||||||
|
|
||||||
@expose('json')
|
@expose('json')
|
||||||
def _lookup(self, primary_key, *remainder):
|
def _lookup(self, primary_key, *remainder):
|
||||||
|
@ -17,7 +17,6 @@ from pecan import expose, response, request
|
|||||||
from pecan.rest import RestController
|
from pecan.rest import RestController
|
||||||
#default response objects
|
#default response objects
|
||||||
from libra.api.model.lbaas import LoadBalancer, Node, session
|
from libra.api.model.lbaas import LoadBalancer, Node, session
|
||||||
from libra.api.model.responses import Responses
|
|
||||||
from libra.api.acl import get_limited_to_project
|
from libra.api.acl import get_limited_to_project
|
||||||
|
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ class NodesController(RestController):
|
|||||||
node
|
node
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.Nodes.get
|
return None
|
||||||
|
|
||||||
@expose()
|
@expose()
|
||||||
def delete(self, load_balancer_id, node_id):
|
def delete(self, load_balancer_id, node_id):
|
||||||
|
@ -13,9 +13,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from pecan import expose, response
|
from pecan import response
|
||||||
from pecan.rest import RestController
|
from pecan.rest import RestController
|
||||||
from libra.api.model.responses import Responses
|
|
||||||
|
|
||||||
|
|
||||||
class SessionPersistenceController(RestController):
|
class SessionPersistenceController(RestController):
|
||||||
@ -23,7 +22,6 @@ class SessionPersistenceController(RestController):
|
|||||||
functions for /loadbalancers/{loadBalancerId}/sessionpersistence/* routing
|
functions for /loadbalancers/{loadBalancerId}/sessionpersistence/* routing
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@expose('json')
|
|
||||||
def get(self, load_balancer_id):
|
def get(self, load_balancer_id):
|
||||||
"""List session persistence configuration.get
|
"""List session persistence configuration.get
|
||||||
|
|
||||||
@ -35,9 +33,8 @@ class SessionPersistenceController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.SessionPersistence.get
|
return None
|
||||||
|
|
||||||
@expose('json')
|
|
||||||
def post(self, load_balancer_id):
|
def post(self, load_balancer_id):
|
||||||
"""Enable session persistence.
|
"""Enable session persistence.
|
||||||
|
|
||||||
@ -49,9 +46,8 @@ class SessionPersistenceController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
response.status = 201
|
response.status = 201
|
||||||
return Responses.LoadBalancers.SessionPersistence.get
|
return None
|
||||||
|
|
||||||
@expose('json')
|
|
||||||
def delete(self, load_balancer_id):
|
def delete(self, load_balancer_id):
|
||||||
"""Disable session persistence.
|
"""Disable session persistence.
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
from pecan import expose, response
|
from pecan import expose, response
|
||||||
from load_balancers import LoadBalancersController
|
from load_balancers import LoadBalancersController
|
||||||
|
from limits import LimitsController
|
||||||
from libra.api.model.responses import Responses
|
from libra.api.model.responses import Responses
|
||||||
|
|
||||||
|
|
||||||
@ -52,3 +53,4 @@ class V1Controller(object):
|
|||||||
|
|
||||||
#pecan uses this controller class for urls that start with /loadbalancers
|
#pecan uses this controller class for urls that start with /loadbalancers
|
||||||
loadbalancers = LoadBalancersController()
|
loadbalancers = LoadBalancersController()
|
||||||
|
limits = LimitsController()
|
||||||
|
@ -50,6 +50,13 @@ class FormatedDateTime(types.TypeDecorator):
|
|||||||
return value.strftime('%Y-%m-%dT%H:%M:%S')
|
return value.strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
|
|
||||||
|
|
||||||
|
class Limits(DeclarativeBase):
|
||||||
|
__tablename__ = 'global_limits'
|
||||||
|
id = Column(u'id', Integer, primary_key=True, nullable=False)
|
||||||
|
name = Column(u'name', VARCHAR(length=128), nullable=False)
|
||||||
|
value = Column(u'value', BIGINT(), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class Device(DeclarativeBase):
|
class Device(DeclarativeBase):
|
||||||
"""device model"""
|
"""device model"""
|
||||||
__tablename__ = 'devices'
|
__tablename__ = 'devices'
|
||||||
|
@ -88,243 +88,3 @@ class Responses(object):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""class LoadBalancers
|
|
||||||
grouping of lb responses
|
|
||||||
"""
|
|
||||||
|
|
||||||
class LoadBalancers(object):
|
|
||||||
"""LoadBalancers list"""
|
|
||||||
get = {
|
|
||||||
'loadBalancers': [
|
|
||||||
{
|
|
||||||
'name': 'lb-site1',
|
|
||||||
'id': '71',
|
|
||||||
'protocol': 'HTTP',
|
|
||||||
'port': '80',
|
|
||||||
'algorithm': 'LEAST_CONNECTIONS',
|
|
||||||
'status': 'ACTIVE',
|
|
||||||
'created': '2010-11-30T03:23:42Z',
|
|
||||||
'updated': '2010-11-30T03:23:44Z'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'lb-site2',
|
|
||||||
'id': '166',
|
|
||||||
'protocol': 'TCP',
|
|
||||||
'port': '9123',
|
|
||||||
'algorithm': 'ROUND_ROBIN',
|
|
||||||
'status': 'ACTIVE',
|
|
||||||
'created': '2010-11-30T03:23:42Z',
|
|
||||||
'updated': '2010-11-30T03:23:44Z'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
"""loadbalancer details"""
|
|
||||||
detail = {
|
|
||||||
'id': '2000',
|
|
||||||
'name': 'sample-loadbalancer',
|
|
||||||
'protocol': 'HTTP',
|
|
||||||
'port': '80',
|
|
||||||
'algorithm': 'ROUND_ROBIN',
|
|
||||||
'status': 'ACTIVE',
|
|
||||||
'created': '2010-11-30T03:23:42Z',
|
|
||||||
'updated': '2010-11-30T03:23:44Z',
|
|
||||||
'virtualIps': [
|
|
||||||
{
|
|
||||||
'id': '1000',
|
|
||||||
'address': '2001:cdba:0000:0000:0000:0000:3257:9652',
|
|
||||||
'type': 'PUBLIC',
|
|
||||||
'ipVersion': 'IPV6'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'nodes': [
|
|
||||||
{
|
|
||||||
'id': '1041',
|
|
||||||
'address': '10.1.1.1',
|
|
||||||
'port': '80',
|
|
||||||
'condition': 'ENABLED',
|
|
||||||
'status': 'ONLINE'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': '1411',
|
|
||||||
'address': '10.1.1.2',
|
|
||||||
'port': '80',
|
|
||||||
'condition': 'ENABLED',
|
|
||||||
'status': 'ONLINE'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'sessionPersistence': {
|
|
||||||
'persistenceType': 'HTTP_COOKIE'
|
|
||||||
},
|
|
||||||
'connectionThrottle': {
|
|
||||||
'maxRequestRate': '50',
|
|
||||||
'rateInterval': '60'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"""create loadbalancer response"""
|
|
||||||
post = {
|
|
||||||
'name': 'a-new-loadbalancer',
|
|
||||||
'id': '144',
|
|
||||||
'protocol': 'HTTP',
|
|
||||||
'port': '83',
|
|
||||||
'algorithm': 'ROUND_ROBIN',
|
|
||||||
'status': 'BUILD',
|
|
||||||
'created': '2011-04-13T14:18:07Z',
|
|
||||||
'updated': '2011-04-13T14:18:07Z',
|
|
||||||
'virtualIps': [
|
|
||||||
{
|
|
||||||
'address': '3ffe:1900:4545:3:200:f8ff:fe21:67cf',
|
|
||||||
'id': '39',
|
|
||||||
'type': 'PUBLIC',
|
|
||||||
'ipVersion': 'IPV6'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'nodes': [
|
|
||||||
{
|
|
||||||
'address': '10.1.1.1',
|
|
||||||
'id': '653',
|
|
||||||
'port': '80',
|
|
||||||
'status': 'ONLINE',
|
|
||||||
'condition': 'ENABLED'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
"""virtualips"""
|
|
||||||
virtualips = {
|
|
||||||
'virtualIps': [
|
|
||||||
{
|
|
||||||
'id': '1021',
|
|
||||||
'address': '206.10.10.210',
|
|
||||||
'type': 'PUBLIC',
|
|
||||||
'ipVersion': 'IPV4'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
"""usage"""
|
|
||||||
usage = {
|
|
||||||
'loadBalancerUsageRecords': [
|
|
||||||
{
|
|
||||||
'id': '394',
|
|
||||||
'transferBytesIn': '2819204',
|
|
||||||
'transferBytesOut': '84923069'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': '473',
|
|
||||||
'transferBytesIn': '0',
|
|
||||||
'transferBytesOut': '0'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
"""class HealthMonitor
|
|
||||||
monitor responses
|
|
||||||
"""
|
|
||||||
|
|
||||||
class HealthMonitor(object):
|
|
||||||
"""monitor CONNECT response"""
|
|
||||||
get = {
|
|
||||||
'type': 'CONNECT',
|
|
||||||
'delay': '20',
|
|
||||||
'timeout': '10',
|
|
||||||
'attemptsBeforeDeactivation': '3'
|
|
||||||
}
|
|
||||||
"""monitor HTTPS response"""
|
|
||||||
get_https = {
|
|
||||||
'type': 'HTTPS',
|
|
||||||
'delay': '10',
|
|
||||||
'timeout': '3',
|
|
||||||
'attemptsBeforeDeactivation': '3',
|
|
||||||
'path': '/healthcheck'
|
|
||||||
}
|
|
||||||
"""class SessionPersistence
|
|
||||||
for managing Session Persistance
|
|
||||||
"""
|
|
||||||
|
|
||||||
class SessionPersistence(object):
|
|
||||||
"""get"""
|
|
||||||
get = {
|
|
||||||
'persistenceType': 'HTTP_COOKIE'
|
|
||||||
}
|
|
||||||
"""class Connections
|
|
||||||
Throttle Connections responses
|
|
||||||
"""
|
|
||||||
|
|
||||||
class ConnectionThrottle(object):
|
|
||||||
"""get"""
|
|
||||||
get = {
|
|
||||||
'maxRequestRate': '50',
|
|
||||||
'rateInterval': '60'
|
|
||||||
}
|
|
||||||
|
|
||||||
"""class Nodes
|
|
||||||
grouping of node related responses
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Nodes(object):
|
|
||||||
"""list of nodes of a specific lb"""
|
|
||||||
get = {
|
|
||||||
'nodes': [
|
|
||||||
{
|
|
||||||
'id': '410',
|
|
||||||
'address': '10.1.1.1',
|
|
||||||
'port': '80',
|
|
||||||
'condition': 'ENABLED',
|
|
||||||
'status': 'ONLINE'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': '236',
|
|
||||||
'address': '10.1.1.2',
|
|
||||||
'port': '80',
|
|
||||||
'condition': 'ENABLED',
|
|
||||||
'status': 'ONLINE'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': '2815',
|
|
||||||
'address': '10.1.1.3',
|
|
||||||
'port': '83',
|
|
||||||
'condition': 'DISABLED',
|
|
||||||
'status': 'OFFLINE'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
"""a specific node details"""
|
|
||||||
get_detail = {
|
|
||||||
'id': '236',
|
|
||||||
'address': '10.1.1.2',
|
|
||||||
'port': '80',
|
|
||||||
'condition': 'ENABLED',
|
|
||||||
'status': 'ONLINE'
|
|
||||||
}
|
|
||||||
|
|
||||||
"""nodes create response"""
|
|
||||||
post = {
|
|
||||||
'nodes': [
|
|
||||||
{
|
|
||||||
'id': '7298',
|
|
||||||
'address': '10.1.1.1',
|
|
||||||
'port': '80',
|
|
||||||
'condition': 'ENABLED',
|
|
||||||
'status': 'ONLINE'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': '293',
|
|
||||||
'address': '10.2.2.1',
|
|
||||||
'port': '80',
|
|
||||||
'weight': '2',
|
|
||||||
'condition': 'ENABLED',
|
|
||||||
'status': 'OFFLINE'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': '183',
|
|
||||||
'address': '10.2.2.4',
|
|
||||||
'port': '88',
|
|
||||||
'weight': '2',
|
|
||||||
'condition': 'DISABLED',
|
|
||||||
'status': 'OFFLINE'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user