Skip to content

connection

nornir_scrapli.connection

ScrapliConfig

Scrapli connection plugin for nornir

Source code in nornir_scrapli/connection.py
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
class ScrapliConfig:
    """Scrapli connection plugin for nornir"""

    connection: ScrapliCfgPlatform

    @staticmethod
    def get_connection(task: Task) -> ScrapliCfgPlatform:
        """
        Try to fetch scrapli-cfg conn, create it if it doesnt exist

        This is a little different than "normal" in that we dont have a connection and we dont
        create them in the "normal" nornir way -- we actually just steal the scrapli connection and
        wrap the scrapli_cfg bits around it.

        Args:
            task: nornir Task object

        Returns:
            ScrapliCfg

        Raises:
            N/A

        """
        connection: ScrapliCfgPlatform

        try:
            connection = task.host.get_connection("scrapli_cfg", task.nornir.config)
        except AttributeError:
            task.host.connections["scrapli_cfg"] = ScrapliConfig.spawn(task=task)
            connection = task.host.get_connection("scrapli_cfg", task.nornir.config)

        return connection

    @staticmethod
    def spawn(task: Task) -> "ConnectionPlugin":
        """
        Spawn a ScrapliConfig object for a nornir host

        This is a little different than "normal" in that we dont have a connection and we dont
        create them in the "normal" nornir way -- we actually just steal the scrapli connection and
        wrap the scrapli_cfg bits around it.

        Args:
            task: nornir Task object

        Returns:
            ScrapliConfig

        Raises:
            N/A

        """
        scrapli_conn = task.host.get_connection("scrapli", task.nornir.config)
        scrapli_cfg_parameters = task.host.get_connection_parameters(connection="scrapli_cfg")

        # should always be a dict afaik, but typing doesnt appreciate the possibility it is None
        extras = scrapli_cfg_parameters.extras or {}
        # always overwrite `dedicated_connection` as we are *not* having a dedicated connection
        # since we are wrapping the "normal" scrapli connection!
        extras["dedicated_connection"] = False

        final_scrapli_cfg_parameters: Dict[str, Any] = {
            "conn": scrapli_conn,
            **extras,
        }
        connection = ScrapliCfg(**final_scrapli_cfg_parameters)
        scrapli_config_connection_obj = ScrapliConfig()
        scrapli_config_connection_obj.connection = connection
        scrapli_config_connection_obj.open()
        return scrapli_config_connection_obj

    def open(self, *args: Any, **kwargs: Any) -> None:
        """
        Override open method of normal nornir connection so we can coopt an existing conn

        Args:
            args: args for not dealing w/ overridden hings
            kwargs: kwargs for not dealing w/ overridden hings

        Returns:
            None

        Raises:
            N/A

        """
        _, _ = args, kwargs
        self.connection.prepare()

    def close(self) -> None:
        """
        Override close method of normal nornir connection so we never close things

        Never closing allows us to not accidentally step on the underlying "normal" scrapli conn

        Args:
            N/A

        Returns:
            None

        Raises:
            N/A

        """

close() -> None

Override close method of normal nornir connection so we never close things

Never closing allows us to not accidentally step on the underlying "normal" scrapli conn

Returns:

Type Description
None

None

Source code in nornir_scrapli/connection.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
def close(self) -> None:
    """
    Override close method of normal nornir connection so we never close things

    Never closing allows us to not accidentally step on the underlying "normal" scrapli conn

    Args:
        N/A

    Returns:
        None

    Raises:
        N/A

    """

get_connection(task: Task) -> ScrapliCfgPlatform staticmethod

Try to fetch scrapli-cfg conn, create it if it doesnt exist

This is a little different than "normal" in that we dont have a connection and we dont create them in the "normal" nornir way -- we actually just steal the scrapli connection and wrap the scrapli_cfg bits around it.

Parameters:

Name Type Description Default
task Task

nornir Task object

required

Returns:

Type Description
ScrapliCfgPlatform

ScrapliCfg

Source code in nornir_scrapli/connection.py
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
@staticmethod
def get_connection(task: Task) -> ScrapliCfgPlatform:
    """
    Try to fetch scrapli-cfg conn, create it if it doesnt exist

    This is a little different than "normal" in that we dont have a connection and we dont
    create them in the "normal" nornir way -- we actually just steal the scrapli connection and
    wrap the scrapli_cfg bits around it.

    Args:
        task: nornir Task object

    Returns:
        ScrapliCfg

    Raises:
        N/A

    """
    connection: ScrapliCfgPlatform

    try:
        connection = task.host.get_connection("scrapli_cfg", task.nornir.config)
    except AttributeError:
        task.host.connections["scrapli_cfg"] = ScrapliConfig.spawn(task=task)
        connection = task.host.get_connection("scrapli_cfg", task.nornir.config)

    return connection

