class GovernanceTest(PyonTestCase): governance_controller = None def setUp(self): self.governance_controller = GovernanceController(FakeContainer()) def test_initialize_from_config(self): intlist = {'conversation', 'information', 'policy'} config = {'interceptor_order':intlist, 'governance_interceptors': {'conversation': {'class': 'pyon.core.governance.conversation.conversation_monitor_interceptor.ConversationMonitorInterceptor' }, 'information': {'class': 'pyon.core.governance.information.information_model_interceptor.InformationModelInterceptor' }, 'policy': {'class': 'pyon.core.governance.policy.policy_interceptor.PolicyInterceptor' } }} self.governance_controller.initialize_from_config(config) self.assertEquals(self.governance_controller.interceptor_order,intlist) self.assertEquals(len(self.governance_controller.interceptor_by_name_dict),len(config['governance_interceptors'])) # TODO - Need to fill this method out def test_process_message(self): pass
def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False self._capabilities = [] # set container id and cc_agent name (as they are set in base class call) self.id = get_default_container_id() self.name = "cc_agent_%s" % self.id Container.instance = self from pyon.core import bootstrap bootstrap.container_instance = self log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # Instantiate Directory and self-register # Has the additional side effect of either # bootstrapping the configuration into the # directory or read the configuration based # in the value of the auto_bootstrap setting self.directory = Directory() # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController(self) # sFlow manager - controls sFlow stat emission self.sflow_manager = SFlowManager(self) # Coordinates the container start self._status = "INIT" # protection for when the container itself is used as a Process for clients self.container = self log.debug("Container initialized, OK.")
def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False # set id and name (as they are set in base class call) self.id = string.replace('%s_%d' % (os.uname()[1], os.getpid()), ".", "_") self.name = "cc_agent_%s" % self.id Container.instance = self # TODO: Bug: Replacing CFG instance not work because references are already public. Update directly dict_merge(CFG, kwargs, inplace=True) from pyon.core import bootstrap bootstrap.container_instance = self bootstrap.assert_configuration(CFG) log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # Load object and service registry etc. bootstrap_pyon() # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController(self) # sFlow manager - controls sFlow stat emission self.sflow_manager = SFlowManager(self) # Coordinates the container start self._is_started = False self._capabilities = [] self._status = "INIT" # protection for when the container itself is used as a Process for clients self.container = self log.debug("Container initialized, OK.")
def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False # set container id and cc_agent name (as they are set in base class call) self.id = get_default_container_id() self.name = "cc_agent_%s" % self.id self._capabilities = [] from pyon.core import bootstrap bootstrap.container_instance = self Container.instance = self log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() # TODO: Do not start a capability here. Symmetric start/stop self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Instantiate Directory self.directory = Directory() # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController(self) # sFlow manager - controls sFlow stat emission self.sflow_manager = SFlowManager(self) # Coordinates the container start self._status = "INIT" # protection for when the container itself is used as a Process for clients self.container = self log.debug("Container initialized, OK.")
def setUp(self): FakeContainer = Mock() FakeContainer.id = "containerid" FakeContainer.node = Mock() self.governance_controller = GovernanceController(FakeContainer()) self.pre_func1 =\ """def precondition_func(process, msg, headers): if headers['op'] != 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ self.pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not have the proper signature self.bad_pre_func1 =\ """def precondition_func(msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not return the proper tuple self.bad_pre_func2 =\ """def precondition_func(process, msg, headers):
class Container(BaseContainerAgent): """ The Capability Container. Its purpose is to spawn/monitor processes and services that do the bulk of the work in the ION system. It also manages connections to the Exchange and the various forms of datastores in the systems. """ # Singleton static variables #node = None id = None name = None pidfile = None instance = None def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False self._capabilities = [] # set container id and cc_agent name (as they are set in base class call) self.id = get_default_container_id() self.name = "cc_agent_%s" % self.id Container.instance = self from pyon.core import bootstrap bootstrap.container_instance = self log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # Instantiate Directory and self-register # Has the additional side effect of either # bootstrapping the configuration into the # directory or read the configuration based # in the value of the auto_bootstrap setting self.directory = Directory() # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController(self) # sFlow manager - controls sFlow stat emission self.sflow_manager = SFlowManager(self) # Coordinates the container start self._status = "INIT" # protection for when the container itself is used as a Process for clients self.container = self log.debug("Container initialized, OK.") def start(self): log.debug("Container starting...") if self._is_started: raise ContainerError("Container already started") # Check if this UNIX process already runs a Container. self.pidfile = "cc-pid-%d" % os.getpid() if os.path.exists(self.pidfile): raise ContainerError("Container.on_start(): Container is a singleton per UNIX process. Existing pid file found: %s" % self.pidfile) # write out a PID file containing our agent messaging name with open(self.pidfile, 'w') as f: pid_contents = {'messaging': dict(CFG.server.amqp), 'container-agent': self.name, 'container-xp': bootstrap.get_sys_name() } f.write(msgpack.dumps(pid_contents)) atexit.register(self._cleanup_pid) self._capabilities.append("PID_FILE") # set up abnormal termination handler for this container def handl(signum, frame): try: self._cleanup_pid() # cleanup the pidfile first self.quit() # now try to quit - will not error on second cleanup pidfile call finally: signal.signal(signal.SIGTERM, self._normal_signal) os.kill(os.getpid(), signal.SIGTERM) self._normal_signal = signal.signal(signal.SIGTERM, handl) self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Self-register with Directory self.directory.register("/Containers", self.id, cc_agent=self.name) self.directory.register("/Containers/%s" % self.id, "Processes") self._capabilities.append("DIRECTORY") # Event repository self.event_repository = EventRepository() self.event_pub = EventPublisher() self._capabilities.append("EVENT_REPOSITORY") # Local resource registry self.resource_registry = ResourceRegistry() self._capabilities.append("RESOURCE_REGISTRY") # Persistent objects self.datastore_manager.get_datastore("objects", DataStore.DS_PROFILE.OBJECTS) # State repository self.state_repository = StateRepository() self._capabilities.append("STATE_REPOSITORY") # Start ExchangeManager, which starts the node (broker connection) self.ex_manager.start() self._capabilities.append("EXCHANGE_MANAGER") self.proc_manager.start() self._capabilities.append("PROC_MANAGER") self.app_manager.start() self._capabilities.append("APP_MANAGER") self.governance_controller.start() self._capabilities.append("GOVERNANCE_CONTROLLER") if CFG.container.get('sflow', {}).get('enabled', False): self.sflow_manager.start() self._capabilities.append("SFLOW_MANAGER") # Start the CC-Agent API rsvc = ProcessRPCServer(node=self.node, from_name=self.name, service=self, process=self) # Start an ION process with the right kind of endpoint factory proc = self.proc_manager.proc_sup.spawn(name=self.name, listeners=[rsvc], service=self) self.proc_manager.proc_sup.ensure_ready(proc) self._capabilities.append("CONTAINER_AGENT") self.event_pub.publish_event(event_type="ContainerLifecycleEvent", origin=self.id, origin_type="CapabilityContainer", sub_type="START", state=ContainerStateEnum.START) self._is_started = True self._status = "RUNNING" log.info("Container started, OK.") @property def node(self): """ Returns the active/default Node that should be used for most communication in the system. Defers to exchange manager, but only if it has been started, otherwise returns None. """ if "EXCHANGE_MANAGER" in self._capabilities: return self.ex_manager.default_node return None @contextmanager def _push_status(self, new_status): """ Temporarily sets the internal status flag. Use this as a decorator or in a with-statement before calling a temporary status changing method, like start_rel_from_url. """ curstatus = self._status self._status = new_status try: yield finally: self._status = curstatus def serve_forever(self): """ Run the container until killed. """ log.debug("In Container.serve_forever") if not self.proc_manager.proc_sup.running: self.start() # serve forever short-circuits if immediate is on and children len is ok num_procs = len(self.proc_manager.proc_sup.children) immediate = CFG.system.get('immediate', False) if not (immediate and num_procs == 1): # only spawned greenlet is the CC-Agent # print a warning just in case if immediate and num_procs != 1: log.warn("CFG.system.immediate=True but number of spawned processes is not 1 (%d)", num_procs) try: # This just waits in this Greenlet for all child processes to complete, # which is triggered somewhere else. self.proc_manager.proc_sup.join_children() except (KeyboardInterrupt, SystemExit) as ex: log.info('Received a kill signal, shutting down the container.') watch_parent = CFG.system.get('watch_parent', None) if watch_parent: watch_parent.kill() except: log.exception('Unhandled error! Forcing container shutdown') else: log.debug("Container.serve_forever short-circuiting due to CFG.system.immediate") self.proc_manager.proc_sup.shutdown(CFG.cc.timeout.shutdown) def status(self): """ Returns the internal status. """ return self._status def _cleanup_pid(self): if self.pidfile: log.debug("Cleanup pidfile: %s", self.pidfile) try: os.remove(self.pidfile) except Exception, e: log.warn("Pidfile could not be deleted: %s" % str(e)) self.pidfile = None
class GovernanceUnitTest(PyonTestCase): governance_controller = None def setUp(self): FakeContainer = Mock() FakeContainer.id = "containerid" FakeContainer.node = Mock() self.governance_controller = GovernanceController(FakeContainer()) self.pre_func1 =\ """def precondition_func(process, msg, headers): if headers['op'] != 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ self.pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not have the proper signature self.bad_pre_func1 =\ """def precondition_func(msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not return the proper tuple self.bad_pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False else: return True """ def test_initialize_from_config(self): intlist = {'policy'} config = { 'interceptor_order': intlist, 'governance_interceptors': { 'policy': { 'class': 'pyon.core.governance.policy.policy_interceptor.PolicyInterceptor' } } } self.governance_controller.initialize_from_config(config) self.assertEquals(self.governance_controller.interceptor_order, intlist) self.assertEquals( len(self.governance_controller.interceptor_by_name_dict), len(config['governance_interceptors'])) # TODO - Need to fill this method out def test_process_message(self): pass def test_register_process_operation_precondition(self): bs = UnitTestService() self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 0) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func1) self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func2') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 2) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func4') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 3) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'self.pre_func1') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 4) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.bad_signature) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 5) def test_unregister_process_operation_precondition(self): bs = UnitTestService() self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 0) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func1) self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func2') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func1') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.func1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.pre_func1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.pre_func1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func2') self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 0) def test_check_process_operation_preconditions(self): bs = UnitTestService() self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func1) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func2') with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func2') self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func3) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.func2) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.pre_func1) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.pre_func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.assertIn('Cannot call the test_op operation', cm.exception.message) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.pre_func2) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func4') self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func4') #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.bad_signature) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.bad_signature) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.bad_return) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.bad_return) #Its possible to register invalid functions - but they it get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.bad_pre_func1) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.bad_pre_func1) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.bad_pre_func2) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.bad_pre_func2) def test_governance_header_values(self): process = Mock() process.name = 'test_process' headers = { 'op': 'test_op', 'process': process, 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz', 'sender-service': 'sender-service', 'ion-actor-roles': { 'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE] } } gov_values = GovernanceHeaderValues(headers) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'test_process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual( gov_values.actor_roles, {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id, '123xyz') self.assertRaises(BadRequest, GovernanceHeaderValues, {}) headers = { 'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz', 'sender-service': 'sender-service', 'ion-actor-roles': { 'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE] } } gov_values = GovernanceHeaderValues(headers) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'Unknown-Process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual( gov_values.actor_roles, {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id, '123xyz') headers = { 'op': 'test_op', 'request': 'request', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz', 'sender-service': 'sender-service', 'ion-actor-roles': { 'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE] } } self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) headers = { 'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz', 'sender-service': 'sender-service', 'ion-actor-123-roles': { 'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE] } } self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) headers = { 'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'sender-service': 'sender-service', 'ion-actor-roles': { 'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE] } } self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) gov_values = GovernanceHeaderValues(headers, resource_id_required=False) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'Unknown-Process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual( gov_values.actor_roles, {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id, '')
class Container(BaseContainerAgent): """ The Capability Container. Its purpose is to spawn/monitor processes and services that do the bulk of the work in the ION system. It also manages connections to the Exchange and the various forms of datastores in the systems. """ # Singleton static variables #node = None id = None name = None pidfile = None instance = None def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False # set container id and cc_agent name (as they are set in base class call) self.id = get_default_container_id() self.name = "cc_agent_%s" % self.id self._capabilities = [] bootstrap.container_instance = self Container.instance = self log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() # TODO: Do not start a capability here. Symmetric start/stop self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Instantiate Directory self.directory = Directory() # internal router self.local_router = None # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController(self) # sFlow manager - controls sFlow stat emission self.sflow_manager = SFlowManager(self) # Coordinates the container start self._status = "INIT" # protection for when the container itself is used as a Process for clients self.container = self # publisher, initialized in start() self.event_pub = None # context-local storage self.context = LocalContextMixin() log.debug("Container initialized, OK.") def start(self): log.debug("Container starting...") if self._is_started: raise ContainerError("Container already started") # Check if this UNIX process already runs a Container. self.pidfile = "cc-pid-%d" % os.getpid() if os.path.exists(self.pidfile): raise ContainerError("Container.on_start(): Container is a singleton per UNIX process. Existing pid file found: %s" % self.pidfile) # write out a PID file containing our agent messaging name with open(self.pidfile, 'w') as f: pid_contents = {'messaging': dict(CFG.server.amqp), 'container-agent': self.name, 'container-xp': bootstrap.get_sys_name()} f.write(msgpack.dumps(pid_contents)) atexit.register(self._cleanup_pid) self._capabilities.append("PID_FILE") # set up abnormal termination handler for this container def handl(signum, frame): try: self._cleanup_pid() # cleanup the pidfile first self.quit() # now try to quit - will not error on second cleanup pidfile call finally: signal.signal(signal.SIGTERM, self._normal_signal) os.kill(os.getpid(), signal.SIGTERM) self._normal_signal = signal.signal(signal.SIGTERM, handl) # set up greenlet debugging signal handler gevent.signal(signal.SIGUSR2, self._handle_sigusr2) self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") self._capabilities.append("DIRECTORY") # Event repository self.event_repository = EventRepository() self.event_pub = EventPublisher() self._capabilities.append("EVENT_REPOSITORY") # Local resource registry self.resource_registry = ResourceRegistry() self._capabilities.append("RESOURCE_REGISTRY") # Persistent objects self.datastore_manager.get_datastore("objects", DataStore.DS_PROFILE.OBJECTS) # State repository self.state_repository = StateRepository() self._capabilities.append("STATE_REPOSITORY") # internal router for local transports self.local_router = LocalRouter(bootstrap.get_sys_name()) self.local_router.start() self.local_router.ready.wait(timeout=2) self._capabilities.append("LOCAL_ROUTER") # Start ExchangeManager, which starts the node (broker connection) self.ex_manager.start() self._capabilities.append("EXCHANGE_MANAGER") self.proc_manager.start() self._capabilities.append("PROC_MANAGER") self.app_manager.start() self._capabilities.append("APP_MANAGER") self.governance_controller.start() self._capabilities.append("GOVERNANCE_CONTROLLER") if CFG.get_safe('container.sflow.enabled', False): self.sflow_manager.start() self._capabilities.append("SFLOW_MANAGER") # Start the CC-Agent API rsvc = ProcessRPCServer(node=self.node, from_name=self.name, service=self, process=self) cleanup = lambda _: self.proc_manager._cleanup_method(self.name, rsvc) # Start an ION process with the right kind of endpoint factory proc = self.proc_manager.proc_sup.spawn(name=self.name, listeners=[rsvc], service=self, cleanup_method=cleanup) self.proc_manager.proc_sup.ensure_ready(proc) proc.start_listeners() self._capabilities.append("CONTAINER_AGENT") self.event_pub.publish_event(event_type="ContainerLifecycleEvent", origin=self.id, origin_type="CapabilityContainer", sub_type="START", state=ContainerStateEnum.START) self._is_started = True self._status = "RUNNING" log.info("Container (%s) started, OK." , self.id) def _handle_sigusr2(self):#, signum, frame): """ Handles SIGUSR2, prints debugging greenlet information. """ gls = GreenletLeak.get_greenlets() allgls = [] for gl in gls: status = GreenletLeak.format_greenlet(gl) # build formatted output: # Greenlet at 0xdeadbeef # self: <EndpointUnit at 0x1ffcceef> # func: bound, EndpointUnit.some_func status[0].insert(0, "%s at %s:" % (gl.__class__.__name__, hex(id(gl)))) # indent anything in status a second time prefmt = [s.replace("\t", "\t\t") for s in status[0]] prefmt.append("traceback:") for line in status[1]: for subline in line.split("\n")[0:2]: prefmt.append(subline) glstr = "\n\t".join(prefmt) allgls.append(glstr) # print it out! print >>sys.stderr, "\n\n".join(allgls) with open("gls-%s" % os.getpid(), "w") as f: f.write("\n\n".join(allgls)) @property def node(self): """ Returns the active/default Node that should be used for most communication in the system. Defers to exchange manager, but only if it has been started, otherwise returns None. """ if "EXCHANGE_MANAGER" in self._capabilities: return self.ex_manager.default_node return None @contextmanager def _push_status(self, new_status): """ Temporarily sets the internal status flag. Use this as a decorator or in a with-statement before calling a temporary status changing method, like start_rel_from_url. """ curstatus = self._status self._status = new_status try: yield finally: self._status = curstatus def serve_forever(self): """ Run the container until killed. """ log.debug("In Container.serve_forever") if not self.proc_manager.proc_sup.running: self.start() # serve forever short-circuits if immediate is on and children len is ok num_procs = len(self.proc_manager.proc_sup.children) immediate = CFG.system.get('immediate', False) if not (immediate and num_procs == 1): # only spawned greenlet is the CC-Agent # print a warning just in case if immediate and num_procs != 1: log.warn("CFG.system.immediate=True but number of spawned processes is not 1 (%d)", num_procs) try: # This just waits in this Greenlet for all child processes to complete, # which is triggered somewhere else. self.proc_manager.proc_sup.join_children() except (KeyboardInterrupt, SystemExit) as ex: log.info('Received a kill signal, shutting down the container.') if hasattr(self, 'gl_parent_watch') and self.gl_parent_watch is not None: self.gl_parent_watch.kill() except: log.exception('Unhandled error! Forcing container shutdown') else: log.debug("Container.serve_forever short-circuiting due to CFG.system.immediate") self.proc_manager.proc_sup.shutdown(CFG.cc.timeout.shutdown) def status(self): """ Returns the internal status. """ return self._status def _cleanup_pid(self): if self.pidfile: log.debug("Cleanup pidfile: %s", self.pidfile) try: os.remove(self.pidfile) except Exception, e: log.warn("Pidfile could not be deleted: %s" % str(e)) self.pidfile = None
class Container(BaseContainerAgent): """ The Capability Container. Its purpose is to spawn/monitor processes and services that do the bulk of the work in the ION system. It also manages connections to the Exchange and the various forms of datastores in the systems. """ # Singleton static variables #node = None id = None name = None pidfile = None instance = None def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False # set container id and cc_agent name (as they are set in base class call) self.id = get_default_container_id() self.name = "cc_agent_%s" % self.id self._capabilities = [] bootstrap.container_instance = self Container.instance = self log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() # TODO: Do not start a capability here. Symmetric start/stop self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Instantiate Directory self.directory = Directory() # internal router self.local_router = None # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController(self) # sFlow manager - controls sFlow stat emission self.sflow_manager = SFlowManager(self) # Coordinates the container start self._status = "INIT" # protection for when the container itself is used as a Process for clients self.container = self # publisher, initialized in start() self.event_pub = None # context-local storage self.context = LocalContextMixin() log.debug("Container initialized, OK.") def start(self): log.debug("Container starting...") if self._is_started: raise ContainerError("Container already started") # Check if this UNIX process already runs a Container. self.pidfile = "cc-pid-%d" % os.getpid() if os.path.exists(self.pidfile): raise ContainerError( "Container.on_start(): Container is a singleton per UNIX process. Existing pid file found: %s" % self.pidfile) # write out a PID file containing our agent messaging name with open(self.pidfile, 'w') as f: pid_contents = { 'messaging': dict(CFG.server.amqp), 'container-agent': self.name, 'container-xp': bootstrap.get_sys_name() } f.write(msgpack.dumps(pid_contents)) atexit.register(self._cleanup_pid) self._capabilities.append("PID_FILE") # set up abnormal termination handler for this container def handl(signum, frame): try: self._cleanup_pid() # cleanup the pidfile first self.quit( ) # now try to quit - will not error on second cleanup pidfile call finally: signal.signal(signal.SIGTERM, self._normal_signal) os.kill(os.getpid(), signal.SIGTERM) self._normal_signal = signal.signal(signal.SIGTERM, handl) # set up greenlet debugging signal handler gevent.signal(signal.SIGUSR2, self._handle_sigusr2) self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") self._capabilities.append("DIRECTORY") # Event repository self.event_repository = EventRepository() self.event_pub = EventPublisher() self._capabilities.append("EVENT_REPOSITORY") # Local resource registry self.resource_registry = ResourceRegistry() self._capabilities.append("RESOURCE_REGISTRY") # Persistent objects self.datastore_manager.get_datastore("objects", DataStore.DS_PROFILE.OBJECTS) # State repository self.state_repository = StateRepository() self._capabilities.append("STATE_REPOSITORY") # internal router for local transports self.local_router = LocalRouter(bootstrap.get_sys_name()) self.local_router.start() self.local_router.ready.wait(timeout=2) self._capabilities.append("LOCAL_ROUTER") # Start ExchangeManager, which starts the node (broker connection) self.ex_manager.start() self._capabilities.append("EXCHANGE_MANAGER") self.proc_manager.start() self._capabilities.append("PROC_MANAGER") self.app_manager.start() self._capabilities.append("APP_MANAGER") self.governance_controller.start() self._capabilities.append("GOVERNANCE_CONTROLLER") if CFG.get_safe('container.sflow.enabled', False): self.sflow_manager.start() self._capabilities.append("SFLOW_MANAGER") # Start the CC-Agent API rsvc = ProcessRPCServer(node=self.node, from_name=self.name, service=self, process=self) cleanup = lambda _: self.proc_manager._cleanup_method(self.name, rsvc) # Start an ION process with the right kind of endpoint factory proc = self.proc_manager.proc_sup.spawn(name=self.name, listeners=[rsvc], service=self, cleanup_method=cleanup) self.proc_manager.proc_sup.ensure_ready(proc) proc.start_listeners() self._capabilities.append("CONTAINER_AGENT") self.event_pub.publish_event(event_type="ContainerLifecycleEvent", origin=self.id, origin_type="CapabilityContainer", sub_type="START", state=ContainerStateEnum.START) self._is_started = True self._status = "RUNNING" log.info("Container (%s) started, OK.", self.id) def _handle_sigusr2(self): #, signum, frame): """ Handles SIGUSR2, prints debugging greenlet information. """ gls = GreenletLeak.get_greenlets() allgls = [] for gl in gls: status = GreenletLeak.format_greenlet(gl) # build formatted output: # Greenlet at 0xdeadbeef # self: <EndpointUnit at 0x1ffcceef> # func: bound, EndpointUnit.some_func status[0].insert( 0, "%s at %s:" % (gl.__class__.__name__, hex(id(gl)))) # indent anything in status a second time prefmt = [s.replace("\t", "\t\t") for s in status[0]] prefmt.append("traceback:") for line in status[1]: for subline in line.split("\n")[0:2]: prefmt.append(subline) glstr = "\n\t".join(prefmt) allgls.append(glstr) # print it out! print >> sys.stderr, "\n\n".join(allgls) with open("gls-%s" % os.getpid(), "w") as f: f.write("\n\n".join(allgls)) @property def node(self): """ Returns the active/default Node that should be used for most communication in the system. Defers to exchange manager, but only if it has been started, otherwise returns None. """ if "EXCHANGE_MANAGER" in self._capabilities: return self.ex_manager.default_node return None @contextmanager def _push_status(self, new_status): """ Temporarily sets the internal status flag. Use this as a decorator or in a with-statement before calling a temporary status changing method, like start_rel_from_url. """ curstatus = self._status self._status = new_status try: yield finally: self._status = curstatus def serve_forever(self): """ Run the container until killed. """ log.debug("In Container.serve_forever") if not self.proc_manager.proc_sup.running: self.start() # serve forever short-circuits if immediate is on and children len is ok num_procs = len(self.proc_manager.proc_sup.children) immediate = CFG.system.get('immediate', False) if not (immediate and num_procs == 1): # only spawned greenlet is the CC-Agent # print a warning just in case if immediate and num_procs != 1: log.warn( "CFG.system.immediate=True but number of spawned processes is not 1 (%d)", num_procs) try: # This just waits in this Greenlet for all child processes to complete, # which is triggered somewhere else. self.proc_manager.proc_sup.join_children() except (KeyboardInterrupt, SystemExit) as ex: log.info( 'Received a kill signal, shutting down the container.') if hasattr(self, 'gl_parent_watch' ) and self.gl_parent_watch is not None: self.gl_parent_watch.kill() except: log.exception('Unhandled error! Forcing container shutdown') else: log.debug( "Container.serve_forever short-circuiting due to CFG.system.immediate" ) self.proc_manager.proc_sup.shutdown(CFG.cc.timeout.shutdown) def status(self): """ Returns the internal status. """ return self._status def _cleanup_pid(self): if self.pidfile: log.debug("Cleanup pidfile: %s", self.pidfile) try: os.remove(self.pidfile) except Exception, e: log.warn("Pidfile could not be deleted: %s" % str(e)) self.pidfile = None
class GovernanceUnitTest(PyonTestCase): governance_controller = None def setUp(self): FakeContainer = Mock() FakeContainer.id = "containerid" FakeContainer.node = Mock() self.governance_controller = GovernanceController(FakeContainer()) self.pre_func1 =\ """def precondition_func(process, msg, headers): if headers['op'] != 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ self.pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not have the proper signature self.bad_pre_func1 =\ """def precondition_func(msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not return the proper tuple self.bad_pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False else: return True """ def test_initialize_from_config(self): intlist = {'conversation', 'information', 'policy'} config = {'interceptor_order': intlist, 'governance_interceptors': {'conversation': {'class': 'pyon.core.governance.conversation.conversation_monitor_interceptor.ConversationMonitorInterceptor'}, 'information': {'class': 'pyon.core.governance.information.information_model_interceptor.InformationModelInterceptor'}, 'policy': {'class': 'pyon.core.governance.policy.policy_interceptor.PolicyInterceptor'}}} self.governance_controller.initialize_from_config(config) self.assertEquals(self.governance_controller.interceptor_order, intlist) self.assertEquals(len(self.governance_controller.interceptor_by_name_dict), len(config['governance_interceptors'])) # TODO - Need to fill this method out def test_process_message(self): pass def test_register_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 3) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'self.pre_func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 4) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 5) def test_unregister_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) def test_check_process_operation_preconditions(self): bs = UnitTestService() self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func2') self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func3) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func2) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.assertIn('Cannot call the test_op operation', cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func2) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func4') #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_signature) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_return) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_return) #Its possible to register invalid functions - but they it get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func2) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func2) def test_resource_policy_event_callback(self): event_data = Mock() event_data.resource_id = 'resource._id' event_data.resource_type = 'resource.type_' event_data.resource_name = 'resource.name' event_data.origin = 'policy._id' policy_rules = 'policy_rules' pc = Mock() pc.get_active_resource_access_policy_rules.return_value = policy_rules self.governance_controller.policy_client = pc self.governance_controller.system_actor_user_header = {} # call resource_policy_event_callback without a PDP self.governance_controller.resource_policy_event_callback(event_data) # expect that nothing happened since there was no PDP to update self.assertEqual(pc.get_active_resource_access_policy_rules.called, False) #add a pdp pdp = Mock() self.governance_controller.policy_decision_point_manager = pdp self.governance_controller.resource_policy_event_callback(event_data) # expect that policy rules are retrieved for resource pc.get_active_resource_access_policy_rules.assert_called_with(event_data.resource_id, headers={}) # expect that pdp is called with new rules pdp.load_resource_policy_rules.assert_called_with(event_data.resource_id, policy_rules) def test_service_policy_event_callback(self): # mock service policy event service_policy_event = Mock() service_policy_event.origin = 'policy_id' service_policy_event.service_name = 'UnitTestService' service_policy_event.op = 'test_op' # mock a container container = Mock() self.governance_controller.container = container # set it up so that service_name resolves neither to a service nor an agent container.proc_manager.is_local_service_process.return_value = False container.proc_manager.is_local_agent_process.return_value = False # add a pdp pdp = Mock() self.governance_controller.policy_decision_point_manager = pdp # check that the pdp is not called because service_name is neither a service nor an agent self.governance_controller.service_policy_event_callback(service_policy_event) self.assertEqual(pdp.called, False) ######### ######### # make the service_name a local service process container.proc_manager.is_local_service_process.return_value = True # set up mock policy client with rules policy_rules = 'policy_rules' pc = Mock() self.governance_controller.policy_client = pc self.governance_controller.system_actor_user_header = {} pc.get_active_service_access_policy_rules.return_value = policy_rules # set local process local_process = Mock() local_process.name = 'local_process' container.proc_manager.get_a_local_process.return_value = local_process # register process operation precondition self.governance_controller.register_process_operation_precondition(local_process, 'test_op', 'func1') # set up the active precondition op = Mock() op.op = 'test_op_2' op.preconditions = ['func2'] pc.get_active_process_operation_preconditions.return_value = [op] self.governance_controller.service_policy_event_callback(service_policy_event) # check that the service_policy_event_callback did not delete all registered preconditions (func1) on operation test_op self.assertEquals('test_op' in self.governance_controller.get_process_operation_dict(local_process.name), True) # and updated with the active one (func2) on test_op2 self.assertEquals('test_op_2' in self.governance_controller.get_process_operation_dict(local_process.name), True) # expect that policy rules are retrieved for resource pc.get_active_service_access_policy_rules.assert_called_with(service_name=service_policy_event.service_name, org_name=self.governance_controller.container_org_name, headers={}) pdp.load_service_policy_rules.assert_called_with(service_policy_event.service_name, policy_rules) def test_governance_header_values(self): process = Mock() process.name = 'test_process' headers = {'op': 'test_op', 'process': process, 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-roles': {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}} gov_values = GovernanceHeaderValues(headers) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'test_process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual(gov_values.actor_roles, {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id,'123xyz') self.assertRaises(BadRequest, GovernanceHeaderValues, {}) headers = {'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-roles': {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}} gov_values = GovernanceHeaderValues(headers) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'Unknown-Process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual(gov_values.actor_roles, {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id,'123xyz') headers = {'op': 'test_op', 'request': 'request', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-roles': {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}} self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) headers = {'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-123-roles': {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}} self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) headers = {'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type','sender-service': 'sender-service', 'ion-actor-roles': {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}} self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) gov_values = GovernanceHeaderValues(headers, resource_id_required=False) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'Unknown-Process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual(gov_values.actor_roles, {'ION': [ION_MANAGER, ORG_MANAGER_ROLE, ORG_MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id,'')
class GovernanceTest(PyonTestCase): governance_controller = None def setUp(self): self.governance_controller = GovernanceController(FakeContainer()) self.pre_func1 =\ """def precondition_func(process, msg, headers): if headers['op'] != 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ self.pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not have the proper signature self.bad_pre_func1 =\ """def precondition_func(msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not return the proper tuple self.bad_pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False else: return True """ def test_initialize_from_config(self): intlist = {'conversation', 'information', 'policy'} config = {'interceptor_order':intlist, 'governance_interceptors': {'conversation': {'class': 'pyon.core.governance.conversation.conversation_monitor_interceptor.ConversationMonitorInterceptor' }, 'information': {'class': 'pyon.core.governance.information.information_model_interceptor.InformationModelInterceptor' }, 'policy': {'class': 'pyon.core.governance.policy.policy_interceptor.PolicyInterceptor' } }} self.governance_controller.initialize_from_config(config) self.assertEquals(self.governance_controller.interceptor_order,intlist) self.assertEquals(len(self.governance_controller.interceptor_by_name_dict),len(config['governance_interceptors'])) # TODO - Need to fill this method out def test_process_message(self): pass def test_register_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 3) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'self.pre_func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 4) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 5) def test_unregister_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func2) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) def test_check_process_operation_preconditions(self): bs = UnitTestService() self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.assertIn('No reason',cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func2) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func3) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.assertIn('No reason',cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func2') self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.assertIn('Cannot call the test_op operation',cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func2) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func4') #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_signature) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_return) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_return) #Its possible to register invalid functions - but they it get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func2) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func2)
class GovernanceUnitTest(PyonTestCase): governance_controller = None def setUp(self): self.governance_controller = GovernanceController(FakeContainer()) self.pre_func1 =\ """def precondition_func(process, msg, headers): if headers['op'] != 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ self.pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not have the proper signature self.bad_pre_func1 =\ """def precondition_func(msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not return the proper tuple self.bad_pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False else: return True """ def test_initialize_from_config(self): intlist = {'conversation', 'information', 'policy'} config = {'interceptor_order':intlist, 'governance_interceptors': {'conversation': {'class': 'pyon.core.governance.conversation.conversation_monitor_interceptor.ConversationMonitorInterceptor' }, 'information': {'class': 'pyon.core.governance.information.information_model_interceptor.InformationModelInterceptor' }, 'policy': {'class': 'pyon.core.governance.policy.policy_interceptor.PolicyInterceptor' } }} self.governance_controller.initialize_from_config(config) self.assertEquals(self.governance_controller.interceptor_order,intlist) self.assertEquals(len(self.governance_controller.interceptor_by_name_dict),len(config['governance_interceptors'])) # TODO - Need to fill this method out def test_process_message(self): pass def test_register_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 3) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'self.pre_func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 4) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 5) def test_unregister_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func2) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) def test_check_process_operation_preconditions(self): bs = UnitTestService() self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.assertIn('No reason',cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func2) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func3) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.assertIn('No reason',cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func2') self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.assertIn('Cannot call the test_op operation',cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func2) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func4') #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_signature) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_return) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_return) #Its possible to register invalid functions - but they it get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func2) self.governance_controller.check_process_operation_preconditions(bs,{}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func2)
def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False # set container id and cc_agent name (as they are set in base class call) self.id = get_default_container_id() self.name = "cc_agent_%s" % self.id self._capabilities = [] bootstrap.container_instance = self Container.instance = self log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() # TODO: Do not start a capability here. Symmetric start/stop self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Instantiate Directory self.directory = Directory() # internal router self.local_router = None # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController(self) # sFlow manager - controls sFlow stat emission self.sflow_manager = SFlowManager(self) # Coordinates the container start self._status = "INIT" # protection for when the container itself is used as a Process for clients self.container = self # publisher, initialized in start() self.event_pub = None # context-local storage self.context = LocalContextMixin() log.debug("Container initialized, OK.")
def setUp(self): self.governance_controller = GovernanceController(FakeContainer())
class GovernanceUnitTest(PyonTestCase): governance_controller = None def setUp(self): FakeContainer = Mock() FakeContainer.id = "containerid" FakeContainer.node = Mock() self.governance_controller = GovernanceController(FakeContainer()) self.pre_func1 =\ """def precondition_func(process, msg, headers): if headers['op'] != 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ self.pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not have the proper signature self.bad_pre_func1 =\ """def precondition_func(msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not return the proper tuple self.bad_pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False else: return True """ def test_initialize_from_config(self): intlist = {'policy'} config = {'interceptor_order': intlist, 'governance_interceptors': {'policy': {'class': 'pyon.core.governance.policy.policy_interceptor.PolicyInterceptor'}}} self.governance_controller.initialize_from_config(config) self.assertEquals(self.governance_controller.interceptor_order, intlist) self.assertEquals(len(self.governance_controller.interceptor_by_name_dict), len(config['governance_interceptors'])) # TODO - Need to fill this method out def test_process_message(self): pass def test_register_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 3) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'self.pre_func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 4) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 5) def test_unregister_process_operation_precondition(self): bs = UnitTestService() self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func1') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func1) self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func2') self.assertEqual(len(self.governance_controller.get_process_operation_dict(bs.name)), 0) def test_check_process_operation_preconditions(self): bs = UnitTestService() self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func1) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func2') with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func2') self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func3) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.func2) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func1) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.pre_func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.assertIn('Cannot call the test_op operation', cm.exception.message) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.pre_func2) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', 'func4') self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', 'func4') #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_signature) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_signature) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', bs.bad_return) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', bs.bad_return) #Its possible to register invalid functions - but they it get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func1) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition(bs, 'test_op', self.bad_pre_func2) self.governance_controller.check_process_operation_preconditions(bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition(bs, 'test_op', self.bad_pre_func2) def test_governance_header_values(self): process = Mock() process.name = 'test_process' headers = {'op': 'test_op', 'process': process, 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-roles': {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}} gov_values = GovernanceHeaderValues(headers) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'test_process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual(gov_values.actor_roles, {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id,'123xyz') self.assertRaises(BadRequest, GovernanceHeaderValues, {}) headers = {'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-roles': {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}} gov_values = GovernanceHeaderValues(headers) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'Unknown-Process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual(gov_values.actor_roles, {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id,'123xyz') headers = {'op': 'test_op', 'request': 'request', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-roles': {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}} self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) headers = {'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type', 'resource-id': '123xyz' ,'sender-service': 'sender-service', 'ion-actor-123-roles': {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}} self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) headers = {'op': 'test_op', 'request': 'request', 'ion-actor-id': 'ionsystem', 'receiver': 'resource-registry', 'sender-type': 'sender-type','sender-service': 'sender-service', 'ion-actor-roles': {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}} self.assertRaises(Inconsistent, GovernanceHeaderValues, headers) gov_values = GovernanceHeaderValues(headers, resource_id_required=False) self.assertEqual(gov_values.op, 'test_op') self.assertEqual(gov_values.process_name, 'Unknown-Process') self.assertEqual(gov_values.actor_id, 'ionsystem') self.assertEqual(gov_values.actor_roles, {'ION': [SUPERUSER_ROLE, MODERATOR_ROLE, MEMBER_ROLE]}) self.assertEqual(gov_values.resource_id,'')
class Container(BaseContainerAgent): """ The Capability Container. Its purpose is to spawn/monitor processes and services that do the bulk of the work in the ION system. """ # Singleton static variables node = None id = None name = None pidfile = None instance = None def __init__(self, *args, **kwargs): BaseContainerAgent.__init__(self, *args, **kwargs) self._is_started = False # set id and name (as they are set in base class call) self.id = string.replace('%s_%d' % (os.uname()[1], os.getpid()), ".", "_") self.name = "cc_agent_%s" % self.id Container.instance = self # TODO: Bug: Replacing CFG instance not work because references are already public. Update directly dict_merge(CFG, kwargs, inplace=True) from pyon.core import bootstrap bootstrap.container_instance = self bootstrap.assert_configuration(CFG) log.debug("Container (sysname=%s) initializing ..." % bootstrap.get_sys_name()) # Keep track of the overrides from the command-line, so they can trump app/rel file data self.spawn_args = kwargs # Load object and service registry etc. bootstrap_pyon() # Create this Container's specific ExchangeManager instance self.ex_manager = ExchangeManager(self) # Create this Container's specific ProcManager instance self.proc_manager = ProcManager(self) # Create this Container's specific AppManager instance self.app_manager = AppManager(self) # DatastoreManager - controls access to Datastores (both mock and couch backed) self.datastore_manager = DatastoreManager() # File System - Interface to the OS File System, using correct path names and setups self.file_system = FileSystem(CFG) # Governance Controller - manages the governance related interceptors self.governance_controller = GovernanceController() # Coordinates the container start self._is_started = False self._capabilities = [] self._status = "INIT" log.debug("Container initialized, OK.") def start(self): log.debug("Container starting...") if self._is_started: raise ContainerError("Container already started") # Check if this UNIX process already runs a Container. self.pidfile = "cc-pid-%d" % os.getpid() if os.path.exists(self.pidfile): raise ContainerError("Container.on_start(): Container is a singleton per UNIX process. Existing pid file found: %s" % self.pidfile) # write out a PID file containing our agent messaging name with open(self.pidfile, 'w') as f: pid_contents = {'messaging': dict(CFG.server.amqp), 'container-agent': self.name, 'container-xp': bootstrap.get_sys_name() } f.write(msgpack.dumps(pid_contents)) atexit.register(self._cleanup_pid) self._capabilities.append("PID_FILE") # set up abnormal termination handler for this container def handl(signum, frame): try: self._cleanup_pid() # cleanup the pidfile first self.quit() # now try to quit - will not error on second cleanup pidfile call finally: signal.signal(signal.SIGTERM, self._normal_signal) os.kill(os.getpid(), signal.SIGTERM) self._normal_signal = signal.signal(signal.SIGTERM, handl) self._capabilities.append("EXCHANGE_CONNECTION") self.datastore_manager.start() self._capabilities.append("DATASTORE_MANAGER") # Instantiate Directory and self-register self.directory = Directory() self.directory.register("/Containers", self.id, cc_agent=self.name) self._capabilities.append("DIRECTORY") # Local resource registry self.resource_registry = ResourceRegistry() self._capabilities.append("RESOURCE_REGISTRY") # Create other repositories to make sure they are there and clean if needed self.datastore_manager.get_datastore("objects", DataStore.DS_PROFILE.OBJECTS) self.state_repository = StateRepository() self._capabilities.append("STATE_REPOSITORY") self.event_repository = EventRepository() self._capabilities.append("EVENT_REPOSITORY") # Start ExchangeManager, which starts the node (broker connection) self.node, self.ioloop = self.ex_manager.start() self._capabilities.append("EXCHANGE_MANAGER") self.proc_manager.start() self._capabilities.append("PROC_MANAGER") self.app_manager.start() self._capabilities.append("APP_MANAGER") self.governance_controller.start() self._capabilities.append("GOVERNANCE_CONTROLLER") # Start the CC-Agent API rsvc = ProcessRPCServer(node=self.node, from_name=self.name, service=self, process=self) # Start an ION process with the right kind of endpoint factory proc = self.proc_manager.proc_sup.spawn((CFG.cc.proctype or 'green', None), listener=rsvc) self.proc_manager.proc_sup.ensure_ready(proc) self._capabilities.append("CONTAINER_AGENT") self._is_started = True self._status = "RUNNING" log.info("Container started, OK.") @contextmanager def _push_status(self, new_status): """ Temporarily sets the internal status flag. Use this as a decorator or in a with-statement before calling a temporary status changing method, like start_rel_from_url. """ curstatus = self._status self._status = new_status try: yield finally: self._status = curstatus def serve_forever(self): """ Run the container until killed. """ log.debug("In Container.serve_forever") if not self.proc_manager.proc_sup.running: self.start() # serve forever short-circuits if immediate is on and children len is ok num_procs = len(self.proc_manager.proc_sup.children) immediate = CFG.system.get('immediate', False) if not (immediate and num_procs == 1): # only spawned greenlet is the CC-Agent # print a warning just in case if immediate and num_procs != 1: log.warn("CFG.system.immediate=True but number of spawned processes is not 1 (%d)", num_procs) try: # This just waits in this Greenlet for all child processes to complete, # which is triggered somewhere else. self.proc_manager.proc_sup.join_children() except (KeyboardInterrupt, SystemExit) as ex: log.info('Received a kill signal, shutting down the container.') except: log.exception('Unhandled error! Forcing container shutdown') else: log.debug("Container.serve_forever short-circuiting due to CFG.system.immediate") self.proc_manager.proc_sup.shutdown(CFG.cc.timeout.shutdown) def status(self): """ Returns the internal status. """ return self._status def _cleanup_pid(self): if self.pidfile: log.debug("Cleanup pidfile: %s", self.pidfile) try: os.remove(self.pidfile) except Exception, e: log.warn("Pidfile could not be deleted: %s" % str(e)) self.pidfile = None
class GovernanceUnitTest(PyonTestCase): governance_controller = None def setUp(self): FakeContainer = Mock() FakeContainer.id = "containerid" FakeContainer.node = Mock() self.governance_controller = GovernanceController(FakeContainer()) self.pre_func1 =\ """def precondition_func(process, msg, headers): if headers['op'] != 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ self.pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not have the proper signature self.bad_pre_func1 =\ """def precondition_func(msg, headers): if headers['op'] == 'test_op': return False, 'Cannot call the test_op operation' else: return True, '' """ #This invalid test function does not return the proper tuple self.bad_pre_func2 =\ """def precondition_func(process, msg, headers): if headers['op'] == 'test_op': return False else: return True """ def test_initialize_from_config(self): intlist = {'conversation', 'information', 'policy'} config = { 'interceptor_order': intlist, 'governance_interceptors': { 'conversation': { 'class': 'pyon.core.governance.conversation.conversation_monitor_interceptor.ConversationMonitorInterceptor' }, 'information': { 'class': 'pyon.core.governance.information.information_model_interceptor.InformationModelInterceptor' }, 'policy': { 'class': 'pyon.core.governance.policy.policy_interceptor.PolicyInterceptor' } } } self.governance_controller.initialize_from_config(config) self.assertEquals(self.governance_controller.interceptor_order, intlist) self.assertEquals( len(self.governance_controller.interceptor_by_name_dict), len(config['governance_interceptors'])) # TODO - Need to fill this method out def test_process_message(self): pass def test_register_process_operation_precondition(self): bs = UnitTestService() self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 0) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func1) self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func2') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 2) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func4') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 3) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'self.pre_func1') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 4) #Its possible to register invalid functions self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.bad_signature) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 5) def test_unregister_process_operation_precondition(self): bs = UnitTestService() self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 0) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func1) self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func2') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func1') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func1') self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.pre_func1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 2) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.pre_func1) self.assertEqual( len( self.governance_controller.get_process_operation_dict( bs.name)['test_op']), 1) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.func2) self.assertEqual( len(self.governance_controller.get_process_operation_dict( bs.name)), 0) def test_check_process_operation_preconditions(self): bs = UnitTestService() self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func1) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func2') with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.func2) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func3) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.assertIn('No reason', cm.exception.message) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func2') self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.pre_func1) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.pre_func2) with self.assertRaises(Unauthorized) as cm: self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.assertIn('Cannot call the test_op operation', cm.exception.message) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.pre_func2) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', 'func4') self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', 'func4') #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.bad_signature) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.bad_signature) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', bs.bad_return) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', bs.bad_return) #Its possible to register invalid functions - but they it get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.bad_pre_func1) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.bad_pre_func1) #Its possible to register invalid functions - but it should get ignored when checked self.governance_controller.register_process_operation_precondition( bs, 'test_op', self.bad_pre_func2) self.governance_controller.check_process_operation_preconditions( bs, {}, {'op': 'test_op'}) self.governance_controller.unregister_process_operation_precondition( bs, 'test_op', self.bad_pre_func2) def test_resource_policy_event_callback(self): event_data = Mock() event_data.resource_id = 'resource._id' event_data.resource_type = 'resource.type_' event_data.resource_name = 'resource.name' event_data.origin = 'policy._id' policy_rules = 'policy_rules' pc = Mock() pc.get_active_resource_access_policy_rules.return_value = policy_rules self.governance_controller.policy_client = pc # call resource_policy_event_callback without a PDP self.governance_controller.resource_policy_event_callback(event_data) # expect that nothing happened since there was no PDP to update self.assertEqual(pc.get_active_resource_access_policy_rules.called, False) #add a pdp pdp = Mock() self.governance_controller.policy_decision_point_manager = pdp self.governance_controller.resource_policy_event_callback(event_data) # expect that policy rules are retrieved for resource pc.get_active_resource_access_policy_rules.assert_called_with( event_data.resource_id) # expect that pdp is called with new rules pdp.load_resource_policy_rules.assert_called_with( event_data.resource_id, policy_rules) def test_service_policy_event_callback(self): # mock service policy event service_policy_event = Mock() service_policy_event.origin = 'policy_id' service_policy_event.service_name = 'UnitTestService' service_policy_event.op = 'test_op' # mock a container container = Mock() self.governance_controller.container = container # set it up so that service_name resolves neither to a service nor an agent container.proc_manager.is_local_service_process.return_value = False container.proc_manager.is_local_agent_process.return_value = False # add a pdp pdp = Mock() self.governance_controller.policy_decision_point_manager = pdp # check that the pdp is not called because service_name is neither a service nor an agent self.governance_controller.service_policy_event_callback( service_policy_event) self.assertEqual(pdp.called, False) ######### ######### # make the service_name a local service process container.proc_manager.is_local_service_process.return_value = True # set up mock policy client with rules policy_rules = 'policy_rules' pc = Mock() self.governance_controller.policy_client = pc pc.get_active_service_access_policy_rules.return_value = policy_rules # set local process local_process = Mock() local_process.name = 'local_process' container.proc_manager.get_a_local_process.return_value = local_process # register process operation precondition self.governance_controller.register_process_operation_precondition( local_process, 'test_op', 'func1') # set up the active precondition op = Mock() op.op = 'test_op_2' op.preconditions = ['func2'] pc.get_active_process_operation_preconditions.return_value = [op] self.governance_controller.service_policy_event_callback( service_policy_event) # check that the service_policy_event_callback deleted all registered preconditions (func1) on operation test_op self.assertEquals( 'test_op' in self.governance_controller.get_process_operation_dict( local_process.name), False) # and updated with the active one (func2) on test_op2 self.assertEquals( 'test_op_2' in self.governance_controller.get_process_operation_dict( local_process.name), True) # expect that policy rules are retrieved for resource pc.get_active_service_access_policy_rules.assert_called_with( service_policy_event.service_name, self.governance_controller._container_org_name) pdp.load_service_policy_rules.assert_called_with( service_policy_event.service_name, policy_rules)