class TestResourceAgent(IonTestCase): @defer.inlineCallbacks def setUp(self): yield self._start_container() # use some sort of agent...doesnt really matter what kind, does it processes = [{ 'name': 'testAgent', 'module': 'ion.agents.instrumentagents.SBE49_IA', 'class': 'SBE49InstrumentAgent' }, { 'name': 'agent_registry', 'module': 'ion.services.coi.agent_registry', 'class': 'AgentRegistryService' }] self.sup = yield self._spawn_processes(processes) self.svc_id = self.sup.get_child_id('testAgent') self.rr_id = self.sup.get_child_id('agent_registry') # Start a client (for the RPC) self.RAClient = ResourceAgentClient(proc=self.sup, target=self.svc_id) # RR Client is ,,,,,desired only for testing self.reg_client = AgentRegistryClient(proc=self.sup) yield self.reg_client.clear_registry() # need any non-generic resource...use an instrument agent one for now self.res_desc = \ InstrumentAgentResourceDescription.create_new_resource() #self.res_desc.version = '1.23' self.res_desc.name = 'I am a test IA resource description' self.res_inst = InstrumentAgentResourceInstance.create_new_resource() self.res_inst.driver_process_id = 'something_for_now.1' self.res_inst.name = 'I am an instantiation of a test IA resource' @defer.inlineCallbacks def tearDown(self): yield self._stop_container() @defer.inlineCallbacks def test_reg_direct(self): registered_agent_desc = \ yield self.reg_client.register_agent_definition(self.res_desc) # Not committed, so not equal, but parts should be self.assertNotEqual(registered_agent_desc, self.res_desc) self.assertEqual(registered_agent_desc.RegistryIdentity, self.res_desc.RegistryIdentity) registered_agent_instance = \ yield self.reg_client.register_agent_instance(self.res_inst) # Not committed, so not equal, but parts should be self.assertNotEqual(registered_agent_instance, self.res_inst) self.assertEqual(registered_agent_instance.RegistryIdentity, self.res_inst.RegistryIdentity) recv_agent_desc = \ yield self.reg_client.get_agent_definition(self.res_desc) self.assertEqual(recv_agent_desc, registered_agent_desc) self.assertEqual(recv_agent_desc.RegistryIdentity, self.res_desc.RegistryIdentity) # Not committed, so not equal self.assertNotEqual(recv_agent_desc, self.res_desc) recv_agent_inst = \ yield self.reg_client.get_agent_instance(self.res_inst) self.assertEqual(recv_agent_inst, registered_agent_instance) # Not commiteed, so not equal, but parts should be self.assertNotEqual(recv_agent_inst, self.res_inst) self.assertEqual(recv_agent_inst.RegistryIdentity, self.res_inst.RegistryIdentity) @defer.inlineCallbacks def test_registration_with_definitions(self): reg_id = yield self.RAClient.register_resource(self.res_inst) orig_result = yield self.RAClient.get_resource_instance() self.assertNotEqual(orig_result, None) self.assertNotEqual(orig_result, self.res_inst) self.assertNotEqual(orig_result.RegistryCommit, self.res_inst.RegistryCommit) self.assertEqual(reg_id.RegistryCommit, '') self.assertNotEqual(orig_result.RegistryCommit, reg_id.RegistryCommit) self.assertEqual(reg_id.RegistryIdentity, orig_result.RegistryIdentity) # Verify the reference is the same result = yield self.RAClient.get_resource_ref() self.assertEqual(result, reg_id) # test update/repeat reg if a different instance new_res_inst = yield self.RAClient.get_resource_instance() new_res_inst.name = "REPLACED TestAgentInstance" new_res_inst.driver_process_id = 'something_else.1' # Even pulling it, modifiying it, then re-registering makes a new one new_result = yield self.RAClient.get_resource_instance() new_result.name = "UPDATED TestAgentInstance" new_result.driver_process_id = 'something_else.2' new_reg_ref = yield self.RAClient.register_resource(new_res_inst) self.assertNotEqual(reg_id, new_reg_ref) new_result2 = yield self.RAClient.get_resource_instance() self.assertNotEqual(new_result2.RegistryIdentity, orig_result.RegistryIdentity) self.assertNotEqual(new_result2.RegistryCommit, orig_result.RegistryCommit) self.assertNotEqual(new_result2.name, orig_result.name) self.assertEqual(new_result2.name, new_res_inst.name) self.assertEqual(new_result2.driver_process_id, new_res_inst.driver_process_id) self.assertNotEqual(new_result2.name, new_result.name) @defer.inlineCallbacks def test_agent_self_registration(self): reg_id = yield self.RAClient.register_resource() result = yield self.RAClient.get_resource_instance() self.assertNotEqual(result, None) self.assertEqual(reg_id.RegistryCommit, '') self.assertNotEqual(result.RegistryCommit, reg_id.RegistryCommit) self.assertEqual(reg_id.RegistryIdentity, result.RegistryIdentity) # Verify the reference is the same result = yield self.RAClient.get_resource_ref() self.assertEqual(result, reg_id) # Make A new agent to verify we have 2 processes = [{ 'name': 'testAgent2', 'module': 'ion.agents.instrumentagents.SBE49_IA', 'class': 'SBE49InstrumentAgent' }] sup2 = yield self._spawn_processes(processes) svc_id2 = self.sup.get_child_id('testAgent2') # Start a client (for the RPC) RAClient2 = ResourceAgentClient(proc=sup2, target=svc_id2) # test update/repeat reg if a different instance yield RAClient2.register_resource() refinst2 = yield RAClient2.get_resource_instance() refinst1 = yield self.RAClient.get_resource_ref() self.assertNotEqual(refinst1.RegistryCommit, refinst2.RegistryCommit) self.assertNotEqual(refinst1.RegistryIdentity, refinst2.RegistryIdentity) self.assertEqual(refinst1.RegistryCommit, result.RegistryCommit) self.assertEqual(refinst1.RegistryIdentity, result.RegistryIdentity) @defer.inlineCallbacks def test_lifecycle(self): registered_res = yield self.RAClient.register_resource(self.res_inst) self.assertNotEqual(registered_res, None) result = yield self.RAClient.get_resource_ref() self.assertEqual(result, registered_res) active_state = LCState('active') inactive_state = LCState('inactive') result = yield self.RAClient.set_lifecycle_state(active_state) self.assertEqual(result, active_state) result = yield self.RAClient.get_lifecycle_state() self.assertEqual(result, active_state) result = yield self.RAClient.set_lifecycle_state(inactive_state) ref = yield self.RAClient.get_resource_ref() self.assertNotEqual(ref, None) self.assertEqual(ref, registered_res) result = yield self.RAClient.get_lifecycle_state() self.assertEqual(result, inactive_state)
class ResourceAgent(BaseProcess): """ Base class for resource agent processes If you are going to write a new agent process, subclass this one and setup a ResourceRegistryClient """ def plc_init(self): """ The Agent Registry client class to hang onto for all registry manipulations """ self.reg_client = AgentRegistryClient(proc=self) """ Our reference object in the Agent Registry """ self.resource_ref = None """ This is what makes us unique for now. When we register, this is our handle """ self.name = None @defer.inlineCallbacks def op_get_lifecycle_state(self, content, headers, msg): """ Get the lifecycle state for the resource @retval LCState string @todo handle errors better """ if (self.resource_ref != None): result = \ yield self.reg_client.get_agent_instance(self.resource_ref) assert(isinstance(result, AgentInstance)) state = result.get_lifecyclestate() yield self.reply_ok(msg, str(state)) else: yield self.reply_err(msg, "Resource not registered!") @defer.inlineCallbacks def op_set_lifecycle_state(self, content, headers, msg): """ Set the lifecycle state for the resource @param content Should be a list with a resource id and a string that can be turned into an LCState object """ assert(isinstance(content, basestring)) state = str(content) assert(state in LCStateNames) state = LCState(state) if (self.resource_ref != None): result = yield self.reg_client.set_agent_lcstate(self.resource_ref, state) self.resource_ref = result.reference(head=True) if (result): yield self.reply_ok(msg, str(state)) return else: yield self.reply_err(msg, \ "Could not set lifecycle state for %s" \ % self.resource_ref.name) return else: yield self.reply_err(msg, \ "Could not set lifecycle state. Resource %s does not exist." \ % self.resource_ref.name) @defer.inlineCallbacks def op_register_resource(self, content, headers, msg): """ Registers or re-registers self in the agent registry. @param content Must include an encoded AgentInstance subclass that may or may not have been previously filled out. The instance class should be appropriate to the type of resource being registered. Perhaps the client is checking the type? @todo Turn initial parameter asserts into a decode check @note Registering an existing InstrumentAgent with an existing registry @msc hscale = "2"; User, InstrumentAgentClient, InstrumentAgentResourceInstance, InstrumentAgent, ResourceAgent, ResourceAgentClient, AgentRegistryClient, AgentRegistry; User -> InstrumentAgent [label="instantiate and spawn IA subclass"]; User -> InstrumentAgentClient[label="instantiate IAClient subclass"]; AgentRegistryClient -> InstrumentAgent [label="reference stored in IA"]; --- [label="All setup now, registry must already have a client on hand"]; User => InstrumentAgentClient [label="register_resource()"]; InstrumentAgentClient -> InstrumentAgentResourceInstance [label="instantiate"]; InstrumentAgentClient -> InstrumentAgentResourceInstance [label="get driver address"]; InstrumentAgentClient <- InstrumentAgentResourceInstance [label="driver address"]; InstrumentAgentClient => InstrumentAgentClient [label="ResourceAgentClient.register_resource()"]; InstrumentAgentClient =>> InstrumentAgent [label="op_register_resource() via AMQP"]; InstrumentAgent => AgentRegistryClient [label="register_agent_instance(self, custom_descriptor)"]; AgentRegistryClient => AgentRegistryClient [label="describe_instance(agent_instance, custom_descriptor)"]; AgentRegistryClient << AgentRegistryClient [label="return AgentDescription"]; AgentRegistryClient => AgentRegistryClient [label="find_registered_agent_instance_from_description(above)"]; AgentRegistryClient =>> AgentRegistry [label="register_resource() via base class AMQP"]; AgentRegistryClient <<= AgentRegistry [label="return via AMQP"]; InstrumentAgent << AgentRegistryClient [label="Success/failure"]; InstrumentAgentClient <<= ResourceAgent [label="Success/failure via InstrumentAgent via AMQP"]; User << InstrumentAgentClient [label="return"]; @endmsc """ if (content == ""): descriptor = None elif (content != None): descriptor = AgentInstance.decode(content) assert((descriptor == None) or (isinstance(descriptor, AgentInstance))) assert(descriptor != "") # Register the instance/description returned_instance = \ yield self.reg_client.register_agent_instance(self, descriptor) self.resource_ref = returned_instance.reference(head=True) if (self.resource_ref == None) or (self.resource_ref == False): yield self.reply_err(msg, "Could not register instance!") else: yield self.reply_ok(msg, self.resource_ref.encode()) @defer.inlineCallbacks def op_get_resource_instance(self, content, headers, msg): """ Get the resource instance for this resource from the agent registry @retval Via messageg, send the resource instance object for this resource, as registered in the agent registry """ if (self.resource_ref != None): result = \ yield self.reg_client.get_agent_instance(self.resource_ref) assert(isinstance(result, AgentInstance)) yield self.reply_ok(msg, result.encode()) else: yield self.reply_err(msg, None) @defer.inlineCallbacks def op_get_resource_ref(self, content, headers, msg): """ Returns the resource id for the resource agent @todo handle case where it isnt registered yet @retval An encoded resource reference if the resource has been registered, None if not registered """ if (self.resource_ref != None): yield self.reply_ok(msg, self.resource_ref.encode()) else: yield self.reply_err(msg, None) def op_get(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_set(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_execute(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_get_status(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_get_capabilities(self, content, headers, msg): """
class ResourceAgent(BaseProcess): """ Base class for resource agent processes If you are going to write a new agent process, subclass this one and setup a ResourceRegistryClient """ def plc_init(self): """ The Agent Registry client class to hang onto for all registry manipulations """ self.reg_client = AgentRegistryClient(proc=self) """ Our reference object in the Agent Registry """ self.resource_ref = None """ This is what makes us unique for now. When we register, this is our handle """ self.name = None @defer.inlineCallbacks def op_get_lifecycle_state(self, content, headers, msg): """ Get the lifecycle state for the resource @retval LCState string @todo handle errors better """ if (self.resource_ref != None): result = \ yield self.reg_client.get_agent_instance(self.resource_ref) assert (isinstance(result, AgentInstance)) state = result.get_lifecyclestate() yield self.reply_ok(msg, str(state)) else: yield self.reply_err(msg, "Resource not registered!") @defer.inlineCallbacks def op_set_lifecycle_state(self, content, headers, msg): """ Set the lifecycle state for the resource @param content Should be a list with a resource id and a string that can be turned into an LCState object """ assert (isinstance(content, basestring)) state = str(content) assert (state in LCStateNames) state = LCState(state) if (self.resource_ref != None): result = yield self.reg_client.set_agent_lcstate( self.resource_ref, state) self.resource_ref = result.reference(head=True) if (result): yield self.reply_ok(msg, str(state)) return else: yield self.reply_err(msg, \ "Could not set lifecycle state for %s" \ % self.resource_ref.name) return else: yield self.reply_err(msg, \ "Could not set lifecycle state. Resource %s does not exist." \ % self.resource_ref.name) @defer.inlineCallbacks def op_register_resource(self, content, headers, msg): """ Registers or re-registers self in the agent registry. @param content Must include an encoded AgentInstance subclass that may or may not have been previously filled out. The instance class should be appropriate to the type of resource being registered. Perhaps the client is checking the type? @todo Turn initial parameter asserts into a decode check @note Registering an existing InstrumentAgent with an existing registry @msc hscale = "2"; User, InstrumentAgentClient, InstrumentAgentResourceInstance, InstrumentAgent, ResourceAgent, ResourceAgentClient, AgentRegistryClient, AgentRegistry; User -> InstrumentAgent [label="instantiate and spawn IA subclass"]; User -> InstrumentAgentClient[label="instantiate IAClient subclass"]; AgentRegistryClient -> InstrumentAgent [label="reference stored in IA"]; --- [label="All setup now, registry must already have a client on hand"]; User => InstrumentAgentClient [label="register_resource()"]; InstrumentAgentClient -> InstrumentAgentResourceInstance [label="instantiate"]; InstrumentAgentClient -> InstrumentAgentResourceInstance [label="get driver address"]; InstrumentAgentClient <- InstrumentAgentResourceInstance [label="driver address"]; InstrumentAgentClient => InstrumentAgentClient [label="ResourceAgentClient.register_resource()"]; InstrumentAgentClient =>> InstrumentAgent [label="op_register_resource() via AMQP"]; InstrumentAgent => AgentRegistryClient [label="register_agent_instance(self, custom_descriptor)"]; AgentRegistryClient => AgentRegistryClient [label="describe_instance(agent_instance, custom_descriptor)"]; AgentRegistryClient << AgentRegistryClient [label="return AgentDescription"]; AgentRegistryClient => AgentRegistryClient [label="find_registered_agent_instance_from_description(above)"]; AgentRegistryClient =>> AgentRegistry [label="register_resource() via base class AMQP"]; AgentRegistryClient <<= AgentRegistry [label="return via AMQP"]; InstrumentAgent << AgentRegistryClient [label="Success/failure"]; InstrumentAgentClient <<= ResourceAgent [label="Success/failure via InstrumentAgent via AMQP"]; User << InstrumentAgentClient [label="return"]; @endmsc """ if (content == ""): descriptor = None elif (content != None): descriptor = AgentInstance.decode(content) assert ((descriptor == None) or (isinstance(descriptor, AgentInstance))) assert (descriptor != "") # Register the instance/description returned_instance = \ yield self.reg_client.register_agent_instance(self, descriptor) self.resource_ref = returned_instance.reference(head=True) if (self.resource_ref == None) or (self.resource_ref == False): yield self.reply_err(msg, "Could not register instance!") else: yield self.reply_ok(msg, self.resource_ref.encode()) @defer.inlineCallbacks def op_get_resource_instance(self, content, headers, msg): """ Get the resource instance for this resource from the agent registry @retval Via messageg, send the resource instance object for this resource, as registered in the agent registry """ if (self.resource_ref != None): result = \ yield self.reg_client.get_agent_instance(self.resource_ref) assert (isinstance(result, AgentInstance)) yield self.reply_ok(msg, result.encode()) else: yield self.reply_err(msg, None) @defer.inlineCallbacks def op_get_resource_ref(self, content, headers, msg): """ Returns the resource id for the resource agent @todo handle case where it isnt registered yet @retval An encoded resource reference if the resource has been registered, None if not registered """ if (self.resource_ref != None): yield self.reply_ok(msg, self.resource_ref.encode()) else: yield self.reply_err(msg, None) def op_get(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_set(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_execute(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_get_status(self, content, headers, msg): """ Abstract method for the Resource Agent interface """ def op_get_capabilities(self, content, headers, msg): """
class TestResourceAgent(IonTestCase): @defer.inlineCallbacks def setUp(self): yield self._start_container() # use some sort of agent...doesnt really matter what kind, does it processes = [ {'name':'testAgent', 'module':'ion.agents.instrumentagents.SBE49_IA', 'class':'SBE49InstrumentAgent'}, {'name':'agent_registry', 'module':'ion.services.coi.agent_registry', 'class':'AgentRegistryService'} ] self.sup = yield self._spawn_processes(processes) self.svc_id = self.sup.get_child_id('testAgent') self.rr_id = self.sup.get_child_id('agent_registry') # Start a client (for the RPC) self.RAClient = ResourceAgentClient(proc=self.sup, target=self.svc_id) # RR Client is ,,,,,desired only for testing self.reg_client = AgentRegistryClient(proc=self.sup) yield self.reg_client.clear_registry() # need any non-generic resource...use an instrument agent one for now self.res_desc = \ InstrumentAgentResourceDescription.create_new_resource() #self.res_desc.version = '1.23' self.res_desc.name = 'I am a test IA resource description' self.res_inst = InstrumentAgentResourceInstance.create_new_resource() self.res_inst.driver_process_id = 'something_for_now.1' self.res_inst.name = 'I am an instantiation of a test IA resource' @defer.inlineCallbacks def tearDown(self): yield self._stop_container() @defer.inlineCallbacks def test_reg_direct(self): registered_agent_desc = \ yield self.reg_client.register_agent_definition(self.res_desc) # Not committed, so not equal, but parts should be self.assertNotEqual(registered_agent_desc, self.res_desc) self.assertEqual(registered_agent_desc.RegistryIdentity, self.res_desc.RegistryIdentity) registered_agent_instance = \ yield self.reg_client.register_agent_instance(self.res_inst) # Not committed, so not equal, but parts should be self.assertNotEqual(registered_agent_instance, self.res_inst) self.assertEqual(registered_agent_instance.RegistryIdentity, self.res_inst.RegistryIdentity) recv_agent_desc = \ yield self.reg_client.get_agent_definition(self.res_desc) self.assertEqual(recv_agent_desc, registered_agent_desc) self.assertEqual(recv_agent_desc.RegistryIdentity, self.res_desc.RegistryIdentity) # Not committed, so not equal self.assertNotEqual(recv_agent_desc, self.res_desc) recv_agent_inst = \ yield self.reg_client.get_agent_instance(self.res_inst) self.assertEqual(recv_agent_inst, registered_agent_instance) # Not commiteed, so not equal, but parts should be self.assertNotEqual(recv_agent_inst, self.res_inst) self.assertEqual(recv_agent_inst.RegistryIdentity, self.res_inst.RegistryIdentity) @defer.inlineCallbacks def test_registration_with_definitions(self): reg_id = yield self.RAClient.register_resource(self.res_inst) orig_result = yield self.RAClient.get_resource_instance() self.assertNotEqual(orig_result, None) self.assertNotEqual(orig_result, self.res_inst) self.assertNotEqual(orig_result.RegistryCommit, self.res_inst.RegistryCommit) self.assertEqual(reg_id.RegistryCommit, '') self.assertNotEqual(orig_result.RegistryCommit, reg_id.RegistryCommit) self.assertEqual(reg_id.RegistryIdentity, orig_result.RegistryIdentity) # Verify the reference is the same result = yield self.RAClient.get_resource_ref() self.assertEqual(result, reg_id) # test update/repeat reg if a different instance new_res_inst = yield self.RAClient.get_resource_instance() new_res_inst.name = "REPLACED TestAgentInstance" new_res_inst.driver_process_id = 'something_else.1' # Even pulling it, modifiying it, then re-registering makes a new one new_result = yield self.RAClient.get_resource_instance() new_result.name = "UPDATED TestAgentInstance" new_result.driver_process_id = 'something_else.2' new_reg_ref = yield self.RAClient.register_resource(new_res_inst) self.assertNotEqual(reg_id, new_reg_ref) new_result2 = yield self.RAClient.get_resource_instance() self.assertNotEqual(new_result2.RegistryIdentity, orig_result.RegistryIdentity) self.assertNotEqual(new_result2.RegistryCommit, orig_result.RegistryCommit) self.assertNotEqual(new_result2.name, orig_result.name) self.assertEqual(new_result2.name, new_res_inst.name) self.assertEqual(new_result2.driver_process_id, new_res_inst.driver_process_id) self.assertNotEqual(new_result2.name, new_result.name) @defer.inlineCallbacks def test_agent_self_registration(self): reg_id = yield self.RAClient.register_resource() result = yield self.RAClient.get_resource_instance() self.assertNotEqual(result, None) self.assertEqual(reg_id.RegistryCommit, '') self.assertNotEqual(result.RegistryCommit, reg_id.RegistryCommit) self.assertEqual(reg_id.RegistryIdentity, result.RegistryIdentity) # Verify the reference is the same result = yield self.RAClient.get_resource_ref() self.assertEqual(result, reg_id) # Make A new agent to verify we have 2 processes = [{'name':'testAgent2', 'module':'ion.agents.instrumentagents.SBE49_IA', 'class':'SBE49InstrumentAgent'}] sup2 = yield self._spawn_processes(processes) svc_id2 = self.sup.get_child_id('testAgent2') # Start a client (for the RPC) RAClient2 = ResourceAgentClient(proc=sup2, target=svc_id2) # test update/repeat reg if a different instance yield RAClient2.register_resource() refinst2 = yield RAClient2.get_resource_instance() refinst1 = yield self.RAClient.get_resource_ref() self.assertNotEqual(refinst1.RegistryCommit, refinst2.RegistryCommit) self.assertNotEqual(refinst1.RegistryIdentity, refinst2.RegistryIdentity) self.assertEqual(refinst1.RegistryCommit, result.RegistryCommit) self.assertEqual(refinst1.RegistryIdentity, result.RegistryIdentity) @defer.inlineCallbacks def test_lifecycle(self): registered_res = yield self.RAClient.register_resource(self.res_inst) self.assertNotEqual(registered_res, None) result = yield self.RAClient.get_resource_ref() self.assertEqual(result, registered_res) active_state = LCState('active') inactive_state = LCState('inactive') result = yield self.RAClient.set_lifecycle_state(active_state) self.assertEqual(result, active_state) result = yield self.RAClient.get_lifecycle_state() self.assertEqual(result, active_state) result = yield self.RAClient.set_lifecycle_state(inactive_state) ref = yield self.RAClient.get_resource_ref() self.assertNotEqual(ref, None) self.assertEqual(ref, registered_res) result = yield self.RAClient.get_lifecycle_state() self.assertEqual(result, inactive_state)