root / utils / proxy.py @ 94fb8123
History | View | Annotate | Download (9.7 kB)
1 |
import nxpy as np |
---|---|
2 |
from ncclient import manager |
3 |
from ncclient.transport.errors import AuthenticationError, SSHError |
4 |
from lxml import etree as ET |
5 |
from django.conf import settings |
6 |
import logging |
7 |
from django.core.cache import cache |
8 |
|
9 |
FORMAT = '%(asctime)s %(levelname)s: %(message)s'
|
10 |
logging.basicConfig(format=FORMAT) |
11 |
logger = logging.getLogger(__name__) |
12 |
logger.setLevel(logging.DEBUG) |
13 |
|
14 |
class Retriever(object): |
15 |
def __init__(self, device=settings.NETCONF_DEVICE, username=settings.NETCONF_USER, password=settings.NETCONF_PASS, filter=settings.ROUTES_FILTER, route_name=None, xml=None): |
16 |
self.device = device
|
17 |
self.username = username
|
18 |
self.password = password
|
19 |
self.filter = filter |
20 |
self.xml = xml
|
21 |
if route_name:
|
22 |
self.filter = settings.ROUTE_FILTER%route_name
|
23 |
|
24 |
def fetch_xml(self): |
25 |
with manager.connect(host=self.device, port=830, username=self.username, password=self.password) as m: |
26 |
xmlconfig = m.get_config(source='running', filter=('subtree',self.filter)).data_xml |
27 |
return xmlconfig
|
28 |
|
29 |
def proccess_xml(self): |
30 |
if self.xml: |
31 |
xmlconfig = self.xml
|
32 |
else:
|
33 |
xmlconfig = self.fetch_xml()
|
34 |
parser = np.Parser() |
35 |
parser.confile = xmlconfig |
36 |
device = parser.export() |
37 |
return device
|
38 |
|
39 |
def fetch_device(self): |
40 |
device = cache.get("device")
|
41 |
if device:
|
42 |
return device
|
43 |
else:
|
44 |
device = self.proccess_xml()
|
45 |
if device.routing_options:
|
46 |
cache.set("device", device)
|
47 |
return device
|
48 |
else:
|
49 |
return False |
50 |
|
51 |
class Applier(object): |
52 |
def __init__(self, route_objects = [], route_object=None, device=settings.NETCONF_DEVICE, username=settings.NETCONF_USER, password=settings.NETCONF_PASS): |
53 |
self.route_object = route_object
|
54 |
self.route_objects = route_objects
|
55 |
self.device = device
|
56 |
self.username = username
|
57 |
self.password = password
|
58 |
|
59 |
def to_xml(self, operation=None): |
60 |
logger.info("Operation: %s"%operation)
|
61 |
if self.route_object: |
62 |
logger.info("Generating XML config")
|
63 |
route_obj = self.route_object
|
64 |
device = np.Device() |
65 |
flow = np.Flow() |
66 |
route = np.Route() |
67 |
flow.routes.append(route) |
68 |
device.routing_options.append(flow) |
69 |
route.name = route_obj.name |
70 |
if operation == "delete": |
71 |
logger.info("Requesting a delete operation")
|
72 |
route.operation = operation |
73 |
device = device.export(netconf_config=True)
|
74 |
return ET.tostring(device)
|
75 |
if route_obj.source:
|
76 |
route.match['source'].append(route_obj.source)
|
77 |
if route_obj.destination:
|
78 |
route.match['destination'].append(route_obj.destination)
|
79 |
if route_obj.protocol:
|
80 |
route.match['protocol'].append(route_obj.protocol)
|
81 |
try:
|
82 |
if route_obj.port:
|
83 |
for port in route_obj.port.all(): |
84 |
route.match['port'].append(port.port)
|
85 |
except:
|
86 |
pass
|
87 |
try:
|
88 |
if route_obj.destinationport:
|
89 |
for port in route_obj.destinationport.all(): |
90 |
route.match['destination-port'].append(port.port)
|
91 |
except:
|
92 |
pass
|
93 |
try:
|
94 |
if route_obj.sourceport:
|
95 |
for port in route_obj.sourceport.all(): |
96 |
route.match['source-port'].append(port.port)
|
97 |
except:
|
98 |
pass
|
99 |
if route_obj.icmpcode:
|
100 |
route.match['icmp-code'].append(route_obj.icmpcode)
|
101 |
if route_obj.icmptype:
|
102 |
route.match['icmp-type'].append(route_obj.icmptype)
|
103 |
if route_obj.tcpflag:
|
104 |
route.match['tcp-flags'].append(route_obj.tcpflag)
|
105 |
try:
|
106 |
if route_obj.dscp:
|
107 |
for dscp in route_obj.dscp.all(): |
108 |
route.match['dscp'].append(dscp.dscp)
|
109 |
except:
|
110 |
pass
|
111 |
if route_obj.fragmenttype:
|
112 |
route.match['fragment'].append(route_obj.fragmenttype)
|
113 |
for thenaction in route_obj.then.all(): |
114 |
if thenaction.action_value:
|
115 |
route.then[thenaction.action] = thenaction.action_value |
116 |
else:
|
117 |
route.then[thenaction.action] = True
|
118 |
if operation == "replace": |
119 |
logger.info("Requesting a replace operation")
|
120 |
route.operation = operation |
121 |
device = device.export(netconf_config=True)
|
122 |
return ET.tostring(device)
|
123 |
else:
|
124 |
return False |
125 |
|
126 |
def delete_routes(self): |
127 |
if self.route_objects: |
128 |
logger.info("Generating XML config")
|
129 |
device = np.Device() |
130 |
flow = np.Flow() |
131 |
for route_object in self.route_objects: |
132 |
route_obj = route_object |
133 |
route = np.Route() |
134 |
flow.routes.append(route) |
135 |
route.name = route_obj.name |
136 |
route.operation = 'delete'
|
137 |
device.routing_options.append(flow) |
138 |
device = device.export(netconf_config=True)
|
139 |
return ET.tostring(device)
|
140 |
else:
|
141 |
return False |
142 |
|
143 |
def apply(self, configuration = None, operation=None): |
144 |
reason = None
|
145 |
if not configuration: |
146 |
configuration = self.to_xml(operation=operation)
|
147 |
edit_is_successful = False
|
148 |
commit_confirmed_is_successful = False
|
149 |
commit_is_successful = False
|
150 |
if configuration:
|
151 |
with manager.connect(host=self.device, port=830, username=self.username, password=self.password) as m: |
152 |
assert(":candidate" in m.server_capabilities) |
153 |
with m.locked(target='candidate'): |
154 |
m.discard_changes() |
155 |
try:
|
156 |
edit_response = m.edit_config(target='candidate', config=configuration, test_option='test-then-set') |
157 |
edit_is_successful, reason = is_successful(edit_response) |
158 |
logger.info("Successfully edited @ %s" % self.device) |
159 |
if not edit_is_successful: |
160 |
raise Exception() |
161 |
except Exception as e: |
162 |
cause="Caught edit exception: %s %s" %(e,reason)
|
163 |
cause=cause.replace('\n', '') |
164 |
logger.error(cause) |
165 |
m.discard_changes() |
166 |
return False, cause |
167 |
if edit_is_successful:
|
168 |
try:
|
169 |
commit_confirmed_response = m.commit(confirmed=True, timeout=settings.COMMIT_CONFIRMED_TIMEOUT)
|
170 |
commit_confirmed_is_successful, reason = is_successful(commit_confirmed_response) |
171 |
|
172 |
if not commit_confirmed_is_successful: |
173 |
raise Exception() |
174 |
else:
|
175 |
logger.info("Successfully confirmed committed @ %s" % self.device) |
176 |
if not settings.COMMIT: |
177 |
return True, "Successfully confirmed committed" |
178 |
except Exception as e: |
179 |
cause="Caught commit confirmed exception: %s %s" %(e,reason)
|
180 |
cause=cause.replace('\n', '') |
181 |
logger.error(cause) |
182 |
return False, cause |
183 |
if settings.COMMIT:
|
184 |
if edit_is_successful and commit_confirmed_is_successful: |
185 |
try:
|
186 |
commit_response = m.commit(confirmed=False)
|
187 |
commit_is_successful, reason = is_successful(commit_response) |
188 |
logger.info("Successfully committed @ %s" % self.device) |
189 |
newconfig = m.get_config(source='running', filter=('subtree',settings.ROUTES_FILTER)).data_xml |
190 |
retrieve = Retriever(xml=newconfig) |
191 |
cache.set("device", retrieve.proccess_xml())
|
192 |
|
193 |
if not commit_is_successful: |
194 |
raise Exception() |
195 |
else:
|
196 |
logger.info("Successfully cached device configuration")
|
197 |
return True, "Successfully committed" |
198 |
except Exception as e: |
199 |
cause="Caught commit exception: %s %s" %(e,reason)
|
200 |
cause=cause.replace('\n', '') |
201 |
logger.error(cause) |
202 |
return False, cause |
203 |
else:
|
204 |
return False, "No configuration was supplied" |
205 |
|
206 |
def is_successful(response): |
207 |
from StringIO import StringIO |
208 |
doc = parsexml_(StringIO(response)) |
209 |
rootNode = doc.getroot() |
210 |
success_list = rootNode.xpath("//*[local-name()='ok']")
|
211 |
if len(success_list)>0: |
212 |
return True, None |
213 |
else:
|
214 |
reason_return = ''
|
215 |
reason_list = rootNode.xpath("//*[local-name()='error-message']")
|
216 |
for reason in reason_list: |
217 |
reason_return = "%s %s" %(reason_return, reason.text)
|
218 |
return False, reason_return |
219 |
|
220 |
|
221 |
def parsexml_(*args, **kwargs): |
222 |
if 'parser' not in kwargs: |
223 |
kwargs['parser'] = ET.ETCompatXMLParser()
|
224 |
doc = ET.parse(*args, **kwargs) |
225 |
return doc
|
226 |
|