Completed
Push — master ( ee9239...fa3047 )
by Beraldo
24s queued 13s
created

kytos.core.kytosd.async_main()   A

Complexity

Conditions 4

Size

Total Lines 47
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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