#
# NEPI, a framework to manage network experiments
# Copyright (C) 2013 INRIA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation;
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Author: Alina Quereilhac
### Attribute Types
class Types:
""" Allowed types for the Attribute value
"""
String = "STRING"
Bool = "BOOL"
Enumerate = "ENUM"
Double = "DOUBLE"
Integer = "INTEGER"
### Attribute Flags
class Flags:
""" Flags to characterize the scope of an Attribute
"""
# Attribute value can not be read (it is hidden to the user)
NoRead = 1 # 1
# Attribute value can not be modified (it is not editable by the user)
NoWrite = 1 << 1 # 2
# Attribute value can be modified only before deployment
Design = 1 << 2 # 4
# Attribute value will be used at deployment time for initial configuration
Construct = 1 << 3 # 8
# Attribute provides credentials to access resources
Credential = 1 << 4 | Design # 16 + 4
# Attribute is a filter used to discover resources
Filter = 1 << 5 | Design # 32 + 4
# Attribute Flag is reserved for internal RM usage (i.e. should be
# transparent to the user)
Reserved = 1 << 6 # 64
# Attribute global is set to all resources of rtype
Global = 1 << 7 # 128
class Attribute(object):
""" An Attribute exposes a configuration parameter of a resource
"""
def __init__(self, name, help, type = Types.String,
flags = None, default = None, allowed = None,
range = None, set_hook = None):
"""
:param name: Name of the Attribute
:type name: str
:param help: Description of the Attribute
:type help: str
:param type: The type expected for the Attribute value.
Should be one of Attribute.Types
:type type: str
:param flags: Defines Attribute behavior (i.e. whether it is read-only,
read and write, etc). This parameter must take its values from
Attribute.Flags. Flags values can be bitwised
:type flags: hex
:param default: Default value for the Attribute
:type default: Depends on the type of Attribute
:param allowed: List of values that the Attribute can take.
This parameter is only meaningful for Enumerate type Attributes
:type allowed: list
:param range: (max, min) tuple with range of possible values for
Attributes.
This parameter is only meaningful for Integer or Double type
Attributes
:type range: (int, int) or (float, float)
:param set_hook: Function that will be executed whenever a new
value is set for the Attribute.
:type set_hook: function
"""
self._name = name
self._help = help
self._type = type
self._flags = flags or 0
self._allowed = allowed
self._range = range
self._default = self._value = default
# callback to be invoked upon changing the
# attribute value
self.set_hook = set_hook
@property
def name(self):
""" Returns the name of the Attribute """
return self._name
@property
def default(self):
""" Returns the default value of the Attribute """
return self._default
@property
def type(self):
""" Returns the type of the Attribute """
return self._type
@property
def help(self):
""" Returns the description of the Attribute """
return self._help
@property
def flags(self):
""" Returns the flags of the Attribute """
return self._flags
@property
def allowed(self):
""" Returns the set of allowed values for the Attribute """
return self._allowed
@property
def range(self):
""" Returns the range of allowed numerical values for the Attribute """
return self._range
def has_flag(self, flag):
""" Returns True if the Attribute has the flag 'flag'
:param flag: Flag to be checked
:type flag: Flags
"""
return (self._flags & flag) == flag
def get_value(self):
""" Returns the value of the Attribute """
return self._value
def set_value(self, value):
""" Configure a new value for the Attribute """
valid = True
if self.type == Types.Enumerate:
valid = value in self._allowed
if self.type in [Types.Double, Types.Integer] and self.range:
(min, max) = self.range
value = float(value)
valid = (value >= min and value <= max)
valid = valid and self.is_valid_value(value)
if valid:
if self.set_hook:
# Hook receives old value, new value
value = self.set_hook(self._value, value)
self._value = value
else:
raise ValueError("Invalid value %s for attribute %s" %
(str(value), self.name))
value = property(get_value, set_value)
def is_valid_value(self, value):
""" Attribute subclasses will override this method to add
adequate validation"""
return True
@property
def has_changed(self):
""" Returns True if the value has changed from the default """
return self.value != self.default