Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / config.py @ f5ff79d9

History | View | Annotate | Download (14 kB)

1 e3f01d64 Stavros Sachtouris
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 7493ccb6 Stavros Sachtouris
#
3 7493ccb6 Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 7493ccb6 Stavros Sachtouris
# without modification, are permitted provided that the following
5 7493ccb6 Stavros Sachtouris
# conditions are met:
6 7493ccb6 Stavros Sachtouris
#
7 7493ccb6 Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 7493ccb6 Stavros Sachtouris
#      disclaimer.
10 7493ccb6 Stavros Sachtouris
#
11 7493ccb6 Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 7493ccb6 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 7493ccb6 Stavros Sachtouris
#      provided with the distribution.
15 7493ccb6 Stavros Sachtouris
#
16 7493ccb6 Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7493ccb6 Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7493ccb6 Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7493ccb6 Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7493ccb6 Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7493ccb6 Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7493ccb6 Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7493ccb6 Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7493ccb6 Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7493ccb6 Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7493ccb6 Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7493ccb6 Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 7493ccb6 Stavros Sachtouris
#
29 7493ccb6 Stavros Sachtouris
# The views and conclusions contained in the software and
30 7493ccb6 Stavros Sachtouris
# documentation are those of the authors and should not be
31 7493ccb6 Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 7493ccb6 Stavros Sachtouris
# or implied, of GRNET S.A.
33 7493ccb6 Stavros Sachtouris
34 7493ccb6 Stavros Sachtouris
import os
35 3f0eae61 Stavros Sachtouris
from logging import getLogger
36 7493ccb6 Stavros Sachtouris
37 7493ccb6 Stavros Sachtouris
from collections import defaultdict
38 29be4062 Stavros Sachtouris
from ConfigParser import RawConfigParser, NoOptionError, NoSectionError, Error
39 3f0eae61 Stavros Sachtouris
from re import match
40 7493ccb6 Stavros Sachtouris
41 ce9ccb40 Stavros Sachtouris
from kamaki.cli.errors import CLISyntaxError
42 144b3551 Stavros Sachtouris
from kamaki import __version__
43 ce9ccb40 Stavros Sachtouris
44 7493ccb6 Stavros Sachtouris
try:
45 7493ccb6 Stavros Sachtouris
    from collections import OrderedDict
46 7493ccb6 Stavros Sachtouris
except ImportError:
47 1792ed1d Stavros Sachtouris
    from kamaki.clients.utils.ordereddict import OrderedDict
48 7493ccb6 Stavros Sachtouris
49 7493ccb6 Stavros Sachtouris
50 29be4062 Stavros Sachtouris
class InvalidCloudNameError(Error):
51 a624a072 Stavros Sachtouris
    """A valid cloud name is accepted by this regex: ([~@#$:-\w]+)"""
52 29be4062 Stavros Sachtouris
53 29be4062 Stavros Sachtouris
54 3f0eae61 Stavros Sachtouris
log = getLogger(__name__)
55 3f0eae61 Stavros Sachtouris
56 7493ccb6 Stavros Sachtouris
# Path to the file that stores the configuration
57 7493ccb6 Stavros Sachtouris
CONFIG_PATH = os.path.expanduser('~/.kamakirc')
58 9f1d1fcf Stavros Sachtouris
HISTORY_PATH = os.path.expanduser('~/.kamaki.history')
59 6144f3d4 Stavros Sachtouris
CLOUD_PREFIX = 'cloud'
60 7493ccb6 Stavros Sachtouris
61 7493ccb6 Stavros Sachtouris
# Name of a shell variable to bypass the CONFIG_PATH value
62 7493ccb6 Stavros Sachtouris
CONFIG_ENV = 'KAMAKI_CONFIG'
63 7493ccb6 Stavros Sachtouris
64 144b3551 Stavros Sachtouris
version = ''
65 144b3551 Stavros Sachtouris
for c in '%s' % __version__:
66 144b3551 Stavros Sachtouris
    if c not in '0.123456789':
67 144b3551 Stavros Sachtouris
        break
68 144b3551 Stavros Sachtouris
    version += c
