Exemple #1
0
class VmmInjectedContGroup(AciResourceBase):
    """Resource representing a VMM injected container group in ACI.

    Identity attributes: VMM domain type, VMM domain name, controller name,
    namespace name and group name.
    """
    identity_attributes = t.identity(
        ('domain_type', t.name),
        ('domain_name', t.name),
        ('controller_name', t.name),
        ('namespace_name', t.name),
        ('name', t.name))
    other_attributes = t.other(
        ('display_name', t.name),
        ('host_name', t.name),
        ('compute_node_name', t.name),
        ('replica_set_name', t.name))
    db_attributes = t.db(('guid', t.string()))

    _aci_mo_name = 'vmmInjectedContGrp'
    _tree_parent = VmmInjectedNamespace

    def __init__(self, **kwargs):
        super(VmmInjectedContGroup, self).__init__({'host_name': '',
                                                    'compute_node_name': '',
                                                    'replica_set_name': '',
                                                    'guid': ''},
                                                   **kwargs)
Exemple #2
0
class ApicAssignment(resource.ResourceBase):
    """Track the APIC to aim-aid mapping"""

    identity_attributes = t.identity(
        ('apic_host', t.string(128)))
    other_attributes = t.other(
        ('aim_aid_id', t.string(64)))
    db_attributes = t.db(
        ('last_update_timestamp', t.string()))

    def __init__(self, **kwargs):
        super(ApicAssignment, self).__init__({'aim_aid_id': ''},
                                             **kwargs)

    def is_available(self, context):
        current = context.store.current_timestamp
        # When the store doesn't support time stamp, the APIC can never
        # be considered available.
        if current is None:
            return False
        result = current - self.last_update_timestamp >= datetime.timedelta(
            seconds=cfg.CONF.aim.apic_available_time)
        if result:
            LOG.info("APIC %s is available. Last update time was %s" %
                     (self.apic_host, self.last_update_timestamp))
            return True
        else:
            LOG.debug("APIC %s is not available. Last update time was %s" %
                      (self.apic_host, self.last_update_timestamp))
            return False
class Tree(api_res.ResourceBase):
    identity_attributes = t.identity(('root_rn', t.string(64)))
    other_attributes = t.other(('needs_reset', t.bool))
    db_attributes = t.db()

    def __init__(self, **kwargs):
        super(Tree, self).__init__({}, **kwargs)
class TypeTreeBase(object):
    identity_attributes = t.identity(('root_rn', t.string(64)))
    other_attributes = t.other(('root_full_hash', t.string(256)),
                               ('tree', t.string()))
    db_attributes = t.db()

    def __init__(self, **kwargs):
        super(TypeTreeBase, self).__init__({}, **kwargs)
class AciFault(resource.ResourceBase, OperationalResource):
    """Fault information reported by ACI."""

    LC_UNKNOWN = 0x0
    LC_SOAKING = 0x1
    LC_RETAINING = 0x10
    LC_RAISED = 0x2
    LC_SOAKING_CLEARING = 0x4
    LC_RAISED_CLEARING = 0x8

    SEV_CLEARED = 'cleared'
    SEV_INFO = 'info'
    SEV_WARNING = 'warning'
    SEV_MINOR = 'minor'
    SEV_MAJOR = 'major'
    SEV_CRITICAL = 'critical'

    _aci_mo_name = 'faultInst'
    identity_attributes = t.identity(('fault_code', t.string()),
                                     ('external_identifier', t.string()))
    other_attributes = t.other(('severity',
                                t.enum(SEV_CLEARED, SEV_CRITICAL, SEV_INFO,
                                       SEV_WARNING, SEV_MAJOR, SEV_MINOR)),
                               ('status_id', t.id), ('cause', t.string()),
                               ('description', t.string(255)))

    db_attributes = t.db(('last_update_timestamp', t.string()))

    def __eq__(self, other):
        try:
            return self.identity == other.identity
        except AttributeError:
            return False

    def __init__(self, **kwargs):
        super(AciFault, self).__init__(
            {
                'severity': self.SEV_INFO,
                'lifecycle_status': self.LC_UNKNOWN,
                'cause': '',
                'description': ""
            }, **kwargs)

    def is_error(self):
        return self.severity in [self.SEV_MAJOR, self.SEV_CRITICAL]

    @property
    def dn(self):
        return self.external_identifier

    @property
    def root(self):
        mos_and_types = utils.decompose_dn(self._aci_mo_name, self.dn)
        if mos_and_types:
            # Faults associated with unrecognized MOs will not decompose
            mo = apic_client.ManagedObjectClass(mos_and_types[0][0])
            return (mo.rn(mos_and_types[0][1])
                    if mo.rn_param_count else mo.rn())
