Passed
Push — master ( 1b986a...ef0e11 )
by Vinicius
03:22 queued 14s
created

kytos.core.config.KytosConfig.parse_args()   B

Complexity

Conditions 2

Size

Total Lines 66
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 37
nop 1
dl 0
loc 66
ccs 11
cts 11
cp 1
crap 2
rs 8.9919
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
"""Here you can control the config parameters to run Kytos controller.
2
3
Basically you can use a config file (-c option) and use arguments on command
4
line. If you specify a config file, then and option configured inside this file
5
will be overridden by the option on command line.
6
"""
7
8 1
import json
9 1
import os
10 1
import uuid
11 1
import warnings
12 1
from argparse import ArgumentParser, RawDescriptionHelpFormatter
13 1
from configparser import ConfigParser
14 1
from pathlib import Path
15
16 1
from jinja2 import Template
17
18 1
from kytos.core.metadata import __version__
19
20 1
BASE_ENV = os.environ.get('VIRTUAL_ENV', None) or '/'
21 1
ETC_KYTOS = 'etc/kytos'
22 1
TEMPLATE_FILES = ['templates/kytos.conf.template',
23
                  'templates/logging.ini.template']
24 1
SYSLOG_ARGS = ['/dev/log'] if Path('/dev/log').exists() else []
25
26
27 1
class KytosConfig():
28
    """Handle settings of Kytos."""
29
30 1
    def __init__(self):
31
        """Parse the command line.
32
33
        The contructor set defaults parameters that can be used by KytosConfig.
34
        """
35 1
        self.options = {}
36 1
        conf_parser = ArgumentParser(add_help=False)
37
38 1
        conf_parser.add_argument("-c", "--conf",
39
                                 help="Specify a config file",
40
                                 metavar="FILE")
41
42 1
        parser = ArgumentParser(prog='kytosd',
43
                                parents=[conf_parser],
44
                                formatter_class=RawDescriptionHelpFormatter,
45
                                description=__doc__)
46
47 1
        parser.add_argument('-v', '--version',
48
                            action='version',
49
                            version="kytosd %s" % __version__)
50
51 1
        parser.add_argument('-D', '--debug',
52
                            action='store_true',
53
                            help="Run in debug mode")
54
55 1
        parser.add_argument('-f', '--foreground',
56
                            action='store_true',
57
                            help="Run in foreground (ctrl+c to stop)")
58
59 1
        parser.add_argument('-l', '--listen',
60
                            action='store',
61
                            help="IP/Interface to be listened")
62
63 1
        parser.add_argument('-n', '--napps',
64
                            action='store',
65
                            help="Specify the napps directory")
66
67 1
        parser.add_argument('-P', '--port',
68
                            action='store',
69
                            help="Port to be listened")
70
71 1
        parser.add_argument('-p', '--pidfile',
72
                            action='store',
73
                            help="Specify the PID file to save.")
74
75 1
        parser.add_argument('-w', '--workdir',
76
                            action='store',
77
                            help="Specify the working directory")
78
79 1
        parser.add_argument('-s', '--protocol_name',
80
                            action='store',
81
                            help="Specify the southbound protocol")
82
83 1
        parser.add_argument('-E', '--enable_entities_by_default',
84
                            action='store_true',
85
                            help="Enable all new Entities by default.")
86
87 1
        parser.add_argument('-C', '--create-superuser',
88
                            action='store_true',
89
                            help="Create a kytos superuser.")
90
91 1
        parser.add_argument('-t', '--thread_pool_max_workers',
92
                            action='store',
93
                            help="Maximum number of threads in the pool.")
94
95 1
        parser.add_argument('-d', '--database',
96
                            action='store',
97
                            help="Database backend.")
98
99 1
        parser.add_argument('-a', '--apm',
100
                            action='store',
101
                            help="APM backend.")
102
103 1
        self.conf_parser, self.parser = conf_parser, parser
104 1
        self.parse_args()
105
106 1
    def parse_args(self):
107
        """Get the command line options and update kytos settings.
108
109
        When installed via pip, defaults values are:
110
111
        .. code-block:: python
112
113
            defaults = {'pidfile': '/var/run/kytos/kytosd.pid',
114
                        'workdir': '/var/lib/kytos',
115
                        'napps': '/var/lib/kytos/napps/',
116
                        'conf': '/etc/kytos/kytos.conf',
117
                        'logging': '/etc/kytos/logging.ini',
118
                        'listen': '0.0.0.0',
119
                        'port': 6653,
120
                        'foreground': False,
121
                        'protocol_name': '',
122
                        'enable_entities_by_default': False,
123
                        'token_expiration_minutes': 180,
124
                        'thread_pool_max_workers': 256,
125
                        'debug': False}
126
127
        """
