Passed
Push — master ( ac1107...683d2f )
by Humberto
01:59 queued 11s
created

kytos.core.config._render_config_templates()   B

Complexity

Conditions 7

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 20
nop 3
dl 0
loc 34
ccs 17
cts 17
cp 1
crap 7
rs 8
c 0
b 0
f 0
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
        self.conf_parser, self.parser = conf_parser, parser
92 1
        self.parse_args()
93
94 1
    def parse_args(self):
95
        """Get the command line options and update kytos settings.
96
97
        When installed via pip, defaults values are:
98
99
        .. code-block:: python
100
101
            defaults = {'pidfile': '/var/run/kytos/kytosd.pid',
102
                        'workdir': '/var/lib/kytos',
103
                        'napps': '/var/lib/kytos/napps/',
104
                        'conf': '/etc/kytos/kytos.conf',
105
                        'logging': '/etc/kytos/logging.ini',
106
                        'listen': '0.0.0.0',
107
                        'port': 6653,
108
                        'foreground': False,
109
                        'protocol_name': '',
110
                        'enable_entities_by_default': False,
111
                        'debug': False}
112
113
        """
114 1
        defaults = {'pidfile': os.path.join(BASE_ENV,
115
                                            'var/run/kytos/kytosd.pid'),
116
                    'workdir': os.path.join(BASE_ENV, 'var/lib/kytos'),
117
                    'napps': os.path.join(BASE_ENV, 'var/lib/kytos/napps/'),
118
                    'napps_repositories': "['https://napps.kytos.io/repo/']",
119
                    'installed_napps': os.path.join(BASE_ENV,
120
                                                    'var/lib/kytos/napps/',
121
                                                    '.installed'),
122
                    'conf': os.path.join(BASE_ENV, 'etc/kytos/kytos.conf'),
123
                    'logging': os.path.join(BASE_ENV, 'etc/kytos/logging.ini'),
124
                    'listen': '0.0.0.0',
125
                    'port': 6653,
126
                    'foreground': False,
127
                    'protocol_name': '',
128
                    'enable_entities_by_default': False,
129
                    'napps_pre_installed': [],
130
                    'vlan_pool': {},
131
                    'debug': False}
132
133 1
        options, argv = self.conf_parser.parse_known_args()
134
135 1
        config = ConfigParser()
136
137 1
        config_file = options.conf or defaults.get('conf')
138
139 1
        if not os.path.exists(config_file):
140 1
            _render_config_templates(TEMPLATE_FILES, BASE_ENV,
141
                                     prefix=BASE_ENV,
142
                                     syslog_args=SYSLOG_ARGS)
143
144 1
        config.read(config_file)
145
146 1
        defaults.update(dict(config.items("daemon")))
147
148 1
        self.parser.set_defaults(**defaults)
149
150 1
        self.options['daemon'] = self._parse_options(argv)
151
152 1
    def _parse_options(self, argv):
153
        """Create a Namespace using the given argv.
154
155
        Args:
156
            argv(dict): Python Dict used to create the namespace.
157
158
        Returns:
159
            options(Namespace): Namespace with the args given
160
161
        """
162 1
        options, unknown = self.parser.parse_known_args(argv)
163 1
        if unknown:
164
            warnings.warn(f"Unknown arguments: {unknown}")
165 1
        options.napps_repositories = json.loads(options.napps_repositories)
166 1
        options.debug = True if options.debug in ['True', True] else False
167 1
        options.daemon = True if options.daemon in ['True', True] else False
168 1
        options.port = int(options.port)
169 1
        options.api_port = int(options.api_port)
170 1
        options.protocol_name = str(options.protocol_name)
171
172 1
        result = options.enable_entities_by_default in ['True', True]
173 1
        options.enable_entities_by_default = result
174
175 1
        if isinstance(options.napps_pre_installed, str):
176 1
            napps = options.napps_pre_installed
177 1
            options.napps_pre_installed = json.loads(napps)
178
179 1
        return options
180
181
182 1
def _render_config_templates(templates,
183
                             destination=Path(__file__).parent,
184
                             **kwargs):
185
    """Create a config file based on a template file.
186
187
    If no destination is passed, the new conf file will be created on the
188
    directory of the template file.
189
190
    Args:
191
        template (string):    Path of the template file
192
        destination (string): Directory in which the config file will
193
                              be placed.
194
    """
195 1
    if str(kwargs['prefix']) != '/':
196 1
        kwargs['prefix'] = Path(str(kwargs['prefix']).rstrip('/'))
197 1
    kwargs['jwt_secret'] = uuid.uuid4().hex
198
199
    # Create the paths used by Kytos.
200 1
    directories = [os.path.join(BASE_ENV, ETC_KYTOS)]
201 1
    for directory in directories:
202 1
        if not os.path.exists(directory):
203 1
            os.makedirs(directory)
204
205 1
    tmpl_path = Path(os.path.abspath(os.path.dirname(__file__))).parent
206
207 1
    for tmpl in templates:
208 1
        path = os.path.join(tmpl_path, tmpl)
209 1
        with open(path, 'r', encoding='utf-8') as src_file:
210 1
            content = Template(src_file.read()).render(**kwargs)
211 1
            tmpl = tmpl.replace('templates', ETC_KYTOS) \
212
                       .replace('.template', '')
213 1
            dst_path = Path(destination) / tmpl
214 1
            with open(dst_path, 'w') as dst_file:
215
                dst_file.write(content)
216