Skip to content

ANTA catalog for services tests

Tests

VerifyDNSLookup

Verifies the DNS (Domain Name Service) name to IP address resolution.

Expected Results
  • Success: The test will pass if a domain name is resolved to an IP address.
  • Failure: The test will fail if a domain name does not resolve to an IP address.
  • Error: This test will error out if a domain name is invalid.
Examples
anta.tests.services:
  - VerifyDNSLookup:
      domain_names:
        - arista.com
        - www.google.com
        - arista.ca

Inputs

Name Type Description Default
domain_names list[str]
List of domain names.
-
Source code in anta/tests/services.py
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
class VerifyDNSLookup(AntaTest):
    """Verifies the DNS (Domain Name Service) name to IP address resolution.

    Expected Results
    ----------------
    * Success: The test will pass if a domain name is resolved to an IP address.
    * Failure: The test will fail if a domain name does not resolve to an IP address.
    * Error: This test will error out if a domain name is invalid.

    Examples
    --------
    ```yaml
    anta.tests.services:
      - VerifyDNSLookup:
          domain_names:
            - arista.com
            - www.google.com
            - arista.ca
    ```
    """

    description = "Verifies the DNS name to IP address resolution."
    categories: ClassVar[list[str]] = ["services"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="bash timeout 10 nslookup {domain}", revision=1)]

    class Input(AntaTest.Input):
        """Input model for the VerifyDNSLookup test."""

        domain_names: list[str]
        """List of domain names."""

    def render(self, template: AntaTemplate) -> list[AntaCommand]:
        """Render the template for each domain name in the input list."""
        return [template.render(domain=domain_name) for domain_name in self.inputs.domain_names]

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyDNSLookup."""
        self.result.is_success()
        failed_domains = []
        for command in self.instance_commands:
            domain = command.params.domain
            output = command.json_output["messages"][0]
            if f"Can't find {domain}: No answer" in output:
                failed_domains.append(domain)
        if failed_domains:
            self.result.is_failure(f"The following domain(s) are not resolved to an IP address: {', '.join(failed_domains)}")

VerifyDNSServers

Verifies if the DNS (Domain Name Service) servers are correctly configured.

This test performs the following checks for each specified DNS Server:

  1. Confirming correctly registered with a valid IPv4 or IPv6 address with the designated VRF.
  2. Ensuring an appropriate priority level.
Expected Results
  • Success: The test will pass if the DNS server specified in the input is configured with the correct VRF and priority.
  • Failure: The test will fail if any of the following conditions are met:
    • The provided DNS server is not configured.
    • The provided DNS server with designated VRF and priority does not match the expected information.
Examples
anta.tests.services:
  - VerifyDNSServers:
      dns_servers:
        - server_address: 10.14.0.1
          vrf: default
          priority: 1
        - server_address: 10.14.0.11
          vrf: MGMT
          priority: 0

Inputs

Name Type Description Default
dns_servers list[DnsServer]
List of DNS servers to verify.
-
Source code in anta/tests/services.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
class VerifyDNSServers(AntaTest):
    """Verifies if the DNS (Domain Name Service) servers are correctly configured.

    This test performs the following checks for each specified DNS Server:

      1. Confirming correctly registered with a valid IPv4 or IPv6 address with the designated VRF.
      2. Ensuring an appropriate priority level.

    Expected Results
    ----------------
    * Success: The test will pass if the DNS server specified in the input is configured with the correct VRF and priority.
    * Failure: The test will fail if any of the following conditions are met:
        - The provided DNS server is not configured.
        - The provided DNS server with designated VRF and priority does not match the expected information.

    Examples
    --------
    ```yaml
    anta.tests.services:
      - VerifyDNSServers:
          dns_servers:
            - server_address: 10.14.0.1
              vrf: default
              priority: 1
            - server_address: 10.14.0.11
              vrf: MGMT
              priority: 0
    ```
    """

    categories: ClassVar[list[str]] = ["services"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ip name-server", revision=1)]

    class Input(AntaTest.Input):
        """Input model for the VerifyDNSServers test."""

        dns_servers: list[DnsServer]
        """List of DNS servers to verify."""
        DnsServer: ClassVar[type[DnsServer]] = DnsServer

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyDNSServers."""
        self.result.is_success()

        command_output = self.instance_commands[0].json_output["nameServerConfigs"]
        for server in self.inputs.dns_servers:
            address = str(server.server_address)
            vrf = server.vrf
            priority = server.priority
            input_dict = {"ipAddr": address, "vrf": vrf}

            # Check if the DNS server is configured with specified VRF.
            if (output := get_dict_superset(command_output, input_dict)) is None:
                self.result.is_failure(f"{server} - Not configured")
                continue

            # Check if the DNS server priority matches with expected.
            if output["priority"] != priority:
                self.result.is_failure(f"{server} - Incorrect priority - Priority: {output['priority']}")

VerifyErrdisableRecovery

Verifies the errdisable recovery reason, status, and interval.

Expected Results
  • Success: The test will pass if the errdisable recovery reason status is enabled and the interval matches the input.
  • Failure: The test will fail if the errdisable recovery reason is not found, the status is not enabled, or the interval does not match the input.
