Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / config.py @ 362adf50

History | View | Annotate | Download (11.8 kB)

1 7493ccb6 Stavros Sachtouris
# Copyright 2011-2012 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 7493ccb6 Stavros Sachtouris
from ConfigParser import RawConfigParser, NoOptionError, NoSectionError
39 3f0eae61 Stavros Sachtouris
from re import match
40 7493ccb6 Stavros Sachtouris
41 ce9ccb40 Stavros Sachtouris
from kamaki.cli.errors import CLISyntaxError
42 ce9ccb40 Stavros Sachtouris
43 7493ccb6 Stavros Sachtouris
try:
44 7493ccb6 Stavros Sachtouris
    from collections import OrderedDict
45 7493ccb6 Stavros Sachtouris
except ImportError:
46 1792ed1d Stavros Sachtouris
    from kamaki.clients.utils.ordereddict import OrderedDict
47 7493ccb6 Stavros Sachtouris
48 7493ccb6 Stavros Sachtouris
49 3f0eae61 Stavros Sachtouris
log = getLogger(__name__)
50 3f0eae61 Stavros Sachtouris
51 7493ccb6 Stavros Sachtouris
# Path to the file that stores the configuration
52 7493ccb6 Stavros Sachtouris
CONFIG_PATH = os.path.expanduser('~/.kamakirc')
53 9f1d1fcf Stavros Sachtouris
HISTORY_PATH = os.path.expanduser('~/.kamaki.history')
54 7493ccb6 Stavros Sachtouris
55 7493ccb6 Stavros Sachtouris
# Name of a shell variable to bypass the CONFIG_PATH value
56 7493ccb6 Stavros Sachtouris
CONFIG_ENV = 'KAMAKI_CONFIG'
57 7493ccb6 Stavros Sachtouris
58 7493ccb6 Stavros Sachtouris
HEADER = """
59 f5c28bfa Stavros Sachtouris
# Kamaki configuration file v3 (kamaki >= v0.9)
60 7493ccb6 Stavros Sachtouris
"""
61 7493ccb6 Stavros Sachtouris
62 7493ccb6 Stavros Sachtouris
DEFAULTS = {
63 7493ccb6 Stavros Sachtouris
    'global': {
64 4f6a21f6 Stavros Sachtouris
        'colors': 'off',
65 edf00ab3 Stavros Sachtouris
        'log_file': os.path.expanduser('~/.kamaki.log'),
66 c5b9380c Stavros Sachtouris
        'log_token': 'off',
67 c5b9380c Stavros Sachtouris
        'log_data': 'off',
68 05e144e2 Stavros Sachtouris
        'max_threads': 7,
69 3f0eae61 Stavros Sachtouris
        'history_file': HISTORY_PATH,
70 3f0eae61 Stavros Sachtouris
        'user_cli': 'astakos',
71 3f0eae61 Stavros Sachtouris
        'file_cli': 'pithos',
72 3f0eae61 Stavros Sachtouris
        'server_cli': 'cyclades',
73 3f0eae61 Stavros Sachtouris
        'flavor_cli': 'cyclades',
74 3f0eae61 Stavros Sachtouris
        'network_cli': 'cyclades',
75 3f0eae61 Stavros Sachtouris
        'image_cli': 'image',
76 3f0eae61 Stavros Sachtouris
        'config_cli': 'config',
77 3f0eae61 Stavros Sachtouris
        'history_cli': 'history'
78 f5c28bfa Stavros Sachtouris
        #  Optional command specs:
79 ce9ccb40 Stavros Sachtouris
        #  'livetest_cli': 'livetest',
80 ce9ccb40 Stavros Sachtouris
        #  'astakos_cli': 'snf-astakos'
81 7493ccb6 Stavros Sachtouris
    },
82 362adf50 Stavros Sachtouris
    'remote':
83 3f0eae61 Stavros Sachtouris
    {
84 3f0eae61 Stavros Sachtouris
        'default': {
85 3f0eae61 Stavros Sachtouris
            'url': '',
86 3f0eae61 Stavros Sachtouris
            'token': ''
87 3f0eae61 Stavros Sachtouris
            #'pithos_type': 'object-store',
88 3f0eae61 Stavros Sachtouris
            #'pithos_version': 'v1',
89 3f0eae61 Stavros Sachtouris
            #'cyclades_type': 'compute',
90 3f0eae61 Stavros Sachtouris
            #'cyclades_version': 'v2.0',
91 3f0eae61 Stavros Sachtouris
            #'plankton_type': 'image',
92 3f0eae61 Stavros Sachtouris
            #'plankton_version': '',
93 3f0eae61 Stavros Sachtouris
            #'astakos_type': 'identity',
94 3f0eae61 Stavros Sachtouris
            #'astakos_version': 'v2.0'
95 3f0eae61 Stavros Sachtouris
        }
96 7493ccb6 Stavros Sachtouris
    }
97 7493ccb6 Stavros Sachtouris
}
98 7493ccb6 Stavros Sachtouris
99 7493ccb6 Stavros Sachtouris
100 7493ccb6 Stavros Sachtouris
class Config(RawConfigParser):
101 3f0eae61 Stavros Sachtouris
    def __init__(self, path=None, with_defaults=True):
