2014-08-31 13:45:35 +02:00
|
|
|
"""Remote module containing methods to bootstrap remotely
|
|
|
|
"""
|
2014-12-19 01:25:38 +01:00
|
|
|
from Pyro4.util import SerializerBase
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
supported_classes = ['bootstrapvz.base.manifest.Manifest',
|
|
|
|
'bootstrapvz.base.bootstrapinfo.BootstrapInformation',
|
2015-01-25 19:52:28 +01:00
|
|
|
'bootstrapvz.base.bootstrapinfo.DictClass',
|
2014-12-19 01:25:38 +01:00
|
|
|
'bootstrapvz.common.fs.loopbackvolume.LoopbackVolume',
|
|
|
|
'bootstrapvz.common.fs.qemuvolume.QEMUVolume',
|
|
|
|
'bootstrapvz.common.fs.virtualdiskimage.VirtualDiskImage',
|
|
|
|
'bootstrapvz.common.fs.virtualmachinedisk.VirtualMachineDisk',
|
|
|
|
'bootstrapvz.base.fs.partitionmaps.gpt.GPTPartitionMap',
|
|
|
|
'bootstrapvz.base.fs.partitionmaps.msdos.MSDOSPartitionMap',
|
|
|
|
'bootstrapvz.base.fs.partitionmaps.none.NoPartitions',
|
2014-12-19 01:43:10 +01:00
|
|
|
'bootstrapvz.base.fs.partitions.mount.Mount',
|
2014-12-19 01:25:38 +01:00
|
|
|
'bootstrapvz.base.fs.partitions.gpt.GPTPartition',
|
|
|
|
'bootstrapvz.base.fs.partitions.gpt_swap.GPTSwapPartition',
|
|
|
|
'bootstrapvz.base.fs.partitions.msdos.MSDOSPartition',
|
|
|
|
'bootstrapvz.base.fs.partitions.msdos_swap.MSDOSSwapPartition',
|
|
|
|
'bootstrapvz.base.fs.partitions.single.SinglePartition',
|
|
|
|
'bootstrapvz.base.fs.partitions.unformatted.UnformattedPartition',
|
|
|
|
'bootstrapvz.common.bytes.Bytes',
|
2015-01-03 12:44:32 +01:00
|
|
|
'bootstrapvz.common.sectors.Sectors',
|
2014-12-19 01:25:38 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
supported_exceptions = ['bootstrapvz.common.exceptions.ManifestError',
|
|
|
|
'bootstrapvz.common.exceptions.TaskListError',
|
|
|
|
'bootstrapvz.common.exceptions.TaskError',
|
|
|
|
'bootstrapvz.base.fs.exceptions.VolumeError',
|
|
|
|
'bootstrapvz.base.fs.exceptions.PartitionError',
|
|
|
|
'bootstrapvz.base.pkg.exceptions.PackageError',
|
|
|
|
'bootstrapvz.base.pkg.exceptions.SourceError',
|
2015-01-19 01:21:16 +01:00
|
|
|
'bootstrapvz.common.exceptions.UnitError',
|
2014-12-19 01:25:38 +01:00
|
|
|
'bootstrapvz.common.fsm_proxy.FSMProxyError',
|
2015-01-25 17:31:46 +01:00
|
|
|
'subprocess.CalledProcessError',
|
2014-12-19 01:25:38 +01:00
|
|
|
]
|
2014-08-31 13:45:35 +02:00
|
|
|
|
|
|
|
|
2014-11-24 23:43:17 +01:00
|
|
|
def register_deserialization_handlers():
|
2016-06-04 11:35:59 +02:00
|
|
|
for supported_class in supported_classes:
|
|
|
|
SerializerBase.register_dict_to_class(supported_class, deserialize)
|
|
|
|
for supported_exc in supported_exceptions:
|
|
|
|
SerializerBase.register_dict_to_class(supported_exc, deserialize_exception)
|
|
|
|
import subprocess
|
|
|
|
SerializerBase.register_class_to_dict(subprocess.CalledProcessError, serialize_called_process_error)
|
2014-11-24 23:43:17 +01:00
|
|
|
|
|
|
|
|
2014-11-25 21:12:37 +01:00
|
|
|
def unregister_deserialization_handlers():
|
2016-06-04 11:35:59 +02:00
|
|
|
for supported_class in supported_classes:
|
|
|
|
SerializerBase.unregister_dict_to_class(supported_class, deserialize)
|
|
|
|
for supported_exc in supported_exceptions:
|
|
|
|
SerializerBase.unregister_dict_to_class(supported_exc, deserialize_exception)
|
2014-11-25 21:12:37 +01:00
|
|
|
|
|
|
|
|
2014-12-19 01:25:38 +01:00
|
|
|
def deserialize_exception(fq_classname, data):
|
2016-06-04 11:35:59 +02:00
|
|
|
class_object = get_class_object(fq_classname)
|
|
|
|
return SerializerBase.make_exception(class_object, data)
|
2014-11-24 23:43:17 +01:00
|
|
|
|
|
|
|
|
2014-12-19 01:25:38 +01:00
|
|
|
def deserialize(fq_classname, data):
|
2016-06-04 11:35:59 +02:00
|
|
|
class_object = get_class_object(fq_classname)
|
|
|
|
from Pyro4.util import SerpentSerializer
|
|
|
|
from Pyro4.errors import SecurityError
|
|
|
|
ser = SerpentSerializer()
|
|
|
|
state = {}
|
|
|
|
for key, value in data.items():
|
|
|
|
try:
|
|
|
|
state[key] = ser.recreate_classes(value)
|
|
|
|
except SecurityError as e:
|
|
|
|
msg = 'Unable to deserialize key `{key}\' on {class_name}'.format(key=key, class_name=fq_classname)
|
|
|
|
raise Exception(msg, e)
|
2014-11-30 19:16:27 +01:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
instance = class_object.__new__(class_object)
|
|
|
|
instance.__setstate__(state)
|
|
|
|
return instance
|
2014-11-30 19:16:27 +01:00
|
|
|
|
|
|
|
|
2015-01-25 17:31:46 +01:00
|
|
|
def serialize_called_process_error(obj):
|
2016-06-04 11:35:59 +02:00
|
|
|
# This is by far the weirdest exception serialization.
|
|
|
|
# There is a bug in both Pyro4 and the Python subprocess module.
|
|
|
|
# CalledProcessError does not populate its args property,
|
|
|
|
# although according to https://docs.python.org/2/library/exceptions.html#exceptions.BaseException.args
|
|
|
|
# it should...
|
|
|
|
# So we populate that property during serialization instead
|
|
|
|
# (the code is grabbed directly from Pyro4's class_to_dict())
|
|
|
|
# However, Pyro4 still cannot figure out to call the deserializer
|
|
|
|
# unless we also use setattr() on the exception to set the args below
|
|
|
|
# (before throwing it).
|
|
|
|
# Mind you, the error "__init__() takes at least 3 arguments (2 given)"
|
|
|
|
# is thrown *on the server* if we don't use setattr().
|
|
|
|
# It's all very confusing to me and I'm not entirely
|
|
|
|
# sure what the exact problem is. Regardless - it works, so there.
|
|
|
|
return {'__class__': obj.__class__.__module__ + '.' + obj.__class__.__name__,
|
|
|
|
'__exception__': True,
|
|
|
|
'args': (obj.returncode, obj.cmd, obj.output),
|
|
|
|
'attributes': vars(obj) # add custom exception attributes
|
|
|
|
}
|
2015-01-25 17:31:46 +01:00
|
|
|
|
|
|
|
|
2014-12-19 01:25:38 +01:00
|
|
|
def get_class_object(fq_classname):
|
2016-06-04 11:35:59 +02:00
|
|
|
parts = fq_classname.split('.')
|
|
|
|
module_name = '.'.join(parts[:-1])
|
|
|
|
class_name = parts[-1]
|
|
|
|
import importlib
|
|
|
|
imported_module = importlib.import_module(module_name)
|
|
|
|
return getattr(imported_module, class_name)
|