Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / baserlib.py @ 6fe4baf0

History | View | Annotate | Download (11.4 kB)

1 c2dca9af Oleksiy Mishchenko
#
2 c2dca9af Oleksiy Mishchenko
#
3 c2dca9af Oleksiy Mishchenko
4 c2dca9af Oleksiy Mishchenko
# Copyright (C) 2006, 2007, 2008 Google Inc.
5 c2dca9af Oleksiy Mishchenko
#
6 c2dca9af Oleksiy Mishchenko
# This program is free software; you can redistribute it and/or modify
7 c2dca9af Oleksiy Mishchenko
# it under the terms of the GNU General Public License as published by
8 c2dca9af Oleksiy Mishchenko
# the Free Software Foundation; either version 2 of the License, or
9 c2dca9af Oleksiy Mishchenko
# (at your option) any later version.
10 c2dca9af Oleksiy Mishchenko
#
11 c2dca9af Oleksiy Mishchenko
# This program is distributed in the hope that it will be useful, but
12 c2dca9af Oleksiy Mishchenko
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 c2dca9af Oleksiy Mishchenko
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 c2dca9af Oleksiy Mishchenko
# General Public License for more details.
15 c2dca9af Oleksiy Mishchenko
#
16 c2dca9af Oleksiy Mishchenko
# You should have received a copy of the GNU General Public License
17 c2dca9af Oleksiy Mishchenko
# along with this program; if not, write to the Free Software
18 c2dca9af Oleksiy Mishchenko
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 c2dca9af Oleksiy Mishchenko
# 02110-1301, USA.
20 c2dca9af Oleksiy Mishchenko
21 c2dca9af Oleksiy Mishchenko
22 c2dca9af Oleksiy Mishchenko
"""Remote API base resources library.
23 c2dca9af Oleksiy Mishchenko

24 c2dca9af Oleksiy Mishchenko
"""
25 c2dca9af Oleksiy Mishchenko
26 b459a848 Andrea Spadaccini
# pylint: disable=C0103
27 fe267188 Iustin Pop
28 fe267188 Iustin Pop
# C0103: Invalid name, since the R_* names are not conforming
29 fe267188 Iustin Pop
30 59b4eeef Iustin Pop
import logging
31 59b4eeef Iustin Pop
32 441e7cfd Oleksiy Mishchenko
from ganeti import luxi
33 b5b67ef9 Michael Hanselmann
from ganeti import rapi
34 3d103742 Iustin Pop
from ganeti import http
35 25e39bfa Iustin Pop
from ganeti import ssconf
36 25e39bfa Iustin Pop
from ganeti import constants
37 59b4eeef Iustin Pop
from ganeti import opcodes
38 59b4eeef Iustin Pop
from ganeti import errors
39 441e7cfd Oleksiy Mishchenko
40 c2dca9af Oleksiy Mishchenko
41 af6433c6 Michael Hanselmann
# Dummy value to detect unchanged parameters
42 af6433c6 Michael Hanselmann
_DEFAULT = object()
43 af6433c6 Michael Hanselmann
44 af6433c6 Michael Hanselmann
45 c2dca9af Oleksiy Mishchenko
def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
46 c2dca9af Oleksiy Mishchenko
  """Builds a URI list as used by index resources.
47 c2dca9af Oleksiy Mishchenko

48 c41eea6e Iustin Pop
  @param ids: list of ids as strings
49 c41eea6e Iustin Pop
  @param uri_format: format to be applied for URI
50 c41eea6e Iustin Pop
  @param uri_fields: optional parameter for field IDs
51 c2dca9af Oleksiy Mishchenko

52 c2dca9af Oleksiy Mishchenko
  """
53 c2dca9af Oleksiy Mishchenko
  (field_id, field_uri) = uri_fields
54 dca1764e Iustin Pop
55 c2dca9af Oleksiy Mishchenko
  def _MapId(m_id):
