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
|
|
|
|