Skip to content

Commit bba96ae

Browse files
authored
Merge pull request #12 from cisco-ie/usage-chaining
Builder pattern, XPath parsing, deprecate insecure, change initialization
2 parents 6e0d16e + 757c39f commit bba96ae

File tree

10 files changed

+657
-159
lines changed

10 files changed

+657
-159
lines changed

Pipfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ wheel = "*"
1414
[packages]
1515
grpcio = "*"
1616
protobuf = "*"
17-
enum34 = "*"
1817
six = "*"
18+
cryptography = "*"
1919

2020
[requires]
2121
python_version = "3.6"

README.md

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,119 @@ This library covers the gNMI defined `capabilities`, `get`, `set`, and `subscrib
1414

1515
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.
1616

17+
### ClientBuilder
18+
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:
19+
20+
```
21+
set_target(...)
22+
Specifies the network element to build a client for.
23+
set_os(...)
24+
Specifies which OS wrapper to deliver.
25+
set_secure(...)
26+
Specifies that a secure gRPC channel should be used.
27+
set_secure_from_file(...)
28+
Loads certificates from file system for secure gRPC channel.
29+
set_secure_from_target(...)
30+
Attempts to utilize available certificate from target for secure gRPC channel.
31+
set_call_authentication(...)
32+
Specifies username/password to utilize for authentication.
33+
set_ssl_target_override(...)
34+
Sets the gRPC option to override the SSL target name.
35+
set_channel_option(...)
36+
Sets a gRPC channel option. Implies knowledge of channel options.
37+
construct()
38+
Constructs and returns the built Client.
39+
```
40+
41+
#### Initialization Examples
42+
`ClientBuilder` can be chained for initialization or instantiated line-by-line.
43+
44+
```python
45+
from cisco_gnmi import ClientBuilder
46+
47+
builder = ClientBuilder('127.0.0.1:9339')
48+
builder.set_os('IOS XR')
49+
builder.set_secure_from_target()
50+
builder.set_call_authentication('admin', 'its_a_secret')
51+
client = builder.construct()
52+
53+
# Or...
54+
55+
client = ClientBuilder('127.0.0.1:9339').set_os('IOS XR').set_secure_from_target().set_call_authentication('admin', 'its_a_secret').construct()
56+
```
57+
58+
Using an encrypted channel automatically getting the certificate from the device, quick for testing:
59+
60+
```python
61+
from cisco_gnmi import ClientBuilder
62+
63+
client = ClientBuilder(
64+
'127.0.0.1:9339'
65+
).set_os('IOS XR').set_secure_from_target().set_call_authentication(
66+
'admin',
67+
'its_a_secret'
68+
).construct()
69+
```
70+
71+
Using an owned root certificate on the filesystem:
72+
73+
```python
74+
from cisco_gnmi import ClientBuilder
75+
76+
client = ClientBuilder(
77+
'127.0.0.1:9339'
78+
).set_os('IOS XR').set_secure_from_file(
79+
'ems.pem'
80+
).set_call_authentication(
81+
'admin',
82+
'its_a_secret'
83+
).construct()
84+
```
85+
86+
Passing certificate content to method:
87+
88+
```python
89+
from cisco_gnmi import ClientBuilder
90+
91+
# Note reading as bytes
92+
with open('ems.pem', 'rb') as cert_fd:
93+
root_cert = cert_fd.read()
94+
95+
client = ClientBuilder(
96+
'127.0.0.1:9339'
97+
).set_os('IOS XR').set_secure(
98+
root_cert
99+
).set_call_authentication(
100+
'admin',
101+
'its_a_secret'
102+
).construct()
103+
```
104+
105+
Usage with root certificate, private key, and cert chain:
106+
107+
```python
108+
from cisco_gnmi import ClientBuilder
109+
110+
client = ClientBuilder(
111+
'127.0.0.1:9339'
112+
).set_os('IOS XR').set_secure_from_file(
113+
root_certificates='rootCA.pem',
114+
private_key='client.key',
115+
certificate_chain='client.crt',
116+
).set_call_authentication(
117+
'admin',
118+
'its_a_secret'
119+
).construct()
120+
```
121+
122+
17123
### Client
18124
`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.
19125

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

22128
### XRClient
23-
`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.
129+
`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.
24130

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

requirements.txt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
-i https://pypi.org/simple
2-
enum34
3-
futures ; python_version < '3.2'
4-
grpcio
5-
protobuf
6-
six
2+
asn1crypto==0.24.0
3+
cffi==1.12.3
4+
cryptography==2.7
5+
enum34==1.1.6
6+
futures==3.3.0 ; python_version < '3.2'
7+
grpcio==1.24.0
8+
ipaddress==1.0.22 ; python_version < '3'
9+
protobuf==3.9.2
10+
pycparser==2.19
11+
six==1.12.0

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@
5252
install_requires=[
5353
"grpcio",
5454
"protobuf",
55-
"enum34",
5655
"six",
56+
"cryptography",
5757
],
5858
extras_require={
5959
"dev": [

src/cisco_gnmi/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@
2626

2727
from .client import Client
2828
from .xr import XRClient
29+
from .builder import ClientBuilder
2930

30-
__version__ = "0.0.2"
31+
__version__ = "1.0.0"

src/cisco_gnmi/auth.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Copyright 2019 Cisco Systems
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are
6+
met:
7+
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
11+
The contents of this file are licensed under the Apache License, Version 2.0
12+
(the "License"); you may not use this file except in compliance with the
13+
License. You may obtain a copy of the License at
14+
15+
http://www.apache.org/licenses/LICENSE-2.0
16+
17+
Unless required by applicable law or agreed to in writing, software
18+
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
20+
License for the specific language governing permissions and limitations under
21+
the License.
22+
"""
23+
24+
import grpc
25+
26+
27+
class CiscoAuthPlugin(grpc.AuthMetadataPlugin):
28+
"""A gRPC AuthMetadataPlugin which adds username/password metadata to each call."""
29+
30+
def __init__(self, username, password):
31+
super(CiscoAuthPlugin, self).__init__()
32+
self.username = username
33+
self.password = password
34+
35+
def __call__(self, context, callback):
36+
callback([("username", self.username), ("password", self.password)], None)

0 commit comments

Comments
 (0)