Skip to content

Commit

Permalink
Merge pull request #12 from cisco-ie/usage-chaining
Browse files Browse the repository at this point in the history
Builder pattern, XPath parsing, deprecate insecure, change initialization
  • Loading branch information
remingtonc authored Oct 3, 2019
2 parents 6e0d16e + 757c39f commit bba96ae
Show file tree
Hide file tree
Showing 10 changed files with 657 additions and 159 deletions.
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ wheel = "*"
[packages]
grpcio = "*"
protobuf = "*"
enum34 = "*"
six = "*"
cryptography = "*"

[requires]
python_version = "3.6"
108 changes: 107 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,119 @@ This library covers the gNMI defined `capabilities`, `get`, `set`, and `subscrib

It is *highly* recommended that users of the library learn [Google Protocol Buffers](https://developers.google.com/protocol-buffers/) syntax to significantly ease usage. Understanding how to read Protocol Buffers, and reference [`gnmi.proto`](https://github.com/openconfig/gnmi/blob/master/proto/gnmi/gnmi.proto), will be immensely useful for utilizing gNMI and any other gRPC interface.

### ClientBuilder
Since `v1.0.0` a builder pattern is available with `ClientBuilder`. `ClientBuilder` provides several `set_*` methods which define the intended `Client` connectivity and a `construct` method to construct and return the desired `Client`. There are several major methods involved here:

```
set_target(...)
Specifies the network element to build a client for.
set_os(...)
Specifies which OS wrapper to deliver.
set_secure(...)
Specifies that a secure gRPC channel should be used.
set_secure_from_file(...)
Loads certificates from file system for secure gRPC channel.
set_secure_from_target(...)
Attempts to utilize available certificate from target for secure gRPC channel.
set_call_authentication(...)
Specifies username/password to utilize for authentication.
set_ssl_target_override(...)
Sets the gRPC option to override the SSL target name.
set_channel_option(...)
Sets a gRPC channel option. Implies knowledge of channel options.
construct()
Constructs and returns the built Client.
```

#### Initialization Examples
`ClientBuilder` can be chained for initialization or instantiated line-by-line.

```python
from cisco_gnmi import ClientBuilder

builder = ClientBuilder('127.0.0.1:9339')
builder.set_os('IOS XR')
builder.set_secure_from_target()
builder.set_call_authentication('admin', 'its_a_secret')
client = builder.construct()

# Or...

client = ClientBuilder('127.0.0.1:9339').set_os('IOS XR').set_secure_from_target().set_call_authentication('admin', 'its_a_secret').construct()
```

Using an encrypted channel automatically getting the certificate from the device, quick for testing:

```python
from cisco_gnmi import ClientBuilder

client = ClientBuilder(
'127.0.0.1:9339'
).set_os('IOS XR').set_secure_from_target().set_call_authentication(
'admin',
'its_a_secret'
).construct()
```

Using an owned root certificate on the filesystem:

```python
from cisco_gnmi import ClientBuilder

client = ClientBuilder(
'127.0.0.1:9339'
).set_os('IOS XR').set_secure_from_file(
'ems.pem'
).set_call_authentication(
'admin',
'its_a_secret'
).construct()
```

Passing certificate content to method:

```python
from cisco_gnmi import ClientBuilder

# Note reading as bytes
with open('ems.pem', 'rb') as cert_fd:
root_cert = cert_fd.read()

client = ClientBuilder(
'127.0.0.1:9339'
).set_os('IOS XR').set_secure(
root_cert
).set_call_authentication(
'admin',
'its_a_secret'
).construct()
```

Usage with root certificate, private key, and cert chain:

```python
from cisco_gnmi import ClientBuilder

client = ClientBuilder(
'127.0.0.1:9339'
).set_os('IOS XR').set_secure_from_file(
root_certificates='rootCA.pem',
private_key='client.key',
certificate_chain='client.crt',
).set_call_authentication(
'admin',
'its_a_secret'
).construct()
```


### Client
`Client` is a very barebones class simply implementing `capabilities`, `get`, `set`, and `subscribe` methods. It provides some context around the expectation for what should be supplied to these RPC functions and helpers for validation.

Methods are documented in [`src/cisco_gnmi/client.py`](src/cisco_gnmi/client.py).

### XRClient
`XRClient` inherets from `Client` and provides several wrapper methods which aid with IOS XR-specific behaviors of the gNMI implementation. These are `delete_xpaths`, `get_xpaths`, `set_json`, and `subscribe_xpaths`. These methods make several assumptions about what kind of information will be supplied to them in order to simplify usage of the gNMI RPCs.
`XRClient` inherets from `Client` and provides several wrapper methods which aid with IOS XR-specific behaviors of the gNMI implementation. These are `delete_xpaths`, `get_xpaths`, `set_json`, and `subscribe_xpaths`. These methods make several assumptions about what kind of information will be supplied to them in order to simplify usage of the gNMI RPCs, detailed in the documentation.

Methods are documented in [`src/cisco_gnmi/xr.py`](src/cisco_gnmi/xr.py).

Expand Down
15 changes: 10 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
-i https://pypi.org/simple
enum34
futures ; python_version < '3.2'
grpcio
protobuf
six
asn1crypto==0.24.0
cffi==1.12.3
cryptography==2.7
enum34==1.1.6
futures==3.3.0 ; python_version < '3.2'
grpcio==1.24.0
ipaddress==1.0.22 ; python_version < '3'
protobuf==3.9.2
pycparser==2.19
six==1.12.0
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
install_requires=[
"grpcio",
"protobuf",
"enum34",
"six",
"cryptography",
],
extras_require={
"dev": [
Expand Down
3 changes: 2 additions & 1 deletion src/cisco_gnmi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@

from .client import Client
from .xr import XRClient
from .builder import ClientBuilder

__version__ = "0.0.2"
__version__ = "1.0.0"
36 changes: 36 additions & 0 deletions src/cisco_gnmi/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Copyright 2019 Cisco Systems
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
The contents of this file are licensed under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
"""

import grpc


class CiscoAuthPlugin(grpc.AuthMetadataPlugin):
"""A gRPC AuthMetadataPlugin which adds username/password metadata to each call."""

def __init__(self, username, password):
super(CiscoAuthPlugin, self).__init__()
self.username = username
self.password = password

def __call__(self, context, callback):
callback([("username", self.username), ("password", self.password)], None)
Loading

0 comments on commit bba96ae

Please sign in to comment.