Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / baserlib.py @ c08fd0d6

History | View | Annotate | Download (13.7 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 fe267188 Iustin Pop
# pylint: disable-msg=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 59b4eeef Iustin Pop
from ganeti import errors
36 c08fd0d6 Michael Hanselmann
from ganeti import compat
37 441e7cfd Oleksiy Mishchenko
38 c2dca9af Oleksiy Mishchenko
39 af6433c6 Michael Hanselmann
# Dummy value to detect unchanged parameters
40 af6433c6 Michael Hanselmann
_DEFAULT = object()
41 af6433c6 Michael Hanselmann
42 c08fd0d6 Michael Hanselmann
#: Supported HTTP methods
43 c08fd0d6 Michael Hanselmann
_SUPPORTED_METHODS = frozenset([
44 c08fd0d6 Michael Hanselmann
  http.HTTP_DELETE,
45 c08fd0d6 Michael Hanselmann
  http.HTTP_GET,
46 c08fd0d6 Michael Hanselmann
  http.HTTP_POST,
47 c08fd0d6 Michael Hanselmann
  http.HTTP_PUT,
48 c08fd0d6 Michael Hanselmann
  ])
49 c08fd0d6 Michael Hanselmann
50 af6433c6 Michael Hanselmann
51 c2dca9af Oleksiy Mishchenko
def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
52 c2dca9af Oleksiy Mishchenko
  """Builds a URI list as used by index resources.
53 c2dca9af Oleksiy Mishchenko

54 c41eea6e Iustin Pop
  @param ids: list of ids as strings
55 c41eea6e Iustin Pop
  @param uri_format: format to be applied for URI
56 c41eea6e Iustin Pop
  @param uri_fields: optional parameter for field IDs
57 c2dca9af Oleksiy Mishchenko

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

77 c41eea6e Iustin Pop
  @param sequence: sequence of lists
78 c41eea6e Iustin Pop
  @param index: index of field
79 c2dca9af Oleksiy Mishchenko

80 c2dca9af Oleksiy Mishchenko
  """
81 c2dca9af Oleksiy Mishchenko
  return map(lambda item: item[index], sequence)
82 c2dca9af Oleksiy Mishchenko
83 c2dca9af Oleksiy Mishchenko
84 c2dca9af Oleksiy Mishchenko
def MapFields(names, data):
85 c2dca9af Oleksiy Mishchenko
  """Maps two lists into one dictionary.
86 c2dca9af Oleksiy Mishchenko

87 c41eea6e Iustin Pop
  Example::
88 c41eea6e Iustin Pop
      >>> MapFields(["a", "b"], ["foo", 123])
89 c41eea6e Iustin Pop
      {'a': 'foo', 'b': 123}
90 c2dca9af Oleksiy Mishchenko

91 c41eea6e Iustin Pop
  @param names: field names (list of strings)
92 c41eea6e Iustin Pop
  @param data: field data (list)
93 c2dca9af Oleksiy Mishchenko

94 c2dca9af Oleksiy Mishchenko
  """
95 c2dca9af Oleksiy Mishchenko
  if len(names) != len(data):
96 c2dca9af Oleksiy Mishchenko
    raise AttributeError("Names and data must have the same length")
97 dca1764e Iustin Pop
  return dict(zip(names, data))
98 c2dca9af Oleksiy Mishchenko
99 c2dca9af Oleksiy Mishchenko
100 51ee2f49 Oleksiy Mishchenko
def MapBulkFields(itemslist, fields):
101 51ee2f49 Oleksiy Mishchenko
  """Map value to field name in to one dictionary.
102 51ee2f49 Oleksiy Mishchenko

103 c41eea6e Iustin Pop
  @param itemslist: a list of items values
104 c41eea6e Iustin Pop
  @param fields: a list of items names
105 c41eea6e Iustin Pop

106 c41eea6e Iustin Pop
  @return: a list of mapped dictionaries
107 51ee2f49 Oleksiy Mishchenko

108 51ee2f49 Oleksiy Mishchenko
  """
109 51ee2f49 Oleksiy Mishchenko
  items_details = []
110 51ee2f49 Oleksiy Mishchenko
  for item in itemslist:
111 51ee2f49 Oleksiy Mishchenko
    mapped = MapFields(fields, item)
112 51ee2f49 Oleksiy Mishchenko
    items_details.append(mapped)
113 51ee2f49 Oleksiy Mishchenko
  return items_details
114 51ee2f49 Oleksiy Mishchenko
115 51ee2f49 Oleksiy Mishchenko
116 d50b3059 Oleksiy Mishchenko
def MakeParamsDict(opts, params):
117 c41eea6e Iustin Pop
  """Makes params dictionary out of a option set.
118 d50b3059 Oleksiy Mishchenko

119 d50b3059 Oleksiy Mishchenko
  This function returns a dictionary needed for hv or be parameters. But only
120 d50b3059 Oleksiy Mishchenko
  those fields which provided in the option set. Takes parameters frozensets
121 d50b3059 Oleksiy Mishchenko
  from constants.
122 d50b3059 Oleksiy Mishchenko

123 d50b3059 Oleksiy Mishchenko
  @type opts: dict
124 d50b3059 Oleksiy Mishchenko
  @param opts: selected options
125 d50b3059 Oleksiy Mishchenko
  @type params: frozenset
126 d50b3059 Oleksiy Mishchenko
  @param params: subset of options
127 d50b3059 Oleksiy Mishchenko
  @rtype: dict
128 d50b3059 Oleksiy Mishchenko
  @return: dictionary of options, filtered by given subset.
129 d50b3059 Oleksiy Mishchenko

130 d50b3059 Oleksiy Mishchenko
  """
131 d50b3059 Oleksiy Mishchenko
  result = {}
132 d50b3059 Oleksiy Mishchenko
133 d50b3059 Oleksiy Mishchenko
  for p in params:
134 d50b3059 Oleksiy Mishchenko
    try:
135 d50b3059 Oleksiy Mishchenko
      value = opts[p]
136 d50b3059 Oleksiy Mishchenko
    except KeyError:
137 d50b3059 Oleksiy Mishchenko
      continue
138 d50b3059 Oleksiy Mishchenko
    result[p] = value
139 d50b3059 Oleksiy Mishchenko
140 d50b3059 Oleksiy Mishchenko
  return result
141 d50b3059 Oleksiy Mishchenko
142 d50b3059 Oleksiy Mishchenko
143 b166ef84 Michael Hanselmann
def FillOpcode(opcls, body, static, rename=None):
144 cfaeaaf7 Michael Hanselmann
  """Fills an opcode with body parameters.
145 cfaeaaf7 Michael Hanselmann

146 cfaeaaf7 Michael Hanselmann
  Parameter types are checked.
147 cfaeaaf7 Michael Hanselmann

148 cfaeaaf7 Michael Hanselmann
  @type opcls: L{opcodes.OpCode}
149 cfaeaaf7 Michael Hanselmann
  @param opcls: Opcode class
150 cfaeaaf7 Michael Hanselmann
  @type body: dict
151 cfaeaaf7 Michael Hanselmann
  @param body: Body parameters as received from client
152 cfaeaaf7 Michael Hanselmann
  @type static: dict
153 cfaeaaf7 Michael Hanselmann
  @param static: Static parameters which can't be modified by client
154 b166ef84 Michael Hanselmann
  @type rename: dict
155 b166ef84 Michael Hanselmann
  @param rename: Renamed parameters, key as old name, value as new name
156 cfaeaaf7 Michael Hanselmann
  @return: Opcode object
157 cfaeaaf7 Michael Hanselmann

158 cfaeaaf7 Michael Hanselmann
  """
159 cfaeaaf7 Michael Hanselmann
  CheckType(body, dict, "Body contents")
160 cfaeaaf7 Michael Hanselmann
161 b166ef84 Michael Hanselmann
  # Make copy to be modified
162 b166ef84 Michael Hanselmann
  params = body.copy()
163 b166ef84 Michael Hanselmann
164 b166ef84 Michael Hanselmann
  if rename:
165 b166ef84 Michael Hanselmann
    for old, new in rename.items():
166 b166ef84 Michael Hanselmann
      if new in params and old in params:
167 b166ef84 Michael Hanselmann
        raise http.HttpBadRequest("Parameter '%s' was renamed to '%s', but"
168 b166ef84 Michael Hanselmann
                                  " both are specified" %
169 b166ef84 Michael Hanselmann
                                  (old, new))
170 b166ef84 Michael Hanselmann
      if old in params:
171 b166ef84 Michael Hanselmann
        assert new not in params
172 b166ef84 Michael Hanselmann
        params[new] = params.pop(old)
173 b166ef84 Michael Hanselmann
174 cfaeaaf7 Michael Hanselmann
  if static:
175 b166ef84 Michael Hanselmann
    overwritten = set(params.keys()) & set(static.keys())
176 cfaeaaf7 Michael Hanselmann
    if overwritten:
177 cfaeaaf7 Michael Hanselmann
      raise http.HttpBadRequest("Can't overwrite static parameters %r" %
178 cfaeaaf7 Michael Hanselmann
                                overwritten)
179 cfaeaaf7 Michael Hanselmann
180 cfaeaaf7 Michael Hanselmann
    params.update(static)
181 cfaeaaf7 Michael Hanselmann
182 cfaeaaf7 Michael Hanselmann
  # Convert keys to strings (simplejson decodes them as unicode)
183 cfaeaaf7 Michael Hanselmann
  params = dict((str(key), value) for (key, value) in params.items())
184 cfaeaaf7 Michael Hanselmann
185 cfaeaaf7 Michael Hanselmann
  try:
186 cfaeaaf7 Michael Hanselmann
    op = opcls(**params) # pylint: disable-msg=W0142
187 cfaeaaf7 Michael Hanselmann
    op.Validate(False)
188 cfaeaaf7 Michael Hanselmann
  except (errors.OpPrereqError, TypeError), err:
189 cfaeaaf7 Michael Hanselmann
    raise http.HttpBadRequest("Invalid body parameters: %s" % err)
190 cfaeaaf7 Michael Hanselmann
191 cfaeaaf7 Michael Hanselmann
  return op
192 cfaeaaf7 Michael Hanselmann
193 cfaeaaf7 Michael Hanselmann
194 e8ebbd2b Michael Hanselmann
def HandleItemQueryErrors(fn, *args, **kwargs):
195 e8ebbd2b Michael Hanselmann
  """Converts errors when querying a single item.
196 e8ebbd2b Michael Hanselmann

197 e8ebbd2b Michael Hanselmann
  """
198 e8ebbd2b Michael Hanselmann
  try:
199 e8ebbd2b Michael Hanselmann
    return fn(*args, **kwargs)
200 e8ebbd2b Michael Hanselmann
  except errors.OpPrereqError, err:
201 e8ebbd2b Michael Hanselmann
    if len(err.args) == 2 and err.args[1] == errors.ECODE_NOENT:
202 e8ebbd2b Michael Hanselmann
      raise http.HttpNotFound()
203 e8ebbd2b Michael Hanselmann
204 e8ebbd2b Michael Hanselmann
    raise
205 e8ebbd2b Michael Hanselmann
206 e8ebbd2b Michael Hanselmann
207 e51ca051 Michael Hanselmann
def FeedbackFn(msg):
208 e51ca051 Michael Hanselmann
  """Feedback logging function for jobs.
209 59b4eeef Iustin Pop

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

213 e51ca051 Michael Hanselmann
  @param msg: the message
214 2d54e29c Iustin Pop

215 59b4eeef Iustin Pop
  """
216 e51ca051 Michael Hanselmann
  (_, log_type, log_msg) = msg
217 59b4eeef Iustin Pop
  logging.info("%s: %s", log_type, log_msg)
218 59b4eeef Iustin Pop
219 59b4eeef Iustin Pop
220 af6433c6 Michael Hanselmann
def CheckType(value, exptype, descr):
221 af6433c6 Michael Hanselmann
  """Abort request if value type doesn't match expected type.
222 af6433c6 Michael Hanselmann

223 af6433c6 Michael Hanselmann
  @param value: Value
224 af6433c6 Michael Hanselmann
  @type exptype: type
225 af6433c6 Michael Hanselmann
  @param exptype: Expected type
226 af6433c6 Michael Hanselmann
  @type descr: string
227 af6433c6 Michael Hanselmann
  @param descr: Description of value
228 af6433c6 Michael Hanselmann
  @return: Value (allows inline usage)
229 af6433c6 Michael Hanselmann

230 af6433c6 Michael Hanselmann
  """
231 af6433c6 Michael Hanselmann
  if not isinstance(value, exptype):
232 af6433c6 Michael Hanselmann
    raise http.HttpBadRequest("%s: Type is '%s', but '%s' is expected" %
233 af6433c6 Michael Hanselmann
                              (descr, type(value).__name__, exptype.__name__))
234 af6433c6 Michael Hanselmann
235 af6433c6 Michael Hanselmann
  return value
236 af6433c6 Michael Hanselmann
237 af6433c6 Michael Hanselmann
238 af6433c6 Michael Hanselmann
def CheckParameter(data, name, default=_DEFAULT, exptype=_DEFAULT):
239 af6433c6 Michael Hanselmann
  """Check and return the value for a given parameter.
240 af6433c6 Michael Hanselmann

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

244 af6433c6 Michael Hanselmann
  @type data: dict
245 af6433c6 Michael Hanselmann
  @param data: Dictionary containing input data
246 af6433c6 Michael Hanselmann
  @type name: string
247 af6433c6 Michael Hanselmann
  @param name: Parameter name
248 af6433c6 Michael Hanselmann
  @param default: Default value (can be None)
249 af6433c6 Michael Hanselmann
  @param exptype: Expected type (can be None)
250 af6433c6 Michael Hanselmann

251 af6433c6 Michael Hanselmann
  """
252 af6433c6 Michael Hanselmann
  try:
253 af6433c6 Michael Hanselmann
    value = data[name]
254 af6433c6 Michael Hanselmann
  except KeyError:
255 af6433c6 Michael Hanselmann
    if default is not _DEFAULT:
256 af6433c6 Michael Hanselmann
      return default
257 af6433c6 Michael Hanselmann
258 af6433c6 Michael Hanselmann
    raise http.HttpBadRequest("Required parameter '%s' is missing" %
259 af6433c6 Michael Hanselmann
                              name)
260 af6433c6 Michael Hanselmann
261 af6433c6 Michael Hanselmann
  if exptype is _DEFAULT:
262 af6433c6 Michael Hanselmann
    return value
263 af6433c6 Michael Hanselmann
264 af6433c6 Michael Hanselmann
  return CheckType(value, exptype, "'%s' parameter" % name)
265 af6433c6 Michael Hanselmann
266 af6433c6 Michael Hanselmann
267 26ff6ee2 Michael Hanselmann
class ResourceBase(object):
268 c2dca9af Oleksiy Mishchenko
  """Generic class for resources.
269 c2dca9af Oleksiy Mishchenko

270 c2dca9af Oleksiy Mishchenko
  """
271 b5b67ef9 Michael Hanselmann
  # Default permission requirements
272 b5b67ef9 Michael Hanselmann
  GET_ACCESS = []
273 b5b67ef9 Michael Hanselmann
  PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
274 b5b67ef9 Michael Hanselmann
  POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
275 b5b67ef9 Michael Hanselmann
  DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]
