Skip to content

Commit

Permalink
Merge pull request #417 from kytos-ng/feat/load_napps_or_shutdown_202…
Browse files Browse the repository at this point in the history
…3.1.1

[2023.1.1] feat: set default ``maxTimeMS`` when creating an index; unhandled exc on `setup()` will exit `kytosd`
  • Loading branch information
viniarck authored Sep 27, 2023
2 parents 8d154b5 + 1359e32 commit d187380
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 19 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ All notable changes to the kytos project will be documented in this file.
UNRELEASED - Under development
******************************

[2023.1.1] 2023-09-26
**********************

Changed
=======
- Parametrized default ``maxTimeMS`` when creating an index via ``Mongo.boostrap_index`` via environment variable ``MONGO_IDX_TIMEOUTMS=30000``. The retries parameters reuse the same environment variables ``MONGO_AUTO_RETRY_STOP_AFTER_ATTEMPT=3``, ``MONGO_AUTO_RETRY_WAIT_RANDOM_MIN=0.1``, ``MONGO_AUTO_RETRY_WAIT_RANDOM_MAX=1`` that NApps controllers have been using.
- ``kytosd`` process will exit if a NApp raises an exception during its ``setup()`` execution.

[2023.1.0] - 2023-06-05
***********************

Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@
# built documents.
#
# The short X.Y version.
version = u'2023.1.0'
version = u'2023.1.1'
show_version = False
# The full version, including alpha/beta/rc tags.
release = u'2023.1.0'
release = u'2023.1.1'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
36 changes: 23 additions & 13 deletions kytos/core/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import re
import sys
import threading
import traceback
from asyncio import AbstractEventLoop
from importlib import import_module
from importlib import reload as reload_module
Expand All @@ -40,7 +41,8 @@
from kytos.core.db import db_conn_wait
from kytos.core.dead_letter import DeadLetter
from kytos.core.events import KytosEvent
from kytos.core.exceptions import KytosAPMInitException, KytosDBInitException
from kytos.core.exceptions import (KytosAPMInitException, KytosDBInitException,
KytosNAppSetupException)
from kytos.core.helpers import executors, now
from kytos.core.interface import Interface
from kytos.core.logs import LogManager
Expand Down Expand Up @@ -251,14 +253,21 @@ def toggle_debug(self, name=None):
def start(self, restart=False):
"""Create pidfile and call start_controller method."""
self.enable_logs()
if self.options.database:
self.db_conn_or_core_shutdown()
self.start_auth()
if self.options.apm:
self.init_apm_or_core_shutdown()
if not restart:
self.create_pidfile()
self.start_controller()
# pylint: disable=broad-except
try:
if self.options.database:
self.db_conn_or_core_shutdown()
self.start_auth()
if self.options.apm:
self.init_apm_or_core_shutdown()
if not restart:
self.create_pidfile()
self.start_controller()
except Exception as exc:
exc_fmt = traceback.format_exc(chain=True)
message = f"Kytos couldn't start because of {str(exc)} {exc_fmt}"
print(message)
sys.exit(1)

def create_pidfile(self):
"""Create a pidfile."""
Expand Down Expand Up @@ -852,10 +861,9 @@ def load_napp(self, username, napp_name):

try:
napp = napp_module.Main(controller=self)
except: # noqa pylint: disable=bare-except
self.log.critical("NApp initialization failed: %s/%s",
username, napp_name, exc_info=True)
return
except Exception as exc: # noqa pylint: disable=bare-except
msg = f"NApp {username}/{napp_name} exception {str(exc)} "
raise KytosNAppSetupException(msg) from exc

self.napps[(username, napp_name)] = napp

Expand Down Expand Up @@ -891,6 +899,8 @@ def load_napps(self):
except FileNotFoundError as exception:
self.log.error("Could not load NApp %s: %s",
napp.id, exception)
msg = f"NApp {napp.id} exception {str(exception)}"
raise KytosNAppSetupException(msg)