open(*args: Any, **kwargs: Any) -> None

Override open method of normal nornir connection so we can coopt an existing conn

Parameters:

Name Type Description Default
args

args for not dealing w/ overridden hings

required
kwargs

kwargs for not dealing w/ overridden hings

required

Returns:

Type Description
None

None

Source code in nornir_scrapli/connection.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def open(self, *args: Any, **kwargs: Any) -> None:
    """
    Override open method of normal nornir connection so we can coopt an existing conn

    Args:
        args: args for not dealing w/ overridden hings
        kwargs: kwargs for not dealing w/ overridden hings

    Returns:
        None

    Raises:
        N/A

    """
    _, _ = args, kwargs
    self.connection.prepare()

spawn(task: Task) -> ConnectionPlugin staticmethod

Spawn a ScrapliConfig object for a nornir host

This is a little different than "normal" in that we dont have a connection and we dont create them in the "normal" nornir way -- we actually just steal the scrapli connection and wrap the scrapli_cfg bits around it.

Parameters:

Name Type Description Default
task Task

nornir Task object

required

Returns:

Type Description
ConnectionPlugin

ScrapliConfig

Source code in nornir_scrapli/connection.py
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
@staticmethod
def spawn(task: Task) -> "ConnectionPlugin":
    """
    Spawn a ScrapliConfig object for a nornir host

    This is a little different than "normal" in that we dont have a connection and we dont
    create them in the "normal" nornir way -- we actually just steal the scrapli connection and
    wrap the scrapli_cfg bits around it.

    Args:
        task: nornir Task object

    Returns:
        ScrapliConfig

    Raises:
        N/A

    """
    scrapli_conn = task.host.get_connection("scrapli", task.nornir.config)
    scrapli_cfg_parameters = task.host.get_connection_parameters(connection="scrapli_cfg")

    # should always be a dict afaik, but typing doesnt appreciate the possibility it is None
    extras = scrapli_cfg_parameters.extras or {}
    # always overwrite `dedicated_connection` as we are *not* having a dedicated connection
    # since we are wrapping the "normal" scrapli connection!
    extras["dedicated_connection"] = False

    final_scrapli_cfg_parameters: Dict[str, Any] = {
        "conn": scrapli_conn,
        **extras,
    }
    connection = ScrapliCfg(**final_scrapli_cfg_parameters)
    scrapli_config_connection_obj = ScrapliConfig()
    scrapli_config_connection_obj.connection = connection
    scrapli_config_connection_obj.open()
    return scrapli_config_connection_obj

ScrapliCore

Scrapli connection plugin for nornir

Source code in nornir_scrapli/connection.py
 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
class ScrapliCore:
    """Scrapli connection plugin for nornir"""

    def open(
        self,
        hostname: Optional[str],
        username: Optional[str],
        password: Optional[str],
        port: Optional[int],
        platform: Optional[str],
        extras: Optional[Dict[str, Any]] = None,
        configuration: Optional[Config] = None,
    ) -> None:
        """
        Open a scrapli connection to a device

        Args:
            hostname: hostname from nornir inventory
            username: username from nornir inventory/connection_options for scrapli
            password: password from nornir inventory/connection_options for scrapli
            port: port from nornir inventory/connection_options for scrapli
            platform: platform from nornir inventory/connection_options for scrapli
            extras: extras dict from connection_options for scrapli -- pass all other scrapli
                arguments here
            configuration: nornir configuration

        Returns:
            None

        Raises:
            NornirScrapliInvalidPlatform: if no platform or an invalid scrapli/napalm platform
                string is provided

        """
        extras = extras or {}
        # 99.9% configuration will always be passed here... but to be consistent w/ the other
        # plugins we'll leave the function signature same/same as the others
        global_config = configuration.dict() if configuration else {}

        parameters: Dict[str, Any] = {
            "host": hostname,
            "auth_username": username or "",
            "auth_password": password or "",
            "port": port or 22,
            "ssh_config_file": global_config.get("ssh", {}).get("config_file", False),
        }

        # will override any of the configs from global nornir config (such as ssh config file) with
        # options from "extras" (connection options)
        parameters.update(extras)

        if extras.get("channel_log", False) is True:
            # if channel_log value is just "True" we append the hostname so that we don't have a
            # single file for potentially hundreds (or more!) of devices which obviously won't
            # work very well. don't update the extras dict directly as that is probably coming from
            # group/default vars, so just push this right onto the new parameters' dict.
            parameters.update({"channel_log": f"scrapli_channel_{hostname}.log"})

        if not platform:
            raise NornirScrapliInvalidPlatform(
                f"'platform' not provided in inventory for host `{hostname}`"
            )

        final_platform: str = PLATFORM_MAP.get(platform, platform)

        if final_platform == "generic":
            connection = GenericDriver(**parameters)
        else:
            try:
                connection = Scrapli(**parameters, platform=final_platform)
            except ScrapliModuleNotFound as exc:
                raise NornirScrapliInvalidPlatform(
                    f"Provided platform `{final_platform}` is not a valid scrapli or napalm "
                    "platform, or is not a valid scrapli-community platform."
                ) from exc

        connection.open()
        self.connection = connection  # pylint: disable=W0201

    def close(self) -> None:
        """
        Close a scrapli connection to a device

        Args:
            N/A

        Returns:
            None

        Raises:
            N/A

        """
        self.connection.close()

