Passed
Pull Request — master (#47)
by Italo Valcy
02:50
created

kytos_zabbix.get_data()   B

Complexity

Conditions 8

Size

Total Lines 21
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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