From: Alina Quereilhac Date: Wed, 9 Mar 2011 13:29:43 +0000 (+0100) Subject: Attribute flags changed to bit flag system X-Git-Tag: nepi_v2~194 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=15c5462598d75f0462b43910ce1aea51efdc9965;p=nepi.git Attribute flags changed to bit flag system --- diff --git a/src/nepi/core/attributes.py b/src/nepi/core/attributes.py index faca972c..d5dd4fd5 100644 --- a/src/nepi/core/attributes.py +++ b/src/nepi/core/attributes.py @@ -1,96 +1,41 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -class AttributesMap(object): - """AttributesMap is the base class for every object whose attributes - are going to be manipulated by the end-user in a script or GUI. - """ - def __init__(self): - self._attributes = dict() - - @property - def attributes(self): - return self._attributes.values() - - @property - def attributes_name(self): - return self._attributes.keys() - - def set_attribute_value(self, name, value): - self._attributes[name].value = value - - def set_attribute_readonly(self, name, readonly = True): - self._attributes[name].readonly = (readonly == True) - - def get_attribute_value(self, name): - return self._attributes[name].value - - def get_attribute_help(self, name): - return self._attributes[name].help - - def get_attribute_type(self, name): - return self._attributes[name].type - - def get_attribute_range(self, name): - if not self._attributes[name].range: - return (None, None) - return self._attributes[name].range - - def get_attribute_allowed(self, name): - return self._attributes[name].allowed - - def get_attribute_readonly(self, name): - return self._attributes[name].readonly - - def get_attribute_visible(self, name): - return self._attributes[name].visible - - def is_attribute_modified(self, name): - return self._attributes[name].modified - - def add_attribute(self, name, help, type, value = None, range = None, - allowed = None, readonly = False, visible = True, - validation_function = None): - if name in self._attributes: - raise AttributeError("Attribute %s already exists" % name) - attribute = Attribute(name, help, type, value, range, allowed, readonly, - visible, validation_function) - self._attributes[name] = attribute - - def del_attribute(self, name): - del self._attributes[name] - - def has_attribute(self, name): - return name in self._attributes - - def destroy(self): - self._attributes = dict() - class Attribute(object): + ### Attribute types STRING, BOOL, ENUM, DOUBLE, INTEGER = ( "STRING", "BOOL", "ENUM", "DOUBLE", "INTEGER") - types = [STRING, BOOL, ENUM, DOUBLE, INTEGER] + ### Attribute Flags + NoFlags = 0x00 + # Attribute is only modifiable during experiment design + DesignOnly = 0x01 + # Attribute is read only and can't be modified by the user + # Note: ReadOnly implies DesignOnly + ReadOnly = 0x03 + # Attribute is invisible to the user + # Note: Invisible implies ReadOnly and DesignOnly + Invisible = 0x07 + # Attribute has no default value in the testbed instance. + # So it needs to be set explicitely + HasNoDefaultValue = 0x08 + def __init__(self, name, help, type, value = None, range = None, - allowed = None, readonly = False, visible = True, - validation_function = None): + allowed = None, flags = NoFlags, validation_function = None): if not type in Attribute.types: raise AttributeError("invalid type %s " % type) self.name = name self._type = type self._help = help self._value = value - self._validation_function = validation_function - # readonly attributes can be seen but not changed by users - self._readonly = (readonly == True) - # invisible attributes cannot be seen or changed by users - self._visible = (visible == True) - self._modified = False + self._flags = flags # range: max and min possible values self._range = range # list of possible values self._allowed = allowed + self._validation_function = validation_function + self._modified = False @property def type(self): @@ -101,12 +46,25 @@ class Attribute(object): return self._help @property - def visible(self): - return self._visible + def flags(self): + return self._flags @property - def readonly(self): - return self._readonly + def invsible(self): + return (self._flags & Attribute.Invisible) == Attribute.Invisible + + @property + def read_only(self): + return (self._flags & Attribute.ReadOnly) == Attribute.ReadOnly + + @property + def has_no_default_value(self): + return (self._flags & Attribute.HasNoDefaultValue) == \ + Attribute.HasNoDefaultValue + + @property + def design_only(self): + return (self._flags & Attribute.DesignOnly) == Attribute.DesignOnly @property def modified(self): @@ -149,3 +107,70 @@ class Attribute(object): def _is_valid(self, value): return not self._validation_function or self._validation_function(value) +class AttributesMap(object): + """AttributesMap is the base class for every object whose attributes + are going to be manipulated by the end-user in a script or GUI. + """ + def __init__(self): + self._attributes = dict() + + @property + def attributes(self): + return self._attributes.values() + + @property + def attributes_name(self): + return self._attributes.keys() + + def set_attribute_value(self, name, value): + self._attributes[name].value = value + + def get_attribute_value(self, name): + return self._attributes[name].value + + def get_attribute_help(self, name): + return self._attributes[name].help + + def get_attribute_type(self, name): + return self._attributes[name].type + + def get_attribute_range(self, name): + if not self._attributes[name].range: + return (None, None) + return self._attributes[name].range + + def get_attribute_allowed(self, name): + return self._attributes[name].allowed + + def is_attribute_read_only(self, name): + return self._attributes[name].read_only + + def is_attribute_invisible(self, name): + return self._attributes[name].invisible + + def is_attribute_design_only(self, name): + return self._attributes[name].design_only + + def has_attribute_no_default_value(self, name): + return self._attributes[name].has_no_default_value + + def is_attribute_modified(self, name): + return self._attributes[name].modified + + def add_attribute(self, name, help, type, value = None, range = None, + allowed = None, flags = Attribute.NoFlags, validation_function = None): + if name in self._attributes: + raise AttributeError("Attribute %s already exists" % name) + attribute = Attribute(name, help, type, value, range, allowed, flags, + validation_function) + self._attributes[name] = attribute + + def del_attribute(self, name): + del self._attributes[name] + + def has_attribute(self, name): + return name in self._attributes + + def destroy(self): + self._attributes = dict() + diff --git a/src/nepi/core/design.py b/src/nepi/core/design.py index f479da9f..c37a45eb 100644 --- a/src/nepi/core/design.py +++ b/src/nepi/core/design.py @@ -157,17 +157,20 @@ class Address(AttributesMap): help = "If set, this address will automatically be assigned", type = Attribute.BOOL, value = False, + flags = Attribute.DesignOnly, validation_function = validation.is_bool) self.add_attribute(name = "Family", help = "Address family type: AF_INET, AFT_INET6", type = Attribute.INTEGER, value = family, - readonly = True) + flags = Attribute.ReadOnly | Attribute.HasNoDefaultValue, + validation_function = validation.is_integer) address_validation = validation.is_ip4_address if family == AF_INET \ else validation.is_ip6_address self.add_attribute(name = "Address", help = "Address number", type = Attribute.STRING, + flags = Attribute.HasNoDefaultValue, validation_function = address_validation) prefix_range = (0, 32) if family == AF_INET else (0, 128) self.add_attribute(name = "NetPrefix", @@ -175,6 +178,7 @@ class Address(AttributesMap): type = Attribute.INTEGER, range = prefix_range, value = 24 if family == AF_INET else 64, + flags = Attribute.HasNoDefaultValue, validation_function = validation.is_integer) if family == AF_INET: self.add_attribute(name = "Broadcast", @@ -189,7 +193,8 @@ class Route(AttributesMap): help = "Address family type: AF_INET, AFT_INET6", type = Attribute.INTEGER, value = family, - readonly = True) + flags = Attribute.ReadOnly | Attribute.HasNoDefaultValue, + validation_function = validation.is_integer) address_validation = validation.is_ip4_address if family == AF_INET \ else validation.is_ip6_address self.add_attribute(name = "Destination", @@ -200,11 +205,13 @@ class Route(AttributesMap): self.add_attribute(name = "NetPrefix", help = "Network destination prefix", type = Attribute.INTEGER, + flags = Attribute.HasNoDefaultValue, prefix_range = prefix_range, validation_function = validation.is_integer) self.add_attribute(name = "NextHop", help = "Address for the next hop", type = Attribute.STRING, + flags = Attribute.HasNoDefaultValue, validation_function = address_validation) class Box(AttributesMap): @@ -235,7 +242,7 @@ class Box(AttributesMap): self._traces[trace.trace_id] = tr for attr in factory.box_attributes: self.add_attribute(attr.name, attr.help, attr.type, attr.value, - attr.range, attr.allowed, attr.readonly, attr.visible, + attr.range, attr.allowed, attr.flags, attr.validation_function) for attr in factory.attributes: if attr.modified: @@ -412,10 +419,9 @@ class Factory(AttributesMap): self._traces.append(trace) def add_box_attribute(self, name, help, type, value = None, range = None, - allowed = None, readonly = False, visible = True, - validation_function = None): - attribute = Attribute(name, help, type, value, range, allowed, readonly, - visible, validation_function) + allowed = None, flags = Attribute.NoFlags, validation_function = None): + attribute = Attribute(name, help, type, value, range, allowed, flags, + validation_function) self._box_attributes.append(attribute) def create(self, guid, testbed_description): @@ -474,7 +480,7 @@ class TestbedDescription(AttributesMap): metadata = Metadata(provider.testbed_id, provider.testbed_version) for attr in metadata.testbed_attributes().attributes: self.add_attribute(attr.name, attr.help, attr.type, attr.value, - attr.range, attr.allowed, attr.readonly, attr.visible, + attr.range, attr.allowed, attr.flags, attr.validation_function) @property diff --git a/src/nepi/core/execute.py b/src/nepi/core/execute.py index b89d7605..b92e85ce 100644 --- a/src/nepi/core/execute.py +++ b/src/nepi/core/execute.py @@ -287,9 +287,6 @@ class ExperimentController(object): for (autoconf, address, family, netprefix, broadcast) in \ data.get_address_data(guid): if address != None: - # TODO: BUG!!! Hardcodeado!!!!!! XXXXXXXXX CORREGIR!!! - family = 0 - netprefix = 24 instance.add_adddress(guid, family, address, netprefix, broadcast) for (family, destination, netprefix, nexthop) in \ diff --git a/src/nepi/core/metadata.py b/src/nepi/core/metadata.py index 6485b495..cf84a2d3 100644 --- a/src/nepi/core/metadata.py +++ b/src/nepi/core/metadata.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from nepi.core.attributes import AttributesMap +from nepi.core.attributes import Attribute, AttributesMap import sys class VersionedMetadataInfo(object): @@ -40,8 +40,7 @@ class VersionedMetadataInfo(object): "value": default attribute value, "range": (maximum, minimun) values else None if not defined, "allowed": array of posible values, - "readonly": whether the attribute is read only for the user, - "visible": whether the attribute is visible for the user, + "flags": attributes flags, "validation_function": validation function for the attribute }) """ @@ -94,8 +93,7 @@ class VersionedMetadataInfo(object): "value": default attribute value, "range": (maximum, minimun) values else None if not defined, "allowed": array of posible values, - "readonly": whether the attribute is read only for the user, - "visible": whether the attribute is visible for the user, + "flags": attributes flags, "validation_function": validation function for the attribute }) ] @@ -121,11 +119,11 @@ class Metadata(object): value = attribute_info["value"] range = attribute_info["range"] allowed = attribute_info["allowed"] - readonly = attribute_info["readonly"] - visible = attribute_info["visible"] + flags = attribute_info["flags"] if "flags" in attribute_info \ + else Attribute.NoFlags validation_function = attribute_info["validation_function"] attributes.add_attribute(name, help, type, value, - range, allowed, readonly, visible, validation_function) + range, allowed, flags, validation_function) return attributes def build_design_factories(self): @@ -187,15 +185,15 @@ class Metadata(object): value = attribute_info["value"] range = attribute_info["range"] allowed = attribute_info["allowed"] - readonly = attribute_info["readonly"] - visible = attribute_info["visible"] + flags = attribute_info["flags"] if "flags" in attribute_info \ + else Attribute.NoFlags validation_function = attribute_info["validation_function"] if box_attributes: factory.add_box_attribute(name, help, type, value, range, - allowed, readonly, visible, validation_function) + allowed, flags, validation_function) else: factory.add_attribute(name, help, type, value, range, - allowed, readonly, visible, validation_function) + allowed, flags, validation_function) def _add_design_traces(self, factory, info): if "traces" in info: diff --git a/src/nepi/core/testbed_impl.py b/src/nepi/core/testbed_impl.py index 63c0b006..ea039e1a 100644 --- a/src/nepi/core/testbed_impl.py +++ b/src/nepi/core/testbed_impl.py @@ -11,6 +11,7 @@ TIME_NOW = "0s" class TestbedInstance(execute.TestbedInstance): def __init__(self, testbed_id, testbed_version): super(TestbedInstance, self).__init__(testbed_id, testbed_version) + self._started = False # testbed attributes for validation self._attributes = None # element factories for validation @@ -225,6 +226,8 @@ class TestbedInstance(execute.TestbedInstance): if not factory.has_attribute(name): raise RuntimeError("Invalid attribute %s for element type %s" % (name, factory_id)) + if self._started and factory.is_attribute_design_only(name): + raise RuntimeError("Attribute %s can only be modified during experiment design" % name) factory.set_attribute_value(name, value) if guid not in self._set: self._set[guid] = dict() @@ -245,6 +248,7 @@ class TestbedInstance(execute.TestbedInstance): parameters = dict() if guid not in self._create_set else \ self._create_set[guid] start_function(self, guid, parameters, traces) + self._started = True def action(self, time, guid, action): raise NotImplementedError diff --git a/src/nepi/testbeds/netns/metadata_v01.py b/src/nepi/testbeds/netns/metadata_v01.py index 46a0860d..d164540f 100644 --- a/src/nepi/testbeds/netns/metadata_v01.py +++ b/src/nepi/testbeds/netns/metadata_v01.py @@ -224,8 +224,7 @@ attributes = dict({ "value": False, "range": None, "allowed": None, - "readonly": False, - "visible": True, + "flags": Attribute.DesignOnly, "validation_function": validation.is_bool }), "lladdr": dict({ @@ -235,8 +234,7 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": False, - "visible": True, + "flags": Attribute.DesignOnly, "validation_function": validation.is_mac_address }), "up": dict({ @@ -246,8 +244,6 @@ attributes = dict({ "value": False, "range": None, "allowed": None, - "readonly": False, - "visible": True, "validation_function": validation.is_bool }), "device_name": dict({ @@ -257,8 +253,7 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": False, - "visible": True, + "flags": Attribute.DesignOnly, "validation_function": validation.is_string }), "mtu": dict({ @@ -268,8 +263,6 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": False, - "visible": True, "validation_function": validation.is_integer }), "broadcast": dict({ @@ -279,8 +272,6 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": False, - "visible": True, "validation_function": validation.is_string # TODO: should be is address! }), "multicast": dict({ @@ -290,8 +281,6 @@ attributes = dict({ "value": False, "range": None, "allowed": None, - "readonly": False, - "visible": True, "validation_function": validation.is_bool }), "arp": dict({ @@ -301,8 +290,6 @@ attributes = dict({ "value": False, "range": None, "allowed": None, - "readonly": False, - "visible": True, "validation_function": validation.is_bool }), "command": dict({ @@ -312,8 +299,7 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": False, - "visible": True, + "flags": Attribute.DesignOnly, "validation_function": validation.is_string }), "user": dict({ @@ -323,8 +309,7 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": False, - "visible": True, + "flags": Attribute.DesignOnly, "validation_function": validation.is_string }), "stdin": dict({ @@ -334,8 +319,7 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": False, - "visible": True, + "flags": Attribute.DesignOnly, "validation_function": validation.is_string }), "max_addresses": dict({ @@ -345,8 +329,7 @@ attributes = dict({ "value": None, "range": None, "allowed": None, - "readonly": True, - "visible": False, + "flags": Attribute.Invisible, "validation_function": validation.is_integer }), "family": dict({ @@ -356,8 +339,7 @@ attributes = dict({ "value": AF_INET, "range": None, "allowed": None, - "readonly": True, - "visible": False, + "flags": Attribute.Invisible, "validation_function": validation.is_integer }), }) @@ -464,8 +446,6 @@ testbed_attributes = dict({ "value": False, "range": None, "allowed": None, - "readonly": False, - "visible": True, "validation_function": validation.is_bool }), "home_directory": dict({ @@ -476,8 +456,7 @@ testbed_attributes = dict({ "value": False, "range": None, "allowed": None, - "readonly": False, - "visible": True, + "flags": Attribute.DesignOnly, "validation_function": validation.is_string }) }) diff --git a/src/nepi/util/parser/_xml.py b/src/nepi/util/parser/_xml.py index 13742cde..9e356920 100644 --- a/src/nepi/util/parser/_xml.py +++ b/src/nepi/util/parser/_xml.py @@ -103,10 +103,8 @@ class XmlExperimentParser(ExperimentParser): address_tag.setAttribute("AutoConfigure", str(autoconf)) if address: address_tag.setAttribute("Address", str(address)) - if family: - address_tag.setAttribute("Family", str(family)) - if netprefix: - address_tag.setAttribute("NetPrefix", str(netprefix)) + address_tag.setAttribute("Family", str(family)) + address_tag.setAttribute("NetPrefix", str(netprefix)) if broadcast: address_tag.setAttribute("Broadcast", str(broadcast)) if addresses_tag.hasChildNodes(): diff --git a/src/nepi/util/parser/base.py b/src/nepi/util/parser/base.py index 7bf5325f..35df079c 100644 --- a/src/nepi/util/parser/base.py +++ b/src/nepi/util/parser/base.py @@ -77,10 +77,8 @@ class ExperimentData(object): address_data["AutoConfigure"] = autoconf if address: address_data["Address"] = address - if family: - address_data["Family"] = family - if netprefix: - address_data["NetPrefix"] = netprefix + address_data["Family"] = family + address_data["NetPrefix"] = netprefix if broadcast: address_data["Broadcast"] = broadcast addresses_data.append(address_data) @@ -209,7 +207,7 @@ class ExperimentParser(object): def attributes_to_data(self, data, guid, attributes): for attribute in attributes: - if attribute.modified: + if attribute.modified or attribute.has_no_default_value: data.add_attribute_data(guid, attribute.name, attribute.value) def traces_to_data(self, data, guid, traces): @@ -228,17 +226,13 @@ class ExperimentParser(object): def addresses_to_data(self, data, guid, addresses): for addr in addresses: - autoconf = addr.get_attribute_value("AutoConfigure") \ - if addr.is_attribute_modified("AutoConfigure") else None - address = addr.get_attribute_value("Address") \ - if addr.is_attribute_modified("Address") else None - netprefix = addr.get_attribute_value("NetPrefix") \ - if addr.is_attribute_modified("NetPrefix") else None - family = addr.get_attribute_value("Family") \ - if addr.is_attribute_modified("Family") else None + autoconf = addr.get_attribute_value("AutoConfigure") + address = addr.get_attribute_value("Address") + netprefix = addr.get_attribute_value("NetPrefix") + family = addr.get_attribute_value("Family") broadcast = addr.get_attribute_value("Broadcast") \ if addr.has_attribute("Broadcast") and \ - addr.is_attribute_modified("Broadcast") else None + addr.is_attribute_modified("Broadcast") else None data.add_address_data(guid, autoconf, address, family, netprefix, broadcast) @@ -312,9 +306,9 @@ class ExperimentParser(object): addr.set_attribute_value("AutoConfigure", autoconf) if address: addr.set_attribute_value("Address", address) - if family: + if family != None: addr.set_attribute_value("Family", family) - if netprefix: + if netprefix != None: addr.set_attribute_value("NetPrefix", netprefix) if broadcast: addr.set_attribute_value("Broadcast", broadcast)