def unload_napp(self, username, napp_name):
"""Unload a specific NApp.
Expand Down
18 changes: 18 additions & 0 deletions kytos/core/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
import pymongo.helpers
from pymongo import MongoClient
from pymongo.errors import AutoReconnect, OperationFailure
from tenacity import (retry, retry_if_exception_type, stop_after_attempt,
wait_random)

from kytos.core.exceptions import KytosDBInitException
from kytos.core.retry import before_sleep

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -88,6 +91,18 @@ class Mongo:
db_name = os.environ.get("MONGO_DBNAME") or "napps"

@classmethod
@retry(
stop=stop_after_attempt(
int(os.environ.get("MONGO_AUTO_RETRY_STOP_AFTER_ATTEMPT", 3))
),
wait=wait_random(
min=int(os.environ.get("MONGO_AUTO_RETRY_WAIT_RANDOM_MIN", 0.1)),
max=int(os.environ.get("MONGO_AUTO_RETRY_WAIT_RANDOM_MAX", 1)),
),
before_sleep=before_sleep,
retry=retry_if_exception_type((OperationFailure, AutoReconnect)),
reraise=True
)
def bootstrap_index(
cls,
collection: str,
Expand All @@ -99,6 +114,9 @@ def bootstrap_index(
indexes = set()
if "background" not in kwargs:
kwargs["background"] = True
if "maxTimeMS" not in kwargs:
timeout_ms = int(os.environ.get("MONGO_IDX_TIMEOUTMS") or 30000)
kwargs["maxTimeMS"] = timeout_ms

for value in db[collection].index_information().values():
if "key" in value and isinstance(value["key"], list):
Expand Down
11 changes: 11 additions & 0 deletions kytos/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ def __str__(self):
return self.message


class KytosNAppSetupException(KytosNAppException):
"""KytosNAppSetupException. """

def __init__(self, message="KytosNAppSetupException") -> None:
"""KytosNAppSetupException."""
super().__init__(message=message)

def __str__(self):
return f"KytosNAppSetupException: {self.message}"


class KytosNAppMissingInitArgument(KytosNAppException):
"""Exception thrown when NApp have a missing init argument."""

Expand Down
2 changes: 1 addition & 1 deletion kytos/core/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
The present metadata is intended to be used mainly on the setup.
"""
__version__ = '2023.1.0'
__version__ = '2023.1.1'
__author__ = 'Kytos Team'
__author_email__ = 'devel@lists.kytos.io'
__license__ = 'MIT'
Expand Down
25 changes: 24 additions & 1 deletion tests/unit/test_core/test_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from kytos.core.buffers import KytosBuffers
from kytos.core.config import KytosConfig
from kytos.core.events import KytosEvent
from kytos.core.exceptions import KytosNAppSetupException
from kytos.core.logs import LogManager
from kytos.core.rest_api import Request

Expand Down Expand Up @@ -181,6 +182,27 @@ def test_start(self, *args):
mock_db_conn_or_shutdown.assert_not_called()
mock_init_apm_or_shutdown.assert_not_called()

@patch('kytos.core.controller.sys')
@patch('kytos.core.controller.Controller.init_apm_or_core_shutdown')
@patch('kytos.core.controller.Controller.db_conn_or_core_shutdown')
@patch('kytos.core.controller.Controller.start_controller')
@patch('kytos.core.controller.Controller.create_pidfile')
@patch('kytos.core.controller.Controller.enable_logs')
def test_start_error_broad_exception(self, *args):
"""Test start error handling broad exception."""
(mock_enable_logs, mock_create_pidfile,
mock_start_controller, mock_db_conn_or_shutdown,
mock_init_apm_or_shutdown, mock_sys) = args
mock_start_controller.side_effect = Exception
self.controller.start()

mock_enable_logs.assert_called()
mock_create_pidfile.assert_called()
mock_start_controller.assert_called()
mock_db_conn_or_shutdown.assert_not_called()
mock_init_apm_or_shutdown.assert_not_called()
mock_sys.exit.assert_called()

@patch('kytos.core.controller.Controller.init_apm_or_core_shutdown')
@patch('kytos.core.controller.Controller.db_conn_or_core_shutdown')
@patch('kytos.core.controller.Controller.start_controller')
Expand Down Expand Up @@ -495,7 +517,8 @@ def test_load_napp__error(self, *args):
module.Main.side_effect = Exception
mock_import_napp.return_value = module

self.controller.load_napp('kytos', 'napp')
with self.assertRaises(KytosNAppSetupException):
self.controller.load_napp('kytos', 'napp')

self.assertEqual(self.controller.napps, {})

Expand Down
7 changes: 5 additions & 2 deletions tests/unit/test_core/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,16 @@ def test_boostrap_index(self) -> None:
keys = [("interfaces.id", 1)]
Mongo().bootstrap_index(coll, keys)
assert db[coll].create_index.call_count == 1
db[coll].create_index.assert_called_with(keys, background=True)
db[coll].create_index.assert_called_with(keys,
background=True,
maxTimeMS=30000)

keys = [("interfaces.id", 1), ("interfaces.name", 1)]
Mongo().bootstrap_index(coll, keys)
assert db[coll].create_index.call_count == 2
db[coll].create_index.assert_called_with(keys,
background=True)
background=True,
maxTimeMS=30000)

@staticmethod
@patch("kytos.core.db.LOG")
Expand Down

0 comments on commit d187380

Please sign in to comment.