[API] Completed TCP Timeout work

Change-Id: Ie512dc5758609d0d0601f448984846b124647e24
This commit is contained in:
Marc Pilon 2014-02-24 12:44:10 -05:00
parent 6aabea4b51
commit f50921e25e
5 changed files with 144 additions and 47 deletions

View File

@ -32,7 +32,7 @@ from libra.common.api.lbaas import loadbalancers_devices, Limits, Vip, Ports
from libra.common.api.lbaas import HealthMonitor
from libra.common.exc import ExhaustedError
from libra.api.model.validators import LBPut, LBPost, LBResp, LBVipResp
from libra.api.model.validators import LBRespNode
from libra.api.model.validators import LBRespNode, LBOptions
from libra.common.api.gearman_client import submit_job
from libra.api.acl import get_limited_to_project
from libra.api.library.exp import OverLimit, IPOutOfRange, NotFound
@ -44,6 +44,12 @@ from wsme import types as wtypes
class LoadBalancersController(RestController):
LB_TIMEOUT_MS = 30000
LB_TIMEOUT_MAX = 1000000
LB_RETRIES = 3
LB_RETRIES_MAX = 256
def __init__(self, lbid=None):
self.lbid = lbid
@ -77,7 +83,8 @@ class LoadBalancersController(RestController):
LoadBalancer.protocol,
LoadBalancer.port, LoadBalancer.algorithm,
LoadBalancer.status, LoadBalancer.created,
LoadBalancer.updated
LoadBalancer.updated, LoadBalancer.timeout,
LoadBalancer.retries
).filter(LoadBalancer.tenantid == tenant_id).\
filter(LoadBalancer.status == 'DELETED').all()
else:
@ -86,7 +93,8 @@ class LoadBalancersController(RestController):
LoadBalancer.protocol,
LoadBalancer.port, LoadBalancer.algorithm,
LoadBalancer.status, LoadBalancer.created,
LoadBalancer.updated
LoadBalancer.updated, LoadBalancer.timeout,
LoadBalancer.retries
).filter(LoadBalancer.tenantid == tenant_id).\
filter(LoadBalancer.status != 'DELETED').all()
load_balancers = {'loadBalancers': []}
@ -96,6 +104,20 @@ class LoadBalancersController(RestController):
lb['nodeCount'] = session.query(Node).\
filter(Node.lbid == lb['id']).count()
lb['id'] = str(lb['id'])
# Unset options get set to default values
lb['options'] = {}
if lb['timeout']:
lb['options']['timeout'] = lb['timeout']
else:
lb['options']['timeout'] = self.LB_TIMEOUT_MS
if lb['retries']:
lb['options']['retries'] = lb['retries']
else:
lb['options']['retries'] = self.LB_RETRIES
del(lb['timeout'])
del(lb['retries'])
load_balancers['loadBalancers'].append(lb)
else:
load_balancers = session.query(
@ -103,6 +125,7 @@ class LoadBalancersController(RestController):
LoadBalancer.port, LoadBalancer.algorithm,
LoadBalancer.status, LoadBalancer.created,
LoadBalancer.updated, LoadBalancer.errmsg,
LoadBalancer.timeout, LoadBalancer.retries,
Vip.id.label('vipid'), Vip.ip
).join(LoadBalancer.devices).\
outerjoin(Device.vip).\
@ -168,6 +191,21 @@ class LoadBalancersController(RestController):
del node['weight']
load_balancers['nodes'].append(node)
# Unset options get set to default values
load_balancers['options'] = {}
if load_balancers['timeout']:
load_balancers['options']['timeout'] =\
load_balancers['timeout']
else:
load_balancers['options']['timeout'] = self.LB_TIMEOUT_MS
if load_balancers['retries']:
load_balancers['options']['retries'] =\
load_balancers['retries']
else:
load_balancers['options']['retries'] = self.LB_RETRIES
del(load_balancers['timeout'])
del(load_balancers['retries'])
session.rollback()
response.status = 200
return load_balancers
@ -252,19 +290,33 @@ class LoadBalancersController(RestController):
num_galera_primary_nodes += 1
# Options defaults
client_timeout_ms = 30000
server_timeout_ms = 30000
connect_timeout_ms = 30000
connect_retries = 3
timeout_ms = self.LB_TIMEOUT_MS
retries = self.LB_RETRIES
if body.options:
if body.options.client_timeout != Unset:
client_timeout_ms = body.options.client_timeout
if body.options.server_timeout != Unset:
server_timeout_ms = body.options.server_timeout
if body.options.connect_timeout != Unset:
connect_timeout_ms = body.options.connect_timeout
if body.options.connect_retries != Unset:
connect_retries = body.options.connect_retries
if body.options.timeout != Unset:
try:
timeout_ms = int(body.options.timeout)
if timeout_ms < 0 or timeout_ms > self.LB_TIMEOUT_MAX:
raise ClientSideError(
'timeout must be between 0 and {0} ms'
.format(self.LB_TIMEOUT_MAX)
)
except ValueError:
raise ClientSideError(
'timeout must be an integer'
)
if body.options.retries != Unset:
try:
retries = int(body.options.retries)
if retries < 0 or retries > self.LB_RETRIES_MAX:
raise ClientSideError(
'retries must be between 0 and {0}'
.format(self.LB_RETRIES_MAX)
)
except ValueError:
raise ClientSideError(
'retries must be an integer'
)
# Galera sanity checks
if is_galera and num_galera_primary_nodes != 1:
@ -431,10 +483,8 @@ class LoadBalancersController(RestController):
else:
lb.algorithm = 'ROUND_ROBIN'
lb.client_timeout = client_timeout_ms
lb.server_timeout = server_timeout_ms
lb.connect_timeout = connect_timeout_ms
lb.connect_retries = connect_retries
lb.timeout = timeout_ms
lb.retries = retries
lb.devices = [device]
# write to database
@ -491,20 +541,42 @@ class LoadBalancersController(RestController):
address=None, id=None, type='ASSIGNING', ipVersion='IPV4'
)
return_data.virtualIps = [vip_resp]
nodes = session.query(
Node.id, Node.address, Node.port, Node.status,
Node.enabled, Node.weight
).join(LoadBalancer.nodes).\
filter(LoadBalancer.tenantid == tenant_id).\
filter(LoadBalancer.id == lb.id).\
all()
return_data.nodes = []
for node in body.nodes:
if node.weight != Unset and node.weight != 1:
out_node = LBRespNode(
port=str(node.port), address=node.address,
condition=node.condition, weight=weight
for node in nodes:
if node.enabled == 1:
condition = 'ENABLED'
else:
condition = 'DISABLED'
if node.weight == 1:
return_data.nodes.append(
LBRespNode(
id=str(node.id), port=str(node.port),
address=node.address, condition=condition,
status=node.status
)
)
else:
out_node = LBRespNode(
port=str(node.port), address=node.address,
condition=node.condition
return_data.nodes.append(
LBRespNode(
id=str(node.id), port=str(node.port),
address=node.address, condition=condition,
status=node.status, weight=str(node.weight)
)
)
return_data.nodes.append(out_node)
return_data.options = LBOptions(timeout=timeout_ms,
retries=retries)
session.commit()
# trigger gearman client to create new lb
submit_job(
@ -551,6 +623,34 @@ class LoadBalancersController(RestController):
if body.algorithm != Unset:
lb.algorithm = body.algorithm
if body.options:
if body.options.timeout != Unset:
try:
timeout_ms = int(body.options.timeout)
if timeout_ms < 0 or timeout_ms > self.LB_TIMEOUT_MAX:
raise ClientSideError(
'timeout must be between 0 and {0} ms'
.format(self.LB_TIMEOUT_MAX)
)
lb.timeout = timeout_ms
except ValueError:
raise ClientSideError(
'timeout must be an integer'
)
if body.options.retries != Unset:
try:
retries = int(body.options.retries)
if retries < 0 or retries > self.LB_RETRIES_MAX:
raise ClientSideError(
'retries must be between 0 and {0}'
.format(self.LB_RETRIES_MAX)
)
lb.retries = retries
except ValueError:
raise ClientSideError(
'retries must be an integer'
)
lb.status = 'PENDING_UPDATE'
device = session.query(
Device.id, Device.name, Device.status

View File

@ -27,10 +27,12 @@ class LBNode(Base):
class LBRespNode(Base):
id = wtypes.text
port = wtypes.text
address = wtypes.text
condition = wtypes.text
weight = int
status = wtypes.text
weight = wtypes.text
class LBNodePut(Base):
@ -60,10 +62,8 @@ class LBVip(Base):
class LBOptions(Base):
client_timeout = int
server_timeout = int
connect_timeout = int
connect_retries = int
timeout = int
retries = int
class LBPost(Base):
@ -79,6 +79,7 @@ class LBPost(Base):
class LBPut(Base):
name = wtypes.text
algorithm = Enum(wtypes.text, 'ROUND_ROBIN', 'LEAST_CONNECTIONS')
options = wsattr('LBOptions')
class LBVipResp(Base):
@ -106,6 +107,7 @@ class LBResp(Base):
updated = wtypes.text
virtualIps = wsattr(['LBVipResp'])
nodes = wsattr(['LBRespNode'])
options = wsattr('LBOptions')
class LBMonitorPut(Base):

View File

@ -443,13 +443,12 @@ class GearmanClientThread(object):
# All new LBs created since these options were supported
# will have default values in the DB. Pre-existing LBs will
# not have any values, so we need to check for that.
if any([lb.client_timeout, lb.server_timeout,
lb.connect_timeout, lb.connect_retries]):
if any([lb.timeout, lb.retries]):
lb_data['options'] = {
'client_timeout': lb.client_timeout,
'server_timeout': lb.server_timeout,
'connect_timeout': lb.connect_timeout,
'connect_retries': lb.connect_retries
'client_timeout': lb.timeout,
'server_timeout': lb.timeout,
'connect_timeout': lb.timeout,
'connect_retries': lb.retries
}
lb_data['monitor'] = monitor_data

View File

@ -111,10 +111,8 @@ class LoadBalancer(DeclarativeBase):
tenantid = Column(u'tenantid', VARCHAR(length=128), nullable=False)
updated = Column(u'updated', FormatedDateTime(), nullable=False)
created = Column(u'created', FormatedDateTime(), nullable=False)
client_timeout = Column(u'client_timeout', INTEGER(), nullable=True)
server_timeout = Column(u'server_timeout', INTEGER(), nullable=True)
connect_timeout = Column(u'connect_timeout', INTEGER(), nullable=True)
connect_retries = Column(u'connect_retries', INTEGER(), nullable=True)
timeout = Column(u'timeout', INTEGER(), nullable=True)
retries = Column(u'retries', INTEGER(), nullable=True)
nodes = relationship(
'Node', backref=backref('loadbalancers', order_by='Node.id')
)

View File

@ -26,10 +26,8 @@ CREATE TABLE loadbalancers (
created TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', # timestamp of when LB was created
updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, # timestamp of when LB was last updated
errmsg VARCHAR(128) DEFAULT NULL, # optional error message which can describe details regarding LBs state, can be blank if no error state exists
client_timeout INT,
server_timeout INT,
connect_timeout INT,
connect_retries INT,
timeout INT,
retries INT,
PRIMARY KEY (id) # ids are unique accross all LBs
) DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;