69 c825ddc9 Stavros Sachtouris
HEADER = '# Kamaki configuration file v%s\n' % version
70 7493ccb6 Stavros Sachtouris
71 7493ccb6 Stavros Sachtouris
DEFAULTS = {
72 7493ccb6 Stavros Sachtouris
    'global': {
73 144b3551 Stavros Sachtouris
        'default_cloud': '',
74 4f6a21f6 Stavros Sachtouris
        'colors': 'off',
75 edf00ab3 Stavros Sachtouris
        'log_file': os.path.expanduser('~/.kamaki.log'),
76 c5b9380c Stavros Sachtouris
        'log_token': 'off',
77 c5b9380c Stavros Sachtouris
        'log_data': 'off',
78 64a3c0de Stavros Sachtouris
        'log_pid': 'off',
79 05e144e2 Stavros Sachtouris
        'max_threads': 7,
80 3f0eae61 Stavros Sachtouris
        'history_file': HISTORY_PATH,
81 3f0eae61 Stavros Sachtouris
        'user_cli': 'astakos',
82 3f0eae61 Stavros Sachtouris
        'file_cli': 'pithos',
83 3f0eae61 Stavros Sachtouris
        'server_cli': 'cyclades',
84 3f0eae61 Stavros Sachtouris
        'flavor_cli': 'cyclades',
85 3f0eae61 Stavros Sachtouris
        'network_cli': 'cyclades',
86 3f0eae61 Stavros Sachtouris
        'image_cli': 'image',
87 3f0eae61 Stavros Sachtouris
        'config_cli': 'config',
88 3f0eae61 Stavros Sachtouris
        'history_cli': 'history'
89 f5c28bfa Stavros Sachtouris
        #  Optional command specs:
90 ce9ccb40 Stavros Sachtouris
        #  'livetest_cli': 'livetest',
91 ce9ccb40 Stavros Sachtouris
        #  'astakos_cli': 'snf-astakos'
92 320aac17 Stavros Sachtouris
        #  'floating_cli': 'cyclades'
93 7493ccb6 Stavros Sachtouris
    },
94 6144f3d4 Stavros Sachtouris
    CLOUD_PREFIX:
95 3f0eae61 Stavros Sachtouris
    {
96 144b3551 Stavros Sachtouris
        #'default': {
97 144b3551 Stavros Sachtouris
        #    'url': '',
98 144b3551 Stavros Sachtouris
        #    'token': ''
99 144b3551 Stavros Sachtouris
        #    'pithos_type': 'object-store',
100 144b3551 Stavros Sachtouris
        #    'pithos_version': 'v1',
101 144b3551 Stavros Sachtouris
        #    'cyclades_type': 'compute',
102 144b3551 Stavros Sachtouris
        #    'cyclades_version': 'v2.0',
103 144b3551 Stavros Sachtouris
        #    'plankton_type': 'image',
104 144b3551 Stavros Sachtouris
        #    'plankton_version': '',
105 144b3551 Stavros Sachtouris
        #    'astakos_type': 'identity',
106 144b3551 Stavros Sachtouris
        #    'astakos_version': 'v2.0'
107 144b3551 Stavros Sachtouris
        #}
108 7493ccb6 Stavros Sachtouris
    }
109 7493ccb6 Stavros Sachtouris
}
110 7493ccb6 Stavros Sachtouris
111 7493ccb6 Stavros Sachtouris
112 e1c18867 Stavros Sachtouris
try:
113 e1c18867 Stavros Sachtouris
    import astakosclient
114 fa382f9e Stavros Sachtouris
    DEFAULTS['global'].update(dict(astakos_cli='snf-astakos'))
115 e1c18867 Stavros Sachtouris
except ImportError:
116 e1c18867 Stavros Sachtouris
    pass
117 e1c18867 Stavros Sachtouris
118 e1c18867 Stavros Sachtouris
119 7493ccb6 Stavros Sachtouris
class Config(RawConfigParser):
120 3f0eae61 Stavros Sachtouris
    def __init__(self, path=None, with_defaults=True):
121 7493ccb6 Stavros Sachtouris
        RawConfigParser.__init__(self, dict_type=OrderedDict)
122 7493ccb6 Stavros Sachtouris
        self.path = path or os.environ.get(CONFIG_ENV, CONFIG_PATH)
123 7493ccb6 Stavros Sachtouris
        self._overrides = defaultdict(dict)
124 3f0eae61 Stavros Sachtouris
        if with_defaults:
125 3f0eae61 Stavros Sachtouris
            self._load_defaults()
126 7493ccb6 Stavros Sachtouris
        self.read(self.path)
