Fix ConfigWriter._DistributeConfig error handling
[ganeti-local] / lib / rapi / baserlib.py
1 #
2 #
3
4 # Copyright (C) 2006, 2007, 2008 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Remote API base resources library.
23
24 """
25
26 import ganeti.cli
27 import ganeti.opcodes
28
29 from ganeti import luxi
30 from ganeti import rapi
31 from ganeti import http
32
33
34 def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
35   """Builds a URI list as used by index resources.
36
37   @param ids: list of ids as strings
38   @param uri_format: format to be applied for URI
39   @param uri_fields: optional parameter for field IDs
40
41   """
42   (field_id, field_uri) = uri_fields
43
44   def _MapId(m_id):
45     return { field_id: m_id, field_uri: uri_format % m_id, }
46
47   # Make sure the result is sorted, makes it nicer to look at and simplifies
48   # unittests.
49   ids.sort()
50
51   return map(_MapId, ids)
52
53
54 def ExtractField(sequence, index):
55   """Creates a list containing one column out of a list of lists.
56
57   @param sequence: sequence of lists
58   @param index: index of field
59
60   """
61   return map(lambda item: item[index], sequence)
62
63
64 def MapFields(names, data):
65   """Maps two lists into one dictionary.
66
67   Example::
68       >>> MapFields(["a", "b"], ["foo", 123])
69       {'a': 'foo', 'b': 123}
70
71   @param names: field names (list of strings)
72   @param data: field data (list)
73
74   """
75   if len(names) != len(data):
76     raise AttributeError("Names and data must have the same length")
77   return dict(zip(names, data))
78
79
80 def _Tags_GET(kind, name=""):
81   """Helper function to retrieve tags.
82
83   """
84   op = ganeti.opcodes.OpGetTags(kind=kind, name=name)
85   tags = ganeti.cli.SubmitOpCode(op)
86   return list(tags)
87
88
89 def _Tags_PUT(kind, tags, name=""):
90   """Helper function to set tags.
91
92   """
93   cl = luxi.Client()
94   return cl.SubmitJob([ganeti.opcodes.OpAddTags(kind=kind, name=name,
95                                                 tags=tags)])
96
97
98 def _Tags_DELETE(kind, tags, name=""):
99   """Helper function to delete tags.
100
101   """
102   cl = luxi.Client()
103   return cl.SubmitJob([ganeti.opcodes.OpDelTags(kind=kind, name=name,
104                                                 tags=tags)])
105
106
107 def MapBulkFields(itemslist, fields):
108   """Map value to field name in to one dictionary.
109
110   @param itemslist: a list of items values
111   @param fields: a list of items names
112
113   @return: a list of mapped dictionaries
114
115   """
116   items_details = []
117   for item in itemslist:
118     mapped = MapFields(fields, item)
119     items_details.append(mapped)
120   return items_details
121
122
123 def MakeParamsDict(opts, params):
124   """Makes params dictionary out of a option set.
125
126   This function returns a dictionary needed for hv or be parameters. But only
127   those fields which provided in the option set. Takes parameters frozensets
128   from constants.
129
130   @type opts: dict
131   @param opts: selected options
132   @type params: frozenset
133   @param params: subset of options
134   @rtype: dict
135   @return: dictionary of options, filtered by given subset.
136
137   """
138   result = {}
139
140   for p in params:
141     try:
142       value = opts[p]
143     except KeyError:
144       continue
145     result[p] = value
146
147   return result
148
149
150 class R_Generic(object):
151   """Generic class for resources.
152
153   """
154   # Default permission requirements
155   GET_ACCESS = []
156   PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
157   POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
158   DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]
159
160   def __init__(self, items, queryargs, req):
161     """Generic resource constructor.
162
163     @param items: a list with variables encoded in the URL
164     @param queryargs: a dictionary with additional options from URL
165
166     """
167     self.items = items
168     self.queryargs = queryargs
169     self.req = req
170     self.sn = None
171
172   def getSerialNumber(self):
173     """Get Serial Number.
174
175     """
176     return self.sn
177
178   def _checkIntVariable(self, name):
179     """Return the parsed value of an int argument.
180
181     """
182     val = self.queryargs.get(name, 0)
183     if isinstance(val, list):
184       if val:
185         val = val[0]
186       else:
187         val = 0
188     try:
189       val = int(val)
190     except (ValueError, TypeError), err:
191       raise http.HttpBadRequest("Invalid value for the"
192                                 " '%s' parameter" % (name,))
193     return val
194
195   def getBodyParameter(self, name, *args):
196     """Check and return the value for a given parameter.
197
198     If a second parameter is not given, an error will be returned,
199     otherwise this parameter specifies the default value.
200
201     @param name: the required parameter
202
203     """
204     if name in self.req.request_body:
205       return self.req.request_body[name]
206     elif args:
207       return args[0]
208     else:
209       raise http.HttpBadRequest("Required parameter '%s' is missing" %
210                                 name)
211
212   def useLocking(self):
213     """Check if the request specifies locking.
214
215     """
216     return self._checkIntVariable('lock')
217
218   def useBulk(self):
219     """Check if the request specifies bulk querying.
220
221     """
222     return self._checkIntVariable('bulk')