Passed
Pull Request — master (#56)
by
unknown
02:31
created

kytos_zabbix.print_kytos_stats()   A

Complexity

Conditions 3

Size

Total Lines 8
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 3
nop 2
1
#!/usr/bin/python3
2
"""
3
   This code was created to integrate Kytos napps with Zabbix
4
5
   Created on: Dec/2020
6
   Author: Italo Valcy
7
8
   Changelog:
9
     - 2020/12/10 - Creating the script for monitoring items of Kytos similar to oess_zabbix.py
10
     - 2020/12/15 - adding option to export EVC statistics (bytes and packets)
11
     - 2022/11/30 - bug fixes and integration with kytos-ng/flow_stats rather than flow_manager
12
     - 2023/05/11 - integration with kytos-ng/kytos_stats rather than flow_stats
13
14
"""
15
16
import os
17
import sys
18
import json
19
import argparse
20
import requests
21
import time
22
23
url='http://192.168.0.1:8181/api'
24
25
CACHE_DIR='/var/cache/kytos_zabbix'
26
cache = {
27
 1: CACHE_DIR + '/nodes.json',
28
 2: CACHE_DIR + '/links.json',
29
 3: CACHE_DIR + '/evcs.json',
30
 4: CACHE_DIR + '/flows.json',
31
 5: CACHE_DIR + '/flows.json',
32
 6: CACHE_DIR + '/tables.json',
33
}
34
35
help_msg = "Kytos wrapper for Zabbix"
36
37
parser = argparse.ArgumentParser()
38
parser.add_argument("-l", "--url", dest="url", help="URL for your Kytos REST API", default=url)
39
parser.add_argument("-u", "--user", dest="username", help="Username to authenticate into Kytos API")
40
parser.add_argument("-p", "--pass", dest="password", help="Password to authenticate into Kytos API")
41
parser.add_argument("-f", "--authfile", dest="authfile", help="Authentication file containing username (first line) and password (second line) to authenticate into Kytos API")
42
parser.add_argument("-T", "--timeout", dest="timeout", type=int, help="You can tell Requests to stop waiting for a response after a given number of seconds", default=5)
43
parser.add_argument("-c", "--cache_policy", dest="cache_policy", default=60, help="Cache policy: never, always or X seconds (default to cache for 600 seconds)")
44
parser.add_argument("-o", "--monitoring_option", dest="option", type=int, default=1, choices=[1, 2, 3, 4, 5, 6], help="Monitoring option: 1 - for monitor nodes, 2 - for monitor links, 3 - for monitor evcs (status), 4 - evc statistics, 5 - OpenFlow flows stats, 6 - OpenFlow tables stats")
45
parser.add_argument("-t", "--target", dest="target", help="Item status (0-down/others, 1-disabled, 2-up/primary, 3-up/backup). Argument is the item id to be monitored (depending on the -o option).")
46
parser.add_argument("-z", "--zabbix_output", dest="count_output", type=int, choices=[1, 2], help="Zabbix LLD: (1) Count number of lines in each output or (2) list-only registers", default=None)
47
parser.add_argument("-s", "--stats", dest="stats", type=int, default=1, choices=[1, 2, 3, 4], help="EVC statistics type: 1 - bytes/UNI_A, 2 - bytes/UNI_Z , 3 - packets/UNI_A, 4 - packets/UNI_Z")
48
49
args = parser.parse_args()
50
51
if args.option == 4 and not args.target:
52
    sys.stderr.write('error: to print statistics it requires -t\n')
53
    parser.print_help()
54
    sys.exit(2)
55
56
if args.authfile:
57
    authdata = open(args.authfile).readlines()
58
    args.username = authdata[0].strip()
59
    args.password = authdata[1].strip()
60
61
args.url = os.environ.get("KYTOS_URL", args.url)
62
args.timeout = os.environ.get("KYTOS_TIMEOUT", args.timeout)
63
args.username = os.environ.get("KYTOS_USERNAME", args.username)
64
args.password = os.environ.get("KYTOS_PASSWORD", args.password)
65
66
def is_valid_cache(option):
67
    filename = cache[option]
68
    if not os.path.isfile(filename) or os.path.getsize(filename) == 0:
69
        return False
70
    if args.cache_policy == 'never':
71
        return False
72
    elif args.cache_policy == 'always':
73
        return True
74
    try:
75
        tmout = int(args.cache_policy)
76
    except:
77
        tmout = 600
78
    return os.stat(filename).st_mtime > time.time() - tmout
79
80
def get_data(option, url):
81
    if is_valid_cache(option):
82
        with open(cache[option], 'r') as file:
83
            return file.read()
84
85
    auth = None
86
    if args.username and args.password:
87
        auth = (args.username, args.password)  # assume HTTP Basic
88
89
    try:
90
        response = requests.get(url, auth=auth, timeout=args.timeout)
91
        assert response.status_code == 200, response.text
92
        data = response.text
93
    except Exception as e:
94
        print("ERROR: failed to get data from URL=%s: %s" % (url, e))
95
        sys.exit(2)
96
97
    if args.cache_policy != 'never':
98
        with open(cache[option], 'w') as file:
99
            file.write(data)
0 ignored issues
show
introduced by
The variable data does not seem to be defined for all execution paths.
Loading history...
100
    return data
101
102
def get_kytos_data(url, option):
103
    API_ENDPOINT = ""
104
    if option == 1:
105
        API_ENDPOINT="/kytos/topology/v3/switches"
106
    elif option == 2:
107
        API_ENDPOINT="/kytos/topology/v3/links"
108
    elif option == 3:
109
        API_ENDPOINT="/kytos/mef_eline/v2/evc"
110
    elif option in [4,5]:
111
        API_ENDPOINT="/amlight/kytos_stats/v1/flow/stats"
112
    elif option in [6]:
113
        API_ENDPOINT="/amlight/kytos_stats/v1/table/stats"
114
115
    data = get_data(option, url + API_ENDPOINT)
116
    try:
117
        data = json.loads(data)
118
        if option == 1:
119
            data = data["switches"]
120
        elif option == 2:
121
            data = data["links"]
122
    except Exception as e:
123
        print("ERROR: failed to get data from URL=%s: %s" % (url + API_ENDPOINT, e))
124
        sys.exit(2)
125
126
    return data
127
128
def convert_status(active, enabled):
129
    if active:
130
        return "2"
131
    elif not enabled:
132
        return "1"
133
    else:
134
        return "0"
135
136
def print_target_results(data, option, target):
137
    if target not in data:
138
        print("Unknown target=%s" % (target))
139
        return
140
141
    if option == 1:
142
        sw = data[target]
143
        print(convert_status(sw["active"], sw["enabled"]))
144
    elif option == 2:
145
        link = data[target]
146
        print(convert_status(link["active"], link["enabled"]))
147
    elif option == 3:
148
        evc = data[target]
149
        status = convert_status(evc["active"], evc["enabled"])
150
        if status != "2" or evc.get("dynamic_backup_path", False):
151
            print(status)
152
            return
153
        if evc["current_path"] == evc["primary_path"]:
154
            print("2")
155
        elif evc["current_path"] == evc["backup_path"]:
156
            print("3")
157
        else:
158
            print("0")
159
160
def print_kytos_stats(data, target):
161
    if target:
162
        print(len(data.get(target, [])))
163
    else:
164
        l = 0
165
        for s in data:
166
            l+= len(data[s])
167
        print(l)
168
169
def print_stats(flows, target, stats_type):
170
    evcs = get_kytos_data(args.url, 3)
171
    if target not in evcs:
172
        print("Unknown target=%s" % (target))
173
        return
174
175
    uni_field = 'uni_a'
176
    if stats_type in [2,4]:
177
        uni_field = 'uni_z'
178
    stats_field = 'byte_count'
179
    if stats_type in [3, 4]:
180
        stats_field = 'packet_count'
181
182
    uni = evcs[target][uni_field]['interface_id'].split(':')
183
    sw = ':'.join(uni[:-1])
184
    iface = int(uni[-1])
185
    try:
186
        tag = evcs[target][uni_field]['tag']['value']
187
    except:
188
        tag = None
189
190
    result = 0
191
    for flow_id, flow in flows.get(sw, {}).items():
192
        if format(flow['cookie'], 'x')[2:] == target and flow['match']['in_port'] == iface and flow['match'].get('dl_vlan') == tag:
193
            result += flow[stats_field]
194
195
    print(result)
196
197
def list_items(data, option):
198
    result = {"data":[]}
199
    if option == 1:
200
        for sw in data:
201
            name = data[sw]["metadata"].get("name", None)
202
            if not name:
203
                name = data[sw]["name"]
204
            result["data"].append({"{#OFSWID}": sw, "{#OFSWNAME}": name})
205
    elif option == 2:
206
        for l in data:
207
            link = data[l]
208
            name = link.get("name", None)
209
            if not name:
210
                name = link["endpoint_a"]["name"] + "_" +  link["endpoint_b"]["name"]
211
            result["data"].append({"{#LINKID}": l, "{#LINKNAME}": name})
212
    elif option == 3:
213
        for evc in data:
214
            result["data"].append({"{#EVCID}": evc, "{#EVCNAME}": data[evc]["name"]})
215
    print(json.dumps(result))
216
217
data = get_kytos_data(args.url, args.option)
218
219
if args.option == 4:
220
    print_stats(data, args.target, args.stats)
221
elif args.option in [5, 6]:
222
    print_kytos_stats(data, args.target)
223
elif args.target:
224
    print_target_results(data, args.option, args.target)
225
elif args.count_output == 1:
226
    # Count amount of items
227
    print(len(data))
228
elif args.count_output == 2:
229
    # List in JSON format. Don't show status!
230
    list_items(data, args.option)
231
else:
232
    parser.print_help()
233