Random Service port in a specific range.

Now the conductor get a random port for the service in a range of unused ports

Change-Id: Ifa51cc8d7a0459d46a72ea1c285b717932bbc94c
This commit is contained in:
Fabio Verboso 2020-03-02 15:01:04 +01:00
parent d407504102
commit c389793692
7 changed files with 68 additions and 10 deletions

View File

@ -15,6 +15,10 @@ auth_strategy=keystone
# value) # value)
#pecan_debug=false #pecan_debug=false
[conductor]
service_port_min=50000
service_port_max=60000
[wamp] [wamp]
wamp_transport_url = ws://<host>:<port>/ wamp_transport_url = ws://<host>:<port>/

View File

@ -616,6 +616,10 @@ class ServiceAlreadyExposed(Conflict):
message = _("A Service with UUID %(uuid)s already exposed.") message = _("A Service with UUID %(uuid)s already exposed.")
class NotEnoughPortForService(NotFound):
message = _("No ports available")
class ExposedServiceNotFound(NotFound): class ExposedServiceNotFound(NotFound):
message = _("ExposedService %(uuid)s could not be found.") message = _("ExposedService %(uuid)s could not be found.")

View File

@ -43,6 +43,8 @@ serializer = objects_base.IotronicObjectSerializer()
Port = list() Port = list()
SERVICE_PORT_LIST = None
def versionCompare(v1, v2): def versionCompare(v1, v2):
"""Method to compare two versions. """Method to compare two versions.
@ -104,8 +106,24 @@ def get_best_agent(ctx):
return agent.hostname return agent.hostname
def random_public_port(): def random_public_port(ctx=None):
return random.randint(50001, 59999) global SERVICE_PORT_LIST
if not SERVICE_PORT_LIST:
# empty, create a cache list
min = cfg.CONF.conductor.service_port_min + 1
max = cfg.CONF.conductor.service_port_max - 1
LOG.debug('recreate service port list cache: min %i max %i', min, max)
full_list = (range(min, max))
exp_list = objects.ExposedService.get_all_ports(ctx)
SERVICE_PORT_LIST = list(set(full_list) - set(exp_list))
if len(SERVICE_PORT_LIST) == 0:
LOG.warning('No more ports available')
return None
else:
num = random.choice(SERVICE_PORT_LIST)
SERVICE_PORT_LIST.remove(num)
return num
def manage_result(res, wamp_rpc_call, board_uuid): def manage_result(res, wamp_rpc_call, board_uuid):
@ -477,6 +495,9 @@ class ConductorEndpoint(object):
except Exception: except Exception:
public_port = random_public_port() public_port = random_public_port()
if not public_port:
return exception.NotEnoughPortForService()
res = self.execute_on_board(ctx, board_uuid, action, res = self.execute_on_board(ctx, board_uuid, action,
(service, public_port)) (service, public_port))
result = manage_result(res, action, board_uuid) result = manage_result(res, action, board_uuid)
@ -504,6 +525,11 @@ class ConductorEndpoint(object):
result = manage_result(res, action, board_uuid) result = manage_result(res, action, board_uuid)
LOG.debug(res.message) LOG.debug(res.message)
global SERVICE_PORT_LIST
try:
SERVICE_PORT_LIST.append(exposed.public_port)
except exception:
pass
exposed.destroy() exposed.destroy()
return result return result
@ -799,9 +825,10 @@ class ConductorEndpoint(object):
except Exception: except Exception:
# TO BE CHANGED
https_port = random_public_port() https_port = random_public_port()
http_port = random_public_port() http_port = random_public_port()
if not https_port or not http_port:
return exception.NotEnoughPortForService()
en_webservice = { en_webservice = {
'board_uuid': board.uuid, 'board_uuid': board.uuid,
@ -918,6 +945,11 @@ class ConductorEndpoint(object):
res = self.execute_on_board(ctx, board.uuid, "ServiceDisable", res = self.execute_on_board(ctx, board.uuid, "ServiceDisable",
(service,), main_req=mreq.uuid) (service,), main_req=mreq.uuid)
LOG.debug(res.message) LOG.debug(res.message)
global SERVICE_PORT_LIST
try:
SERVICE_PORT_LIST.append(exposed.public_port)
except exception:
pass
exposed.destroy() exposed.destroy()
try: try:

View File

@ -40,6 +40,12 @@ conductor_opts = [
help='Maximum time (in seconds) since the last check-in ' help='Maximum time (in seconds) since the last check-in '
'of a conductor. A conductor is considered inactive ' 'of a conductor. A conductor is considered inactive '
'when this time has been exceeded.'), 'when this time has been exceeded.'),
cfg.IntOpt('service_port_min',
default=50000,
help='Min value for genereting random ports for services'),
cfg.IntOpt('service_port_max',
default=60000,
help='Max value for genereting random ports for services'),
] ]
CONF = cfg.CONF CONF = cfg.CONF

View File

@ -911,9 +911,13 @@ class Connection(api.Connection):
raise exception.ExposedServiceNotFound() raise exception.ExposedServiceNotFound()
def get_exposed_service_list(self, board_uuid): def get_exposed_service_list(self, board_uuid):
if board_uuid:
query = model_query( query = model_query(
models.ExposedService).filter_by( models.ExposedService).filter_by(
board_uuid=board_uuid) board_uuid=board_uuid)
else:
query = model_query(
models.ExposedService)
return query.all() return query.all()
def _do_update_exposed_service(self, service_id, values): def _do_update_exposed_service(self, service_id, values):

View File

@ -31,6 +31,14 @@ class ExposedService(base.IotronicObject):
'public_port': int 'public_port': int
} }
@base.remotable_classmethod
def get_all_ports(cls, context):
ls = cls.list(context)
ports = []
for x in ls:
ports.append(x.public_port)
return ports
@staticmethod @staticmethod
def _from_db_object(exposed_service, db_exposed_service): def _from_db_object(exposed_service, db_exposed_service):
"""Converts a database entity to a formal object.""" """Converts a database entity to a formal object."""
@ -96,7 +104,7 @@ class ExposedService(base.IotronicObject):
return exp_service return exp_service
@base.remotable_classmethod @base.remotable_classmethod
def list(cls, context, board_uuid): def list(cls, context, board_uuid=None):
"""Return a list of ExposedService objects. """Return a list of ExposedService objects.
:param context: Security context. :param context: Security context.

View File

@ -1,6 +1,6 @@
[tox] [tox]
minversion = 2.3.1 minversion = 2.3.1
envlist = py3,pep8 envlist = py35,pep8
skipsdist = True skipsdist = True
[testenv] [testenv]
@ -22,8 +22,8 @@ commands =
basepython = python2.7 basepython = python2.7
commands = flake8 {posargs} commands = flake8 {posargs}
[testenv:py3] [testenv:py35]
basepython = python3 basepython = python3.5
[flake8] [flake8]