class GenericFileTransferForm(ServiceForm): form_type = HiddenField(default="generic_file_transfer_service") direction = SelectField(choices=(("get", "Get"), ("put", "Put"))) protocol = SelectField(choices=(("scp", "SCP"), ("sftp", "SFTP"))) source_file = StringField(validators=[InputRequired()], substitution=True) destination_file = StringField(validators=[InputRequired()], substitution=True) missing_host_key_policy = BooleanField() load_known_host_keys = BooleanField() look_for_keys = BooleanField() source_file_includes_globbing = BooleanField( "Source file includes glob pattern") max_transfer_size = IntegerField(default=2**30) window_size = IntegerField(default=2**30) timeout = FloatField(default=10.0) credentials = SelectField( "Credentials", choices=( ("device", "Device Credentials"), ("user", "User Credentials"), ("custom", "Custom Credentials"), ), ) custom_username = StringField("Custom Username", substitution=True) custom_password = PasswordField("Custom Password", substitution=True) def validate(self): valid_form = super().validate() invalid_direction = (self.source_file_includes_globbing.data and self.direction.data == "get") if invalid_direction: self.direction.errors.append( "Globbing only works with the 'PUT' direction") return valid_form and not invalid_direction
class NapalmPingForm(NapalmForm): form_type = HiddenField(default="napalm_ping_service") count = IntegerField(default=5) packet_size = IntegerField(default=100) destination_ip = StringField(substitution=True) source_ip = StringField(substitution=True) 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 PingForm(ServiceForm): form_type = HiddenField(default="ping_service") protocol = SelectField(choices=(("ICMP", "ICMP Ping"), ("TCP", "TCP Ping"))) ports = StringField() count = IntegerField(default=5) timeout = IntegerField(default=2) ttl = IntegerField(default=60) packet_size = IntegerField(default=56)
class GenericFileTransferForm(ServiceForm): form_type = HiddenField(default="generic_file_transfer_service") direction = SelectField(choices=(("get", "Get"), ("put", "Put"))) protocol = SelectField(choices=(("scp", "SCP"), ("sftp", "SFTP"))) source_file = StringField(validators=[InputRequired()], substitution=True) destination_file = StringField(validators=[InputRequired()], substitution=True) 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)") max_transfer_size = IntegerField(default=2**30) window_size = IntegerField(default=2**30)
class NapalmTracerouteForm(NapalmForm): form_type = HiddenField(default="napalm_traceroute_service") destination_ip = StringField(substitution=True) source_ip = StringField(substitution=True) 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 DeviceForm(ObjectForm): template = "object" form_type = HiddenField(default="device") id = HiddenField() icon = SelectField( "Icon", choices=( ("antenna", "Antenna"), ("firewall", "Firewall"), ("host", "Host"), ("optical_switch", "Optical switch"), ("regenerator", "Regenerator"), ("router", "Router"), ("server", "Server"), ("switch", "Switch"), ), ) ip_address = StringField("IP address") port = IntegerField("Port", default=22) operating_system = StringField("Operating System") os_version = StringField("OS Version") longitude = StringField("Longitude", default=0.0) latitude = StringField("Latitude", default=0.0) username = StringField("Username") password = PasswordField("Password") enable_password = PasswordField("'Enable' Password") napalm_driver = SelectField("NAPALM Driver", choices=app.NAPALM_DRIVERS, default="ios") netmiko_driver = SelectField("Netmiko Driver", choices=app.NETMIKO_DRIVERS, default="cisco_ios") scrapli_driver = SelectField("Scrapli Driver", choices=choices(app.SCRAPLI_DRIVERS), default="cisco_iosxe")
class ServerForm(BaseForm): template = "object" form_type = HiddenField(default="server") id = HiddenField() name = StringField("Name", [InputRequired()]) description = StringField("Description") ip_address = StringField("IP address") weight = IntegerField("Weigth")
class ServerForm(BaseForm): action = "eNMS.base.processData" form_type = HiddenField(default="server") id = HiddenField() name = StringField("Name", [InputRequired()]) description = StringField(widget=TextArea(), render_kw={"rows": 6}) ip_address = StringField("IP address") weight = IntegerField("Weigth", default=1)
class CustomForm(BaseForm): form_type = HiddenField(default="custom") address = SelectField(choices=[("ipv4", "IPv4"), ("ipv6", "IPv6")]) connected_links = MultipleInstanceField("Links", model="link") hostname = StringField("Username", default="admin") ip_address = StringField("IP address") neighbors = MultipleInstanceField("Devices", model="device") password = PasswordField("Password") router_id = IntegerField("Router ID") carry_customer_traffic = BooleanField("Carry Customer Traffic", default=False)
class TaskForm(BaseForm): action = "eNMS.base.processData" form_type = HiddenField(default="task") id = HiddenField() name = StringField("Name", [InputRequired()]) default_access = SelectField(choices=( ("creator", "Creator only"), ("public", "Public (all users)"), ("admin", "Admin Users only"), )) scheduling_mode = SelectField( "Scheduling Mode", choices=(("cron", "Crontab Scheduling"), ("standard", "Standard Scheduling")), ) description = StringField("Description") start_date = StringField("Start Date", type="date") end_date = StringField("End Date", type="date") frequency = IntegerField("Frequency", default=0) frequency_unit = SelectField( "Frequency Unit", choices=( ("seconds", "Seconds"), ("minutes", "Minutes"), ("hours", "Hours"), ("days", "Days"), ), ) crontab_expression = StringField("Crontab Expression") initial_payload = DictField("Payload") @classmethod def form_init(cls): cls.configure_relationships("devices", "pools", "service") def validate(self): valid_form = super().validate() if self.name.data == "Bulk Edit": return valid_form no_date = self.scheduling_mode.data == "standard" and not self.start_date.data if no_date: self.start_date.errors.append("A start date must be set.") no_cron_expression = (self.scheduling_mode.data == "cron" and not self.crontab_expression.data) if no_cron_expression: self.crontab_expression.errors.append( "A crontab expression must be set.") no_service = not self.service.data if no_service: self.service.errors.append("No service set.") return valid_form and not any( [no_date, no_cron_expression, no_service])
class NapalmForm(ConnectionForm): form_type = HiddenField(default="napalm") abstract_service = True driver = SelectField(choices=app.NAPALM_DRIVERS) use_device_driver = BooleanField(default=True) timeout = IntegerField(default=10) optional_args = DictField() groups = { "Napalm Parameters": { "commands": ["driver", "use_device_driver", "timeout", "optional_args"], "default": "expanded", }, **ConnectionForm.groups, }
class ConfigureBgpForm(NapalmForm): form_type = HiddenField(default="configure_bgp_service") local_as = IntegerField("Local AS", default=0) loopback = StringField("Loopback", default="Lo42") loopback_ip = StringField("Loopback IP") neighbor_ip = StringField("Neighbor IP") remote_as = IntegerField("Remote AS") vrf_name = StringField("VRF Name") groups = { "Main Parameters": { "commands": [ "local_as", "loopback", "loopback_ip", "neighbor_ip", "remote_as", "vrf_name", ], "default": "expanded", }, **NapalmForm.groups, }
class SRPolicyForm(NapalmForm): form_type = HiddenField(default="sr_policy_service") headend = SelectField(choices=( ("pe01", "pe01"), ("pe02", "pe02"), ("pe03", "pe03"), ("pe04", "pe04"), ("p11", "p11"), ("p12", "p12"), ), default="pe01") endpoint = SelectField(choices=( ("pe01", "pe01"), ("pe02", "pe02"), ("pe03", "pe03"), ("pe04", "pe04"), ("p11", "p11"), ("p12", "p12"), ), default="pe04") endpoint_ipv4 = StringField( "end-point ipv4", [ IPAddress( ipv4=True, message= "Please enter an end-point ipv4 address for the endpoint_ipv4 field", ) ], ) color = IntegerField(validators=[NumberRange(min=1, max=4294967295)]) description = StringField() path_name = StringField(validators=[InputRequired()]) segment_list = FieldList(FormField(SegmentForm), min_entries=5) groups = { "Policy Details": { "commands": ["headend", "endpoint", "endpoint_ipv4", "color", "description"], "default": "expanded" }, "Policy Path": { "commands": ["path_name", "segment_list"], "default": "expanded", }, **NapalmForm.groups, }
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 = StringField(substitution=True) payload = DictField(json_only=True, substitution=True) params = DictField(substitution=True) headers = DictField(substitution=True) verify_ssl_certificate = BooleanField("Verify SSL Certificate") timeout = IntegerField(default=15) username = StringField() password = PasswordField()
class UnixShellScriptForm(NetmikoForm): form_type = HiddenField(default="unix_shell_script_service") enable_mode = BooleanField("Run as root using sudo") config_mode = BooleanField("Config mode") 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 = StringField(substitution=True) auto_find_prompt = BooleanField(default=True) strip_prompt = BooleanField(default=True) strip_command = BooleanField(default=True) groups = { "Main Parameters": { "commands": ["source_code"], "default": "expanded" }, "Advanced Netmiko Parameters": { "commands": [ "expect_string", "auto_find_prompt", "strip_prompt", "strip_command", ], "default": "hidden", }, **NetmikoForm.groups, }
class VlanConfigurationForm(NapalmForm): form_type = HiddenField(default="vlan_configuration_service") action = SelectField( choices=( ("load_merge_candidate", "Load merge"), ("load_replace_candidate", "Load replace"), ) ) interface_name = StringField(validators=[InputRequired()]) vlan_id = IntegerField(validators=[NumberRange(min=10, max=4000)]) description = StringField() vrf = StringField() qos = StringField() ipv4s = FieldList(FormField(Ipv4Form), min_entries=5) ipv6s = FieldList(FormField(Ipv6Form), min_entries=5) shutdown = SelectField( choices=( ("yes", "yes"), ("no", "no"), ), default="no" ) groups = { "Main Parameters": { "commands": [ "action", "interface_name", "vlan_id", "description", "vrf", "qos", "shutdown" ], "default": "expanded" }, "IPv4 address Parameters": { "commands": ["ipv4s"], "default": "expanded", }, "IPv6 address Parameters": { "commands": ["ipv6s"], "default": "expanded", }, **NapalmForm.groups, }
class TaskForm(BaseForm): template = "object" form_type = HiddenField(default="task") id = HiddenField() scheduling_mode = SelectField( "Scheduling Mode", choices=(("cron", "Crontab Scheduling"), ("standard", "Standard Scheduling")), ) name = StringField("Name", [InputRequired()]) description = StringField("Description") start_date = StringField("Start Date", type="date") end_date = StringField("End Date", type="date") frequency = IntegerField("Frequency", default=0) frequency_unit = SelectField( "Frequency Unit", choices=( ("seconds", "Seconds"), ("minutes", "Minutes"), ("hours", "Hours"), ("days", "Days"), ), ) crontab_expression = StringField("Crontab Expression") initial_payload = DictField("Payload") def validate(self): valid_form = super().validate() no_date = self.scheduling_mode.data == "standard" and not self.start_date.data if no_date: self.start_date.errors.append("A start date must be set.") no_cron_expression = (self.scheduling_mode.data == "cron" and not self.crontab_expression.data) if no_cron_expression: self.crontab_expression.errors.append( "A crontab expression must be set.") no_service = not self.service.data if no_service: self.service.errors.append("No service set.") return valid_form and not any( [no_date, no_cron_expression, no_service])
class CredentialForm(BaseForm): action = "eNMS.base.processData" form_type = HiddenField(default="credential") id = HiddenField() name = StringField("Name", [InputRequired()]) description = StringField(widget=TextArea(), render_kw={"rows": 13}) role = SelectField( "Role", choices=( ("read-write", "Read Write"), ("read-only", "Read Only"), ), ) subtype = SelectField("Type", choices=(("password", "Username / Password"), ("key", "SSH Key"))) device_pools = MultipleInstanceField("Devices", model="pool") user_pools = MultipleInstanceField("Users", model="pool") priority = IntegerField("Priority", default=1) username = StringField("Username") enable_password = PasswordField("'Enable' Password") password = PasswordField("Password") private_key = StringField(widget=TextArea(), render_kw={"rows": 10})
class NetconfForm(ConnectionForm): form_type = HiddenField(default="netconf_service") nc_type = SelectField( choices=( ("get_config", "Get Full Config"), ("get_filtered_config", "Get"), ("push_config", "Edit Config"), ("copy_config", "Copy Config"), ("rpc", "Dispatch"), ), label="NETCONF Operation", ) xml_filter = StringField(label="XML Filter", widget=TextArea(), render_kw={"rows": 5}, substitution=True) target = SelectField( choices=( ("running", "Running"), ("candidate", "Candidate"), ("startup", "Startup"), ), label="Target Config", ) default_operation = SelectField( choices=( ("merge", "Merge"), ("replace", "Replace"), ("None", "None"), ), label="Default config operation", validate_choice=False, ) test_option = SelectField( choices=( ("test-then-set", "Test, then set"), ("set", "Set"), ("None", "None"), ), label="Config test option", validate_choice=False, ) error_option = SelectField( choices=( ("stop-on-error", "Stop on error"), ("continue-on-error", "Continue on error"), ("rollback-on-error", "Rollback on error"), ("None", "None"), ), label="Error option", validate_choice=False, ) lock = BooleanField(label="Lock target") unlock = BooleanField(label="Unlock target") copy_source = SelectField( choices=( ("running", "Running"), ("candidate", "Candidate"), ("startup", "Startup"), ("source_url", "Source URL"), ), label="Copy Source", validate_choice=False, ) source_url = StringField( label="Copy source URL", widget=TextArea(), render_kw={"rows": 1}, substitution=True, ) copy_destination = SelectField( choices=( ("running", "Running"), ("candidate", "Candidate"), ("startup", "Startup"), ("destination_url", "Destination URL"), ), label="Copy Destination", validate_choice=False, ) destination_url = StringField( label="Copy destination URL", widget=TextArea(), render_kw={"rows": 1}, substitution=True, ) commit_conf = BooleanField(label="Commit") timeout = IntegerField(default=15) xml_conversion = BooleanField(label="Convert XML result to dictionary", default=True) @classmethod def form_init(cls): parameters = { "get_config": ["target", "xml_conversion"], "get_filtered_config": [ "target", "xml_filter", "xml_conversion", ], "push_config": [ "target", "xml_filter", "default_operation", "test_option", "error_option", "lock", "unlock", "commit_conf", "xml_conversion", ], "copy_config": [ "copy_source", "source_url", "copy_destination", "destination_url", "commit_conf", "xml_conversion", ], "rpc": ["xml_filter", "xml_conversion"], } list_parameters = list(set(sum(parameters.values(), []))) cls.groups = { "NETCONF Parameters": { "commands": ["nc_type"] + list_parameters, "default": "expanded", }, **ConnectionForm.groups, } cls.input_data = HiddenField( "", default=dumps({ "fields": list_parameters, "netconf_type": parameters }), )
class ExampleForm(ServiceForm): # Each service model must have an corresponding form. # The purpose of a form is twofold: # - Define how the service is displayed in the UI # - Check for each field that the user input is valid. # A service cannot be created/updated until all fields are validated. # The following line is mandatory: the default value must point # to the service. form_type = HiddenField(default="example_service") # string1 is defined as a "SelectField": it will be displayed as a # drop-down list in the UI. string1 = SelectField(choices=[("cisco", "Cisco"), ("juniper", "Juniper"), ("arista", "Arista")]) # String2 is a StringField, which is displayed as a standard textbox. # The "InputRequired" validator is used: this field is mandatory. string2 = StringField("String 2 (required)", [InputRequired()]) # The main address field uses two validators: # - The input length must be comprised between 7 and 25 characters # - The input syntax must match that of an email address. mail_address = StringField( "Mail address", [Length(min=7, max=25), Email()]) # This IP address validator will ensure the user input is a valid IPv4 address. # If it isn't, you can set the error message to be displayed in the GUI. ip_address = StringField( "IP address", [ IPAddress( ipv4=True, message="Please enter an IPv4 address for the IP address field", ) ], ) # MAC address validator mac_address = StringField("MAC address", [MacAddress()]) # The NumberRange validator will ensure the user input is an integer # between 3 and 8. number_in_range = IntegerField("Number in range", [NumberRange(min=3, max=8)]) # The Regexp field will ensure the user input matches the regular expression. regex = StringField("Regular expression", [Regexp(r".*")]) # URL validation, with or without TLD. url = StringField( "URL", [ URL( require_tld=True, message="An URL with TLD is required for the url field", ) ], ) # The NoneOf validator lets you define forbidden value for a field. exclusion_field = StringField( "Exclusion field", [ NoneOf( ("a", "b", "c"), message=("'a', 'b', and 'c' are not valid " "inputs for the exclusion field"), ) ], ) an_integer = IntegerField() a_float = FloatField() # If validator the user input is more complex, you can create a python function # to implement the validation mechanism. # Here, the custom_integer field will be validated by the "validate_custom_integer" # function below. # That function will check that the custom integer value is superior to the product # of "an_integer" and "a_float". # You must raise a "ValidationError" when the validation fails. custom_integer = IntegerField("Custom Integer") # A SelectMultipleField will be displayed as a drop-down list that allows # multiple selection. a_list = SelectMultipleField( choices=[("value1", "Value 1"), ("value2", "Value 2"), ("value3", "Value 3")]) a_dict = DictField() # A BooleanField is displayed as a check box. boolean1 = BooleanField() boolean2 = BooleanField("Boolean N°1") def validate_custom_integer(self, field): product = self.an_integer.data * self.a_float.data if field.data > product: raise ValidationError("Custom integer must be less than the " "product of 'An integer' and 'A float'")
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", python=True, widget=TextArea(), render_kw={"rows": 2} ) device_query_property = SelectField( "Query Property Type", choices=(("name", "Name"), ("ip_address", "IP address")) ) devices = MultipleInstanceField("Devices") disable_result_creation = BooleanField("Disable Result Creation") pools = MultipleInstanceField("Pools") update_pools = BooleanField("Update pools before running") workflows = MultipleInstanceField("Workflows") waiting_time = IntegerField( "Time to Wait before next service is started (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)") reply_to = StringField("Reply-to Email Address") number_of_retries = IntegerField("Number of retries", default=0) time_between_retries = IntegerField("Time between retries (in seconds)", default=10) max_number_of_retries = IntegerField("Maximum number of retries", default=100) maximum_runs = IntegerField("Maximum number of runs", default=1) skip = BooleanField("Skip") skip_query = StringField( "Skip Query (Python)", python=True, widget=TextArea(), render_kw={"rows": 2} ) skip_value = SelectField( "Skip Value", choices=(("True", "True"), ("False", "False")), ) vendor = StringField("Vendor") operating_system = StringField("Operating System") iteration_values = StringField("Iteration Values", python=True) initial_payload = DictField() iteration_variable_name = StringField( "Iteration Variable Name", default="iteration_value" ) iteration_devices = StringField("Iteration Devices", python=True) iteration_devices_property = SelectField( "Iteration Devices Property", choices=(("name", "Name"), ("ip_address", "IP address")), ) preprocessing = StringField(type="code", python=True, widget=TextArea()) postprocessing = StringField(type="code", python=True, widget=TextArea()) postprocessing_mode = SelectField( choices=( ("always", "Always run"), ("success", "Run on success only"), ("failure", "Run on failure only"), ) ) public = BooleanField("Public") log_level = SelectField( "Logging", choices=((0, "Disable logging"), *enumerate(app.log_levels, 1)), default=1, validation=False, ) multiprocessing = BooleanField("Multiprocessing") max_processes = IntegerField("Maximum number of processes", default=15) validation_condition = SelectField( choices=( ("success", "Run on success only"), ("failure", "Run on failure only"), ("always", "Always run"), ) ) 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 = StringField( "Content Match", widget=TextArea(), render_kw={"rows": 8}, substitution=True ) content_match_regex = BooleanField("Match content with Regular Expression") dict_match = DictField("Dictionary to Match Against", substitution=True) negative_logic = BooleanField("Negative logic") delete_spaces_before_matching = BooleanField("Delete Spaces before Matching") run_method = SelectField( "Run Method", choices=( ("per_device", "Run the service once per device"), ("once", "Run the service once"), ), ) 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 ) if no_recipient_error: self.mail_recipient.errors.append( "Please add at least one recipient for the mail notification." ) forbidden_name_error = self.scoped_name.data in ("Start", "End", "Placeholder") if forbidden_name_error: self.name.errors.append("This name is not allowed.") 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 conversion_validation_mismatch and not forbidden_name_error )
class PanelForm(BaseForm): form_type = HiddenField(default="panel") action = "eNMS.plugins.submitPanelForm" ip_address = StringField("IP address", render_kw={"help": "ip_address"}) router_id = IntegerField("Router ID")