Stage Steps

Stage steps are the bread and butter of the clean stage as they do all the heavy lifting.

Lets continue with the ChangeBootVariable example you’ve seen in the previous pages. To change the boot variable on an IOSXE device I would have to take these steps:

  • Delete any existing boot variables

  • Configure my new boot variables

  • Configure the config-register

  • Write memory

  • Verify the boot variables were set correctly

  • Verify the config-register was set correctly

You can see there are six steps to changing and verifying the boot variable on an IOSXE device.

Note

It’s important to keep the steps to a stage small and manageable. This allows us to overwrite small sections of a stage and reuse the rest (for example cat9k doesn’t use the config register).

Adding a step into the clean stage is simple. Lets go through it step-by-step for the first time.

Define a new method and give it a name that clearly describes the step. There are three arguments that will always be defined (self, steps, and device) but there may be more if you are passing arguments to the stage.

1class ChangeBootVariable(BaseStage):
2
3    def delete_boot_variable(self, steps, device):

Note

We have temporarily removed the schema, argument defaults, and exec_order for these examples.

Inside the method we always start with the steps object. Create a step and give it a descriptive title as it will be shown in the logs.

1class ChangeBootVariable(BaseStage):
2
3    def delete_boot_variable(self, steps, device):
4
5        with steps.start("Delete any configure boot variables") as step:

Finally write Python code to complete any actions required.

If you need to fail the step because an exception was caught, make sure to pass the exception object to the step.failed() call using the from_exception argument like in the example. This will ensure the exception traceback is logged for ease of debugging.

 1class ChangeBootVariable(BaseStage):
 2
 3    def delete_boot_variable(self, steps, device):
 4
 5        with steps.start("Delete any configure boot variables") as step:
 6
 7            try:
 8                device.configure("no boot system")
 9            except Exception as e:
10                step.failed("Failed to delete configured boot variables",
11                            from_exception=e)
12
13            step.passed("Successfully deleted configured boot variables")

Adding back the schema, argument defaults, and exec_order, this is what you should have so far.

 1from genie.metaparser.util.schemaengine import Optional
 2from genie.libs.clean import BaseStage
 3
 4class ChangeBootVariable(BaseStage):
 5
 6    # ============
 7    # Stage Schema
 8    # ============
 9    schema = {
10        Optional('images'): list,
11        Optional('timeout'): int,
12        Optional('config_register'): str,
13        Optional('current_running_image'): bool,
14    }
15
16    # =================
17    # Argument Defaults
18    # =================
19    TIMEOUT = 300
20    CONFIG_REGISTER = '0x2102'
21    CURRENT_RUNNING_IMAGE = False
22
23    # ==============================
24    # Execution order of Stage steps
25    # ==============================
26    exec_order = [
27
28    ]
29
30    def delete_boot_variable(self, steps, device):
31
32        with steps.start("Delete any configure boot variables") as step:
33
34            try:
35                device.configure("no boot system")
36            except Exception as e:
37                step.failed("Failed to delete configured boot variables",
38                            from_exception=e)
39
40            step.passed("Successfully deleted configured boot variables")

Passing Step Arguments

To pass arguments to a clean step, add the arguments to the method and if there’s a default, set it equal to that. Here’s an example were we pass images, timeout, and current_running_image. You can see we provided the defaults by using:

timeout=TIMEOUT current_running_image=CURRENT_RUNNING_IMAGE

During runtime these values will be overwritten with user provided values (if provided). You can then use these arguments like you would in any other Python method.

 1import logging
 2
 3from genie.metaparser.util.schemaengine import Optional
 4from genie.libs.clean import BaseStage
 5
 6log = logging.getLogger(__name__)
 7
 8class ChangeBootVariable(BaseStage):
 9
10    # ============
11    # Stage Schema
12    # ============
13    schema = {
14        Optional('images'): list,
15        Optional('timeout'): int,
16        Optional('config_register'): str,
17        Optional('current_running_image'): bool,
18    }
19
20    # =================
21    # Argument Defaults
22    # =================
23    TIMEOUT = 300
24    CONFIG_REGISTER = '0x2102'
25    CURRENT_RUNNING_IMAGE = False
26
27    # ==============================
28    # Execution order of Stage steps
29    # ==============================
30    exec_order = [
31
32    ]
33
34    def delete_boot_variable(self, steps, device):
35
36        with steps.start("Delete any configure boot variables") as step:
37
38            try:
39                device.configure("no boot system")
40            except Exception as e:
41                step.failed("Failed to delete configured boot variables",
42                            from_exception=e)
43
44            step.passed("Successfully deleted configured boot variables")
45
46    def configure_boot_variable(self, steps, device, images, timeout=TIMEOUT,
47                                current_running_image=CURRENT_RUNNING_IMAGE):
48
49        with steps.start("Set boot variable to images provided for {}".format(
50                device.name)) as step:
51
52            if current_running_image:
53                log.info("Retrieving and using the running image due to "
54                         "'current_running_image: True'")
55
56                try:
57                    output = device.parse('show version')
58                    images = [output['version']['system_image']]
59                except Exception as e:
60                    step.failed("Failed to retrieve the running image. Cannot "
61                                "set boot variables",
62                                from_exception=e)
63
64            try:
65                device.api.execute_set_boot_variable(
66                    boot_images=images, timeout=timeout)
67            except Exception as e:
68                step.failed("Failed to set boot variables to images provided",
69                            from_exception=e)
70            else:
71                step.passed("Successfully set boot variables to images provided")