Exemple #6
0
class Configuration(ResourceBase):

    identity_attributes = t.identity(
        ('key', t.string(52)), ('host', t.string(52)), ('group', t.string(52)))
    other_attributes = t.other(('value', t.string(512)))
    db_attributes = t.db(('version', t.string(36)))

    def __init__(self, **kwargs):
        super(Configuration, self).__init__({}, **kwargs)
Exemple #7
0
class Agent(ResourceBase):
    """Resource representing an AIM Agent"""

    identity_attributes = t.identity(('id', t.id))
    other_attributes = t.other(
        ('agent_type', t.string(255)),
        ('host', t.string(255)),
        ('binary_file', t.string(255)),
        ('admin_state_up', t.bool),
        ('description', t.string(255)),
        ('hash_trees', t.list_of_ids),
        ('version', t.string()))
    # Attrbutes completely managed by the DB (eg. timestamps)
    db_attributes = t.db(('heartbeat_timestamp', t.string()))

    def __init__(self, **kwargs):
        super(Agent, self).__init__({'admin_state_up': True,
                                     'id': utils.generate_uuid()}, **kwargs)

    def __eq__(self, other):
        return self.id == other.id

    # An object is hashable if it has a hash value which never changes during
    # its lifetime (it needs a __hash__() method), and can be compared to
    # other objects (it needs an __eq__() or __cmp__() method).
    # Hashable objects which compare equal must have the same hash value.
    #
    # If you define __eq__() , the default __hash__() (namely, hashing the
    # address of the object in memory) goes away.
    # So for each class defining __eq__() we must also
    # define __hash__() even though parent class has __hash__().
    def __hash__(self):
        return super(Agent, self).__hash__()

    def is_down(self, context):
        current = context.store.current_timestamp
        # When the store doesn't support timestamps the agent can never
        # be considered down.
        if current is None:
            return False
        result = current - self.heartbeat_timestamp >= datetime.timedelta(
            seconds=cfg.CONF.aim.agent_down_time)
        if result:
            LOG.warn("Agent %s is down. Last heartbeat was %s" %
                     (self.id, self.heartbeat_timestamp))
        else:
            LOG.debug("Agent %s is alive, its last heartbeat was %s" %
                      (self.id, self.heartbeat_timestamp))
        return result

    def down_time(self, context):
        if self.is_down(context):
            current = context.store.current_timestamp
            return (current - self.heartbeat_timestamp).seconds
class ActionLog(api_res.ResourceBase):
    CREATE = 'create'
    DELETE = 'delete'
    RESET = 'reset'

    identity_attributes = t.identity(('uuid', t.string(64)))
    other_attributes = t.other(
        ('action', t.enum(CREATE, DELETE, RESET)),
        ('object_type', t.string(50)),
        ('object_dict', t.string()),
        ('root_rn', t.string(64)),
    )
    db_attributes = t.db(('timestamp', t.string()), ('id', t.integer))

    def __init__(self, **kwargs):
        super(ActionLog, self).__init__({'uuid': utils.generate_uuid()},
                                        **kwargs)