102 7493ccb6 Stavros Sachtouris
        RawConfigParser.__init__(self, dict_type=OrderedDict)
103 7493ccb6 Stavros Sachtouris
        self.path = path or os.environ.get(CONFIG_ENV, CONFIG_PATH)
104 7493ccb6 Stavros Sachtouris
        self._overrides = defaultdict(dict)
105 3f0eae61 Stavros Sachtouris
        if with_defaults:
106 3f0eae61 Stavros Sachtouris
            self._load_defaults()
107 7493ccb6 Stavros Sachtouris
        self.read(self.path)
108 7493ccb6 Stavros Sachtouris
109 ce9ccb40 Stavros Sachtouris
        for section in self.sections():
110 ce9ccb40 Stavros Sachtouris
            r = self._remote_name(section)
111 ce9ccb40 Stavros Sachtouris
            if r:
112 ce9ccb40 Stavros Sachtouris
                for k, v in self.items(section):
113 ce9ccb40 Stavros Sachtouris
                    self.set_remote(r, k, v)
114 ce9ccb40 Stavros Sachtouris
                self.remove_section(section)
115 14b9a185 Stavros Sachtouris
116 3f0eae61 Stavros Sachtouris
    @staticmethod
117 3f0eae61 Stavros Sachtouris
    def _remote_name(full_section_name):
118 3f0eae61 Stavros Sachtouris
        matcher = match('remote "(\w+)"', full_section_name)
119 3f0eae61 Stavros Sachtouris
        return matcher.groups()[0] if matcher else None
120 3f0eae61 Stavros Sachtouris
121 14b9a185 Stavros Sachtouris
    def rescue_old_file(self):
122 ce9ccb40 Stavros Sachtouris
        lost_terms = []
123 ce9ccb40 Stavros Sachtouris
        global_terms = DEFAULTS['global'].keys()
