| 1 |  |  | """Manage Network Application files.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | import json | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | import logging | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | import os | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | import re | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | import shutil | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | import sys | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | import tarfile | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | import urllib | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | from pathlib import Path | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | from random import randint | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | from jinja2 import Environment, FileSystemLoader | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | from kytos.utils.client import NAppsClient | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | from kytos.utils.config import KytosConfig | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  | log = logging.getLogger(__name__) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  | class NAppsManager: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |     """Deal with NApps at filesystem level and ask Kytos to (un)load NApps.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |     def __init__(self, controller=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         """If controller is not informed, the necessary paths must be. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |         If ``controller`` is available, NApps will be (un)loaded at runtime and | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |         you don't need to inform the paths. Otherwise, you should inform the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |         required paths for the methods called. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |             controller (kytos.Controller): Controller to (un)load NApps. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |             install_path (str): Folder where NApps should be installed. If | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |                 None, use the controller's configuration. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |             enabled_path (str): Folder where enabled NApps are stored. If None, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |                 use the controller's configuration. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |         self._controller = controller | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |         self._config = KytosConfig().config | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |         self._kytos_api = self._config.get('kytos', 'api') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |         self._load_kytos_configuration() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |         self.user = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |         self.napp = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |         self.version = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     def _load_kytos_configuration(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         """Request current configurations loaded by Kytos instance.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         uri = self._kytos_api + 'kytos/config/' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |             options = json.loads(urllib.request.urlopen(uri).read()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         except urllib.error.URLError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |             print('Kytos is not running.') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |             sys.exit() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         self._installed = Path(options.get('installed_napps')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |         self._enabled = Path(options.get('napps')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     def set_napp(self, user, napp, version=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |         """Set info about NApp. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |             user (str): NApps Server username. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |             napp (str): NApp name. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |             version (str): NApp version. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |         self.user = user | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         self.napp = napp | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |         self.version = version or 'latest' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |     def napp_id(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |         """Identifier of NApp.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |         return '/'.join((self.user, self.napp)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |     def _get_napps(napps_dir): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |         """List of (username, napp_name) found in ``napps_dir``.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |         jsons = napps_dir.glob('*/*/kytos.json') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |         return sorted(j.parts[-3:-1] for j in jsons) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |     def get_enabled(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         """Sorted list of (username, napp_name) of enabled napps.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |         return self._get_napps(self._enabled) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |     def get_installed(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |         """Sorted list of (username, napp_name) of installed napps.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |         return self._get_napps(self._installed) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |     def is_installed(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |         """Whether a NApp is installed.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |         return (self.user, self.napp) in self.get_installed() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |     def get_disabled(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |         """Sorted list of (username, napp_name) of disabled napps. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |         The difference of installed and enabled. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |         installed = set(self.get_installed()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         enabled = set(self.get_enabled()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |         return sorted(installed - enabled) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |     def dependencies(self, user=None, napp=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |         """Method used to get napp_dependencies from install NApp. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |             user(string)  A Username. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |             napp(string): A NApp name. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |             napps(list): List with tuples with Username and NApp name. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |                          e.g. [('kytos'/'of_core'), ('kytos/of_l2ls')] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |         napps = self._get_napp_key('napp_dependencies', user, napp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |         return [tuple(napp.split('/')) for napp in napps] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |     def get_description(self, user=None, napp=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |         """Return the description from kytos.json.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |         return self._get_napp_key('description', user, napp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |     def get_version(self, user=None, napp=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |         """Return the version from kytos.json.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |         return self._get_napp_key('version', user, napp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |     def _get_napp_key(self, key, user=None, napp=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |         """Generic method used to return a value from kytos.json. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |             user (string): A Username. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |             napp (string): A NApp name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |             key (string): Key used to get the value within kytos.json. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |             meta (object): Value stored in kytos.json. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |         if user is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |             user = self.user | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |         if napp is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |             napp = self.napp | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |         kj = self._installed / user / napp / 'kytos.json' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |             with kj.open() as f: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |                 meta = json.load(f) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |                 return meta[key] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |         except (FileNotFoundError, json.JSONDecodeError, KeyError): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |             return '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |     def disable(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |         """Disable a NApp if it is enabled.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |         enabled = self.enabled_dir() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |             enabled.unlink() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |             if self._controller is not None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |                 self._controller.unload_napp(self.user, self.napp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |         except FileNotFoundError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |             pass  # OK, it was already disabled | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |     def enabled_dir(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |         """Return the enabled dir from current napp.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |         return self._enabled / self.user / self.napp | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |     def installed_dir(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |         """Return the installed dir from current napp.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |         return self._installed / self.user / self.napp | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |     def enable(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |         """Enable a NApp if not already enabled. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |             FileNotFoundError: If NApp is not installed. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |             PermissionError: No filesystem permission to enable NApp. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |         enabled = self.enabled_dir() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |         installed = self.installed_dir() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |         if not installed.is_dir(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |             raise FileNotFoundError('Install NApp {} first.'.format( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |                 self.napp_id)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |         elif not enabled.exists(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |             self._check_module(enabled.parent) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |             try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |                 # Create symlink | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |                 enabled.symlink_to(installed) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |                 if self._controller is not None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |                     self._controller.load_napp(self.user, self.napp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |             except FileExistsError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |                 pass  # OK, NApp was already enabled | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  |             except PermissionError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |                 raise PermissionError('Permission error on enabling NApp. Try ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  |                                       'with sudo.') | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 189 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 190 |  |  |     def is_enabled(self): | 
            
                                                                        
                            
            
                                    
            
            
                | 191 |  |  |         """Whether a NApp is enabled.""" | 
            
                                                                        
                            
            
                                    
            
            
                | 192 |  |  |         return (self.user, self.napp) in self.get_enabled() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |     def uninstall(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |         """Delete code inside NApp directory, if existent.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  |         if self.is_installed(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |             installed = self.installed_dir() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  |             if installed.is_symlink(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |                 installed.unlink() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  |                 shutil.rmtree(str(installed)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |     def valid_name(username): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 |  |  |         """Check the validity of the given 'name'. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 |  |  |         The following checks are done: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 208 |  |  |         - name starts with a letter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 209 |  |  |         - name contains only letters, numbers or underscores | 
            
                                                                                                            
                            
            
                                    
            
            
                | 210 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 211 |  |  |         return username and re.match(r'[a-zA-Z][a-zA-Z0-9_]{2,}$', username) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 212 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 213 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 214 |  |  |     def render_template(templates_path, template_filename, context): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 215 |  |  |         """Render Jinja2 template for a NApp structure.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 216 |  |  |         TEMPLATE_ENV = Environment(autoescape=False, trim_blocks=False, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 217 |  |  |                                    loader=FileSystemLoader(templates_path)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 218 |  |  |         return TEMPLATE_ENV.get_template(template_filename).render(context) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 219 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 220 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 221 |  |  |     def search(pattern): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 222 |  |  |         """Search all server NApps matching pattern. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 223 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 224 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 225 |  |  |             pattern (str): Python regular expression. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 226 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 227 |  |  |         def match(napp): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 228 |  |  |             """Whether a NApp metadata matches the pattern.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 229 |  |  |             # WARNING: This will change for future versions, when 'author' will | 
            
                                                                                                            
                            
            
                                    
            
            
                | 230 |  |  |             # be removed. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 231 |  |  |             username = napp.get('username', napp.get('author')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 232 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 233 |  |  |             strings = ['{}/{}'.format(username, napp.get('name')), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 234 |  |  |                        napp.get('description')] + napp.get('tags') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 235 |  |  |             return any(pattern.match(string) for string in strings) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 236 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 237 |  |  |         napps = NAppsClient().get_napps() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 238 |  |  |         return [napp for napp in napps if match(napp)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 239 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 240 |  |  |     def install_local(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 241 |  |  |         """Make a symlink in install folder to a local NApp. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 242 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 243 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 244 |  |  |             FileNotFoundError: If NApp is not found. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 245 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 246 |  |  |         folder = self._get_local_folder() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 247 |  |  |         installed = self.installed_dir() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 248 |  |  |         self._check_module(installed.parent) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 249 |  |  |         installed.symlink_to(folder.resolve()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 250 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 251 |  |  |     def _get_local_folder(self, root=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 252 |  |  |         """Return local NApp root folder. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 253 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 254 |  |  |         Search for kytos.json in _./_ folder and _./user/napp_. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 255 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 256 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 257 |  |  |             root (pathlib.Path): Where to begin searching. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 258 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 259 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 260 |  |  |             FileNotFoundError: If there is no such local NApp. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 261 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 262 |  |  |         Return: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 263 |  |  |             pathlib.Path: NApp root folder. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 264 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 265 |  |  |         if root is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 266 |  |  |             root = Path() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 267 |  |  |         for folders in ['.'], [self.user, self.napp]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 268 |  |  |             kytos_json = root / Path(*folders) / 'kytos.json' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 269 |  |  |             if kytos_json.exists(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 270 |  |  |                 with kytos_json.open() as f: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 271 |  |  |                     meta = json.load(f) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 272 |  |  |                     # WARNING: This will change in future versions, when | 
            
                                                                                                            
                            
            
                                    
            
            
                | 273 |  |  |                     # 'author' will be removed. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 274 |  |  |                     username = meta.get('username', meta.get('author')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 275 |  |  |                     if username == self.user and meta.get('name') == self.napp: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 276 |  |  |                         return kytos_json.parent | 
            
                                                                                                            
                            
            
                                    
            
            
                | 277 |  |  |         raise FileNotFoundError('kytos.json not found.') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 278 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 279 |  |  |     def install_remote(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 280 |  |  |         """Download, extract and install NApp.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 281 |  |  |         package, pkg_folder = None, None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 282 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 283 |  |  |             package = self._download() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 284 |  |  |             pkg_folder = self._extract(package) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 285 |  |  |             napp_folder = self._get_local_folder(pkg_folder) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 286 |  |  |             dst = self._installed / self.user / self.napp | 
            
                                                                                                            
                            
            
                                    
            
            
                | 287 |  |  |             self._check_module(dst.parent) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 288 |  |  |             shutil.move(str(napp_folder), str(dst)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 289 |  |  |         finally: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 290 |  |  |             # Delete temporary files | 
            
                                                                                                            
                            
            
                                    
            
            
                | 291 |  |  |             if package: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 292 |  |  |                 Path(package).unlink() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 293 |  |  |             if pkg_folder and pkg_folder.exists(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 294 |  |  |                 shutil.rmtree(str(pkg_folder)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 295 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 296 |  |  |     def _download(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 297 |  |  |         """Download NApp package from server. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 298 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 299 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 300 |  |  |             urllib.error.HTTPError: If download is not successful. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 301 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 302 |  |  |         Return: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 303 |  |  |             str: Downloaded temp filename. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 304 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 305 |  |  |         repo = self._config.get('napps', 'repo') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 306 |  |  |         napp_id = '{}/{}-{}.napp'.format(self.user, self.napp, self.version) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 307 |  |  |         uri = os.path.join(repo, napp_id) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 308 |  |  |         return urllib.request.urlretrieve(uri)[0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 309 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 310 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 311 |  |  |     def _extract(filename): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 312 |  |  |         """Extract package to a temporary folder. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 313 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 314 |  |  |         Return: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 315 |  |  |             pathlib.Path: Temp dir with package contents. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 316 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 317 |  |  |         random_string = '{:0d}'.format(randint(0, 10**6)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 318 |  |  |         tmp = '/tmp/kytos-napp-' + Path(filename).stem + '-' + random_string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 319 |  |  |         os.mkdir(tmp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 320 |  |  |         with tarfile.open(filename, 'r:xz') as tar: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 321 |  |  |             tar.extractall(tmp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 322 |  |  |         return Path(tmp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 323 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 324 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 325 |  |  |     def create_napp(cls): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 326 |  |  |         """Bootstrap a basic NApp strucutre for you to develop your NApp. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 327 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 328 |  |  |         This will create, on the current folder, a clean structure of a NAPP, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 329 |  |  |         filling some contents on this structure. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 330 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 331 |  |  |         base = os.environ.get('VIRTUAL_ENV', '/') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 332 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 333 |  |  |         templates_path = os.path.join(base, 'etc', 'skel', 'kytos', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 334 |  |  |                                       'napp-structure', 'username', 'napp') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 335 |  |  |         username = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 336 |  |  |         napp_name = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 337 |  |  |         description = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 338 |  |  |         print('--------------------------------------------------------------') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 339 |  |  |         print('Welcome to the bootstrap process of your NApp.') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 340 |  |  |         print('--------------------------------------------------------------') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 341 |  |  |         print('In order to answer both the username and the napp name,') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 342 |  |  |         print('You must follow this naming rules:') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 343 |  |  |         print(' - name starts with a letter') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 344 |  |  |         print(' - name contains only letters, numbers or underscores') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 345 |  |  |         print(' - at least three characters') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 346 |  |  |         print('--------------------------------------------------------------') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 347 |  |  |         print('') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 348 |  |  |         msg = 'Please, insert your NApps Server username: ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 349 |  |  |         while not cls.valid_name(username): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 350 |  |  |             username = input(msg) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 351 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 352 |  |  |         while not cls.valid_name(napp_name): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 353 |  |  |             napp_name = input('Please, insert your NApp name: ') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 354 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 355 |  |  |         msg = 'Please, insert a brief description for your NApp [optional]: ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 356 |  |  |         description = input(msg) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 357 |  |  |         if not description: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 358 |  |  |             description = \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 359 |  |  |                 '# TODO: <<<< Insert here your NApp description >>>>'  # noqa | 
            
                                                                                                            
                            
            
                                    
            
            
                | 360 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 361 |  |  |         context = {'username': username, 'napp': napp_name, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 362 |  |  |                    'description': description} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 363 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 364 |  |  |         #: Creating the directory structure (username/napp_name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 365 |  |  |         os.makedirs(username, exist_ok=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 366 |  |  |         #: Creating ``__init__.py`` files | 
            
                                                                                                            
                            
            
                                    
            
            
                | 367 |  |  |         with open(os.path.join(username, '__init__.py'), 'w'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 368 |  |  |             pass | 
            
                                                                                                            
                            
            
                                    
            
            
                | 369 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 370 |  |  |         os.makedirs(os.path.join(username, napp_name)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 371 |  |  |         with open(os.path.join(username, napp_name, '__init__.py'), 'w'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 372 |  |  |             pass | 
            
                                                                                                            
                            
            
                                    
            
            
                | 373 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 374 |  |  |         #: Creating the other files based on the templates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 375 |  |  |         templates = os.listdir(templates_path) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 376 |  |  |         templates.remove('__init__.py') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 377 |  |  |         for tmp in templates: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 378 |  |  |             fname = os.path.join(username, napp_name, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 379 |  |  |                                  tmp.rsplit('.template')[0]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 380 |  |  |             with open(fname, 'w') as file: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 381 |  |  |                 content = cls.render_template(templates_path, tmp, context) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 382 |  |  |                 file.write(content) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 383 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 384 |  |  |         msg = '\nCongratulations! Your NApp have been bootstrapped!\nNow you ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 385 |  |  |         msg += 'can go to the directory {}/{} and begin to code your NApp.' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 386 |  |  |         print(msg.format(username, napp_name)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 387 |  |  |         print('Have fun!') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 388 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 389 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 390 |  |  |     def _check_module(folder): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 391 |  |  |         """Create module folder with empty __init__.py if it doesn't exist. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 392 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 393 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 394 |  |  |             folder (pathlib.Path): Module path. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 395 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 396 |  |  |         if not folder.exists(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 397 |  |  |             folder.mkdir(parents=True, exist_ok=True, mode=0o755) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 398 |  |  |             (folder / '__init__.py').touch() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 399 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 400 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 401 |  |  |     def build_napp_package(napp_name): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 402 |  |  |         """Build the .napp file to be sent to the napps server. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 403 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 404 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 405 |  |  |             napp_identifier (str): Identifier formatted as | 
            
                                                                                                            
                            
            
                                    
            
            
                | 406 |  |  |                 <username>/<napp_name> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 407 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 408 |  |  |         Return: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 409 |  |  |             file_payload (binary): The binary representation of the napp | 
            
                                                                                                            
                            
            
                                    
            
            
                | 410 |  |  |                 package that will be POSTed to the napp server. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 411 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 412 |  |  |         ignored_extensions = ['.swp', '.pyc', '.napp'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 413 |  |  |         ignored_dirs = ['__pycache__'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 414 |  |  |         files = os.listdir() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 415 |  |  |         for filename in files: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 416 |  |  |             if os.path.isfile(filename) and '.' in filename and \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 417 |  |  |                     filename.rsplit('.', 1)[1] in ignored_extensions: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 418 |  |  |                 files.remove(filename) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 419 |  |  |             elif os.path.isdir(filename) and filename in ignored_dirs: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 420 |  |  |                 files.remove(filename) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 421 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 422 |  |  |         # Create the '.napp' package | 
            
                                                                                                            
                            
            
                                    
            
            
                | 423 |  |  |         napp_file = tarfile.open(napp_name + '.napp', 'x:xz') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 424 |  |  |         for local_f in files: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 425 |  |  |             napp_file.add(local_f) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 426 |  |  |         napp_file.close() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 427 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 428 |  |  |         # Get the binary payload of the package | 
            
                                                                                                            
                            
            
                                    
            
            
                | 429 |  |  |         file_payload = open(napp_name + '.napp', 'rb') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 430 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 431 |  |  |         # remove the created package from the filesystem | 
            
                                                                                                            
                            
            
                                    
            
            
                | 432 |  |  |         os.remove(napp_name + '.napp') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 433 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 434 |  |  |         return file_payload | 
            
                                                                                                            
                            
            
                                    
            
            
                | 435 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 436 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 437 |  |  |     def create_metadata(*args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 438 |  |  |         """Generate the metadata to send the napp package.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 439 |  |  |         json_filename = kwargs.get('json_filename', 'kytos.json') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 440 |  |  |         readme_filename = kwargs.get('readme_filename', 'README.rst') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 441 |  |  |         ignore_json = kwargs.get('ignore_json', False) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 442 |  |  |         metadata = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 443 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 444 |  |  |         if not ignore_json: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 445 |  |  |             try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 446 |  |  |                 with open(json_filename) as json_file: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 447 |  |  |                     metadata = json.load(json_file) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 448 |  |  |             except FileNotFoundError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 449 |  |  |                 print("ERROR: Could not access kytos.json file.") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 450 |  |  |                 sys.exit(1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 451 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 452 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 453 |  |  |             with open(readme_filename) as readme_file: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 454 |  |  |                 metadata['readme'] = readme_file.read() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 455 |  |  |         except FileNotFoundError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 456 |  |  |             metadata['readme'] = '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 457 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 458 |  |  |         return metadata | 
            
                                                                                                            
                            
            
                                    
            
            
                | 459 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 460 |  |  |     def upload(self, *args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 461 |  |  |         """Create package and upload it to NApps Server. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 462 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 463 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 464 |  |  |             FileNotFoundError: If kytos.json is not found. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 465 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 466 |  |  |         metadata = self.create_metadata(*args, **kwargs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 467 |  |  |         package = self.build_napp_package(metadata.get('name')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 468 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 469 |  |  |         NAppsClient().upload_napp(metadata, package) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 470 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 471 |  |  |     def delete(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 472 |  |  |         """Delete a NApp. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 473 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 474 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 475 |  |  |             requests.HTTPError: When there's a server error. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 476 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 477 |  |  |         client = NAppsClient(self._config) | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 478 |  |  |         client.delete(self.user, self.napp) | 
            
                                                        
            
                                    
            
            
                | 479 |  |  |  |