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