Exemple #9
0
class Agent(ResourceBase):
    """Resource representing an AIM Agent"""

    identity_attributes = t.identity(('id', t.id))
    other_attributes = t.other(
        ('agent_type', t.string(255)), ('host', t.string(255)),
        ('binary_file', t.string(255)), ('admin_state_up', t.bool),
        ('description', t.string(255)), ('hash_trees', t.list_of_ids),
        ('version', t.string()))
    # Attrbutes completely managed by the DB (eg. timestamps)
    db_attributes = t.db(('heartbeat_timestamp', t.string()))

    def __init__(self, **kwargs):
        super(Agent, self).__init__(
            {
                'admin_state_up': True,
                'id': utils.generate_uuid()
            }, **kwargs)

    def __eq__(self, other):
        return self.id == other.id

    def is_down(self, context):
        current = context.store.current_timestamp
        # When the store doesn't support timestamps the agent can never
        # be considered down.
        if current is None:
            return False
        result = current - self.heartbeat_timestamp >= datetime.timedelta(
            seconds=cfg.CONF.aim.agent_down_time)
        if result:
            LOG.warn("Agent %s is down. Last heartbeat was %s" %
                     (self.id, self.heartbeat_timestamp))
        else:
            LOG.debug("Agent %s is alive, its last heartbeat was %s" %
                      (self.id, self.heartbeat_timestamp))
        return result

    def down_time(self, context):
        if self.is_down(context):
            current = context.store.current_timestamp
            return (current - self.heartbeat_timestamp).seconds
Exemple #10
0
class VmmInjectedDeployment(AciResourceBase):
    """Resource representing a VMM injected deployment in ACI.

    Identity attributes: VMM domain type, VMM domain name, controller name,
    namespace name and deployment name.
    """
    identity_attributes = t.identity(
        ('domain_type', t.name), ('domain_name', t.name),
        ('controller_name', t.name), ('namespace_name', t.name),
        ('name', t.name))
    other_attributes = t.other(('display_name', t.name),
                               ('replicas', t.integer))
    db_attributes = t.db(('guid', t.string()))

    _aci_mo_name = 'vmmInjectedDepl'
    _tree_parent = VmmInjectedNamespace

    def __init__(self, **kwargs):
        super(VmmInjectedDeployment, self).__init__({
            'replicas': 0,
            'guid': ''
        }, **kwargs)
Exemple #11
0
class VmmInjectedService(AciResourceBase):
    """Resource representing a VMM injected service in ACI.

    Identity attributes: VMM domain type, VMM domain name, controller name,
    namespace name and service name.
    """
    identity_attributes = t.identity(
        ('domain_type', t.name),
        ('domain_name', t.name),
        ('controller_name', t.name),
        ('namespace_name', t.name),
        ('name', t.name))
    other_attributes = t.other(
        ('display_name', t.name),
        ('service_type', t.enum('clusterIp', 'externalName', 'nodePort',
                                'loadBalancer')),
        ('cluster_ip', t.string()),
        ('load_balancer_ip', t.string()),
        ('service_ports', t.list_of_dicts(('port', t.ports),
                                          ('protocol', t.string(32)),
                                          ('target_port', t.string(32)),
                                          ('node_port', t.ports))),
        ('endpoints', t.list_of_dicts(('ip', t.string()),
                                      ('pod_name', t.name))))
    db_attributes = t.db(('guid', t.string()))

    _aci_mo_name = 'vmmInjectedSvc'
    _tree_parent = VmmInjectedNamespace

    def __init__(self, **kwargs):
        super(VmmInjectedService, self).__init__(
            {'service_type': 'clusterIp',
             'cluster_ip': '0.0.0.0',
             'load_balancer_ip': '0.0.0.0',
             'service_ports': [],
             'endpoints': [],
             'guid': ''},
            **kwargs)
