1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 55 56 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 104 105 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 166 167 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 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
|
# Basic Usage
## Picking the right Driver
Assuming you are using scrapli to connect to one of the five "core" platforms, you should almost always use the
provided corresponding "core" driver. For example if you are connecting to an Arista EOS device, you should use the
`EOSDriver`. You can select this driver "manually" or using the scrapli factory `Scrapli` (or the async scrapli
factory `AsyncScrapli`).
Importing your driver manually looks like this:
```python
from scrapli.driver.core import EOSDriver
```
If you are using asyncio, you can use the async variant of the driver:
```python
from scrapli.driver.core import AsyncEOSDriver
```
The core drivers and associated platforms are outlined below:
| Platform/OS | Scrapli Driver | Scrapli Async Driver | Platform Name |
|---------------|-----------------|----------------------|---------------|
| Cisco IOS-XE | IOSXEDriver | AsyncIOSXEDriver | cisco_iosxe |
| Cisco NX-OS | NXOSDriver | AsyncNXOSDriver | cisco_nxos |
| Cisco IOS-XR | IOSXRDriver | AsyncIOSXRDriver | cisco_iosxr |
| Arista EOS | EOSDriver | AsyncEOSDriver | arista_eos |
| Juniper JunOS | JunosDriver | AsyncJunosDriver | juniper_junos |
All drivers can be imported from `scrapli.driver.core`.
If you would rather use the factory class to dynamically select the appropriate driver based on a platform string (as
seen in the above table), you can do so as follows:
```python
from scrapli import Scrapli
device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
"platform": "cisco_iosxe"
}
conn = Scrapli(**device)
conn.open()
print(conn.get_prompt())
```
Note that the `Scrapli` and `AsyncScrapli` classes inherit from the `NetworkDriver` and `AsyncNetworkDriver` classes
respectively, so all editor code completion and type indicating behavior should work nicely! For non "core
" platforms please see the [scrapli_community project](https://github.com/scrapli/scrapli_community).
If you are working with a platform not listed above (and/or is not in the scrapli community project), you have three
options:
1. You can use the (base)`Driver` driver directly, which you can read about [here](https://carlmontanari.github.io/scrapli/user_guide/advanced_usage/#using-driver-directly)
2. You can use the `GenericDriver` which you can read about [here](https://carlmontanari.github.io/scrapli/user_guide/advanced_usage/#using-the-genericdriver)
3. You can use the `NetworkDriver` which is similar to option 2 but you will need to understand/provide privilege
/prompt information so scrapli can properly escalate/deescalate to/from configuration (or other) modes.
In general you should probably simply create a scrapli community platform (read about adding a platform
[here](https://github.com/scrapli/scrapli_community#adding-a-platform), but failing that the `GenericDriver` is
probably the simplest path forward.
Note: if you are using async you *must* set the transport to `asyncssh` or `asynctelnet`!
## Basic Driver Arguments
The drivers of course need some information about the device you are trying to connect to. The most common arguments
to provide to the driver are outlined below:
| Argument | Purpose/Value |
|------------------|-------------------------------------------------------------|
| host | name/ip of host to connect to |
| port | port of host to connect to (defaults to port 22) |
| auth_username | username for authentication |
| auth_password | password for authentication |
| auth_secondary | password for secondary authentication (enable password) |
| auth_private_key | private key for authentication |
| auth_strict_key | strict key checking -- TRUE by default! |
| ssh_config_file | True/False or path to ssh config file to use |
These arguments may be passed as keyword arguments to the driver of your choice, or, commonly are passed via
dictionary unpacking as show below:
```python
from scrapli.driver.core import IOSXRDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
conn = IOSXRDriver(**my_device)
conn.open()
```
*NOTE* that scrapli enables strict host key checking by default!
## Opening and Closing a Connection
scrapli does *not* open the connection for you when creating your scrapli connection object in normal operations, you
must manually call the `open` method prior to sending any commands to the device as shown below.
```python
from scrapli.driver.core import IOSXRDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
conn = IOSXRDriver(**my_device)
conn.open()
response = conn.send_command("show version")
```
Connections can be closed by calling the `close` method:
```python
conn.close()
```
scrapli also supports using a context manager (`with` block), when using the context manager the connection will be
automatically opened and closed for you.
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
with IOSXEDriver(**my_device) as conn:
response = conn.send_command("show version")
```
## Sending Commands
When using any of the core network drivers (`JunosDriver`, `EOSDriver`, etc.) or the `GenericDriver`, the `send_command
` and `send_commands` methods will respectively send a single command or list of commands to the device.
When using the core network drivers, the command(s) will be sent at the `default_desired_privilege_level` level which is
typically "privilege exec" (or equivalent) privilege level. Please see [Driver Privilege Levels](https://carlmontanari.github.io/scrapli/user_guide/advanced_usage/#driver-privilege-levels)
in the advanced usage section for more details on privilege levels. As the `GenericDriver` doesn't know or
care about privilege levels you would need to manually handle acquiring the appropriate privilege level for you
command yourself if using that driver.
Note the different methods for sending a single command versus a list of commands!
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
conn = IOSXEDriver(**my_device)
conn.open()
response = conn.send_command("show version")
responses = conn.send_commands(["show run", "show ip int brief"])
```
Finally, if you prefer to have a file containing a list of commands to send, there is a `send_commands_from_file` method
. This method excepts the provided file to have a single command to send per line in the file.
## Response Object
All command/config operations that happen in the `GenericDriver` or any of the drivers inheriting from the
`NetworkDriver` result in a `Response` object being created. The `Response` object contains attributes for the
command sent (`channel_input`), start/end/elapsed time, and of course the result of the command sent.
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
conn = IOSXEDriver(**my_device)
conn.open()
response = conn.send_command("show version")
print(response.elapsed_time)
print(response.result)
```
If using `send_commands` (plural!) then scrapli will return a `MultiResponse` object containing multiple `Response`
objects. The `MultiResponse` object is for all intents and purposes just a list of `Response` objects (with a few
very minor differences).
In addition to containing the input and output of the command(s) that you sent, the `Response` object also contains a
method `textfsm_parse_output` (for more on TextFSM support see
[Textfsm/NTC-Templates Integration](#textfsmntc-templates-integration)) which will attempt to parse and return the
received output. If parsing fails, the value returned will be an empty list -- meaning you will *always* get
"structured data" returned, however it will just be an empty object if parsing fails.
```python
>>> structured_result = response.textfsm_parse_output()
>>> print(structured_result)
[['16.4.1', 'IOS-XE', 'csr1000v', '2 days, 22 hours, 10 minutes', 'reload', 'packages.conf', ['CSR1000V'], ['9FKLJWM5EB0'], '0x2102', []]]
```
## Sending Configurations
When using any of the core drivers, you can send configurations via the `send_config`, `send_configs` or
`send_configs_from_file` methods which will handle privilege escalation for you. `send_config` accepts a single
string, `send_configs` accepts a list of strings, and of course `send_configs_from_file` accepts a string path to a
file containing configurations to send. Note that `send_configs_from_file` -- just like with it's commands sibling
-- will treat each line in the file as a configuration element, in this way it behaves much like `send_configs`.
Lastly, it is good to know that `send_config` (singular!) will parse the configuration string provided and split it
into lines -- this means that the underlying behavior is the same as `send_configs`, however this method returns a
single `Response` object. This `send_config` method can be used to send entire configurations to devices in a
reliable fashion.
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
with IOSXEDriver(**my_device) as conn:
conn.send_configs(["interface loopback123", "description configured by scrapli"])
```
If you need to get into any kind of "special" configuration mode, such as "configure exclusive", "configure private
", or "configure session XYZ", you can pass the name of the corresponding privilege level via the `privilege_level
` argument. Please see the [Driver Privilege Levels](https://carlmontanari.github.io/scrapli/user_guide/advanced_usage/#driver-privilege-levels) section for more details!
Lastly, note that scrapli does *not* exit configuration mode at completion of a "configuration" event -- this is
because scrapli (with the Network drivers) will automatically acquire `default_desired_privilege_level` before
sending a "command" -- so there is no need, from a scrapli perspective, to explicitly exit config mode at end of
the configuration session.
## Textfsm/NTC-Templates Integration
scrapli supports parsing output with TextFSM and ntc-templates. This of course requires installing TextFSM and having
ntc-templates somewhere on your system. When using a platform driver (i.e. `IOSXEDriver`) the textfsm-platform will be
set for you (based on the driver device type). If you wish to parse the output of your send commands, you can use the
`textfsm_parse_output` method of the response object. This method will attempt to find the template for you
-- based on the textfsm-platform and the channel-input (the command sent). If textfsm parsing succeeds, the
structured result is returned. If textfsm parsing fails, an empty list is returned.
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
with IOSXEDriver(**my_device) as conn:
response = conn.send_command("show version")
structured_result = response.textfsm_parse_output()
print(structured_result)
```
scrapli also supports passing in templates manually (meaning not using the pip installed ntc-templates directory to
find templates) if desired. The `textfsm_parse_output` method and `scrapli.helper.textfsm_parse` function both accepts a string or loaded (TextIOWrapper
) template and output to parse. This can be useful if you have custom or one off templates or don't want to pip
install ntc-templates.
```python
from scrapli.driver.core import IOSXEDriver
from scrapli.helper import textfsm_parse
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
with IOSXEDriver(**my_device) as conn:
response = conn.send_command("show version")
structured_result = textfsm_parse("/path/to/my/template", response.result)
```
*NOTE*: If a template does not return structured data an empty list will be returned!
*NOTE*: Textfsm and ntc-templates is an optional extra for scrapli; you can install these modules manually or using
the optional extras install via pip:
`pip install scrapli[textfsm]`
## Cisco Genie Integration
Very much the same as the textfsm/ntc-templates integration, scrapli has optional integration with Cisco's PyATS
/Genie parsing library for parsing show command output. While there are parsers for non-Cisco platforms, this is
currently just an option for Cisco platforms within scrapli.
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
with IOSXEDriver(**my_device) as conn:
response = conn.send_command("show version")
structured_result = response.genie_parse_output()
print(structured_result)
```
*NOTE*: If a parser does not return structured data an empty list will be returned!
*NOTE*: PyATS and Genie is an optional extra for scrapli; you can install these modules manually or using
the optional extras install via pip:
`pip install scrapli[genie]`
## TTP Integration
The scrapli response object also contains a `ttp_parse_output` method, that, as you may have guessed, uses the
[ttp](https://github.com/dmulyalin/ttp) library to parse output received from the device. Other than the obvious
difference that this is in fact a different type of parser, the only difference from a usage perspective is that
the `ttp_parse_output` method requires a template string, string path to a template, or loaded (TextIOWrapper
) template string to be passed. This is because there is no index or mapping of platform:command:template as there
is with TextFSM/ntc-templates and genie.
An example ttp file (slightly modified from the great ttp quickstart guide) - in this case we'll pretend this file is
called "my_template.ttp":
```text
interface {{ interface }}
ip address {{ ip }} {{ mask }}
description {{ description }}
```
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
with IOSXEDriver(**my_device) as conn:
response = conn.send_command("show run interface GigabitEthernet1")
structured_result = response.ttp_parse_output(template="my_template.ttp")
print(structured_result)
```
*NOTE*: If a parser does parse data, ttp will return an empty list (as with the other parser methods)
*NOTE*: ttp is an optional extra for scrapli; you can install these modules manually or using the optional extras
install via pip:
`pip install scrapli[ttp]`
## Handling Prompts
In some cases you may need to run an "interactive" command on your device. The `send_interactive` method of the
`GenericDriver` or its sub-classes (`NetworkDriver` and "core" drivers) can be used to accomplish this. This method
accepts a list of "interact_events" -- or basically commands you would like to send, and their expected resulting
prompt. A third, optional, element is available for each "interaction", this last element is a bool that indicates
weather or not the input that you are sending to the device is "hidden" or obfuscated by the device. This is
typically used for password prompts where the input that is sent does not show up on the screen (if you as a
human are sitting on a terminal typing).
This method can accept one or N "events" and thus can be used to deal with any number of subsequent prompts.
One last important item about this method is that it accepts an argument `privilege_level` -- the value of this
argument should be the name of the privilege level that you would like to execute the interactive command at
. This is an optional argument, with a default of the `default_desired_privilege_level` attribute which is normally
"privilege exec" or similar depending on the platform.
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
}
with IOSXEDriver(**my_device) as conn:
interactive = conn.send_interactive(
[
("copy flash: scp:", "Source filename []?", False),
("somefile.txt", "Address or name of remote host []?", False),
("172.31.254.100", "Destination username [carl]?", False),
("scrapli", "Password:", False),
("super_secure_password", "csr1000v#", True),
]
)
```
## Telnet
scrapli supports telnet as a transport driver via the standard library module `telnetlib` or with a custom-built
async telnet transport (creatively called "asynctelnet") built on the standard library `asycnio`.
A few things worth noting:
- You can set the username and password prompt expect string by passing the `auth_telnet_login_pattern` and
`auth_password_pattern` arguments respectively at driver creation -- *or* if you prefer by using the property
setters of the same names on the channel object, for example: `conn.channel.auth_telnet_login_pattern` prior to
calling `open`.
- If you wish to provide custom prompt values you can provide a string to look for "in" the output from the device,
or a regular expression pattern that starts with `^` and ends with `$` -- if you don't use the line anchors the
pattern will be `re.escape`'d.
- When using telnet you may need to set the `comms_return_char` to `\r\n` the tests against the core platforms pass
without this, however it seems that some console server type devices are looking for this `\r\n` pattern instead of
the default `\n` pattern.
## SSH Config Support
scrapli supports using OpenSSH configuration files in a few ways. For "system" SSH transport (default setting
), passing a path to a config file will simply make scrapli "point" to that file, and therefore use that
configuration files attributes (because it is just exec'ing system SSH!). You can also pass `True` to let
scrapli search in system default locations for a ssh config file (`~/.ssh/config` and `/etc/ssh/ssh_config`).
SSH transports other than "system" transport may support *some* subset of the OpenSSH configuration files, but will
not provide full support. Asyncssh, for example, will automatically pick up and handle proxy-jumps, SSH keys, and
some other items -- this is a 100% asyncssh feature and has nothing to do with scrapli (other than the fact that
scrapli allows you to use asyncssh).
*NOTE* -- scrapli does NOT disable strict host checking by default. Obviously this is the "smart" behavior, but it
can be overridden on a per host basis in your SSH config file, or by passing `False` to the "auth_strict_key
" argument on object instantiation.
```python
from scrapli.driver.core import IOSXEDriver
my_device = {
"host": "172.18.0.11",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
"ssh_config_file": "~/my_ssh_config",
}
with IOSXEDriver(**my_device) as conn:
print(conn.get_prompt())
```
|