Skip to content

Commit 73c7a4e

Browse files
committed
Initial draft
1 parent ba742f2 commit 73c7a4e

File tree

1 file changed

+348
-0
lines changed

1 file changed

+348
-0
lines changed
+348
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
---
2+
published: false
3+
date: '2016-08-08 14:26 -0600'
4+
title: ''
5+
author: Shelly Cadora
6+
---
7+
## Configuring Model-Driven Telemetry with YDK
8+
9+
## Model-Driven Configuration for Model-Driven Telemetry
10+
11+
In an [earlier tutorial](https://xrdocs.github.io/telemetry/tutorials/2016-07-25-configuring-model-driven-telemetry-mdt-with-yang/), I wrote about how to configure MDT using the OpenConfig Telemetry YANG model using [ncclient](https://github.com/ncclient/ncclient) and a lot of XML. An even simpler way to do this is to use [YDK](https://developer.cisco.com/site/ydk/), a developer toolkit that automatically generates APIs directly from YANG models. The Python classes that are generated by YDK mirror the YANG model hierarchy. So if you know some Python and you understand the YANG model, you can start writing code, no knowledge of NETCONF or XML required.
12+
13+
## The OC Telemetry Model
14+
15+
Let's start by reviewing the struture of the [OpenConfig telemetry model](https://github.com/openconfig/public/blob/master/release/models/telemetry/openconfig-telemetry.yang).
16+
17+
{% capture "output" %}
18+
Script Output:
19+
20+
```
21+
module: openconfig-telemetry
22+
+--rw telemetry-system
23+
+--rw sensor-groups
24+
| +--rw sensor-group* [sensor-group-id]
25+
| +--rw sensor-group-id -> ../config/sensor-group-id
26+
| +--rw config
27+
| | +--rw sensor-group-id? string
28+
| +--ro state
29+
| | +--ro sensor-group-id? string
30+
| +--rw sensor-paths
31+
| +--rw sensor-path* [path]
32+
| +--rw path -> ../config/path
33+
| +--rw config
34+
| | +--rw path? string
35+
| | +--rw exclude-filter? string
36+
| +--ro state
37+
| +--ro path? string
38+
| +--ro exclude-filter? string
39+
+--rw destination-groups
40+
| +--rw destination-group* [group-id]
41+
| +--rw group-id -> ../config/group-id
42+
| +--rw config
43+
| | +--rw group-id? string
44+
| +--ro state
45+
| | +--ro group-id? string
46+
| +--rw destinations
47+
| +--rw destination* [destination-address destination-port]
48+
| +--rw destination-address -> ../config/destination-address
49+
| +--rw destination-port -> ../config/destination-port
50+
| +--rw config
51+
| | +--rw destination-address? inet:ip-address
52+
| | +--rw destination-port? uint16
53+
| | +--rw destination-protocol? telemetry-stream-protocol
54+
| +--ro state
55+
| +--ro destination-address? inet:ip-address
56+
| +--ro destination-port? uint16
57+
| +--ro destination-protocol? telemetry-stream-protocol
58+
+--rw subscriptions
59+
+--rw persistent
60+
| +--rw subscription* [subscription-id]
61+
| +--rw subscription-id -> ../config/subscription-id
62+
| +--rw config
63+
| | +--rw subscription-id? uint64
64+
| | +--rw local-source-address? inet:ip-address
65+
| | +--rw originated-qos-marking? inet:dscp
66+
| +--ro state
67+
| | +--ro subscription-id? uint64
68+
| | +--ro local-source-address? inet:ip-address
69+
| | +--ro originated-qos-marking? inet:dscp
70+
| +--rw sensor-profiles
71+
| | +--rw sensor-profile* [sensor-group]
72+
| | +--rw sensor-group -> ../config/sensor-group
73+
| | +--rw config
74+
| | | +--rw sensor-group? -> /telemetry-system/sensor-groups/sensor-group/config/sensor-group-id
75+
| | | +--rw sample-interval? uint64
76+
| | | +--rw heartbeat-interval? uint64
77+
| | | +--rw suppress-redundant? boolean
78+
| | +--ro state
79+
| | +--ro sensor-group? -> /telemetry-system/sensor-groups/sensor-group/config/sensor-group-id
80+
| | +--ro sample-interval? uint64
81+
| | +--ro heartbeat-interval? uint64
82+
| | +--ro suppress-redundant? boolean
83+
| +--rw destination-groups
84+
| +--rw destination-group* [group-id]
85+
| +--rw group-id -> ../config/group-id
86+
| +--rw config
87+
| | +--rw group-id? -> ../../../../../../../destination-groups/destination-group/group-id
88+
| +--rw state
89+
| +--rw group-id? -> ../../../../../../../destination-groups/destination-group/group-id
90+
+--rw dynamic
91+
+--ro subscription* [subscription-id]
92+
+--ro subscription-id -> ../state/subscription-id
93+
+--ro state
94+
| +--ro subscription-id? uint64
95+
| +--ro destination-address? inet:ip-address
96+
| +--ro destination-port? uint16
97+
| +--ro destination-protocol? telemetry-stream-protocol
98+
| +--ro sample-interval? uint64
99+
| +--ro heartbeat-interval? uint64
100+
| +--ro suppress-redundant? boolean
101+
| +--ro originated-qos-marking? inet:dscp
102+
+--ro sensor-paths
103+
+--ro sensor-path* [path]
104+
+--ro path -> ../state/path
105+
+--ro state
106+
+--ro path? string
107+
+--ro exclude-filter? string
108+
```
109+
{% endcapture %}
110+
111+
<div class="notice--warning">
112+
{{ output | markdownify }}
113+
</div>
114+
115+
You can spend a lot of time understanding the intricacies of YANG and all the details, but all we really need to know for now is that the model has three major sections:
116+
117+
- The **destination-group** tells the router where to send telemetry data and how. Only needed for dial-out configuration.
118+
- The **sensor-group** identifies a list of YANG models that the router should stream.
119+
- The **subscription** ties together the destination-group and the sensor-group.
120+
121+
## Configuring the Router for gRPC Dial-in
122+
123+
YDK leverages ncclient to handle the NETCONF connection:
124+
125+
```python
126+
from ydk.providers import NetconfServiceProvider
127+
from ydk.services import CRUDService
128+
129+
HOST = '10.30.111.9'
130+
PORT = 830
131+
USER = 'cisco'
132+
PASS = 'cisco'
133+
134+
xr = NetconfServiceProvider(address=HOST,
135+
port=PORT,
136+
username=USER,
137+
password=PASS,
138+
protocol = 'ssh')
139+
```
140+
141+
And here's what we get:
142+
143+
{% capture "output" %}
144+
Script Output:
145+
146+
```
147+
<?xml version="1.0"?>
148+
<rpc-reply message-id="urn:uuid:939c718e-81ee-43ec-9733-565aa53fedb2" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
149+
<data>
150+
<telemetry-system xmlns="http://openconfig.net/yang/telemetry">
151+
<sensor-groups>
152+
<sensor-group>
153+
<sensor-group-id>SGroup3</sensor-group-id>
154+
<config>
155+
<sensor-group-id>SGroup3</sensor-group-id>
156+
</config>
157+
<sensor-paths>
158+
<sensor-path>
159+
<path>openconfig-interfaces:interfaces%2finterface</path>
160+
<config>
161+
<path>openconfig-interfaces:interfaces%2finterface</path>
162+
</config>
163+
</sensor-path>
164+
</sensor-paths>
165+
</sensor-group>
166+
</sensor-groups>
167+
<subscriptions>
168+
<persistent>
169+
<subscription>
170+
<subscription-id>Sub3</subscription-id>
171+
<config>
172+
<subscription-id>Sub3</subscription-id>
173+
</config>
174+
<sensor-profiles>
175+
<sensor-profile>
176+
<sensor-group>SGroup3</sensor-group>
177+
<config>
178+
<sensor-group>SGroup3</sensor-group>
179+
<sample-interval>30000</sample-interval>
180+
</config>
181+
</sensor-profile>
182+
</sensor-profiles>
183+
</subscription>
184+
</persistent>
185+
</subscriptions>
186+
</telemetry-system>
187+
</data>
188+
</rpc-reply>
189+
190+
191+
```
192+
{% endcapture %}
193+
194+
<div class="notice--warning">
195+
{{ output | markdownify }}
196+
</div>
197+
198+
So what does all that mean to the router? It breaks down into three parts which you'll recall from the YANG model above:
199+
200+
- The **destination-group** tells the router where to send telemetry data and how. The absence of a destination-group in the output above alerts us to the fact that this is a dial-in configuration (the collector will initiate the session to the router).
201+
- The **sensor-group** identifies a list of YANG models that the router should stream. In this case, the router has a sensor-group called "SGroup3" that will send interface statistics data from the OpenConfig Interfaces YANG model.
202+
- The **subscription** ties together the destination-group and the sensor-group. This router has a subscription name "Sub3" that will send the list of models in SGroup3 at an interval of 30 second (30000 milleseconds).
203+
204+
If you read the [earlier tutorial](https://xrdocs.github.io/telemetry/tutorials/2016-07-21-configuring-model-driven-telemetry-mdt/) on configuring MDT with CLI, you might recognize this as the same as the gRPC dial-in configuration described there. If you missed that thrilling installment, the XML above is the YANG equivalent of this CLI:
205+
206+
{% capture "output" %}
207+
CLI Output:
208+
209+
```
210+
telemetry model-driven
211+
sensor-group SGroup3
212+
sensor-path openconfig-interfaces:interfaces/interface
213+
!
214+
subscription Sub3
215+
sensor-group-id SGroup3 sample-interval 30000
216+
!
217+
```
218+
219+
{% endcapture %}
220+
221+
<div class="notice--info">
222+
{{ output | markdownify }}
223+
</div>
224+
225+
## Edit-Config
226+
227+
So let's say we want to add a second model to SGroup3 (Cisco-IOS-XR-ipv4-arp-oper). We can do that with the following NETCONF operations:
228+
229+
```python
230+
edit_data = '''
231+
<config>
232+
<telemetry-system xmlns="http://openconfig.net/yang/telemetry">
233+
<sensor-groups>
234+
<sensor-group>
235+
<sensor-group-id>SGroup3</sensor-group-id>
236+
<sensor-paths>
237+
<sensor-path>
238+
<config>
239+
<path>Cisco-IOS-XR-ipv4-arp-oper:arp%2fnodes%2fnode%2fentries%2fentry</path>
240+
</config>
241+
</sensor-path>
242+
</sensor-paths>
243+
</sensor-group>
244+
</sensor-groups>
245+
</config>
246+
'''
247+
248+
xr.edit_config(edit_data, target='candidate', format='xml')
249+
xr.commit()
250+
```
251+
252+
If we do a get-config operation again:
253+
254+
```python
255+
c = xr.get_config(source='running', filter=('subtree', filter))
256+
print(c)
257+
```
258+
259+
... we'll see that SGroup3 has the new addition.
260+
261+
262+
{% capture "output" %}
263+
Script Output:
264+
265+
```
266+
<?xml version="1.0"?>
267+
<rpc-reply message-id="urn:uuid:abd0a7ee-5f06-4754-b2a3-dae6e3d797aa" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
268+
<data>
269+
<telemetry-system xmlns="http://openconfig.net/yang/telemetry">
270+
<sensor-groups>
271+
<sensor-group>
272+
<sensor-group-id>SGroup3</sensor-group-id>
273+
<config>
274+
<sensor-group-id>SGroup3</sensor-group-id>
275+
</config>
276+
<sensor-paths>
277+
<sensor-path>
278+
<path>openconfig-interfaces:interfaces%2finterface</path>
279+
<config>
280+
<path>openconfig-interfaces:interfaces%2finterface</path>
281+
</config>
282+
</sensor-path>
283+
<sensor-path>
284+
<path>Cisco-IOS-XR-ipv4-arp-oper:arp%2fnodes%2fnode%2fentries%2fentry</path>
285+
<config>
286+
<path>Cisco-IOS-XR-ipv4-arp-oper:arp%2fnodes%2fnode%2fentries%2fentry</path>
287+
</config>
288+
</sensor-path>
289+
</sensor-paths>
290+
</sensor-group>
291+
</sensor-groups>
292+
<subscriptions>
293+
<persistent>
294+
<subscription>
295+
<subscription-id>Sub3</subscription-id>
296+
<config>
297+
<subscription-id>Sub3</subscription-id>
298+
</config>
299+
<sensor-profiles>
300+
<sensor-profile>
301+
<sensor-group>SGroup3</sensor-group>
302+
<config>
303+
<sensor-group>SGroup3</sensor-group>
304+
<sample-interval>30000</sample-interval>
305+
</config>
306+
</sensor-profile>
307+
</sensor-profiles>
308+
</subscription>
309+
</persistent>
310+
</subscriptions>
311+
</telemetry-system>
312+
</data>
313+
</rpc-reply>
314+
315+
```
316+
{% endcapture %}
317+
318+
<div class="notice--warning">
319+
{{ output | markdownify }}
320+
</div>
321+
322+
And if you need some CLI to reassure yourself that it worked, here it is:
323+
324+
{% capture "output" %}
325+
CLI Output:
326+
327+
```
328+
RP/0/RP0/CPU0:SunC#show run telemetry model-driven
329+
Mon Aug 8 20:09:57.149 UTC
330+
telemetry model-driven
331+
sensor-group SGroup3
332+
sensor-path openconfig-interfaces:interfaces/interface
333+
sensor-path Cisco-IOS-XR-ipv4-arp-oper:arp/nodes/node/entries/entry
334+
!
335+
subscription Sub3
336+
sensor-group-id SGroup3 sample-interval 30000
337+
!
338+
!
339+
```
340+
{% endcapture %}
341+
342+
<div class="notice--info">
343+
{{ output | markdownify }}
344+
</div>
345+
346+
## Conclusion
347+
Armed with the examples in this blog and a understanding of the telemetry YANG model, you should now be able to use YANG configuration models to configure the router to stream YANG models with the operational data you want. How's that for model-driven programmability?
348+

0 commit comments

Comments
 (0)