class AciStatus(resource.ResourceBase, OperationalResource):
    """Status of an AIM resource that is mapped to ACI object.

    Following attributes are available:
    * sync_status - Indicates whether ACI object was created/updated
    * sync_message - Informational or error message related to ACI
                     object creation/update
    * health_score - Health score of ACI object as reported by APIC
    * health_level - Level-wise classification of health-score
    * faults - List of AciFault objects as reported by APIC
    """

    # ACI object create/update is pending
    SYNC_PENDING = 'sync_pending'
    # ACI object was created/updated. It may or may not be in healthy state
    SYNCED = 'synced'
    # Create/update of ACI object failed
    SYNC_FAILED = 'sync_failed'
    SYNC_NA = 'N/A'

    identity_attributes = t.identity(('resource_type', t.string()),
                                     ('resource_id', t.id),
                                     ('resource_root', t.name))
    other_attributes = t.other(
        ('sync_status', t.enum(SYNCED, SYNC_PENDING, SYNC_FAILED)),
        ('sync_message', t.string()), ('health_score', t.number),
        ('faults', t.list_of_strings))
    db_attributes = t.db(('id', t.string(36)))

    HEALTH_POOR = "Poor Health Score"
    HEALTH_FAIR = "Fair Health Score"
    HEALTH_GOOD = "Good Health Score"
    HEALTH_EXCELLENT = "Excellent Health Score"

    def __init__(self, **kwargs):
        super(AciStatus, self).__init__(
            {
                'resource_type': None,
                'resource_id': None,
                'sync_status': self.SYNC_NA,
                'sync_message': '',
                'health_score': 100,
                'faults': []
            }, **kwargs)
        self._parent_class = None

    @property
    def health_level(self):
        if self.health_score > 90:
            return self.HEALTH_EXCELLENT
        elif self.health_score > 75:
            return self.HEALTH_GOOD
        elif self.health_score > 50:
            return self.HEALTH_FAIR
        else:
            return self.HEALTH_POOR

    @property
    def parent_class(self):
        if not self._parent_class:
            for path in resource_paths:
                try:
                    self._parent_class = importutils.import_class(
                        path + '.%s' % self.resource_type)
                except ImportError:
                    continue
        return self._parent_class

    @property
    def root(self):
        return self.resource_root

    def is_build(self):
        return self.sync_status in [self.SYNC_PENDING, self.SYNC_NA]

    def is_error(self):
        return (self.sync_status == self.SYNC_FAILED
                or self.health_level == self.HEALTH_POOR
                or [f for f in self.faults if f.is_error()])
Exemple #13
0
class ResourceBase(object):
    """Base class for AIM resource.

    Class property 'identity_attributes' gives a list of resource
    attributes that uniquely identify the resource. The values of
    these attributes directly determines the corresponding ACI
    object identifier (DN). These attributes must always be specified.
    Class property 'other_attributes' gives a list of additional
    resource attributes that are defined on the resource.
    Class property 'db_attributes' gives a list of resource attributes
    that are managed by the database layer, eg: timestamp, incremental counter.
    """

    db_attributes = t.db()
    common_db_attributes = t.db(('epoch', t.epoch))
    sorted_attributes = []

    def __init__(self, defaults, **kwargs):
        unset_attr = [k for k in self.identity_attributes
                      if kwargs.get(k) is None and k not in defaults]
        if 'display_name' in self.other_attributes:
            defaults.setdefault('display_name', '')
        if unset_attr:
            raise exc.IdentityAttributesMissing(klass=type(self).__name__,
                                                attr=unset_attr)
        if kwargs.pop('_set_default', True):
            for k, v in defaults.items():
                setattr(self, k, v)
        for k, v in kwargs.items():
            setattr(self, k, v)

    def __getattr__(self, item):
        if item == 'epoch':
            return None
        super(ResourceBase, self).__getattr__(item)

    @property
    def identity(self):
        return [str(getattr(self, x)) for x in self.identity_attributes.keys()]

    @classmethod
    def attributes(cls):
        return (list(cls.identity_attributes.keys()) +
                list(cls.other_attributes.keys()) +
                list(cls.db_attributes.keys()) +
                list(cls.common_db_attributes.keys()))

    @classmethod
    def user_attributes(cls):
        return list(cls.identity_attributes.keys()) + list(
            cls.other_attributes.keys())

    @classmethod
    def non_user_attributes(cls):
        return list(cls.db_attributes.keys()) + list(
            cls.common_db_attributes.keys())

    @property
    def members(self):
        return {x: self.__dict__[x] for x in self.attributes() +
                ['pe_existing', '_error', '_pending'] if x in self.__dict__}

    @property
    def hash(self):
        def make_serializable(key, attr):
            if isinstance(attr, list) and key not in self.sorted_attributes:
                return sorted(make_serializable(None, x) for x in attr)
            if isinstance(attr, dict):
                return sorted([(k, make_serializable(k, v))
                               for k, v in attr.items()])
            if isinstance(attr, set):
                return sorted([(make_serializable(None, x) for x in attr)])
            if isinstance(attr, (int, float, bool, type(None))):
                return attr
            # Don't know the type, make it serializable anyways
            return str(attr)
        serializable = make_serializable(None, self.members)
        return int(md5(base64.b64encode(
            oslo_serialization.jsonutils.dump_as_bytes(
                serializable, sort_keys=True))).hexdigest(), 16)

    def user_equal(self, other):
        def sort_if_list(key, attr):
            # In Py3, sorting a dict w.r.t. keys first & then its values
            # natively is not available. So this is a fix for that.
            if six.PY3:
                if isinstance(attr,
                              list) and key not in self.sorted_attributes:
                    if attr and isinstance(attr[0], dict):
                        return sorted(attr, key=lambda d: sorted(d.items()))
                    return sorted(attr)
                return attr
            return (sorted(attr) if isinstance(attr, list) and
                    key not in self.sorted_attributes else attr)

        missing = object()

        if type(self) != type(other):
            return False

        for attr in self.user_attributes():
            if (sort_if_list(attr, getattr(self, attr, missing)) !=
                    sort_if_list(attr, getattr(other, attr, missing))):
                return False
        return True

    def __str__(self):
        return '%s(%s)' % (type(self).__name__, ','.join(self.identity))

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        return not self.__eq__(other)

    def __repr__(self):
        return '%s(%s)' % (super(ResourceBase, self).__repr__(), self.members)

    # An object is hashable if it has a hash value which never changes during
    # its lifetime (it needs a __hash__() method), and can be compared to
    # other objects (it needs an __eq__() or __cmp__() method).
    # Hashable objects which compare equal must have the same hash value.
    #
    # If you define __eq__() , the default __hash__() (namely, hashing the
    # address of the object in memory) goes away.
    # So for each class defining __eq__() we must also
    # define __hash__() even though parent class has __hash__().
    def __hash__(self):
        return self.hash
