Passed
Pull Request — master (#269)
by Gleyberson
01:35
created

kytos.utils.config.KytosConfig.__init__()   A

Complexity

Conditions 4

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4.0039

Importance

Changes 0
Metric Value
cc 4
eloc 16
nop 2
dl 0
loc 27
ccs 15
cts 16
cp 0.9375
crap 4.0039
rs 9.6
c 0
b 0
f 0
1
"""Kytos utils configuration."""
2
# This file is part of kytos-utils.
3
#
4
# Copyright (c) 2016 Kytos Team
5
#
6
# Authors:
7
#    Beraldo Leal <beraldo AT ncc DOT unesp DOT br>
8
9 1
import json
10 1
import logging
11 1
import os
12 1
import re
13 1
import shutil
14 1
from collections import namedtuple
15 1
from configparser import ConfigParser
16 1
from pathlib import Path
17 1
from urllib.error import URLError
18 1
from urllib.request import urlopen
19
20 1
if 'VIRTUAL_ENV' in os.environ:
21 1
    BASE_ENV = os.environ['VIRTUAL_ENV']
22
else:
23
    BASE_ENV = '/'
24
25 1
ETC_KYTOS = 'etc/kytos'
26 1
KYTOS_SKEL_PATH = 'templates/skel'
27 1
LOG = logging.getLogger(__name__)
28
29
30 1
class KytosConfig():
31
    """Kytos Configs.
32
33
    Read the config file for kytos utils and/or request data for the user in
34
    order to get the correct paths and links.
35
    """
36
37 1
    def __init__(self, config_file='~/.kytosrc'):
38
        """Init method.
39
40
        Receive the config_file as argument.
41
        """
42 1
        self._create_data_files_directory()
43 1
        self.config_file = os.path.expanduser(config_file)
44 1
        self.debug = False
45 1
        if self.debug:
46
            LOG.setLevel(logging.DEBUG)
47
48
        # allow_no_value=True is used to keep the comments on the config file.
49 1
        self.config = ConfigParser(allow_no_value=True)
50
51
        # Parse the config file. If no config file was found, then create some
52
        # default sections on the config variable.
53 1
        self.config.read(self.config_file)
54 1
        self.check_sections(self.config)
55
56 1
        self.set_env_or_defaults()
57
58 1
        if not os.path.exists(self.config_file):
59 1
            LOG.warning("Config file %s not found.", self.config_file)
60 1
            LOG.warning("Creating a new empty config file.")
61 1
            with open(self.config_file, 'w') as output_file:
62 1
                os.chmod(self.config_file, 0o0600)
63 1
                self.config.write(output_file)
64
65 1
    @staticmethod
66
    def _create_data_files_directory():
67
        """Install data_files in the /etc directory."""
68 1
        parent_dir = Path(os.path.abspath(os.path.dirname(__file__))).parent
69
70 1
        etc_kytos = os.path.join(BASE_ENV, ETC_KYTOS)
71
72 1
        if not os.path.exists(etc_kytos):
73 1
            os.makedirs(etc_kytos)
74
75 1
        src = os.path.join(parent_dir, KYTOS_SKEL_PATH)
76 1
        skel = KYTOS_SKEL_PATH.replace('templates/', '')
77 1
        dst = os.path.join(BASE_ENV, ETC_KYTOS, skel)
78 1
        if os.path.exists(dst):
79 1
            if not os.listdir(dst):
80
                # Path already exists but it's empty, so we'll populate it
81
                # We remove it first to avoid an exception from copytree
82
                os.rmdir(dst)
83
        else:
84 1
            shutil.copytree(src, dst)
85
86 1
    def log_configs(self):
87
        """Log the read configs if debug is enabled."""
88
        for sec in self.config.sections():
89
            LOG.debug('   %s: %s', sec, self.config.options(sec))
90
91 1
    def set_env_or_defaults(self):
92
        """Read some environment variables and set them on the config.
93
94
        If no environment variable is found and the config section/key is
95
        empty, then set some default values.
96
        """
97 1
        option = namedtuple('Option', ['section', 'name', 'env_var',
98
                                       'default_value'])
99
100 1
        options = [option('auth', 'user', 'NAPPS_USER', None),
101
                   option('auth', 'token', 'NAPPS_TOKEN', None),
102
                   option('napps', 'api', 'NAPPS_API_URI',
103
                          'https://napps.kytos.io/api/'),
104
                   option('napps', 'repo', 'NAPPS_REPO_URI',
105
                          'https://napps.kytos.io/repo'),
106
                   option('kytos', 'api', 'KYTOS_API',
107
                          'http://localhost:8181/')]
108
109 1
        for option in options:
110 1
            if not self.config.has_option(option.section, option.name):
111 1
                env_value = os.environ.get(option.env_var,
112
                                           option.default_value)
113 1
                if env_value:
114 1
                    self.config.set(option.section, option.name, env_value)
115
116 1
        self.config.set('global', 'debug', str(self.debug))
117
118 1
    @staticmethod
119
    def check_sections(config):
120
        """Create a empty config file."""
121 1
        default_sections = ['global', 'auth', 'napps', 'kytos']
122 1
        for section in default_sections:
123 1
            if not config.has_section(section):
124 1
                config.add_section(section)
125
126 1
    def save_token(self, user, token):
127
        """Save the token on the config file."""
128
        self.config.set('auth', 'user', user)
129
        self.config.set('auth', 'token', token)
130
        # allow_no_value=True is used to keep the comments on the config file.
131
        new_config = ConfigParser(allow_no_value=True)
132
133
        # Parse the config file. If no config file was found, then create some
134
        # default sections on the config variable.
135
        new_config.read(self.config_file)
136
        self.check_sections(new_config)
137
138
        new_config.set('auth', 'user', user)
139
        new_config.set('auth', 'token', token)
140
        filename = os.path.expanduser(self.config_file)
141
        with open(filename, 'w') as out_file:
142
            os.chmod(filename, 0o0600)
143
            new_config.write(out_file)
144
145 1
    def clear_token(self):
146
        """Clear Token information on config file."""
147
        # allow_no_value=True is used to keep the comments on the config file.
148
        new_config = ConfigParser(allow_no_value=True)
149
150
        # Parse the config file. If no config file was found, then create some
151
        # default sections on the config variable.
152
        new_config.read(self.config_file)
153
        self.check_sections(new_config)
154
155
        new_config.remove_option('auth', 'user')
156
        new_config.remove_option('auth', 'token')
157
        filename = os.path.expanduser(self.config_file)
158
        with open(filename, 'w') as out_file:
159
            os.chmod(filename, 0o0600)
160
            new_config.write(out_file)
161
162 1
    @classmethod
163
    def get_metadata(cls):
164
        """Return kytos-utils metadata."""
165
        meta_path = ("%s/metadata.py" % os.path.dirname(__file__))
166
        meta_file = open(meta_path).read()
167
        metadata = dict(re.findall(r"(__[a-z]+__)\s*=\s*'([^']+)'", meta_file))
168
        return metadata
169
170 1
    @classmethod
171
    def get_remote_metadata(cls):
172
        """Return kytos metadata."""
173
        kytos_api = KytosConfig().config.get('kytos', 'api')
174
        meta_uri = kytos_api + 'api/kytos/core/metadata/'
175
        meta_file = urlopen(meta_uri).read()
176
        metadata = json.loads(meta_file)
177
        return metadata
178
179 1
    @classmethod
180
    def check_versions(cls):
181
        """Check if kytos and kytos-utils metadata are compatible."""
182
        try:
183
            kytos_metadata = cls.get_remote_metadata()
184
            kytos_version = kytos_metadata.get('__version__')
185
        except URLError as exc:
186
            LOG.debug('Couldn\'t connect to kytos server: %s', exc)
187
        else:
188
            kutils_metadata = cls.get_metadata()
189
            kutils_version = kutils_metadata.get('__version__')
190
191
            if kytos_version != kutils_version:
192
                logger = logging.getLogger()
193
                logger.warning('kytos (%s) and kytos utils (%s) versions '
194
                               'are not equal.', kytos_version, kutils_version)
195