56 e687ec01 Michael Hanselmann
    return {
57 e687ec01 Michael Hanselmann
      field_id: m_id,
58 e687ec01 Michael Hanselmann
      field_uri: uri_format % m_id,
59 e687ec01 Michael Hanselmann
      }
60 c2dca9af Oleksiy Mishchenko
61 c2dca9af Oleksiy Mishchenko
  # Make sure the result is sorted, makes it nicer to look at and simplifies
62 c2dca9af Oleksiy Mishchenko
  # unittests.
63 c2dca9af Oleksiy Mishchenko
  ids.sort()
64 c2dca9af Oleksiy Mishchenko
65 c2dca9af Oleksiy Mishchenko
  return map(_MapId, ids)
66 c2dca9af Oleksiy Mishchenko
67 c2dca9af Oleksiy Mishchenko
68 c2dca9af Oleksiy Mishchenko
def ExtractField(sequence, index):
69 c2dca9af Oleksiy Mishchenko
  """Creates a list containing one column out of a list of lists.
70 c2dca9af Oleksiy Mishchenko

71 c41eea6e Iustin Pop
  @param sequence: sequence of lists
72 c41eea6e Iustin Pop
  @param index: index of field
73 c2dca9af Oleksiy Mishchenko

74 c2dca9af Oleksiy Mishchenko
  """
75 c2dca9af Oleksiy Mishchenko
  return map(lambda item: item[index], sequence)
76 c2dca9af Oleksiy Mishchenko
77 c2dca9af Oleksiy Mishchenko
78 c2dca9af Oleksiy Mishchenko
def MapFields(names, data):
79 c2dca9af Oleksiy Mishchenko
  """Maps two lists into one dictionary.
80 c2dca9af Oleksiy Mishchenko

81 c41eea6e Iustin Pop
  Example::
82 c41eea6e Iustin Pop
      >>> MapFields(["a", "b"], ["foo", 123])
83 c41eea6e Iustin Pop
      {'a': 'foo', 'b': 123}
84 c2dca9af Oleksiy Mishchenko

85 c41eea6e Iustin Pop
  @param names: field names (list of strings)
86 c41eea6e Iustin Pop
  @param data: field data (list)
87 c2dca9af Oleksiy Mishchenko

88 c2dca9af Oleksiy Mishchenko
  """
89 c2dca9af Oleksiy Mishchenko
  if len(names) != len(data):
90 c2dca9af Oleksiy Mishchenko
    raise AttributeError("Names and data must have the same length")
91 dca1764e Iustin Pop
  return dict(zip(names, data))
92 c2dca9af Oleksiy Mishchenko
93 c2dca9af Oleksiy Mishchenko
94 64246438 Iustin Pop
def _Tags_GET(kind, name):
95 c2dca9af Oleksiy Mishchenko
  """Helper function to retrieve tags.
96 c2dca9af Oleksiy Mishchenko

97 c2dca9af Oleksiy Mishchenko
  """
98 414ebaf1 Michael Hanselmann
  if kind in (constants.TAG_INSTANCE,
99 414ebaf1 Michael Hanselmann
              constants.TAG_NODEGROUP,
100 414ebaf1 Michael Hanselmann
              constants.TAG_NODE):
101 25e39bfa Iustin Pop
    if not name:
102 59b4eeef Iustin Pop
      raise http.HttpBadRequest("Missing name on tag request")
103 59b4eeef Iustin Pop
    cl = GetClient()
104 25e39bfa Iustin Pop
    if kind == constants.TAG_INSTANCE:
105 25e39bfa Iustin Pop
      fn = cl.QueryInstances
106 414ebaf1 Michael Hanselmann
    elif kind == constants.TAG_NODEGROUP:
107 414ebaf1 Michael Hanselmann
      fn = cl.QueryGroups
108 25e39bfa Iustin Pop
    else:
109 25e39bfa Iustin Pop
      fn = cl.QueryNodes
110 25e39bfa Iustin Pop
    result = fn(names=[name], fields=["tags"], use_locking=False)
111 25e39bfa Iustin Pop
    if not result or not result[0]:
112 25e39bfa Iustin Pop
      raise http.HttpBadGateway("Invalid response from tag query")
113 25e39bfa Iustin Pop
    tags = result[0][0]
114 25e39bfa Iustin Pop
  elif kind == constants.TAG_CLUSTER:
115 25e39bfa Iustin Pop
    ssc = ssconf.SimpleStore()
116 25e39bfa Iustin Pop
    tags = ssc.GetClusterTags()
117 25e39bfa Iustin Pop
118 c2dca9af Oleksiy Mishchenko
  return list(tags)
119 c2dca9af Oleksiy Mishchenko
120 c2dca9af Oleksiy Mishchenko
121 64246438 Iustin Pop
def _Tags_PUT(kind, tags, name, dry_run):
122 441e7cfd Oleksiy Mishchenko
  """Helper function to set tags.
123 441e7cfd Oleksiy Mishchenko

124 441e7cfd Oleksiy Mishchenko
  """
125 d1602edc Iustin Pop
  return SubmitJob([opcodes.OpTagsSet(kind=kind, name=name,
126 64246438 Iustin Pop
                                      tags=tags, dry_run=dry_run)])
127 441e7cfd Oleksiy Mishchenko
128 441e7cfd Oleksiy Mishchenko
129 64246438 Iustin Pop
def _Tags_DELETE(kind, tags, name, dry_run):
130 15fd9fd5 Oleksiy Mishchenko
  """Helper function to delete tags.
131 15fd9fd5 Oleksiy Mishchenko

132 15fd9fd5 Oleksiy Mishchenko
  """
133 3f0ab95f Iustin Pop
  return SubmitJob([opcodes.OpTagsDel(kind=kind, name=name,
134 64246438 Iustin Pop
                                      tags=tags, dry_run=dry_run)])
135 15fd9fd5 Oleksiy Mishchenko
136 15fd9fd5 Oleksiy Mishchenko
137 51ee2f49 Oleksiy Mishchenko
def MapBulkFields(itemslist, fields):
138 51ee2f49 Oleksiy Mishchenko
  """Map value to field name in to one dictionary.
139 51ee2f49 Oleksiy Mishchenko

140 c41eea6e Iustin Pop
  @param itemslist: a list of items values
141 c41eea6e Iustin Pop
  @param fields: a list of items names
142 c41eea6e Iustin Pop

143 c41eea6e Iustin Pop
  @return: a list of mapped dictionaries
144 51ee2f49 Oleksiy Mishchenko

145 51ee2f49 Oleksiy Mishchenko
  """
146 51ee2f49 Oleksiy Mishchenko
  items_details = []
147 51ee2f49 Oleksiy Mishchenko
  for item in itemslist:
148 51ee2f49 Oleksiy Mishchenko
    mapped = MapFields(fields, item)
149 51ee2f49 Oleksiy Mishchenko
    items_details.append(mapped)
150 51ee2f49 Oleksiy Mishchenko
  return items_details
151 51ee2f49 Oleksiy Mishchenko
152 51ee2f49 Oleksiy Mishchenko
153 d50b3059 Oleksiy Mishchenko
def MakeParamsDict(opts, params):
154 c41eea6e Iustin Pop
  """Makes params dictionary out of a option set.
155 d50b3059 Oleksiy Mishchenko

156 d50b3059 Oleksiy Mishchenko
  This function returns a dictionary needed for hv or be parameters. But only
157 d50b3059 Oleksiy Mishchenko
  those fields which provided in the option set. Takes parameters frozensets
158 d50b3059 Oleksiy Mishchenko
  from constants.
159 d50b3059 Oleksiy Mishchenko

160 d50b3059 Oleksiy Mishchenko
  @type opts: dict
161 d50b3059 Oleksiy Mishchenko
  @param opts: selected options
162 d50b3059 Oleksiy Mishchenko
  @type params: frozenset
163 d50b3059 Oleksiy Mishchenko
  @param params: subset of options
164 d50b3059 Oleksiy Mishchenko
  @rtype: dict
165 d50b3059 Oleksiy Mishchenko
  @return: dictionary of options, filtered by given subset.
166 d50b3059 Oleksiy Mishchenko

167 d50b3059 Oleksiy Mishchenko
  """