276 b5b67ef9 Michael Hanselmann
277 7a8f64da Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
278 c2dca9af Oleksiy Mishchenko
    """Generic resource constructor.
279 c2dca9af Oleksiy Mishchenko

280 c41eea6e Iustin Pop
    @param items: a list with variables encoded in the URL
281 c41eea6e Iustin Pop
    @param queryargs: a dictionary with additional options from URL
282 c2dca9af Oleksiy Mishchenko

283 c2dca9af Oleksiy Mishchenko
    """
284 c2dca9af Oleksiy Mishchenko
    self.items = items
285 c2dca9af Oleksiy Mishchenko
    self.queryargs = queryargs
286 627ad739 Michael Hanselmann
    self._req = req
287 627ad739 Michael Hanselmann
288 2feecf12 Michael Hanselmann
  def _GetRequestBody(self):
289 2feecf12 Michael Hanselmann
    """Returns the body data.
290 2feecf12 Michael Hanselmann

291 2feecf12 Michael Hanselmann
    """
292 2feecf12 Michael Hanselmann
    return self._req.private.body_data
293 2feecf12 Michael Hanselmann
294 2feecf12 Michael Hanselmann
  request_body = property(fget=_GetRequestBody)
295 3d103742 Iustin Pop
296 3fb8680a Michael Hanselmann
  def _checkIntVariable(self, name, default=0):
