Statistics
| Branch: | Tag: | Revision:

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