124 ce9ccb40 Stavros Sachtouris
        translations = dict(
125 ce9ccb40 Stavros Sachtouris
            config=dict(serv='', cmd='config'),
126 ce9ccb40 Stavros Sachtouris
            history=dict(serv='', cmd='history'),
127 ce9ccb40 Stavros Sachtouris
            pithos=dict(serv='pithos', cmd='file'),
128 ce9ccb40 Stavros Sachtouris
            file=dict(serv='pithos', cmd='file'),
129 ce9ccb40 Stavros Sachtouris
            store=dict(serv='pithos', cmd='file'),
130 ce9ccb40 Stavros Sachtouris
            storage=dict(serv='pithos', cmd='file'),
131 ce9ccb40 Stavros Sachtouris
            image=dict(serv='plankton', cmd='image'),
132 ce9ccb40 Stavros Sachtouris
            plankton=dict(serv='plankton', cmd='image'),
133 ce9ccb40 Stavros Sachtouris
            compute=dict(serv='compute', cmd=''),
134 ce9ccb40 Stavros Sachtouris
            cyclades=dict(serv='compute', cmd='server'),
135 ce9ccb40 Stavros Sachtouris
            server=dict(serv='compute', cmd='server'),
136 ce9ccb40 Stavros Sachtouris
            flavor=dict(serv='compute', cmd='flavor'),
137 ce9ccb40 Stavros Sachtouris
            network=dict(serv='compute', cmd='network'),
138 ce9ccb40 Stavros Sachtouris
            astakos=dict(serv='astakos', cmd='user'),
139 ce9ccb40 Stavros Sachtouris
            user=dict(serv='astakos', cmd='user'),
140 ce9ccb40 Stavros Sachtouris
        )
141 ce9ccb40 Stavros Sachtouris
142 ce9ccb40 Stavros Sachtouris
        for s in self.sections():
143 ce9ccb40 Stavros Sachtouris
            if s in ('global'):
144 ce9ccb40 Stavros Sachtouris
                # global.url, global.token -->
145 ce9ccb40 Stavros Sachtouris
                # remote.default.url, remote.default.token
146 ce9ccb40 Stavros Sachtouris
                for term in set(self.keys(s)).difference(global_terms):
147 ce9ccb40 Stavros Sachtouris
                    if term not in ('url', 'token'):
148 ce9ccb40 Stavros Sachtouris
                        lost_terms.append('%s.%s = %s' % (
149 ce9ccb40 Stavros Sachtouris
                            s, term, self.get(s, term)))
150 ce9ccb40 Stavros Sachtouris
                        self.remove_option(s, term)
151 ce9ccb40 Stavros Sachtouris
                        continue
152 ce9ccb40 Stavros Sachtouris
                    gval = self.get(s, term)
153 ce9ccb40 Stavros Sachtouris
                    cval = self.get_remote('default', term)
154 ce9ccb40 Stavros Sachtouris
                    if gval and cval and (
155 ce9ccb40 Stavros Sachtouris
                        gval.lower().strip('/') != cval.lower().strip('/')):
156 ce9ccb40 Stavros Sachtouris
                            raise CLISyntaxError(
157 ce9ccb40 Stavros Sachtouris
                                'Conflicting values for default %s' % term,
158 ce9ccb40 Stavros Sachtouris
                                importance=2, details=[
159 ce9ccb40 Stavros Sachtouris
                                    ' global.%s:  %s' % (term, gval),
160 ce9ccb40 Stavros Sachtouris
                                    ' remote.default.%s:  %s' % (term, cval),
161 ce9ccb40 Stavros Sachtouris
                                    'Please remove one of them manually:',
162 ce9ccb40 Stavros Sachtouris
                                    ' /config delete global.%s' % term,
163 ce9ccb40 Stavros Sachtouris
                                    ' or'
164 ce9ccb40 Stavros Sachtouris
                                    ' /config delete remote.default.%s' % term,
165 ce9ccb40 Stavros Sachtouris
                                    'and try again'])
166 ce9ccb40 Stavros Sachtouris
                    elif gval:
167 ce9ccb40 Stavros Sachtouris
                        print('... rescue %s.%s => remote.default.%s' % (
168 ce9ccb40 Stavros Sachtouris
                            s, term, term))
169 ce9ccb40 Stavros Sachtouris
                        self.set_remote('default', term, gval)
170 ce9ccb40 Stavros Sachtouris
                    self.remove_option(s, term)
171 ce9ccb40 Stavros Sachtouris
            # translation for <service> or <command> settings
172 ce9ccb40 Stavros Sachtouris
            # <service> or <command group> settings --> translation --> global
173 ce9ccb40 Stavros Sachtouris
            elif s in translations:
174 ce9ccb40 Stavros Sachtouris
175 ce9ccb40 Stavros Sachtouris
                if s in ('history',):
176 ce9ccb40 Stavros Sachtouris
                    k = 'file'
177 ce9ccb40 Stavros Sachtouris
                    v = self.get(s, k)
178 ce9ccb40 Stavros Sachtouris
                    if v:
179 ce9ccb40 Stavros Sachtouris
                        print('... rescue %s.%s => global.%s_%s' % (
180 ce9ccb40 Stavros Sachtouris
                            s, k, s, k))
181 ce9ccb40 Stavros Sachtouris
                        self.set('global', '%s_%s' % (s, k), v)
182 ce9ccb40 Stavros Sachtouris
                        self.remove_option(s, k)
183 ce9ccb40 Stavros Sachtouris
184 ce9ccb40 Stavros Sachtouris
                trn = translations[s]
185 ce9ccb40 Stavros Sachtouris
                for k, v in self.items(s, False):
186 ce9ccb40 Stavros Sachtouris
                    if v and k in ('cli',):
187 ce9ccb40 Stavros Sachtouris
                        print('... rescue %s.%s => global.%s_cli' % (
188 ce9ccb40 Stavros Sachtouris
                            s, k, trn['cmd']))
189 ce9ccb40 Stavros Sachtouris
                        self.set('global', 'file_cli', v)
190 ce9ccb40 Stavros Sachtouris
                    elif v and k in ('url', 'token'):
191 ce9ccb40 Stavros Sachtouris
                        print(
192 ce9ccb40 Stavros Sachtouris
                            '... rescue %s.%s => remote.default.%s_%s' % (
193 ce9ccb40 Stavros Sachtouris
                                s, k, trn['serv'], k))
194 ce9ccb40 Stavros Sachtouris
                        self.set_remote('default', 'pithos_%s' % k, v)
195 ce9ccb40 Stavros Sachtouris
                    elif v:
196 ce9ccb40 Stavros Sachtouris
                        lost_terms.append('%s.%s = %s' % (s, k, v))
197 ce9ccb40 Stavros Sachtouris
                self.remove_section(s)
198 ce9ccb40 Stavros Sachtouris
        #  self.pretty_print()
199 ce9ccb40 Stavros Sachtouris
        return lost_terms
200 ce9ccb40 Stavros Sachtouris
201 ce9ccb40 Stavros Sachtouris
    def pretty_print(self):
202 ce9ccb40 Stavros Sachtouris
        for s in self.sections():
203 ce9ccb40 Stavros Sachtouris
            print s
204 ce9ccb40 Stavros Sachtouris
            for k, v in self.items(s):
205 ce9ccb40 Stavros Sachtouris
                if isinstance(v, dict):
206 ce9ccb40 Stavros Sachtouris
                    print '\t', k, '=> {'
207 ce9ccb40 Stavros Sachtouris
                    for ki, vi in v.items():
208 ce9ccb40 Stavros Sachtouris
                        print '\t\t', ki, '=>', vi
209 ce9ccb40 Stavros Sachtouris
                    print('\t}')
210 ce9ccb40 Stavros Sachtouris
                else:
211 ce9ccb40 Stavros Sachtouris
                    print '\t', k, '=>', v
212 14b9a185 Stavros Sachtouris
213 3f0eae61 Stavros Sachtouris
    def guess_version(self):
214 3f0eae61 Stavros Sachtouris
        checker = Config(self.path, with_defaults=False)
215 3f0eae61 Stavros Sachtouris
        sections = checker.sections()
216 3f0eae61 Stavros Sachtouris
        log.warning('Config file heuristic 1: global section ?')
217 3f0eae61 Stavros Sachtouris
        if 'global' in sections:
218 3f0eae61 Stavros Sachtouris
            if checker.get('global', 'url') or checker.get('global', 'token'):
219 3f0eae61 Stavros Sachtouris
                log.warning('..... config file has an old global section')