297 3d103742 Iustin Pop
    """Return the parsed value of an int argument.
298 3d103742 Iustin Pop

299 3d103742 Iustin Pop
    """
300 3fb8680a Michael Hanselmann
    val = self.queryargs.get(name, default)
301 3d103742 Iustin Pop
    if isinstance(val, list):
302 3d103742 Iustin Pop
      if val:
303 3d103742 Iustin Pop
        val = val[0]
304 3d103742 Iustin Pop
      else:
305 3fb8680a Michael Hanselmann
        val = default
306 3d103742 Iustin Pop
    try:
307 3d103742 Iustin Pop
      val = int(val)
308 7c4d6c7b Michael Hanselmann
    except (ValueError, TypeError):
309 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Invalid value for the"
310 3d103742 Iustin Pop
                                " '%s' parameter" % (name,))
311 3d103742 Iustin Pop
    return val
312 3d103742 Iustin Pop
313 e5b7c4ca Iustin Pop
  def _checkStringVariable(self, name, default=None):
314 e5b7c4ca Iustin Pop
    """Return the parsed value of an int argument.
315 e5b7c4ca Iustin Pop

316 e5b7c4ca Iustin Pop
    """
317 e5b7c4ca Iustin Pop
    val = self.queryargs.get(name, default)
318 e5b7c4ca Iustin Pop
    if isinstance(val, list):
