Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / baserlib.py @ 7eac4a4d

History | View | Annotate | Download (7.9 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 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 c2dca9af Oleksiy Mishchenko
def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
42 c2dca9af Oleksiy Mishchenko
  """Builds a URI list as used by index resources.
43 c2dca9af Oleksiy Mishchenko

44 c41eea6e Iustin Pop
  @param ids: list of ids as strings
45 c41eea6e Iustin Pop
  @param uri_format: format to be applied for URI
46 c41eea6e Iustin Pop
  @param uri_fields: optional parameter for field IDs
47 c2dca9af Oleksiy Mishchenko

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

64 c41eea6e Iustin Pop
  @param sequence: sequence of lists
65 c41eea6e Iustin Pop
  @param index: index of field
66 c2dca9af Oleksiy Mishchenko

67 c2dca9af Oleksiy Mishchenko
  """
68 c2dca9af Oleksiy Mishchenko
  return map(lambda item: item[index], sequence)
69 c2dca9af Oleksiy Mishchenko
70 c2dca9af Oleksiy Mishchenko
71 c2dca9af Oleksiy Mishchenko
def MapFields(names, data):
72 c2dca9af Oleksiy Mishchenko
  """Maps two lists into one dictionary.
73 c2dca9af Oleksiy Mishchenko

74 c41eea6e Iustin Pop
  Example::
75 c41eea6e Iustin Pop
      >>> MapFields(["a", "b"], ["foo", 123])
76 c41eea6e Iustin Pop
      {'a': 'foo', 'b': 123}
77 c2dca9af Oleksiy Mishchenko

78 c41eea6e Iustin Pop
  @param names: field names (list of strings)
79 c41eea6e Iustin Pop
  @param data: field data (list)
80 c2dca9af Oleksiy Mishchenko

81 c2dca9af Oleksiy Mishchenko
  """
82 c2dca9af Oleksiy Mishchenko
  if len(names) != len(data):
83 c2dca9af Oleksiy Mishchenko
    raise AttributeError("Names and data must have the same length")
84 dca1764e Iustin Pop
  return dict(zip(names, data))
85 c2dca9af Oleksiy Mishchenko
86 c2dca9af Oleksiy Mishchenko
87 64246438 Iustin Pop
def _Tags_GET(kind, name):
88 c2dca9af Oleksiy Mishchenko
  """Helper function to retrieve tags.
89 c2dca9af Oleksiy Mishchenko

90 c2dca9af Oleksiy Mishchenko
  """
91 25e39bfa Iustin Pop
  if kind == constants.TAG_INSTANCE or kind == constants.TAG_NODE:
92 25e39bfa Iustin Pop
    if not name:
93 59b4eeef Iustin Pop
      raise http.HttpBadRequest("Missing name on tag request")
94 59b4eeef Iustin Pop
    cl = GetClient()
95 25e39bfa Iustin Pop
    if kind == constants.TAG_INSTANCE:
96 25e39bfa Iustin Pop
      fn = cl.QueryInstances
97 25e39bfa Iustin Pop
    else:
98 25e39bfa Iustin Pop
      fn = cl.QueryNodes
99 25e39bfa Iustin Pop
    result = fn(names=[name], fields=["tags"], use_locking=False)
100 25e39bfa Iustin Pop
    if not result or not result[0]:
101 25e39bfa Iustin Pop
      raise http.HttpBadGateway("Invalid response from tag query")
102 25e39bfa Iustin Pop
    tags = result[0][0]
103 25e39bfa Iustin Pop
  elif kind == constants.TAG_CLUSTER:
104 25e39bfa Iustin Pop
    ssc = ssconf.SimpleStore()
105 25e39bfa Iustin Pop
    tags = ssc.GetClusterTags()
106 25e39bfa Iustin Pop
107 c2dca9af Oleksiy Mishchenko
  return list(tags)
108 c2dca9af Oleksiy Mishchenko
109 c2dca9af Oleksiy Mishchenko
110 64246438 Iustin Pop
def _Tags_PUT(kind, tags, name, dry_run):
111 441e7cfd Oleksiy Mishchenko
  """Helper function to set tags.
112 441e7cfd Oleksiy Mishchenko

113 441e7cfd Oleksiy Mishchenko
  """
114 64246438 Iustin Pop
  return SubmitJob([opcodes.OpAddTags(kind=kind, name=name,
115 64246438 Iustin Pop
                                      tags=tags, dry_run=dry_run)])
116 441e7cfd Oleksiy Mishchenko
117 441e7cfd Oleksiy Mishchenko
118 64246438 Iustin Pop
def _Tags_DELETE(kind, tags, name, dry_run):
119 15fd9fd5 Oleksiy Mishchenko
  """Helper function to delete tags.
120 15fd9fd5 Oleksiy Mishchenko

121 15fd9fd5 Oleksiy Mishchenko
  """
122 64246438 Iustin Pop
  return SubmitJob([opcodes.OpDelTags(kind=kind, name=name,
123 64246438 Iustin Pop
                                      tags=tags, dry_run=dry_run)])
124 15fd9fd5 Oleksiy Mishchenko
125 15fd9fd5 Oleksiy Mishchenko
126 51ee2f49 Oleksiy Mishchenko
def MapBulkFields(itemslist, fields):
127 51ee2f49 Oleksiy Mishchenko
  """Map value to field name in to one dictionary.
128 51ee2f49 Oleksiy Mishchenko

129 c41eea6e Iustin Pop
  @param itemslist: a list of items values
130 c41eea6e Iustin Pop
  @param fields: a list of items names
131 c41eea6e Iustin Pop

132 c41eea6e Iustin Pop
  @return: a list of mapped dictionaries
133 51ee2f49 Oleksiy Mishchenko

134 51ee2f49 Oleksiy Mishchenko
  """
135 51ee2f49 Oleksiy Mishchenko
  items_details = []
136 51ee2f49 Oleksiy Mishchenko
  for item in itemslist:
137 51ee2f49 Oleksiy Mishchenko
    mapped = MapFields(fields, item)
138 51ee2f49 Oleksiy Mishchenko
    items_details.append(mapped)
139 51ee2f49 Oleksiy Mishchenko
  return items_details
140 51ee2f49 Oleksiy Mishchenko
141 51ee2f49 Oleksiy Mishchenko
142 d50b3059 Oleksiy Mishchenko
def MakeParamsDict(opts, params):
143 c41eea6e Iustin Pop
  """Makes params dictionary out of a option set.
144 d50b3059 Oleksiy Mishchenko

145 d50b3059 Oleksiy Mishchenko
  This function returns a dictionary needed for hv or be parameters. But only
146 d50b3059 Oleksiy Mishchenko
  those fields which provided in the option set. Takes parameters frozensets
147 d50b3059 Oleksiy Mishchenko
  from constants.
148 d50b3059 Oleksiy Mishchenko

149 d50b3059 Oleksiy Mishchenko
  @type opts: dict
150 d50b3059 Oleksiy Mishchenko
  @param opts: selected options
151 d50b3059 Oleksiy Mishchenko
  @type params: frozenset
152 d50b3059 Oleksiy Mishchenko
  @param params: subset of options
153 d50b3059 Oleksiy Mishchenko
  @rtype: dict
154 d50b3059 Oleksiy Mishchenko
  @return: dictionary of options, filtered by given subset.
155 d50b3059 Oleksiy Mishchenko

156 d50b3059 Oleksiy Mishchenko
  """
157 d50b3059 Oleksiy Mishchenko
  result = {}
158 d50b3059 Oleksiy Mishchenko
159 d50b3059 Oleksiy Mishchenko
  for p in params:
160 d50b3059 Oleksiy Mishchenko
    try:
161 d50b3059 Oleksiy Mishchenko
      value = opts[p]
162 d50b3059 Oleksiy Mishchenko
    except KeyError:
163 d50b3059 Oleksiy Mishchenko
      continue
164 d50b3059 Oleksiy Mishchenko
    result[p] = value
165 d50b3059 Oleksiy Mishchenko
166 d50b3059 Oleksiy Mishchenko
  return result
167 d50b3059 Oleksiy Mishchenko
168 d50b3059 Oleksiy Mishchenko
169 59b4eeef Iustin Pop
def SubmitJob(op, cl=None):
170 59b4eeef Iustin Pop
  """Generic wrapper for submit job, for better http compatibility.
171 59b4eeef Iustin Pop

172 59b4eeef Iustin Pop
  @type op: list
173 59b4eeef Iustin Pop
  @param op: the list of opcodes for the job
174 59b4eeef Iustin Pop
  @type cl: None or luxi.Client
175 59b4eeef Iustin Pop
  @param cl: optional luxi client to use
176 59b4eeef Iustin Pop
  @rtype: string
177 59b4eeef Iustin Pop
  @return: the job ID
178 59b4eeef Iustin Pop

179 59b4eeef Iustin Pop
  """
180 59b4eeef Iustin Pop
  try:
181 59b4eeef Iustin Pop
    if cl is None:
182 59b4eeef Iustin Pop
      cl = GetClient()
183 59b4eeef Iustin Pop
    return cl.SubmitJob(op)
184 59b4eeef Iustin Pop
  except errors.JobQueueFull:
185 59b4eeef Iustin Pop
    raise http.HttpServiceUnavailable("Job queue is full, needs archiving")
186 59b4eeef Iustin Pop
  except errors.JobQueueDrainError:
187 59b4eeef Iustin Pop
    raise http.HttpServiceUnavailable("Job queue is drained, cannot submit")
188 59b4eeef Iustin Pop
  except luxi.NoMasterError, err:
189 59b4eeef Iustin Pop
    raise http.HttpBadGateway("Master seems to unreachable: %s" % str(err))
190 59b4eeef Iustin Pop
  except luxi.TimeoutError, err:
191 59b4eeef Iustin Pop
    raise http.HttpGatewayTimeout("Timeout while talking to the master"
192 59b4eeef Iustin Pop
                                  " daemon. Error: %s" % str(err))
193 59b4eeef Iustin Pop
194 59b4eeef Iustin Pop
def GetClient():
195 59b4eeef Iustin Pop
  """Geric wrapper for luxi.Client(), for better http compatiblity.
196 59b4eeef Iustin Pop

197 59b4eeef Iustin Pop
  """
198 59b4eeef Iustin Pop
  try:
199 59b4eeef Iustin Pop
    return luxi.Client()
200 59b4eeef Iustin Pop
  except luxi.NoMasterError, err:
201 59b4eeef Iustin Pop
    raise http.HttpBadGateway("Master seems to unreachable: %s" % str(err))
202 59b4eeef Iustin Pop
203 59b4eeef Iustin Pop
204 2d54e29c Iustin Pop
def FeedbackFn(ts, log_type, log_msg): # pylint: disable-msg=W0613
205 59b4eeef Iustin Pop
  """Feedback logging function for http case.
206 59b4eeef Iustin Pop

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

210 2d54e29c Iustin Pop
  @param ts: the timestamp (unused)
211 2d54e29c Iustin Pop

212 59b4eeef Iustin Pop
  """
213 59b4eeef Iustin Pop
  logging.info("%s: %s", log_type, log_msg)
214 59b4eeef Iustin Pop
215 59b4eeef Iustin Pop
216 c2dca9af Oleksiy Mishchenko
class R_Generic(object):
217 c2dca9af Oleksiy Mishchenko
  """Generic class for resources.
218 c2dca9af Oleksiy Mishchenko

219 c2dca9af Oleksiy Mishchenko
  """
220 b5b67ef9 Michael Hanselmann
  # Default permission requirements
221 b5b67ef9 Michael Hanselmann
  GET_ACCESS = []
222 b5b67ef9 Michael Hanselmann
  PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
223 b5b67ef9 Michael Hanselmann
  POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
224 b5b67ef9 Michael Hanselmann
  DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]
