Revision ff9c047c lib/objects.py
b/lib/objects.py | ||
---|---|---|
147 | 147 |
"""Load data from a string.""" |
148 | 148 |
return ConfigObject.Load(StringIO(data)) |
149 | 149 |
|
150 |
def ToDict(self): |
|
151 |
"""Convert to a dict holding only standard python types. |
|
152 |
|
|
153 |
The generic routine just dumps all of this object's attributes in |
|
154 |
a dict. It does not work if the class has children who are |
|
155 |
ConfigObjects themselves (e.g. the nics list in an Instance), in |
|
156 |
which case the object should subclass the function in order to |
|
157 |
make sure all objects returned are only standard python types. |
|
158 |
|
|
159 |
""" |
|
160 |
return dict([(k, getattr(self, k, None)) for k in self.__slots__]) |
|
161 |
|
|
162 |
@classmethod |
|
163 |
def FromDict(cls, val): |
|
164 |
"""Create an object from a dictionary. |
|
165 |
|
|
166 |
This generic routine takes a dict, instantiates a new instance of |
|
167 |
the given class, and sets attributes based on the dict content. |
|
168 |
|
|
169 |
As for `ToDict`, this does not work if the class has children |
|
170 |
who are ConfigObjects themselves (e.g. the nics list in an |
|
171 |
Instance), in which case the object should subclass the function |
|
172 |
and alter the objects. |
|
173 |
|
|
174 |
""" |
|
175 |
if not isinstance(val, dict): |
|
176 |
raise errors.ConfigurationError("Invalid object passed to FromDict:" |
|
177 |
" expected dict, got %s" % type(val)) |
|
178 |
obj = cls(**val) |
|
179 |
return obj |
|
180 |
|
|
181 |
@staticmethod |
|
182 |
def _ContainerToDicts(container): |
|
183 |
"""Convert the elements of a container to standard python types. |
|
184 |
|
|
185 |
This method converts a container with elements derived from |
|
186 |
ConfigData to standard python types. If the container is a dict, |
|
187 |
we don't touch the keys, only the values. |
|
188 |
|
|
189 |
""" |
|
190 |
if isinstance(container, dict): |
|
191 |
ret = dict([(k, v.ToDict()) for k, v in container.iteritems()]) |
|
192 |
elif isinstance(container, (list, tuple, set, frozenset)): |
|
193 |
ret = [elem.ToDict() for elem in container] |
|
194 |
else: |
|
195 |
raise TypeError("Invalid type %s passed to _ContainerToDicts" % |
|
196 |
type(container)) |
|
197 |
return ret |
|
198 |
|
|
199 |
@staticmethod |
|
200 |
def _ContainerFromDicts(source, c_type, e_type): |
|
201 |
"""Convert a container from standard python types. |
|
202 |
|
|
203 |
This method converts a container with standard python types to |
|
204 |
ConfigData objects. If the container is a dict, we don't touch the |
|
205 |
keys, only the values. |
|
206 |
|
|
207 |
""" |
|
208 |
if not isinstance(c_type, type): |
|
209 |
raise TypeError("Container type %s passed to _ContainerFromDicts is" |
|
210 |
" not a type" % type(c_type)) |
|
211 |
if c_type is dict: |
|
212 |
ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()]) |
|
213 |
elif c_type in (list, tuple, set, frozenset): |
|
214 |
ret = c_type([e_type.FromDict(elem) for elem in source]) |
|
215 |
else: |
|
216 |
raise TypeError("Invalid container type %s passed to" |
|
217 |
" _ContainerFromDicts" % c_type) |
|
218 |
return ret |
|
219 |
|
|
220 |
def __repr__(self): |
|
221 |
"""Implement __repr__ for ConfigObjects.""" |
|
222 |
return repr(self.ToDict()) |
|
223 |
|
|
150 | 224 |
|
151 | 225 |
class TaggableObject(ConfigObject): |
152 | 226 |
"""An generic class supporting tags. |
... | ... | |
201 | 275 |
except KeyError: |
202 | 276 |
raise errors.TagError("Tag not found") |
203 | 277 |
|
278 |
def ToDict(self): |
|
279 |
"""Taggable-object-specific conversion to standard python types. |
|
280 |
|
|
281 |
This replaces the tags set with a list. |
|
282 |
|
|
283 |
""" |
|
284 |
bo = super(TaggableObject, self).ToDict() |
|
285 |
|
|
286 |
tags = bo.get("tags", None) |
|
287 |
if isinstance(tags, set): |
|
288 |
bo["tags"] = list(tags) |
|
289 |
return bo |
|
290 |
|
|
291 |
@classmethod |
|
292 |
def FromDict(cls, val): |
|
293 |
"""Custom function for instances. |
|
294 |
|
|
295 |
""" |
|
296 |
obj = super(TaggableObject, cls).FromDict(val) |
|
297 |
if hasattr(obj, "tags") and isinstance(obj.tags, list): |
|
298 |
obj.tags = set(obj.tags) |
|
299 |
return obj |
|
300 |
|
|
204 | 301 |
|
205 | 302 |
class ConfigData(ConfigObject): |
206 | 303 |
"""Top-level config object.""" |
207 | 304 |
__slots__ = ["cluster", "nodes", "instances"] |
208 | 305 |
|
306 |
def ToDict(self): |
|
307 |
"""Custom function for top-level config data. |
|
308 |
|
|
309 |
This just replaces the list of instances, nodes and the cluster |
|
310 |
with standard python types. |
|
311 |
|
|
312 |
""" |
|
313 |
mydict = super(ConfigData, self).ToDict() |
|
314 |
mydict["cluster"] = mydict["cluster"].ToDict() |
|
315 |
for key in "nodes", "instances": |
|
316 |
mydict[key] = self._ContainerToDicts(mydict[key]) |
|
317 |
|
|
318 |
return mydict |
|
319 |
|
|
320 |
@classmethod |
|
321 |
def FromDict(cls, val): |
|
322 |
"""Custom function for top-level config data |
|
323 |
|
|
324 |
""" |
|
325 |
obj = super(ConfigData, cls).FromDict(val) |
|
326 |
obj.cluster = Cluster.FromDict(obj.cluster) |
|
327 |
obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node) |
|
328 |
obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance) |
|
329 |
return obj |
|
330 |
|
|
209 | 331 |
|
210 | 332 |
class NIC(ConfigObject): |
211 | 333 |
"""Config object representing a network card.""" |
... | ... | |
286 | 408 |
# be different) |
287 | 409 |
return result |
288 | 410 |
|
411 |
def ToDict(self): |
|
412 |
"""Disk-specific conversion to standard python types. |
|
413 |
|
|
414 |
This replaces the children lists of objects with lists of |
|
415 |
standard python types. |
|
416 |
|
|
417 |
""" |
|
418 |
bo = super(Disk, self).ToDict() |
|
419 |
|
|
420 |
for attr in ("children",): |
|
421 |
alist = bo.get(attr, None) |
|
422 |
if alist: |
|
423 |
bo[attr] = self._ContainerToDicts(alist) |
|
424 |
return bo |
|
425 |
|
|
426 |
@classmethod |
|
427 |
def FromDict(cls, val): |
|
428 |
"""Custom function for Disks |
|
429 |
|
|
430 |
""" |
|
431 |
obj = super(Disk, cls).FromDict(val) |
|
432 |
if obj.children: |
|
433 |
obj.children = cls._ContainerFromDicts(obj.children, list, Disk) |
|
434 |
if obj.logical_id and isinstance(obj.logical_id, list): |
|
435 |
obj.logical_id = tuple(obj.logical_id) |
|
436 |
if obj.physical_id and isinstance(obj.physical_id, list): |
|
437 |
obj.physical_id = tuple(obj.physical_id) |
|
438 |
return obj |
|
439 |
|
|
289 | 440 |
|
290 | 441 |
class Instance(TaggableObject): |
291 | 442 |
"""Config object representing an instance.""" |
... | ... | |
392 | 543 |
|
393 | 544 |
return None |
394 | 545 |
|
546 |
def ToDict(self): |
|
547 |
"""Instance-specific conversion to standard python types. |
|
548 |
|
|
549 |
This replaces the children lists of objects with lists of standard |
|
550 |
python types. |
|
551 |
|
|
552 |
""" |
|
553 |
bo = super(Instance, self).ToDict() |
|
554 |
|
|
555 |
for attr in "nics", "disks": |
|
556 |
alist = bo.get(attr, None) |
|
557 |
if alist: |
|
558 |
nlist = self._ContainerToDicts(alist) |
|
559 |
else: |
|
560 |
nlist = [] |
|
561 |
bo[attr] = nlist |
|
562 |
return bo |
|
563 |
|
|
564 |
@classmethod |
|
565 |
def FromDict(cls, val): |
|
566 |
"""Custom function for instances. |
|
567 |
|
|
568 |
""" |
|
569 |
obj = super(Instance, cls).FromDict(val) |
|
570 |
obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC) |
|
571 |
obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk) |
|
572 |
return obj |
|
573 |
|
|
395 | 574 |
|
396 | 575 |
class OS(ConfigObject): |
397 | 576 |
"""Config object representing an operating system.""" |
Also available in: Unified diff