def setup_image(args, image): """ set up image as specified in args args: cmdline arguments image: cloud_tests.image instance to operate on return_value: tuple of results and fail count """ # mapping of setup cmdline arg name to setup function # represented as a tuple rather than a dict or odict as lookup by name not # needed, and order is important as --script and --upgrade go at the end handlers = ( # arg handler description ('deb', install_deb, 'setup func for --deb, install deb'), ('rpm', install_rpm, 'setup func for --rpm, install rpm'), ('repo', enable_repo, 'setup func for --repo, enable repo'), ('ppa', enable_ppa, 'setup func for --ppa, enable ppa'), ('script', run_script, 'setup func for --script, run script'), ('upgrade', upgrade, 'setup func for --upgrade, upgrade pkgs'), ) # determine which setup functions needed calls = [ partial(stage.run_single, desc, partial(func, args, image)) for name, func, desc in handlers if getattr(args, name, None) ] image_name = 'image: distro={}, release={}'.format( image.properties['os'], image.properties['release']) LOG.info('setting up %s', image_name) return stage.run_stage('set up for {}'.format(image_name), calls, continue_after_error=False)
def __exit__(self, etype, value, trace): """Destroy instance.""" if self.instance is not None: if self.preserve_instance: LOG.info('Preserving test instance %s', self.instance.name) else: self.instance.destroy()
def collect_image(args, platform, os_name): """ collect data for image args: cmdline arguments platform: instantiated platform os_name: name of distro to collect for return_value: tuple of results and fail count """ res = ({}, 1) os_config = config.load_os_config(os_name) if not os_config.get('enabled'): raise ValueError('OS {} not enabled'.format(os_name)) component = PlatformComponent( partial(images.get_image, platform, os_config)) LOG.info('acquiring image for os: %s', os_name) with component as image: res = run_stage('set up and collect data for os: {}'.format(os_name), [partial(setup_image.setup_image, args, image)] + [partial(collect_snapshot, args, image, os_name)], continue_after_error=False) return res
def collect_image(args, platform, os_name): """Collect data for image. @param args: cmdline arguments @param platform: instantiated platform @param os_name: name of distro to collect for @return_value: tuple of results and fail count """ res = ({}, 1) os_config = config.load_os_config( platform.platform_name, os_name, require_enabled=True, feature_overrides=args.feature_override) LOG.debug('os config: %s', os_config) component = PlatformComponent( partial(platforms.get_image, platform, os_config)) LOG.info('acquiring image for os: %s', os_name) with component as image: res = run_stage('set up and collect data for os: {}'.format(os_name), [partial(setup_image.setup_image, args, image)] + [partial(collect_snapshot, args, image, os_name)], continue_after_error=False) return res
def setup_image(args, image): """Set up image as specified in args. @param args: cmdline arguments @param image: cloud_tests.image instance to operate on @return_value: tuple of results and fail count """ # update the args if necessary for this image overrides = image.setup_overrides LOG.debug('updating args for setup with: %s', overrides) args = util.update_args(args, overrides, preserve_old=True) # mapping of setup cmdline arg name to setup function # represented as a tuple rather than a dict or odict as lookup by name not # needed, and order is important as --script and --upgrade go at the end handlers = ( # arg handler description ('deb', install_deb, 'setup func for --deb, install deb'), ('rpm', install_rpm, 'setup func for --rpm, install rpm'), ('repo', enable_repo, 'setup func for --repo, enable repo'), ('ppa', enable_ppa, 'setup func for --ppa, enable ppa'), ('script', run_script, 'setup func for --script, run script'), ('upgrade', upgrade, 'setup func for --upgrade, upgrade cloud-init'), ('upgrade-full', upgrade_full, 'setup func for --upgrade-full'), ) # determine which setup functions needed calls = [partial(stage.run_single, desc, partial(func, args, image)) for name, func, desc in handlers if getattr(args, name, None)] LOG.info('setting up %s', image) res = stage.run_stage( 'set up for {}'.format(image), calls, continue_after_error=False) return res
def collect_test_data(args, snapshot, os_name, test_name): """Collect data for test case. @param args: cmdline arguments @param snapshot: instantiated snapshot @param test_name: name or path of test to run @return_value: tuple of results and fail count """ res = ({}, 1) # load test config test_name = config.path_to_name(test_name) test_config = config.load_test_config(test_name) user_data = test_config['cloud_config'] test_scripts = test_config['collect_scripts'] test_output_dir = os.sep.join( (args.data_dir, snapshot.platform_name, os_name, test_name)) # if test is not enabled, skip and return 0 failures if not test_config.get('enabled', False): LOG.warning('test config %s is not enabled, skipping', test_name) return ({}, 0) # if testcase requires a feature flag that the image does not support, # skip the testcase with a warning req_features = test_config.get('required_features', []) if any(feature not in snapshot.features for feature in req_features): LOG.warning('test config %s requires features not supported by image, ' 'skipping.\nrequired features: %s\nsupported features: %s', test_name, req_features, snapshot.features) return ({}, 0) # if there are user data overrides required for this test case, apply them overrides = snapshot.config.get('user_data_overrides', {}) if overrides: LOG.debug('updating user data for collect with: %s', overrides) user_data = util.update_user_data(user_data, overrides) # create test instance component = PlatformComponent( partial(platforms.get_instance, snapshot, user_data, block=True, start=False, use_desc=test_name)) LOG.info('collecting test data for test: %s', test_name) with component as instance: start_call = partial(run_single, 'boot instance', partial( instance.start, wait=True, wait_for_cloud_init=True)) collect_calls = [partial(run_single, 'script {}'.format(script_name), partial(collect_script, instance, test_output_dir, script, script_name)) for script_name, script in test_scripts.items()] console_log = partial( run_single, 'collect console', partial(collect_console, instance, test_output_dir)) res = run_stage('collect for test: {}'.format(test_name), [start_call] + collect_calls + [console_log]) return res
def bddeb(args): """Entry point for build deb. @param args: cmdline arguments @return_value: fail count """ LOG.info('preparing to build cloud-init deb') (res, failed) = run_stage('build deb', [partial(setup_build, args)]) return failed
def bddeb(args): """Entry point for build deb. @param args: cmdline arguments @return_value: fail count """ LOG.info('preparing to build cloud-init deb') _res, failed = run_stage('build deb', [partial(setup_build, args)]) return failed
def collect_test_data(args, snapshot, os_name, test_name): """ collect data for test case args: cmdline arguments snapshot: instantiated snapshot test_name: name or path of test to run return_value: tuple of results and fail count """ res = ({}, 1) # load test config test_name = config.path_to_name(test_name) test_config = config.load_test_config(test_name) user_data = test_config['cloud_config'] test_scripts = test_config['collect_scripts'] test_output_dir = os.sep.join( (args.data_dir, snapshot.platform_name, os_name, test_name)) boot_timeout = (test_config.get('boot_timeout') if isinstance( test_config.get('boot_timeout'), int) else snapshot.config.get('timeout')) # if test is not enabled, skip and return 0 failures if not test_config.get('enabled', False): LOG.warning('test config %s is not enabled, skipping', test_name) return ({}, 0) # create test instance component = PlatformComponent( partial(instances.get_instance, snapshot, user_data, block=True, start=False, use_desc=test_name)) LOG.info('collecting test data for test: %s', test_name) with component as instance: start_call = partial( run_single, 'boot instance', partial(instance.start, wait=True, wait_time=boot_timeout)) collect_calls = [ partial( run_single, 'script {}'.format(script_name), partial(collect_script, instance, test_output_dir, script, script_name)) for script_name, script in test_scripts.items() ] res = run_stage('collect for test: {}'.format(test_name), [start_call] + collect_calls) return res
def generate_ssh_keys(data_dir): """Generate SSH keys to be used with image.""" LOG.info('generating SSH keys') filename = os.path.join(data_dir, 'id_rsa') if os.path.exists(filename): c_util.del_file(filename) c_util.subp([ 'ssh-keygen', '-t', 'rsa', '-b', '4096', '-f', filename, '-P', '', '-C', 'ubuntu@cloud_test' ], capture=True)
def collect_snapshot(args, image, os_name): """ collect data for snapshot of image args: cmdline arguments image: instantiated image with set up complete return_value tuple of results and fail count """ res = ({}, 1) component = PlatformComponent(partial(snapshots.get_snapshot, image)) LOG.debug('creating snapshot for %s', os_name) with component as snapshot: LOG.info('collecting test data for os: %s', os_name) res = run_stage('collect test data for {}'.format(os_name), [ partial(collect_test_data, args, snapshot, os_name, test_name) for test_name in args.test_config ]) return res
def collect_snapshot(args, image, os_name): """Collect data for snapshot of image. @param args: cmdline arguments @param image: instantiated image with set up complete @return_value tuple of results and fail count """ res = ({}, 1) component = PlatformComponent(partial(platforms.get_snapshot, image)) LOG.debug('creating snapshot for %s', os_name) with component as snapshot: LOG.info('collecting test data for os: %s', os_name) res = run_stage( 'collect test data for {}'.format(os_name), [partial(collect_test_data, args, snapshot, os_name, test_name) for test_name in args.test_config]) return res
def verify(args): """Verify test data. @param args: directory of test data @return_value: 0 for success, or number of failed tests """ failed = 0 res = {} # find test data tests = util.list_test_data(args.data_dir) for platform in tests.keys(): res[platform] = {} for os_name in tests[platform].keys(): test_name = "platform='{}', os='{}'".format(platform, os_name) LOG.info('test: %s verifying test data', test_name) # run test res[platform][os_name] = verify_data( os.sep.join((args.data_dir, platform, os_name)), tests[platform][os_name]) # handle results fail_list = [ k for k, v in res[platform][os_name].items() if not v.get('passed') ] if len(fail_list) == 0: LOG.info('test: %s passed all tests', test_name) else: LOG.warning('test: %s failed %s tests', test_name, len(fail_list)) failed += len(fail_list) # dump results LOG.debug('verify results: %s', res) if args.result: util.merge_results({'verify': res}, args.result) return failed
def setup_image(args, image): """Set up image as specified in args. @param args: cmdline arguments @param image: cloud_tests.image instance to operate on @return_value: tuple of results and fail count """ # update the args if necessary for this image overrides = image.setup_overrides LOG.debug('updating args for setup with: %s', overrides) args = util.update_args(args, overrides, preserve_old=True) # mapping of setup cmdline arg name to setup function # represented as a tuple rather than a dict or odict as lookup by name not # needed, and order is important as --script and --upgrade go at the end handlers = ( # arg handler description ('deb', install_deb, 'setup func for --deb, install deb'), ('rpm', install_rpm, 'setup func for --rpm, install rpm'), ('repo', enable_repo, 'setup func for --repo, enable repo'), ('ppa', enable_ppa, 'setup func for --ppa, enable ppa'), ('script', run_script, 'setup func for --script, run script'), ('upgrade', upgrade, 'setup func for --upgrade, upgrade cloud-init'), ('upgrade-full', upgrade_full, 'setup func for --upgrade-full'), ) # determine which setup functions needed calls = [partial(stage.run_single, desc, partial(func, args, image)) for name, func, desc in handlers if getattr(args, name, None)] try: data = yaml.load(image.read_data("/etc/cloud/build.info", decode=True)) info = ' '.join(["%s=%s" % (k, data.get(k)) for k in ("build_name", "serial") if k in data]) except Exception as e: info = "N/A (%s)" % e LOG.info('setting up %s (%s)', image, info) res = stage.run_stage( 'set up for {}'.format(image), calls, continue_after_error=False) return res
def collect_platform(args, platform_name): """Collect data for platform. @param args: cmdline arguments @param platform_name: platform to collect for @return_value: tuple of results and fail count """ res = ({}, 1) platform_config = config.load_platform_config(platform_name, require_enabled=True) component = PlatformComponent( partial(platforms.get_platform, platform_name, platform_config)) LOG.info('setting up platform: %s', platform_name) with component as platform: res = run_stage('collect for platform: {}'.format(platform_name), [ partial(collect_image, args, platform, os_name) for os_name in args.os_name ]) return res
def verify(args): """Verify test data. @param args: directory of test data @return_value: 0 for success, or number of failed tests """ failed = 0 res = {} # find test data tests = util.list_test_data(args.data_dir) for platform in tests.keys(): res[platform] = {} for os_name in tests[platform].keys(): test_name = "platform='{}', os='{}'".format(platform, os_name) LOG.info('test: %s verifying test data', test_name) # run test res[platform][os_name] = verify_data( args.data_dir, platform, os_name, tests[platform][os_name]) # handle results fail_list = [k for k, v in res[platform][os_name].items() if not v.get('passed')] if len(fail_list) == 0: LOG.info('test: %s passed all tests', test_name) else: LOG.warning('test: %s failed %s tests', test_name, len(fail_list)) failed += len(fail_list) # dump results LOG.debug('\n---- Verify summarized results:\n%s', format_results(res)) if args.result: util.merge_results({'verify': res}, args.result) return failed
def collect_platform(args, platform_name): """Collect data for platform. @param args: cmdline arguments @param platform_name: platform to collect for @return_value: tuple of results and fail count """ res = ({}, 1) platform_config = config.load_platform_config( platform_name, require_enabled=True) platform_config['data_dir'] = args.data_dir LOG.debug('platform config: %s', platform_config) component = PlatformComponent( partial(platforms.get_platform, platform_name, platform_config)) LOG.info('setting up platform: %s', platform_name) with component as platform: res = run_stage('collect for platform: {}'.format(platform_name), [partial(collect_image, args, platform, os_name) for os_name in args.os_name]) return res
def collect_platform(args, platform_name): """ collect data for platform args: cmdline arguments platform_name: platform to collect for return_value: tuple of results and fail count """ res = ({}, 1) platform_config = config.load_platform_config(platform_name) if not platform_config.get('enabled'): raise ValueError('Platform {} not enabled'.format(platform_name)) component = PlatformComponent( partial(platforms.get_platform, platform_name, platform_config)) LOG.info('setting up platform: %s', platform_name) with component as platform: res = run_stage('collect for platform: {}'.format(platform_name), [ partial(collect_image, args, platform, os_name) for os_name in args.os_name ]) return res
def setup_build(args): """Set build system up then run build. @param args: cmdline arguments @return_value: tuple of results and fail count """ res = ({}, 1) # set up platform LOG.info('setting up platform: %s', args.build_platform) platform_config = config.load_platform_config(args.build_platform) platform_call = partial(platforms.get_platform, args.build_platform, platform_config) with PlatformComponent(platform_call) as platform: # set up image LOG.info('acquiring image for os: %s', args.build_os) img_conf = config.load_os_config(platform.platform_name, args.build_os) image_call = partial(images.get_image, platform, img_conf) with PlatformComponent(image_call) as image: # set up snapshot snapshot_call = partial(snapshots.get_snapshot, image) with PlatformComponent(snapshot_call) as snapshot: # create instance with cloud-config to set it up LOG.info('creating instance to build deb in') empty_cloud_config = "#cloud-config\n{}" instance_call = partial(instances.get_instance, snapshot, empty_cloud_config, use_desc='build cloud-init deb') with PlatformComponent(instance_call) as instance: # build the deb res = run_single('build deb on system', partial(build_deb, args, instance)) return res
def setup_build(args): """Set build system up then run build. @param args: cmdline arguments @return_value: tuple of results and fail count """ res = ({}, 1) # set up platform LOG.info('setting up platform: %s', args.build_platform) platform_config = config.load_platform_config(args.build_platform) platform_call = partial(platforms.get_platform, args.build_platform, platform_config) with PlatformComponent(platform_call) as platform: # set up image LOG.info('acquiring image for os: %s', args.build_os) img_conf = config.load_os_config(platform.platform_name, args.build_os) image_call = partial(platforms.get_image, platform, img_conf) with PlatformComponent(image_call) as image: # set up snapshot snapshot_call = partial(platforms.get_snapshot, image) with PlatformComponent(snapshot_call) as snapshot: # create instance with cloud-config to set it up LOG.info('creating instance to build deb in') empty_cloud_config = "#cloud-config\n{}" instance_call = partial( platforms.get_instance, snapshot, empty_cloud_config, use_desc='build cloud-init deb') with PlatformComponent(instance_call) as instance: # build the deb res = run_single('build deb on system', partial(build_deb, args, instance)) return res
def collect_test_data(args, snapshot, os_name, test_name): """Collect data for test case. @param args: cmdline arguments @param snapshot: instantiated snapshot @param test_name: name or path of test to run @return_value: tuple of results and fail count """ res = ({}, 1) # load test config test_name_in = test_name test_name = config.path_to_name(test_name) test_config = config.load_test_config(test_name) user_data = test_config['cloud_config'] test_scripts = test_config['collect_scripts'] test_output_dir = os.sep.join( (args.data_dir, snapshot.platform_name, os_name, test_name)) # if test is not enabled, skip and return 0 failures if not test_config.get('enabled', False): LOG.warning('test config %s is not enabled, skipping', test_name) return ({}, 0) test_class = get_test_class( config.name_to_module(test_name_in), test_data={'platform': snapshot.platform_name, 'os_name': os_name}, test_conf=test_config['cloud_config']) try: test_class.maybeSkipTest() except base.SkipTest as s: LOG.warning('skipping test config %s: %s', test_name, s) return ({}, 0) # if testcase requires a feature flag that the image does not support, # skip the testcase with a warning req_features = test_config.get('required_features', []) if any(feature not in snapshot.features for feature in req_features): LOG.warning('test config %s requires features not supported by image, ' 'skipping.\nrequired features: %s\nsupported features: %s', test_name, req_features, snapshot.features) return ({}, 0) # if there are user data overrides required for this test case, apply them overrides = snapshot.config.get('user_data_overrides', {}) if overrides: LOG.debug('updating user data for collect with: %s', overrides) user_data = util.update_user_data(user_data, overrides) # create test instance component = PlatformComponent( partial(platforms.get_instance, snapshot, user_data, block=True, start=False, use_desc=test_name), preserve_instance=args.preserve_instance) LOG.info('collecting test data for test: %s', test_name) with component as instance: start_call = partial(run_single, 'boot instance', partial( instance.start, wait=True, wait_for_cloud_init=True)) collect_calls = [partial(run_single, 'script {}'.format(script_name), partial(collect_script, instance, test_output_dir, script, script_name)) for script_name, script in test_scripts.items()] res = run_stage('collect for test: {}'.format(test_name), [start_call] + collect_calls) instance.shutdown() collect_console(instance, test_output_dir) return res
def __exit__(self, etype, value, trace): """Destroy tempdir if no errors occurred.""" if etype or self.preserve: LOG.info('leaving data in %s', self.tmpdir) else: shutil.rmtree(self.tmpdir)