Package ganeti :: Package rapi :: Module baserlib
[hide private]
[frames] | no frames]

Source Code for Module ganeti.rapi.baserlib

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008 Google Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 19  # 02110-1301, USA. 
 20   
 21   
 22  """Remote API base resources library. 
 23   
 24  """ 
 25   
 26  # pylint: disable-msg=C0103 
 27   
 28  # C0103: Invalid name, since the R_* names are not conforming 
 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 -def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
42 """Builds a URI list as used by index resources. 43 44 @param ids: list of ids as strings 45 @param uri_format: format to be applied for URI 46 @param uri_fields: optional parameter for field IDs 47 48 """ 49 (field_id, field_uri) = uri_fields 50 51 def _MapId(m_id): 52 return { field_id: m_id, field_uri: uri_format % m_id, }
53 54 # Make sure the result is sorted, makes it nicer to look at and simplifies 55 # unittests. 56 ids.sort() 57 58 return map(_MapId, ids) 59 60
61 -def ExtractField(sequence, index):
62 """Creates a list containing one column out of a list of lists. 63 64 @param sequence: sequence of lists 65 @param index: index of field 66 67 """ 68 return map(lambda item: item[index], sequence)
69 70
71 -def MapFields(names, data):
72 """Maps two lists into one dictionary. 73 74 Example:: 75 >>> MapFields(["a", "b"], ["foo", 123]) 76 {'a': 'foo', 'b': 123} 77 78 @param names: field names (list of strings) 79 @param data: field data (list) 80 81 """ 82 if len(names) != len(data): 83 raise AttributeError("Names and data must have the same length") 84 return dict(zip(names, data))
85 86
87 -def _Tags_GET(kind, name=""):
88 """Helper function to retrieve tags. 89 90 """ 91 if kind == constants.TAG_INSTANCE or kind == constants.TAG_NODE: 92 if not name: 93 raise http.HttpBadRequest("Missing name on tag request") 94 cl = GetClient() 95 if kind == constants.TAG_INSTANCE: 96 fn = cl.QueryInstances 97 else: 98 fn = cl.QueryNodes 99 result = fn(names=[name], fields=["tags"], use_locking=False) 100 if not result or not result[0]: 101 raise http.HttpBadGateway("Invalid response from tag query") 102 tags = result[0][0] 103 elif kind == constants.TAG_CLUSTER: 104 ssc = ssconf.SimpleStore() 105 tags = ssc.GetClusterTags() 106 107 return list(tags)
108 109
110 -def _Tags_PUT(kind, tags, name=""):
111 """Helper function to set tags. 112 113 """ 114 return SubmitJob([opcodes.OpAddTags(kind=kind, name=name, tags=tags)])
115 116
117 -def _Tags_DELETE(kind, tags, name=""):
118 """Helper function to delete tags. 119 120 """ 121 return SubmitJob([opcodes.OpDelTags(kind=kind, name=name, tags=tags)])
122 123
124 -def MapBulkFields(itemslist, fields):
125 """Map value to field name in to one dictionary. 126 127 @param itemslist: a list of items values 128 @param fields: a list of items names 129 130 @return: a list of mapped dictionaries 131 132 """ 133 items_details = [] 134 for item in itemslist: 135 mapped = MapFields(fields, item) 136 items_details.append(mapped) 137 return items_details
138 139
140 -def MakeParamsDict(opts, params):
141 """Makes params dictionary out of a option set. 142 143 This function returns a dictionary needed for hv or be parameters. But only 144 those fields which provided in the option set. Takes parameters frozensets 145 from constants. 146 147 @type opts: dict 148 @param opts: selected options 149 @type params: frozenset 150 @param params: subset of options 151 @rtype: dict 152 @return: dictionary of options, filtered by given subset. 153 154 """ 155 result = {} 156 157 for p in params: 158 try: 159 value = opts[p] 160 except KeyError: 161 continue 162 result[p] = value 163 164 return result
165 166
167 -def SubmitJob(op, cl=None):
168 """Generic wrapper for submit job, for better http compatibility. 169 170 @type op: list 171 @param op: the list of opcodes for the job 172 @type cl: None or luxi.Client 173 @param cl: optional luxi client to use 174 @rtype: string 175 @return: the job ID 176 177 """ 178 try: 179 if cl is None: 180 cl = GetClient() 181 return cl.SubmitJob(op) 182 except errors.JobQueueFull: 183 raise http.HttpServiceUnavailable("Job queue is full, needs archiving") 184 except errors.JobQueueDrainError: 185 raise http.HttpServiceUnavailable("Job queue is drained, cannot submit") 186 except luxi.NoMasterError, err: 187 raise http.HttpBadGateway("Master seems to unreachable: %s" % str(err)) 188 except luxi.TimeoutError, err: 189 raise http.HttpGatewayTimeout("Timeout while talking to the master" 190 " daemon. Error: %s" % str(err))
191
192 -def GetClient():
193 """Geric wrapper for luxi.Client(), for better http compatiblity. 194 195 """ 196 try: 197 return luxi.Client() 198 except luxi.NoMasterError, err: 199 raise http.HttpBadGateway("Master seems to unreachable: %s" % str(err))
200 201
202 -def FeedbackFn(ts, log_type, log_msg):
203 """Feedback logging function for http case. 204 205 We don't have a stdout for printing log messages, so log them to the 206 http log at least. 207 208 """ 209 logging.info("%s: %s", log_type, log_msg)
210 211
212 -class R_Generic(object):
213 """Generic class for resources. 214 215 """ 216 # Default permission requirements 217 GET_ACCESS = [] 218 PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE] 219 POST_ACCESS = [rapi.RAPI_ACCESS_WRITE] 220 DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE] 221
222 - def __init__(self, items, queryargs, req):
223 """Generic resource constructor. 224 225 @param items: a list with variables encoded in the URL 226 @param queryargs: a dictionary with additional options from URL 227 228 """ 229 self.items = items 230 self.queryargs = queryargs 231 self.req = req 232 self.sn = None
233
234 - def getSerialNumber(self):
235 """Get Serial Number. 236 237 """ 238 return self.sn
239
240 - def _checkIntVariable(self, name):
241 """Return the parsed value of an int argument. 242 243 """ 244 val = self.queryargs.get(name, 0) 245 if isinstance(val, list): 246 if val: 247 val = val[0] 248 else: 249 val = 0 250 try: 251 val = int(val) 252 except (ValueError, TypeError): 253 raise http.HttpBadRequest("Invalid value for the" 254 " '%s' parameter" % (name,)) 255 return val
256
257 - def _checkStringVariable(self, name, default=None):
258 """Return the parsed value of an int argument. 259 260 """ 261 val = self.queryargs.get(name, default) 262 if isinstance(val, list): 263 if val: 264 val = val[0] 265 else: 266 val = default 267 return val
268
269 - def getBodyParameter(self, name, *args):
270 """Check and return the value for a given parameter. 271 272 If a second parameter is not given, an error will be returned, 273 otherwise this parameter specifies the default value. 274 275 @param name: the required parameter 276 277 """ 278 if name in self.req.request_body: 279 return self.req.request_body[name] 280 elif args: 281 return args[0] 282 else: 283 raise http.HttpBadRequest("Required parameter '%s' is missing" % 284 name)
285
286 - def useLocking(self):
287 """Check if the request specifies locking. 288 289 """ 290 return self._checkIntVariable('lock')
291
292 - def useBulk(self):
293 """Check if the request specifies bulk querying. 294 295 """ 296 return self._checkIntVariable('bulk')
297