def load(self, state, raw, source): logger.debug('Parsing agenda from "{}"'.format(source)) log.indent() try: if not isinstance(raw, dict): raise ConfigError( 'Invalid agenda, top level entry must be a dict') self._populate_and_validate_config(state, raw, source) sections = self._pop_sections(raw) global_workloads = self._pop_workloads(raw) if not global_workloads: msg = 'No jobs avaliable. Please ensure you have specified at '\ 'least one workload to run.' raise ConfigError(msg) if raw: msg = 'Invalid top level agenda entry(ies): "{}"' raise ConfigError(msg.format('", "'.join(list(raw.keys())))) sect_ids, wkl_ids = self._collect_ids(sections, global_workloads) self._process_global_workloads(state, global_workloads, wkl_ids) self._process_sections(state, sections, sect_ids, wkl_ids) state.agenda = source except (ConfigError, SerializerSyntaxError) as e: raise ConfigError('Error in "{}":\n\t{}'.format(source, str(e))) finally: log.dedent()
def update_config_from_source(final_config, source, state): if source in state.generic_config: final_config.name = state.generic_name for name, cfg_point in state.cfg_points.items(): if name in state.generic_config[source]: if name in state.seen_specific_config: msg = ('"{generic_name}" configuration "{config_name}" has ' 'already been specified more specifically for ' '{specific_name} in:\n\t\t{sources}') seen_sources = state.seen_specific_config[name] msg = msg.format(generic_name=state.generic_name, config_name=name, specific_name=state.specific_name, sources=", ".join(seen_sources)) raise ConfigError(msg) value = state.generic_config[source].pop(name) cfg_point.set_value(final_config, value, check_mandatory=False) if state.generic_config[source]: msg = 'Unexpected values for {}: {}' raise ConfigError(msg.format(state.generic_name, state.generic_config[source])) if source in state.specific_config: final_config.name = state.specific_name for name, cfg_point in state.cfg_points.items(): if name in state.specific_config[source]: state.seen_specific_config[name].append(str(source)) value = state.specific_config[source].pop(name) cfg_point.set_value(final_config, value, check_mandatory=False) if state.specific_config[source]: msg = 'Unexpected values for {}: {}' raise ConfigError(msg.format(state.specific_name, state.specific_config[source]))
def add_configs(self, plugin_name, values, source): if self.is_global_alias(plugin_name): self.add_global_alias(plugin_name, values, source) return if source not in self.sources: msg = "Source '{}' has not been added to the plugin cache." raise RuntimeError(msg.format(source)) if caseless_string(plugin_name) in ['global', 'config']: msg = '"{}" entry specified inside config/global section; If this is ' \ 'defined in a config file, move the entry content into the top level' raise ConfigError(msg.format((plugin_name))) if (not self.loader.has_plugin(plugin_name) and plugin_name not in self.targets and plugin_name not in GENERIC_CONFIGS): msg = 'configuration provided for unknown plugin "{}"' raise ConfigError(msg.format(plugin_name)) if not hasattr(values, 'items'): msg = 'Plugin configuration for "{}" not a dictionary ({} is {})' raise ConfigError( msg.format(plugin_name, repr(values), type(values))) for name, value in values.items(): if (plugin_name not in GENERIC_CONFIGS and name not in self.get_plugin_parameters(plugin_name)): msg = "'{}' is not a valid parameter for '{}'" raise ConfigError(msg.format(name, plugin_name)) self.plugin_configs[plugin_name][source][name] = value
def validate_parameters(self, params): if not params.get('resistor_values'): raise ConfigError('Mandatory parameter "resistor_values" is not set.') if params.get('labels'): if len(params.get('labels')) != len(params.get('resistor_values')): msg = 'Number of Energy Probe port labels does not match the number of resistor values.' raise ConfigError(msg)
def set_value(self, obj, value=None, check_mandatory=True): if self.deprecated: if value is not None: msg = 'Depreciated parameter supplied for "{}" in "{}". The value will be ignored.' logger.warning(msg.format(self.name, obj.name)) return if value is None: if self.default is not None: value = self.kind(self.default) elif check_mandatory and self.mandatory: msg = 'No values specified for mandatory parameter "{}" in {}' raise ConfigError(msg.format(self.name, obj.name)) else: try: value = self.kind(value) except (ValueError, TypeError): typename = get_type_name(self.kind) msg = 'Bad value "{}" for {}; must be {} {}' article = get_article(typename) raise ConfigError(msg.format(value, self.name, article, typename)) if value is not None: self.validate_value(self.name, value) if self.merge and hasattr(obj, self.name): value = merge_config_values(getattr(obj, self.name), value) setattr(obj, self.name, value)
def _pop_sections(self, raw): sections = raw.pop("sections", []) if not isinstance(sections, list): raise ConfigError('Invalid entry "sections" - must be a list') for section in sections: if not hasattr(section, 'items'): raise ConfigError( 'Invalid section "{}" - must be a dict'.format(section)) return sections
def set(self, name, value, check_mandatory=True): if name not in self.configuration: raise ConfigError('Unknown {} configuration "{}"'.format(self.name, name)) try: self.configuration[name].set_value(self, value, check_mandatory=check_mandatory) except (TypeError, ValueError, ConfigError) as e: msg = 'Invalid value "{}" for "{}": {}' raise ConfigError(msg.format(value, name, e))
def validate_allowed_values(self, name, value): if 'list' in str(self.kind): for v in value: if v not in self.allowed_values: msg = 'Invalid value {} for {} in {}; must be in {}' raise ConfigError(msg.format(v, self.name, name, self.allowed_values)) else: if value not in self.allowed_values: msg = 'Invalid value {} for {} in {}; must be in {}' raise ConfigError(msg.format(value, self.name, name, self.allowed_values))
def _get_oid(self): columns = ['{}s.oid'.format(self.kind)] tables = ['{}s'.format(self.kind)] conditions = ['runs.run_uuid = \'{}\''.format(self.run_uuid)] oid = self._read_db(columns, tables, conditions, as_dict=False) if not oid: raise ConfigError('No matching run entries found for run_uuid {}'.format(self.run_uuid)) if len(oid) > 1: raise ConfigError('Multiple entries found for run_uuid: {}'.format(self.run_uuid)) return oid[0][0]
def load(self, state, raw, source, wrap_exceptions=True): # pylint: disable=too-many-branches logger.debug('Parsing config from "{}"'.format(source)) log.indent() try: state.plugin_cache.add_source(source) if 'run_name' in raw: msg = '"run_name" can only be specified in the config '\ 'section of an agenda' raise ConfigError(msg) if 'id' in raw: raise ConfigError('"id" cannot be set globally') merge_augmentations(raw) # Get WA core configuration for cfg_point in state.settings.configuration.values(): value = pop_aliased_param(cfg_point, raw) if value is not None: logger.debug('Setting meta "{}" to "{}"'.format( cfg_point.name, value)) state.settings.set(cfg_point.name, value) # Get run specific configuration for cfg_point in state.run_config.configuration.values(): value = pop_aliased_param(cfg_point, raw) if value is not None: logger.debug('Setting run "{}" to "{}"'.format( cfg_point.name, value)) state.run_config.set(cfg_point.name, value) # Get global job spec configuration for cfg_point in JobSpec.configuration.values(): value = pop_aliased_param(cfg_point, raw) if value is not None: logger.debug('Setting global "{}" to "{}"'.format( cfg_point.name, value)) state.jobs_config.set_global_value(cfg_point.name, value) for name, values in raw.items(): # Assume that all leftover config is for a plug-in or a global # alias it is up to PluginCache to assert this assumption logger.debug('Caching "{}" with "{}"'.format( identifier(name), values)) state.plugin_cache.add_configs(identifier(name), values, source) except ConfigError as e: if wrap_exceptions: raise ConfigError('Error in "{}":\n{}'.format(source, str(e))) else: raise e finally: log.dedent()
def _load_file(filepath, error_name): if not os.path.isfile(filepath): raise ValueError("{} does not exist".format(filepath)) try: raw = read_pod(filepath) includes = _process_includes(raw, filepath, error_name) except SerializerSyntaxError as e: raise ConfigError('Error parsing {} {}: {}'.format( error_name, filepath, e)) if not isinstance(raw, dict): message = '{} does not contain a valid {} structure; top level must be a dict.' raise ConfigError(message.format(filepath, error_name)) return raw, includes
def _collect_valid_id(entry_id, seen_ids, entry_type): if entry_id is None: return entry_id = str(entry_id) if entry_id in seen_ids: raise ConfigError('Duplicate {} ID "{}".'.format(entry_type, entry_id)) # "-" is reserved for joining section and workload IDs if "-" in entry_id: msg = 'Invalid {} ID "{}"; IDs cannot contain a "-"' raise ConfigError(msg.format(entry_type, entry_id)) if entry_id == "global": msg = 'Invalid {} ID "global"; is a reserved ID' raise ConfigError(msg.format(entry_type)) seen_ids.add(entry_id)
def set_runtime_parameters(self, parameters): for name, value in parameters.items(): cfg = self.get_config_for_name(name) if cfg is None: msg = 'Unsupported runtime parameter: "{}"' raise ConfigError(msg.format(name)) cfg.set_runtime_parameter(name, value)
def validate(self): super(Youtube, self).validate() self.gui.uiauto_params['video_source'] = self.video_source self.gui.uiauto_params['search_term'] = self.search_term # Make sure search term is set if video source is 'search' if (self.video_source == 'search') and not self.search_term: raise ConfigError("Param 'search_term' must be specified when video source is 'search'")
def initialize(self, context): if not self.target.is_rooted and self.as_root: raise ConfigError( 'The target is not rooted, cannot run poller as root.') host_poller = context.get_resource( Executable(self, self.target.abi, "poller")) target_poller = self.target.install(host_poller) expanded_paths = [] for path in self.files: if "*" in path: for p in self.target.list_directory(path): expanded_paths.append(p) else: expanded_paths.append(path) self.files = expanded_paths if not self.labels: self.labels = self._generate_labels() self.target_output_path = self.target.path.join( self.target.working_directory, 'poller.csv') self.target_log_path = self.target.path.join( self.target.working_directory, 'poller.log') marker_option = '' if self.align_with_ftrace: marker_option = '-m' signal.connect(self._adjust_timestamps, signal.AFTER_JOB_OUTPUT_PROCESSED) self.command = '{} -t {} {} -l {} {} > {} 2>{}'.format( target_poller, self.sample_interval * 1000, marker_option, ','.join(self.labels), ' '.join(self.files), self.target_output_path, self.target_log_path)
def __init__(self, target, **kwargs): if target.os == 'chromeos': if target.supports_android: target = target.android_container else: raise ConfigError('Target does not appear to support Android') super(ApkWorkload, self).__init__(target, **kwargs) if self.activity is not None and '.' not in self.activity: # If we're receiving just the activity name, it's taken relative to # the package namespace: self.activity = '.' + self.activity self.apk = PackageHandler(self, package_name=self.package_name, variant=self.variant, strict=self.strict, version=self.version or self.supported_versions, force_install=self.force_install, install_timeout=self.install_timeout, uninstall=self.uninstall, exact_abi=self.exact_abi, prefer_host_package=self.prefer_host_package, clear_data_on_reset=self.clear_data_on_reset, activity=self.activity, min_version=self.min_version, max_version=self.max_version)
def initialize(self, context): self.instruments = self.backend.get_instruments(self.target, context.run_output.metadir, **self.params) for instrument in self.instruments.values(): if not (instrument.mode & CONTINUOUS): # pylint: disable=superfluous-parens msg = '{} instrument does not support continuous measurement collection' raise ConfigError(msg.format(self.instrument)) instrument.setup() for channel in self.channels or []: # Check that the expeccted channels exist. # If there are multiple Instruments, they were all constructed with # the same channels param, so check them all. for instrument in self.instruments.values(): if not instrument.get_channels(channel): raise ConfigError('No channels found for "{}"'.format(channel))
def package_record(self, args): if self.target.os != 'android' and self.target.os != 'chromeos': raise ConfigError('Target does not appear to be running Android') if self.target.os == 'chromeos' and not self.target.supports_android: raise ConfigError('Target does not appear to support Android') if args.clear: self.target.execute('pm clear {}'.format(args.package)) self.logger.info('Starting {}'.format(args.package)) cmd = 'monkey -p {} -c android.intent.category.LAUNCHER 1' self.target.execute(cmd.format(args.package)) output_path, file_name = self._split_revent_location(args.output) revent_file = self.target.get_workpath(file_name) self.record(revent_file, '', output_path) msg = 'Recording is available at: \'{}\'' self.logger.info(msg.format(os.path.join(output_path, file_name)))
def validate(self): if self.min_version and self.max_version: if version_tuple(self.min_version) > version_tuple( self.max_version): msg = 'Cannot specify min version ({}) greater than max version ({})' raise ConfigError( msg.format(self.min_version, self.max_version))
def execute(self, state, args): agenda = OrderedDict() agenda['config'] = OrderedDict(augmentations=[], iterations=args.iterations) agenda['workloads'] = [] target_desc = None targets = {td.name: td for td in list_target_descriptions()} for name in args.plugins: if name in targets: if target_desc is not None: raise ConfigError( 'Specifying multiple devices: {} and {}'.format( target_desc.name, name)) target_desc = targets[name] agenda['config']['device'] = name agenda['config'][ 'device_config'] = target_desc.get_default_config() continue extcls = pluginloader.get_plugin_class(name) config = pluginloader.get_default_config(name) # Handle special case for EnergyInstrumentBackends if issubclass(extcls, EnergyInstrumentBackend): if 'energy_measurement' not in agenda['config'][ 'augmentations']: energy_config = pluginloader.get_default_config( 'energy_measurement') agenda['config']['augmentations'].append( 'energy_measurement') agenda['config']['energy_measurement'] = energy_config agenda['config']['energy_measurement'][ 'instrument'] = extcls.name agenda['config']['energy_measurement'][ 'instrument_parameters'] = config elif extcls.kind == 'workload': entry = OrderedDict() entry['name'] = extcls.name if name != extcls.name: entry['label'] = name entry['params'] = config agenda['workloads'].append(entry) else: if extcls.kind in ('instrument', 'output_processor'): if extcls.name not in agenda['config']['augmentations']: agenda['config']['augmentations'].append(extcls.name) if extcls.name not in agenda['config']: agenda['config'][extcls.name] = config if args.output: wfh = open(args.output, 'w') else: wfh = sys.stdout yaml.dump(agenda, wfh, indent=4, default_flow_style=False) if args.output: wfh.close()
def validate(self, ext): ext_params = set(p.name for p in ext.parameters) for param in self.params: if param not in ext_params: # Raising config error because aliases might have come through # the config. msg = 'Parameter {} (defined in alias {}) is invalid for {}' raise ConfigError(msg.format(param, self.name, ext.name))
def set_param(obj, value, core, parameter): '''Method to store passed parameter if it is not already specified for that cpu''' cpus = resolve_unique_domain_cpus(core, obj.target) for cpu in cpus: if parameter in obj.config[cpu]: msg = 'Cannot set "{}" for core "{}"; Parameter for CPU{} has already been set' raise ConfigError(msg.format(parameter, core, cpu)) obj.config[cpu][parameter] = value
def _process_workload_entry(workload, seen_workload_ids, jobs_config): workload = _get_workload_entry(workload) workload = _construct_valid_entry(workload, seen_workload_ids, "wk", jobs_config) if "workload_name" not in workload: raise ConfigError('No workload name specified in entry {}'.format( workload['id'])) return workload
def validate(self, obj, check_mandatory=True): value = getattr(obj, self.name, None) if value is not None: self.validate_value(obj.name, value) else: if check_mandatory and self.mandatory: msg = 'No value specified for mandatory parameter "{}" in {}.' raise ConfigError(msg.format(self.name, obj.name))
def __init__(self, policy): if isinstance(policy, RebootPolicy): policy = policy.policy policy = policy.strip().lower().replace(' ', '_') if policy not in self.valid_policies: message = 'Invalid reboot policy {}; must be one of {}'.format(policy, ', '.join(self.valid_policies)) raise ConfigError(message) self.policy = policy
def _merge_using_priority_specificity(self, specific_name, generic_name, merged_config, is_final=True): """ WA configuration can come from various sources of increasing priority, as well as being specified in a generic and specific manner (e.g ``device_config`` and ``nexus10`` respectivly). WA has two rules for the priority of configuration: - Configuration from higher priority sources overrides configuration from lower priority sources. - More specific configuration overrides less specific configuration. There is a situation where these two rules come into conflict. When a generic configuration is given in config source of high priority and a specific configuration is given in a config source of lower priority. In this situation it is not possible to know the end users intention and WA will error. :param specific_name: The name of the specific configuration used e.g ``nexus10`` :param generic_name: The name of the generic configuration e.g ``device_config`` :param merge_config: A dict of ``ConfigurationPoint``s to be used when merging configuration. keys=config point name, values=config point :param is_final: if ``True`` (the default) make sure that mandatory parameters are set. :rtype: A fully merged and validated configuration in the form of a obj_dict. """ ms = MergeState() ms.generic_name = generic_name ms.specific_name = specific_name ms.generic_config = copy(self.plugin_configs[generic_name]) ms.specific_config = copy(self.plugin_configs[specific_name]) ms.cfg_points = self.get_plugin_parameters(specific_name) sources = self.sources # set_value uses the 'name' attribute of the passed object in it error # messages, to ensure these messages make sense the name will have to be # changed several times during this function. merged_config.name = specific_name for source in sources: try: update_config_from_source(merged_config, source, ms) except ConfigError as e: raise ConfigError('Error in "{}":\n\t{}'.format( source, str(e))) # Validate final configuration merged_config.name = specific_name for cfg_point in ms.cfg_points.values(): cfg_point.validate(merged_config, check_mandatory=is_final)
def __init__(self, target, **kwargs): if target.os == 'chromeos': if target.supports_android: target = target.android_container else: raise ConfigError('Target does not appear to support Android') super(UiautoWorkload, self).__init__(target, **kwargs) self.gui = UiAutomatorGUI(self)
def validate_parameters(self): '''Method to validate parameters against each other''' for cpu in self.config: config = self.config[cpu] minf = config.get('min_frequency') maxf = config.get('max_frequency') freq = config.get('frequency') if freq and minf: msg = 'CPU{}: Can\'t set both cpu frequency and minimum frequency' raise ConfigError(msg.format(cpu)) if freq and maxf: msg = 'CPU{}: Can\'t set both cpu frequency and maximum frequency' raise ConfigError(msg.format(cpu)) if (maxf and minf) and self._resolve_freq(minf, cpu) > self._resolve_freq(maxf, cpu): msg = 'CPU{}: min_frequency "{}" cannot be greater than max_frequency "{}"' raise ConfigError(msg.format(cpu, minf, maxf))
def set_num_cores(obj, value, core): cpus = resolve_cpus(core, obj.target) max_cores = len(cpus) value = integer(value) if value > max_cores: msg = 'Cannot set number of {}\'s to {}; max is {}' raise ValueError(msg.format(core, value, max_cores)) msg = 'CPU{} Hotplugging already configured' # Set cpus to be enabled for cpu in cpus[:value]: if cpu in obj.num_cores: raise ConfigError(msg.format(cpu)) obj.num_cores[cpu] = True # Set the remaining cpus to be disabled. for cpu in cpus[value:]: if cpu in obj.num_cores: raise ConfigError(msg.format(cpu)) obj.num_cores[cpu] = False
def __init__(self, **kwargs): self.logger = logging.getLogger(self.name) self._modules = [] self.capabilities = getattr(self.__class__, 'capabilities', []) for param in self.parameters: param.set_value(self, kwargs.get(param.name)) for key in kwargs: if key not in self.parameters: message = 'Unexpected parameter "{}" for {}' raise ConfigError(message.format(key, self.name))