319 e5b7c4ca Iustin Pop
      if val:
320 e5b7c4ca Iustin Pop
        val = val[0]
321 e5b7c4ca Iustin Pop
      else:
322 e5b7c4ca Iustin Pop
        val = default
323 e5b7c4ca Iustin Pop
    return val
324 3d103742 Iustin Pop
325 6e99c5a0 Iustin Pop
  def getBodyParameter(self, name, *args):
326 6e99c5a0 Iustin Pop
    """Check and return the value for a given parameter.
327 6e99c5a0 Iustin Pop

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

331 6e99c5a0 Iustin Pop
    @param name: the required parameter
332 6e99c5a0 Iustin Pop

333 6e99c5a0 Iustin Pop
    """
334 af6433c6 Michael Hanselmann
    if args:
335 1c54156d Luca Bigliardi
      return CheckParameter(self.request_body, name, default=args[0])
336 ab221ddf Michael Hanselmann
337 1c54156d Luca Bigliardi
    return CheckParameter(self.request_body, name)
338 6e99c5a0 Iustin Pop
339 3d103742 Iustin Pop
  def useLocking(self):
340 3d103742 Iustin Pop
    """Check if the request specifies locking.
341 3d103742 Iustin Pop

342 3d103742 Iustin Pop
    """
343 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("lock"))
344 3d103742 Iustin Pop
345 3d103742 Iustin Pop
  def useBulk(self):