225 b5b67ef9 Michael Hanselmann
226 7a8f64da Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
227 c2dca9af Oleksiy Mishchenko
    """Generic resource constructor.
228 c2dca9af Oleksiy Mishchenko

229 c41eea6e Iustin Pop
    @param items: a list with variables encoded in the URL
230 c41eea6e Iustin Pop
    @param queryargs: a dictionary with additional options from URL
231 c2dca9af Oleksiy Mishchenko

232 c2dca9af Oleksiy Mishchenko
    """
233 c2dca9af Oleksiy Mishchenko
    self.items = items
234 c2dca9af Oleksiy Mishchenko
    self.queryargs = queryargs
235 7a8f64da Oleksiy Mishchenko
    self.req = req
236 713faea6 Oleksiy Mishchenko
    self.sn = None
237 713faea6 Oleksiy Mishchenko
238 713faea6 Oleksiy Mishchenko
  def getSerialNumber(self):
239 713faea6 Oleksiy Mishchenko
    """Get Serial Number.
240 713faea6 Oleksiy Mishchenko

241 713faea6 Oleksiy Mishchenko
    """
242 713faea6 Oleksiy Mishchenko
    return self.sn
243 3d103742 Iustin Pop
244 3fb8680a Michael Hanselmann
  def _checkIntVariable(self, name, default=0):
