Passed
Push — master ( d123f2...591d9b )
by Humberto
04:46 queued 01:50
created

kytos.core.kytosd.async_main()   B

Complexity

Conditions 6

Size

Total Lines 57
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 10.1248

Importance

Changes 0
Metric Value
cc 6
eloc 35
nop 1
dl 0
loc 57
rs 8.1066
c 0
b 0
f 0
ccs 18
cts 35
cp 0.5143
crap 10.1248

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
#!/usr/bin/env python3
2 1
"""Start Kytos SDN Platform core."""
3 1
import asyncio
4 1
import functools
5 1
import os
6 1
import signal
7 1
from concurrent.futures import ThreadPoolExecutor
8 1
from pathlib import Path
9
10 1
import daemon
11 1
from IPython.terminal.embed import InteractiveShellEmbed
12 1
from IPython.terminal.prompts import Prompts, Token
13 1
from traitlets.config.loader import Config
14
15 1
from kytos.core import Controller
16 1
from kytos.core.config import KytosConfig
17 1
from kytos.core.metadata import __version__
18
19 1
BASE_ENV = Path(os.environ.get('VIRTUAL_ENV', '/'))
20
21
22 1
class KytosPrompt(Prompts):
23
    """Configure Kytos prompt for interactive shell."""
24
25 1
    def in_prompt_tokens(self):
26
        """Kytos IPython prompt."""
27
        return [(Token.Prompt, 'kytos $> ')]
28
29
30 1
def _create_pid_dir():
31
    """Create the directory in /var/run to hold the pidfile."""
32 1
    pid_dir = os.path.join(BASE_ENV, 'var/run/kytos')
33 1
    os.makedirs(pid_dir, exist_ok=True)
34 1
    if BASE_ENV == '/':  # system install
35 1
        os.chmod(pid_dir, 0o1777)  # permissions like /tmp
36
37
38 1
def create_shell(controller=None):
39
    """Load Kytos interactive shell."""
40 1
    kytos_ascii = r"""
41
      _          _
42
     | |        | |
43
     | | ___   _| |_ ___  ___
44
     | |/ / | | | __/ _ \/ __|
45
     |   <| |_| | || (_) \__ \
46
     |_|\_\__,  |\__\___/|___/
47
            __/ |
48
           |___/
49
    """
50
51 1
    banner1 = f"""\033[95m{kytos_ascii}\033[0m
52
    Welcome to Kytos SDN Platform!
53
54
    We are making a huge effort to make sure that this console will work fine
55
    but for now it's still experimental.
56
57
    Kytos website.: https://kytos.io/
58
    Documentation.: https://docs.kytos.io/
59
    OF Address....:"""
60
61 1
    exit_msg = "Stopping Kytos daemon... Bye, see you!"
62
63 1
    if controller:
64 1
        address = controller.server.server_address[0]
65 1
        port = controller.server.server_address[1]
66 1
        banner1 += f" tcp://{address}:{port}\n"
67
68 1
        api_port = controller.api_server.port
69 1
        banner1 += f"    WEB UI........: http://{address}:{api_port}/\n"
70 1
        banner1 += f"    Kytos Version.: {__version__}"
71
72 1
    banner1 += "\n"
73
74 1
    cfg = Config()
75 1
    cfg.TerminalInteractiveShell.autocall = 2
76 1
    cfg.TerminalInteractiveShell.show_rewritten_input = False
77 1
    cfg.TerminalInteractiveShell.confirm_exit = False
78
79
    # Avoiding sqlite3.ProgrammingError when trying to save command history
80
    # on Kytos shutdown
81 1
    cfg.HistoryAccessor.enabled = False
82
83 1
    ipshell = InteractiveShellEmbed(config=cfg,
84
                                    banner1=banner1,
85
                                    exit_msg=exit_msg)
86 1
    ipshell.prompts = KytosPrompt(ipshell)
87 1
    return ipshell
88
89
90
# def disable_threadpool_exit():
91
#     """Avoid traceback when ThreadPool tries to shut down threads again."""
92
#     import atexit
93
#     from concurrent.futures import thread, ThreadPoolExecutor
94
#     atexit.unregister(thread._python_exit)
95
96 1
def main():
97
    """Read config and start Kytos in foreground or daemon mode."""
98
    # data_files is not enough when installing from PyPI
99
100 1
    _create_pid_dir()
101
102 1
    config = KytosConfig().options['daemon']
103
104 1
    if config.foreground or not config.daemon:
105 1
        async_main(config)
106
    else:
107 1
        with daemon.DaemonContext():
108 1
            async_main(config)
109
110
111 1
def async_main(config):
112
    """Start main Kytos Daemon with asyncio loop."""
113 1
    def stop_controller(controller, shell_task=None):
114
        """Stop the controller before quitting."""
115
        loop = asyncio.get_event_loop()
116
117
        if loop:
118
            # If stop() hangs, old ctrl+c behaviour will be restored
119
            loop.remove_signal_handler(signal.SIGINT)
120
            loop.remove_signal_handler(signal.SIGTERM)
121
122
        # disable_threadpool_exit()
123
124
        controller.log.info("Stopping Kytos controller...")
125
        controller.stop()
126
127
        if shell_task:
128
            shell_task.cancel()
129
130 1
    async def start_shell_async():
131
        """Run the shell inside a thread and stop controller when done."""
132
        interactive_shell = create_shell(controller)
133
134
        try:
135
            data = await loop.run_in_executor(executor, interactive_shell)
136
        finally:
137
            # Exit all embedded code in shell
138
            interactive_shell.magic("%exit_raise")
139
            stop_controller(controller)
140
        return data
141
142 1
    loop = asyncio.get_event_loop()
143
144 1
    controller = Controller(config)
145
146 1
    if controller.options.debug:
147 1
        loop.set_debug(True)
148
149 1
    loop.call_soon(controller.start)
150
151 1
    shell_task = None
152 1
    if controller.options.foreground:
153 1
        executor = ThreadPoolExecutor(max_workers=1)
154 1
        shell_task = loop.create_task(start_shell_async())
155
156 1
    kill_handler = functools.partial(stop_controller, controller, shell_task)
157 1
    loop.add_signal_handler(signal.SIGINT, kill_handler)
158 1
    loop.add_signal_handler(signal.SIGTERM, kill_handler)
159
160 1
    try:
161 1
        loop.run_forever()
162
    except SystemExit as exc:
163
        controller.log.error(exc)
164
        controller.log.info("Shutting down Kytos...")
165
    finally:
166
167
        loop.close()
168