1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Remote API base resources library.
23
24 """
25
26
27
28
29
30 import logging
31
32 from ganeti import luxi
33 from ganeti import rapi
34 from ganeti import http
35 from ganeti import ssconf
36 from ganeti import constants
37 from ganeti import opcodes
38 from ganeti import errors
39
40
41
42 _DEFAULT = object()
43
44
45 -def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
46 """Builds a URI list as used by index resources.
47
48 @param ids: list of ids as strings
49 @param uri_format: format to be applied for URI
50 @param uri_fields: optional parameter for field IDs
51
52 """
53 (field_id, field_uri) = uri_fields
54
55 def _MapId(m_id):
56 return {
57 field_id: m_id,
58 field_uri: uri_format % m_id,
59 }
60
61
62
63 ids.sort()
64
65 return map(_MapId, ids)
66
67
69 """Creates a list containing one column out of a list of lists.
70
71 @param sequence: sequence of lists
72 @param index: index of field
73
74 """
75 return map(lambda item: item[index], sequence)
76
77
79 """Maps two lists into one dictionary.
80
81 Example::
82 >>> MapFields(["a", "b"], ["foo", 123])
83 {'a': 'foo', 'b': 123}
84
85 @param names: field names (list of strings)
86 @param data: field data (list)
87
88 """
89 if len(names) != len(data):
90 raise AttributeError("Names and data must have the same length")
91 return dict(zip(names, data))
92
93
119
120
127
128
135
136
138 """Map value to field name in to one dictionary.
139
140 @param itemslist: a list of items values
141 @param fields: a list of items names
142
143 @return: a list of mapped dictionaries
144
145 """
146 items_details = []
147 for item in itemslist:
148 mapped = MapFields(fields, item)
149 items_details.append(mapped)
150 return items_details
151
152
154 """Makes params dictionary out of a option set.
155
156 This function returns a dictionary needed for hv or be parameters. But only
157 those fields which provided in the option set. Takes parameters frozensets
158 from constants.
159
160 @type opts: dict
161 @param opts: selected options
162 @type params: frozenset
163 @param params: subset of options
164 @rtype: dict
165 @return: dictionary of options, filtered by given subset.
166
167 """
168 result = {}
169
170 for p in params:
171 try:
172 value = opts[p]
173 except KeyError:
174 continue
175 result[p] = value
176
177 return result
178
179
181 """Fills an opcode with body parameters.
182
183 Parameter types are checked.
184
185 @type opcls: L{opcodes.OpCode}
186 @param opcls: Opcode class
187 @type body: dict
188 @param body: Body parameters as received from client
189 @type static: dict
190 @param static: Static parameters which can't be modified by client
191 @type rename: dict
192 @param rename: Renamed parameters, key as old name, value as new name
193 @return: Opcode object
194
195 """
196 if body is None:
197 params = {}
198 else:
199 CheckType(body, dict, "Body contents")
200
201
202 params = body.copy()
203
204 if rename:
205 for old, new in rename.items():
206 if new in params and old in params:
207 raise http.HttpBadRequest("Parameter '%s' was renamed to '%s', but"
208 " both are specified" %
209 (old, new))
210 if old in params:
211 assert new not in params
212 params[new] = params.pop(old)
213
214 if static:
215 overwritten = set(params.keys()) & set(static.keys())
216 if overwritten:
217 raise http.HttpBadRequest("Can't overwrite static parameters %r" %
218 overwritten)
219
220 params.update(static)
221
222
223 params = dict((str(key), value) for (key, value) in params.items())
224
225 try:
226 op = opcls(**params)
227 op.Validate(False)
228 except (errors.OpPrereqError, TypeError), err:
229 raise http.HttpBadRequest("Invalid body parameters: %s" % err)
230
231 return op
232
233
261
262
274
275
287
288
290 """Feedback logging function for jobs.
291
292 We don't have a stdout for printing log messages, so log them to the
293 http log at least.
294
295 @param msg: the message
296
297 """
298 (_, log_type, log_msg) = msg
299 logging.info("%s: %s", log_type, log_msg)
300
301
303 """Abort request if value type doesn't match expected type.
304
305 @param value: Value
306 @type exptype: type
307 @param exptype: Expected type
308 @type descr: string
309 @param descr: Description of value
310 @return: Value (allows inline usage)
311
312 """
313 if not isinstance(value, exptype):
314 raise http.HttpBadRequest("%s: Type is '%s', but '%s' is expected" %
315 (descr, type(value).__name__, exptype.__name__))
316
317 return value
318
319
321 """Check and return the value for a given parameter.
322
323 If no default value was given and the parameter doesn't exist in the input
324 data, an error is raise.
325
326 @type data: dict
327 @param data: Dictionary containing input data
328 @type name: string
329 @param name: Parameter name
330 @param default: Default value (can be None)
331 @param exptype: Expected type (can be None)
332
333 """
334 try:
335 value = data[name]
336 except KeyError:
337 if default is not _DEFAULT:
338 return default
339
340 raise http.HttpBadRequest("Required parameter '%s' is missing" %
341 name)
342
343 if exptype is _DEFAULT:
344 return value
345
346 return CheckType(value, exptype, "'%s' parameter" % name)
347
348
350 """Generic class for resources.
351
352 """
353
354 GET_ACCESS = []
355 PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
356 POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
357 DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]
358
359 - def __init__(self, items, queryargs, req):
360 """Generic resource constructor.
361
362 @param items: a list with variables encoded in the URL
363 @param queryargs: a dictionary with additional options from URL
364
365 """
366 self.items = items
367 self.queryargs = queryargs
368 self._req = req
369
370 - def _GetRequestBody(self):
371 """Returns the body data.
372
373 """
374 return self._req.private.body_data
375
376 request_body = property(fget=_GetRequestBody)
377
379 """Return the parsed value of an int argument.
380
381 """
382 val = self.queryargs.get(name, default)
383 if isinstance(val, list):
384 if val:
385 val = val[0]
386 else:
387 val = default
388 try:
389 val = int(val)
390 except (ValueError, TypeError):
391 raise http.HttpBadRequest("Invalid value for the"
392 " '%s' parameter" % (name,))
393 return val
394
396 """Return the parsed value of an int argument.
397
398 """
399 val = self.queryargs.get(name, default)
400 if isinstance(val, list):
401 if val:
402 val = val[0]
403 else:
404 val = default
405 return val
406
407 - def getBodyParameter(self, name, *args):
408 """Check and return the value for a given parameter.
409
410 If a second parameter is not given, an error will be returned,
411 otherwise this parameter specifies the default value.
412
413 @param name: the required parameter
414
415 """
416 if args:
417 return CheckParameter(self.request_body, name, default=args[0])
418
419 return CheckParameter(self.request_body, name)
420
422 """Check if the request specifies locking.
423
424 """
425 return bool(self._checkIntVariable("lock"))
426
428 """Check if the request specifies bulk querying.
429
430 """
431 return bool(self._checkIntVariable("bulk"))
432
434 """Check if the request specifies a forced operation.
435
436 """
437 return bool(self._checkIntVariable("force"))
438
440 """Check if the request specifies dry-run mode.
441
442 """
443 return bool(self._checkIntVariable("dry-run"))
444