kytos.utils.config.KytosConfig.get_metadata()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

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