127 7493ccb6 Stavros Sachtouris
128 ce9ccb40 Stavros Sachtouris
        for section in self.sections():
129 144b3551 Stavros Sachtouris
            r = self._cloud_name(section)
130 ce9ccb40 Stavros Sachtouris
            if r:
131 ce9ccb40 Stavros Sachtouris
                for k, v in self.items(section):
132 144b3551 Stavros Sachtouris
                    self.set_cloud(r, k, v)
133 ce9ccb40 Stavros Sachtouris
                self.remove_section(section)
134 14b9a185 Stavros Sachtouris
135 3f0eae61 Stavros Sachtouris
    @staticmethod
136 144b3551 Stavros Sachtouris
    def _cloud_name(full_section_name):
137 29be4062 Stavros Sachtouris
        if not full_section_name.startswith(CLOUD_PREFIX + ' '):
138 29be4062 Stavros Sachtouris
            return None
139 a624a072 Stavros Sachtouris
        matcher = match(CLOUD_PREFIX + ' "([~@#$:\-\w]+)"', full_section_name)
140 29be4062 Stavros Sachtouris
        if matcher:
141 29be4062 Stavros Sachtouris
            return matcher.groups()[0]
142 29be4062 Stavros Sachtouris
        else:
143 29be4062 Stavros Sachtouris
            icn = full_section_name[len(CLOUD_PREFIX) + 1:]
144 29be4062 Stavros Sachtouris
            raise InvalidCloudNameError('Invalid Cloud Name %s' % icn)
145 3f0eae61 Stavros Sachtouris
146 14b9a185 Stavros Sachtouris
    def rescue_old_file(self):
147 ce9ccb40 Stavros Sachtouris
        lost_terms = []
148 ce9ccb40 Stavros Sachtouris
        global_terms = DEFAULTS['global'].keys()
149 ce9ccb40 Stavros Sachtouris
        translations = dict(
150 ce9ccb40 Stavros Sachtouris
            config=dict(serv='', cmd='config'),
151 ce9ccb40 Stavros Sachtouris
            history=dict(serv='', cmd='history'),
152 ce9ccb40 Stavros Sachtouris
            pithos=dict(serv='pithos', cmd='file'),
153 ce9ccb40 Stavros Sachtouris
            file=dict(serv='pithos', cmd='file'),
154 ce9ccb40 Stavros Sachtouris
            store=dict(serv='pithos', cmd='file'),
155 ce9ccb40 Stavros Sachtouris
            storage=dict(serv='pithos', cmd='file'),
156 ce9ccb40 Stavros Sachtouris
            image=dict(serv='plankton', cmd='image'),
157 ce9ccb40 Stavros Sachtouris
            plankton=dict(serv='plankton', cmd='image'),
158 ce9ccb40 Stavros Sachtouris
            compute=dict(serv='compute', cmd=''),
159 ce9ccb40 Stavros Sachtouris
            cyclades=dict(serv='compute', cmd='server'),
160 ce9ccb40 Stavros Sachtouris
            server=dict(serv='compute', cmd='server'),
161 ce9ccb40 Stavros Sachtouris
            flavor=dict(serv='compute', cmd='flavor'),
162 ce9ccb40 Stavros Sachtouris
            network=dict(serv='compute', cmd='network'),
163 ce9ccb40 Stavros Sachtouris
            astakos=dict(serv='astakos', cmd='user'),
164 ce9ccb40 Stavros Sachtouris
            user=dict(serv='astakos', cmd='user'),
165 ce9ccb40 Stavros Sachtouris
        )
166 ce9ccb40 Stavros Sachtouris
167 6144f3d4 Stavros Sachtouris
        self.set('global', 'default_' + CLOUD_PREFIX, 'default')
168 ce9ccb40 Stavros Sachtouris
        for s in self.sections():
169 ce9ccb40 Stavros Sachtouris
            if s in ('global'):
170 ce9ccb40 Stavros Sachtouris
                # global.url, global.token -->
171 144b3551 Stavros Sachtouris
                # cloud.default.url, cloud.default.token
172 ce9ccb40 Stavros Sachtouris
                for term in set(self.keys(s)).difference(global_terms):
173 ce9ccb40 Stavros Sachtouris
                    if term not in ('url', 'token'):
174 ce9ccb40 Stavros Sachtouris
                        lost_terms.append('%s.%s = %s' % (
175 ce9ccb40 Stavros Sachtouris
                            s, term, self.get(s, term)))