245 3d103742 Iustin Pop
    """Return the parsed value of an int argument.
246 3d103742 Iustin Pop

247 3d103742 Iustin Pop
    """
248 3fb8680a Michael Hanselmann
    val = self.queryargs.get(name, default)
249 3d103742 Iustin Pop
    if isinstance(val, list):
250 3d103742 Iustin Pop
      if val:
251 3d103742 Iustin Pop
        val = val[0]
252 3d103742 Iustin Pop
      else:
253 3fb8680a Michael Hanselmann
        val = default
254 3d103742 Iustin Pop
    try:
255 3d103742 Iustin Pop
      val = int(val)
256 7c4d6c7b Michael Hanselmann
    except (ValueError, TypeError):
257 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Invalid value for the"
258 3d103742 Iustin Pop
                                " '%s' parameter" % (name,))
259 3d103742 Iustin Pop
    return val
260 3d103742 Iustin Pop
261 e5b7c4ca Iustin Pop
  def _checkStringVariable(self, name, default=None):
262 e5b7c4ca Iustin Pop
    """Return the parsed value of an int argument.
263 e5b7c4ca Iustin Pop

264 e5b7c4ca Iustin Pop
    """
265 e5b7c4ca Iustin Pop
    val = self.queryargs.get(name, default)
266 e5b7c4ca Iustin Pop
    if isinstance(val, list):
