1# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
2# Copyright (c) 2011 Chris Moyer http://coredumped.org/
3#
4# Permission is hereby granted, free of charge, to any person obtaining a
5# copy of this software and associated documentation files (the
6# "Software"), to deal in the Software without restriction, including
7# without limitation the rights to use, copy, modify, merge, publish, dis-
8# tribute, sublicense, and/or sell copies of the Software, and to permit
9# persons to whom the Software is furnished to do so, subject to the fol-
10# lowing conditions:
11#
12# The above copyright notice and this permission notice shall be included
13# in all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21# IN THE SOFTWARE.
22#
23import os
24import re
25import warnings
26
27import boto
28
29from boto.compat import expanduser, ConfigParser, StringIO
30
31
32# By default we use two locations for the boto configurations,
33# /etc/boto.cfg and ~/.boto (which works on Windows and Unix).
34BotoConfigPath = '/etc/boto.cfg'
35BotoConfigLocations = [BotoConfigPath]
36UserConfigPath = os.path.join(expanduser('~'), '.boto')
37BotoConfigLocations.append(UserConfigPath)
38
39# If there's a BOTO_CONFIG variable set, we load ONLY
40# that variable
41if 'BOTO_CONFIG' in os.environ:
42    BotoConfigLocations = [expanduser(os.environ['BOTO_CONFIG'])]
43
44# If there's a BOTO_PATH variable set, we use anything there
45# as the current configuration locations, split with os.pathsep.
46elif 'BOTO_PATH' in os.environ:
47    BotoConfigLocations = []
48    for path in os.environ['BOTO_PATH'].split(os.pathsep):
49        BotoConfigLocations.append(expanduser(path))
50
51
52class Config(ConfigParser):
53
54    def __init__(self, path=None, fp=None, do_load=True):
55        # We don't use ``super`` here, because ``ConfigParser`` still uses
56        # old-style classes.
57        ConfigParser.__init__(self, {'working_dir': '/mnt/pyami',
58                                         'debug': '0'})
59        if do_load:
60            if path:
61                self.load_from_path(path)
62            elif fp:
63                self.readfp(fp)
64            else:
65                self.read(BotoConfigLocations)
66            if "AWS_CREDENTIAL_FILE" in os.environ:
67                full_path = expanduser(os.environ['AWS_CREDENTIAL_FILE'])
68                try:
69                    self.load_credential_file(full_path)
70                except IOError:
71                    warnings.warn('Unable to load AWS_CREDENTIAL_FILE (%s)' % full_path)
72
73    def load_credential_file(self, path):
74        """Load a credential file as is setup like the Java utilities"""
75        c_data = StringIO()
76        c_data.write("[Credentials]\n")
77        for line in open(path, "r").readlines():
78            c_data.write(line.replace("AWSAccessKeyId", "aws_access_key_id").replace("AWSSecretKey", "aws_secret_access_key"))
79        c_data.seek(0)
80        self.readfp(c_data)
81
82    def load_from_path(self, path):
83        file = open(path)
84        for line in file.readlines():
85            match = re.match("^#import[\s\t]*([^\s^\t]*)[\s\t]*$", line)
86            if match:
87                extended_file = match.group(1)
88                (dir, file) = os.path.split(path)
89                self.load_from_path(os.path.join(dir, extended_file))
90        self.read(path)
91
92    def save_option(self, path, section, option, value):
93        """
94        Write the specified Section.Option to the config file specified by path.
95        Replace any previous value.  If the path doesn't exist, create it.
96        Also add the option the the in-memory config.
97        """
98        config = ConfigParser()
99        config.read(path)
100        if not config.has_section(section):
101            config.add_section(section)
102        config.set(section, option, value)
103        fp = open(path, 'w')
104        config.write(fp)
105        fp.close()
106        if not self.has_section(section):
107            self.add_section(section)
108        self.set(section, option, value)
109
110    def save_user_option(self, section, option, value):
111        self.save_option(UserConfigPath, section, option, value)
112
113    def save_system_option(self, section, option, value):
114        self.save_option(BotoConfigPath, section, option, value)
115
116    def get_instance(self, name, default=None):
117        try:
118            val = self.get('Instance', name)
119        except:
120            val = default
121        return val
122
123    def get_user(self, name, default=None):
124        try:
125            val = self.get('User', name)
126        except:
127            val = default
128        return val
129
130    def getint_user(self, name, default=0):
131        try:
132            val = self.getint('User', name)
133        except:
134            val = default
135        return val
136
137    def get_value(self, section, name, default=None):
138        return self.get(section, name, default)
139
140    def get(self, section, name, default=None):
141        try:
142            val = ConfigParser.get(self, section, name)
143        except:
144            val = default
145        return val
146
147    def getint(self, section, name, default=0):
148        try:
149            val = ConfigParser.getint(self, section, name)
150        except:
151            val = int(default)
152        return val
153
154    def getfloat(self, section, name, default=0.0):
155        try:
156            val = ConfigParser.getfloat(self, section, name)
157        except:
158            val = float(default)
159        return val
160
161    def getbool(self, section, name, default=False):
162        if self.has_option(section, name):
163            val = self.get(section, name)
164            if val.lower() == 'true':
165                val = True
166            else:
167                val = False
168        else:
169            val = default
170        return val
171
172    def setbool(self, section, name, value):
173        if value:
174            self.set(section, name, 'true')
175        else:
176            self.set(section, name, 'false')
177
178    def dump(self):
179        s = StringIO()
180        self.write(s)
181        print(s.getvalue())
182
183    def dump_safe(self, fp=None):
184        if not fp:
185            fp = StringIO()
186        for section in self.sections():
187            fp.write('[%s]\n' % section)
188            for option in self.options(section):
189                if option == 'aws_secret_access_key':
190                    fp.write('%s = xxxxxxxxxxxxxxxxxx\n' % option)
191                else:
192                    fp.write('%s = %s\n' % (option, self.get(section, option)))
193
194    def dump_to_sdb(self, domain_name, item_name):
195        from boto.compat import json
196        sdb = boto.connect_sdb()
197        domain = sdb.lookup(domain_name)
198        if not domain:
199            domain = sdb.create_domain(domain_name)
200        item = domain.new_item(item_name)
201        item.active = False
202        for section in self.sections():
203            d = {}
204            for option in self.options(section):
205                d[option] = self.get(section, option)
206            item[section] = json.dumps(d)
207        item.save()
208
209    def load_from_sdb(self, domain_name, item_name):
210        from boto.compat import json
211        sdb = boto.connect_sdb()
212        domain = sdb.lookup(domain_name)
213        item = domain.get_item(item_name)
214        for section in item.keys():
215            if not self.has_section(section):
216                self.add_section(section)
217            d = json.loads(item[section])
218            for attr_name in d.keys():
219                attr_value = d[attr_name]
220                if attr_value is None:
221                    attr_value = 'None'
222                if isinstance(attr_value, bool):
223                    self.setbool(section, attr_name, attr_value)
224                else:
225                    self.set(section, attr_name, attr_value)
226