Passed
Pull Request — master (#263)
by Gleyberson
01:23
created

kytos.utils.config   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Test Coverage

Coverage 51.16%

Importance

Changes 0
Metric Value
eloc 101
dl 0
loc 164
ccs 44
cts 86
cp 0.5116
rs 10
c 0
b 0
f 0
wmc 23

9 Methods

Rating   Name   Duplication   Size   Complexity  
A KytosConfig.clear_token() 0 16 2
A KytosConfig.set_env_or_defaults() 0 26 4
A KytosConfig.log_configs() 0 4 2
A KytosConfig.check_versions() 0 16 4
A KytosConfig.save_token() 0 18 2
A KytosConfig.__init__() 0 26 4
A KytosConfig.get_metadata() 0 7 1
A KytosConfig.check_sections() 0 7 3
A KytosConfig.get_remote_metadata() 0 8 1
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
from collections import namedtuple
14 1
from configparser import ConfigParser
15 1
from urllib.error import URLError
16 1
from urllib.request import urlopen
17
18 1
LOG = logging.getLogger(__name__)
19
20
21 1
class KytosConfig():
22
    """Kytos Configs.
23
24
    Read the config file for kytos utils and/or request data for the user in
25
    order to get the correct paths and links.
26
    """
27
28 1
    def __init__(self, config_file='~/.kytosrc'):
29
        """Init method.
30
31
        Receive the config_file as argument.
32
        """
33 1
        self.config_file = os.path.expanduser(config_file)
34 1
        self.debug = False
35 1
        if self.debug:
36
            LOG.setLevel(logging.DEBUG)
37
38
        # allow_no_value=True is used to keep the comments on the config file.
39 1
        self.config = ConfigParser(allow_no_value=True)
40
41
        # Parse the config file. If no config file was found, then create some
42
        # default sections on the config variable.
43 1
        self.config.read(self.config_file)
44 1
        self.check_sections(self.config)
45
46 1
        self.set_env_or_defaults()
47
48 1
        if not os.path.exists(self.config_file):
49 1
            LOG.warning("Config file %s not found.", self.config_file)
50 1
            LOG.warning("Creating a new empty config file.")
51 1
            with open(self.config_file, 'w') as output_file:
52 1
                os.chmod(self.config_file, 0o0600)
53 1
                self.config.write(output_file)
54
55 1
    def log_configs(self):
56
        """Log the read configs if debug is enabled."""
57
        for sec in self.config.sections():
58
            LOG.debug('   %s: %s', sec, self.config.options(sec))
59
60 1
    def set_env_or_defaults(self):
61
        """Read some environment variables and set them on the config.
62
63
        If no environment variable is found and the config section/key is
64
        empty, then set some default values.
65
        """
66 1
        option = namedtuple('Option', ['section', 'name', 'env_var',
67
                                       'default_value'])
68
69 1
        options = [option('auth', 'user', 'NAPPS_USER', None),
70
                   option('auth', 'token', 'NAPPS_TOKEN', None),
71
                   option('napps', 'api', 'NAPPS_API_URI',
72
                          'https://napps.kytos.io/api/'),
73
                   option('napps', 'repo', 'NAPPS_REPO_URI',
74
                          'https://napps.kytos.io/repo'),
75
                   option('kytos', 'api', 'KYTOS_API',
76
                          'http://localhost:8181/')]
77
78 1
        for option in options:
79 1
            if not self.config.has_option(option.section, option.name):
80 1
                env_value = os.environ.get(option.env_var,
81
                                           option.default_value)
82 1
                if env_value:
83 1
                    self.config.set(option.section, option.name, env_value)
84
85 1
        self.config.set('global', 'debug', str(self.debug))
86
87 1
    @staticmethod
88
    def check_sections(config):
89
        """Create a empty config file."""
90 1
        default_sections = ['global', 'auth', 'napps', 'kytos']
91 1
        for section in default_sections:
92 1
            if not config.has_section(section):
93 1
                config.add_section(section)
94
95 1
    def save_token(self, user, token):
96
        """Save the token on the config file."""
97
        self.config.set('auth', 'user', user)
98
        self.config.set('auth', 'token', token)
99
        # allow_no_value=True is used to keep the comments on the config file.
100
        new_config = ConfigParser(allow_no_value=True)
101
102
        # Parse the config file. If no config file was found, then create some
103
        # default sections on the config variable.
104
        new_config.read(self.config_file)
105
        self.check_sections(new_config)
106
107
        new_config.set('auth', 'user', user)
108
        new_config.set('auth', 'token', token)
109
        filename = os.path.expanduser(self.config_file)
110
        with open(filename, 'w') as out_file:
111
            os.chmod(filename, 0o0600)
112
            new_config.write(out_file)
113
114 1
    def clear_token(self):
115
        """Clear Token information on config file."""
116
        # allow_no_value=True is used to keep the comments on the config file.
117
        new_config = ConfigParser(allow_no_value=True)
118
119
        # Parse the config file. If no config file was found, then create some
120
        # default sections on the config variable.
121
        new_config.read(self.config_file)
122
        self.check_sections(new_config)
123
124
        new_config.remove_option('auth', 'user')
125
        new_config.remove_option('auth', 'token')
126
        filename = os.path.expanduser(self.config_file)
127
        with open(filename, 'w') as out_file:
128
            os.chmod(filename, 0o0600)
129
            new_config.write(out_file)
130
131 1
    @classmethod
132
    def get_metadata(cls):
133
        """Return kytos-utils metadata."""
134
        meta_path = ("%s/metadata.py" % os.path.dirname(__file__))
135
        meta_file = open(meta_path).read()
136
        metadata = dict(re.findall(r"(__[a-z]+__)\s*=\s*'([^']+)'", meta_file))
137
        return metadata
138
139 1
    @classmethod
140
    def get_remote_metadata(cls):
141
        """Return kytos metadata."""
142
        kytos_api = KytosConfig().config.get('kytos', 'api')
143
        meta_uri = kytos_api + 'api/kytos/core/metadata/'
144
        meta_file = urlopen(meta_uri).read()
145
        metadata = json.loads(meta_file)
146
        return metadata
147
148 1
    @classmethod
149
    def check_versions(cls):
150
        """Check if kytos and kytos-utils metadata are compatible."""
151
        try:
152
            kytos_metadata = cls.get_remote_metadata()
153
            kytos_version = kytos_metadata.get('__version__')
154
        except URLError as exc:
155
            LOG.debug('Couldn\'t connect to kytos server: %s', exc)
156
        else:
157
            kutils_metadata = cls.get_metadata()
158
            kutils_version = kutils_metadata.get('__version__')
159
160
            if kytos_version != kutils_version:
161
                logger = logging.getLogger()
162
                logger.warning('kytos (%s) and kytos utils (%s) versions '
163
                               'are not equal.', kytos_version, kutils_version)
164