168 d50b3059 Oleksiy Mishchenko
  result = {}
169 d50b3059 Oleksiy Mishchenko
170 d50b3059 Oleksiy Mishchenko
  for p in params:
171 d50b3059 Oleksiy Mishchenko
    try:
172 d50b3059 Oleksiy Mishchenko
      value = opts[p]
173 d50b3059 Oleksiy Mishchenko
    except KeyError:
174 d50b3059 Oleksiy Mishchenko
      continue
175 d50b3059 Oleksiy Mishchenko
    result[p] = value
176 d50b3059 Oleksiy Mishchenko
177 d50b3059 Oleksiy Mishchenko
  return result
178 d50b3059 Oleksiy Mishchenko
179 d50b3059 Oleksiy Mishchenko
180 b166ef84 Michael Hanselmann
def FillOpcode(opcls, body, static, rename=None):
181 cfaeaaf7 Michael Hanselmann
  """Fills an opcode with body parameters.
182 cfaeaaf7 Michael Hanselmann

183 cfaeaaf7 Michael Hanselmann
  Parameter types are checked.
184 cfaeaaf7 Michael Hanselmann

185 cfaeaaf7 Michael Hanselmann
  @type opcls: L{opcodes.OpCode}
186 cfaeaaf7 Michael Hanselmann
  @param opcls: Opcode class
187 cfaeaaf7 Michael Hanselmann
  @type body: dict
188 cfaeaaf7 Michael Hanselmann
  @param body: Body parameters as received from client
189 cfaeaaf7 Michael Hanselmann
  @type static: dict
190 cfaeaaf7 Michael Hanselmann
  @param static: Static parameters which can't be modified by client
191 b166ef84 Michael Hanselmann
  @type rename: dict
192 b166ef84 Michael Hanselmann
  @param rename: Renamed parameters, key as old name, value as new name
193 cfaeaaf7 Michael Hanselmann
  @return: Opcode object
194 cfaeaaf7 Michael Hanselmann

195 cfaeaaf7 Michael Hanselmann
  """
196 fa411651 Michael Hanselmann
  if body is None:
197 fa411651 Michael Hanselmann
    params = {}
198 fa411651 Michael Hanselmann
  else:
199 fa411651 Michael Hanselmann
    CheckType(body, dict, "Body contents")
200 cfaeaaf7 Michael Hanselmann
201 fa411651 Michael Hanselmann
    # Make copy to be modified
202 fa411651 Michael Hanselmann
    params = body.copy()
203 b166ef84 Michael Hanselmann
204 b166ef84 Michael Hanselmann
  if rename:
205 b166ef84 Michael Hanselmann
    for old, new in rename.items():
206 b166ef84 Michael Hanselmann
      if new in params and old in params:
207 b166ef84 Michael Hanselmann
        raise http.HttpBadRequest("Parameter '%s' was renamed to '%s', but"
208 b166ef84 Michael Hanselmann
                                  " both are specified" %
209 b166ef84 Michael Hanselmann
                                  (old, new))
210 b166ef84 Michael Hanselmann
      if old in params:
211 b166ef84 Michael Hanselmann
        assert new not in params
212 b166ef84 Michael Hanselmann
        params[new] = params.pop(old)
213 b166ef84 Michael Hanselmann
214 cfaeaaf7 Michael Hanselmann
  if static:
215 b166ef84 Michael Hanselmann
    overwritten = set(params.keys()) & set(static.keys())
216 cfaeaaf7 Michael Hanselmann
    if overwritten:
217 cfaeaaf7 Michael Hanselmann
      raise http.HttpBadRequest("Can't overwrite static parameters %r" %
218 cfaeaaf7 Michael Hanselmann
                                overwritten)
219 cfaeaaf7 Michael Hanselmann
220 cfaeaaf7 Michael Hanselmann
    params.update(static)
221 cfaeaaf7 Michael Hanselmann
222 cfaeaaf7 Michael Hanselmann
  # Convert keys to strings (simplejson decodes them as unicode)
223 cfaeaaf7 Michael Hanselmann
  params = dict((str(key), value) for (key, value) in params.items())
224 cfaeaaf7 Michael Hanselmann
225 cfaeaaf7 Michael Hanselmann
  try:
226 b459a848 Andrea Spadaccini
    op = opcls(**params) # pylint: disable=W0142
227 cfaeaaf7 Michael Hanselmann
    op.Validate(False)
228 cfaeaaf7 Michael Hanselmann
  except (errors.OpPrereqError, TypeError), err:
229 cfaeaaf7 Michael Hanselmann
    raise http.HttpBadRequest("Invalid body parameters: %s" % err)
230 cfaeaaf7 Michael Hanselmann
231 cfaeaaf7 Michael Hanselmann
  return op
232 cfaeaaf7 Michael Hanselmann
233 cfaeaaf7 Michael Hanselmann
234 59b4eeef Iustin Pop
def SubmitJob(op, cl=None):
235 59b4eeef Iustin Pop
  """Generic wrapper for submit job, for better http compatibility.
236 59b4eeef Iustin Pop

237 59b4eeef Iustin Pop
  @type op: list
238 59b4eeef Iustin Pop
  @param op: the list of opcodes for the job
239 59b4eeef Iustin Pop
  @type cl: None or luxi.Client
240 59b4eeef Iustin Pop
  @param cl: optional luxi client to use
241 59b4eeef Iustin Pop
  @rtype: string
242 59b4eeef Iustin Pop
  @return: the job ID
243 59b4eeef Iustin Pop

244 59b4eeef Iustin Pop
  """
245 59b4eeef Iustin Pop
  try:
246 59b4eeef Iustin Pop
    if cl is None:
247 59b4eeef Iustin Pop
      cl = GetClient()
248 59b4eeef Iustin Pop
    return cl.SubmitJob(op)
249 59b4eeef Iustin Pop
  except errors.JobQueueFull:
250 59b4eeef Iustin Pop
    raise http.HttpServiceUnavailable("Job queue is full, needs archiving")
251 59b4eeef Iustin Pop
  except errors.JobQueueDrainError:
252 59b4eeef Iustin Pop
    raise http.HttpServiceUnavailable("Job queue is drained, cannot submit")
253 59b4eeef Iustin Pop
  except luxi.NoMasterError, err:
254 5a1c22fe Iustin Pop
    raise http.HttpBadGateway("Master seems to be unreachable: %s" % str(err))
255 5a1c22fe Iustin Pop
  except luxi.PermissionError:
256 5a1c22fe Iustin Pop
    raise http.HttpInternalServerError("Internal error: no permission to"
257 5a1c22fe Iustin Pop
                                       " connect to the master daemon")
258 59b4eeef Iustin Pop
  except luxi.TimeoutError, err:
259 59b4eeef Iustin Pop
    raise http.HttpGatewayTimeout("Timeout while talking to the master"
260 59b4eeef Iustin Pop
                                  " daemon. Error: %s" % str(err))
261 59b4eeef Iustin Pop
262 e8ebbd2b Michael Hanselmann
263 e8ebbd2b Michael Hanselmann
def HandleItemQueryErrors(fn, *args, **kwargs):
264 e8ebbd2b Michael Hanselmann
  """Converts errors when querying a single item.
265 e8ebbd2b Michael Hanselmann

266 e8ebbd2b Michael Hanselmann
  """
