Statistics
| Branch: | Tag: | Revision:

root / utils / proxy.py @ 064ecc91

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, 600)
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):
60
        if self.route_object:
61
            logger.info("Generating XML config")
62
            route_obj = self.route_object
63
            device = np.Device()
64
            flow = np.Flow()
65
            route = np.Route()
66
            flow.routes.append(route)
67
            device.routing_options.append(flow)
68
            route.name = route_obj.name
69
            match = route_obj.match
70
            if match.matchSource:
71
                route.match['source'].append(match.matchSource.address)
72
            if match.matchDestination:
73
                route.match['destination'].append(match.matchDestination.address)
74
            if match.matchprotocol:
75
                route.match['protocol'].append(match.matchprotocol.protocol)
76
            if match.matchport:
77
                for port in match.matchport.all():
78
                    route.match['port'].append(port.port)
79
            if match.matchDestinationPort:
80
                for port in match.matchDestinationPort.all():
81
                    route.match['destination-port'].append(port.port)
82
            if match.matchSourcePort:
83
                for port in match.matchSourcePort.all():
84
                    route.match['source-port'].append(port.port)
85
            if match.matchicmpcode:
86
                route.match['icmp-code'].append(match.matchicmpcode.icmp_code)
87
            if match.matchicmptype:
88
                route.match['icmp-type'].append(match.matchicmptype.icmp_type)
89
            if match.matchTcpFlag:
90
                route.match['tcp-flags'].append(match.matchTcpFlag.tcp_flags)
91
            if match.matchdscp:
92
                for dscp in match.matchdscp.all():
93
                    route.match['dscp'].append(dscp.dscp)
94
            if match.matchfragmenttype:
95
                route.match['fragment'].append(match.matchfragmenttype.fragmenttype)
96
            then = route_obj.then
97
            for thenaction in then.thenaction.all():
98
                if thenaction.action_value:
99
                    route.then[thenaction.action] = thenaction.action_value
100
                else:
101
                    route.then[thenaction.action] = True
102
            device = device.export(netconf_config=True)
103
            return ET.tostring(device)
104
        else:
105
            return False
106
    
107
    def delete_route(self):
108
        if self.route_object:
109
            logger.info("Generating XML config")
110
            route_obj = self.route_object
111
            device = np.Device()
112
            flow = np.Flow()
113
            route = np.Route()
114
            flow.routes.append(route)
115
            device.routing_options.append(flow)
116
            route.name = route_obj.name
117
            route.operation = 'delete'
118
            device = device.export(netconf_config=True)
119
            return ET.tostring(device)
120
        else:
121
            return False
122

    
123
    def delete_routes(self):
124
        if self.route_objects:
125
            logger.info("Generating XML config")
126
            device = np.Device()
127
            flow = np.Flow()
128
            for route_object in self.route_objects:
129
                route_obj = route_object
130
                route = np.Route()
131
                flow.routes.append(route)
132
                route.name = route_obj.name
133
                route.operation = 'delete'
134
            device.routing_options.append(flow)
135
            device = device.export(netconf_config=True)
136
            return ET.tostring(device)
137
        else:
138
            return False    
139
    
140
    def apply(self, configuration = None):
141
        reason = None
142
        if not configuration:
143
            configuration = self.to_xml()
144
        edit_is_successful = False
145
        commit_confirmed_is_successful = False
146
        commit_is_successful = False
147
        if configuration:
148
            with manager.connect(host=self.device, port=830, username=self.username, password=self.password) as m:
149
                assert(":candidate" in m.server_capabilities)
150
                with m.locked(target='candidate'):
151
                    m.discard_changes()
152
                    try:
153
                        edit_response = m.edit_config(target='candidate', config=configuration, test_option='test-then-set')
154
                        edit_is_successful, reason = is_successful(edit_response)
155
                        logger.info("Successfully edited @ %s" % self.device)
156
                        if not edit_is_successful:
157
                            raise Exception()
158
                    except Exception as e:
159
                        cause="Caught edit exception: %s %s" %(e,reason)
160
                        cause=cause.replace('\n', '')
161
                        logger.error(cause)
162
                        m.discard_changes()
163
                        return False, cause
164
                    if edit_is_successful:
165
                        try:
166
                            commit_confirmed_response = m.commit(confirmed=True, timeout=settings.COMMIT_CONFIRMED_TIMEOUT)
167
                            commit_confirmed_is_successful, reason = is_successful(commit_confirmed_response)
168
                                
169
                            if not commit_confirmed_is_successful:
170
                                raise Exception()
171
                            else:
172
                                logger.info("Successfully confirmed committed @ %s" % self.device)
173
                                if not settings.COMMIT:
174
                                    return True, "Successfully confirmed committed"
175
                        except Exception as e:
176
                            cause="Caught commit confirmed exception: %s %s" %(e,reason)
177
                            cause=cause.replace('\n', '')
178
                            logger.error(cause)
179
                            return False, cause
180
                        if settings.COMMIT:
181
                            if edit_is_successful and commit_confirmed_is_successful:
182
                                try:
183
                                    commit_response = m.commit(confirmed=False)
184
                                    commit_is_successful, reason = is_successful(commit_response)
185
                                    logger.info("Successfully committed @ %s" % self.device)
186
                                    newconfig = m.get_config(source='running', filter=('subtree',settings.ROUTES_FILTER)).data_xml
187
                                    retrieve = Retriever(xml=newconfig)
188
                                    cache.set("device", retrieve.proccess_xml(), 600)
189
                                    
190
                                    if not commit_is_successful:
191
                                        raise Exception()
192
                                    else:
193
                                        logger.info("Successfully cached device configuration")
194
                                        return True, "Successfully committed"
195
                                except Exception as e:
196
                                    cause="Caught commit exception: %s %s" %(e,reason)
197
                                    cause=cause.replace('\n', '')
198
                                    logger.error(cause)
199
                                    return False, cause
200
        else:
201
            return False, "No configuration was supplied"
202
            
203
def is_successful(response):
204
    from StringIO import StringIO
205
    doc = parsexml_(StringIO(response))
206
    rootNode = doc.getroot()
207
    success_list = rootNode.xpath("//*[local-name()='ok']")
208
    if len(success_list)>0:
209
        return True, None
210
    else:
211
        reason_return = ''
212
        reason_list = rootNode.xpath("//*[local-name()='error-message']")
213
        for reason in reason_list:
214
            reason_return = "%s %s" %(reason_return, reason.text)  
215
        return False, reason_return
216
    
217
    
218
def parsexml_(*args, **kwargs):
219
    if 'parser' not in kwargs:
220
        kwargs['parser'] = ET.ETCompatXMLParser()
221
    doc = ET.parse(*args, **kwargs)
222
    return doc
223