Exemple #14
0
class ResourceBase(object):
    """Base class for AIM resource.

    Class property 'identity_attributes' gives a list of resource
    attributes that uniquely identify the resource. The values of
    these attributes directly determines the corresponding ACI
    object identifier (DN). These attributes must always be specified.
    Class property 'other_attributes' gives a list of additional
    resource attributes that are defined on the resource.
    Class property 'db_attributes' gives a list of resource attributes
    that are managed by the database layer, eg: timestamp, incremental counter.
    """

    db_attributes = t.db()
    common_db_attributes = t.db(('epoch', t.epoch))
    sorted_attributes = []

    def __init__(self, defaults, **kwargs):
        unset_attr = [
            k for k in self.identity_attributes
            if kwargs.get(k) is None and k not in defaults
        ]
        if 'display_name' in self.other_attributes:
            defaults.setdefault('display_name', '')
        if unset_attr:
            raise exc.IdentityAttributesMissing(klass=type(self).__name__,
                                                attr=unset_attr)
        if kwargs.pop('_set_default', True):
            for k, v in defaults.iteritems():
                setattr(self, k, v)
        for k, v in kwargs.iteritems():
            setattr(self, k, v)

    def __getattr__(self, item):
        if item == 'epoch':
            return None
        super(ResourceBase, self).__getattr__(item)

    @property
    def identity(self):
        return [str(getattr(self, x)) for x in self.identity_attributes.keys()]

    @classmethod
    def attributes(cls):
        return (cls.identity_attributes.keys() + cls.other_attributes.keys() +
                cls.db_attributes.keys() + cls.common_db_attributes.keys())

    @classmethod
    def user_attributes(cls):
        return cls.identity_attributes.keys() + cls.other_attributes.keys()

    @classmethod
    def non_user_attributes(cls):
        return cls.db_attributes.keys() + cls.common_db_attributes.keys()

    @property
    def members(self):
        return {
            x: self.__dict__[x]
            for x in self.attributes() + ['pe_existing', '_error', '_pending']
            if x in self.__dict__
        }

    @property
    def hash(self):
        def make_serializable(key, attr):
            if isinstance(attr, list) and key not in self.sorted_attributes:
                return sorted(make_serializable(None, x) for x in attr)
            if isinstance(attr, dict):
                return sorted([(k, make_serializable(k, v))
                               for k, v in attr.iteritems()])
            if isinstance(attr, set):
                return sorted([(make_serializable(None, x) for x in attr)])
            if isinstance(attr, (int, float, bool, type(None))):
                return attr
            # Don't know the type, make it serializable anyways
            return str(attr)

        serializable = make_serializable(None, self.members)
        return int(
            md5(base64.b64encode(json.dumps(serializable,
                                            sort_keys=True))).hexdigest(), 16)

    def user_equal(self, other):
        def sort_if_list(key, attr):
            return (sorted(attr) if isinstance(attr, list)
                    and key not in self.sorted_attributes else attr)

        missing = object()

        if type(self) != type(other):
            return False
        for attr in self.user_attributes():
            if (sort_if_list(attr, getattr(self, attr, missing)) !=
                    sort_if_list(attr, getattr(other, attr, missing))):
                return False
        return True

    def __str__(self):
        return '%s(%s)' % (type(self).__name__, ','.join(self.identity))

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        return not self.__eq__(other)

    def __repr__(self):
        return '%s(%s)' % (super(ResourceBase, self).__repr__(), self.members)

    def __hash__(self):
        return self.hash