176 ce9ccb40 Stavros Sachtouris
                        self.remove_option(s, term)
177 ce9ccb40 Stavros Sachtouris
                        continue
178 ce9ccb40 Stavros Sachtouris
                    gval = self.get(s, term)
179 c825ddc9 Stavros Sachtouris
                    try:
180 c825ddc9 Stavros Sachtouris
                        cval = self.get_cloud('default', term)
181 c825ddc9 Stavros Sachtouris
                    except KeyError:
182 c825ddc9 Stavros Sachtouris
                        cval = ''
183 ce9ccb40 Stavros Sachtouris
                    if gval and cval and (
184 ce9ccb40 Stavros Sachtouris
                        gval.lower().strip('/') != cval.lower().strip('/')):
185 ce9ccb40 Stavros Sachtouris
                            raise CLISyntaxError(
186 ce9ccb40 Stavros Sachtouris
                                'Conflicting values for default %s' % term,
187 ce9ccb40 Stavros Sachtouris
                                importance=2, details=[
188 ce9ccb40 Stavros Sachtouris
                                    ' global.%s:  %s' % (term, gval),
189 6144f3d4 Stavros Sachtouris
                                    ' %s.default.%s:  %s' % (
190 6144f3d4 Stavros Sachtouris
                                        CLOUD_PREFIX, term, cval),
191 ce9ccb40 Stavros Sachtouris
                                    'Please remove one of them manually:',
192 ce9ccb40 Stavros Sachtouris
                                    ' /config delete global.%s' % term,
193 ce9ccb40 Stavros Sachtouris
                                    ' or'
194 6144f3d4 Stavros Sachtouris
                                    ' /config delete %s.default.%s' % (
195 6144f3d4 Stavros Sachtouris
                                        CLOUD_PREFIX, term),
196 ce9ccb40 Stavros Sachtouris
                                    'and try again'])
197 ce9ccb40 Stavros Sachtouris
                    elif gval:
198 6144f3d4 Stavros Sachtouris
                        print('... rescue %s.%s => %s.default.%s' % (
199 6144f3d4 Stavros Sachtouris
                            s, term, CLOUD_PREFIX, term))
200 144b3551 Stavros Sachtouris
                        self.set_cloud('default', term, gval)
201 ce9ccb40 Stavros Sachtouris
                    self.remove_option(s, term)
202 ce9ccb40 Stavros Sachtouris
            # translation for <service> or <command> settings
203 ce9ccb40 Stavros Sachtouris
            # <service> or <command group> settings --> translation --> global
204 ce9ccb40 Stavros Sachtouris
            elif s in translations:
205 ce9ccb40 Stavros Sachtouris
206 ce9ccb40 Stavros Sachtouris
                if s in ('history',):
207 ce9ccb40 Stavros Sachtouris
                    k = 'file'
208 ce9ccb40 Stavros Sachtouris
                    v = self.get(s, k)
209 ce9ccb40 Stavros Sachtouris
                    if v:
210 ce9ccb40 Stavros Sachtouris
                        print('... rescue %s.%s => global.%s_%s' % (
211 ce9ccb40 Stavros Sachtouris
                            s, k, s, k))
212 ce9ccb40 Stavros Sachtouris
                        self.set('global', '%s_%s' % (s, k), v)
213 ce9ccb40 Stavros Sachtouris
                        self.remove_option(s, k)
214 ce9ccb40 Stavros Sachtouris
215 ce9ccb40 Stavros Sachtouris
                trn = translations[s]
216 ce9ccb40 Stavros Sachtouris
                for k, v in self.items(s, False):
217 ce9ccb40 Stavros Sachtouris
                    if v and k in ('cli',):
218 ce9ccb40 Stavros Sachtouris
                        print('... rescue %s.%s => global.%s_cli' % (
219 ce9ccb40 Stavros Sachtouris
                            s, k, trn['cmd']))
220 144b3551 Stavros Sachtouris
                        self.set('global', '%s_cli' % trn['cmd'], v)
221 144b3551 Stavros Sachtouris
                    elif k in ('container',) and trn['serv'] in ('pithos',):
222 6144f3d4 Stavros Sachtouris
                        print('... rescue %s.%s => %s.default.pithos_%s' % (
223 6144f3d4 Stavros Sachtouris
                                    s, k, CLOUD_PREFIX, k))
