def cleanup_broker(): # @Dave: This is maybe too brute force and there is maybe a better pattern... connect_str = "-q -H %s -P %s -u %s -p %s -V %s" % (CFG.get_safe('server.amqp_priv.host', CFG.get_safe('server.amqp.host', 'localhost')), CFG.get_safe('container.exchange.management.port', '55672'), CFG.get_safe('container.exchange.management.username', 'guest'), CFG.get_safe('container.exchange.management.password', 'guest'), '/') from putil.rabbithelper import clean_by_sysname clean_by_sysname(connect_str, get_sys_name())
def prepare_container(): """ Walks through pyon initialization in a deterministic way and initializes Container. In particular make sure configuration is loaded in correct order and pycc startup arguments are considered. """ import threading threading.current_thread().name = "CC-Main" # SIDE EFFECT: The import triggers static initializers: Monkey patching, setting pyon defaults import pyon from pyon.core import bootstrap, config # Set global testing flag to False. We are running as capability container, because # we started through the pycc program. bootstrap.testing = False # Set sysname if provided in startup argument if opts.sysname: bootstrap.set_sys_name(opts.sysname) # Trigger any initializing default logic in get_sys_name bootstrap.get_sys_name() command_line_config = kwargs # This holds the minimal configuration used to bootstrap pycc and pyon and connect to datastores. bootstrap_config = None # This holds the new CFG object for pyon. Build it up in proper sequence and conditions. pyon_config = config.read_standard_configuration() # Initial pyon.yml + pyon.local.yml # Load config override if provided. Supports variants literal and list of paths config_override = None if opts.config: if "{" in opts.config: # Variant 1: Dict of config values try: eval_value = ast.literal_eval(opts.config) config_override = eval_value except ValueError: raise Exception("Value error in config arg '%s'" % opts.config) else: # Variant 2: List of paths from pyon.util.config import Config config_override = Config([opts.config]).data # Determine bootstrap_config if opts.config_from_directory: # Load minimal bootstrap config if option "config_from_directory" bootstrap_config = config.read_local_configuration(["res/config/pyon_min_boot.yml"]) config.apply_local_configuration(bootstrap_config, pyon.DEFAULT_LOCAL_CONFIG_PATHS) config.apply_configuration(bootstrap_config, config_override) config.apply_configuration(bootstrap_config, command_line_config) print "pycc: config_from_directory=True. Minimal bootstrap configuration:", bootstrap_config else: # Otherwise: Set to standard set of local config files plus command line overrides bootstrap_config = deepcopy(pyon_config) config.apply_configuration(bootstrap_config, config_override) config.apply_configuration(bootstrap_config, command_line_config) # Override sysname from config file or command line if not opts.sysname and bootstrap_config.get_safe("system.name", None): new_sysname = bootstrap_config.get_safe("system.name") bootstrap.set_sys_name(new_sysname) # Delete sysname datastores if option "force_clean" is set if opts.force_clean: from pyon.datastore import clear_couch_util print "pycc: force_clean=True. DROP DATASTORES for sysname=%s" % bootstrap.get_sys_name() clear_couch_util.clear_couch( bootstrap_config, prefix=bootstrap.get_sys_name(), sysname=bootstrap.get_sys_name() ) pyon_config.container.filesystem.force_clean = True from pyon.core.interfaces.interfaces import InterfaceAdmin iadm = InterfaceAdmin(bootstrap.get_sys_name(), config=bootstrap_config) # If auto_bootstrap, load config and interfaces into directory # Note: this is idempotent and will not alter anything if this is not the first container to run if bootstrap_config.system.auto_bootstrap: print "pycc: auto_bootstrap=True." stored_config = deepcopy(pyon_config) config.apply_configuration(stored_config, config_override) config.apply_configuration(stored_config, command_line_config) iadm.create_core_datastores() iadm.store_config(stored_config) # Determine the final pyon_config # - Start from standard config already set (pyon.yml + local YML files) # - Optionally load config from directory if opts.config_from_directory: config.apply_remote_config(bootstrap_cfg=bootstrap_config, system_cfg=pyon_config) # - Apply container profile specific config config.apply_profile_configuration(pyon_config, bootstrap_config) # - Reapply pyon.local.yml here again for good measure config.apply_local_configuration(pyon_config, pyon.DEFAULT_LOCAL_CONFIG_PATHS) # - Last apply any separate command line config overrides config.apply_configuration(pyon_config, config_override) config.apply_configuration(pyon_config, command_line_config) # Also set the immediate flag, but only if specified - it is an override if opts.immediate: from pyon.util.containers import dict_merge dict_merge(pyon_config, {"system": {"immediate": True}}, True) # Bootstrap pyon's core. Load configuration etc. bootstrap.bootstrap_pyon(pyon_cfg=pyon_config) # Delete any queues/exchanges owned by sysname if option "broker_clean" is set if opts.broker_clean: print "pycc: broker_clean=True, sysname:", bootstrap.get_sys_name() # build connect str connect_str = "-q -H %s -P %s -u %s -p %s -V %s" % ( pyon_config.get_safe("server.amqp_priv.host", pyon_config.get_safe("server.amqp.host", "localhost")), pyon_config.get_safe("container.exchange.management.port", "55672"), pyon_config.get_safe("container.exchange.management.username", "guest"), pyon_config.get_safe("container.exchange.management.password", "guest"), "/", ) from putil.rabbithelper import clean_by_sysname deleted_exchanges, deleted_queues = clean_by_sysname(connect_str, bootstrap.get_sys_name()) print " exchanges deleted (%s): %s" % (len(deleted_exchanges), ",".join(deleted_exchanges)) print " queues deleted (%s): %s" % (len(deleted_queues), ",".join(deleted_queues)) if opts.force_clean: path = os.path.join(pyon_config.get_safe("container.filesystem.root", "/tmp/ion"), bootstrap.get_sys_name()) print "force_clean: Removing", path FileSystem._clean(pyon_config) # Auto-bootstrap interfaces if bootstrap_config.system.auto_bootstrap: iadm.store_interfaces(idempotent=True) iadm.close() if opts.no_container: print "pycc: no_container=True. Stopping here." return None # Create the container instance from pyon.container.cc import Container container = Container(*args, **command_line_config) return container
def prepare_container(): """ Walks through pyon initialization in a deterministic way and initializes Container. In particular make sure configuration is loaded in correct order and pycc startup arguments are considered. """ import threading threading.current_thread().name = "CC-Main" # SIDE EFFECT: The import triggers static initializers: Monkey patching, setting pyon defaults import pyon from pyon.core import bootstrap, config # Set global testing flag to False. We are running as capability container. This is NO TEST. bootstrap.testing = False # Set sysname if provided in startup argument if opts.sysname: bootstrap.set_sys_name(opts.sysname) # Trigger any initializing default logic in get_sys_name bootstrap.get_sys_name() command_line_config = kwargs # This holds the minimal configuration used to bootstrap pycc and pyon and connect to datastores. bootstrap_config = None # This holds the new CFG object for pyon. Build it up in proper sequence and conditions. pyon_config = config.read_standard_configuration( ) # Initial pyon.yml + pyon.local.yml # Load config override if provided. Supports variants literal and list of paths config_override = None if opts.config: if '{' in opts.config: # Variant 1: Dict of config values try: eval_value = ast.literal_eval(opts.config) config_override = eval_value except ValueError: raise Exception("Value error in config arg '%s'" % opts.config) else: # Variant 2: List of paths from pyon.util.config import Config config_override = Config([opts.config]).data # Determine bootstrap_config if opts.config_from_directory: # Load minimal bootstrap config if option "config_from_directory" bootstrap_config = config.read_local_configuration( ['res/config/pyon_min_boot.yml']) config.apply_local_configuration(bootstrap_config, pyon.DEFAULT_LOCAL_CONFIG_PATHS) config.apply_configuration(bootstrap_config, config_override) config.apply_configuration(bootstrap_config, command_line_config) print "pycc: config_from_directory=True. Minimal bootstrap configuration:", bootstrap_config else: # Otherwise: Set to standard set of local config files plus command line overrides bootstrap_config = deepcopy(pyon_config) config.apply_configuration(bootstrap_config, config_override) config.apply_configuration(bootstrap_config, command_line_config) # Override sysname from config file or command line if not opts.sysname and bootstrap_config.get_safe("system.name", None): new_sysname = bootstrap_config.get_safe("system.name") bootstrap.set_sys_name(new_sysname) # Delete sysname datastores if option "force_clean" is set if opts.force_clean: from pyon.datastore import clear_couch_util print "pycc: force_clean=True. DROP DATASTORES for sysname=%s" % bootstrap.get_sys_name( ) clear_couch_util.clear_couch(bootstrap_config, prefix=bootstrap.get_sys_name()) pyon_config.container.filesystem.force_clean = True from pyon.core.interfaces.interfaces import InterfaceAdmin iadm = InterfaceAdmin(bootstrap.get_sys_name(), config=bootstrap_config) # If auto_bootstrap, load config and interfaces into directory # Note: this is idempotent and will not alter anything if this is not the first container to run if bootstrap_config.system.auto_bootstrap: print "pycc: auto_bootstrap=True." stored_config = deepcopy(pyon_config) config.apply_configuration(stored_config, config_override) config.apply_configuration(stored_config, command_line_config) iadm.create_core_datastores() iadm.store_config(stored_config) # Determine the final pyon_config # - Start from standard config already set (pyon.yml + local YML files) # - Optionally load config from directory if opts.config_from_directory: config.apply_remote_config(bootstrap_cfg=bootstrap_config, system_cfg=pyon_config) config.apply_local_configuration( pyon_config, pyon.DEFAULT_LOCAL_CONFIG_PATHS ) # apply pyon.local.yml again over top # - Last apply any separate command line config overrides config.apply_configuration(pyon_config, config_override) config.apply_configuration(pyon_config, command_line_config) # Also set the immediate flag, but only if specified - it is an override if opts.immediate: from pyon.util.containers import dict_merge dict_merge(pyon_config, {'system': {'immediate': True}}, True) # Bootstrap pyon's core. Load configuration etc. bootstrap.bootstrap_pyon(pyon_cfg=pyon_config) # Delete any queues/exchanges owned by sysname if option "broker_clean" is set if opts.broker_clean: print "pycc: broker_clean=True, sysname:", bootstrap.get_sys_name() # build connect str connect_str = "-q -H %s -P 55672 -u %s -p %s -V %s" % ( pyon_config.get_safe( 'server.amqp_priv.host', pyon_config.get_safe('server.amqp.host', 'localhost')), pyon_config.get_safe('container.exchange.management.username', 'guest'), pyon_config.get_safe('container.exchange.management.password', 'guest'), '/') from putil.rabbithelper import clean_by_sysname deleted_exchanges, deleted_queues = clean_by_sysname( connect_str, bootstrap.get_sys_name()) print " exchanges deleted (%s): %s" % ( len(deleted_exchanges), ",".join(deleted_exchanges)) print " queues deleted (%s): %s" % ( len(deleted_queues), ",".join(deleted_queues)) # Auto-bootstrap interfaces if bootstrap_config.system.auto_bootstrap: iadm.store_interfaces(idempotent=True) iadm.close() if opts.no_container: print "pycc: no_container=True. Stopping here." return None # Create the container instance from pyon.container.cc import Container container = Container(*args, **command_line_config) return container
def begin(self): """Called before any tests are collected or run. Use this to perform any setup needed before testing begins. """ # Make sure we initialize pyon before anything in this plugin executes from pyon.core import bootstrap if not bootstrap.pyon_initialized: bootstrap.bootstrap_pyon() try: from pyon.public import get_sys_name, CFG self.sysname = get_sys_name() # Clean exchanges and system queues out there try: connect_str = '-H %s -P 55672 -u %s -p %s -V %s' % (CFG.server.amqp.host, CFG.server.amqp.username, CFG.server.amqp.password, CFG.server.amqp.vhost) deleted_exchanges, deleted_queues = clean_by_sysname(connect_str, self.sysname) debug.write('Deleted exchanges:\n%s \n' % '\n'.join(deleted_exchanges)) debug.write('Deleted queues:\n%s \n' % '\n'.join(deleted_queues)) except Exception as e: pass # Force datastore loader to use the same sysname from pyon.datastore.datastore_admin import DatastoreAdmin self.datastore_admin = DatastoreAdmin(config=CFG) self.datastore_admin.clear_datastore(prefix=self.sysname) def die(signum, frame): # For whatever reason, the parent doesn't die some times # when getting KeyboardInterrupt. Hence this signal # handler. # Signal is pass through. The child pycc gets # its own KeyboardInterrupt and will shut down accordingly. debug.write('Received Keyboard Interrupt. Exiting now.\n') os._exit(9) signal.signal(signal.SIGINT, die) def no_zombie(signum, frame): # Debug to figure out who's dying debug.write('SIGCHLD received\n') stack = [] while frame: stack.append(frame) frame =frame.f_back stack.reverse() for frame in stack: debug.write('Frame %s in %s at line %s\n' % (frame.f_code.co_name, frame.f_code.co_filename, frame.f_lineno)) debug.write('Child is dead...Clean up now so there is no zombie\n') (pid, status) = os.wait() exitstatus, signum = status & 0xff, (status & 0xff00) >> 8 debug.write('Child pid %d with exit status %d and signum %d\n' % (pid, exitstatus, signum)) # Could be dangerous. Comment this out. # signal.signal(signal.SIGCHLD, no_zombie) def container_started_cb(signum, frame): """Callback when child pycc service is ready""" self.container_started = True signal.signal(signal.SIGUSR1, container_started_cb) # Make sure the pycc process has the same sysname as the nose ccargs = ['bin/pycc', '-o', '--noshell', '-sp', '--sysname=%s' % self.sysname, '--logcfg=res/config/logging.pycc.yml', '--rel=%s' % self.rel, "--config={'system': {'auto_bootstrap': True}}"] debug.write('Starting cc process: %s\n' % ' '.join(ccargs)) newenv = os.environ.copy() po = subprocess.Popen(ccargs, env=newenv, close_fds=True) self.ccs.append(po) # Wait for container to be ready while not self.container_started: time.sleep(0.2) debug.write('Child container is ready...\n') # Dump datastore self.datastore_admin.dump_datastore(path='res/dd', compact=True) debug.write('Dump child container state to file...\n') # Clean again to make sure the first nosetest starts on a clean # slate self.datastore_admin.clear_datastore(prefix=self.sysname) # Set PYCC env var in case CEI needs to skip tests in pycc mode os.environ['PYCC_MODE'] = '1' # Enable CEI mode for the tests os.environ['CEI_LAUNCH_TEST'] = '1' debug.write('Start nose tests now...\n') except Exception as e: self.container_shutdown() raise e
def begin(self): """Called before any tests are collected or run. Use this to perform any setup needed before testing begins. """ # Make sure we initialize pyon before anything in this plugin executes from pyon.core import bootstrap if not bootstrap.pyon_initialized: bootstrap.bootstrap_pyon() try: from pyon.public import get_sys_name, CFG self.sysname = get_sys_name() # Clean exchanges and system queues out there try: connect_str = '-H %s -P 55672 -u %s -p %s -V %s' % (CFG.server.amqp.host, CFG.server.amqp.username, CFG.server.amqp.password, CFG.server.amqp.vhost) deleted_exchanges, deleted_queues = clean_by_sysname(connect_str, self.sysname) debug.write('Deleted exchanges:\n%s \n' % '\n'.join(deleted_exchanges)) debug.write('Deleted queues:\n%s \n' % '\n'.join(deleted_queues)) except Exception as e: pass # Force datastore loader to use the same sysname from pyon.datastore.datastore_admin import DatastoreAdmin self.datastore_admin = DatastoreAdmin(config=CFG) self.datastore_admin.clear_datastore(prefix=self.sysname) def die(signum, frame): # For whatever reason, the parent doesn't die some times # when getting KeyboardInterrupt. Hence this signal # handler. # Signal is pass through. The child pycc gets # its own KeyboardInterrupt and will shut down accordingly. debug.write('Received Keyboard Interrupt. Exiting now.\n') os._exit(9) signal.signal(signal.SIGINT, die) def no_zombie(signum, frame): # Debug to figure out who's dying debug.write('SIGCHLD received\n') stack = [] while frame: stack.append(frame) frame =frame.f_back stack.reverse() for frame in stack: debug.write('Frame %s in %s at line %s\n' % (frame.f_code.co_name, frame.f_code.co_filename, frame.f_lineno)) debug.write('Child is dead...Clean up now so there is no zombie\n') (pid, status) = os.wait() exitstatus, signum = status & 0xff, (status & 0xff00) >> 8 debug.write('Child pid %d with exit status %d and signum %d\n' % (pid, exitstatus, signum)) # Could be dangerous. Comment this out. # signal.signal(signal.SIGCHLD, no_zombie) def container_started_cb(signum, frame): """Callback when child pycc service is ready""" self.container_started = True signal.signal(signal.SIGUSR1, container_started_cb) # Make sure the pycc process has the same sysname as the nose ccargs = ['bin/pycc', '-o', '--noshell', '-sp', '--sysname=%s' % self.sysname, '--logcfg=res/config/logging.pycc.yml', '--rel=%s' % self.rel, "--config={'system': {'auto_bootstrap': True}}"] debug.write('Starting cc process: %s\n' % ' '.join(ccargs)) newenv = os.environ.copy() po = subprocess.Popen(ccargs, env=newenv, close_fds=True) self.ccs.append(po) # Wait for container to be ready while not self.container_started: time.sleep(0.2) debug.write('Child container is ready...\n') # Dump datastore self.datastore_admin.dump_datastore(path='res/dd', compact=True) debug.write('Dump child container state to file...\n') # Clean again to make sure the first nosetest starts on a clean # slate self.datastore_admin.clear_datastore(prefix=self.sysname) # Enable CEI mode for the tests os.environ['CEI_LAUNCH_TEST'] = '1' debug.write('Start nose tests now...\n') except Exception as e: self.container_shutdown() raise e