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 { field_id: m_id, field_uri: uri_format % m_id, }
57
58
59
60 ids.sort()
61
62 return map(_MapId, ids)
63
64
66 """Creates a list containing one column out of a list of lists.
67
68 @param sequence: sequence of lists
69 @param index: index of field
70
71 """
72 return map(lambda item: item[index], sequence)
73
74
76 """Maps two lists into one dictionary.
77
78 Example::
79 >>> MapFields(["a", "b"], ["foo", 123])
80 {'a': 'foo', 'b': 123}
81
82 @param names: field names (list of strings)
83 @param data: field data (list)
84
85 """
86 if len(names) != len(data):
87 raise AttributeError("Names and data must have the same length")
88 return dict(zip(names, data))
89
90
112
113
120
121
128
129
131 """Map value to field name in to one dictionary.
132
133 @param itemslist: a list of items values
134 @param fields: a list of items names
135
136 @return: a list of mapped dictionaries
137
138 """
139 items_details = []
140 for item in itemslist:
141 mapped = MapFields(fields, item)
142 items_details.append(mapped)
143 return items_details
144
145
147 """Makes params dictionary out of a option set.
148
149 This function returns a dictionary needed for hv or be parameters. But only
150 those fields which provided in the option set. Takes parameters frozensets
151 from constants.
152
153 @type opts: dict
154 @param opts: selected options
155 @type params: frozenset
156 @param params: subset of options
157 @rtype: dict
158 @return: dictionary of options, filtered by given subset.
159
160 """
161 result = {}
162
163 for p in params:
164 try:
165 value = opts[p]
166 except KeyError:
167 continue
168 result[p] = value
169
170 return result
171
172
174 """Fills an opcode with body parameters.
175
176 Parameter types are checked.
177
178 @type opcls: L{opcodes.OpCode}
179 @param opcls: Opcode class
180 @type body: dict
181 @param body: Body parameters as received from client
182 @type static: dict
183 @param static: Static parameters which can't be modified by client
184 @return: Opcode object
185
186 """
187 CheckType(body, dict, "Body contents")
188
189 if static:
190 overwritten = set(body.keys()) & set(static.keys())
191 if overwritten:
192 raise http.HttpBadRequest("Can't overwrite static parameters %r" %
193 overwritten)
194
195
196 params = body.copy()
197
198 if static:
199 params.update(static)
200
201
202 params = dict((str(key), value) for (key, value) in params.items())
203
204 try:
205 op = opcls(**params)
206 op.Validate(False)
207 except (errors.OpPrereqError, TypeError), err:
208 raise http.HttpBadRequest("Invalid body parameters: %s" % err)
209
210 return op
211
212
240
241
253
254
266
267
269 """Feedback logging function for jobs.
270
271 We don't have a stdout for printing log messages, so log them to the
272 http log at least.
273
274 @param msg: the message
275
276 """
277 (_, log_type, log_msg) = msg
278 logging.info("%s: %s", log_type, log_msg)
279
280
282 """Abort request if value type doesn't match expected type.
283
284 @param value: Value
285 @type exptype: type
286 @param exptype: Expected type
287 @type descr: string
288 @param descr: Description of value
289 @return: Value (allows inline usage)
290
291 """
292 if not isinstance(value, exptype):
293 raise http.HttpBadRequest("%s: Type is '%s', but '%s' is expected" %
294 (descr, type(value).__name__, exptype.__name__))
295
296 return value
297
298
300 """Check and return the value for a given parameter.
301
302 If no default value was given and the parameter doesn't exist in the input
303 data, an error is raise.
304
305 @type data: dict
306 @param data: Dictionary containing input data
307 @type name: string
308 @param name: Parameter name
309 @param default: Default value (can be None)
310 @param exptype: Expected type (can be None)
311
312 """
313 try:
314 value = data[name]
315 except KeyError:
316 if default is not _DEFAULT:
317 return default
318
319 raise http.HttpBadRequest("Required parameter '%s' is missing" %
320 name)
321
322 if exptype is _DEFAULT:
323 return value
324
325 return CheckType(value, exptype, "'%s' parameter" % name)
326
327
329 """Generic class for resources.
330
331 """
332
333 GET_ACCESS = []
334 PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
335 POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
336 DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]
337
338 - def __init__(self, items, queryargs, req):
339 """Generic resource constructor.
340
341 @param items: a list with variables encoded in the URL
342 @param queryargs: a dictionary with additional options from URL
343
344 """
345 self.items = items
346 self.queryargs = queryargs
347 self._req = req
348
349 - def _GetRequestBody(self):
350 """Returns the body data.
351
352 """
353 return self._req.private.body_data
354
355 request_body = property(fget=_GetRequestBody)
356
358 """Return the parsed value of an int argument.
359
360 """
361 val = self.queryargs.get(name, default)
362 if isinstance(val, list):
363 if val:
364 val = val[0]
365 else:
366 val = default
367 try:
368 val = int(val)
369 except (ValueError, TypeError):
370 raise http.HttpBadRequest("Invalid value for the"
371 " '%s' parameter" % (name,))
372 return val
373
375 """Return the parsed value of an int argument.
376
377 """
378 val = self.queryargs.get(name, default)
379 if isinstance(val, list):
380 if val:
381 val = val[0]
382 else:
383 val = default
384 return val
385
386 - def getBodyParameter(self, name, *args):
387 """Check and return the value for a given parameter.
388
389 If a second parameter is not given, an error will be returned,
390 otherwise this parameter specifies the default value.
391
392 @param name: the required parameter
393
394 """
395 if args:
396 return CheckParameter(self.request_body, name, default=args[0])
397
398 return CheckParameter(self.request_body, name)
399
401 """Check if the request specifies locking.
402
403 """
404 return bool(self._checkIntVariable("lock"))
405
407 """Check if the request specifies bulk querying.
408
409 """
410 return bool(self._checkIntVariable("bulk"))
411
413 """Check if the request specifies a forced operation.
414
415 """
416 return bool(self._checkIntVariable("force"))
417
419 """Check if the request specifies dry-run mode.
420
421 """
422 return bool(self._checkIntVariable("dry-run"))
423