224 144b3551 Stavros Sachtouris
                        self.set_cloud('default', 'pithos_%s' % k, v)
225 144b3551 Stavros Sachtouris
                    else:
226 ce9ccb40 Stavros Sachtouris
                        lost_terms.append('%s.%s = %s' % (s, k, v))
227 ce9ccb40 Stavros Sachtouris
                self.remove_section(s)
228 ce9ccb40 Stavros Sachtouris
        #  self.pretty_print()
229 ce9ccb40 Stavros Sachtouris
        return lost_terms
230 ce9ccb40 Stavros Sachtouris
231 ce9ccb40 Stavros Sachtouris
    def pretty_print(self):
232 ce9ccb40 Stavros Sachtouris
        for s in self.sections():
233 ce9ccb40 Stavros Sachtouris
            print s
234 ce9ccb40 Stavros Sachtouris
            for k, v in self.items(s):
235 ce9ccb40 Stavros Sachtouris
                if isinstance(v, dict):
236 ce9ccb40 Stavros Sachtouris
                    print '\t', k, '=> {'
237 ce9ccb40 Stavros Sachtouris
                    for ki, vi in v.items():
238 ce9ccb40 Stavros Sachtouris
                        print '\t\t', ki, '=>', vi
239 ce9ccb40 Stavros Sachtouris
                    print('\t}')
240 ce9ccb40 Stavros Sachtouris
                else:
241 ce9ccb40 Stavros Sachtouris
                    print '\t', k, '=>', v
242 14b9a185 Stavros Sachtouris
243 3f0eae61 Stavros Sachtouris
    def guess_version(self):
244 144b3551 Stavros Sachtouris
        """
245 144b3551 Stavros Sachtouris
        :returns: (float) version of the config file or 0.0 if unrecognized
246 144b3551 Stavros Sachtouris
        """
247 3f0eae61 Stavros Sachtouris
        checker = Config(self.path, with_defaults=False)
248 3f0eae61 Stavros Sachtouris
        sections = checker.sections()
249 144b3551 Stavros Sachtouris
        log.warning('Config file heuristic 1: old global section ?')
250 3f0eae61 Stavros Sachtouris
        if 'global' in sections:
251 3f0eae61 Stavros Sachtouris
            if checker.get('global', 'url') or checker.get('global', 'token'):
252 3f0eae61 Stavros Sachtouris
                log.warning('..... config file has an old global section')
253 c825ddc9 Stavros Sachtouris
                return 0.8
254 14b9a185 Stavros Sachtouris
        log.warning('........ nope')
255 df0045d8 Stavros Sachtouris
        log.warning('Config file heuristic 2: Any cloud sections ?')
256 6144f3d4 Stavros Sachtouris
        if CLOUD_PREFIX in sections:
257 6144f3d4 Stavros Sachtouris
            for r in self.keys(CLOUD_PREFIX):
258 144b3551 Stavros Sachtouris
                log.warning('... found cloud "%s"' % r)
259 c825ddc9 Stavros Sachtouris
                return 0.9
260 df0045d8 Stavros Sachtouris
        log.warning('........ nope')
261 3f0eae61 Stavros Sachtouris
        log.warning('All heuristics failed, cannot decide')
262 df0045d8 Stavros Sachtouris
        return 0.9
263 3f0eae61 Stavros Sachtouris
264 144b3551 Stavros Sachtouris
    def get_cloud(self, cloud, option):
265 ce9ccb40 Stavros Sachtouris
        """
266 144b3551 Stavros Sachtouris
        :param cloud: (str) cloud alias
267 ce9ccb40 Stavros Sachtouris

268 144b3551 Stavros Sachtouris
        :param option: (str) option in cloud section
269 ce9ccb40 Stavros Sachtouris

270 ce9ccb40 Stavros Sachtouris
        :returns: (str) the value assigned on this option
271 ce9ccb40 Stavros Sachtouris

272 144b3551 Stavros Sachtouris
        :raises KeyError: if cloud or cloud's option does not exist
273 ce9ccb40 Stavros Sachtouris
        """
274 6144f3d4 Stavros Sachtouris
        r = self.get(CLOUD_PREFIX, cloud)
275 ce9ccb40 Stavros Sachtouris
        if not r:
276 144b3551 Stavros Sachtouris
            raise KeyError('Cloud "%s" does not exist' % cloud)
277 ce9ccb40 Stavros Sachtouris
        return r[option]