346 3d103742 Iustin Pop
    """Check if the request specifies bulk querying.
347 3d103742 Iustin Pop

348 3d103742 Iustin Pop
    """
349 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("bulk"))
350 6f59b964 Iustin Pop
351 3427d34f Michael Hanselmann
  def useForce(self):
352 3427d34f Michael Hanselmann
    """Check if the request specifies a forced operation.
353 3427d34f Michael Hanselmann

354 3427d34f Michael Hanselmann
    """
355 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("force"))
356 3427d34f Michael Hanselmann
357 6f59b964 Iustin Pop
  def dryRun(self):
358 6f59b964 Iustin Pop
    """Check if the request specifies dry-run mode.
359 6f59b964 Iustin Pop

360 6f59b964 Iustin Pop
    """
361 b939de46 Michael Hanselmann
    return bool(self._checkIntVariable("dry-run"))
362 be1ddd09 Michael Hanselmann
363 be1ddd09 Michael Hanselmann
  def GetClient(self):
364 be1ddd09 Michael Hanselmann
    """Wrapper for L{luxi.Client} with HTTP-specific error handling.
365 be1ddd09 Michael Hanselmann

366 be1ddd09 Michael Hanselmann
    """
367 be1ddd09 Michael Hanselmann
    # Could be a function, pylint: disable=R0201
