EdgeRouter - Setup Wizard Tutorial with Examples

Overview


Readers will learn how to configure Feature Setup Wizards for EdgeRouters.

 

A working wizard includes four parts:

  1. view -- wizard.html
  2. validator -- validator.json
  3. backend process -- wizard-run (wizard-run is a shellscript in the example that follows later in the article)
  4. format result -- result.json (dependent on the previous parts)

Below is a screenshot of a test wizard configuration. When the Apply button is clicked, the system will perform validation according to the customized .json formatted validator (if there is anything in the validator.json). Assuming validation passes, the added function in wizard-run will be triggered in EdgeOS. In the example provided, the only "function" is to save the .json format result, that is, result.json to /tmp directory of the router when changes are applied.

 

 

Files Explained


Here are the contents of the wizard.html file:

 

<div class="instructions">
    Test wizard configuration
</div>

<fieldset name="test" class="primary expanded">
    <legend>Title</legend>
    <div><span>Addable Configs:</span></div>
    <div class="clear"></div>
    <div class="addable" data-min="2" data-max="10" data-object="addable-test" data-objectify="1">
        <div class="addable-template">
            <div class="multi">
                <div><span class="text">Interfaces</span></div><div><span><select name="interfaces" /></span></div>
                <div><span class="text">text input</span></div><div><input type="text" name="text" data-infotip='This is a test infotip.' /></div>
                <div><span class="text">same line checkbox</span></div><div><input name="nchecks" type="checkbox" value="nc" /><span data-infotip='This is a same line checkbox.'>c2</span></div>
            </div>
            <div class="clear"></div>
            <div><span class="text" style="width:110px;">new line checkbox</span></div><div><input name="checks" type="checkbox" value="c" /><span data-infotip='This is a new line checkbox.'>c1</span></div>
            <div><button type="button" class="addable-remove">Remove</button></div>
            <div class="clear"></div>
        </div>
        <div class="addable-container">
            <!-- the addable templates will be inserted here -->
        </div>
        <button type="button" class="addable-add">Add New</button>
    </div>
</fieldset>

For the addable section, there are a few useful attributes:

 

<div class="addable" data-min="0" data-max="10" data-object="addable-test" data-objectify="1"></div>

data-min is the minimum number of addable templates. It will still initial the wizard with zero addables, but if data-min is greater than zero, the first (data-min - 1) templates would not have remove button. Following is the example with data-min = 2:

 

 

As you can see, the first two addable entry don't have remove button.

 

<div class="addable" data-min="2" data-max="10" data-object="addable-test" data-objectify="1"></div>

data-max is the maximum number of addable templates. If there are max number of addable templates, the add button would be disabled.

 

<div class="addable" data-min="2" data-max="10" data-object="addable-test" data-objectify="1"></div>

 data-object is the key of the addable part in result.json.

 

{                                                                               
    "addable-test":                                                             
    [                                                                           
        {                                                                       
            "interfaces": "e123",                                               
            "text": "1.1.1.1",                                                       
            "nchecks": "nc",                                                    
            "checks": "c"                                                       
        },                                                                      
        {                                                                       
            "interfaces": "eth0",                                               
            "text": "1.1.1.2",                                                       
            "nchecks": "nc",                                                    
            "checks": "c"                                                       
        },                                                                      
        {                                                                       
            "interfaces": "eth0",                                               
            "text": "1.1.1.3",                                                       
            "nchecks": "nc",                                                    
            "checks": "c"                                                       
        },                                                                      
        {                                                                       
            "interfaces": "eth0",                                               
            "text": "1.1.1.4",                                                       
            "nchecks": "nc",                                                    
            "checks": "c"                                                       
        }                                                                       
    ]                                                                           
}

Here is a example for the validator:

 

{
    "rules": {
        "interfaces": {
            "required": true,
            "interfaceName": 1
        },
        "text": {
            "required": true,
            "ipv4": 1
        },
        "checks": {
            "required": true
        },
        "nchecks": {
            "required": true
        }
    }
}

In the validator, name of validator methods are pretty intuitive. required means this field is required, ipv4 means input for this field has to be in valid ipv4 format, and interfaceName means the input string needs to be a valid interface name. Each validator looks for the element with matched name. Take a look at the following script:

 

        "interfaces": {
            "required": true,
            "interfaceName": 1
        },

The above script looks for element with name 'interfaces' and check if the field is filled and if the input string is a valid interface name.

 

Here's a few tips for naming convention of input elements in wizard.html:

  1. names don't start with 'other_'
  2. names don't end with numbers. For instance, 'eth1' is not a valid name for wizard. You can use more specific names like 'eth1_address' and etc instead.
  3. If one of the inputs has a name which is another's prefix, it won't work. For instance, if inputs with names 'input' and 'inputa' are in the same wizard form, it would not save result properly. You can change it 'inputa', 'inputb'.
  4. names don't contain special characters 

 

The following screenshot shos what the view looks like when validation fails.

 

 

If all validation passes, the apply function wizard-run is triggered. If changes are applied successfully, you can find the JSON formatted result located in /tmp directory.

 

Note: The result is only saved for demonstration purposes, and you can write your own apply function with or without saving them.