278 ce9ccb40 Stavros Sachtouris
279 362adf50 Stavros Sachtouris
    def get_global(self, option):
280 362adf50 Stavros Sachtouris
        return self.get('global', option)
281 362adf50 Stavros Sachtouris
282 144b3551 Stavros Sachtouris
    def set_cloud(self, cloud, option, value):
283 ce9ccb40 Stavros Sachtouris
        try:
284 6144f3d4 Stavros Sachtouris
            d = self.get(CLOUD_PREFIX, cloud) or dict()
285 ce9ccb40 Stavros Sachtouris
        except KeyError:
286 844a6bdb Stavros Sachtouris
            d = dict()
287 ce9ccb40 Stavros Sachtouris
        d[option] = value
288 6144f3d4 Stavros Sachtouris
        self.set(CLOUD_PREFIX, cloud, d)
289 362adf50 Stavros Sachtouris
290 362adf50 Stavros Sachtouris
    def set_global(self, option, value):
291 362adf50 Stavros Sachtouris
        self.set('global', option, value)
292 ce9ccb40 Stavros Sachtouris
293 7493ccb6 Stavros Sachtouris
    def _load_defaults(self):
294 7493ccb6 Stavros Sachtouris
        for section, options in DEFAULTS.items():
295 7493ccb6 Stavros Sachtouris
            for option, val in options.items():
296 7493ccb6 Stavros Sachtouris
                self.set(section, option, val)
297 7493ccb6 Stavros Sachtouris
298 f724cd35 Stavros Sachtouris
    def _get_dict(self, section, include_defaults=True):
299 f724cd35 Stavros Sachtouris
        try:
300 f724cd35 Stavros Sachtouris
            d = dict(DEFAULTS[section]) if include_defaults else {}
301 f724cd35 Stavros Sachtouris
        except KeyError:
302 f724cd35 Stavros Sachtouris
            d = {}
303 f724cd35 Stavros Sachtouris
        try:
304 f724cd35 Stavros Sachtouris
            d.update(RawConfigParser.items(self, section))
305 f724cd35 Stavros Sachtouris
        except NoSectionError:
306 f724cd35 Stavros Sachtouris
            pass
307 f724cd35 Stavros Sachtouris
        return d
308 f724cd35 Stavros Sachtouris
309 8eb8c540 Stavros Sachtouris
    def reload(self):
310 8eb8c540 Stavros Sachtouris
        self = self.__init__(self.path)
311 8eb8c540 Stavros Sachtouris
312 7493ccb6 Stavros Sachtouris
    def get(self, section, option):
313 114e19da Stavros Sachtouris
        """
314 144b3551 Stavros Sachtouris
        :param section: (str) HINT: for clouds, use cloud.<section>
315 114e19da Stavros Sachtouris

316 114e19da Stavros Sachtouris
        :param option: (str)
317 114e19da Stavros Sachtouris

318 114e19da Stavros Sachtouris
        :returns: (str) the value stored at section: {option: value}
319 114e19da Stavros Sachtouris
        """
320 7493ccb6 Stavros Sachtouris
        value = self._overrides.get(section, {}).get(option)
321 7493ccb6 Stavros Sachtouris
        if value is not None:
322 7493ccb6 Stavros Sachtouris
            return value
323 6144f3d4 Stavros Sachtouris
        prefix = CLOUD_PREFIX + '.'
324 144b3551 Stavros Sachtouris
        if section.startswith(prefix):
325 144b3551 Stavros Sachtouris
            return self.get_cloud(section[len(prefix):], option)
326 7493ccb6 Stavros Sachtouris
        try:
327 7493ccb6 Stavros Sachtouris
            return RawConfigParser.get(self, section, option)
328 7493ccb6 Stavros Sachtouris
        except (NoSectionError, NoOptionError):
329 7493ccb6 Stavros Sachtouris
            return DEFAULTS.get(section, {}).get(option)
330 7493ccb6 Stavros Sachtouris
331 7493ccb6 Stavros Sachtouris
    def set(self, section, option, value):
332 114e19da Stavros Sachtouris
        """
333 144b3551 Stavros Sachtouris
        :param section: (str) HINT: for remotes use cloud.<section>
334 114e19da Stavros Sachtouris

335 114e19da Stavros Sachtouris
        :param option: (str)
336 114e19da Stavros Sachtouris

337 114e19da Stavros Sachtouris
        :param value: str
338 114e19da Stavros Sachtouris
        """
