class NapalmPingForm(NapalmForm): form_type = HiddenField(default="napalm_ping_service") count = IntegerField(default=5) packet_size = IntegerField(default=100) destination_ip = SubstitutionField() source_ip = SubstitutionField() timeout = IntegerField(default=2) ttl = IntegerField(default=255) vrf = StringField() groups = { "Ping Parameters": { "commands": [ "count", "packet_size", "destination_ip", "source_ip", "timeout", "ttl", "vrf", ], "default": "expanded", }, **NapalmForm.groups, }
class NetmikoValidationForm(NetmikoForm): form_type = HiddenField(default="netmiko_validation_service") command = SubstitutionField() expect_string = SubstitutionField() auto_find_prompt = BooleanField(default=True) strip_prompt = BooleanField(default=True) strip_command = BooleanField(default=True) use_genie = BooleanField(default=False) groups = { "Main Parameters": { "commands": ["command"], "default": "expanded" }, "Advanced Netmiko Parameters": { "commands": [ "expect_string", "auto_find_prompt", "strip_prompt", "strip_command", "use_genie", ], "default": "hidden", }, **NetmikoForm.groups, }
class NetmikoValidationForm(ServiceForm, NetmikoForm, ValidationForm): form_type = HiddenField(default="NetmikoValidationService") command = SubstitutionField() expect_string = SubstitutionField() auto_find_prompt = BooleanField(default=True) strip_prompt = BooleanField(default=True) strip_command = BooleanField(default=True) groups = { "Main Parameters": { "commands": ["command"], "default": "expanded" }, "Netmiko Parameters": NetmikoForm.group, "Advanced Netmiko Parameters": { "commands": [ "expect_string", "auto_find_prompt", "strip_prompt", "strip_command", ], "default": "hidden", }, "Validation Parameters": ValidationForm.group, }
class NetmikoFileTransferForm(NetmikoForm): form_type = HiddenField(default="netmiko_file_transfer_service") source_file = SubstitutionField(validators=[InputRequired()]) destination_file = SubstitutionField(validators=[InputRequired()]) file_system = StringField() direction = SelectField(choices=(("put", "Upload"), ("get", "Download"))) disable_md5 = BooleanField() inline_transfer = BooleanField() overwrite_file = BooleanField() groups = { "Main Parameters": { "commands": [ "source_file", "destination_file", "file_system", "direction", "disable_md5", "inline_transfer", "overwrite_file", ], "default": "expanded", }, **NetmikoForm.groups, }
class GenericFileTransferForm(ServiceForm): form_type = HiddenField(default="GenericFileTransferService") direction = SelectField(choices=(("get", "Get"), ("put", "Put"))) protocol = SelectField(choices=(("scp", "SCP"), ("sftp", "SFTP"))) source_file = SubstitutionField(validators=[InputRequired()]) destination_file = SubstitutionField(validators=[InputRequired()]) missing_host_key_policy = BooleanField() load_known_host_keys = BooleanField() look_for_keys = BooleanField() source_file_includes_globbing = BooleanField( "Source file includes glob pattern (Put Direction only)")
class NapalmTracerouteForm(ServiceForm, NapalmForm): form_type = HiddenField(default="NapalmTracerouteService") destination_ip = SubstitutionField() source_ip = SubstitutionField() timeout = IntegerField() ttl = IntegerField() vrf = StringField() groups = { "Napalm Parameters": NapalmForm.group, "Ping Parameters": ["destination_ip", "source_ip", "timeout", "ttl", "vrf"], }
class NapalmTracerouteForm(NapalmForm): form_type = HiddenField(default="napalm_traceroute_service") destination_ip = SubstitutionField() source_ip = SubstitutionField() timeout = IntegerField(default=2) ttl = IntegerField(default=255) vrf = StringField() groups = { "Ping Parameters": { "commands": ["destination_ip", "source_ip", "timeout", "ttl", "vrf"], "default": "expanded", }, **NapalmForm.groups, }
class PayloadExtractionForm(ServiceForm): form_type = HiddenField(default="PayloadExtractionService") has_targets = BooleanField("Has Target Devices") variable1 = StringField() query1 = SubstitutionField() match_type1 = SelectField(choices=match_choices) match1 = StringField(widget=TextArea(), render_kw={"rows": 5}) variable2 = StringField() query2 = SubstitutionField() match_type2 = SelectField(choices=match_choices) match2 = StringField(widget=TextArea(), render_kw={"rows": 5}) variable3 = StringField() query3 = SubstitutionField() match_type3 = SelectField(choices=match_choices) match3 = StringField(widget=TextArea(), render_kw={"rows": 5})
class ConnectionForm(ServiceForm): form_type = HiddenField(default="connection") abstract_service = True credentials = SelectField( "Credentials", choices=( ("device", "Device Credentials"), ("user", "User Credentials"), ("custom", "Custom Credentials"), ), ) custom_username = SubstitutionField("Custom Username") custom_password = PasswordSubstitutionField("Custom Password") start_new_connection = BooleanField("Start New Connection") close_connection = BooleanField("Close Connection") group = { "commands": [ "credentials", "custom_username", "custom_password", "start_new_connection", "close_connection", ], "default": "expanded", }
class MailNotificationForm(ServiceForm): form_type = HiddenField(default="mail_notification_service") title = SubstitutionField() sender = StringField() recipients = StringField() body = SubstitutionField(widget=TextArea(), render_kw={"rows": 5}) def validate(self): valid_form = super().validate() for field in ("title", "sender", "recipients", "body"): if not getattr(self, field).data: getattr( self, field).errors.append(f"{field.capitalize()} is missing.") valid_form = False return valid_form
class NapalmConfigurationForm(ServiceForm, NapalmForm): form_type = HiddenField(default="NapalmConfigurationService") action = SelectField(choices=( ("load_merge_candidate", "Load merge"), ("load_replace_candidate", "Load replace"), )) content = SubstitutionField(widget=TextArea(), render_kw={"rows": 5})
class RestCallForm(ServiceForm, ValidationForm): form_type = HiddenField(default="RestCallService") has_targets = BooleanField("Has Target Devices") call_type = SelectField(choices=( ("GET", "GET"), ("POST", "POST"), ("PUT", "PUT"), ("DELETE", "DELETE"), ("PATCH", "PATCH"), )) rest_url = SubstitutionField() payload = JsonSubstitutionField() params = DictSubstitutionField() headers = DictSubstitutionField() verify_ssl_certificate = BooleanField("Verify SSL Certificate") timeout = IntegerField(default=15) username = StringField() password = PasswordField() groups = { "Main Parameters": [ "has_targets", "call_type", "rest_url", "payload", "params", "headers", "verify_ssl_certificate", "timeout", "username", "password", ], "Validation Parameters": ValidationForm.group, }
class AnsiblePlaybookForm(ServiceForm, ValidationForm): form_type = HiddenField(default="AnsiblePlaybookService") has_targets = BooleanField("Has Target Devices") playbook_path = NoValidationSelectField("Playbook Path", choices=()) arguments = SubstitutionField("Arguments (Ansible command line options)") pass_device_properties = BooleanField( "Pass Device Inventory Properties (to be used " "in the playbook as {{name}} or {{ip_address}})") options = DictSubstitutionField( "Options (passed to ansible as -e extra args)") groups = { "Main Parameters": [ "has_targets", "playbook_path", "arguments", "pass_device_properties", "options", ], "Validation Parameters": ValidationForm.group, } def validate(self) -> bool: valid_form = super().validate() pass_properties_error = (self.pass_device_properties.data and not self.has_targets.data) if pass_properties_error: self.pass_device_properties.errors.append( "'pass device properties' requires 'has device targets' to be selected." ) return valid_form and not pass_properties_error
class NetmikoConfigurationForm(NetmikoForm): form_type = HiddenField(default="netmiko_configuration_service") config_mode = BooleanField("Config mode", default=True) content = SubstitutionField(widget=TextArea(), render_kw={"rows": 5}) commit_configuration = BooleanField() exit_config_mode = BooleanField(default=True) strip_prompt = BooleanField() strip_command = BooleanField() config_mode_command = StringField() groups = { "Main Parameters": { "commands": [ "content", "commit_configuration", "exit_config_mode", "config_mode_command", ], "default": "expanded", }, "Advanced Netmiko Parameters": { "commands": ["strip_prompt", "strip_command"], "default": "hidden", }, **NetmikoForm.groups, }
class NetmikoPromptsForm(NetmikoForm): form_type = HiddenField(default="netmiko_prompts_service") command = SubstitutionField() confirmation1 = SubstitutionField() response1 = SubstitutionField() confirmation2 = SubstitutionField() response2 = SubstitutionField() confirmation3 = SubstitutionField() response3 = SubstitutionField() groups = { "Main Parameters": { "commands": [ "command", "confirmation1", "response1", "confirmation2", "response2", "confirmation3", "response3", ], "default": "expanded", }, **NetmikoForm.groups, }
class NetmikoPromptsForm(ServiceForm, NetmikoForm, ValidationForm): form_type = HiddenField(default="NetmikoPromptsService") command = SubstitutionField() confirmation1 = SubstitutionField() response1 = SubstitutionField() confirmation2 = SubstitutionField() response2 = SubstitutionField() confirmation3 = SubstitutionField() response3 = SubstitutionField() groups = { "Main Parameters": { "commands": [ "command", "confirmation1", "response1", "confirmation2", "response2", "confirmation3", "response3", ], "default": "expanded", }, "Netmiko Parameters": NetmikoForm.group, "String Validation Parameters": ValidationForm.group, }
class AnsiblePlaybookForm(ServiceForm): form_type = HiddenField(default="ansible_playbook_service") playbook_path = NoValidationSelectField("Playbook Path", choices=()) arguments = SubstitutionField("Arguments (Ansible command line options)") pass_device_properties = BooleanField( "Pass Device Inventory Properties (to be used " "in the playbook as {{name}} or {{ip_address}})") options = DictSubstitutionField( "Options (passed to ansible as -e extra args)")
class ValidationForm(BaseForm): form_type = HiddenField(default="service_validation") abstract_service = True conversion_method = SelectField( choices=( ("none", "No conversion"), ("text", "Text"), ("json", "Json dictionary"), ("xml", "XML dictionary"), ) ) validation_method = SelectField( "Validation Method", choices=( ("text", "Validation by text match"), ("dict_included", "Validation by dictionary inclusion"), ("dict_equal", "Validation by dictionary equality"), ), ) content_match = SubstitutionField( "Content Match", widget=TextArea(), render_kw={"rows": 8} ) content_match_regex = BooleanField("Match content with Regular Expression") dict_match = DictSubstitutionField("Dictionary to Match Against") negative_logic = BooleanField("Negative logic") delete_spaces_before_matching = BooleanField("Delete Spaces before Matching") group = { "commands": [ "conversion_method", "validation_method", "content_match", "content_match_regex", "dict_match", "negative_logic", "delete_spaces_before_matching", ], "default": "expanded", } def validate(self) -> bool: valid_form = super().validate() conversion_validation_mismatch = ( self.conversion_method.data == "text" and "dict" in self.validation_method.data or self.conversion_method.data in ("xml", "json") and "dict" not in self.validation_method.data ) if conversion_validation_mismatch: self.conversion_method.errors.append( f"The conversion method is set to '{self.conversion_method.data}'" f" and the validation method to '{self.validation_method.data}' :" " these do not match." ) return valid_form and not conversion_validation_mismatch
class NapalmPingForm(ServiceForm, NapalmForm): form_type = HiddenField(default="NapalmPingService") count = IntegerField() packet_size = IntegerField() destination_ip = SubstitutionField() source_ip = SubstitutionField() timeout = IntegerField() ttl = IntegerField() vrf = StringField() groups = { "Napalm Parameters": NapalmForm.group, "Ping Parameters": [ "count", "packet_size", "destination_ip", "source_ip", "timeout", "ttl", "vrf", ], }
class NapalmConfigurationForm(NapalmForm): form_type = HiddenField(default="napalm_configuration_service") action = SelectField(choices=( ("load_merge_candidate", "Load merge"), ("load_replace_candidate", "Load replace"), )) content = SubstitutionField(widget=TextArea(), render_kw={"rows": 5}) groups = { "Main Parameters": { "commands": ["action", "content"], "default": "expanded" }, **NapalmForm.groups, }
class ServiceForm(JobForm): form_type = HiddenField(default="service") credentials = SelectField( "Credentials", choices=( ("device", "Device Credentials"), ("user", "User Credentials"), ("custom", "Custom Credentials"), ), ) custom_username = SubstitutionField("Custom Username") custom_password = PasswordSubstitutionField("Custom Password") multiprocessing = BooleanField("Multiprocessing") max_processes = IntegerField("Maximum number of processes", default=50)
class NetmikoValidationForm(NetmikoForm): form_type = HiddenField(default="netmiko_validation_service") commands = SubstitutionField(widget=TextArea(), render_kw={"rows": 5}) expect_string = SubstitutionField() auto_find_prompt = BooleanField(default=True) strip_prompt = BooleanField(default=True) strip_command = BooleanField(default=True) groups = { "Main Parameters": { "commands": ["commands"], "default": "expanded" }, "Advanced Netmiko Parameters": { "commands": [ "expect_string", "auto_find_prompt", "strip_prompt", "strip_command", ], "default": "hidden", }, **NetmikoForm.groups, }
class StringValidationForm(BaseForm): form_type = HiddenField(default="string_service_validation") abstract_service = True content_match = SubstitutionField("Content Match", widget=TextArea(), render_kw={"rows": 8}) content_match_regex = BooleanField("Match content with Regular Expression") negative_logic = BooleanField("Negative logic") delete_spaces_before_matching = BooleanField( "Delete Spaces before Matching") group = [ "content_match", "content_match_regex", "negative_logic", "delete_spaces_before_matching", ]
class RestCallForm(ServiceForm): form_type = HiddenField(default="rest_call_service") call_type = SelectField(choices=( ("GET", "GET"), ("POST", "POST"), ("PUT", "PUT"), ("DELETE", "DELETE"), ("PATCH", "PATCH"), )) rest_url = SubstitutionField() payload = JsonSubstitutionField() params = DictSubstitutionField() headers = DictSubstitutionField() verify_ssl_certificate = BooleanField("Verify SSL Certificate") timeout = IntegerField(default=15) username = StringField() password = PasswordField()
class UnixShellScriptForm(ServiceForm, StringValidationForm, NetmikoForm): form_type = HiddenField(default="UnixShellScriptService") privileged_mode = BooleanField("Privileged mode (run as root using sudo)") source_code = StringField( widget=TextArea(), render_kw={"rows": 15}, default=("#!/bin/bash\n" "# The following example shell script returns" " 0 for success; non-zero for failure\n" "directory_contents=`ls -al /root` # Needs privileged mode\n" "return_code=$?\n" "if [ $return_code -ne 0 ]; then\n" " exit $return_code # Indicating Failure\n" "else\n" ' echo -e "$directory_contents"\n' " exit 0 # Indicating Success\n" "fi\n"), ) driver = SelectField(choices=app.NETMIKO_DRIVERS, default="linux") use_device_driver = BooleanField(default=True) fast_cli = BooleanField() timeout = IntegerField(default=10) delay_factor = FloatField(default=1.0) global_delay_factor = FloatField(default=1.0) expect_string = SubstitutionField() auto_find_prompt = BooleanField(default=True) strip_prompt = BooleanField(default=True) strip_command = BooleanField(default=True) groups = { "Main Parameters": { "commands": ["source_code"], "default": "expanded" }, "Netmiko Parameters": NetmikoForm.group, "Advanced Netmiko Parameters": { "commands": [ "expect_string", "auto_find_prompt", "strip_prompt", "strip_command", ], "default": "hidden", }, "Validation Parameters": StringValidationForm.group, }
class AnsiblePlaybookForm(ServiceForm, ValidationForm): form_type = HiddenField(default="AnsiblePlaybookService") has_targets = BooleanField("Has Target Devices") playbook_path = NoValidationSelectField("Playbook Path", choices=()) arguments = SubstitutionField("Arguments (Ansible command line options)") pass_device_properties = BooleanField( "Pass Device Inventory Properties (to be used " "in the playbook as {{name}} or {{ip_address}})") options = DictField("Options (passed to ansible as -e extra args)") groups = { "Main Parameters": [ "playbook_path", "arguments", "pass_device_properties", "options", ], "Validation Parameters": ValidationForm.group, }
class IterationForm(ServiceForm): form_type = HiddenField(default="IterationService") has_targets = BooleanField("Has Target Devices") origin_of_values = SelectField( "Where Values come from", choices=( ("user_provided_values", "User-provided Values (dictionary)"), ("yaql_query", "YaQL Query on the Payload"), ), ) user_provided_values = DictField( "Iteration Values for Iteration: User provided " "(Expect dictionary {'all' : [...]} or {'device-name' : [...], ...})" ) yaql_query_values = SubstitutionField( "Iteration Values for Iteration: YaQL query on the payload" ) variable_name = StringField("Iteration Variable Name") iterated_job = InstanceField("Job to run for each Value", instance_type="Job")
class NetmikoConfigurationForm(ServiceForm, NetmikoForm): form_type = HiddenField(default="NetmikoConfigurationService") content = SubstitutionField(widget=TextArea(), render_kw={"rows": 5}) commit_configuration = BooleanField() exit_config_mode = BooleanField() strip_prompt = BooleanField() strip_command = BooleanField() config_mode_command = StringField() groups = { "Main Parameters": [ "content", "commit_configuration", "exit_config_mode", "strip_prompt", "strip_command", "config_mode_command", ], "Netmiko Parameters": NetmikoForm.group, }
class ServiceForm(BaseForm): template = "service" form_type = HiddenField(default="service") id = HiddenField() name = StringField("Name") type = StringField("Service Type") shared = BooleanField("Shared Service") scoped_name = StringField("Scoped Name", [InputRequired()]) description = StringField("Description") device_query = StringField("Device Query") device_query_property = SelectField("Query Property Type", choices=(("name", "Name"), ("ip_address", "IP address"))) devices = MultipleInstanceField("Devices") pools = MultipleInstanceField("Pools") workflows = MultipleInstanceField("Workflows") waiting_time = IntegerField("Waiting time (in seconds)", default=0) send_notification = BooleanField("Send a notification") send_notification_method = SelectField( "Notification Method", choices=(("mail", "Mail"), ("slack", "Slack"), ("mattermost", "Mattermost")), ) notification_header = StringField(widget=TextArea(), render_kw={"rows": 5}) include_device_results = BooleanField("Include Device Results") include_link_in_summary = BooleanField("Include Result Link in Summary") display_only_failed_nodes = BooleanField("Display only Failed Devices") mail_recipient = StringField("Mail Recipients (separated by comma)") number_of_retries = IntegerField("Number of retries", default=0) time_between_retries = IntegerField("Time between retries (in seconds)", default=10) maximum_runs = IntegerField("Maximum number of runs", default=1) skip = BooleanField("Skip") skip_query = StringField("Skip Query (Python)") vendor = StringField("Vendor") operating_system = StringField("Operating System") initial_payload = DictField() iteration_values = StringField("Iteration Values (Python Query)") iteration_variable_name = StringField("Iteration Variable Name", default="iteration_value") iteration_devices = StringField("Iteration Devices (Python Query)") iteration_devices_property = SelectField( "Iteration Devices Property", choices=(("name", "Name"), ("ip_address", "IP address")), ) result_postprocessing = StringField(widget=TextArea(), render_kw={"rows": 7}) multiprocessing = BooleanField("Multiprocessing") max_processes = IntegerField("Maximum number of processes", default=50) conversion_method = SelectField(choices=( ("none", "No conversion"), ("text", "Text"), ("json", "Json dictionary"), ("xml", "XML dictionary"), )) validation_method = SelectField( "Validation Method", choices=( ("none", "No validation"), ("text", "Validation by text match"), ("dict_included", "Validation by dictionary inclusion"), ("dict_equal", "Validation by dictionary equality"), ), ) content_match = SubstitutionField("Content Match", widget=TextArea(), render_kw={"rows": 8}) content_match_regex = BooleanField("Match content with Regular Expression") dict_match = DictSubstitutionField("Dictionary to Match Against") negative_logic = BooleanField("Negative logic") delete_spaces_before_matching = BooleanField( "Delete Spaces before Matching") query_fields = [ "device_query", "skip_query", "iteration_values", "result_postprocessing", ] def validate(self): valid_form = super().validate() no_recipient_error = (self.send_notification.data and self.send_notification_method.data == "mail" and not self.mail_recipient.data and not app.config["mail"]["recipients"]) if no_recipient_error: self.mail_recipient.errors.append( "Please add at least one recipient for the mail notification.") bracket_error = False for query_field in self.query_fields: field = getattr(self, query_field) try: parse(field.data) except Exception as exc: bracket_error = True field.errors.append(f"Wrong python expression ({exc}).") if "{{" in field.data and "}}" in field.data: bracket_error = True field.errors.append( "You cannot use variable substitution " "in a field expecting a python expression.") conversion_validation_mismatch = ( self.conversion_method.data == "text" and "dict" in self.validation_method.data or self.conversion_method.data in ("xml", "json") and "dict" not in self.validation_method.data) if conversion_validation_mismatch: self.conversion_method.errors.append( f"The conversion method is set to '{self.conversion_method.data}'" f" and the validation method to '{self.validation_method.data}' :" " these do not match.") return (valid_form and not no_recipient_error and not bracket_error and not conversion_validation_mismatch)
class UnixCommandForm(ServiceForm, ValidationForm): form_type = HiddenField(default="UnixCommandService") command = SubstitutionField()