368 be1ddd09 Michael Hanselmann
    try:
369 be1ddd09 Michael Hanselmann
      return luxi.Client()
370 be1ddd09 Michael Hanselmann
    except luxi.NoMasterError, err:
371 be1ddd09 Michael Hanselmann
      raise http.HttpBadGateway("Can't connect to master daemon: %s" % err)
372 be1ddd09 Michael Hanselmann
    except luxi.PermissionError:
373 be1ddd09 Michael Hanselmann
      raise http.HttpInternalServerError("Internal error: no permission to"
374 be1ddd09 Michael Hanselmann
                                         " connect to the master daemon")
375 be1ddd09 Michael Hanselmann
376 be1ddd09 Michael Hanselmann
  def SubmitJob(self, op, cl=None):
377 be1ddd09 Michael Hanselmann
    """Generic wrapper for submit job, for better http compatibility.
378 be1ddd09 Michael Hanselmann

379 be1ddd09 Michael Hanselmann
    @type op: list
380 be1ddd09 Michael Hanselmann
    @param op: the list of opcodes for the job
381 be1ddd09 Michael Hanselmann
    @type cl: None or luxi.Client
382 be1ddd09 Michael Hanselmann
    @param cl: optional luxi client to use
383 be1ddd09 Michael Hanselmann
    @rtype: string
384 be1ddd09 Michael Hanselmann
    @return: the job ID
385 be1ddd09 Michael Hanselmann

386 be1ddd09 Michael Hanselmann
    """
387 be1ddd09 Michael Hanselmann
    if cl is None:
388 be1ddd09 Michael Hanselmann
      cl = self.GetClient()
389 be1ddd09 Michael Hanselmann
    try:
390 be1ddd09 Michael Hanselmann
      return cl.SubmitJob(op)
391 be1ddd09 Michael Hanselmann
    except errors.JobQueueFull:
392 be1ddd09 Michael Hanselmann
      raise http.HttpServiceUnavailable("Job queue is full, needs archiving")
393 be1ddd09 Michael Hanselmann
    except errors.JobQueueDrainError:
394 be1ddd09 Michael Hanselmann
      raise http.HttpServiceUnavailable("Job queue is drained, cannot submit")
395 be1ddd09 Michael Hanselmann
    except luxi.NoMasterError, err:
396 be1ddd09 Michael Hanselmann
      raise http.HttpBadGateway("Master seems to be unreachable: %s" % err)
397 be1ddd09 Michael Hanselmann
    except luxi.PermissionError:
398 be1ddd09 Michael Hanselmann
      raise http.HttpInternalServerError("Internal error: no permission to"
399 be1ddd09 Michael Hanselmann
                                         " connect to the master daemon")
400 be1ddd09 Michael Hanselmann
    except luxi.TimeoutError, err:
401 be1ddd09 Michael Hanselmann
      raise http.HttpGatewayTimeout("Timeout while talking to the master"
402 be1ddd09 Michael Hanselmann
                                    " daemon: %s" % err)
