async def _validate(self, schema_name, data, id=None): verrors = ValidationErrors() await self._ensure_unique(verrors, schema_name, "name", data["name"], id) if data["type"] not in TYPES: verrors.add(f"{schema_name}.type", "Invalid type") raise verrors else: type = TYPES[data["type"]] attributes_verrors = validate_attributes(type.credentials_schema, data) verrors.add_child(f"{schema_name}.attributes", attributes_verrors) if verrors: raise verrors await type.validate_and_pre_save(self.middleware, verrors, f"{schema_name}.attributes", data["attributes"]) if verrors: raise verrors
async def construct_schema_for_item_version(self, item_version_details, new_values, update): schema_name = f'chart_release_{"update" if update else "create"}' attrs = list( itertools.chain.from_iterable( get_schema(q, update) for q in item_version_details['schema']['questions'])) dict_obj = update_conditional_validation( Dict(schema_name, *attrs, update=update), {'schema': { 'attrs': item_version_details['schema']['questions'] }}) verrors = validate_attributes(attrs, {'values': new_values}, attr_key='values', dict_kwargs={ 'conditional_validation': dict_obj.conditional_validation, 'update': update, }) return { 'verrors': verrors, 'new_values': new_values, 'dict_obj': dict_obj, 'schema_name': schema_name, }
async def common_validation(self, data, schema_name): verrors = ValidationErrors() if data['authenticator'] not in self.schemas: verrors.add( f'{schema_name}.authenticator', f'System does not support {data["authenticator"]} as an Authenticator' ) else: verrors = validate_attributes(self.schemas[data['authenticator']], data) if verrors: raise verrors
async def common_validation(self, data, schema_name): verrors = ValidationErrors() if data['authenticator'] not in self.schemas: verrors.add( f'{schema_name}.authenticator', f'System does not support {data["authenticator"]} as an Authenticator' ) else: verrors = validate_attributes(self.schemas[data['authenticator']], data) if verrors: raise verrors
async def _validate(self, service, schema_name): verrors = ValidationErrors() factory = ALERT_SERVICES_FACTORIES.get(service["type"]) if factory is None: verrors.add(f"{schema_name}.type", "This field has invalid value") raise verrors verrors.add_child(f"{schema_name}.attributes", validate_attributes(list(factory.schema.attrs.values()), service)) if verrors: raise verrors
async def _validate(self, schema_name, data, id=None): verrors = ValidationErrors() await self._ensure_unique(verrors, schema_name, "name", data["name"], id) if data["provider"] not in REMOTES: verrors.add(f"{schema_name}.provider", "Invalid provider") else: provider = REMOTES[data["provider"]] attributes_verrors = validate_attributes(provider.credentials_schema, data) verrors.add_child(f"{schema_name}.attributes", attributes_verrors) if verrors: raise verrors
async def _validate(self, schema_name, data, id=None): verrors = ValidationErrors() await self._ensure_unique(verrors, schema_name, "name", data["name"], id) if data["provider"] not in REMOTES: verrors.add(f"{schema_name}.provider", "Invalid provider") else: provider = REMOTES[data["provider"]] attributes_verrors = validate_attributes(provider.credentials_schema, data) verrors.add_child(f"{schema_name}.attributes", attributes_verrors) if verrors: raise verrors
async def _basic_validate(self, verrors, name, data): if data["encryption"]: if not data["encryption_password"]: verrors.add( f"{name}.encryption_password", "This field is required when encryption is enabled") credentials = await self._get_credentials(data["credentials"]) if not credentials: verrors.add(f"{name}.credentials", "Invalid credentials") for i, (limit1, limit2) in enumerate(zip(data["bwlimit"], data["bwlimit"][1:])): if limit1["time"] >= limit2["time"]: verrors.add( f"{name}.bwlimit.{i + 1}.time", f"Invalid time order: {limit1['time']}, {limit2['time']}") try: shlex.split(data["args"]) except ValueError as e: verrors.add(f"{name}.args", f"Parse error: {e.args[0]}") if verrors: raise verrors provider = REMOTES[credentials["provider"]] schema = [] if provider.buckets: schema.append(Str("bucket", required=True, empty=False)) schema.append(Str("folder", required=True)) schema.extend(provider.task_schema) schema.extend(self.common_task_schema(provider)) attributes_verrors = validate_attributes(schema, data, additional_attrs=True) if not attributes_verrors: await provider.pre_save_task(data, credentials, verrors) verrors.add_child(f"{name}.attributes", attributes_verrors)
async def _validate(self, schema_name, data, id=None): verrors = ValidationErrors() await self._ensure_unique(verrors, schema_name, "name", data["name"], id) if data["type"] not in TYPES: verrors.add(f"{schema_name}.type", "Invalid type") raise verrors else: type = TYPES[data["type"]] attributes_verrors = validate_attributes(type.credentials_schema, data) verrors.add_child(f"{schema_name}.attributes", attributes_verrors) if verrors: raise verrors await type.validate_and_pre_save(self.middleware, verrors, f"{schema_name}.attributes", data["attributes"]) if verrors: raise verrors
async def _basic_validate(self, verrors, name, data): if data["encryption"]: if not data["encryption_password"]: verrors.add(f"{name}.encryption_password", "This field is required when encryption is enabled") credentials = await self._get_credentials(data["credentials"]) if not credentials: verrors.add(f"{name}.credentials", "Invalid credentials") try: shlex.split(data["args"]) except ValueError as e: verrors.add(f"{name}.args", f"Parse error: {e.args[0]}") if verrors: raise verrors provider = REMOTES[credentials["provider"]] schema = [] if provider.buckets: schema.append(Str("bucket", required=True, empty=False)) schema.append(Str("folder", required=True)) schema.extend(provider.task_schema) schema.extend(self.common_task_schema(provider)) attributes_verrors = validate_attributes(schema, data, additional_attrs=True) if not attributes_verrors: await provider.pre_save_task(data, credentials, verrors) verrors.add_child(f"{name}.attributes", attributes_verrors)
async def validate_attrs(self, data): verrors = ValidationErrors() additional_params = data.get('additional_params') if additional_params: # Let's be very generic here and introduce very basic validation # Expected format is as following # [ipv6.icmpneighbor] # history = 86400 # enabled = yes # # While we are here, we will also introduce basic formatting to the file to ensure # that we can make it as compliable as possible param_str = '' for i in additional_params.split('\n'): i = i.strip() if not i: continue if i.startswith('#'): # Let's not validate this if i.replace('#', '').startswith('['): param_str += f'\n\n{i}' else: param_str += f'\n\t{i}' continue if i.startswith('[') and not i.endswith(']'): verrors.add( 'netdata_update.additional_params', f'Please correct format for {i}. i.e [system.intr]') elif not i.startswith('[') and '=' not in i: verrors.add( 'netdata_update.additional_params', f'Please correct format for {i}. i.e enabled = yes') if i.startswith('['): param_str += f'\n\n{i}' else: param_str += f'\n\t{i}' data['additional_params'] = param_str + '\n' bind_to_ips = data.get('bind') if bind_to_ips: valid_ips = [ ip['address'] for ip in await self.middleware.call('interfaces.ip_in_use') ] valid_ips.extend(['127.0.0.1', '::1', '0.0.0.0', '::']) for bind_ip in bind_to_ips: if bind_ip not in valid_ips: verrors.add('netdata_update.bind', f'Invalid {bind_ip} bind IP') else: verrors.add('netdata_update.bind', 'This field is required') update_alarms = data.pop('update_alarms', {}) valid_alarms = self._alarms if update_alarms: for alarm in update_alarms: if alarm not in valid_alarms: verrors.add('netdata_update.alarms', f'{alarm} not a valid alarm') verrors.extend( validate_attributes([ Dict(key, Bool('enabled', required=True)) for key in update_alarms ], {'attributes': update_alarms})) # Validating streaming metrics now stream_mode = data.get('stream_mode') if stream_mode == 'SLAVE': for key in ('api_key', 'destination'): if not data.get(key): verrors.add( f'netdata_update.{key}', f'{key} is required with stream mode as SLAVE') destinations = data.get('destination') if destinations: ip_addr = IpAddress() port = Port() for dest in destinations: ip = dest.split(':')[0] try: ip_addr(ip) except ValueError as e: verrors.add('netdata_update.destination', str(e)) else: if ':' in dest: try: port(dest.split(':')[1]) except ValueError as e: verrors.add('netdata_update.destination', f'Not a valid port: {e}') elif stream_mode == 'MASTER': for key in ('allow_from', 'api_key'): if not data.get(key): verrors.add( f'netdata_update.{key}', f'{key} is required with stream mode as MASTER') verrors.check() data['alarms'].update(update_alarms) return data
async def validate_attrs(self, data): verrors = ValidationErrors() additional_params = data.get('additional_params') if additional_params: # Let's be very generic here and introduce very basic validation # Expected format is as following # [ipv6.icmpneighbor] # history = 86400 # enabled = yes # # While we are here, we will also introduce basic formatting to the file to ensure # that we can make it as compliable as possible param_str = '' for i in additional_params.split('\n'): i = i.strip() if not i: continue if i.startswith('#'): # Let's not validate this if i.replace('#', '').startswith('['): param_str += f'\n\n{i}' else: param_str += f'\n\t{i}' continue if i.startswith('[') and not i.endswith(']'): verrors.add( 'netdata_update.additional_params', f'Please correct format for {i}. i.e [system.intr]' ) elif not i.startswith('[') and '=' not in i: verrors.add( 'netdata_update.additional_params', f'Please correct format for {i}. i.e enabled = yes' ) if i.startswith('['): param_str += f'\n\n{i}' else: param_str += f'\n\t{i}' data['additional_params'] = param_str + '\n' bind_to_ips = data.get('bind') if bind_to_ips: valid_ips = [ip['address'] for ip in await self.middleware.call('interface.ip_in_use')] valid_ips.extend(['127.0.0.1', '::1', '0.0.0.0', '::']) for bind_ip in bind_to_ips: if bind_ip not in valid_ips: verrors.add( 'netdata_update.bind', f'Invalid {bind_ip} bind IP' ) else: verrors.add( 'netdata_update.bind', 'This field is required' ) update_alarms = data.pop('update_alarms', {}) valid_alarms = self._alarms if update_alarms: for alarm in update_alarms: if alarm not in valid_alarms: verrors.add( 'netdata_update.alarms', f'{alarm} not a valid alarm' ) verrors.extend( validate_attributes( [Dict(key, Bool('enabled', required=True)) for key in update_alarms], {'attributes': update_alarms} ) ) # Validating streaming metrics now stream_mode = data.get('stream_mode') if stream_mode == 'SLAVE': for key in ('api_key', 'destination'): if not data.get(key): verrors.add( f'netdata_update.{key}', f'{key} is required with stream mode as SLAVE' ) destinations = data.get('destination') if destinations: ip_addr = IpAddress() port = Port() for dest in destinations: ip = dest.split(':')[0] try: ip_addr(ip) except ValueError as e: verrors.add( 'netdata_update.destination', str(e) ) else: if ':' in dest: try: port(int(dest.split(':')[1])) except ValueError as e: verrors.add( 'netdata_update.destination', f'Not a valid port: {e}' ) elif stream_mode == 'MASTER': for key in ('allow_from', 'api_key'): if not data.get(key): verrors.add( f'netdata_update.{key}', f'{key} is required with stream mode as MASTER' ) verrors.check() data['alarms'].update(update_alarms) return data