267 e8ebbd2b Michael Hanselmann
  try:
268 e8ebbd2b Michael Hanselmann
    return fn(*args, **kwargs)
269 e8ebbd2b Michael Hanselmann
  except errors.OpPrereqError, err:
270 e8ebbd2b Michael Hanselmann
    if len(err.args) == 2 and err.args[1] == errors.ECODE_NOENT:
271 e8ebbd2b Michael Hanselmann
      raise http.HttpNotFound()
272 e8ebbd2b Michael Hanselmann
273 e8ebbd2b Michael Hanselmann
    raise
274 e8ebbd2b Michael Hanselmann
275 e8ebbd2b Michael Hanselmann
276 59b4eeef Iustin Pop
def GetClient():
277 59b4eeef Iustin Pop
  """Geric wrapper for luxi.Client(), for better http compatiblity.
278 59b4eeef Iustin Pop

279 59b4eeef Iustin Pop
  """
280 59b4eeef Iustin Pop
  try:
281 59b4eeef Iustin Pop
    return luxi.Client()
282 59b4eeef Iustin Pop
  except luxi.NoMasterError, err:
283 59b4eeef Iustin Pop
    raise http.HttpBadGateway("Master seems to unreachable: %s" % str(err))
284 5a1c22fe Iustin Pop
  except luxi.PermissionError:
285 5a1c22fe Iustin Pop
    raise http.HttpInternalServerError("Internal error: no permission to"
286 5a1c22fe Iustin Pop
                                       " connect to the master daemon")
287 59b4eeef Iustin Pop
288 59b4eeef Iustin Pop
289 e51ca051 Michael Hanselmann
def FeedbackFn(msg):
290 e51ca051 Michael Hanselmann
  """Feedback logging function for jobs.
291 59b4eeef Iustin Pop

292 59b4eeef Iustin Pop
  We don't have a stdout for printing log messages, so log them to the
293 59b4eeef Iustin Pop
  http log at least.
294 59b4eeef Iustin Pop

295 e51ca051 Michael Hanselmann
  @param msg: the message
296 2d54e29c Iustin Pop

297 59b4eeef Iustin Pop
  """
298 e51ca051 Michael Hanselmann
  (_, log_type, log_msg) = msg
299 59b4eeef Iustin Pop
  logging.info("%s: %s", log_type, log_msg)
300 59b4eeef Iustin Pop
301 59b4eeef Iustin Pop
302 af6433c6 Michael Hanselmann
def CheckType(value, exptype, descr):
303 af6433c6 Michael Hanselmann
  """Abort request if value type doesn't match expected type.
304 af6433c6 Michael Hanselmann

305 af6433c6 Michael Hanselmann
  @param value: Value
306 af6433c6 Michael Hanselmann
  @type exptype: type
307 af6433c6 Michael Hanselmann
  @param exptype: Expected type
308 af6433c6 Michael Hanselmann
  @type descr: string
309 af6433c6 Michael Hanselmann
  @param descr: Description of value
310 af6433c6 Michael Hanselmann
  @return: Value (allows inline usage)
311 af6433c6 Michael Hanselmann

312 af6433c6 Michael Hanselmann
  """
313 af6433c6 Michael Hanselmann
  if not isinstance(value, exptype):
314 af6433c6 Michael Hanselmann
    raise http.HttpBadRequest("%s: Type is '%s', but '%s' is expected" %
315 af6433c6 Michael Hanselmann
                              (descr, type(value).__name__, exptype.__name__))
316 af6433c6 Michael Hanselmann
317 af6433c6 Michael Hanselmann
  return value
