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