Exemple #15
0
class AciFault(resource.ResourceBase, OperationalResource):
    """Fault information reported by ACI."""

    LC_UNKNOWN = 0x0
    LC_SOAKING = 0x1
    LC_RETAINING = 0x10
    LC_RAISED = 0x2
    LC_SOAKING_CLEARING = 0x4
    LC_RAISED_CLEARING = 0x8

    SEV_CLEARED = 'cleared'
    SEV_INFO = 'info'
    SEV_WARNING = 'warning'
    SEV_MINOR = 'minor'
    SEV_MAJOR = 'major'
    SEV_CRITICAL = 'critical'

    _aci_mo_name = 'faultInst'
    identity_attributes = t.identity(('fault_code', t.string()),
                                     ('external_identifier', t.string()))
    other_attributes = t.other(('severity',
                                t.enum(SEV_CLEARED, SEV_CRITICAL, SEV_INFO,
                                       SEV_WARNING, SEV_MAJOR, SEV_MINOR)),
                               ('status_id', t.id), ('cause', t.string()),
                               ('description', t.string(255)))

    db_attributes = t.db(('last_update_timestamp', t.string()))

    def __eq__(self, other):
        try:
            return self.identity == other.identity
        except AttributeError:
            return False

    # An object is hashable if it has a hash value which never changes during
    # its lifetime (it needs a __hash__() method), and can be compared to
    # other objects (it needs an __eq__() or __cmp__() method).
    # Hashable objects which compare equal must have the same hash value.
    #
    # If you define __eq__() , the default __hash__() (namely, hashing the
    # address of the object in memory) goes away.
    # So for each class defining __eq__() we must also
    # define __hash__() even though parent class has __hash__().
    def __hash__(self):
        return super(AciFault, self).__hash__()

    def __init__(self, **kwargs):
        super(AciFault, self).__init__(
            {
                'severity': self.SEV_INFO,
                'lifecycle_status': self.LC_UNKNOWN,
                'cause': '',
                'description': ""
            }, **kwargs)

    def is_error(self):
        return self.severity in [self.SEV_MAJOR, self.SEV_CRITICAL]

    @property
    def dn(self):
        return self.external_identifier

    @property
    def root(self):
        mos_and_types = utils.decompose_dn(self._aci_mo_name, self.dn)
        if mos_and_types:
            # Faults associated with unrecognized MOs will not decompose
            mo = apic_client.ManagedObjectClass(mos_and_types[0][0])
            return (mo.rn(mos_and_types[0][1])
                    if mo.rn_param_count else mo.rn())