403 c08fd0d6 Michael Hanselmann
404 c08fd0d6 Michael Hanselmann
405 c08fd0d6 Michael Hanselmann
class _MetaOpcodeResource(type):
406 c08fd0d6 Michael Hanselmann
  """Meta class for RAPI resources.
407 c08fd0d6 Michael Hanselmann

408 c08fd0d6 Michael Hanselmann
  """
409 c08fd0d6 Michael Hanselmann
  _ATTRS = [(method, "%s_OPCODE" % method, "%s_RENAME" % method,
410 c08fd0d6 Michael Hanselmann
             "Get%sOpInput" % method.capitalize())
411 c08fd0d6 Michael Hanselmann
            for method in _SUPPORTED_METHODS]
412 c08fd0d6 Michael Hanselmann
413 c08fd0d6 Michael Hanselmann
  def __call__(mcs, *args, **kwargs):
414 c08fd0d6 Michael Hanselmann
    """Instantiates class and patches it for use by the RAPI daemon.
415 c08fd0d6 Michael Hanselmann

416 c08fd0d6 Michael Hanselmann
    """
417 c08fd0d6 Michael Hanselmann
    # Access to private attributes of a client class, pylint: disable=W0212
418 c08fd0d6 Michael Hanselmann
    obj = type.__call__(mcs, *args, **kwargs)
419 c08fd0d6 Michael Hanselmann
420 c08fd0d6 Michael Hanselmann
    for (method, op_attr, rename_attr, fn_attr) in mcs._ATTRS:
421 c08fd0d6 Michael Hanselmann
      try:
422 c08fd0d6 Michael Hanselmann
        opcode = getattr(obj, op_attr)
423 c08fd0d6 Michael Hanselmann
      except AttributeError:
424 c08fd0d6 Michael Hanselmann
        # If the "*_OPCODE" attribute isn't set, "*_RENAME" or "Get*OpInput"
425 c08fd0d6 Michael Hanselmann
        # shouldn't either
426 c08fd0d6 Michael Hanselmann
        assert not hasattr(obj, rename_attr)
427 c08fd0d6 Michael Hanselmann
        assert not hasattr(obj, fn_attr)
428 c08fd0d6 Michael Hanselmann
        continue
429 c08fd0d6 Michael Hanselmann
430 c08fd0d6 Michael Hanselmann
      assert not hasattr(obj, method)
431 c08fd0d6 Michael Hanselmann
432 c08fd0d6 Michael Hanselmann
      # Generate handler method on handler instance
433 c08fd0d6 Michael Hanselmann
      setattr(obj, method,
434 c08fd0d6 Michael Hanselmann
              compat.partial(obj._GenericHandler, opcode,
435 c08fd0d6 Michael Hanselmann
                             getattr(obj, rename_attr, None),
436 c08fd0d6 Michael Hanselmann
                             getattr(obj, fn_attr, obj._GetDefaultData)))
437 c08fd0d6 Michael Hanselmann
438 c08fd0d6 Michael Hanselmann
    return obj
