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())
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 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
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())