1#!/router/bin/python-2.7.4
2
3import re
4import misc_methods
5
6class PlatformResponseMissmatch(Exception):
7    def __init__(self, message):
8        # Call the base class constructor with the parameters it needs
9        super(PlatformResponseMissmatch, self).__init__(message + ' is not available for given platform state and data.\nPlease make sure the relevant features are turned on in the platform.')
10
11class PlatformResponseAmbiguity(Exception):
12    def __init__(self, message):
13        # Call the base class constructor with the parameters it needs
14        super(PlatformResponseAmbiguity, self).__init__(message + ' found more than one file matching the provided filename.\nPlease provide more distinct filename.')
15
16
17class CShowParser(object):
18
19    @staticmethod
20    def parse_drop_stats (query_response, interfaces_list):
21        res          = {'total_drops' : 0}
22        response_lst = query_response.split('\r\n')
23        mtch_found   = 0
24
25        for line in response_lst:
26            mtch = re.match("^\s*(\w+/\d/\d)\s+(\d+)\s+(\d+)", line)
27            if mtch:
28                mtch_found += 1
29                if (mtch.group(1) in interfaces_list):
30                    res[mtch.group(1)] = (int(mtch.group(2)) + int(mtch.group(3)))
31                    res['total_drops'] += (int(mtch.group(2)) + int(mtch.group(3)))
32#       if mtch_found == 0: # no matches found at all
33#           raise PlatformResponseMissmatch('Drop stats')
34#       else:
35#           return res
36        return res
37
38    @staticmethod
39    def parse_nbar_stats (query_response):
40        response_lst = query_response.split('\r\n')
41        stats        = {}
42        final_stats  = {}
43        mtch_found   = 0
44
45        for line in response_lst:
46            mtch = re.match("\s*([\w-]+)\s*(\d+)\s*(\d+)\s+", line)
47            if mtch:
48                mtch_found += 1
49                key     = mtch.group(1)
50                pkt_in  = int(mtch.group(2))
51                pkt_out = int(mtch.group(3))
52
53                avg_pkt_cnt = ( pkt_in + pkt_out )/2
54                if avg_pkt_cnt == 0.0:
55                    # escaping zero division case
56                    continue
57                if key in stats:
58                    stats[key] += avg_pkt_cnt
59                else:
60                    stats[key] = avg_pkt_cnt
61
62        # Normalize the results to percents
63        for protocol in stats:
64            protocol_norm_stat = int(stats[protocol]*10000/stats['Total'])/100.0 # round the result to x.xx format
65            if (protocol_norm_stat != 0.0):
66                final_stats[protocol] = protocol_norm_stat
67
68        if mtch_found == 0: # no matches found at all
69            raise PlatformResponseMissmatch('NBAR classification stats')
70        else:
71            return { 'percentage' : final_stats, 'packets' : stats }
72
73    @staticmethod
74    def parse_nat_stats (query_response):
75        response_lst = query_response.split('\r\n')
76        res          = {}
77        mtch_found   = 0
78
79        for line in response_lst:
80            mtch = re.match("Total (active translations):\s+(\d+).*(\d+)\s+static,\s+(\d+)\s+dynamic", line)
81            if mtch:
82                mtch_found += 1
83                res['total_active_trans']   = int(mtch.group(2))
84                res['static_active_trans']  = int(mtch.group(3))
85                res['dynamic_active_trans'] = int(mtch.group(4))
86                continue
87
88            mtch = re.match("(Hits):\s+(\d+)\s+(Misses):\s+(\d+)", line)
89            if mtch:
90                mtch_found += 1
91                res['num_of_hits']   = int(mtch.group(2))
92                res['num_of_misses'] = int(mtch.group(4))
93
94        if mtch_found == 0: # no matches found at all
95            raise PlatformResponseMissmatch('NAT translations stats')
96        else:
97            return res
98
99    @staticmethod
100    def parse_cpu_util_stats (query_response):
101        response_lst = query_response.split('\r\n')
102        res = { 'cpu0' : 0,
103                'cpu1' : 0 }
104        mtch_found = 0
105        for line in response_lst:
106            mtch = re.match("\W*Processing: Load\D*(\d+)\D*(\d+)\D*(\d+)\D*(\d+)\D*", line)
107            if mtch:
108                mtch_found += 1
109                res['cpu0'] += float(mtch.group(1))
110                res['cpu1'] += float(mtch.group(2))
111
112        if mtch_found == 0: # no matches found at all
113            raise PlatformResponseMissmatch('CPU utilization processing')
114        else:
115            res['cpu0'] = res['cpu0']/mtch_found
116            res['cpu1'] = res['cpu1']/mtch_found
117            return res
118
119    @staticmethod
120    def parse_cft_stats (query_response):
121        response_lst = query_response.split('\r\n')
122        res = {}
123        mtch_found = 0
124        for line in response_lst:
125            mtch = re.match("\W*(\w+)\W*([:]|[=])\W*(\d+)", line)
126            if mtch:
127                mtch_found += 1
128                res[ str( mix_string(m.group(1)) )] = float(m.group(3))
129        if mtch_found == 0: # no matches found at all
130            raise PlatformResponseMissmatch('CFT counters stats')
131        else:
132            return res
133
134
135    @staticmethod
136    def parse_cvla_memory_usage(query_response):
137        response_lst = query_response.split('\r\n')
138        res      = {}
139        res2     = {}
140        cnt      = 0
141        state    = 0
142        name     = ''
143        number   = 0.0
144
145        for line in response_lst:
146            if state == 0:
147                mtch = re.match("\W*Entity name:\W*(\w[^\r\n]+)", line)
148                if mtch:
149                    name = misc_methods.mix_string(mtch.group(1))
150                    state = 1
151                    cnt += 1
152            elif state == 1:
153                mtch = re.match("\W*Handle:\W*(\d+)", line)
154                if mtch:
155                    state = state + 1
156                else:
157                    state = 0;
158            elif state == 2:
159                mtch = re.match("\W*Number of allocations:\W*(\d+)", line)
160                if mtch:
161                    state = state + 1
162                    number=float(mtch.group(1))
163                else:
164                    state = 0;
165            elif state == 3:
166                mtch = re.match("\W*Memory allocated:\W*(\d+)", line)
167                if mtch:
168                    state = 0
169                    res[name]   = float(mtch.group(1))
170                    res2[name]  = number
171                else:
172                    state = 0
173        if cnt == 0:
174            raise PlatformResponseMissmatch('CVLA memory usage stats')
175
176        return (res,res2)
177
178
179    @staticmethod
180    def parse_show_image_version(query_response):
181        response_lst = query_response.split('\r\n')
182        res      = {}
183
184        for line in response_lst:
185            mtch = re.match("System image file is \"(\w+):(.*/)?(.+)\"", line)
186            if mtch:
187                res['drive'] = mtch.group(1)
188                res['image'] = mtch.group(3)
189                return res
190
191        raise PlatformResponseMissmatch('Running image info')
192
193
194    @staticmethod
195    def parse_image_existence(query_response, img_name):
196        response_lst = query_response.split('\r\n')
197        cnt      = 0
198
199        for line in response_lst:
200            regex = re.compile(".* (?!include) %s" % img_name )
201            mtch = regex.match(line)
202            if mtch:
203                cnt += 1
204        if cnt == 1:
205            return True
206        elif cnt > 1:
207            raise PlatformResponseAmbiguity('Image existence')
208        else:
209            return False
210
211    @staticmethod
212    def parse_file_copy (query_response):
213        rev_response_lst = reversed(query_response.split('\r\n'))
214        lines_parsed     = 0
215
216        for line in rev_response_lst:
217            mtch = re.match("\[OK - (\d+) bytes\]", line)
218            if mtch:
219                return True
220            lines_parsed += 1
221
222            if lines_parsed > 5:
223                return False
224        return False
225
226
227if __name__ == "__main__":
228    pass
229