267 e5b7c4ca Iustin Pop
      if val:
268 e5b7c4ca Iustin Pop
        val = val[0]
269 e5b7c4ca Iustin Pop
      else:
270 e5b7c4ca Iustin Pop
        val = default
271 e5b7c4ca Iustin Pop
    return val
272 3d103742 Iustin Pop
273 6e99c5a0 Iustin Pop
  def getBodyParameter(self, name, *args):
274 6e99c5a0 Iustin Pop
    """Check and return the value for a given parameter.
275 6e99c5a0 Iustin Pop

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

279 6e99c5a0 Iustin Pop
    @param name: the required parameter
280 6e99c5a0 Iustin Pop

281 6e99c5a0 Iustin Pop
    """
282 6e99c5a0 Iustin Pop
    if name in self.req.request_body:
283 6e99c5a0 Iustin Pop
      return self.req.request_body[name]
284 6e99c5a0 Iustin Pop
    elif args:
285 6e99c5a0 Iustin Pop
      return args[0]
286 6e99c5a0 Iustin Pop
    else:
287 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Required parameter '%s' is missing" %
288 6e99c5a0 Iustin Pop
                                name)
289 6e99c5a0 Iustin Pop
290 3d103742 Iustin Pop
  def useLocking(self):
291 3d103742 Iustin Pop
    """Check if the request specifies locking.
292 3d103742 Iustin Pop

293 3d103742 Iustin Pop
    """
294 3d103742 Iustin Pop
    return self._checkIntVariable('lock')
295 3d103742 Iustin Pop
296 3d103742 Iustin Pop
  def useBulk(self):
297 3d103742 Iustin Pop
    """Check if the request specifies bulk querying.
298 3d103742 Iustin Pop

299 3d103742 Iustin Pop
    """
300 3d103742 Iustin Pop
    return self._checkIntVariable('bulk')
301 6f59b964 Iustin Pop
302 3427d34f Michael Hanselmann
  def useForce(self):
303 3427d34f Michael Hanselmann
    """Check if the request specifies a forced operation.
304 3427d34f Michael Hanselmann

305 3427d34f Michael Hanselmann
    """
306 3427d34f Michael Hanselmann
    return self._checkIntVariable('force')
307 3427d34f Michael Hanselmann
308 6f59b964 Iustin Pop
  def dryRun(self):
309 6f59b964 Iustin Pop
    """Check if the request specifies dry-run mode.
310 6f59b964 Iustin Pop

311 6f59b964 Iustin Pop
    """
312 6f59b964 Iustin Pop
    return self._checkIntVariable('dry-run')