128 1
        defaults = {'pidfile': os.path.join(BASE_ENV,
129
                                            'var/run/kytos/kytosd.pid'),
130
                    'workdir': os.path.join(BASE_ENV, 'var/lib/kytos'),
131
                    'napps': os.path.join(BASE_ENV, 'var/lib/kytos/napps/'),
132
                    'napps_repositories': "['https://napps.kytos.io/repo/']",
133
                    'installed_napps': os.path.join(BASE_ENV,
134
                                                    'var/lib/kytos/napps/',
135
                                                    '.installed'),
136
                    'conf': os.path.join(BASE_ENV, 'etc/kytos/kytos.conf'),
137
                    'logging': os.path.join(BASE_ENV, 'etc/kytos/logging.ini'),
138
                    'logger_decorators':
139
                        ["kytos.core.logger_decorators.queue_decorator"],
140
                    'listen': '0.0.0.0',
141
                    'port': 6653,
142
                    'foreground': False,
143
                    'protocol_name': '',
144
                    'enable_entities_by_default': False,
145
                    'napps_pre_installed': [],
146
                    'authenticate_urls': [],
147
                    'vlan_pool': {},
148
                    'token_expiration_minutes': 180,
149
                    'thread_pool_max_workers': {},
150
                    'database': '',
151
                    'apm': '',
152
                    'debug': False}
153
154 1
        options, argv = self.conf_parser.parse_known_args()
155
156 1
        config = ConfigParser()
157
158 1
        config_file = options.conf or defaults.get('conf')
159
160 1
        if not os.path.exists(config_file):
161 1
            _render_config_templates(TEMPLATE_FILES, BASE_ENV,
162
                                     prefix=BASE_ENV,
163
                                     syslog_args=SYSLOG_ARGS)
164
165 1
        config.read(config_file)
166
167 1
        defaults.update(dict(config.items("daemon")))
168
169 1
        self.parser.set_defaults(**defaults)
170
171 1
        self.options['daemon'] = self._parse_options(argv)
172
173 1
    def _parse_options(self, argv):
174
        """Create a Namespace using the given argv.
175
176
        Args:
177
            argv(dict): Python Dict used to create the namespace.
178
179
        Returns:
180
            options(Namespace): Namespace with the args given
181
182
        """
183 1
        options, unknown = self.parser.parse_known_args(argv)
184 1
        if unknown:
185 1
            warnings.warn(f"Unknown arguments: {unknown}")
186 1
        options.napps_repositories = json.loads(options.napps_repositories)
187 1
        options.debug = options.debug in ['True', True]
188 1
        options.daemon = options.daemon in ['True', True]
189 1
        options.port = int(options.port)
190 1
        options.api_port = int(options.api_port)
191 1
        options.protocol_name = str(options.protocol_name)
192 1
        options.token_expiration_minutes = int(options.
193
                                               token_expiration_minutes)
194 1
        result = options.enable_entities_by_default in ['True', True]
195 1
        options.enable_entities_by_default = result
196
197 1
        def _parse_json(value):
198
            """Parse JSON lists and dicts from the config file."""
199 1
            if isinstance(value, str):
200 1
                return json.loads(value)
201 1
            return value
202
203 1
        options.logger_decorators = _parse_json(options.logger_decorators)
204 1
        options.napps_pre_installed = _parse_json(options.napps_pre_installed)
205 1
        options.vlan_pool = _parse_json(options.vlan_pool)
206 1
        options.authenticate_urls = _parse_json(options.authenticate_urls)
207 1
        thread_pool_max_workers = options.thread_pool_max_workers
208 1
        options.thread_pool_max_workers = _parse_json(thread_pool_max_workers)
209
210 1
        return options
211
212
213 1
def _render_config_templates(templates,
214
                             destination=Path(__file__).parent,
215
                             **kwargs):
216
    """Create a config file based on a template file.
217
218
    If no destination is passed, the new conf file will be created on the
219
    directory of the template file.
220
221
    Args:
222
        template (string):    Path of the template file
223
        destination (string): Directory in which the config file will
224
                              be placed.
225
    """
226 1
    if str(kwargs['prefix']) != '/':
227 1
        kwargs['prefix'] = Path(str(kwargs['prefix']).rstrip('/'))
228 1
    kwargs['jwt_secret'] = uuid.uuid4().hex
229
230
    # Create the paths used by Kytos.
231 1
    directories = [os.path.join(BASE_ENV, ETC_KYTOS)]
232 1
    for directory in directories:
233 1
        os.makedirs(directory, exist_ok=True)
234
235 1
    tmpl_path = Path(os.path.abspath(os.path.dirname(__file__))).parent
236
237 1
    for tmpl in templates:
238 1
        path = os.path.join(tmpl_path, tmpl)
239 1
        with open(path, 'r', encoding='utf-8') as src_file:
240 1
            content = Template(src_file.read()).render(**kwargs)
241 1
            tmpl = tmpl.replace('templates', ETC_KYTOS) \
242
                       .replace('.template', '')
243 1
            dst_path = Path(destination) / tmpl
244 1
            with open(dst_path, 'w') as dst_file:
245
                dst_file.write(content)
246