Examples
anta.tests.services:
  - VerifyErrdisableRecovery:
      reasons:
        - reason: acl
          interval: 30
        - reason: bpduguard
          interval: 30

Inputs

Name Type Description Default
reasons list[ErrDisableReason]
List of errdisable reasons.
-

ErrDisableReason

Name Type Description Default
reason ErrDisableReasons
Type or name of the errdisable reason.
-
interval ErrDisableInterval
Interval of the reason in seconds.
-
Source code in anta/tests/services.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
class VerifyErrdisableRecovery(AntaTest):
    """Verifies the errdisable recovery reason, status, and interval.

    Expected Results
    ----------------
    * Success: The test will pass if the errdisable recovery reason status is enabled and the interval matches the input.
    * Failure: The test will fail if the errdisable recovery reason is not found, the status is not enabled, or the interval does not match the input.

    Examples
    --------
    ```yaml
    anta.tests.services:
      - VerifyErrdisableRecovery:
          reasons:
            - reason: acl
              interval: 30
            - reason: bpduguard
              interval: 30
    ```
    """

    categories: ClassVar[list[str]] = ["services"]
    # NOTE: Only `text` output format is supported for this command
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show errdisable recovery", ofmt="text")]

    class Input(AntaTest.Input):
        """Input model for the VerifyErrdisableRecovery test."""

        reasons: list[ErrDisableReason]
        """List of errdisable reasons."""

        class ErrDisableReason(BaseModel):
            """Model for an errdisable reason."""

            reason: ErrDisableReasons
            """Type or name of the errdisable reason."""
            interval: ErrDisableInterval
            """Interval of the reason in seconds."""

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyErrdisableRecovery."""
        command_output = self.instance_commands[0].text_output
        self.result.is_success()
        for error_reason in self.inputs.reasons:
            input_reason = error_reason.reason
            input_interval = error_reason.interval
            reason_found = False

            # Skip header and last empty line
            lines = command_output.split("\n")[2:-1]
            for line in lines:
                # Skip empty lines
                if not line.strip():
                    continue
                # Split by first two whitespaces
                reason, status, interval = line.split(None, 2)
                if reason != input_reason:
                    continue
                reason_found = True
                actual_reason_data = {"interval": interval, "status": status}
                expected_reason_data = {"interval": str(input_interval), "status": "Enabled"}
                if actual_reason_data != expected_reason_data:
                    failed_log = get_failed_logs(expected_reason_data, actual_reason_data)
                    self.result.is_failure(f"`{input_reason}`:{failed_log}\n")
                break

            if not reason_found:
                self.result.is_failure(f"`{input_reason}`: Not found.\n")

VerifyHostname

Verifies the hostname of a device.

Expected Results
  • Success: The test will pass if the hostname matches the provided input.
  • Failure: The test will fail if the hostname does not match the provided input.
Examples
anta.tests.services:
  - VerifyHostname:
      hostname: s1-spine1

Inputs

Name Type Description Default
hostname str
Expected hostname of the device.
-
Source code in anta/tests/services.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class VerifyHostname(AntaTest):
    """Verifies the hostname of a device.

    Expected Results
    ----------------
    * Success: The test will pass if the hostname matches the provided input.
    * Failure: The test will fail if the hostname does not match the provided input.

    Examples
    --------
    ```yaml
    anta.tests.services:
      - VerifyHostname:
          hostname: s1-spine1
    ```
    """

    categories: ClassVar[list[str]] = ["services"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show hostname", revision=1)]

    class Input(AntaTest.Input):
        """Input model for the VerifyHostname test."""

        hostname: str
        """Expected hostname of the device."""

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyHostname."""
        hostname = self.instance_commands[0].json_output["hostname"]

        if hostname != self.inputs.hostname:
            self.result.is_failure(f"Expected `{self.inputs.hostname}` as the hostname, but found `{hostname}` instead.")
        else:
            self.result.is_success()

Input models

DnsServer

Model for a DNS server configuration.

Name Type Description Default
server_address IPv4Address | IPv6Address
The IPv4 or IPv6 address of the DNS server.
-
vrf str
The VRF instance in which the DNS server resides. Defaults to 'default'.
'default'
priority int
The priority level of the DNS server, ranging from 0 to 4. Lower values indicate a higher priority, with 0 being the highest and 4 the lowest.
Field(ge=0, le=4)
Source code in anta/input_models/services.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class DnsServer(BaseModel):
    """Model for a DNS server configuration."""

    model_config = ConfigDict(extra="forbid")
    server_address: IPv4Address | IPv6Address
    """The IPv4 or IPv6 address of the DNS server."""
    vrf: str = "default"
    """The VRF instance in which the DNS server resides. Defaults to 'default'."""
    priority: int = Field(ge=0, le=4)
    """The priority level of the DNS server, ranging from 0 to 4. Lower values indicate a higher priority, with 0 being the highest and 4 the lowest."""

    def __str__(self) -> str:
        """Return a human-readable string representation of the DnsServer for reporting.

        Examples
        --------
        Server 10.0.0.1 (VRF: default, Priority: 1)
        """
        return f"Server {self.server_address} (VRF: {self.vrf}, Priority: {self.priority})"