220 14b9a185 Stavros Sachtouris
                return 2.0
221 14b9a185 Stavros Sachtouris
        log.warning('........ nope')
222 3f0eae61 Stavros Sachtouris
        log.warning('Config file heuristic 2: at least 1 remote section ?')
223 362adf50 Stavros Sachtouris
        if 'remote' in sections:
224 362adf50 Stavros Sachtouris
            for r in self.keys('remote'):
225 ce9ccb40 Stavros Sachtouris
                log.warning('... found remote "%s"' % r)
226 14b9a185 Stavros Sachtouris
                return 3.0
227 14b9a185 Stavros Sachtouris
        log.warning('........ nope')
228 3f0eae61 Stavros Sachtouris
        log.warning('All heuristics failed, cannot decide')
229 14b9a185 Stavros Sachtouris
        return 0.0
230 3f0eae61 Stavros Sachtouris
231 ce9ccb40 Stavros Sachtouris
    def get_remote(self, remote, option):
232 ce9ccb40 Stavros Sachtouris
        """
233 ce9ccb40 Stavros Sachtouris
        :param remote: (str) remote cloud alias
234 ce9ccb40 Stavros Sachtouris

235 ce9ccb40 Stavros Sachtouris
        :param option: (str) option in remote cloud section
236 ce9ccb40 Stavros Sachtouris

237 ce9ccb40 Stavros Sachtouris
        :returns: (str) the value assigned on this option
238 ce9ccb40 Stavros Sachtouris

239 ce9ccb40 Stavros Sachtouris
        :raises KeyError: if remote or remote's option does not exist
240 ce9ccb40 Stavros Sachtouris
        """
241 362adf50 Stavros Sachtouris
        r = self.get('remote', remote)
242 ce9ccb40 Stavros Sachtouris
        if not r:
243 ce9ccb40 Stavros Sachtouris
            raise KeyError('Remote "%s" does not exist' % remote)
244 ce9ccb40 Stavros Sachtouris
        return r[option]
245 ce9ccb40 Stavros Sachtouris
246 362adf50 Stavros Sachtouris
    def get_global(self, option):
247 362adf50 Stavros Sachtouris
        return self.get('global', option)
248 362adf50 Stavros Sachtouris
249 ce9ccb40 Stavros Sachtouris
    def set_remote(self, remote, option, value):
250 ce9ccb40 Stavros Sachtouris
        try:
251 362adf50 Stavros Sachtouris
            d = self.get('remote', remote)
252 ce9ccb40 Stavros Sachtouris
        except KeyError:
253 ce9ccb40 Stavros Sachtouris
            pass
254 ce9ccb40 Stavros Sachtouris
        d[option] = value
255 362adf50 Stavros Sachtouris
        self.set('remote', remote, d)
256 362adf50 Stavros Sachtouris
257 362adf50 Stavros Sachtouris
    def set_global(self, option, value):
258 362adf50 Stavros Sachtouris
        self.set('global', option, value)
259 ce9ccb40 Stavros Sachtouris
260 7493ccb6 Stavros Sachtouris
    def _load_defaults(self):
261 7493ccb6 Stavros Sachtouris
        for section, options in DEFAULTS.items():
262 7493ccb6 Stavros Sachtouris
            for option, val in options.items():
263 7493ccb6 Stavros Sachtouris
                self.set(section, option, val)
264 7493ccb6 Stavros Sachtouris
265 f724cd35 Stavros Sachtouris
    def _get_dict(self, section, include_defaults=True):
266 f724cd35 Stavros Sachtouris
        try:
267 f724cd35 Stavros Sachtouris
            d = dict(DEFAULTS[section]) if include_defaults else {}
268 f724cd35 Stavros Sachtouris
        except KeyError:
269 f724cd35 Stavros Sachtouris
            d = {}
270 f724cd35 Stavros Sachtouris
        try:
271 f724cd35 Stavros Sachtouris
            d.update(RawConfigParser.items(self, section))
