def modify_policy_set_family_selection( self, policy_id: str, families: List[Tuple[str, bool, bool]], *, auto_add_new_families: Optional[bool] = True, ) -> Any: """ Selected the NVTs of a policy at a family level. Arguments: policy_id: UUID of policy to modify. families: A list of tuples with the first entry being the name of the NVT family selected, second entry a boolean indicating whether new NVTs should be added to the family automatically, and third entry a boolean indicating whether all nvts from the family should be included. auto_add_new_families: Whether new families should be added to the policy automatically. Default: True. """ if not policy_id: raise RequiredArgument( function=self.modify_policy_set_family_selection.__name__, argument="policy_id", ) if not is_list_like(families): raise InvalidArgumentType( function=self.modify_policy_set_family_selection.__name__, argument="families", arg_type="list", ) cmd = XmlCommand("modify_config") cmd.set_attribute("config_id", str(policy_id)) _xmlfamsel = cmd.add_element("family_selection") _xmlfamsel.add_element("growing", to_bool(auto_add_new_families)) for family in families: _xmlfamily = _xmlfamsel.add_element("family") _xmlfamily.add_element("name", family[0]) if len(family) != 3: raise InvalidArgument( "Family must be a tuple of 3. (str, bool, bool)") if not isinstance(family[1], bool) or not isinstance( family[2], bool): raise InvalidArgumentType( function=( self.modify_policy_set_family_selection.__name__), argument="families", arg_type="[tuple(str, bool, bool)]", ) _xmlfamily.add_element("all", to_bool(family[2])) _xmlfamily.add_element("growing", to_bool(family[1])) return self._send_xml_command(cmd)
def modify_scan_config_set_family_selection( self, config_id: str, families: List[Tuple[str, bool, bool]], *, auto_add_new_families: Optional[bool] = True, ) -> Any: """ Selected the NVTs of a scan config at a family level. Arguments: config_id: UUID of scan config to modify. families: A list of tuples (str, bool, bool): str: the name of the NVT family selected, bool: add new NVTs to the family automatically, bool: include all NVTs from the family auto_add_new_families: Whether new families should be added to the scan config automatically. Default: True. """ if not config_id: raise RequiredArgument( function=self.modify_scan_config_set_family_selection.__name__, argument="config_id", ) if not is_list_like(families): raise InvalidArgumentType( function=self.modify_scan_config_set_family_selection.__name__, argument="families", arg_type="list", ) cmd = XmlCommand("modify_config") cmd.set_attribute("config_id", str(config_id)) _xmlfamsel = cmd.add_element("family_selection") _xmlfamsel.add_element("growing", to_bool(auto_add_new_families)) for family in families: _xmlfamily = _xmlfamsel.add_element("family") _xmlfamily.add_element("name", family[0]) if len(family) != 3: raise InvalidArgument( "Family must be a tuple of 3. (str, bool, bool)") if not isinstance(family[1], bool) or not isinstance( family[2], bool): raise InvalidArgumentType( function=( self.modify_scan_config_set_family_selection.__name__), argument="families", arg_type="[tuple(str, bool, bool)]", ) _xmlfamily.add_element("all", to_bool(family[2])) _xmlfamily.add_element("growing", to_bool(family[1])) return self._send_xml_command(cmd)
def test_string_conversion(self): with self.assertRaises(InvalidArgumentType) as cm: raise InvalidArgumentType("foo", "bar") ex = cm.exception self.assertEqual(str(ex), "The argument foo must be of type bar.") self.assertIsNone(ex.function) with self.assertRaises(InvalidArgumentType) as cm: raise InvalidArgumentType("foo", "bar", function="baz") ex = cm.exception self.assertEqual(str(ex), "In baz the argument foo must be of type bar.")
def test_string_conversion(self): with self.assertRaises(InvalidArgumentType) as cm: raise InvalidArgumentType('foo', 'bar') ex = cm.exception self.assertEqual(str(ex), 'The argument foo must be of type bar.') self.assertIsNone(ex.function) with self.assertRaises(InvalidArgumentType) as cm: raise InvalidArgumentType('foo', 'bar', function='baz') ex = cm.exception self.assertEqual(str(ex), 'In baz the argument foo must be of type bar.')
def help( self, *, help_format: Optional[HelpFormat] = None, brief: Optional[bool] = None, ) -> Any: """Get the help text Arguments: help_format: Format of of the help: "html", "rnc", "text" or "xml brief: If True help is brief Returns: The response. See :py:meth:`send_command` for details. """ cmd = XmlCommand("help") help_type = "" if brief: help_type = "brief" cmd.set_attribute("type", help_type) if help_format: if not isinstance(help_format, HelpFormat): raise InvalidArgumentType( function=self.help.__name__, argument="feed_type", arg_type=HelpFormat.__name__, ) cmd.set_attribute("format", help_format.value) return self._send_xml_command(cmd)
def get_info(self, info_id: str, info_type: InfoType) -> Any: """Request a single secinfo Arguments: info_id: UUID of an existing secinfo info_type: Type must be either CERT_BUND_ADV, CPE, CVE, DFN_CERT_ADV, OVALDEF, NVT Returns: The response. See :py:meth:`send_command` for details. """ if not info_type: raise RequiredArgument(function=self.get_info.__name__, argument='info_type') if not isinstance(info_type, InfoType): raise InvalidArgumentType( function=self.get_info.__name__, argument='info_type', arg_type=InfoType.__name__, ) if not info_id: raise RequiredArgument(function=self.get_info.__name__, argument='info_id') cmd = XmlCommand("get_info") cmd.set_attribute("info_id", info_id) cmd.set_attribute("type", info_type.value) # for single entity always request all details cmd.set_attribute("details", "1") return self._send_xml_command(cmd)
def modify_ticket( self, ticket_id: str, *, status: Optional[TicketStatus] = None, note: Optional[str] = None, assigned_to_user_id: Optional[str] = None, comment: Optional[str] = None ) -> Any: """Modify a single ticket Arguments: ticket_id: UUID of an existing ticket status: New status for the ticket note: Note for the status change. Required if status is set. assigned_to_user_id: UUID of the user the ticket should be assigned to comment: Comment for the ticket Returns: The response. See :py:meth:`send_command` for details. """ if not ticket_id: raise RequiredArgument( function=self.modify_ticket.__name__, argument='ticket_id' ) if status and not note: raise RequiredArgument( function=self.modify_ticket.__name__, argument='note', ) if note and not status: raise RequiredArgument( function=self.modify_ticket.__name__, argument='status', ) cmd = XmlCommand("modify_ticket") cmd.set_attribute("ticket_id", ticket_id) if assigned_to_user_id: _assigned = cmd.add_element("assigned_to") _user = _assigned.add_element("user") _user.set_attribute("id", assigned_to_user_id) if status: if not isinstance(status, TicketStatus): raise InvalidArgumentType( function=self.modify_ticket.__name__, argument='status', arg_type=TicketStatus.__name__, ) cmd.add_element('status', status.value) cmd.add_element('{}_note'.format(status.name.lower()), note) if comment: cmd.add_element("comment", comment) return self._send_xml_command(cmd)
def create_port_range( self, port_list_id: str, start: int, end: int, port_range_type: PortRangeType, *, comment: Optional[str] = None, ) -> Any: """Create new port range Arguments: port_list_id: UUID of the port list to which to add the range start: The first port in the range end: The last port in the range port_range_type: The type of the ports: TCP, UDP, ... comment: Comment for the port range Returns: The response. See :py:meth:`send_command` for details. """ if not port_list_id: raise RequiredArgument( function=self.create_port_range.__name__, argument="port_list_id", ) if not port_range_type: raise RequiredArgument( function=self.create_port_range.__name__, argument="port_range_type", ) if not start: raise RequiredArgument(function=self.create_port_range.__name__, argument="start") if not end: raise RequiredArgument(function=self.create_port_range.__name__, argument="end") if not isinstance(port_range_type, PortRangeType): raise InvalidArgumentType( function=self.create_port_range.__name__, argument="port_range_type", arg_type=PortRangeType.__name__, ) cmd = XmlCommand("create_port_range") cmd.add_element("port_list", attrs={"id": port_list_id}) cmd.add_element("start", str(start)) cmd.add_element("end", str(end)) cmd.add_element("type", port_range_type.value) if comment: cmd.add_element("comment", comment) return self._send_xml_command(cmd)
def pretty_print( xml: Union[str, List[Union[Element, str]], Element], file: IOBase = sys.stdout, ): """Prints beautiful XML-Code This function gets a string containing the xml, an object of List[lxml.etree.Element] or directly a lxml element. Print it with good readable format. Arguments: xml (str, List[lxml.etree.Element] or lxml.etree.Element): xml as string, List[lxml.etree.Element] or directly a lxml element. file: A IOBase type. Can be a File, StringIO, ... """ if not isinstance(file, IOBase): raise TypeError( f"Type needs to be from IOBase, not {type(file)}.") from None if isinstance(xml, list): for item in xml: if isxmlelement(item): file.write( xmltostring( item, pretty_print=True).decode(sys.getdefaultencoding() + "\n")) else: file.write(item + "\n") elif isxmlelement(xml): file.write( xmltostring(xml, pretty_print=True).decode(sys.getdefaultencoding() + "\n")) elif isinstance(xml, str): tree = secET.fromstring(xml) file.write( xmltostring(tree, pretty_print=True).decode(sys.getdefaultencoding() + "\n")) else: raise InvalidArgumentType(function=pretty_print.__name__, argument="xml", arg_type="")
def modify_filter( self, filter_id: str, *, comment: Optional[str] = None, name: Optional[str] = None, term: Optional[str] = None, filter_type: Optional[FilterType] = None, ) -> Any: """Modifies an existing filter. Arguments: filter_id: UUID of the filter to be modified comment: Comment on filter. name: Name of filter. term: Filter term. filter_type: Resource type filter applies to. Returns: The response. See :py:meth:`send_command` for details. """ if not filter_id: raise RequiredArgument( function=self.modify_filter.__name__, argument="filter_id" ) cmd = XmlCommand("modify_filter") cmd.set_attribute("filter_id", filter_id) if comment: cmd.add_element("comment", comment) if name: cmd.add_element("name", name) if term: cmd.add_element("term", term) if filter_type: if not isinstance(filter_type, FilterType): raise InvalidArgumentType( function=self.modify_filter.__name__, argument="filter_type", arg_type=FilterType.__name__, ) cmd.add_element("type", filter_type.value) return self._send_xml_command(cmd)
def get_info_list( self, info_type: InfoType, *, filter: Optional[str] = None, filter_id: Optional[str] = None, name: Optional[str] = None, details: Optional[bool] = None, ) -> Any: """Request a list of security information Arguments: info_type: Type must be either CERT_BUND_ADV, CPE, CVE, DFN_CERT_ADV, OVALDEF, NVT or ALLINFO filter: Filter term to use for the query filter_id: UUID of an existing filter to use for the query name: Name or identifier of the requested information details: Whether to include information about references to this information Returns: The response. See :py:meth:`send_command` for details. """ if not info_type: raise RequiredArgument(function=self.get_info_list.__name__, argument='info_type') if not isinstance(info_type, InfoType): raise InvalidArgumentType( function=self.get_info_list.__name__, argument='info_type', arg_type=InfoType.__name__, ) cmd = XmlCommand("get_info") cmd.set_attribute("type", info_type.value) _add_filter(cmd, filter, filter_id) if name: cmd.set_attribute("name", name) if details is not None: cmd.set_attribute("details", _to_bool(details)) return self._send_xml_command(cmd)
def create_filter( self, name: str, *, filter_type: Optional[FilterType] = None, comment: Optional[str] = None, term: Optional[str] = None, ) -> Any: """Create a new filter Arguments: name: Name of the new filter filter_type: Filter for entity type comment: Comment for the filter term: Filter term e.g. 'name=foo' Returns: The response. See :py:meth:`send_command` for details. """ if not name: raise RequiredArgument( function=self.create_filter.__name__, argument="name" ) cmd = XmlCommand("create_filter") _xmlname = cmd.add_element("name", name) if comment: cmd.add_element("comment", comment) if term: cmd.add_element("term", term) if filter_type: if not isinstance(filter_type, FilterType): raise InvalidArgumentType( function=self.create_filter.__name__, argument="filter_type", arg_type=FilterType.__name__, ) cmd.add_element("type", filter_type.value) return self._send_xml_command(cmd)
def get_credential( self, credential_id: str, *, scanners: Optional[bool] = None, targets: Optional[bool] = None, credential_format: Optional[CredentialFormat] = None, ) -> Any: """Request a single credential Arguments: credential_id: UUID of an existing credential scanners: Whether to include a list of scanners using the credentials targets: Whether to include a list of targets using the credentials credential_format: One of "key", "rpm", "deb", "exe" or "pem" Returns: The response. See :py:meth:`send_command` for details. """ if not credential_id: raise RequiredArgument(function=self.get_credential.__name__, argument="credential_id") cmd = XmlCommand("get_credentials") cmd.set_attribute("credential_id", credential_id) if credential_format: if not isinstance(credential_format, CredentialFormat): raise InvalidArgumentType( function=self.get_credential.__name__, argument="credential_format", arg_type=CredentialFormat.__name__, ) cmd.set_attribute("format", credential_format.value) if scanners is not None: cmd.set_attribute("scanners", to_bool(scanners)) if targets is not None: cmd.set_attribute("targets", to_bool(targets)) return self._send_xml_command(cmd)
def modify_scan_config_set_nvt_selection(self, config_id: str, family: str, nvt_oids: List[str]) -> Any: """Modifies the selected nvts of an existing scan config The manager updates the given family in the config to include only the given NVTs. Arguments: config_id: UUID of scan config to modify. family: Name of the NVT family to include NVTs from nvt_oids: List of NVTs to select for the family. """ if not config_id: raise RequiredArgument( function=self.modify_scan_config_set_nvt_selection.__name__, argument="config_id", ) if not family: raise RequiredArgument( function=self.modify_scan_config_set_nvt_selection.__name__, argument="family argument", ) if not is_list_like(nvt_oids): raise InvalidArgumentType( function=self.modify_scan_config_set_nvt_selection.__name__, argument="nvt_oids", arg_type="list", ) cmd = XmlCommand("modify_config") cmd.set_attribute("config_id", str(config_id)) _xmlnvtsel = cmd.add_element("nvt_selection") _xmlnvtsel.add_element("family", family) for nvt in nvt_oids: _xmlnvtsel.add_element("nvt", attrs={"oid": nvt}) return self._send_xml_command(cmd)
def create_tag(self, name: str, resource_type: EntityType, *, resource_filter: Optional[str] = None, resource_ids: Optional[List[str]] = None, value: Optional[str] = None, comment: Optional[str] = None, active: Optional[bool] = None) -> Any: """Create a tag. Arguments: name: Name of the tag. A full tag name consisting of namespace and predicate e.g. `foo:bar`. resource_type: Entity type the tag is to be attached to. resource_filter: Filter term to select resources the tag is to be attached to. Only one of resource_filter or resource_ids can be provided. resource_ids: IDs of the resources the tag is to be attached to. Only one of resource_filter or resource_ids can be provided. value: Value associated with the tag. comment: Comment for the tag. active: Whether the tag should be active. Returns: The response. See :py:meth:`send_command` for details. """ if not name: raise RequiredArgument(function=self.create_tag.__name__, argument='name') if resource_filter and resource_ids: raise InvalidArgument( "create_tag accepts either resource_filter or resource_ids " "argument", function=self.create_tag.__name__, ) if not resource_type: raise RequiredArgument(function=self.create_tag.__name__, argument='resource_type') if not isinstance(resource_type, self.types.EntityType): raise InvalidArgumentType( function=self.create_tag.__name__, argument='resource_type', arg_type=EntityType.__name__, ) cmd = XmlCommand('create_tag') cmd.add_element('name', name) _xmlresources = cmd.add_element("resources") if resource_filter is not None: _xmlresources.set_attribute("filter", resource_filter) for resource_id in resource_ids or []: _xmlresources.add_element("resource", attrs={"id": str(resource_id)}) _xmlresources.add_element("type", resource_type.value) if comment: cmd.add_element("comment", comment) if value: cmd.add_element("value", value) if active is not None: if active: cmd.add_element("active", "1") else: cmd.add_element("active", "0") return self._send_xml_command(cmd)
def modify_credential( self, credential_id: str, *, name: Optional[str] = None, comment: Optional[str] = None, allow_insecure: Optional[bool] = None, certificate: Optional[str] = None, key_phrase: Optional[str] = None, private_key: Optional[str] = None, login: Optional[str] = None, password: Optional[str] = None, auth_algorithm: Optional[SnmpAuthAlgorithm] = None, community: Optional[str] = None, privacy_algorithm: Optional[SnmpPrivacyAlgorithm] = None, privacy_password: Optional[str] = None, public_key: Optional[str] = None) -> Any: """Modifies an existing credential. Arguments: credential_id: UUID of the credential name: Name of the credential comment: Comment for the credential allow_insecure: Whether to allow insecure use of the credential certificate: Certificate for the credential key_phrase: Key passphrase for the private key private_key: Private key to use for login login: Username for the credential password: Password for the credential auth_algorithm: The authentication algorithm for SNMP community: The SNMP community privacy_algorithm: The privacy algorithm for SNMP privacy_password: The SNMP privacy password public_key: PGP public key in *armor* plain text format Returns: The response. See :py:meth:`send_command` for details. """ if not credential_id: raise RequiredArgument( function=self.modify_credential.__name__, argument='credential_id', ) cmd = XmlCommand("modify_credential") cmd.set_attribute("credential_id", credential_id) if comment: cmd.add_element("comment", comment) if name: cmd.add_element("name", name) if allow_insecure is not None: cmd.add_element("allow_insecure", _to_bool(allow_insecure)) if certificate: cmd.add_element("certificate", certificate) if key_phrase and private_key: _xmlkey = cmd.add_element("key") _xmlkey.add_element("phrase", key_phrase) _xmlkey.add_element("private", private_key) elif (not key_phrase and private_key) or (key_phrase and not private_key): raise RequiredArgument( function=self.modify_credential.__name__, argument='key_phrase and private_key', ) if login: cmd.add_element("login", login) if password: cmd.add_element("password", password) if auth_algorithm: if not isinstance(auth_algorithm, self.types.SnmpAuthAlgorithm): raise InvalidArgumentType( function=self.modify_credential.__name__, argument='auth_algorithm', arg_type=SnmpAuthAlgorithm.__name__, ) cmd.add_element("auth_algorithm", auth_algorithm.value) if community: cmd.add_element("community", community) if privacy_algorithm is not None or privacy_password is not None: _xmlprivacy = cmd.add_element("privacy") if privacy_algorithm is not None: if not isinstance(privacy_algorithm, self.types.SnmpPrivacyAlgorithm): raise InvalidArgumentType( function=self.modify_credential.__name__, argument='privacy_algorithm', arg_type=SnmpPrivacyAlgorithm.__name__, ) _xmlprivacy.add_element("algorithm", privacy_algorithm.value) if privacy_password is not None: _xmlprivacy.add_element("password", privacy_password) if public_key: _xmlkey = cmd.add_element("key") _xmlkey.add_element("public", public_key) return self._send_xml_command(cmd)
def __create_task(self, name: str, config_id: str, target_id: str, scanner_id: str, usage_type: UsageType, function: str, *, alterable: Optional[bool] = None, hosts_ordering: Optional[HostsOrdering] = None, schedule_id: Optional[str] = None, alert_ids: Optional[List[str]] = None, comment: Optional[str] = None, schedule_periods: Optional[int] = None, observers: Optional[List[str]] = None, preferences: Optional[dict] = None) -> Any: if not name: raise RequiredArgument(function=function, argument='name') if not config_id: raise RequiredArgument(function=function, argument='config_id') if not target_id: raise RequiredArgument(function=function, argument='target_id') if not scanner_id: raise RequiredArgument(function=function, argument='scanner_id') # don't allow to create a container task with create_task if target_id == '0': raise InvalidArgument(function=function, argument='target_id') cmd = XmlCommand("create_task") cmd.add_element("name", name) cmd.add_element("usage_type", usage_type.value) cmd.add_element("config", attrs={"id": config_id}) cmd.add_element("target", attrs={"id": target_id}) cmd.add_element("scanner", attrs={"id": scanner_id}) if comment: cmd.add_element("comment", comment) if alterable is not None: cmd.add_element("alterable", _to_bool(alterable)) if hosts_ordering: if not isinstance(hosts_ordering, HostsOrdering): raise InvalidArgumentType( function=function, argument='hosts_ordering', arg_type=HostsOrdering.__name__, ) cmd.add_element("hosts_ordering", hosts_ordering.value) if alert_ids: if isinstance(alert_ids, str): deprecation( "Please pass a list as alert_ids parameter to {}. " "Passing a string is deprecated and will be removed in " "future.".format(function)) # if a single id is given as a string wrap it into a list alert_ids = [alert_ids] if _is_list_like(alert_ids): # parse all given alert id's for alert in alert_ids: cmd.add_element("alert", attrs={"id": str(alert)}) if schedule_id: cmd.add_element("schedule", attrs={"id": schedule_id}) if schedule_periods is not None: if (not isinstance(schedule_periods, numbers.Integral) or schedule_periods < 0): raise InvalidArgument( "schedule_periods must be an integer greater or equal " "than 0") cmd.add_element("schedule_periods", str(schedule_periods)) if observers is not None: if not _is_list_like(observers): raise InvalidArgumentType(function=function, argument='observers', arg_type='list') # gvmd splits by comma and space # gvmd tries to lookup each value as user name and afterwards as # user id. So both user name and user id are possible cmd.add_element("observers", _to_comma_list(observers)) if preferences is not None: if not isinstance(preferences, collections.abc.Mapping): raise InvalidArgumentType( function=function, argument='preferences', arg_type=collections.abc.Mapping.__name__, ) _xmlprefs = cmd.add_element("preferences") for pref_name, pref_value in preferences.items(): _xmlpref = _xmlprefs.add_element("preference") _xmlpref.add_element("scanner_name", pref_name) _xmlpref.add_element("value", str(pref_value)) return self._send_xml_command(cmd)
def test_raise_with_argument_and_arg_type(self): with self.assertRaisesRegex(InvalidArgumentType, "^The argument foo must be of type bar.$"): raise InvalidArgumentType("foo", "bar")
def create_scanner( self, name: str, host: str, port: int, scanner_type: ScannerType, credential_id: str, *, ca_pub: Optional[str] = None, comment: Optional[str] = None, ) -> Any: """Create a new scanner Arguments: name: Name of the scanner host: The host of the scanner port: The port of the scanner scanner_type: Type of the scanner. credential_id: UUID of client certificate credential for the scanner ca_pub: Certificate of CA to verify scanner certificate comment: Comment for the scanner Returns: The response. See :py:meth:`send_command` for details. """ if not name: raise RequiredArgument(function=self.create_scanner.__name__, argument="name") if not host: raise RequiredArgument(function=self.create_scanner.__name__, argument="host") if not port: raise RequiredArgument(function=self.create_scanner.__name__, argument="port") if not scanner_type: raise RequiredArgument(function=self.create_scanner.__name__, argument="scanner_type") if not credential_id: raise RequiredArgument(function=self.create_scanner.__name__, argument="credential_id") if not isinstance(scanner_type, ScannerType): raise InvalidArgumentType( function=self.create_scanner.__name__, argument="scanner_type", arg_type=ScannerType.__name__, ) cmd = XmlCommand("create_scanner") cmd.add_element("name", name) cmd.add_element("host", host) cmd.add_element("port", str(port)) cmd.add_element("type", scanner_type.value) if ca_pub: cmd.add_element("ca_pub", ca_pub) cmd.add_element("credential", attrs={"id": str(credential_id)}) if comment: cmd.add_element("comment", comment) return self._send_xml_command(cmd)
def create_note( self, text: str, nvt_oid: str, *, days_active: Optional[int] = None, hosts: Optional[List[str]] = None, port: Optional[str] = None, result_id: Optional[str] = None, severity: Optional[Severity] = None, task_id: Optional[str] = None, threat: Optional[SeverityLevel] = None, ) -> Any: """Create a new note Arguments: text: Text of the new note nvt_id: OID of the nvt to which note applies days_active: Days note will be active. -1 on always, 0 off hosts: A list of hosts addresses port: Port to which the override applies, needs to be a string in the form {number}/{protocol} result_id: UUID of a result to which note applies severity: Severity to which note applies task_id: UUID of task to which note applies threat: Severity level to which note applies. Will be converted to severity. Returns: The response. See :py:meth:`send_command` for details. """ if not text: raise RequiredArgument( function=self.create_note.__name__, argument="text" ) if not nvt_oid: raise RequiredArgument( function=self.create_note.__name__, argument="nvt_oid" ) cmd = XmlCommand("create_note") cmd.add_element("text", text) cmd.add_element("nvt", attrs={"oid": nvt_oid}) if days_active is not None: cmd.add_element("active", str(days_active)) if hosts: cmd.add_element("hosts", to_comma_list(hosts)) if port: if check_port(port): cmd.add_element("port", str(port)) else: raise InvalidArgument( function=self.create_note.__name__, argument="port" ) if result_id: cmd.add_element("result", attrs={"id": result_id}) if severity is not None: cmd.add_element("severity", str(severity)) if task_id: cmd.add_element("task", attrs={"id": task_id}) if threat is not None: if not isinstance(threat, SeverityLevel): raise InvalidArgumentType( function="create_note", argument="threat", arg_type=SeverityLevel.__name__, ) cmd.add_element("threat", threat.value) return self._send_xml_command(cmd)
def modify_scanner( self, scanner_id: str, *, scanner_type: Optional[ScannerType] = None, host: Optional[str] = None, port: Optional[int] = None, comment: Optional[str] = None, name: Optional[str] = None, ca_pub: Optional[str] = None, credential_id: Optional[str] = None, ) -> Any: """Modifies an existing scanner. Arguments: scanner_id: UUID of scanner to modify. scanner_type: New type of the Scanner. host: Host of the scanner. port: Port of the scanner. comment: Comment on scanner. name: Name of scanner. ca_pub: Certificate of CA to verify scanner's certificate. credential_id: UUID of the client certificate credential for the Scanner. Returns: The response. See :py:meth:`send_command` for details. """ if not scanner_id: raise RequiredArgument( function=self.modify_scanner.__name__, argument="scanner_id argument", ) cmd = XmlCommand("modify_scanner") cmd.set_attribute("scanner_id", scanner_id) if scanner_type is not None: if not isinstance(scanner_type, ScannerType): raise InvalidArgumentType( function=self.modify_scanner.__name__, argument="scanner_type", arg_type=ScannerType.__name__, ) cmd.add_element("type", scanner_type.value) if host: cmd.add_element("host", host) if port: cmd.add_element("port", str(port)) if comment: cmd.add_element("comment", comment) if name: cmd.add_element("name", name) if ca_pub: cmd.add_element("ca_pub", ca_pub) if credential_id: cmd.add_element("credential", attrs={"id": str(credential_id)}) return self._send_xml_command(cmd)
def test_raise_with_function(self): with self.assertRaisesRegex( InvalidArgumentType, "^In baz the argument foo must be of type bar.$", ): raise InvalidArgumentType("foo", "bar", function="baz")
def create_target( self, name: str, *, make_unique: Optional[bool] = None, asset_hosts_filter: Optional[str] = None, hosts: Optional[List[str]] = None, comment: Optional[str] = None, exclude_hosts: Optional[List[str]] = None, ssh_credential_id: Optional[str] = None, ssh_credential_port: Optional[int] = None, smb_credential_id: Optional[str] = None, esxi_credential_id: Optional[str] = None, snmp_credential_id: Optional[str] = None, alive_test: Optional[AliveTest] = None, reverse_lookup_only: Optional[bool] = None, reverse_lookup_unify: Optional[bool] = None, port_range: Optional[str] = None, port_list_id: Optional[str] = None, ) -> Any: """Create a new target Arguments: name: Name of the target make_unique: Deprecated. Will be ignored. asset_hosts_filter: Filter to select target host from assets hosts hosts: List of hosts addresses to scan exclude_hosts: List of hosts addresses to exclude from scan comment: Comment for the target ssh_credential_id: UUID of a ssh credential to use on target ssh_credential_port: The port to use for ssh credential smb_credential_id: UUID of a smb credential to use on target snmp_credential_id: UUID of a snmp credential to use on target esxi_credential_id: UUID of a esxi credential to use on target alive_test: Which alive test to use reverse_lookup_only: Whether to scan only hosts that have names reverse_lookup_unify: Whether to scan only one IP when multiple IPs have the same name. port_range: Port range for the target port_list_id: UUID of the port list to use on target Returns: The response. See :py:meth:`send_command` for details. """ cmd = XmlCommand("create_target") _xmlname = cmd.add_element("name", name) if make_unique is not None: warnings.warn( 'create_target make_unique argument is deprecated ' 'and will be ignored.', DeprecationWarning, ) if not name: raise RequiredArgument(function=self.create_target.__name__, argument='name') if asset_hosts_filter: cmd.add_element("asset_hosts", attrs={"filter": str(asset_hosts_filter)}) elif hosts: cmd.add_element("hosts", _to_comma_list(hosts)) else: raise RequiredArgument( function=self.create_target.__name__, argument='hosts or asset_hosts_filter', ) if comment: cmd.add_element("comment", comment) if exclude_hosts: cmd.add_element("exclude_hosts", _to_comma_list(exclude_hosts)) if ssh_credential_id: _xmlssh = cmd.add_element("ssh_credential", attrs={"id": ssh_credential_id}) if ssh_credential_port: _xmlssh.add_element("port", str(ssh_credential_port)) if smb_credential_id: cmd.add_element("smb_credential", attrs={"id": smb_credential_id}) if esxi_credential_id: cmd.add_element("esxi_credential", attrs={"id": esxi_credential_id}) if snmp_credential_id: cmd.add_element("snmp_credential", attrs={"id": snmp_credential_id}) if alive_test: if not isinstance(alive_test, AliveTest): raise InvalidArgumentType( function=self.create_target.__name__, argument='alive_test', arg_type=AliveTest.__name__, ) cmd.add_element("alive_tests", alive_test.value) if reverse_lookup_only is not None: cmd.add_element("reverse_lookup_only", _to_bool(reverse_lookup_only)) if reverse_lookup_unify is not None: cmd.add_element("reverse_lookup_unify", _to_bool(reverse_lookup_unify)) # since 20.08 one of port_range or port_list_id is required! if not port_range and not port_list_id: raise RequiredArgument( function=self.create_target.__name__, argument='port_range or port_list_id', ) if port_range: cmd.add_element("port_range", port_range) if port_list_id: cmd.add_element("port_list", attrs={"id": port_list_id}) return self._send_xml_command(cmd)
def test_is_gvm_error(self): with self.assertRaises(GvmError): raise InvalidArgumentType("foo", "bar")
def create_task( self, name: str, config_id: str, target_id: str, scanner_id: str, *, alterable: Optional[bool] = None, hosts_ordering: Optional[HostsOrdering] = None, schedule_id: Optional[str] = None, alert_ids: Optional[List[str]] = None, comment: Optional[str] = None, schedule_periods: Optional[int] = None, observers: Optional[List[str]] = None, preferences: Optional[dict] = None, ) -> Any: """Create a new scan task Arguments: name: Name of the new task config_id: UUID of config to use by the task target_id: UUID of target to be scanned scanner_id: UUID of scanner to use for scanning the target comment: Comment for the task alterable: Whether the task should be alterable alert_ids: List of UUIDs for alerts to be applied to the task hosts_ordering: The order hosts are scanned in schedule_id: UUID of a schedule when the task should be run. schedule_periods: A limit to the number of times the task will be scheduled, or 0 for no limit observers: List of names or ids of users which should be allowed to observe this task preferences: Name/Value pairs of scanner preferences. Returns: The response. See :py:meth:`send_command` for details. """ if not name: raise RequiredArgument(function=self.create_task.__name__, argument="name") if not config_id: raise RequiredArgument(function=self.create_task.__name__, argument="config_id") if not target_id: raise RequiredArgument(function=self.create_task.__name__, argument="target_id") if not scanner_id: raise RequiredArgument(function=self.create_task.__name__, argument="scanner_id") # don't allow to create a container task with create_task if target_id == "0": raise InvalidArgument(function=self.create_task.__name__, argument="target_id") cmd = XmlCommand("create_task") cmd.add_element("name", name) cmd.add_element("usage_type", "scan") cmd.add_element("config", attrs={"id": config_id}) cmd.add_element("target", attrs={"id": target_id}) cmd.add_element("scanner", attrs={"id": scanner_id}) if comment: cmd.add_element("comment", comment) if alterable is not None: cmd.add_element("alterable", to_bool(alterable)) if hosts_ordering: if not isinstance(hosts_ordering, HostsOrdering): raise InvalidArgumentType( function=self.create_task.__name__, argument="hosts_ordering", arg_type=HostsOrdering.__name__, ) cmd.add_element("hosts_ordering", hosts_ordering.value) if alert_ids is not None: if not is_list_like(alert_ids): raise InvalidArgumentType( function=self.modify_task.__name__, argument="alert_ids", arg_type="list", ) if not len(alert_ids) == 0: for alert in alert_ids: cmd.add_element("alert", attrs={"id": str(alert)}) if schedule_id: cmd.add_element("schedule", attrs={"id": schedule_id}) if schedule_periods is not None: if (not isinstance(schedule_periods, Integral) or schedule_periods < 0): raise InvalidArgument( "schedule_periods must be an integer greater or equal " "than 0") cmd.add_element("schedule_periods", str(schedule_periods)) if observers is not None: if not is_list_like(observers): raise InvalidArgumentType( function=self.create_task.__name__, argument="observers", arg_type="list", ) # gvmd splits by comma and space # gvmd tries to lookup each value as user name and afterwards as # user id. So both user name and user id are possible cmd.add_element("observers", to_comma_list(observers)) if preferences is not None: if not isinstance(preferences, Mapping): raise InvalidArgumentType( function=self.create_task.__name__, argument="preferences", arg_type=Mapping.__name__, ) _xmlprefs = cmd.add_element("preferences") for pref_name, pref_value in preferences.items(): _xmlpref = _xmlprefs.add_element("preference") _xmlpref.add_element("scanner_name", pref_name) _xmlpref.add_element("value", str(pref_value)) return self._send_xml_command(cmd)
def modify_alert( self, alert_id: str, *, name: Optional[str] = None, comment: Optional[str] = None, filter_id: Optional[str] = None, event: Optional[AlertEvent] = None, event_data: Optional[dict] = None, condition: Optional[AlertCondition] = None, condition_data: Optional[dict] = None, method: Optional[AlertMethod] = None, method_data: Optional[dict] = None ) -> Any: """Modifies an existing alert. Arguments: alert_id: UUID of the alert to be modified. name: Name of the Alert. condition: The condition that must be satisfied for the alert to occur. If the event is either 'Updated SecInfo arrived' or 'New SecInfo arrived', condition must be 'Always'. Otherwise, condition can also be on of 'Severity at least', 'Filter count changed' or 'Filter count at least'. condition_data: Data that defines the condition event: The event that must happen for the alert to occur, one of 'Task run status changed', 'Updated SecInfo arrived' or 'New SecInfo arrived' event_data: Data that defines the event method: The method by which the user is alerted, one of 'SCP', 'Send', 'SMB', 'SNMP', 'Syslog' or 'Email'; if the event is neither 'Updated SecInfo arrived' nor 'New SecInfo arrived', method can also be one of 'Start Task', 'HTTP Get', 'Sourcefire Connector' or 'verinice Connector'. method_data: Data that defines the method filter_id: Filter to apply when executing alert comment: Comment for the alert Returns: The response. See :py:meth:`send_command` for details. """ if not alert_id: raise RequiredArgument( function=self.modify_alert.__name__, argument='alert_id' ) cmd = XmlCommand("modify_alert") cmd.set_attribute("alert_id", str(alert_id)) if name: cmd.add_element("name", name) if comment: cmd.add_element("comment", comment) if filter_id: cmd.add_element("filter", attrs={"id": filter_id}) if condition: if not isinstance(condition, AlertCondition): raise InvalidArgumentType( function=self.modify_alert.__name__, argument='condition', arg_type=AlertCondition.__name__, ) conditions = cmd.add_element("condition", condition.value) if condition_data is not None: for key, value in condition_data.items(): _data = conditions.add_element("data", value) _data.add_element("name", key) if method: if not isinstance(method, AlertMethod): raise InvalidArgumentType( function=self.modify_alert.__name__, argument='method', arg_type=AlertMethod.__name__, ) methods = cmd.add_element("method", method.value) if method_data is not None: for key, value in method_data.items(): _data = methods.add_element("data", value) _data.add_element("name", key) if event: if not isinstance(event, AlertEvent): raise InvalidArgumentType( function=self.modify_alert.__name__, argument='event', arg_type=AlertEvent.__name__, ) _check_event(event, condition, method) events = cmd.add_element("event", event.value) if event_data is not None: for key, value in event_data.items(): _data = events.add_element("data", value) _data.add_element("name", key) return self._send_xml_command(cmd)
def modify_tag(self, tag_id: str, *, comment: Optional[str] = None, name: Optional[str] = None, value=None, active=None, resource_action: Optional[str] = None, resource_type: Optional[EntityType] = None, resource_filter: Optional[str] = None, resource_ids: Optional[List[str]] = None) -> Any: """Modifies an existing tag. Arguments: tag_id: UUID of the tag. comment: Comment to add to the tag. name: Name of the tag. value: Value of the tag. active: Whether the tag is active. resource_action: Whether to add or remove resources instead of overwriting. One of '', 'add', 'set' or 'remove'. resource_type: Type of the resources to which to attach the tag. Required if resource_filter is set. resource_filter: Filter term to select resources the tag is to be attached to. resource_ids: IDs of the resources to which to attach the tag. Returns: The response. See :py:meth:`send_command` for details. """ if not tag_id: raise RequiredArgument(function=self.modify_tag.__name__, argument='tag_id') cmd = XmlCommand("modify_tag") cmd.set_attribute("tag_id", str(tag_id)) if comment: cmd.add_element("comment", comment) if name: cmd.add_element("name", name) if value: cmd.add_element("value", value) if active is not None: cmd.add_element("active", _to_bool(active)) if resource_action or resource_filter or resource_ids or resource_type: if resource_filter and not resource_type: raise RequiredArgument(function=self.modify_tag.__name__, argument='resource_type') _xmlresources = cmd.add_element("resources") if resource_action is not None: _xmlresources.set_attribute("action", resource_action) if resource_filter is not None: _xmlresources.set_attribute("filter", resource_filter) for resource_id in resource_ids or []: _xmlresources.add_element("resource", attrs={"id": str(resource_id)}) if resource_type is not None: if not isinstance(resource_type, self.types.EntityType): raise InvalidArgumentType( function=self.modify_tag.__name__, argument="resource_type", arg_type=EntityType.__name__, ) _xmlresources.add_element("type", resource_type.value) return self._send_xml_command(cmd)
def modify_target( self, target_id: str, *, name: Optional[str] = None, comment: Optional[str] = None, hosts: Optional[List[str]] = None, exclude_hosts: Optional[List[str]] = None, ssh_credential_id: Optional[str] = None, ssh_credential_port: Optional[bool] = None, smb_credential_id: Optional[str] = None, esxi_credential_id: Optional[str] = None, snmp_credential_id: Optional[str] = None, alive_test: Optional[AliveTest] = None, allow_simultaneous_ips: Optional[bool] = None, reverse_lookup_only: Optional[bool] = None, reverse_lookup_unify: Optional[bool] = None, port_list_id: Optional[str] = None, ) -> Any: """Modifies an existing target. Arguments: target_id: ID of target to modify. comment: Comment on target. name: Name of target. hosts: List of target hosts. exclude_hosts: A list of hosts to exclude. ssh_credential_id: UUID of SSH credential to use on target. ssh_credential_port: The port to use for ssh credential smb_credential_id: UUID of SMB credential to use on target. esxi_credential_id: UUID of ESXi credential to use on target. snmp_credential_id: UUID of SNMP credential to use on target. port_list_id: UUID of port list describing ports to scan. alive_test: Which alive tests to use. allow_simultaneous_ips: Whether to scan multiple IPs of the same host simultaneously reverse_lookup_only: Whether to scan only hosts that have names. reverse_lookup_unify: Whether to scan only one IP when multiple IPs have the same name. Returns: The response. See :py:meth:`send_command` for details. """ if not target_id: raise RequiredArgument(function=self.modify_target.__name__, argument="target_id") cmd = XmlCommand("modify_target") cmd.set_attribute("target_id", target_id) if comment: cmd.add_element("comment", comment) if name: cmd.add_element("name", name) if hosts: cmd.add_element("hosts", to_comma_list(hosts)) if exclude_hosts is None: exclude_hosts = [""] if exclude_hosts: cmd.add_element("exclude_hosts", to_comma_list(exclude_hosts)) if alive_test: if not isinstance(alive_test, AliveTest): raise InvalidArgumentType( function=self.modify_target.__name__, argument="alive_test", arg_type=AliveTest.__name__, ) cmd.add_element("alive_tests", alive_test.value) if ssh_credential_id: _xmlssh = cmd.add_element("ssh_credential", attrs={"id": ssh_credential_id}) if ssh_credential_port: _xmlssh.add_element("port", str(ssh_credential_port)) if smb_credential_id: cmd.add_element("smb_credential", attrs={"id": smb_credential_id}) if esxi_credential_id: cmd.add_element("esxi_credential", attrs={"id": esxi_credential_id}) if snmp_credential_id: cmd.add_element("snmp_credential", attrs={"id": snmp_credential_id}) if allow_simultaneous_ips is not None: cmd.add_element("allow_simultaneous_ips", to_bool(allow_simultaneous_ips)) if reverse_lookup_only is not None: cmd.add_element("reverse_lookup_only", to_bool(reverse_lookup_only)) if reverse_lookup_unify is not None: cmd.add_element("reverse_lookup_unify", to_bool(reverse_lookup_unify)) if port_list_id: cmd.add_element("port_list", attrs={"id": port_list_id}) return self._send_xml_command(cmd)
def create_credential( self, name: str, credential_type: CredentialType, *, comment: Optional[str] = None, allow_insecure: Optional[bool] = None, certificate: Optional[str] = None, key_phrase: Optional[str] = None, private_key: Optional[str] = None, login: Optional[str] = None, password: Optional[str] = None, auth_algorithm: Optional[SnmpAuthAlgorithm] = None, community: Optional[str] = None, privacy_algorithm: Optional[SnmpPrivacyAlgorithm] = None, privacy_password: Optional[str] = None, public_key: Optional[str] = None) -> Any: """Create a new credential Create a new credential e.g. to be used in the method of an alert. Currently the following credential types are supported: - Username + Password - Username + SSH-Key - Client Certificates - SNMPv1 or SNMPv2c protocol - S/MIME Certificate - OpenPGP Key - Password only Arguments: name: Name of the new credential credential_type: The credential type. comment: Comment for the credential allow_insecure: Whether to allow insecure use of the credential certificate: Certificate for the credential. Required for client-certificate and smime credential types. key_phrase: Key passphrase for the private key. Used for the username+ssh-key credential type. private_key: Private key to use for login. Required for usk credential type. Also used for the cc credential type. The supported key types (dsa, rsa, ecdsa, ...) and formats (PEM, PKC#12, OpenSSL, ...) depend on your installed GnuTLS version. login: Username for the credential. Required for username+password, username+ssh-key and snmp credential type. password: Password for the credential. Used for username+password and snmp credential types. community: The SNMP community auth_algorithm: The SNMP authentication algorithm. Required for snmp credential type. privacy_algorithm: The SNMP privacy algorithm privacy_password: The SNMP privacy password public_key: PGP public key in *armor* plain text format. Required for pgp credential type. Examples: Creating a Username + Password credential .. code-block:: python gmp.create_credential( name='UP Credential', credential_type=CredentialType.USERNAME_PASSWORD, login='******', password='******', ); Creating a Username + SSH Key credential .. code-block:: python with open('path/to/private-ssh-key') as f: key = f.read() gmp.create_credential( name='USK Credential', credential_type=CredentialType.USERNAME_SSH_KEY, login='******', key_phrase='foobar', private_key=key, ) Creating a PGP credential .. note:: A compatible public pgp key file can be exported with GnuPG via :: $ gpg --armor --export [email protected] > alice.asc .. code-block:: python with open('path/to/pgp.key.asc') as f: key = f.read() gmp.create_credential( name='PGP Credential', credential_type=CredentialType.PGP_ENCRYPTION_KEY, public_key=key, ) Creating a S/MIME credential .. code-block:: python with open('path/to/smime-cert') as f: cert = f.read() gmp.create_credential( name='SMIME Credential', credential_type=CredentialType.SMIME_CERTIFICATE, certificate=cert, ) Creating a Password-Only credential .. code-block:: python gmp.create_credential( name='Password-Only Credential', credential_type=CredentialType.PASSWORD_ONLY, password='******', ) Returns: The response. See :py:meth:`send_command` for details. """ if not name: raise RequiredArgument(function=self.create_credential.__name__, argument='name') if not isinstance(credential_type, self.types.CredentialType): raise InvalidArgumentType( function=self.create_credential.__name__, argument='credential_type', arg_type=CredentialType.__name__, ) cmd = XmlCommand("create_credential") cmd.add_element("name", name) cmd.add_element("type", credential_type.value) if comment: cmd.add_element("comment", comment) if allow_insecure is not None: cmd.add_element("allow_insecure", _to_bool(allow_insecure)) if (credential_type == CredentialType.CLIENT_CERTIFICATE or credential_type == CredentialType.SMIME_CERTIFICATE): if not certificate: raise RequiredArgument( function=self.create_credential.__name__, argument='certificate', ) cmd.add_element("certificate", certificate) if (credential_type == CredentialType.USERNAME_PASSWORD or credential_type == CredentialType.USERNAME_SSH_KEY or credential_type == CredentialType.SNMP): if not login: raise RequiredArgument( function=self.create_credential.__name__, argument='login') cmd.add_element("login", login) if credential_type == CredentialType.PASSWORD_ONLY and not password: raise RequiredArgument(function=self.create_credential.__name__, argument='password') if (credential_type == CredentialType.USERNAME_PASSWORD or credential_type == CredentialType.SNMP or credential_type == CredentialType.PASSWORD_ONLY) and password: cmd.add_element("password", password) if credential_type == CredentialType.USERNAME_SSH_KEY: if not private_key: raise RequiredArgument( function=self.create_credential.__name__, argument='private_key', ) _xmlkey = cmd.add_element("key") _xmlkey.add_element("private", private_key) if key_phrase: _xmlkey.add_element("phrase", key_phrase) if credential_type == CredentialType.CLIENT_CERTIFICATE and private_key: _xmlkey = cmd.add_element("key") _xmlkey.add_element("private", private_key) if credential_type == CredentialType.SNMP: if not isinstance(auth_algorithm, self.types.SnmpAuthAlgorithm): raise InvalidArgumentType( function=self.create_credential.__name__, argument='auth_algorithm', arg_type=SnmpAuthAlgorithm.__name__, ) cmd.add_element("auth_algorithm", auth_algorithm.value) if community: cmd.add_element("community", community) if privacy_algorithm is not None or privacy_password: _xmlprivacy = cmd.add_element("privacy") if privacy_algorithm is not None: if not isinstance(privacy_algorithm, self.types.SnmpPrivacyAlgorithm): raise InvalidArgumentType( function=self.create_credential.__name__, argument='privacy_algorithm', arg_type=SnmpPrivacyAlgorithm.__name__, ) _xmlprivacy.add_element("algorithm", privacy_algorithm.value) if privacy_password: _xmlprivacy.add_element("password", privacy_password) if credential_type == CredentialType.PGP_ENCRYPTION_KEY: if not public_key: raise RequiredArgument( function=self.create_credential.__name__, argument='public_key', ) _xmlkey = cmd.add_element("key") _xmlkey.add_element("public", public_key) return self._send_xml_command(cmd)
def modify_task( self, task_id: str, *, name: Optional[str] = None, config_id: Optional[str] = None, target_id: Optional[str] = None, scanner_id: Optional[str] = None, alterable: Optional[bool] = None, hosts_ordering: Optional[HostsOrdering] = None, schedule_id: Optional[str] = None, schedule_periods: Optional[int] = None, comment: Optional[str] = None, alert_ids: Optional[List[str]] = None, observers: Optional[List[str]] = None, preferences: Optional[dict] = None, ) -> Any: """Modifies an existing task. Arguments: task_id: UUID of task to modify. name: The name of the task. config_id: UUID of scan config to use by the task target_id: UUID of target to be scanned scanner_id: UUID of scanner to use for scanning the target comment: The comment on the task. alert_ids: List of UUIDs for alerts to be applied to the task hosts_ordering: The order hosts are scanned in schedule_id: UUID of a schedule when the task should be run. schedule_periods: A limit to the number of times the task will be scheduled, or 0 for no limit. observers: List of names or ids of users which should be allowed to observe this task preferences: Name/Value pairs of scanner preferences. Returns: The response. See :py:meth:`send_command` for details. """ if not task_id: raise RequiredArgument(function=self.modify_task.__name__, argument="task_id argument") cmd = XmlCommand("modify_task") cmd.set_attribute("task_id", task_id) if name: cmd.add_element("name", name) if comment: cmd.add_element("comment", comment) if config_id: cmd.add_element("config", attrs={"id": config_id}) if target_id: cmd.add_element("target", attrs={"id": target_id}) if alterable is not None: cmd.add_element("alterable", to_bool(alterable)) if hosts_ordering: if not isinstance(hosts_ordering, HostsOrdering): raise InvalidArgumentType( function=self.modify_task.__name__, argument="hosts_ordering", arg_type=HostsOrdering.__name__, ) cmd.add_element("hosts_ordering", hosts_ordering.value) if scanner_id: cmd.add_element("scanner", attrs={"id": scanner_id}) if schedule_id: cmd.add_element("schedule", attrs={"id": schedule_id}) if schedule_periods is not None: if (not isinstance(schedule_periods, Integral) or schedule_periods < 0): raise InvalidArgument( "schedule_periods must be an integer greater or equal " "than 0") cmd.add_element("schedule_periods", str(schedule_periods)) if alert_ids is not None: if not is_list_like(alert_ids): raise InvalidArgumentType( function=self.modify_task.__name__, argument="alert_ids", arg_type="list", ) if len(alert_ids) == 0: cmd.add_element("alert", attrs={"id": "0"}) else: for alert in alert_ids: cmd.add_element("alert", attrs={"id": str(alert)}) if observers is not None: if not is_list_like(observers): raise InvalidArgumentType( function=self.modify_task.__name__, argument="observers", arg_type="list", ) cmd.add_element("observers", to_comma_list(observers)) if preferences is not None: if not isinstance(preferences, Mapping): raise InvalidArgumentType( function=self.modify_task.__name__, argument="preferences", arg_type=Mapping.__name__, ) _xmlprefs = cmd.add_element("preferences") for pref_name, pref_value in preferences.items(): _xmlpref = _xmlprefs.add_element("preference") _xmlpref.add_element("scanner_name", pref_name) _xmlpref.add_element("value", str(pref_value)) return self._send_xml_command(cmd)