439 c08fd0d6 Michael Hanselmann
440 c08fd0d6 Michael Hanselmann
441 c08fd0d6 Michael Hanselmann
class OpcodeResource(ResourceBase):
442 c08fd0d6 Michael Hanselmann
  """Base class for opcode-based RAPI resources.
443 c08fd0d6 Michael Hanselmann

444 c08fd0d6 Michael Hanselmann
  Instances of this class automatically gain handler functions through
445 c08fd0d6 Michael Hanselmann
  L{_MetaOpcodeResource} for any method for which a C{$METHOD$_OPCODE} variable
446 c08fd0d6 Michael Hanselmann
  is defined at class level. Subclasses can define a C{Get$Method$OpInput}
447 c08fd0d6 Michael Hanselmann
  method to do their own opcode input processing (e.g. for static values). The
448 c08fd0d6 Michael Hanselmann
  C{$METHOD$_RENAME} variable defines which values are renamed (see
449 c08fd0d6 Michael Hanselmann
  L{FillOpcode}).
450 c08fd0d6 Michael Hanselmann

451 c08fd0d6 Michael Hanselmann
  @cvar GET_OPCODE: Set this to a class derived from L{opcodes.OpCode} to
452 c08fd0d6 Michael Hanselmann
    automatically generate a GET handler submitting the opcode
453 c08fd0d6 Michael Hanselmann
  @cvar GET_RENAME: Set this to rename parameters in the GET handler (see
454 c08fd0d6 Michael Hanselmann
    L{FillOpcode})
455 c08fd0d6 Michael Hanselmann
  @ivar GetGetOpInput: Define this to override the default method for
456 c08fd0d6 Michael Hanselmann
    getting opcode parameters (see L{baserlib.OpcodeResource._GetDefaultData})
457 c08fd0d6 Michael Hanselmann

458 c08fd0d6 Michael Hanselmann
  @cvar PUT_OPCODE: Set this to a class derived from L{opcodes.OpCode} to
459 c08fd0d6 Michael Hanselmann
    automatically generate a PUT handler submitting the opcode
460 c08fd0d6 Michael Hanselmann
  @cvar PUT_RENAME: Set this to rename parameters in the PUT handler (see
461 c08fd0d6 Michael Hanselmann
    L{FillOpcode})
462 c08fd0d6 Michael Hanselmann
  @ivar GetPutOpInput: Define this to override the default method for
463 c08fd0d6 Michael Hanselmann
    getting opcode parameters (see L{baserlib.OpcodeResource._GetDefaultData})
464 c08fd0d6 Michael Hanselmann

465 c08fd0d6 Michael Hanselmann
  @cvar POST_OPCODE: Set this to a class derived from L{opcodes.OpCode} to
466 c08fd0d6 Michael Hanselmann
    automatically generate a POST handler submitting the opcode
467 c08fd0d6 Michael Hanselmann
  @cvar POST_RENAME: Set this to rename parameters in the DELETE handler (see
468 c08fd0d6 Michael Hanselmann
    L{FillOpcode})
469 c08fd0d6 Michael Hanselmann
  @ivar GetPostOpInput: Define this to override the default method for
470 c08fd0d6 Michael Hanselmann
    getting opcode parameters (see L{baserlib.OpcodeResource._GetDefaultData})
471 c08fd0d6 Michael Hanselmann

472 c08fd0d6 Michael Hanselmann
  @cvar DELETE_OPCODE: Set this to a class derived from L{opcodes.OpCode} to
473 c08fd0d6 Michael Hanselmann
    automatically generate a GET handler submitting the opcode
474 c08fd0d6 Michael Hanselmann
  @cvar DELETE_RENAME: Set this to rename parameters in the DELETE handler (see
475 c08fd0d6 Michael Hanselmann
    L{FillOpcode})
476 c08fd0d6 Michael Hanselmann
  @ivar GetDeleteOpInput: Define this to override the default method for
477 c08fd0d6 Michael Hanselmann
    getting opcode parameters (see L{baserlib.OpcodeResource._GetDefaultData})
478 c08fd0d6 Michael Hanselmann

479 c08fd0d6 Michael Hanselmann
  """
480 c08fd0d6 Michael Hanselmann
  __metaclass__ = _MetaOpcodeResource
481 c08fd0d6 Michael Hanselmann
482 c08fd0d6 Michael Hanselmann
  def _GetDefaultData(self):
483 c08fd0d6 Michael Hanselmann
    return (self.request_body, None)
484 c08fd0d6 Michael Hanselmann
485 c08fd0d6 Michael Hanselmann
  def _GenericHandler(self, opcode, rename, fn):
486 c08fd0d6 Michael Hanselmann
    (body, static) = fn()
487 c08fd0d6 Michael Hanselmann
    op = FillOpcode(opcode, body, static, rename=rename)
488 c08fd0d6 Michael Hanselmann
    return self.SubmitJob([op])