Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / config / __init__.py @ 534e7bbb

History | View | Annotate | Download (14.6 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 c5997814 Stavros Sachtouris
from sys import stdout, stderr
37 7493ccb6 Stavros Sachtouris
38 7493ccb6 Stavros Sachtouris
from collections import defaultdict
39 29be4062 Stavros Sachtouris
from ConfigParser import RawConfigParser, NoOptionError, NoSectionError, Error
40 3f0eae61 Stavros Sachtouris
from re import match
41 7493ccb6 Stavros Sachtouris
42 ce9ccb40 Stavros Sachtouris
from kamaki.cli.errors import CLISyntaxError
43 144b3551 Stavros Sachtouris
from kamaki import __version__
44 ce9ccb40 Stavros Sachtouris
45 7493ccb6 Stavros Sachtouris
try:
46 7493ccb6 Stavros Sachtouris
    from collections import OrderedDict
47 7493ccb6 Stavros Sachtouris
except ImportError:
48 1792ed1d Stavros Sachtouris
    from kamaki.clients.utils.ordereddict import OrderedDict
49 7493ccb6 Stavros Sachtouris
50 7493ccb6 Stavros Sachtouris
51 29be4062 Stavros Sachtouris
class InvalidCloudNameError(Error):
52 c5997814 Stavros Sachtouris
    """A valid cloud name must pass through this regex: ([~@#$:.-\w]+)"""
53 29be4062 Stavros Sachtouris
54 29be4062 Stavros Sachtouris
55 3f0eae61 Stavros Sachtouris
log = getLogger(__name__)
56 3f0eae61 Stavros Sachtouris
57 7493ccb6 Stavros Sachtouris
# Path to the file that stores the configuration
58 7493ccb6 Stavros Sachtouris
CONFIG_PATH = os.path.expanduser('~/.kamakirc')
59 9f1d1fcf Stavros Sachtouris
HISTORY_PATH = os.path.expanduser('~/.kamaki.history')
60 6144f3d4 Stavros Sachtouris
CLOUD_PREFIX = 'cloud'
61 7493ccb6 Stavros Sachtouris
62 7493ccb6 Stavros Sachtouris
# Name of a shell variable to bypass the CONFIG_PATH value
63 7493ccb6 Stavros Sachtouris
CONFIG_ENV = 'KAMAKI_CONFIG'
64 7493ccb6 Stavros Sachtouris
65 144b3551 Stavros Sachtouris
version = ''
66 144b3551 Stavros Sachtouris
for c in '%s' % __version__:
67 144b3551 Stavros Sachtouris
    if c not in '0.123456789':
68 144b3551 Stavros Sachtouris
        break
69 144b3551 Stavros Sachtouris
    version += c
70 c825ddc9 Stavros Sachtouris
HEADER = '# Kamaki configuration file v%s\n' % version
71 7493ccb6 Stavros Sachtouris
72 7493ccb6 Stavros Sachtouris
DEFAULTS = {
73 7493ccb6 Stavros Sachtouris
    'global': {
74 144b3551 Stavros Sachtouris
        'default_cloud': '',
75 4f6a21f6 Stavros Sachtouris
        'colors': 'off',
76 edf00ab3 Stavros Sachtouris
        'log_file': os.path.expanduser('~/.kamaki.log'),
77 c5b9380c Stavros Sachtouris
        'log_token': 'off',
78 c5b9380c Stavros Sachtouris
        'log_data': 'off',
79 64a3c0de Stavros Sachtouris
        'log_pid': 'off',
80 05e144e2 Stavros Sachtouris
        'max_threads': 7,
81 3f0eae61 Stavros Sachtouris
        'history_file': HISTORY_PATH,
82 3f0eae61 Stavros Sachtouris
        'user_cli': 'astakos',
83 3f0eae61 Stavros Sachtouris
        'file_cli': 'pithos',
84 3f0eae61 Stavros Sachtouris
        'server_cli': 'cyclades',
85 3f0eae61 Stavros Sachtouris
        'flavor_cli': 'cyclades',
86 3f0eae61 Stavros Sachtouris
        'network_cli': 'cyclades',
87 6489c38b Stavros Sachtouris
        'ip_cli': 'cyclades',
88 3f0eae61 Stavros Sachtouris
        'image_cli': 'image',
89 3f0eae61 Stavros Sachtouris
        'config_cli': 'config',
90 3f0eae61 Stavros Sachtouris
        'history_cli': 'history'
91 f5c28bfa Stavros Sachtouris
        #  Optional command specs:
92 ce9ccb40 Stavros Sachtouris
        #  'livetest_cli': 'livetest',
93 ce9ccb40 Stavros Sachtouris
        #  'astakos_cli': 'snf-astakos'
94 7493ccb6 Stavros Sachtouris
    },
95 9f5cbafe Stavros Sachtouris
    CLOUD_PREFIX: {
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 c5997814 Stavros Sachtouris
121 3f0eae61 Stavros Sachtouris
    def __init__(self, path=None, with_defaults=True):
122 7493ccb6 Stavros Sachtouris
        RawConfigParser.__init__(self, dict_type=OrderedDict)
123 7493ccb6 Stavros Sachtouris
        self.path = path or os.environ.get(CONFIG_ENV, CONFIG_PATH)
124 7493ccb6 Stavros Sachtouris
        self._overrides = defaultdict(dict)
125 3f0eae61 Stavros Sachtouris
        if with_defaults:
126 3f0eae61 Stavros Sachtouris
            self._load_defaults()
127 7493ccb6 Stavros Sachtouris
        self.read(self.path)
128 7493ccb6 Stavros Sachtouris
129 ce9ccb40 Stavros Sachtouris
        for section in self.sections():
130 144b3551 Stavros Sachtouris
            r = self._cloud_name(section)
131 ce9ccb40 Stavros Sachtouris
            if r:
132 ce9ccb40 Stavros Sachtouris
                for k, v in self.items(section):
133 144b3551 Stavros Sachtouris
                    self.set_cloud(r, k, v)
134 ce9ccb40 Stavros Sachtouris
                self.remove_section(section)
135 14b9a185 Stavros Sachtouris
136 3f0eae61 Stavros Sachtouris
    @staticmethod
137 144b3551 Stavros Sachtouris
    def _cloud_name(full_section_name):
138 29be4062 Stavros Sachtouris
        if not full_section_name.startswith(CLOUD_PREFIX + ' '):
139 29be4062 Stavros Sachtouris
            return None
140 c5997814 Stavros Sachtouris
        matcher = match(CLOUD_PREFIX + ' "([~@#$.:\-\w]+)"', full_section_name)
141 29be4062 Stavros Sachtouris
        if matcher:
142 29be4062 Stavros Sachtouris
            return matcher.groups()[0]
143 29be4062 Stavros Sachtouris
        else:
144 29be4062 Stavros Sachtouris
            icn = full_section_name[len(CLOUD_PREFIX) + 1:]
145 29be4062 Stavros Sachtouris
            raise InvalidCloudNameError('Invalid Cloud Name %s' % icn)
146 3f0eae61 Stavros Sachtouris
147 c5997814 Stavros Sachtouris
    def rescue_old_file(self, err=stderr):
148 ce9ccb40 Stavros Sachtouris
        lost_terms = []
149 ce9ccb40 Stavros Sachtouris
        global_terms = DEFAULTS['global'].keys()
150 ce9ccb40 Stavros Sachtouris
        translations = dict(
151 ce9ccb40 Stavros Sachtouris
            config=dict(serv='', cmd='config'),
152 ce9ccb40 Stavros Sachtouris
            history=dict(serv='', cmd='history'),
153 ce9ccb40 Stavros Sachtouris
            pithos=dict(serv='pithos', cmd='file'),
154 ce9ccb40 Stavros Sachtouris
            file=dict(serv='pithos', cmd='file'),
155 ce9ccb40 Stavros Sachtouris
            store=dict(serv='pithos', cmd='file'),
156 ce9ccb40 Stavros Sachtouris
            storage=dict(serv='pithos', cmd='file'),
157 ce9ccb40 Stavros Sachtouris
            image=dict(serv='plankton', cmd='image'),
158 ce9ccb40 Stavros Sachtouris
            plankton=dict(serv='plankton', cmd='image'),
159 ce9ccb40 Stavros Sachtouris
            compute=dict(serv='compute', cmd=''),
160 ce9ccb40 Stavros Sachtouris
            cyclades=dict(serv='compute', cmd='server'),
161 ce9ccb40 Stavros Sachtouris
            server=dict(serv='compute', cmd='server'),
162 ce9ccb40 Stavros Sachtouris
            flavor=dict(serv='compute', cmd='flavor'),
163 ce9ccb40 Stavros Sachtouris
            network=dict(serv='compute', cmd='network'),
164 ce9ccb40 Stavros Sachtouris
            astakos=dict(serv='astakos', cmd='user'),
165 ce9ccb40 Stavros Sachtouris
            user=dict(serv='astakos', cmd='user'),
166 ce9ccb40 Stavros Sachtouris
        )
167 ce9ccb40 Stavros Sachtouris
168 6144f3d4 Stavros Sachtouris
        self.set('global', 'default_' + CLOUD_PREFIX, 'default')
169 ce9ccb40 Stavros Sachtouris
        for s in self.sections():
170 c5997814 Stavros Sachtouris
            if s in ('global', ):
171 ce9ccb40 Stavros Sachtouris
                # global.url, global.token -->
172 144b3551 Stavros Sachtouris
                # cloud.default.url, cloud.default.token
173 ce9ccb40 Stavros Sachtouris
                for term in set(self.keys(s)).difference(global_terms):
174 ce9ccb40 Stavros Sachtouris
                    if term not in ('url', 'token'):
175 ce9ccb40 Stavros Sachtouris
                        lost_terms.append('%s.%s = %s' % (
176 ce9ccb40 Stavros Sachtouris
                            s, term, self.get(s, term)))
177 ce9ccb40 Stavros Sachtouris
                        self.remove_option(s, term)
178 ce9ccb40 Stavros Sachtouris
                        continue
179 ce9ccb40 Stavros Sachtouris
                    gval = self.get(s, term)
180 c5997814 Stavros Sachtouris
                    default_cloud = self.get(
181 c5997814 Stavros Sachtouris
                        'global', 'default_cloud') or 'default'
182 c825ddc9 Stavros Sachtouris
                    try:
183 c5997814 Stavros Sachtouris
                        cval = self.get_cloud(default_cloud, term)
184 c825ddc9 Stavros Sachtouris
                    except KeyError:
185 c825ddc9 Stavros Sachtouris
                        cval = ''
186 ce9ccb40 Stavros Sachtouris
                    if gval and cval and (
187 ce9ccb40 Stavros Sachtouris
                        gval.lower().strip('/') != cval.lower().strip('/')):
188 ce9ccb40 Stavros Sachtouris
                            raise CLISyntaxError(
189 c5997814 Stavros Sachtouris
                                'Conflicting values for default %s' % (
190 c5997814 Stavros Sachtouris
                                    term),
191 ce9ccb40 Stavros Sachtouris
                                importance=2, details=[
192 ce9ccb40 Stavros Sachtouris
                                    ' global.%s:  %s' % (term, gval),
193 c5997814 Stavros Sachtouris
                                    ' %s.%s.%s:  %s' % (
194 c5997814 Stavros Sachtouris
                                        CLOUD_PREFIX,
195 c5997814 Stavros Sachtouris
                                        default_cloud,
196 c5997814 Stavros Sachtouris
                                        term,
197 c5997814 Stavros Sachtouris
                                        cval),
198 ce9ccb40 Stavros Sachtouris
                                    'Please remove one of them manually:',
199 ce9ccb40 Stavros Sachtouris
                                    ' /config delete global.%s' % term,
200 ce9ccb40 Stavros Sachtouris
                                    ' or'
201 c5997814 Stavros Sachtouris
                                    ' /config delete %s.%s.%s' % (
202 c5997814 Stavros Sachtouris
                                        CLOUD_PREFIX, default_cloud, term),
203 ce9ccb40 Stavros Sachtouris
                                    'and try again'])
204 ce9ccb40 Stavros Sachtouris
                    elif gval:
205 c5997814 Stavros Sachtouris
                        err.write(u'... rescue %s.%s => %s.%s.%s\n' % (
206 c5997814 Stavros Sachtouris
                            s, term, CLOUD_PREFIX, default_cloud, term))
207 c5997814 Stavros Sachtouris
                        err.flush()
208 144b3551 Stavros Sachtouris
                        self.set_cloud('default', term, gval)
209 ce9ccb40 Stavros Sachtouris
                    self.remove_option(s, term)
210 ce9ccb40 Stavros Sachtouris
            # translation for <service> or <command> settings
211 ce9ccb40 Stavros Sachtouris
            # <service> or <command group> settings --> translation --> global
212 ce9ccb40 Stavros Sachtouris
            elif s in translations:
213 ce9ccb40 Stavros Sachtouris
214 ce9ccb40 Stavros Sachtouris
                if s in ('history',):
215 ce9ccb40 Stavros Sachtouris
                    k = 'file'
216 ce9ccb40 Stavros Sachtouris
                    v = self.get(s, k)
217 ce9ccb40 Stavros Sachtouris
                    if v:
218 c5997814 Stavros Sachtouris
                        err.write(u'... rescue %s.%s => global.%s_%s\n' % (
219 ce9ccb40 Stavros Sachtouris
                            s, k, s, k))
220 c5997814 Stavros Sachtouris
                        err.flush()
221 ce9ccb40 Stavros Sachtouris
                        self.set('global', '%s_%s' % (s, k), v)
222 ce9ccb40 Stavros Sachtouris
                        self.remove_option(s, k)
223 ce9ccb40 Stavros Sachtouris
224 ce9ccb40 Stavros Sachtouris
                trn = translations[s]
225 ce9ccb40 Stavros Sachtouris
                for k, v in self.items(s, False):
226 ce9ccb40 Stavros Sachtouris
                    if v and k in ('cli',):
227 c5997814 Stavros Sachtouris
                        err.write(u'... rescue %s.%s => global.%s_cli\n' % (
228 ce9ccb40 Stavros Sachtouris
                            s, k, trn['cmd']))
229 c5997814 Stavros Sachtouris
                        err.flush()
230 144b3551 Stavros Sachtouris
                        self.set('global', '%s_cli' % trn['cmd'], v)
231 144b3551 Stavros Sachtouris
                    elif k in ('container',) and trn['serv'] in ('pithos',):
232 c5997814 Stavros Sachtouris
                        err.write(
233 c5997814 Stavros Sachtouris
                            u'... rescue %s.%s => %s.default.pithos_%s\n' % (
234 c5997814 Stavros Sachtouris
                                s, k, CLOUD_PREFIX, k))
235 c5997814 Stavros Sachtouris
                        err.flush()
236 144b3551 Stavros Sachtouris
                        self.set_cloud('default', 'pithos_%s' % k, v)
237 144b3551 Stavros Sachtouris
                    else:
238 ce9ccb40 Stavros Sachtouris
                        lost_terms.append('%s.%s = %s' % (s, k, v))
239 ce9ccb40 Stavros Sachtouris
                self.remove_section(s)
240 ce9ccb40 Stavros Sachtouris
        #  self.pretty_print()
241 ce9ccb40 Stavros Sachtouris
        return lost_terms
242 ce9ccb40 Stavros Sachtouris
243 c5997814 Stavros Sachtouris
    def pretty_print(self, out=stdout):
244 ce9ccb40 Stavros Sachtouris
        for s in self.sections():
245 c5997814 Stavros Sachtouris
            out.write(s)
246 c5997814 Stavros Sachtouris
            out.flush()
247 ce9ccb40 Stavros Sachtouris
            for k, v in self.items(s):
248 ce9ccb40 Stavros Sachtouris
                if isinstance(v, dict):
249 c5997814 Stavros Sachtouris
                    out.write(u'\t%s => {\n' % k)
250 c5997814 Stavros Sachtouris
                    out.flush()
251 ce9ccb40 Stavros Sachtouris
                    for ki, vi in v.items():
252 c5997814 Stavros Sachtouris
                        out.write(u'\t\t%s => %s\n' % (ki, vi))
253 c5997814 Stavros Sachtouris
                        out.flush()
254 c5997814 Stavros Sachtouris
                    out.write(u'\t}\n')
255 ce9ccb40 Stavros Sachtouris
                else:
256 c5997814 Stavros Sachtouris
                    out.write(u'\t %s => %s\n' % (k, v))
257 c5997814 Stavros Sachtouris
                out.flush()
258 14b9a185 Stavros Sachtouris
259 3f0eae61 Stavros Sachtouris
    def guess_version(self):
260 144b3551 Stavros Sachtouris
        """
261 3564be49 Stavros Sachtouris
        :returns: (float) version of the config file or 0.9 if unrecognized
262 144b3551 Stavros Sachtouris
        """
263 3f0eae61 Stavros Sachtouris
        checker = Config(self.path, with_defaults=False)
264 3f0eae61 Stavros Sachtouris
        sections = checker.sections()
265 f1d06d74 Stavros Sachtouris
        log.debug('Config file heuristic 1: old global section ?')
266 3f0eae61 Stavros Sachtouris
        if 'global' in sections:
267 3f0eae61 Stavros Sachtouris
            if checker.get('global', 'url') or checker.get('global', 'token'):
268 f1d06d74 Stavros Sachtouris
                log.debug('..... config file has an old global section')
269 c825ddc9 Stavros Sachtouris
                return 0.8
270 f1d06d74 Stavros Sachtouris
        log.debug('........ nope')
271 f1d06d74 Stavros Sachtouris
        log.debug('Config file heuristic 2: Any cloud sections ?')
272 6144f3d4 Stavros Sachtouris
        if CLOUD_PREFIX in sections:
273 6144f3d4 Stavros Sachtouris
            for r in self.keys(CLOUD_PREFIX):
274 f1d06d74 Stavros Sachtouris
                log.debug('... found cloud "%s"' % r)
275 c825ddc9 Stavros Sachtouris
                return 0.9
276 f1d06d74 Stavros Sachtouris
        log.debug('........ nope')
277 f1d06d74 Stavros Sachtouris
        log.debug('All heuristics failed, cannot decide')
278 df0045d8 Stavros Sachtouris
        return 0.9
279 3f0eae61 Stavros Sachtouris
280 144b3551 Stavros Sachtouris
    def get_cloud(self, cloud, option):
281 ce9ccb40 Stavros Sachtouris
        """
282 144b3551 Stavros Sachtouris
        :param cloud: (str) cloud alias
283 ce9ccb40 Stavros Sachtouris

284 144b3551 Stavros Sachtouris
        :param option: (str) option in cloud section
285 ce9ccb40 Stavros Sachtouris

286 ce9ccb40 Stavros Sachtouris
        :returns: (str) the value assigned on this option
287 ce9ccb40 Stavros Sachtouris

288 144b3551 Stavros Sachtouris
        :raises KeyError: if cloud or cloud's option does not exist
289 ce9ccb40 Stavros Sachtouris
        """
290 6144f3d4 Stavros Sachtouris
        r = self.get(CLOUD_PREFIX, cloud)
291 ce9ccb40 Stavros Sachtouris
        if not r:
292 144b3551 Stavros Sachtouris
            raise KeyError('Cloud "%s" does not exist' % cloud)
293 ce9ccb40 Stavros Sachtouris
        return r[option]
294 ce9ccb40 Stavros Sachtouris
295 144b3551 Stavros Sachtouris
    def set_cloud(self, cloud, option, value):
296 ce9ccb40 Stavros Sachtouris
        try:
297 6144f3d4 Stavros Sachtouris
            d = self.get(CLOUD_PREFIX, cloud) or dict()
298 ce9ccb40 Stavros Sachtouris
        except KeyError:
299 844a6bdb Stavros Sachtouris
            d = dict()
300 ce9ccb40 Stavros Sachtouris
        d[option] = value
301 6144f3d4 Stavros Sachtouris
        self.set(CLOUD_PREFIX, cloud, d)
302 362adf50 Stavros Sachtouris
303 7493ccb6 Stavros Sachtouris
    def _load_defaults(self):
304 7493ccb6 Stavros Sachtouris
        for section, options in DEFAULTS.items():
305 7493ccb6 Stavros Sachtouris
            for option, val in options.items():
306 7493ccb6 Stavros Sachtouris
                self.set(section, option, val)
307 7493ccb6 Stavros Sachtouris
308 f724cd35 Stavros Sachtouris
    def _get_dict(self, section, include_defaults=True):
309 f724cd35 Stavros Sachtouris
        try:
310 f724cd35 Stavros Sachtouris
            d = dict(DEFAULTS[section]) if include_defaults else {}
311 f724cd35 Stavros Sachtouris
        except KeyError:
312 f724cd35 Stavros Sachtouris
            d = {}
313 f724cd35 Stavros Sachtouris
        try:
314 f724cd35 Stavros Sachtouris
            d.update(RawConfigParser.items(self, section))
315 f724cd35 Stavros Sachtouris
        except NoSectionError:
316 f724cd35 Stavros Sachtouris
            pass
317 f724cd35 Stavros Sachtouris
        return d
318 f724cd35 Stavros Sachtouris
319 8eb8c540 Stavros Sachtouris
    def reload(self):
320 8eb8c540 Stavros Sachtouris
        self = self.__init__(self.path)
321 8eb8c540 Stavros Sachtouris
322 7493ccb6 Stavros Sachtouris
    def get(self, section, option):
323 114e19da Stavros Sachtouris
        """
324 144b3551 Stavros Sachtouris
        :param section: (str) HINT: for clouds, use cloud.<section>
325 114e19da Stavros Sachtouris

326 114e19da Stavros Sachtouris
        :param option: (str)
327 114e19da Stavros Sachtouris

328 114e19da Stavros Sachtouris
        :returns: (str) the value stored at section: {option: value}
329 114e19da Stavros Sachtouris
        """
330 7493ccb6 Stavros Sachtouris
        value = self._overrides.get(section, {}).get(option)
331 7493ccb6 Stavros Sachtouris
        if value is not None:
332 7493ccb6 Stavros Sachtouris
            return value
333 6144f3d4 Stavros Sachtouris
        prefix = CLOUD_PREFIX + '.'
334 144b3551 Stavros Sachtouris
        if section.startswith(prefix):
335 144b3551 Stavros Sachtouris
            return self.get_cloud(section[len(prefix):], option)
336 7493ccb6 Stavros Sachtouris
        try:
337 7493ccb6 Stavros Sachtouris
            return RawConfigParser.get(self, section, option)
338 7493ccb6 Stavros Sachtouris
        except (NoSectionError, NoOptionError):
339 7493ccb6 Stavros Sachtouris
            return DEFAULTS.get(section, {}).get(option)
340 7493ccb6 Stavros Sachtouris
341 7493ccb6 Stavros Sachtouris
    def set(self, section, option, value):
342 114e19da Stavros Sachtouris
        """
343 144b3551 Stavros Sachtouris
        :param section: (str) HINT: for remotes use cloud.<section>
344 114e19da Stavros Sachtouris

345 114e19da Stavros Sachtouris
        :param option: (str)
346 114e19da Stavros Sachtouris

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