318 af6433c6 Michael Hanselmann
319 af6433c6 Michael Hanselmann
320 af6433c6 Michael Hanselmann
def CheckParameter(data, name, default=_DEFAULT, exptype=_DEFAULT):
321 af6433c6 Michael Hanselmann
  """Check and return the value for a given parameter.
322 af6433c6 Michael Hanselmann

323 af6433c6 Michael Hanselmann
  If no default value was given and the parameter doesn't exist in the input
324 af6433c6 Michael Hanselmann
  data, an error is raise.
325 af6433c6 Michael Hanselmann

326 af6433c6 Michael Hanselmann
  @type data: dict
327 af6433c6 Michael Hanselmann
  @param data: Dictionary containing input data
328 af6433c6 Michael Hanselmann
  @type name: string
329 af6433c6 Michael Hanselmann
  @param name: Parameter name
330 af6433c6 Michael Hanselmann
  @param default: Default value (can be None)
331 af6433c6 Michael Hanselmann
  @param exptype: Expected type (can be None)
332 af6433c6 Michael Hanselmann

333 af6433c6 Michael Hanselmann
  """
334 af6433c6 Michael Hanselmann
  try:
335 af6433c6 Michael Hanselmann
    value = data[name]
336 af6433c6 Michael Hanselmann
  except KeyError:
337 af6433c6 Michael Hanselmann
    if default is not _DEFAULT:
338 af6433c6 Michael Hanselmann
      return default
339 af6433c6 Michael Hanselmann
340 af6433c6 Michael Hanselmann
    raise http.HttpBadRequest("Required parameter '%s' is missing" %
341 af6433c6 Michael Hanselmann
                              name)
342 af6433c6 Michael Hanselmann
343 af6433c6 Michael Hanselmann
  if exptype is _DEFAULT:
344 af6433c6 Michael Hanselmann
    return value
345 af6433c6 Michael Hanselmann
346 af6433c6 Michael Hanselmann
  return CheckType(value, exptype, "'%s' parameter" % name)
347 af6433c6 Michael Hanselmann
348 af6433c6 Michael Hanselmann
349 c2dca9af Oleksiy Mishchenko
class R_Generic(object):
350 c2dca9af Oleksiy Mishchenko
  """Generic class for resources.
351 c2dca9af Oleksiy Mishchenko

352 c2dca9af Oleksiy Mishchenko
  """
353 b5b67ef9 Michael Hanselmann
  # Default permission requirements
354 b5b67ef9 Michael Hanselmann
  GET_ACCESS = []
355 b5b67ef9 Michael Hanselmann
  PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
356 b5b67ef9 Michael Hanselmann
  POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
357 b5b67ef9 Michael Hanselmann
  DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]
358 b5b67ef9 Michael Hanselmann
359 7a8f64da Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
360 c2dca9af Oleksiy Mishchenko
    """Generic resource constructor.
361 c2dca9af Oleksiy Mishchenko

362 c41eea6e Iustin Pop
    @param items: a list with variables encoded in the URL
363 c41eea6e Iustin Pop
    @param queryargs: a dictionary with additional options from URL
364 c2dca9af Oleksiy Mishchenko

365 c2dca9af Oleksiy Mishchenko
    """
366 c2dca9af Oleksiy Mishchenko
    self.items = items
367 c2dca9af Oleksiy Mishchenko
    self.queryargs = queryargs
368 627ad739 Michael Hanselmann
    self._req = req
369 627ad739 Michael Hanselmann
370 2feecf12 Michael Hanselmann
  def _GetRequestBody(self):
371 2feecf12 Michael Hanselmann
    """Returns the body data.
372 2feecf12 Michael Hanselmann

373 2feecf12 Michael Hanselmann
    """
374 2feecf12 Michael Hanselmann
    return self._req.private.body_data
375 2feecf12 Michael Hanselmann
376 2feecf12 Michael Hanselmann
  request_body = property(fget=_GetRequestBody)
