def __init__(self, name, config=None): self.allowed_options.update({'type', 'unit', 'scale'}) self.name = name self.type = config['type'] super().__init__(config) if self.value_encoder is None: raise NotImplementedError( 'You must provide a value encoder for setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__)) if self.default is None: raise NotImplementedError( 'You must provide a default value for setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__)) self.scale = config.get('scale') if self.scale is not None: if not isinstance(self.scale, Number): raise SettingConfigException( 'Scale provided for setting {} must be a numeric type. Found: {} "{}"' .format(self.name, self.scale.__class__.__name__, self.scale))
def decode_option_ps1(self, data, path=None): lines = data.split('\n') # TODO?: refactor below so that it won't break when parameter order of source is different than expected/not sourced from this encoder setting_line = list( filter( lambda l: l.startswith( 'Set-WebConfigurationProperty -Filter "{}" -PSPath "{}" -Name "{}" -Value ' .format( self.filter, path if path else self.default_path, self.name_override if self.name_override else self.name)), lines)) if len(setting_line) > 1: raise SettingRuntimeException( "Found more than one value for registry setting {} in the provided powershel text:\n{}", q(self.name), data) if len(setting_line) < 1: value = self.system_default # If web config settings are not adjusted, the system default value is in effect so long as the site exists else: value = setting_line[0].split()[-1] try: return self.get_value_encoder().decode(value) except ValueError as e: raise SettingRuntimeException( 'Invalid value to decode for setting {}. ' 'Error: {}. Arg: {}'.format(q(self.name), str(e), value))
def __init__(self, config=None): super().__init__(config) if self.value_encoder is None: raise NotImplementedError( 'You must provide value encoder for dotnet setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__)) if self.system_default is None: # feel free to remove this in the case of dotnet settings with no system defaults raise NotImplementedError( 'You must provide system_default for dotnet setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__))
def validate_data(self, data): if not isinstance(data, list): raise SettingRuntimeException( 'Expected list on input for RangeSetting. ' 'Got {} instead.'.format(q(type(data).__name__))) opts = self.filter_data(data) if len(opts) > 1: raise SettingRuntimeException( 'Received multiple values for setting {}, only one value is allowed ' 'on decode'.format(q(self.name))) if not opts and self.default is None: raise SettingRuntimeException( 'No value found to decode for setting {} and no ' 'default value was configured.'.format(q(self.name))) return opts
def decode(data): val = data.lower() if val[-1] != 'm': raise ValueError( 'Invalid value {} to decode from megabytes to gigabytes.'. format(q(data))) return int(val[:-1]) / 1024
def __init__(self, config=None): super().__init__(config) if self.path is None: raise NotImplementedError( 'You must provide path for registry setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__))
def __init__(self, config=None): super().__init__(config) if self.filter is None: raise NotImplementedError( 'You must provide a filter for web config setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__))
def __init__(self, config=None): self.allowed_options.update({'values', 'disable_others'}) super().__init__(config) if self.config.get('values'): self.values = self.config.get('values') if self.default is not None and self.default not in self.values: raise SettingConfigException( 'Default value for setting GCType was not found in the defined list of values. ' 'Found {}. Supported: {}'.format(q(self.default), self.values)) self.max = len(self.values) - 1 disable_others = self.config.get('disable_others') if disable_others is not None: self.disable_others = disable_others self.settings = [] for value in self.values: class Setting(BooleanSetting): name = value default = 0 formats = ('XX:{value}Use{name}', ) setting = Setting() self.settings.append(setting)
def check_class_defaults(self): super().check_class_defaults() if not self.formats or not isinstance(self.formats, (list, tuple, set)): raise NotImplementedError( 'Attribute `formats` in the setting class {} must be a list with at least ' 'one defined setting format. Found {}.'.format( self.__class__.__name__, q(self.formats))) if (self.preferred_format is None or not isinstance(self.preferred_format, int) or self.preferred_format < 0 or self.preferred_format >= len(self.formats)): raise NotImplementedError( 'Attribute `preferred_format` in the setting class {} ' 'must be an integer in the range 0 to {}. ' 'Found {}.'.format(self.__class__.__name__, len(self.formats), q(self.preferred_format)))
def validate_value(self, value): if value not in self.values: raise SettingRuntimeException( 'Provided value {} for encode is not ' 'one of the available ones: {}.'.format( q(value), ', '.join(self.values))) value = self.values.index(value) value = super().validate_value(value) return value
def decode_option_json(self, data, path=None): """ Decodes dict of primitive values back into single primitive value. :param data: dict of setting values for the given path and filter of the current setting class :param path: path string from parent WebConfigSetting config_list :return: Single primitive value """ if path is None: path = self.default_path wc = data.get("WebConfig") # NOTE: because json structure is used during adjust as validation, it is built to be more fail-deadly # as these failures would indicate the describe data is misformatted. When describe.ps1 is up to date, webconfig values will always # be present in describe json even if they haven't been adjusted yet if not wc: raise SettingRuntimeException( "WebConfig dict for path:setting {}:{} was not found in describe data" .format(path, self.name)) if not isinstance(wc, dict): raise SettingRuntimeException( 'Describe WebConfig data {} must have its value be a dict. ' 'It is currently {}.'.format(q(self.name), wc.__class__.__name__)) if len(wc) < 0: raise SettingRuntimeException( "WebConfig dict for path:setting {}:{} was found but had no key values" .format(path, self.name)) name_locator = self.name_override if self.name_override else self.name try: value = wc[path][self.filter][name_locator] except KeyError: raise SettingRuntimeException( "Unable to located value of setting in path '{}' under filter '{}' by name(_override) '{}'" " within the describe data provided".format( path, self.filter, name_locator)) try: return self.get_value_encoder().decode(value) except ValueError as e: raise SettingRuntimeException( 'Invalid value to decode for setting {}. ' 'Error: {}. Arg: {}'.format(q(self.name), str(e), value))
def encode_multi(self, values, expected_type=None): encoded = self._encode_multi(values) expected_type = str if expected_type is None else expected_type if expected_type in ('str', str): return encoded if expected_type in ('list', list): return encoded.split('\n') raise EncoderConfigException( 'Unrecognized expected_type passed on encode in dotnet encoder: {}. ' 'Supported: "list", "str"'.format(q(expected_type)))
def decode_option(self, data): if isinstance(data, dict): return self.decode_option_json(data) elif isinstance(data, str): return self.decode_option_ps1(data) else: raise SettingRuntimeException( 'Unrecognized data type passed on decode_option in dotnet encoder setting: {}. ' 'Supported: "dict (loaded json)", "str (powershell script)"'. format(q(data.__class__.__name__)))
def decode_option(self, data): if not isinstance(data, dict): raise SettingRuntimeException( 'Unrecognized data type passed on decode_option in nameval encoder setting type: {}. ' 'Supported: "dict (parsed multiline file)"'.format( q(data.__class__.__name__))) value = data.get(self.name) if value is None: return self.config['default'] return value
def decode_multi(self, data): if not isinstance(data, str): raise EncoderRuntimeException( 'Unrecognized data type passed on decode in nameval encoder: {}. ' 'Supported: "str"'.format(q(data.__class__.__name__))) # parse lines into dict for more efficient setting decode # NOTE: section will need revision to support other setting formats data_dict = {} for sett_line in data.split('\n'): if sett_line == '': continue sett_tup = sett_line.split('=') if len(sett_tup) != 2: raise EncoderRuntimeException( 'Malformed setting line passed on decode in nameval encoder: ' '{}'.format(q(sett_line))) data_dict[sett_tup[0]] = sett_tup[1] return self._decode_multi(data_dict)
def load_encoder(encoder): if isinstance(encoder, str): try: return importlib.import_module( 'encoders.{}'.format(encoder)).Encoder except ImportError: raise ImportError('Unable to import encoder {}'.format(q(encoder))) except AttributeError: raise AttributeError( 'Were not able to import encoder\'s class from encoders.{}'. format(encoder)) return encoder
def decode_multi(self, data): if isinstance(data, str): try: data = json.loads(data) except ValueError: pass # Assuming data is a string representing a PS1 script else: if not isinstance(data, dict): raise EncoderRuntimeException( 'Unrecognized data type passed on decode in dotnet encoder: {}. ' 'Supported: "dict", "str"'.format( q(data.__class__.__name__))) return self._decode_multi(data)
def __init__(self, name, config=None): self.allowed_options.update({'values', 'type', 'unit'}) self.name = name self.type = config['type'] super().__init__(config) if not isinstance(self.config.get('values'), list): raise SettingConfigException( 'Incompatible values data provided for setting {} ' 'handled by class {}: {}'.format(q(self.name), self.__class__.__name__, self.config.get('values'))) if self.config.get('default') is None: raise SettingConfigException( 'You must provide a default value for setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__)) if self.config['default'] not in self.config['values']: raise SettingConfigException( 'Default value not contained in values for setting {} ' 'handled by class {}'.format(q(self.name), self.__class__.__name__))
def validate_data(self, data): decoded_values = { setting.name: setting.decode_option(data) for setting in self.settings } if sum(decoded_values.values()) > 1: raise SettingRuntimeException( 'There is more than 1 active GC in the input data for setting GCType.' ) if not any(decoded_values.values()) and self.default is None: raise SettingRuntimeException( 'No value found to decode for setting GCType and no ' 'default value was configured.'.format(q(self.name))) return decoded_values
def decode_option(self, data): """ Decodes list of primitive values back into single primitive value. :param data: List of multiple primitive values :return: Single primitive value """ opts = self.validate_data(data) if opts: opt = opts[0] value = self.get_format_match(opt).groups()[0] try: return self.get_value_encoder().decode(value) except ValueError as e: raise SettingRuntimeException( 'Invalid value to decode for setting {}. ' 'Error: {}. Arg: {}'.format(q(self.name), str(e), opt)) return self.default
def decode_option_json(self, data): """ Decodes describe data dict back into single primitive value of the current setting. :param data: dict of describe data :return: Single primitive value """ # NOTE: because json structure is used during adjust as validation, it is built to be more fail-deadly # as these failures would indicate an out of date describe.ps1 reg = data.get(self.path, None) if not reg: raise SettingRuntimeException( "Registry path {} for setting {} was not found in describe data" .format(self.path, self.name)) # NOTE: Until registry options are set, getting the registry path will return no keys but each of the settings does have a system default value # which will be considered to be in effect in cases where the path in data has no keys value = reg.get(self.name, self.system_default) try: return self.get_value_encoder().decode(value) except ValueError as e: raise SettingRuntimeException( 'Invalid value to decode for setting {}. ' 'Error: {}. Arg: {}'.format(q(self.name), str(e), value))
def validate_value(self, value): if value not in self.config['values']: raise SettingRuntimeException( 'Value provided for setting {} was not contained in configured values. ' 'Value: {}.'.format(q(self.name), q(value)))