close() -> None

Close a scrapli connection to a device

Returns:

Type Description
None

None

Source code in nornir_scrapli/connection.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def close(self) -> None:
    """
    Close a scrapli connection to a device

    Args:
        N/A

    Returns:
        None

    Raises:
        N/A

    """
    self.connection.close()

open(hostname: Optional[str], username: Optional[str], password: Optional[str], port: Optional[int], platform: Optional[str], extras: Optional[Dict[str, Any]] = None, configuration: Optional[Config] = None) -> None

Open a scrapli connection to a device

Parameters:

Name Type Description Default
hostname Optional[str]

hostname from nornir inventory

required
username Optional[str]

username from nornir inventory/connection_options for scrapli

required
password Optional[str]

password from nornir inventory/connection_options for scrapli

required
port Optional[int]

port from nornir inventory/connection_options for scrapli

required
platform Optional[str]

platform from nornir inventory/connection_options for scrapli

required
extras Optional[Dict[str, Any]]

extras dict from connection_options for scrapli -- pass all other scrapli arguments here

None
configuration Optional[Config]

nornir configuration

None

Returns:

Type Description
None

None

Raises:

Type Description
NornirScrapliInvalidPlatform

if no platform or an invalid scrapli/napalm platform string is provided

Source code in nornir_scrapli/connection.py
 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
def open(
    self,
    hostname: Optional[str],
    username: Optional[str],
    password: Optional[str],
    port: Optional[int],
    platform: Optional[str],
    extras: Optional[Dict[str, Any]] = None,
    configuration: Optional[Config] = None,
) -> None:
    """
    Open a scrapli connection to a device

    Args:
        hostname: hostname from nornir inventory
        username: username from nornir inventory/connection_options for scrapli
        password: password from nornir inventory/connection_options for scrapli
        port: port from nornir inventory/connection_options for scrapli
        platform: platform from nornir inventory/connection_options for scrapli
        extras: extras dict from connection_options for scrapli -- pass all other scrapli
            arguments here
        configuration: nornir configuration

    Returns:
        None

    Raises:
        NornirScrapliInvalidPlatform: if no platform or an invalid scrapli/napalm platform
            string is provided

    """
    extras = extras or {}
    # 99.9% configuration will always be passed here... but to be consistent w/ the other
    # plugins we'll leave the function signature same/same as the others
    global_config = configuration.dict() if configuration else {}

    parameters: Dict[str, Any] = {
        "host": hostname,
        "auth_username": username or "",
        "auth_password": password or "",
        "port": port or 22,
        "ssh_config_file": global_config.get("ssh", {}).get("config_file", False),
    }

    # will override any of the configs from global nornir config (such as ssh config file) with
    # options from "extras" (connection options)
    parameters.update(extras)

    if extras.get("channel_log", False) is True:
        # if channel_log value is just "True" we append the hostname so that we don't have a
        # single file for potentially hundreds (or more!) of devices which obviously won't
        # work very well. don't update the extras dict directly as that is probably coming from
        # group/default vars, so just push this right onto the new parameters' dict.
        parameters.update({"channel_log": f"scrapli_channel_{hostname}.log"})

    if not platform:
        raise NornirScrapliInvalidPlatform(
            f"'platform' not provided in inventory for host `{hostname}`"
        )

    final_platform: str = PLATFORM_MAP.get(platform, platform)

    if final_platform == "generic":
        connection = GenericDriver(**parameters)
    else:
        try:
            connection = Scrapli(**parameters, platform=final_platform)
        except ScrapliModuleNotFound as exc:
            raise NornirScrapliInvalidPlatform(
                f"Provided platform `{final_platform}` is not a valid scrapli or napalm "
                "platform, or is not a valid scrapli-community platform."
            ) from exc

    connection.open()
    self.connection = connection  # pylint: disable=W0201

ScrapliNetconf

Scrapli NETCONF connection plugin for nornir