377 3d103742 Iustin Pop
378 3fb8680a Michael Hanselmann
  def _checkIntVariable(self, name, default=0):
379 3d103742 Iustin Pop
    """Return the parsed value of an int argument.
380 3d103742 Iustin Pop

381 3d103742 Iustin Pop
    """
382 3fb8680a Michael Hanselmann
    val = self.queryargs.get(name, default)
383 3d103742 Iustin Pop
    if isinstance(val, list):
384 3d103742 Iustin Pop
      if val:
385 3d103742 Iustin Pop
        val = val[0]
386 3d103742 Iustin Pop
      else:
387 3fb8680a Michael Hanselmann
        val = default
388 3d103742 Iustin Pop
    try:
389 3d103742 Iustin Pop
      val = int(val)
390 7c4d6c7b Michael Hanselmann
    except (ValueError, TypeError):
391 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Invalid value for the"
392 3d103742 Iustin Pop
                                " '%s' parameter" % (name,))
393 3d103742 Iustin Pop
    return val
394 3d103742 Iustin Pop
395 e5b7c4ca Iustin Pop
  def _checkStringVariable(self, name, default=None):
396 e5b7c4ca Iustin Pop
    """Return the parsed value of an int argument.
397 e5b7c4ca Iustin Pop

398 e5b7c4ca Iustin Pop
    """
399 e5b7c4ca Iustin Pop
    val = self.queryargs.get(name, default)
400 e5b7c4ca Iustin Pop
    if isinstance(val, list):
401 e5b7c4ca Iustin Pop
      if val:
402 e5b7c4ca Iustin Pop
        val = val[0]
403 e5b7c4ca Iustin Pop
      else:
404 e5b7c4ca Iustin Pop
        val = default
405 e5b7c4ca Iustin Pop
    return val
406 3d103742 Iustin Pop
407 6e99c5a0 Iustin Pop
  def getBodyParameter(self, name, *args):
408 6e99c5a0 Iustin Pop
    """Check and return the value for a given parameter.
409 6e99c5a0 Iustin Pop

410 6e99c5a0 Iustin Pop
    If a second parameter is not given, an error will be returned,
411 6e99c5a0 Iustin Pop
    otherwise this parameter specifies the default value.
412 6e99c5a0 Iustin Pop

413 6e99c5a0 Iustin Pop
    @param name: the required parameter
414 6e99c5a0 Iustin Pop

415 6e99c5a0 Iustin Pop
    """
416 af6433c6 Michael Hanselmann
    if args:
417 1c54156d Luca Bigliardi
      return CheckParameter(self.request_body, name, default=args[0])
418 ab221ddf Michael Hanselmann
419 1c54156d Luca Bigliardi
    return CheckParameter(self.request_body, name)
420 6e99c5a0 Iustin Pop
421 3d103742 Iustin Pop
  def useLocking(self):
422 3d103742 Iustin Pop
    """Check if the request specifies locking.
423 3d103742 Iustin Pop

424 3d103742 Iustin Pop
    """
425 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("lock"))
426 3d103742 Iustin Pop
427 3d103742 Iustin Pop
  def useBulk(self):
428 3d103742 Iustin Pop
    """Check if the request specifies bulk querying.
429 3d103742 Iustin Pop

430 3d103742 Iustin Pop
    """
431 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("bulk"))
432 6f59b964 Iustin Pop
433 3427d34f Michael Hanselmann
  def useForce(self):
434 3427d34f Michael Hanselmann
    """Check if the request specifies a forced operation.
435 3427d34f Michael Hanselmann

436 3427d34f Michael Hanselmann
    """
437 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("force"))
438 3427d34f Michael Hanselmann
439 6f59b964 Iustin Pop
  def dryRun(self):
440 6f59b964 Iustin Pop
    """Check if the request specifies dry-run mode.
441 6f59b964 Iustin Pop

442 6f59b964 Iustin Pop
    """
443 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("dry-run"))