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

View File

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

View File

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

View File

@@ -111,10 +111,8 @@ class LoadBalancer(DeclarativeBase):
tenantid = Column(u'tenantid', VARCHAR(length=128), nullable=False) tenantid = Column(u'tenantid', VARCHAR(length=128), nullable=False)
updated = Column(u'updated', FormatedDateTime(), nullable=False) updated = Column(u'updated', FormatedDateTime(), nullable=False)
created = Column(u'created', FormatedDateTime(), nullable=False) created = Column(u'created', FormatedDateTime(), nullable=False)
client_timeout = Column(u'client_timeout', INTEGER(), nullable=True) timeout = Column(u'timeout', INTEGER(), nullable=True)
server_timeout = Column(u'server_timeout', INTEGER(), nullable=True) retries = Column(u'retries', INTEGER(), nullable=True)
connect_timeout = Column(u'connect_timeout', INTEGER(), nullable=True)
connect_retries = Column(u'connect_retries', INTEGER(), nullable=True)
nodes = relationship( nodes = relationship(
'Node', backref=backref('loadbalancers', order_by='Node.id') '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 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 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 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, timeout INT,
server_timeout INT, retries INT,
connect_timeout INT,
connect_retries INT,
PRIMARY KEY (id) # ids are unique accross all LBs PRIMARY KEY (id) # ids are unique accross all LBs
) DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci; ) DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;