Create InvalidCloudNameError, raise it when needed
[kamaki] / kamaki / cli / commands / config.py
1 # Copyright 2011-2012 GRNET S.A. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
5 # conditions are met:
6 #
7 #   1. Redistributions of source code must retain the above
8 #      copyright notice, this list of conditions and the following
9 #      disclaimer.
10 #
11 #   2. Redistributions in binary form must reproduce the above
12 #      copyright notice, this list of conditions and the following
13 #      disclaimer in the documentation and/or other materials
14 #      provided with the distribution.
15 #
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERaUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
28 #
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
33
34 from sys import stdout
35
36 from kamaki.cli import command
37 from kamaki.cli.argument import FlagArgument
38 from kamaki.cli.commands import _command_init, errors
39 from kamaki.cli.command_tree import CommandTree
40 from kamaki.cli.errors import CLIError, CLISyntaxError
41
42 config_cmds = CommandTree('config', 'Kamaki configurations')
43 _commands = [config_cmds]
44
45 about_options = '\nAbout options:\
46     \n. syntax: [group.]option\
47     \n. example: global.log_file\
48     \n. special case: <option> is equivalent to global.<option>\
49     \n. configuration file syntax:\
50     \n.   [group]\
51     \n.   option=value\
52     \n.   (more options can be set per group)\
53     \n. special case: named clouds.\
54     \n. E.g. for a cloud "demo":\
55     \n.   [cloud "demo"]\
56     \n.   url = <http://single/authentication/url/for/demo/site>\
57     \n.   token = <auth_token_from_demo_site>\
58     \n. which are referenced as cloud.demo.url , cloud.demo.token'
59
60
61 @command(config_cmds)
62 class config_list(_command_init):
63     """List all configuration options
64     FAQ:
65     Q: I haven't set any options!
66     A: Defaults are used (override with /config set )
67     Q: There are more options than I have set
68     A: Default options remain if not explicitly replaced or deleted
69     """
70
71     @errors.generic.all
72     def _run(self):
73         print 'ANY PROBLEMOS?'
74         for section in sorted(self.config.sections()):
75             items = self.config.items(section)
76             for key, val in sorted(items):
77                 if section in ('cloud',):
78                     prefix = '%s.%s' % (section, key)
79                     for k, v in val.items():
80                         print('%s.%s = %s' % (prefix, k, v))
81                 else:
82                     print('%s.%s = %s' % (section, key, val))
83
84     def main(self):
85         self._run()
86
87
88 @command(config_cmds)
89 class config_get(_command_init):
90     """Show a configuration option"""
91
92     __doc__ += about_options
93
94     @errors.generic.all
95     def _run(self, option):
96         section, sep, key = option.rpartition('.')
97         if not sep:
98             match = False
99             for k in self.config.keys(key):
100                 match = True
101                 if option != 'cloud':
102                     stdout.write('%s.%s =' % (option, k))
103                 self._run('%s.%s' % (option, k))
104             if match:
105                 return
106             section = 'global'
107         prefix = 'cloud.'
108         get, section = (
109             self.config.get_cloud, section[len(prefix):]) if (
110                 section.startswith(prefix)) else (self.config.get, section)
111         value = get(section, key)
112         if isinstance(value, dict):
113             for k, v in value.items():
114                 print('%s.%s.%s = %s' % (section, key, k, v))
115         elif value:
116             print(value)
117
118     def main(self, option):
119         self._run(option)
120
121
122 @command(config_cmds)
123 class config_set(_command_init):
124     """Set a configuration option"""
125
126     __doc__ += about_options
127
128     @errors.generic.all
129     def _run(self, option, value):
130         section, sep, key = option.rpartition('.')
131         prefix = 'cloud.'
132         if section.startswith(prefix):
133             self.config.set_cloud(section[len(prefix):], key, value)
134         elif section in ('cloud',):
135             raise CLISyntaxError(
136                 'Invalid syntax for cloud definition', importance=2, details=[
137                     'To define a cloud "%s"' % key,
138                     'set the cloud\'s authentication url and token:',
139                     '  /config set cloud.%s.url <URL>' % key,
140                     '  /config set cloud.%s.token <t0k3n>' % key])
141         else:
142             section = section or 'global'
143             self.config.set(section, key, value)
144         self.config.write()
145         self.config.reload()
146
147     def main(self, option, value):
148         self._run(option, value)
149
150
151 @command(config_cmds)
152 class config_delete(_command_init):
153     """Delete a configuration option
154     Default values are not removed by default. To alter this behavior in a
155     session, use --default.
156     """
157
158     arguments = dict(
159         default=FlagArgument(
160             'Remove default value as well (persists until end of session)',
161             '--default')
162     )
163
164     @errors.generic.all
165     def _run(self, option):
166         section, sep, key = option.rpartition('.')
167         section = section or 'global'
168         prefix = 'cloud.'
169         if section.startswith(prefix):
170             cloud = section[len(prefix):]
171             try:
172                 self.config.remove_from_cloud(cloud, key)
173             except KeyError:
174                 raise CLIError('Field %s does not exist' % option)
175         else:
176             self.config.remove_option(section, key, self['default'])
177         self.config.write()
178         self.config.reload()
179
180     def main(self, option):
181         self._run(option)