272 f724cd35 Stavros Sachtouris
        except NoSectionError:
273 f724cd35 Stavros Sachtouris
            pass
274 f724cd35 Stavros Sachtouris
        return d
275 f724cd35 Stavros Sachtouris
276 8eb8c540 Stavros Sachtouris
    def reload(self):
277 8eb8c540 Stavros Sachtouris
        self = self.__init__(self.path)
278 8eb8c540 Stavros Sachtouris
279 7493ccb6 Stavros Sachtouris
    def get(self, section, option):
280 7493ccb6 Stavros Sachtouris
        value = self._overrides.get(section, {}).get(option)
281 7493ccb6 Stavros Sachtouris
        if value is not None:
282 7493ccb6 Stavros Sachtouris
            return value
283 7493ccb6 Stavros Sachtouris
284 7493ccb6 Stavros Sachtouris
        try:
285 7493ccb6 Stavros Sachtouris
            return RawConfigParser.get(self, section, option)
286 7493ccb6 Stavros Sachtouris
        except (NoSectionError, NoOptionError):
287 7493ccb6 Stavros Sachtouris
            return DEFAULTS.get(section, {}).get(option)
288 7493ccb6 Stavros Sachtouris
289 7493ccb6 Stavros Sachtouris
    def set(self, section, option, value):
290 7493ccb6 Stavros Sachtouris
        if section not in RawConfigParser.sections(self):
291 7493ccb6 Stavros Sachtouris
            self.add_section(section)
292 7493ccb6 Stavros Sachtouris
        RawConfigParser.set(self, section, option, value)
293 7493ccb6 Stavros Sachtouris
294 3fe56be4 Stavros Sachtouris
    def remove_option(self, section, option, also_remove_default=False):
295 7493ccb6 Stavros Sachtouris
        try:
296 3fe56be4 Stavros Sachtouris
            if also_remove_default:
297 3fe56be4 Stavros Sachtouris
                DEFAULTS[section].pop(option)
298 7493ccb6 Stavros Sachtouris
            RawConfigParser.remove_option(self, section, option)
299 7493ccb6 Stavros Sachtouris
        except NoSectionError:
300 7493ccb6 Stavros Sachtouris
            pass
301 7493ccb6 Stavros Sachtouris
302 f724cd35 Stavros Sachtouris
    def keys(self, section, include_defaults=True):
303 f724cd35 Stavros Sachtouris
        d = self._get_dict(section, include_defaults)
304 f724cd35 Stavros Sachtouris
        return d.keys()
305 f724cd35 Stavros Sachtouris
306 57ecec97 Stavros Sachtouris
    def items(self, section, include_defaults=True):
307 f724cd35 Stavros Sachtouris
        d = self._get_dict(section, include_defaults)
308 7493ccb6 Stavros Sachtouris
        return d.items()
309 7493ccb6 Stavros Sachtouris
310 7493ccb6 Stavros Sachtouris
    def override(self, section, option, value):
311 7493ccb6 Stavros Sachtouris
        self._overrides[section][option] = value
312 7493ccb6 Stavros Sachtouris
313 7493ccb6 Stavros Sachtouris
    def write(self):
314 362adf50 Stavros Sachtouris
        for r, d in self.items('remote'):
315 ce9ccb40 Stavros Sachtouris
            for k, v in d.items():
316 ce9ccb40 Stavros Sachtouris
                self.set('remote "%s"' % r, k, v)
317 362adf50 Stavros Sachtouris
        self.remove_section('remote')
318 ce9ccb40 Stavros Sachtouris
319 7493ccb6 Stavros Sachtouris
        with open(self.path, 'w') as f:
320 7493ccb6 Stavros Sachtouris
            os.chmod(self.path, 0600)
321 7493ccb6 Stavros Sachtouris
            f.write(HEADER.lstrip())
322 8eb8c540 Stavros Sachtouris
            f.flush()
323 7493ccb6 Stavros Sachtouris
            RawConfigParser.write(self, f)