From 0d1ae6110d1821a4081f656bbbaf699e99108b4e Mon Sep 17 00:00:00 2001 From: Fabio Verboso Date: Mon, 2 Mar 2020 15:01:04 +0100 Subject: [PATCH] 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 --- etc/iotronic/iotronic.conf | 4 ++++ iotronic/common/exception.py | 4 ++++ iotronic/conductor/endpoints.py | 38 +++++++++++++++++++++++++++--- iotronic/conductor/manager.py | 6 +++++ iotronic/db/sqlalchemy/api.py | 10 +++++--- iotronic/objects/exposedservice.py | 10 +++++++- tox.ini | 3 +++ 7 files changed, 68 insertions(+), 7 deletions(-) diff --git a/etc/iotronic/iotronic.conf b/etc/iotronic/iotronic.conf index 66256a9..ff320ce 100644 --- a/etc/iotronic/iotronic.conf +++ b/etc/iotronic/iotronic.conf @@ -15,6 +15,10 @@ auth_strategy=keystone # value) #pecan_debug=false +[conductor] +service_port_min=50000 +service_port_max=60000 + [wamp] wamp_transport_url = ws://:/ diff --git a/iotronic/common/exception.py b/iotronic/common/exception.py index 5f48412..0880005 100644 --- a/iotronic/common/exception.py +++ b/iotronic/common/exception.py @@ -616,6 +616,10 @@ class ServiceAlreadyExposed(Conflict): message = _("A Service with UUID %(uuid)s already exposed.") +class NotEnoughPortForService(NotFound): + message = _("No ports available") + + class ExposedServiceNotFound(NotFound): message = _("ExposedService %(uuid)s could not be found.") diff --git a/iotronic/conductor/endpoints.py b/iotronic/conductor/endpoints.py index ffff503..8a7fb56 100644 --- a/iotronic/conductor/endpoints.py +++ b/iotronic/conductor/endpoints.py @@ -43,6 +43,8 @@ serializer = objects_base.IotronicObjectSerializer() Port = list() +SERVICE_PORT_LIST = None + def versionCompare(v1, v2): """Method to compare two versions. @@ -104,8 +106,24 @@ def get_best_agent(ctx): return agent.hostname -def random_public_port(): - return random.randint(50001, 59999) +def random_public_port(ctx=None): + 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): @@ -477,6 +495,9 @@ class ConductorEndpoint(object): except Exception: public_port = random_public_port() + if not public_port: + return exception.NotEnoughPortForService() + res = self.execute_on_board(ctx, board_uuid, action, (service, public_port)) result = manage_result(res, action, board_uuid) @@ -504,6 +525,11 @@ class ConductorEndpoint(object): result = manage_result(res, action, board_uuid) LOG.debug(res.message) + global SERVICE_PORT_LIST + try: + SERVICE_PORT_LIST.append(exposed.public_port) + except exception: + pass exposed.destroy() return result @@ -799,9 +825,10 @@ class ConductorEndpoint(object): except Exception: - # TO BE CHANGED https_port = random_public_port() http_port = random_public_port() + if not https_port or not http_port: + return exception.NotEnoughPortForService() en_webservice = { 'board_uuid': board.uuid, @@ -918,6 +945,11 @@ class ConductorEndpoint(object): res = self.execute_on_board(ctx, board.uuid, "ServiceDisable", (service,), main_req=mreq.uuid) LOG.debug(res.message) + global SERVICE_PORT_LIST + try: + SERVICE_PORT_LIST.append(exposed.public_port) + except exception: + pass exposed.destroy() try: diff --git a/iotronic/conductor/manager.py b/iotronic/conductor/manager.py index ba8db9c..101a0a3 100644 --- a/iotronic/conductor/manager.py +++ b/iotronic/conductor/manager.py @@ -40,6 +40,12 @@ conductor_opts = [ help='Maximum time (in seconds) since the last check-in ' 'of a conductor. A conductor is considered inactive ' '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 diff --git a/iotronic/db/sqlalchemy/api.py b/iotronic/db/sqlalchemy/api.py index f208dc1..367e34b 100644 --- a/iotronic/db/sqlalchemy/api.py +++ b/iotronic/db/sqlalchemy/api.py @@ -911,9 +911,13 @@ class Connection(api.Connection): raise exception.ExposedServiceNotFound() def get_exposed_service_list(self, board_uuid): - query = model_query( - models.ExposedService).filter_by( - board_uuid=board_uuid) + if board_uuid: + query = model_query( + models.ExposedService).filter_by( + board_uuid=board_uuid) + else: + query = model_query( + models.ExposedService) return query.all() def _do_update_exposed_service(self, service_id, values): diff --git a/iotronic/objects/exposedservice.py b/iotronic/objects/exposedservice.py index 0c75aa6..8ed0d5a 100644 --- a/iotronic/objects/exposedservice.py +++ b/iotronic/objects/exposedservice.py @@ -31,6 +31,14 @@ class ExposedService(base.IotronicObject): '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 def _from_db_object(exposed_service, db_exposed_service): """Converts a database entity to a formal object.""" @@ -96,7 +104,7 @@ class ExposedService(base.IotronicObject): return exp_service @base.remotable_classmethod - def list(cls, context, board_uuid): + def list(cls, context, board_uuid=None): """Return a list of ExposedService objects. :param context: Security context. diff --git a/tox.ini b/tox.ini index c77a23a..3efac4c 100644 --- a/tox.ini +++ b/tox.ini @@ -25,6 +25,9 @@ commands = flake8 {posargs} [testenv:py3] basepython = python3 +[testenv:py35] +basepython = python3 + [flake8] # TODO(dmllr): Analyze or fix the warnings blacklisted below