Exemplo n.º 1
0
    def receive(self, request, unused_link_id, unused_cost):
        """Called when a management request is received."""
        def error(e, trace):
            """Raise an error"""
            self.log(
                LOG_ERROR, "Error performing %s: %s" %
                (request.properties.get('operation'), e.description))
            self.respond(request, e.status, e.description)

        # If there's no reply_to, don't bother to process the request.
        if not request.reply_to:
            return

        # Coarse locking, handle one request at a time.
        with self.request_lock:
            try:
                self.entities.refresh_from_c()
                self.log(LOG_DEBUG, "Agent request %s" % request)
                status, body = self.handle(request)
                self.respond(request, status=status, body=body)
            except ManagementError as e:
                error(e, format_exc())
            except ValidationError as e:
                error(BadRequestStatus(str(e)), format_exc())
            except Exception as e:
                error(
                    InternalServerErrorStatus("%s: %s" %
                                              (type(e).__name__, e)),
                    format_exc())
Exemplo n.º 2
0
 def entity_class(self, entity_type):
     """Return the class that implements entity_type"""
     class_name = camelcase(entity_type.short_name, capital=True) + 'Entity'
     entity_class = globals().get(class_name)
     if not entity_class:
         raise InternalServerErrorStatus(
             "Can't find implementation '%s' for '%s'" % (class_name, entity_type.name))
     return entity_class
Exemplo n.º 3
0
    def find_entity(self, request):
        """Find the entity addressed by request"""

        requested_type = request.properties.get('type')
        if requested_type:
            requested_type = self.schema.entity_type(requested_type)
        # ids is a map of identifying attribute values
        ids = dict((k, request.properties.get(k))
                   for k in ['name', 'identity'] if k in request.properties)

        # Special case for management object: if no name/id and no conflicting type
        # then assume this is for "self"
        if not ids:
            if not requested_type or self.management.entity_type.is_a(
                    requested_type):
                return self.management
            else:
                raise BadRequestStatus("%s: No name or identity provided" %
                                       requested_type)

        def attrvals():
            """String form of the id attribute values for error messages"""
            return " ".join(["%s=%r" % (k, v) for k, v in ids.iteritems()])

        k, v = ids.iteritems().next()  # Get the first id attribute
        found = self.entities.map_filter(None,
                                         lambda e: e.attributes.get(k) == v)
        if len(found) == 1:
            entity = found[0]
        elif len(found) > 1:
            raise InternalServerErrorStatus(
                "Duplicate (%s) entities with %s=%r" % (len(found), k, v))
        else:
            raise NotFoundStatus("No entity with %s" % attrvals())

        for k, v in ids.iteritems():
            if entity[k] != v:
                raise BadRequestStatus("Conflicting %s" % attrvals())

        if requested_type:
            if not entity.entity_type.is_a(requested_type):
                raise BadRequestStatus(
                    "Entity type '%s' does not extend requested type '%s'" %
                    (entity.entity_type.name, requested_type))

        return entity
Exemplo n.º 4
0
class Agent(object):
    """AMQP managment agent. Manages entities, directs requests to the correct entity."""

    def __init__(self, dispatch, qd):
        self.qd = qd
        self.dispatch = dispatch
        self.schema = QdSchema()
        self.entities = EntityCache(self)
        self.request_lock = Lock()
        self.log_adapter = LogAdapter("AGENT")
        self.policy = PolicyManager(self)
        self.management = self.create_entity({"type": "management"})
        self.add_entity(self.management)

    def log(self, level, text):
        info = traceback.extract_stack(limit=2)[0] # Caller frame info
        self.log_adapter.log(level, text, info[0], info[1])

    def activate(self, address):
        """Register the management address to receive management requests"""
        self.entities.refresh_from_c()
        self.log(LOG_INFO, "Activating management agent on %s" % address)
        self.io = IoAdapter(self.receive, address, 'L', '0', TREATMENT_ANYCAST_CLOSEST)

    def entity_class(self, entity_type):
        """Return the class that implements entity_type"""
        class_name = camelcase(entity_type.short_name, capital=True) + 'Entity'
        entity_class = globals().get(class_name)
        if not entity_class:
            raise InternalServerErrorStatus(
                "Can't find implementation '%s' for '%s'" % (class_name, entity_type.name))
        return entity_class

    def create_entity(self, attributes):
        """Create an instance of the implementation class for an entity"""

        if attributes.get('identity') is not None:
            raise BadRequestStatus("'identity' attribute cannot be specified %s" % attributes)
        if attributes.get('type') is None:
            raise BadRequestStatus("No 'type' attribute in %s" % attributes)
        entity_type = self.schema.entity_type(attributes['type'])
        return self.entity_class(entity_type)(self, entity_type, attributes)

    def respond(self, request, status=OK, description=None, body=None):
        """Send a response to the client"""
        if body is None: body = {}
        description = description or STATUS_TEXT[status]
        response = Message(
            address=request.reply_to,
            correlation_id=request.correlation_id,
            properties={'statusCode': status, 'statusDescription': description},
            body=body)
        self.log(LOG_DEBUG, "Agent response:\n  %s\n  Responding to: \n  %s"%(response, request))
        try:
            self.io.send(response)
        except:
            self.log(LOG_ERROR, "Can't respond to %s: %s"%(request, format_exc()))

    def receive(self, request, unused_link_id, unused_cost):
        """Called when a management request is received."""
        def error(e, trace):
            """Raise an error"""
            self.log(LOG_ERROR, "Error performing %s: %s"%(request.properties.get('operation'), e.message))
            self.respond(request, e.status, e.description)

        # If there's no reply_to, don't bother to process the request.
        if not request.reply_to:
            return

        # Coarse locking, handle one request at a time.
        with self.request_lock:
            try:
                self.entities.refresh_from_c()
                self.log(LOG_DEBUG, "Agent request %s"% request)
                status, body = self.handle(request)
                self.respond(request, status=status, body=body)
            except ManagementError, e:
                error(e, format_exc())
            except ValidationError, e:
                error(BadRequestStatus(str(e)), format_exc())
            except Exception, e:
                error(InternalServerErrorStatus("%s: %s"%(type(e).__name__, e)), format_exc())