Source code in nornir_scrapli/connection.py
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
class ScrapliNetconf:
    """Scrapli NETCONF connection plugin for nornir"""

    def open(
        self,
        hostname: Optional[str],
        username: Optional[str],
        password: Optional[str],
        port: Optional[int],
        platform: Optional[str],
        extras: Optional[Dict[str, Any]] = None,
        configuration: Optional[Config] = None,
    ) -> None:
        """
        Open a scrapli connection to a device

        Args:
            hostname: hostname from nornir inventory
            username: username from nornir inventory/connection_options for scrapli
            password: password from nornir inventory/connection_options for scrapli
            port: port from nornir inventory/connection_options for scrapli
            platform: platform from nornir inventory/connection_options for scrapli; ignored with
                scrapli netconf
            extras: extras dict from connection_options for scrapli -- pass all other scrapli
                arguments here
            configuration: nornir configuration

        Returns:
            None

        Raises:
            N/A

        """
        # platform is irrelevant for scrapli netconf for now
        _ = platform
        extras = extras or {}
        # 99.9% configuration will always be passed here... but to be consistent w/ the other
        # plugins we'll leave the function signature same/same as the others
        global_config = configuration.dict() if configuration else {}

        parameters: Dict[str, Any] = {
            "host": hostname,
            "auth_username": username or "",
            "auth_password": password or "",
            "port": port or 830,
            "ssh_config_file": global_config.get("ssh", {}).get("config_file", False),
        }

        # will override any of the configs from global nornir config (such as ssh config file) with
        # options from "extras" (connection options)
        parameters.update(extras)

        connection = NetconfDriver(**parameters)
        connection.open()
        self.connection = connection  # pylint: disable=W0201

    def close(self) -> None:
        """
        Close a scrapli netconf connection to a device

        Args:
            N/A

        Returns:
            None

        Raises:
            N/A

        """
        self.connection.close()

close() -> None

Close a scrapli netconf connection to a device

Returns:

Type Description
None

None

Source code in nornir_scrapli/connection.py
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
def close(self) -> None:
    """
    Close a scrapli netconf connection to a device

    Args:
        N/A

    Returns:
        None

    Raises:
        N/A

    """
    self.connection.close()

open(hostname: Optional[str], username: Optional[str], password: Optional[str], port: Optional[int], platform: Optional[str], extras: Optional[Dict[str, Any]] = None, configuration: Optional[Config] = None) -> None

Open a scrapli connection to a device

Parameters:

Name Type Description Default
hostname Optional[str]

hostname from nornir inventory

required
username Optional[str]

username from nornir inventory/connection_options for scrapli

required
password Optional[str]

password from nornir inventory/connection_options for scrapli

required
port Optional[int]

port from nornir inventory/connection_options for scrapli

required
platform Optional[str]

platform from nornir inventory/connection_options for scrapli; ignored with scrapli netconf

required
extras Optional[Dict[str, Any]]

extras dict from connection_options for scrapli -- pass all other scrapli arguments here

None
configuration Optional[Config]

nornir configuration

None

Returns:

Type Description
None

None

Source code in nornir_scrapli/connection.py
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
def open(
    self,
    hostname: Optional[str],
    username: Optional[str],
    password: Optional[str],
    port: Optional[int],
    platform: Optional[str],
    extras: Optional[Dict[str, Any]] = None,
    configuration: Optional[Config] = None,
) -> None:
    """
    Open a scrapli connection to a device

    Args:
        hostname: hostname from nornir inventory
        username: username from nornir inventory/connection_options for scrapli
        password: password from nornir inventory/connection_options for scrapli
        port: port from nornir inventory/connection_options for scrapli
        platform: platform from nornir inventory/connection_options for scrapli; ignored with
            scrapli netconf
        extras: extras dict from connection_options for scrapli -- pass all other scrapli
            arguments here
        configuration: nornir configuration

    Returns:
        None

    Raises:
        N/A

    """
    # platform is irrelevant for scrapli netconf for now
    _ = platform
    extras = extras or {}
    # 99.9% configuration will always be passed here... but to be consistent w/ the other
    # plugins we'll leave the function signature same/same as the others
    global_config = configuration.dict() if configuration else {}

    parameters: Dict[str, Any] = {
        "host": hostname,
        "auth_username": username or "",
        "auth_password": password or "",
        "port": port or 830,
        "ssh_config_file": global_config.get("ssh", {}).get("config_file", False),
    }

    # will override any of the configs from global nornir config (such as ssh config file) with
    # options from "extras" (connection options)
    parameters.update(extras)

    connection = NetconfDriver(**parameters)
    connection.open()
    self.connection = connection  # pylint: disable=W0201