339 6144f3d4 Stavros Sachtouris
        prefix = CLOUD_PREFIX + '.'
340 144b3551 Stavros Sachtouris
        if section.startswith(prefix):
341 29be4062 Stavros Sachtouris
            cloud = self._cloud_name(
342 29be4062 Stavros Sachtouris
                CLOUD_PREFIX + ' "' + section[len(prefix):] + '"')
343 29be4062 Stavros Sachtouris
            return self.set_cloud(cloud, option, value)
344 7493ccb6 Stavros Sachtouris
        if section not in RawConfigParser.sections(self):
345 7493ccb6 Stavros Sachtouris
            self.add_section(section)
346 7493ccb6 Stavros Sachtouris
        RawConfigParser.set(self, section, option, value)
347 7493ccb6 Stavros Sachtouris
348 3fe56be4 Stavros Sachtouris
    def remove_option(self, section, option, also_remove_default=False):
349 7493ccb6 Stavros Sachtouris
        try:
350 3fe56be4 Stavros Sachtouris
            if also_remove_default:
351 3fe56be4 Stavros Sachtouris
                DEFAULTS[section].pop(option)
352 7493ccb6 Stavros Sachtouris
            RawConfigParser.remove_option(self, section, option)
353 7493ccb6 Stavros Sachtouris
        except NoSectionError:
354 7493ccb6 Stavros Sachtouris
            pass
355 7493ccb6 Stavros Sachtouris
356 a7aacf12 Stavros Sachtouris
    def remove_from_cloud(self, cloud, option):
357 6144f3d4 Stavros Sachtouris
        d = self.get(CLOUD_PREFIX, cloud)
358 844a6bdb Stavros Sachtouris
        if isinstance(d, dict):
359 844a6bdb Stavros Sachtouris
            d.pop(option)
360 844a6bdb Stavros Sachtouris
361 f724cd35 Stavros Sachtouris
    def keys(self, section, include_defaults=True):
362 f724cd35 Stavros Sachtouris
        d = self._get_dict(section, include_defaults)
363 f724cd35 Stavros Sachtouris
        return d.keys()
364 f724cd35 Stavros Sachtouris
365 57ecec97 Stavros Sachtouris
    def items(self, section, include_defaults=True):
366 f724cd35 Stavros Sachtouris
        d = self._get_dict(section, include_defaults)
367 7493ccb6 Stavros Sachtouris
        return d.items()
368 7493ccb6 Stavros Sachtouris
369 7493ccb6 Stavros Sachtouris
    def override(self, section, option, value):
370 7493ccb6 Stavros Sachtouris
        self._overrides[section][option] = value
371 7493ccb6 Stavros Sachtouris
372 7493ccb6 Stavros Sachtouris
    def write(self):
373 35d47a6c Stavros Sachtouris
        cld_bu = self._get_dict(CLOUD_PREFIX)
374 6144f3d4 Stavros Sachtouris
        try:
375 6144f3d4 Stavros Sachtouris
            for r, d in self.items(CLOUD_PREFIX):
376 6144f3d4 Stavros Sachtouris
                for k, v in d.items():
377 6144f3d4 Stavros Sachtouris
                    self.set(CLOUD_PREFIX + ' "%s"' % r, k, v)
378 6144f3d4 Stavros Sachtouris
            self.remove_section(CLOUD_PREFIX)
379 6144f3d4 Stavros Sachtouris
380 6144f3d4 Stavros Sachtouris
            with open(self.path, 'w') as f:
381 6144f3d4 Stavros Sachtouris
                os.chmod(self.path, 0600)
382 6144f3d4 Stavros Sachtouris
                f.write(HEADER.lstrip())
383 6144f3d4 Stavros Sachtouris
                f.flush()
384 6144f3d4 Stavros Sachtouris
                RawConfigParser.write(self, f)
385 6144f3d4 Stavros Sachtouris
        finally:
386 6144f3d4 Stavros Sachtouris
            if CLOUD_PREFIX not in self.sections():
387 6144f3d4 Stavros Sachtouris
                self.add_section(CLOUD_PREFIX)
388 35d47a6c Stavros Sachtouris
            for cloud, d in cld_bu.items():
389 35d47a6c Stavros Sachtouris
                self.set(CLOUD_PREFIX, cloud, d)