Package cm_api :: Package endpoints :: Module types
[hide private]
[frames] | no frames]

Source Code for Module cm_api.endpoints.types

   1  # Licensed to Cloudera, Inc. under one 
   2  # or more contributor license agreements.  See the NOTICE file 
   3  # distributed with this work for additional information 
   4  # regarding copyright ownership.  Cloudera, Inc. licenses this file 
   5  # to you under the Apache License, Version 2.0 (the 
   6  # "License"); you may not use this file except in compliance 
   7  # with the License.  You may obtain a copy of the License at 
   8  # 
   9  #     http://www.apache.org/licenses/LICENSE-2.0 
  10  # 
  11  # Unless required by applicable law or agreed to in writing, software 
  12  # distributed under the License is distributed on an "AS IS" BASIS, 
  13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  14  # See the License for the specific language governing permissions and 
  15  # limitations under the License. 
  16   
  17  try: 
  18    import json 
  19  except ImportError: 
  20    import simplejson as json 
  21   
  22  import copy 
  23  import datetime 
  24  import time 
  25   
  26  __docformat__ = "epytext" 
27 28 -class Attr(object):
29 """ 30 Encapsulates information about an attribute in the JSON encoding of the 31 object. It identifies properties of the attribute such as whether it's 32 read-only, its type, etc. 33 """ 34 DATE_FMT = "%Y-%m-%dT%H:%M:%S.%fZ" 35
36 - def __init__(self, atype=None, rw=True, is_api_list=False):
37 self._atype = atype 38 self._is_api_list = is_api_list 39 self.rw = rw
40
41 - def to_json(self, value, preserve_ro):
42 """ 43 Returns the JSON encoding of the given attribute value. 44 45 If the value has a 'to_json_dict' object, that method is called. Otherwise, 46 the following values are returned for each input type: 47 - datetime.datetime: string with the API representation of a date. 48 - dictionary: if 'atype' is ApiConfig, a list of ApiConfig objects. 49 - python list: python list (or ApiList) with JSON encoding of items 50 - the raw value otherwise 51 """ 52 if hasattr(value, 'to_json_dict'): 53 return value.to_json_dict(preserve_ro) 54 elif isinstance(value, dict) and self._atype == ApiConfig: 55 return config_to_api_list(value) 56 elif isinstance(value, datetime.datetime): 57 return value.strftime(self.DATE_FMT) 58 elif isinstance(value, list) or isinstance(value, tuple): 59 if self._is_api_list: 60 return ApiList(value).to_json_dict() 61 else: 62 return [ self.to_json(x, preserve_ro) for x in value ] 63 else: 64 return value
65
66 - def from_json(self, resource_root, data):
67 """ 68 Parses the given JSON value into an appropriate python object. 69 70 This means: 71 - a datetime.datetime if 'atype' is datetime.datetime 72 - a converted config dictionary or config list if 'atype' is ApiConfig 73 - if the attr is an API list, an ApiList with instances of 'atype' 74 - an instance of 'atype' if it has a 'from_json_dict' method 75 - a python list with decoded versions of the member objects if the input 76 is a python list. 77 - the raw value otherwise 78 """ 79 if data is None: 80 return None 81 82 if self._atype == datetime.datetime: 83 return datetime.datetime.strptime(data, self.DATE_FMT) 84 elif self._atype == ApiConfig: 85 # ApiConfig is special. We want a python dictionary for summary views, 86 # but an ApiList for full views. Try to detect each case from the JSON 87 # data. 88 if not data['items']: 89 return { } 90 first = data['items'][0] 91 return json_to_config(data, len(first) == 2) 92 elif self._is_api_list: 93 return ApiList.from_json_dict(data, resource_root, self._atype) 94 elif isinstance(data, list): 95 return [ self.from_json(resource_root, x) for x in data ] 96 elif hasattr(self._atype, 'from_json_dict'): 97 return self._atype.from_json_dict(data, resource_root) 98 else: 99 return data
100
101 -class ROAttr(Attr):
102 """ 103 Subclass that just defines the attribute as read-only. 104 """
105 - def __init__(self, atype=None, is_api_list=False):
106 Attr.__init__(self, atype=atype, rw=False, is_api_list=is_api_list)
107
108 109 -def check_api_version(resource_root, min_version):
110 """ 111 Checks if the resource_root's API version it at least the given minimum 112 version. 113 """ 114 if resource_root.version < min_version: 115 raise Exception("API version %s is required but %s is in use." 116 % (min_version, resource_root.version))
117
118 119 -def call(method, path, ret_type, 120 ret_is_list=False, data=None, params=None, api_version=1):
121 """ 122 Generic function for calling a resource method and automatically dealing with 123 serialization of parameters and deserialization of return values. 124 125 @param method: method to call (must be bound to a resource; 126 e.g., "resource_root.get"). 127 @param path: the full path of the API method to call. 128 @param ret_type: return type of the call. 129 @param ret_is_list: whether the return type is an ApiList. 130 @param data: Optional data to send as payload to the call. 131 @param params: Optional query parameters for the call. 132 @param api_version: minimum API version for the call. 133 """ 134 check_api_version(method.im_self, api_version) 135 if data is not None: 136 data = json.dumps(Attr(is_api_list=True).to_json(data, False)) 137 ret = method(path, data=data, params=params) 138 else: 139 ret = method(path, params=params) 140 if ret_type is None: 141 return 142 elif ret_is_list: 143 return ApiList.from_json_dict(ret, method.im_self, ret_type) 144 elif isinstance(ret, list): 145 return [ ret_type.from_json_dict(x, method.im_self) for x in ret ] 146 else: 147 return ret_type.from_json_dict(ret, method.im_self)
148
149 -class BaseApiObject(object):
150 """ 151 The BaseApiObject helps with (de)serialization from/to JSON. 152 153 The derived class has two ways of defining custom attributes: 154 - Overwriting the '_ATTRIBUTES' field with the attribute dictionary 155 - Override the _get_attributes() method, in case static initialization of 156 the above field is not possible. 157 158 It's recommended that the _get_attributes() implementation do caching to 159 avoid computing the dictionary on every invocation. 160 161 The derived class's constructor must call the base class's init() static 162 method. All constructor arguments (aside from self and resource_root) must 163 be keywords arguments with default values (typically None), or 164 from_json_dict() will not work. 165 """ 166 167 _ATTRIBUTES = { } 168 _WHITELIST = ( '_resource_root', '_attributes' ) 169 170 @classmethod
171 - def _get_attributes(cls):
172 """ 173 Returns a map of property names to attr instances (or None for default 174 attribute behavior) describing the properties of the object. 175 176 By default, this method will return the class's _ATTRIBUTES field. 177 Classes can override this method to do custom initialization of the 178 attributes when needed. 179 """ 180 return cls._ATTRIBUTES
181 182 @staticmethod
183 - def init(obj, resource_root, attrs=None):
184 """ 185 Wraper around the real constructor to avoid issues with the 'self' 186 argument. Call like this, from a subclass's constructor: 187 188 - BaseApiObject.init(self, locals()) 189 """ 190 # This works around http://bugs.python.org/issue2646 191 # We use unicode strings as keys in kwargs. 192 str_attrs = { } 193 if attrs: 194 for k, v in attrs.iteritems(): 195 if k not in ('self', 'resource_root'): 196 str_attrs[k] = v 197 BaseApiObject.__init__(obj, resource_root, **str_attrs)
198
199 - def __init__(self, resource_root, **attrs):
200 """ 201 Initializes internal state and sets all known writable properties of the 202 object to None. Then initializes the properties given in the provided 203 attributes dictionary. 204 205 @param resource_root: API resource object. 206 @param attrs: optional dictionary of attributes to set. This should only 207 contain r/w attributes. 208 """ 209 self._resource_root = resource_root 210 211 for name, attr in self._get_attributes().iteritems(): 212 object.__setattr__(self, name, None) 213 if attrs: 214 self._set_attrs(attrs, from_json=False)
215
216 - def _set_attrs(self, attrs, allow_ro=False, from_json=True):
217 """ 218 Sets all the attributes in the dictionary. Optionally, allows setting 219 read-only attributes (e.g. when deserializing from JSON) and skipping 220 JSON deserialization of values. 221 """ 222 for k, v in attrs.iteritems(): 223 attr = self._check_attr(k, allow_ro) 224 if attr and from_json: 225 v = attr.from_json(self._get_resource_root(), v) 226 object.__setattr__(self, k, v)
227
228 - def __setattr__(self, name, val):
229 if name not in BaseApiObject._WHITELIST: 230 self._check_attr(name, False) 231 object.__setattr__(self, name, val)
232
233 - def _check_attr(self, name, allow_ro):
234 if name not in self._get_attributes(): 235 raise AttributeError('Invalid property %s for class %s.' % 236 (name, self.__class__.__name__)) 237 attr = self._get_attributes()[name] 238 if not allow_ro and attr and not attr.rw: 239 raise AttributeError('Attribute %s of class %s is read only.' % 240 (name, self.__class__.__name__)) 241 return attr
242
243 - def _get_resource_root(self):
244 return self._resource_root
245
246 - def _update(self, api_obj):
247 """Copy state from api_obj to this object.""" 248 if not isinstance(self, api_obj.__class__): 249 raise ValueError( 250 "Class %s does not derive from %s; cannot update attributes." % 251 (self.__class__, api_obj.__class__)) 252 253 for name in self._get_attributes().keys(): 254 try: 255 val = getattr(api_obj, name) 256 setattr(self, name, val) 257 except AttributeError, ignored: 258 pass
259
260 - def to_json_dict(self, preserve_ro=False):
261 dic = { } 262 for name, attr in self._get_attributes().iteritems(): 263 if not preserve_ro and attr and not attr.rw: 264 continue 265 try: 266 value = getattr(self, name) 267 if value is not None: 268 if attr: 269 dic[name] = attr.to_json(value, preserve_ro) 270 else: 271 dic[name] = value 272 except AttributeError: 273 pass 274 return dic
275
276 - def __str__(self):
277 """ 278 Default implementation of __str__. Uses the type name and the first 279 attribute retrieved from the attribute map to create the string. 280 """ 281 name = self._get_attributes().keys()[0] 282 value = getattr(self, name, None) 283 return "<%s>: %s = %s" % (self.__class__.__name__, name, value)
284 285 @classmethod
286 - def from_json_dict(cls, dic, resource_root):
287 obj = cls(resource_root) 288 obj._set_attrs(dic, allow_ro=True) 289 return obj
290
291 -class BaseApiResource(BaseApiObject):
292 """ 293 A specialization of BaseApiObject that provides some utility methods for 294 resources. This class allows easier serialization / deserialization of 295 parameters and return values. 296 """ 297
298 - def _api_version(self):
299 """ 300 Returns the minimum API version for this resource. Defaults to 1. 301 """ 302 return 1
303
304 - def _path(self):
305 """ 306 Returns the path to the resource. 307 308 e.g., for a service 'foo' in cluster 'bar', this should return 309 '/clusters/bar/services/foo'. 310 """ 311 raise NotImplementedError
312
313 - def _require_min_api_version(self, version):
314 """ 315 Raise an exception if the version of the api is less than the given version. 316 317 @param version: The minimum required version. 318 """ 319 actual_version = self._get_resource_root().version 320 version = max(version, self._api_version()) 321 if actual_version < version: 322 raise Exception("API version %s is required but %s is in use." 323 % (version, actual_version))
324
325 - def _cmd(self, command, data=None, params=None, api_version=1):
326 """ 327 Invokes a command on the resource. Commands are expected to be under the 328 "commands/" sub-resource. 329 """ 330 return self._post("commands/" + command, ApiCommand, 331 data=data, params=params, api_version=api_version)
332
333 - def _get_config(self, rel_path, view, api_version=1):
334 """ 335 Retrieves an ApiConfig list from the given relative path. 336 """ 337 self._require_min_api_version(api_version) 338 params = view and dict(view=view) or None 339 resp = self._get_resource_root().get(self._path() + '/' + rel_path, 340 params=params) 341 return json_to_config(resp, view == 'full')
342
343 - def _update_config(self, rel_path, config, api_version=1):
344 self._require_min_api_version(api_version) 345 resp = self._get_resource_root().put(self._path() + '/' + rel_path, 346 data=config_to_json(config)) 347 return json_to_config(resp, False)
348
349 - def _delete(self, rel_path, ret_type, ret_is_list=False, params=None, 350 api_version=1):
351 return self._call('delete', rel_path, ret_type, ret_is_list, None, params, 352 api_version)
353
354 - def _get(self, rel_path, ret_type, ret_is_list=False, params=None, 355 api_version=1):
356 return self._call('get', rel_path, ret_type, ret_is_list, None, params, 357 api_version)
358
359 - def _post(self, rel_path, ret_type, ret_is_list=False, data=None, params=None, 360 api_version=1):
361 return self._call('post', rel_path, ret_type, ret_is_list, data, params, 362 api_version)
363
364 - def _put(self, rel_path, ret_type, ret_is_list=False, data=None, params=None, 365 api_version=1):
366 return self._call('put', rel_path, ret_type, ret_is_list, data, params, 367 api_version)
368
369 - def _call(self, method, rel_path, ret_type, ret_is_list=False, data=None, 370 params=None, api_version=1):
371 path = self._path() 372 if rel_path: 373 path += '/' + rel_path 374 return call(getattr(self._get_resource_root(), method), 375 path, 376 ret_type, 377 ret_is_list, 378 data, 379 params, 380 api_version)
381
382 -class ApiList(BaseApiObject):
383 """A list of some api object""" 384 LIST_KEY = "items" 385
386 - def __init__(self, objects, resource_root=None, **attrs):
387 BaseApiObject.__init__(self, resource_root, **attrs) 388 # Bypass checks in BaseApiObject.__setattr__ 389 object.__setattr__(self, 'objects', objects)
390
391 - def __str__(self):
392 return "<ApiList>(%d): [%s]" % ( 393 len(self.objects), 394 ", ".join([str(item) for item in self.objects]))
395
396 - def to_json_dict(self, preserve_ro=False):
397 ret = BaseApiObject.to_json_dict(self, preserve_ro) 398 attr = Attr() 399 ret[ApiList.LIST_KEY] = [ attr.to_json(x, preserve_ro) for x in self.objects ] 400 return ret
401
402 - def __len__(self):
403 return self.objects.__len__()
404
405 - def __iter__(self):
406 return self.objects.__iter__()
407
408 - def __getitem__(self, i):
409 return self.objects.__getitem__(i)
410
411 - def __getslice(self, i, j):
412 return self.objects.__getslice__(i, j)
413 414 @classmethod
415 - def from_json_dict(cls, dic, resource_root, member_cls=None):
416 if not member_cls: 417 member_cls = cls._MEMBER_CLASS 418 attr = Attr(atype=member_cls) 419 items = [] 420 if ApiList.LIST_KEY in dic: 421 items = [ attr.from_json(resource_root, x) for x in dic[ApiList.LIST_KEY] ] 422 ret = cls(items) 423 # If the class declares custom attributes, populate them based on the input 424 # dict. The check avoids extra overhead for the common case, where we just 425 # have a plain list. _set_attrs() also does not understand the "items" 426 # attribute, so it can't be in the input data. 427 if cls._ATTRIBUTES: 428 if ApiList.LIST_KEY in dic: 429 dic = copy.copy(dic) 430 del dic[ApiList.LIST_KEY] 431 ret._set_attrs(dic, allow_ro=True) 432 return ret
433
434 -class ApiHostRef(BaseApiObject):
435 _ATTRIBUTES = { 436 'hostId' : None, 437 } 438
439 - def __init__(self, resource_root, hostId=None):
440 BaseApiObject.init(self, resource_root, locals())
441
442 - def __str__(self):
443 return "<ApiHostRef>: %s" % (self.hostId)
444
445 -class ApiServiceRef(BaseApiObject):
446 _ATTRIBUTES = { 447 'clusterName' : None, 448 'serviceName' : None, 449 'peerName' : None, 450 } 451
452 - def __init__(self, resource_root, serviceName=None, clusterName=None, 453 peerName=None):
454 BaseApiObject.init(self, resource_root, locals())
455
456 -class ApiClusterRef(BaseApiObject):
457 _ATTRIBUTES = { 458 'clusterName' : None, 459 } 460
461 - def __init__(self, resource_root, clusterName = None):
462 BaseApiObject.init(self, resource_root, locals())
463
464 -class ApiRoleRef(BaseApiObject):
465 _ATTRIBUTES = { 466 'clusterName' : None, 467 'serviceName' : None, 468 'roleName' : None, 469 } 470
471 - def __init__(self, resource_root, serviceName=None, roleName=None, 472 clusterName=None):
473 BaseApiObject.init(self, resource_root, locals())
474
475 -class ApiRoleConfigGroupRef(BaseApiObject):
476 _ATTRIBUTES = { 477 'roleConfigGroupName' : None, 478 } 479
480 - def __init__(self, resource_root, roleConfigGroupName=None):
481 BaseApiObject.init(self, resource_root, locals())
482
483 -class ApiCommand(BaseApiObject):
484 SYNCHRONOUS_COMMAND_ID = -1 485 486 @classmethod
487 - def _get_attributes(cls):
488 if not cls.__dict__.has_key('_ATTRIBUTES'): 489 cls._ATTRIBUTES = { 490 'id' : ROAttr(), 491 'name' : ROAttr(), 492 'startTime' : ROAttr(datetime.datetime), 493 'endTime' : ROAttr(datetime.datetime), 494 'active' : ROAttr(), 495 'success' : ROAttr(), 496 'resultMessage' : ROAttr(), 497 'clusterRef' : ROAttr(ApiClusterRef), 498 'serviceRef' : ROAttr(ApiServiceRef), 499 'roleRef' : ROAttr(ApiRoleRef), 500 'hostRef' : ROAttr(ApiHostRef), 501 'children' : ROAttr(ApiCommand, is_api_list=True), 502 'parent' : ROAttr(ApiCommand), 503 'resultDataUrl' : ROAttr(), 504 'canRetry' : ROAttr(), 505 } 506 return cls._ATTRIBUTES
507
508 - def __str__(self):
509 return "<ApiCommand>: '%s' (id: %s; active: %s; success: %s)" % ( 510 self.name, self.id, self.active, self.success)
511
512 - def _path(self):
513 return '/commands/%d' % self.id
514
515 - def fetch(self):
516 """ 517 Retrieve updated data about the command from the server. 518 519 @return: A new ApiCommand object. 520 """ 521 if self.id == ApiCommand.SYNCHRONOUS_COMMAND_ID: 522 return self 523 524 resp = self._get_resource_root().get(self._path()) 525 return ApiCommand.from_json_dict(resp, self._get_resource_root())
526
527 - def wait(self, timeout=None):
528 """ 529 Wait for command to finish. 530 531 @param timeout: (Optional) Max amount of time (in seconds) to wait. Wait 532 forever by default. 533 @return: The final ApiCommand object, containing the last known state. 534 The command may still be running in case of timeout. 535 """ 536 if self.id == ApiCommand.SYNCHRONOUS_COMMAND_ID: 537 return self 538 539 SLEEP_SEC = 5 540 541 if timeout is None: 542 deadline = None 543 else: 544 deadline = time.time() + timeout 545 546 while True: 547 cmd = self.fetch() 548 if not cmd.active: 549 return cmd 550 551 if deadline is not None: 552 now = time.time() 553 if deadline < now: 554 return cmd 555 else: 556 time.sleep(min(SLEEP_SEC, deadline - now)) 557 else: 558 time.sleep(SLEEP_SEC)
559 560
561 - def abort(self):
562 """ 563 Abort a running command. 564 565 @return: A new ApiCommand object with the updated information. 566 """ 567 if self.id == ApiCommand.SYNCHRONOUS_COMMAND_ID: 568 return self 569 570 path = self._path() + '/abort' 571 resp = self._get_resource_root().post(path) 572 return ApiCommand.from_json_dict(resp, self._get_resource_root())
573
574 - def retry(self):
575 """ 576 Retry a failed or aborted command. 577 578 @return: A new ApiCommand object with the updated information. 579 """ 580 path = self._path() + '/retry' 581 resp = self._get_resource_root().post(path) 582 return ApiCommand.from_json_dict(resp, self._get_resource_root())
583
584 -class ApiBulkCommandList(ApiList):
585 _ATTRIBUTES = { 586 'errors' : ROAttr(), 587 } 588 _MEMBER_CLASS = ApiCommand
589
590 -class ApiCommandMetadata(BaseApiObject):
591 _ATTRIBUTES = { 592 'name' : ROAttr(), 593 'argSchema' : ROAttr(), 594 } 595
596 - def __init__(self, resource_root):
597 BaseApiObject.init(self, resource_root)
598
599 - def __str__(self):
600 return "<ApiCommandMetadata>: %s (%s)" % (self.name, self.argSchema)
601
602 # 603 # Metrics. 604 # 605 606 -class ApiMetricData(BaseApiObject):
607 """Metric reading data.""" 608 609 _ATTRIBUTES = { 610 'timestamp' : ROAttr(datetime.datetime), 611 'value' : ROAttr(), 612 } 613
614 - def __init__(self, resource_root):
615 BaseApiObject.init(self, resource_root)
616
617 618 -class ApiMetric(BaseApiObject):
619 """Metric information.""" 620 621 _ATTRIBUTES = { 622 'name' : ROAttr(), 623 'context' : ROAttr(), 624 'unit' : ROAttr(), 625 'data' : ROAttr(ApiMetricData), 626 'displayName' : ROAttr(), 627 'description' : ROAttr(), 628 } 629
630 - def __init__(self, resource_root):
631 BaseApiObject.init(self, resource_root)
632
633 # 634 # Activities. 635 # 636 637 -class ApiActivity(BaseApiObject):
638 _ATTRIBUTES = { 639 'name' : ROAttr(), 640 'type' : ROAttr(), 641 'parent' : ROAttr(), 642 'startTime' : ROAttr(), 643 'finishTime' : ROAttr(), 644 'id' : ROAttr(), 645 'status' : ROAttr(), 646 'user' : ROAttr(), 647 'group' : ROAttr(), 648 'inputDir' : ROAttr(), 649 'outputDir' : ROAttr(), 650 'mapper' : ROAttr(), 651 'combiner' : ROAttr(), 652 'reducer' : ROAttr(), 653 'queueName' : ROAttr(), 654 'schedulerPriority' : ROAttr(), 655 } 656
657 - def __init__(self, resource_root):
658 BaseApiObject.init(self, resource_root)
659
660 - def __str__(self):
661 return "<ApiActivity>: %s (%s)" % (self.name, self.status)
662
663 # 664 # Replication 665 # 666 667 -class ApiCmPeer(BaseApiObject):
668 _ATTRIBUTES = { 669 'name' : None, 670 'url' : None, 671 'username' : None, 672 'password' : None, 673 'type' : None, 674 'clouderaManagerCreatedUser' : None, 675 } 676
677 - def __str__(self):
678 return "<ApiPeer>: %s (%s)" % (self.name, self.url)
679
680 -class ApiLicensedFeatureUsage(BaseApiObject):
681 _ATTRIBUTES = { 682 'totals' : ROAttr(), 683 'clusters' : ROAttr(), 684 }
685
686 -class ApiReplicationDiagnosticsCollectionArgs(BaseApiObject):
687 _ATTRIBUTES = { 688 'commands' : ROAttr(), 689 'ticketNumber' : ROAttr(), 690 'comments' : ROAttr(), 691 'phoneHome' : ROAttr(), 692 }
693
694 -class ApiHdfsReplicationArguments(BaseApiObject):
695 _ATTRIBUTES = { 696 'sourceService' : Attr(ApiServiceRef), 697 'sourcePath' : None, 698 'destinationPath' : None, 699 'mapreduceServiceName' : None, 700 'userName' : None, 701 'sourceUser' : None, 702 'numMaps' : None, 703 'dryRun' : None, 704 'bandwidthPerMap' : None, 705 'logPath' : None, 706 'schedulerPoolName' : None, 707 'abortOnError' : None, 708 'preservePermissions' : None, 709 'preserveBlockSize' : None, 710 'preserveReplicationCount' : None, 711 'removeMissingFiles' : None, 712 'skipChecksumChecks' : None, 713 'skipListingChecksumChecks' : None, 714 'skipTrash' : None, 715 'replicationStrategy' : None, 716 'preserveXAttrs' : None, 717 'exclusionFilters' : None, 718 'raiseSnapshotDiffFailures' : None, 719 }
720
721 -class ApiHdfsCloudReplicationArguments(ApiHdfsReplicationArguments):
722 @classmethod
723 - def _get_attributes(cls):
724 if not cls.__dict__.has_key('_ATTRIBUTES'): 725 attrs = { 726 'sourceAccount' : None, 727 'destinationAccount' : None, 728 } 729 attrs.update(ApiHdfsReplicationArguments._get_attributes()) 730 cls._ATTRIBUTES = attrs 731 return cls._ATTRIBUTES
732
733 -class ApiHdfsReplicationResult(BaseApiObject):
734 _ATTRIBUTES = { 735 'progress' : ROAttr(), 736 'counters' : ROAttr(), 737 'numBytesDryRun' : ROAttr(), 738 'numFilesDryRun' : ROAttr(), 739 'numFilesExpected' : ROAttr(), 740 'numBytesExpected' : ROAttr(), 741 'numFilesCopied' : ROAttr(), 742 'numBytesCopied' : ROAttr(), 743 'numFilesSkipped' : ROAttr(), 744 'numBytesSkipped' : ROAttr(), 745 'numFilesDeleted' : ROAttr(), 746 'numFilesCopyFailed' : ROAttr(), 747 'numBytesCopyFailed' : ROAttr(), 748 'setupError' : ROAttr(), 749 'jobId' : ROAttr(), 750 'jobDetailsUri' : ROAttr(), 751 'dryRun' : ROAttr(), 752 'snapshottedDirs' : ROAttr(), 753 'failedFiles' : ROAttr(), 754 'runAsUser' : ROAttr(), 755 'runOnSourceAsUser' : ROAttr(), 756 'remainingTime' : ROAttr(), 757 'throughput' : ROAttr(), 758 'estimatedCompletionTime' : ROAttr(), 759 }
760
761 -class ApiHiveTable(BaseApiObject):
762 _ATTRIBUTES = { 763 'database' : None, 764 'tableName' : None, 765 } 766
767 - def __str__(self):
768 return "<ApiHiveTable>: %s, %s" % (self.database, self.tableName)
769
770 -class ApiImpalaUDF(BaseApiObject):
771 _ATTRIBUTES = { 772 'database' : ROAttr(), 773 'signature' : ROAttr(), 774 } 775
776 - def __str__(self):
777 return "<ApiImpalaUDF>: %s, %s" % (self.database, self.signature)
778
779 -class ApiHiveUDF(BaseApiObject):
780 _ATTRIBUTES = { 781 'database' : ROAttr(), 782 'signature' : ROAttr(), 783 } 784
785 - def __str__(self):
786 return "<ApiHiveUDF>: %s, %s" % (self.database, self.signature)
787
788 -class ApiHiveReplicationArguments(BaseApiObject):
789 _ATTRIBUTES = { 790 'sourceService' : Attr(ApiServiceRef), 791 'tableFilters' : Attr(ApiHiveTable), 792 'exportDir' : None, 793 'force' : None, 794 'replicateData' : None, 795 'hdfsArguments' : Attr(ApiHdfsReplicationArguments), 796 'dryRun' : None, 797 'replicateImpalaMetadata' : None, 798 'runInvalidateMetadata' : None, 799 'numThreads' : None, 800 }
801
802 -class ApiHiveReplicationResult(BaseApiObject):
803 _ATTRIBUTES = { 804 'tableCount' : ROAttr(), 805 'tables' : ROAttr(ApiHiveTable), 806 'impalaUDFCount' : ROAttr(), 807 'impalaUDFs' : ROAttr(ApiImpalaUDF), 808 'hiveUDFCount' : ROAttr(), 809 'hiveUDFs' : ROAttr(ApiHiveUDF), 810 'errorCount' : ROAttr(), 811 'errors' : ROAttr(), 812 'dataReplicationResult' : ROAttr(ApiHdfsReplicationResult), 813 'dryRun' : ROAttr(), 814 'runAsUser' : ROAttr(), 815 'runOnSourceAsUser' : ROAttr(), 816 'phase' : ROAttr(), 817 'statsAvailable' : ROAttr(), 818 'dbProcessed' : ROAttr(), 819 'tableProcessed' : ROAttr(), 820 'partitionProcessed' : ROAttr(), 821 'functionProcessed' : ROAttr(), 822 'indexProcessed' : ROAttr(), 823 'statsProcessed' : ROAttr(), 824 'dbExpected' : ROAttr(), 825 'tableExpected' : ROAttr(), 826 'partitionExpected' : ROAttr(), 827 'functionExpected' : ROAttr(), 828 'indexExpected' : ROAttr(), 829 'statsExpected' : ROAttr(), 830 }
831
832 -class ApiReplicationCommand(ApiCommand):
833 @classmethod
834 - def _get_attributes(cls):
835 if not cls.__dict__.has_key('_ATTRIBUTES'): 836 attrs = { 837 'hdfsResult' : ROAttr(ApiHdfsReplicationResult), 838 'hiveResult' : ROAttr(ApiHiveReplicationResult), 839 } 840 attrs.update(ApiCommand._get_attributes()) 841 cls._ATTRIBUTES = attrs 842 return cls._ATTRIBUTES
843
844 -class ApiReplicationSchedule(BaseApiObject):
845 _ATTRIBUTES = { 846 'startTime' : Attr(datetime.datetime), 847 'endTime' : Attr(datetime.datetime), 848 'interval' : None, 849 'intervalUnit' : None, 850 'paused' : None, 851 'hdfsArguments' : Attr(ApiHdfsReplicationArguments), 852 'hiveArguments' : Attr(ApiHiveReplicationArguments), 853 'hdfsCloudArguments' : Attr(ApiHdfsCloudReplicationArguments), 854 'alertOnStart' : None, 855 'alertOnSuccess' : None, 856 'alertOnFail' : None, 857 'alertOnAbort' : None, 858 'id' : ROAttr(), 859 'displayName' : ROAttr(), 860 'description' : ROAttr(), 861 'nextRun' : ROAttr(datetime.datetime), 862 'history' : ROAttr(ApiReplicationCommand), 863 'active' : None, 864 'displayName' : None, 865 'description' : None 866 }
867
868 -class ApiHBaseSnapshotPolicyArguments(BaseApiObject):
869 _ATTRIBUTES = { 870 'tableRegExps' : None, 871 'storage' : None, 872 }
873
874 -class ApiHdfsSnapshotPolicyArguments(BaseApiObject):
875 _ATTRIBUTES = { 876 'pathPatterns' : None, 877 }
878
879 -class ApiHBaseSnapshot(BaseApiObject):
880 _ATTRIBUTES = { 881 'snapshotName' : None, 882 'tableName' : None, 883 'creationTime' : ROAttr(datetime.datetime), 884 'storage' : None, 885 }
886
887 -class ApiHBaseSnapshotError(BaseApiObject):
888 _ATTRIBUTES = { 889 'tableName' : ROAttr(), 890 'snapshotName' : ROAttr(), 891 'error' : ROAttr(), 892 'storage' : ROAttr(), 893 }
894
895 -class ApiHdfsSnapshot(BaseApiObject):
896 _ATTRIBUTES = { 897 'path' : None, 898 'snapshotName' : None, 899 'snapshotPath' : None, 900 'creationTime' : ROAttr(datetime.datetime), 901 }
902
903 -class ApiHdfsSnapshotError(BaseApiObject):
904 _ATTRIBUTES = { 905 'path' : ROAttr(), 906 'snapshotName' : ROAttr(), 907 'snapshotPath' : ROAttr(), 908 'error' : ROAttr(), 909 }
910
911 -class ApiHBaseSnapshotResult(BaseApiObject):
912 _ATTRIBUTES = { 913 'processedTableCount' : ROAttr(), 914 'processedTables' : ROAttr(), 915 'unprocessedTableCount' : ROAttr(), 916 'unprocessedTables' : ROAttr(), 917 'createdSnapshotCount' : ROAttr(), 918 'createdSnapshots' : ROAttr(ApiHBaseSnapshot), 919 'deletedSnapshotCount' : ROAttr(), 920 'deletedSnapshots' : ROAttr(ApiHBaseSnapshot), 921 'creationErrorCount' : ROAttr(), 922 'creationErrors' : ROAttr(ApiHBaseSnapshotError), 923 'deletionErrorCount' : ROAttr(), 924 'deletionErrors' : ROAttr(ApiHBaseSnapshotError), 925 }
926
927 -class ApiHdfsSnapshotResult(BaseApiObject):
928 _ATTRIBUTES = { 929 'processedPathCount' : ROAttr(), 930 'processedPaths' : ROAttr(), 931 'unprocessedPathCount' : ROAttr(), 932 'unprocessedPaths' : ROAttr(), 933 'createdSnapshotCount' : ROAttr(), 934 'createdSnapshots' : ROAttr(ApiHdfsSnapshot), 935 'deletedSnapshotCount' : ROAttr(), 936 'deletedSnapshots' : ROAttr(ApiHdfsSnapshot), 937 'creationErrorCount' : ROAttr(), 938 'creationErrors' : ROAttr(ApiHdfsSnapshotError), 939 'deletionErrorCount' : ROAttr(), 940 'deletionErrors' : ROAttr(ApiHdfsSnapshotError), 941 }
942
943 -class ApiSnapshotCommand(BaseApiObject):
944 @classmethod
945 - def _get_attributes(cls):
946 if not cls.__dict__.has_key('_ATTRIBUTES'): 947 attrs = { 948 'hdfsResult' : ROAttr(ApiHdfsSnapshotResult), 949 'hbaseResult' : ROAttr(ApiHBaseSnapshotResult), 950 } 951 attrs.update(ApiCommand._get_attributes()) 952 cls._ATTRIBUTES = attrs 953 return cls._ATTRIBUTES
954
955 -class ApiSnapshotPolicy(BaseApiObject):
956 """ 957 @type name: str 958 @ivar name: Name of the snapshot policy. 959 @type description: str 960 @ivar description: Description of the snapshot policy. 961 @type hourly_snapshots: int 962 @ivar hourly_snapshots: Number of hourly snapshots to be retained (default: 0). 963 @type daily_snapshots: int 964 @ivar daily_snapshots: Number of daily snapshots to be retained (default: 0). 965 @type weekly_snapshots: int 966 @ivar weekly_snapshots: Number of weekly snapshots to be retained (default: 0). 967 @type monthly_snapshots: int 968 @ivar monthly_snapshots: Number of monthly snapshots to be retained (default: 0). 969 @type yearly_snapshots: int 970 @ivar yearly_snapshots: Number of yearly snapshots to be retained (default: 0). 971 @type hours_for_hourly_snapshots: list of int 972 @ivar hours_for_hourly_snapshots: Hours of the day that hourly snapshots should be created. 973 Valid values are 0 to 23. If this list is empty, then hourly snapshots are 974 created for every hour. 975 @type minute_of_hour: int 976 @ivar minute_of_hour: Minute in the hour that hourly, daily, weekly, monthly and yearly 977 snapshots should be created. Valid values are 0 to 59 (default: 0). 978 @type hour_of_day: int 979 @ivar hour_of_day: Hour in the day that daily, weekly, monthly and yearly snapshots should be created. 980 Valid values are 0 to 23 (default: 0). 981 @type day_of_week: int 982 @ivar day_of_week: Day of the week that weekly snapshots should be created. 983 Valid values are 1 to 7, 1 representing Sunday (default: 1). 984 @type day_of_month: int 985 @ivar day_of_month: Day of the month that monthly and yearly snapshots should be created. 986 Values from 1 to 31 are allowed. Additionally 0 to -30 can be used to 987 specify offsets from the last day of the month (default: 1). 988 @type month_of_year: int 989 @ivar month_of_year: Month of the year that yearly snapshots should be created. 990 Valid values are 1 to 12, 1 representing January (default: 1). 991 @ivar alert_on_start: whether to generate alerts on start of snapshot creation/deletion activity. 992 @ivar alert_on_success: whether to generate alerts on successful completion of snapshot creation/deletion activity. 993 @ivar alert_on_fail: whether to generate alerts on failure of snapshot creation/deletion activity. 994 @ivar alert_on_abort: whether to generate alerts on abort of snapshot creation/deletion activity. 995 @ivar paused: whether to run the policy on schedule 996 @type hbaseArguments: ApiHBaseSnapshotPolicyArguments 997 @ivar hbaseArguments: HBase specific arguments for the replication job. 998 @type hdfsArguments: ApiHdfsSnapshotPolicyArguments 999 @ivar hdfsArguments: HDFS specific arguments for the replication job. 1000 """ 1001 _ATTRIBUTES = { 1002 'name' : None, 1003 'description' : None, 1004 'hourlySnapshots' : None, 1005 'dailySnapshots' : None, 1006 'weeklySnapshots' : None, 1007 'monthlySnapshots' : None, 1008 'yearlySnapshots' : None, 1009 'minuteOfHour' : None, 1010 'hourOfDay' : None, 1011 'dayOfWeek' : None, 1012 'dayOfMonth' : None, 1013 'monthOfYear' : None, 1014 'hoursForHourlySnapshots' : None, 1015 'alertOnStart' : None, 1016 'alertOnSuccess' : None, 1017 'alertOnFail' : None, 1018 'alertOnAbort' : None, 1019 'paused' : None, 1020 'hbaseArguments' : Attr(ApiHBaseSnapshotPolicyArguments), 1021 'hdfsArguments' : Attr(ApiHdfsSnapshotPolicyArguments), 1022 'lastCommand' : ROAttr(ApiSnapshotCommand), 1023 'lastSuccessfulCommand' : ROAttr(ApiSnapshotCommand), 1024 }
1025
1026 # 1027 # Batch. 1028 # 1029 1030 -class ApiBatchRequestElement(BaseApiObject):
1031 """One element in a batch request.""" 1032 _ATTRIBUTES = { 1033 'method' : None, 1034 'url' : None, 1035 'body' : None, 1036 'contentType' : None, 1037 'acceptType' : None, 1038 }
1039
1040 -class ApiBatchResponseElement(BaseApiObject):
1041 """One element in a batch response.""" 1042 _ATTRIBUTES = { 1043 'statusCode' : ROAttr(), 1044 'response' : ROAttr(), 1045 }
1046
1047 -class ApiBatchResponseList(ApiList):
1048 """A list of batch response objects.""" 1049 _ATTRIBUTES = { 1050 'success' : ROAttr(), 1051 } 1052 _MEMBER_CLASS = ApiBatchResponseElement
1053
1054 # 1055 # Configuration helpers. 1056 # 1057 1058 -class ApiConfig(BaseApiObject):
1059 _ATTRIBUTES = { 1060 'name' : None, 1061 'value' : None, 1062 'required' : ROAttr(), 1063 'default' : ROAttr(), 1064 'displayName' : ROAttr(), 1065 'description' : ROAttr(), 1066 'relatedName' : ROAttr(), 1067 'sensitive' : ROAttr(), 1068 'validationState' : ROAttr(), 1069 'validationMessage' : ROAttr(), 1070 'validationWarningsSuppressed' : ROAttr() 1071 } 1072
1073 - def __init__(self, resource_root, name=None, value=None):
1074 BaseApiObject.init(self, resource_root, locals())
1075
1076 - def __str__(self):
1077 return "<ApiConfig>: %s = %s" % (self.name, self.value)
1078
1079 -class ApiImpalaQuery(BaseApiObject):
1080 _ATTRIBUTES = { 1081 'queryId' : ROAttr(), 1082 'queryState' : ROAttr(), 1083 'queryType' : ROAttr(), 1084 'statement' : ROAttr(), 1085 'database' : ROAttr(), 1086 'rowsProduced' : ROAttr(), 1087 'coordinator' : ROAttr(ApiHostRef), 1088 'user' : ROAttr(), 1089 'startTime' : ROAttr(datetime.datetime), 1090 'endTime' : ROAttr(datetime.datetime), 1091 'detailsAvailable' : ROAttr(), 1092 'attributes' : ROAttr(), 1093 'durationMillis' : ROAttr() 1094 } 1095
1096 - def __str__(self):
1097 return "<ApiImpalaQuery>: %s" % (self.queryId)
1098
1099 # 1100 # WatchedDirectories data types 1101 # 1102 1103 -class ApiWatchedDir(BaseApiObject):
1104 1105 _ATTRIBUTES = { 1106 'path' : None 1107 } 1108
1109 - def __str__(self):
1110 return "<ApiWatchedDir>: %s" % (self.path)
1111
1112 -class ApiWatchedDirList(ApiList):
1113 1114 _ATTRIBUTES = { 1115 'watchedDirs' : ROAttr(ApiWatchedDir) 1116 } 1117 _MEMBER_CLASS = ApiWatchedDir
1118
1119 -class ApiImpalaQueryResponse(BaseApiObject):
1120 1121 _ATTRIBUTES = { 1122 'queries' : ROAttr(ApiImpalaQuery), 1123 'warnings' : ROAttr() 1124 }
1125
1126 -class ApiImpalaQueryDetailsResponse(BaseApiObject):
1127 _ATTRIBUTES = { 1128 'details' : ROAttr() 1129 } 1130
1131 - def __str__(self):
1132 return "<AipImpalaQueryDetailsResponse> %s" % self.details
1133
1134 -class ApiImpalaCancelResponse(BaseApiObject):
1135 _ATTRIBUTES = { 1136 'warning' : ROAttr() 1137 } 1138
1139 - def __str__(self):
1140 return "<ApiImpalaCancelResponse> %s" % self.warning
1141
1142 -class ApiImpalaQueryAttribute(BaseApiObject):
1143 1144 _ATTRIBUTES = { 1145 'name' : ROAttr(), 1146 'type' : ROAttr(), 1147 'displayName' : ROAttr(), 1148 'supportsHistograms' : ROAttr(), 1149 'description' : ROAttr() 1150 } 1151
1152 - def __str__(self):
1153 return "<ApiImpalaQueryAttribute> %s" % name
1154
1155 -class ApiMr2AppInformation(BaseApiObject):
1156 _ATTRIBUTES = { 1157 'jobState' : ROAttr() 1158 } 1159
1160 - def __str__(self):
1161 return "<ApiMr2AppInformation>: %s" % (self.jobState)
1162
1163 -class ApiYarnApplication(BaseApiObject):
1164 _ATTRIBUTES = { 1165 'applicationId' : ROAttr(), 1166 'name' : ROAttr(), 1167 'user' : ROAttr(), 1168 'startTime' : ROAttr(datetime.datetime), 1169 'endTime' : ROAttr(datetime.datetime), 1170 'pool' : ROAttr(), 1171 'state' : ROAttr(), 1172 'progress' : ROAttr(), 1173 'mr2AppInformation' : ROAttr(ApiMr2AppInformation), 1174 'attributes' : ROAttr(), 1175 'allocatedMB' : ROAttr(), 1176 'allocatedVCores' : ROAttr(), 1177 'runningContainers' : ROAttr(), 1178 'applicationTags' : ROAttr(), 1179 'allocatedMemorySeconds' : ROAttr(), 1180 'allocatedVcoreSeconds' : ROAttr(), 1181 'containerUsedMemorySeconds' : ROAttr(), 1182 'containerUsedCpuSeconds' : ROAttr(), 1183 'containerUsedVcoreSeconds' : ROAttr(), 1184 'containerAllocatedMemorySeconds' : ROAttr(), 1185 'containerAllocatedVcoreSeconds' : ROAttr(), 1186 'containerUsedMemoryMax' : ROAttr(), 1187 } 1188
1189 - def __str__(self):
1190 return "<ApiYarnApplication>: %s" % (self.applicationId)
1191
1192 -class ApiYarnApplicationResponse(BaseApiObject):
1193 1194 _ATTRIBUTES = { 1195 'applications' : ROAttr(ApiYarnApplication), 1196 'warnings' : ROAttr() 1197 }
1198
1199 -class ApiYarnKillResponse(BaseApiObject):
1200 _ATTRIBUTES = { 1201 'warning' : ROAttr() 1202 } 1203
1204 - def __str__(self):
1205 return "<ApiYarnKillResponse> %s" % self.warning
1206
1207 -class ApiYarnApplicationAttribute(BaseApiObject):
1208 1209 _ATTRIBUTES = { 1210 'name' : ROAttr(), 1211 'type' : ROAttr(), 1212 'displayName' : ROAttr(), 1213 'supportsHistograms' : ROAttr(), 1214 'description' : ROAttr() 1215 } 1216
1217 - def __str__(self):
1218 return "<ApiYarnApplicationAttribute> %s" % name
1219
1220 -class ApiTimeSeriesRequest(BaseApiObject):
1221 _ATTRIBUTES = { 1222 'query' : None, 1223 'from' : None, 1224 'to' : None, 1225 'contentType' : None, 1226 'desiredRollup' : None, 1227 'mustUseDesiredRollup' : None 1228 } 1229
1230 - def __str__(self):
1231 return "<ApiTimeSeriesRequest>: %s" % (self.query)
1232
1233 -class ApiProductVersion(BaseApiObject):
1234 _ATTRIBUTES = { 1235 'version' : None, 1236 'product' : None, 1237 }
1238
1239 -class ApiClusterTemplateConfig(BaseApiObject):
1240 _ATTRIBUTES = { 1241 'name' : None, 1242 'value' : None, 1243 'ref' : None, 1244 'variable' : None, 1245 'autoConfig' : None, 1246 }
1247
1248 -class ApiClusterTemplateRoleConfigGroup(BaseApiObject):
1249 _ATTRIBUTES = { 1250 'refName' : None, 1251 'roleType' : None, 1252 'base' : None, 1253 'displayName' : None, 1254 'configs' : Attr(ApiClusterTemplateConfig), 1255 }
1256
1257 -class ApiClusterTemplateRole(BaseApiObject):
1258 _ATTRIBUTES = { 1259 'refName' : None, 1260 'roleType' : None, 1261 }
1262
1263 -class ApiClusterTemplateHostTemplate(BaseApiObject):
1264 _ATTRIBUTES = { 1265 'refName' : None, 1266 'cardinality' : None, 1267 'roleConfigGroupsRefNames' : None, 1268 }
1269
1270 -class ApiClusterTemplateHostInfo(BaseApiObject):
1271 _ATTRIBUTES = { 1272 'hostName' : None, 1273 'hostNameRange' : None, 1274 'rackId' : None, 1275 'hostTemplateRefName' : None, 1276 'roleRefNames' : None, 1277 }
1278
1279 -class ApiClusterTemplateVariable(BaseApiObject):
1280 _ATTRIBUTES = { 1281 'name' : None, 1282 'value' : None, 1283 }
1284
1285 -class ApiClusterTemplateRoleConfigGroupInfo(BaseApiObject):
1286 _ATTRIBUTES = { 1287 'rcgRefName' : None, 1288 'name' : None, 1289 }
1290
1291 -class ApiClusterTemplateInstantiator(BaseApiObject):
1292 _ATTRIBUTES = { 1293 'clusterName' : None, 1294 'hosts' : Attr(ApiClusterTemplateHostInfo), 1295 'variables' : Attr(ApiClusterTemplateVariable), 1296 'roleConfigGroups' : Attr(ApiClusterTemplateRoleConfigGroupInfo), 1297 }
1298
1299 -class ApiClusterTemplateService(BaseApiObject):
1300 _ATTRIBUTES = { 1301 'refName' : None, 1302 'serviceType' : None, 1303 'serviceConfigs' : Attr(ApiClusterTemplateConfig), 1304 'roleConfigGroups' : Attr(ApiClusterTemplateRoleConfigGroup), 1305 'displayName' : None, 1306 'roles' : Attr(ApiClusterTemplateRole), 1307 }
1308
1309 -class ApiClusterTemplate(BaseApiObject):
1310 _ATTRIBUTES = { 1311 'cdhVersion' : None, 1312 'displayName' : None, 1313 'cmVersion' : None, 1314 "repositories" : None, 1315 'products' : Attr(ApiProductVersion), 1316 'services' : Attr(ApiClusterTemplateService), 1317 'hostTemplates' : Attr(ApiClusterTemplateHostTemplate), 1318 'instantiator' : Attr(ApiClusterTemplateInstantiator), 1319 }
1320
1321 -def config_to_api_list(dic):
1322 """ 1323 Converts a python dictionary into a list containing the proper 1324 ApiConfig encoding for configuration data. 1325 1326 @param dic: Key-value pairs to convert. 1327 @return: JSON dictionary of an ApiConfig list (*not* an ApiList). 1328 """ 1329 config = [ ] 1330 for k, v in dic.iteritems(): 1331 config.append({ 'name' : k, 'value': v }) 1332 return { ApiList.LIST_KEY : config }
1333
1334 -def config_to_json(dic):
1335 """ 1336 Converts a python dictionary into a JSON payload. 1337 1338 The payload matches the expected "apiConfig list" type used to update 1339 configuration parameters using the API. 1340 1341 @param dic: Key-value pairs to convert. 1342 @return: String with the JSON-encoded data. 1343 """ 1344 return json.dumps(config_to_api_list(dic))
1345
1346 -def json_to_config(dic, full = False):
1347 """ 1348 Converts a JSON-decoded config dictionary to a python dictionary. 1349 1350 When materializing the full view, the values in the dictionary will be 1351 instances of ApiConfig, instead of strings. 1352 1353 @param dic: JSON-decoded config dictionary. 1354 @param full: Whether to materialize the full view of the config data. 1355 @return: Python dictionary with config data. 1356 """ 1357 config = { } 1358 for entry in dic['items']: 1359 k = entry['name'] 1360 if full: 1361 config[k] = ApiConfig.from_json_dict(entry, None) 1362 else: 1363 config[k] = entry.get('value') 1364 return config
1365