Skip to content

Commit 8907c56

Browse files
author
kkumara3
committed
added Policy manipulation example
1 parent 6d8e5d7 commit 8907c56

File tree

4 files changed

+227
-5
lines changed

4 files changed

+227
-5
lines changed

examples/grpc_example.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
""" Basic gRPC getcall configuration. Shows how to set up the vairables
2+
for tls and how to put into the class and get information from the box.
3+
"""
14
import sys
25
sys.path.insert(0, '../')
36
from lib.cisco_grpc_client import CiscoGRPCClient
47
import json
58

69
def main():
710
'''
8-
To not use tls we need to do 2 things.
11+
To not use tls we need to do 2 things.
912
1. Comment the variables creds and options out
1013
2. Remove creds and options CiscoGRPCClient
1114
ex: client = CiscoGRPCClient('11.1.1.10', 57777, 10, 'vagrant', 'vagrant')

examples/route_policy.py

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
"""
2+
This module needs to be able to do a few things using gRPC Openconfig modules.
3+
1. Get information on policy and bgp neighbors.
4+
2. Apple to apply single or multiple policies to an interfaces.
5+
3. Get a policy from box a and apply it to box b.
6+
4. It needs to use templating to create new policies and apply to upload them in the end.
7+
"""
8+
import json
9+
from collections import OrderedDict
10+
import sys
11+
sys.path.insert(0, '../')
12+
from lib.cisco_grpc_client import CiscoGRPCClient
13+
14+
15+
class RoutePolicy(object):
16+
"""Class to manipulate route policy and bgp neighbors using openconfig
17+
"""
18+
def __init__(self, host, port, username, password):
19+
"""This class creates a grpc client for the functions to use.
20+
:param host: The ip address for the device.
21+
:param port: The port for the device.
22+
:param user: Username for device login.
23+
:param password: Password for device login.
24+
:type host: str
25+
:type port: int
26+
:type password: str
27+
:type username: str
28+
"""
29+
self.client = CiscoGRPCClient(host, port, 10, username, password)
30+
31+
def get_policies(self):
32+
"""sends a gRPC request and returns openconfig json of policies
33+
:return: Json string of policies
34+
:rtype: json object
35+
"""
36+
path = '{"openconfig-routing-policy:routing-policy": [null]}'
37+
result = self.client.getconfig(path)
38+
policies = json.loads(result, object_pairs_hook=OrderedDict)
39+
return policies
40+
41+
def list_policies(self):
42+
"""Prints a list policies names for a router
43+
"""
44+
bgp_policies = self.get_policies()
45+
policy_definitions = bgp_policies['openconfig-routing-policy:routing-policy']['policy-definitions']['policy-definition']
46+
print '\nPolicy Names:\n'
47+
for policy in policy_definitions:
48+
print 'Name: %s' % policy['name']
49+
50+
def detail_policy(self, policy_name):
51+
"""Prints the full json of a policy in Openconfig and returns it
52+
:param policy_name: Policy Name on the box (case sensative).
53+
:type policy_name: str
54+
:return: Json string of policy
55+
:rtype: str
56+
"""
57+
bgp_policies = self.get_policies()
58+
policy_definitions = bgp_policies['openconfig-routing-policy:routing-policy']['policy-definitions']['policy-definition']
59+
for policy in policy_definitions:
60+
if policy_name == policy['name']:
61+
print json.dumps(policy, indent=4, separators=(',', ': '))
62+
inner = json.dumps(policy)
63+
template = '{"openconfig-routing-policy:routing-policy": {"policy-definitions": {"policy-definition": [%s]}}}' % inner
64+
return json.dumps(json.loads(template, object_pairs_hook=OrderedDict), indent=4, separators=(',', ': '))
65+
66+
def get_neighbors(self):
67+
"""sends a gRPC request and returns openconfig json of BGP
68+
:return: Json string of policies
69+
:rtype: json object
70+
"""
71+
path = '{"openconfig-bgp:bgp": [null]}'
72+
result = self.client.getconfig(path)
73+
bgp = json.loads(result, object_pairs_hook=OrderedDict)
74+
return bgp
75+
76+
def list_neighbors(self):
77+
"""Prints a list bgp neighbors for a router
78+
"""
79+
bgp = self.get_neighbors()
80+
bgp_neighbors = bgp['openconfig-bgp:bgp']['neighbors']['neighbor']
81+
print "\nNeighbor's\n"
82+
for neighbor in bgp_neighbors:
83+
print 'Neighbor: %s AS: %s' % (neighbor['neighbor-address'], neighbor['config']['peer-as'])
84+
85+
def detail_neighbor(self, neighbor_address):
86+
"""Prints the full json of a neighbor in Openconfig format
87+
:param policy_name: Neighbor Address on the box.
88+
:type policy_name: str
89+
"""
90+
bgp = self.get_neighbors()
91+
bgp_neighbors = bgp['openconfig-bgp:bgp']['neighbors']['neighbor']
92+
for neighbor in bgp_neighbors:
93+
if neighbor_address == neighbor['neighbor-address']:
94+
print json.dumps(neighbor, indent=4, separators=(',', ': '))
95+
inner = json.dumps(neighbor)
96+
template = '{"openconfig-bgp:bgp": {"neighbors": {"neighbor" : [%s]}}}' % inner
97+
return json.dumps(json.loads(template, object_pairs_hook=OrderedDict), indent=4, separators=(',', ': '))
98+
99+
def is_int(self, num):
100+
"""Helper function to see if value is a integer.
101+
Used to figure if its an AS or Neighbor Address
102+
:param num: A number or str
103+
:type: int or str
104+
:rtype boolean
105+
"""
106+
try:
107+
int(num)
108+
return True
109+
except ValueError:
110+
return False
111+
112+
def merge_config(self, config):
113+
"""gRPC merge call to push config changes to Router
114+
:param config: yang structured config in json
115+
:type config: str
116+
:return error if applicable
117+
:rtype str
118+
"""
119+
try:
120+
response = self.client.mergeconfig(config)
121+
if response.errors:
122+
err = json.loads(response.errors)
123+
return json.dumps(err, indent=4, separators=(',', ': '))
124+
except ValueError as err:
125+
return err
126+
127+
def neighbor_policy(self, neighbor_address, policy, direction):
128+
"""Function to update a neighbors or AS policy
129+
:param neighbor_address: neighbor address or AS for policy
130+
:param policy: name of policy to be applied
131+
:param direction: export-policy or import-policy
132+
:type neighbor_address: str or int
133+
:type policy: str
134+
:type direction: str
135+
:returns: Prints neighbors it is applied to, and new bgp neighbor config
136+
"""
137+
updated_neighbors = []
138+
bgp = self.get_neighbors()
139+
bgp_neighbors = bgp['openconfig-bgp:bgp']['neighbors']['neighbor']
140+
for neighbor in bgp_neighbors:
141+
if self.is_int(neighbor_address):
142+
val = neighbor['config']['peer-as']
143+
else:
144+
val = neighbor['neighbor-address']
145+
if val in neighbor_address:
146+
if len(policy) > 1 and isinstance(policy, list):
147+
policy = self.multiple_policies(policy, neighbor_address)
148+
# Change the policy to drop.
149+
ipvs = neighbor['afi-safis']['afi-safi']
150+
for ipv in ipvs:
151+
curr_policy = ipv['apply-policy']['config'][direction]
152+
ipv['apply-policy']['config']['export-policy'] = policy
153+
ip_type = ipv['afi-safi-name']
154+
# Add the removed neighbors to list.
155+
updated_neighbors.append((neighbor['neighbor-address'], ip_type, curr_policy))
156+
updated_neighbors = json.dumps(updated_neighbors)
157+
print updated_neighbors
158+
bgp_config = json.dumps(bgp)
159+
err = self.merge_config(bgp_config)
160+
if not err:
161+
print err
162+
print '\nNew Neighbor Detail:\n'
163+
self.detail_neighbor(neighbor_address)
164+
165+
def multiple_policies(self, policies, neighbor):
166+
"""Creates a new policy that applies list of policies to it.
167+
:param policies: list of policies that you want applied to a single policy
168+
:param neighbor: the neighbor you are going to apply these policies (used for naming)
169+
:type policies: list
170+
:type neighbor: str
171+
:return: Name of the policy that is created
172+
:rtype: str
173+
"""
174+
policy_name = neighbor.replace('.', '_')
175+
policy_name = 'multi_policy_' + policy_name
176+
shell = '{"openconfig-routing-policy:routing-policy": {"policy-definitions": {"policy-definition": [{"name": "%s","statements": {"statement": []}}]}}}' % policy_name
177+
shell = json.loads(shell, object_pairs_hook=OrderedDict)
178+
conditions = shell['openconfig-routing-policy:routing-policy']['policy-definitions']['policy-definition'][0]['statements']['statement']
179+
for policy in policies:
180+
policy_nm = 'Policy_' + policy
181+
json_policy = '{"name": "%s", "conditions": {"call-policy": "%s"}}' % (policy_nm, policy)
182+
json_policy = json.loads(json_policy, object_pairs_hook=OrderedDict)
183+
conditions.append(json_policy)
184+
multi_policy = json.dumps(shell)
185+
print self.merge_config(multi_policy)
186+
return policy_name
187+
188+
def main():
189+
"""
190+
Testing and demoing functions in class
191+
"""
192+
# Create a class object for route policy manipulation
193+
route = RoutePolicy('localhost', 57777, 'vagrant', 'vagrant')
194+
# List Policies from Router
195+
route.list_policies()
196+
print '\nnext function\n'
197+
# Get the full json object of the policy, allows for manipulation
198+
policy = route.detail_policy('TEST')
199+
print '\nnext function\n'
200+
# List BGP neighbors
201+
route.list_neighbors()
202+
print '\nnext function\n'
203+
# Get the full json object of the BGP neighbor, allows for manipulation
204+
route.detail_neighbor('11.1.1.2')
205+
print '\nnext function\n'
206+
# Apply multiple policies to a single neighbor interface
207+
route.neighbor_policy('11.1.1.2', ['TEST', 'SEND-MED-IGP'], 'export-policy')
208+
print '\nnext function\n'
209+
# Store policy in json file to modify
210+
policy_file = open('policy.json', 'w')
211+
policy_file.write(policy)
212+
policy_file.close()
213+
# Merge policy from file to router
214+
policy_file = open('policy.json', 'r')
215+
route.merge_config(policy_file.read())
216+
policy_file.close()
217+
218+
if __name__ == '__main__':
219+
main()

examples/telemetry_collector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def print_connectivity(connectivity):
1212
print connectivity
1313

1414
# Change client details to match your environment.
15-
client = CiscoGRPCClient('10.200.96.16', 57400, 100, 'mdt', 'f33dm3d4t4')
15+
client = CiscoGRPCClient('localhost', 57777, 10, 'vagrant', 'vagrant')
1616
subscription_id = 'sub1'
1717
recv_count = 0
1818
# Handle connectivity changes.

lib/cisco_grpc_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
class CiscoGRPCClient(object):
99
def __init__(self, host, port, timeout, user, password, creds=None, options=None):
1010
"""This class creates grpc calls using python.
11-
:param username: Username for device login
11+
:param user: Username for device login
1212
:param password: Password for device login
1313
:param host: The ip address for the device
1414
:param port: The port for the device
1515
:param timeout: how long before the rpc call timesout
1616
:param creds: Input of the pem file
1717
:param options: TLS server name
1818
:type password: str
19-
:type username: str
20-
:type server: str
19+
:type user: str
20+
:type host: str
2121
:type port: int
2222
:type timeout:int
2323
:type creds: str

0 commit comments

Comments
 (0)