Issues (15)

scripts/kytos_zabbix.py (1 issue)

Severity
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, 5], help="EVC statistics type: 1 - bytes/UNI_A, 2 - bytes/UNI_Z , 3 - packets/UNI_A, 4 - packets/UNI_Z. Table statistics type: 5 - active count, default - number of tables")
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 = int(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
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 compare_paths(path1, path2):
137
    if len(path1) != len(path2):
138
        return False
139
    return all(x.get('id') == y.get('id') for x,y in zip(path1, path2))
140
141
def print_target_results(data, option, target):
142
    if target not in data:
143
        print("Unknown target=%s" % (target))
144
        return
145
146
    if option == 1:
147
        sw = data[target]
148
        print(convert_status(sw["active"], sw["enabled"]))
149
    elif option == 2:
150
        link = data[target]
151
        print(convert_status(link["active"], link["enabled"]))
152
    elif option == 3:
153
        evc = data[target]
154
        status = convert_status(evc["active"], evc["enabled"])
155
        if status != "2" or evc.get("dynamic_backup_path", False):
156
            print(status)
157
            return
158
        if compare_paths(evc["current_path"], evc["primary_path"]):
159
            print("2")
160
        elif compare_paths(evc["current_path"], evc["backup_path"]):
161
            print("3")
162
        else:
163
            print("0")
164
165
def print_flow_stats(data, target):
166
    if target:
167
        print(len(data.get(target, [])))
168
    else:
169
        l = 0
170
        for s in data:
171
            l+= len(data[s])
172
        print(l)
173
174
def print_tables_stats(data, target, stats_type):
175
    if target:
176
        split = target.split('::')
177
        dpid = split[0]
178
        tables = data.get(dpid, [])
179
        if len(split) > 1:
180
            table_id = split[1]
181
            if table_id in tables:
182
                tables = {table_id: tables.get(table_id)} 
183
            else:
184
                tables = {} 
185
        if stats_type != 5:
186
            print(len(tables))
187
        else:             
188
            stats = {table_id:table.get('active_count') for table_id, table in tables.items()}
189
            print(stats)  
190
    else:
191
        l = 0
192
        for s in data:
193
            l+= len(data[s])
194
        print(l)
195
196
def print_stats(flows, target, stats_type):
197
    evcs = get_kytos_data(args.url, 3)
198
    if target not in evcs:
199
        print("Unknown target=%s" % (target))
200
        return
201
202
    uni_field = 'uni_a'
203
    if stats_type in [2,4]:
204
        uni_field = 'uni_z'
205
    stats_field = 'byte_count'
206
    if stats_type in [3, 4]:
207
        stats_field = 'packet_count'
208
209
    uni = evcs[target][uni_field]['interface_id'].split(':')
210
    sw = ':'.join(uni[:-1])
211
    iface = int(uni[-1])
212
    try:
213
        tag = evcs[target][uni_field]['tag']['value']
214
    except:
215
        tag = None
216
217
    result = 0
218
    for flow_id, flow in flows.get(sw, {}).items():
219
        if format(flow['cookie'], 'x')[2:] == target and flow['match']['in_port'] == iface and flow['match'].get('dl_vlan') == tag:
220
            result += flow[stats_field]
221
222
    print(result)
223
224
def list_items(data, option):
225
    result = {"data":[]}
226
    if option == 1:
227
        for sw in data:
228
            name = data[sw]["metadata"].get("name", None)
229
            if not name:
230
                name = data[sw]["name"]
231
            result["data"].append({"{#OFSWID}": sw, "{#OFSWNAME}": name})
232
    elif option == 2:
233
        for l in data:
234
            link = data[l]
235
            name = link.get("name", None)
236
            if not name:
237
                name = link["endpoint_a"]["name"] + "_" +  link["endpoint_b"]["name"]
238
            result["data"].append({"{#LINKID}": l, "{#LINKNAME}": name})
239
    elif option == 3:
240
        for evc in data:
241
            result["data"].append({"{#EVCID}": evc, "{#EVCNAME}": data[evc]["name"]})
242
    print(json.dumps(result))
243
244
data = get_kytos_data(args.url, args.option)
245
246
if args.option == 4:
247
    print_stats(data, args.target, args.stats)
248
elif args.option == 5:
249
    print_flow_stats(data, args.target)
250
elif args.option == 6:
251
    print_tables_stats(data, args.target, args.stats)
252
elif args.target:
253
    print_target_results(data, args.option, args.target)
254
elif args.count_output == 1:
255
    # Count amount of items
256
    print(len(data))
257
elif args.count_output == 2:
258
    # List in JSON format. Don't show status!
259
    list_items(data, args.option)
260
else:
261
    parser.print_help()
262