ovs_pmd_stats: bugfix for excessive padding with ovs-vswitchd 2.14.99.
[barometer.git] / 3rd_party / ovs_pmd_stats / ovs_pmd_stats.py
1 #!/usr/bin/env python
2 #
3 # Copyright(c) 2017 Intel Corporation. All rights reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #    http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17 # Authors:
18 #   Roman Korynkevych <romanx.korynkevych@intel.com>
19
20 import socket
21 import argparse
22 import json
23 import logging
24
25 HOSTNAME = socket.gethostname()
26 PROG_NAME = 'ovs_pmd_stats'
27 TYPE = 'counter'
28
29 MAIN_THREAD = 'main thread'
30 PMD_THREAD = 'pmd thread'
31
32 REQUEST_MESSAGE = '{"id":0,"method":"dpif-netdev/pmd-stats-show","params":[]}'
33 RESPONSE_MESSAGE_TIMEOUT = 1.0
34
35 # Setup arguments
36 parser = argparse.ArgumentParser(prog=PROG_NAME)
37 parser.add_argument('--socket-pid-file', required=True, help='ovs-vswitchd.pid file location')
38 args = parser.parse_args()
39
40 try:
41     fp = open(args.socket_pid_file, 'r')
42     pid = fp.readline()
43     fp.close()
44 except IOError as e:
45     logging.error('I/O error({}): {}'.format(e.errno, e.strerror))
46     raise SystemExit()
47 except:
48     logging.error('Unexpected error:', sys.exc_info()[0])
49     raise SystemExit()
50
51 server_address = args.socket_pid_file.replace('.pid', '.{}.ctl'.format(pid.strip()))
52
53 # open unix socket to ovs-vswitch
54 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
55 try:
56     sock.connect(server_address)
57 except socket.error as msg:
58     logging.error('Socket address: {} Error: {}'.format(server_address, msg))
59     raise SystemExit()
60
61 # set timeout
62 sock.settimeout(RESPONSE_MESSAGE_TIMEOUT)
63
64 # send request
65 sock.sendall(REQUEST_MESSAGE)
66
67 # listen for respnse message
68 rdata = ''
69 while True:
70     try:
71         rdata += sock.recv(4096)
72
73         if rdata.count('{') == rdata.count('}'):
74           break
75     except socket.timeout:
76         logging.error('Response message has not been received in {} sec.'.format(RESPONSE_MESSAGE_TIMEOUT))
77         raise SystemExit()
78     except socket.error as e:
79         logging.error('Error received while reading: {}'.format(e.strerror))
80         raise SystemExit()
81
82 # parse the message
83 try:
84     s = json.loads(rdata, strict=False)
85 except ValueError as e:
86     logging.error('Failed to parse JSON response: {}'.format(e.strerror))
87     raise SystemExit()
88
89 # check for key string presence in the string
90 if 'result' not in s or 'id' not in s or 'error' not in s:
91     logging.error("One of the keys: ['id'], ['result'], ['error'] is missed in the response")
92     logging.error('Msg: {}'.format(s))
93     raise SystemExit()
94
95 array = s['result'].replace('\t', '').splitlines()
96
97 # submit metrics in collectd format
98 plugin_instance = ''
99 for el in array:
100     if MAIN_THREAD in el or PMD_THREAD in el:
101         plugin_instance = el[:-1].replace(' ', '_')
102     else:
103         type_instance = el.split(':')[0].replace(' ', "_")
104         value = el.split(':')[1].strip().split(' ')[0]
105         print('PUTVAL %s/%s-%s/%s-%s N:%s' % (HOSTNAME, PROG_NAME, plugin_instance, TYPE, type_instance, value))
106
107 # close socket
108 sock.close()