~pwlars/ubuntu-test-cases/auto-offline-devices

« back to all changes in this revision

Viewing changes to tests/health-check/health-check-test-pid.py

  • Committer: Andy Doan
  • Date: 2014-04-23 19:21:18 UTC
  • mto: This revision was merged to the branch mainline in revision 221.
  • Revision ID: andy.doan@canonical.com-20140423192118-pc37rpziylei3nni
add bootchart test

In order to comply with the qa-dashboard expectations, this test
produces a "boot.json" file that re-labels steps to things it
expects like xorg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python3
2
 
#
3
 
#
4
 
# Copyright (C) 2013 Canonical
5
 
#
6
 
# This program is free software; you can redistribute it and/or
7
 
# modify it under the terms of the GNU General Public License
8
 
# as published by the Free Software Foundation; either version 2
9
 
# of the License, or (at your option) any later version.
10
 
#
11
 
# This program is distributed in the hope that it will be useful,
12
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
# GNU General Public License for more details.
15
 
#
16
 
# You should have received a copy of the GNU General Public License
17
 
# along with this program; if not, write to the Free Software
18
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19
 
#
20
 
#
21
 
# Syntax:
22
 
#       health-check-test-pid.py pid [ path-to-threshold-files ]
23
 
#
24
 
# The process name is resolved and the tool will use a
25
 
# `procname`.threshold file to compare against.  If this file does not exist,
26
 
# default.threshold is used.
27
 
#
28
 
 
29
 
import json
30
 
import os
31
 
import subprocess
32
 
import sys
33
 
import psutil
34
 
import platform
35
 
 
36
 
#
37
 
# Default test run durations in seconds
38
 
#
39
 
default_duration = 60
40
 
 
41
 
default_threshold_path = os.path.join(
42
 
    os.path.join(os.path.dirname(__file__), 'thresholds'), platform.machine())
43
 
 
44
 
default_pass_unknown_process = True
45
 
 
46
 
 
47
 
def read_threshold(procname):
48
 
    """Parse thresholds file.
49
 
 
50
 
    lines starting with '#' are comments
51
 
    format is: key value, e.g.
52
 
       health-check.cpu-load.cpu-load-total.total-cpu-percent  0.5
53
 
       health-check.cpu-load.cpu-load-total.user-cpu-percent   0.5
54
 
       health-check.cpu-load.cpu-load-total.system-cpu-percent 0.5
55
 
    """
56
 
    fname = default_threshold_path + "/" + procname + ".threshold"
57
 
    thresholds = {}
58
 
    n = 0
59
 
 
60
 
    with open(fname) as file:
61
 
        for line in file:
62
 
            n = n + 1
63
 
            if len(line) > 1 and not line.startswith("#"):
64
 
                tmp = line.split()
65
 
                if len(tmp) == 2:
66
 
                    thresholds[tmp[0]] = tmp[1]
67
 
                else:
68
 
                    sys.stderr.write(
69
 
                        "Threshold file %s line %d format error" % (fname, n))
70
 
 
71
 
    return thresholds
72
 
 
73
 
 
74
 
def check_threshold(data, key, fullkey, threshold):
75
 
    """Locate a threshold in the JSON data, compare it to the threshold"""
76
 
 
77
 
    try:
78
 
        d = data[key[0]]
79
 
    except KeyError:
80
 
        sys.stderr.write(
81
 
            "health-check JSON data does not have key " + fullkey + "\n")
82
 
        return (True, "Attribute not found and ignored")
83
 
 
84
 
    key = key[1:]
85
 
    if len(key) > 0:
86
 
        return check_threshold(d, key, fullkey, threshold)
87
 
    else:
88
 
        val = float(d)
89
 
        if threshold >= val:
90
 
            cmp = str(threshold) + " >= " + str(val)
91
 
            return (True, cmp)
92
 
        else:
93
 
            cmp = str(threshold) + " < " + str(val)
94
 
            return (False, cmp)
95
 
 
96
 
 
97
 
def check_thresholds(procname, data, thresholds):
98
 
    print("process: " + procname)
99
 
    failed = False
100
 
    for key in sorted(thresholds.keys()):
101
 
        if key.startswith("health-check"):
102
 
            threshold = float(thresholds[key])
103
 
            (ret, str) = check_threshold(data, key.split('.'), key, threshold)
104
 
            if ret:
105
 
                msg = "PASSED"
106
 
            else:
107
 
                msg = "FAILED"
108
 
                failed = True
109
 
 
110
 
            sys.stderr.write(msg + ": " + str + ": " + key + "\n")
111
 
 
112
 
    return failed
113
 
 
114
 
 
115
 
def health_check(pid, procname):
116
 
    """run health-check on a given process
117
 
 
118
 
    :return: True if failed, False if passed
119
 
    """
120
 
    thresholds = read_threshold(procname)
121
 
    #
122
 
    #  Can't test without thresholds
123
 
    #
124
 
    if len(thresholds) == 0:
125
 
        if default_pass_unknown_process:
126
 
            sys.stderr.write("No thresholds for process " + procname + "\n")
127
 
            sys.stderr.write("Defaulting to pass this test\n")
128
 
            return False
129
 
        else:
130
 
            thresholds = read_threshold("default")
131
 
            if len(thresholds) == 0:
132
 
                sys.stderr.write(
133
 
                    "No thresholds for process " + procname + "\n")
134
 
            else:
135
 
                sys.stderr.write(
136
 
                    "Using default thresholds for process " + procname + "\n")
137
 
 
138
 
    duration = default_duration
139
 
 
140
 
    if 'duration' in thresholds:
141
 
        duration = int(thresholds['duration'])
142
 
 
143
 
    filename = "health-check-" + str(pid) + ".json"
144
 
    args = [
145
 
        'health-check', '-c', '-f', '-d', str(duration),
146
 
        '-w', '-W', '-r', '-p', str(pid), '-o', filename
147
 
    ]
148
 
 
149
 
    try:
150
 
        subprocess.check_output(args)
151
 
        with open(filename) as f:
152
 
            data = json.load(f)
153
 
            return check_thresholds(procname, data, thresholds)
154
 
    except subprocess.CalledProcessError as e:
155
 
        print(e)
156
 
        exit(1)
157
 
 
158
 
 
159
 
def get_proc(pid):
160
 
    proc = None
161
 
    try:
162
 
        p = psutil.Process(pid)
163
 
        pgid = os.getpgid(pid)
164
 
        if pgid == 0:
165
 
            sys.stderr.write(
166
 
                "Cannot run health-check on kernel task with PID(%d)\n" % pid)
167
 
        else:
168
 
            proc = p
169
 
    except psutil.NoSuchProcess as e:
170
 
        sys.stderr.write('%s\n' % e)
171
 
    except OSError as e:
172
 
        if e.errno == 3:
173
 
            sys.stderr.write("Cannot find pgid on process with PID %d\n" % pid)
174
 
    return proc.as_dict(attrs=['pid', 'name'])
175
 
 
176
 
 
177
 
def main(pid):
178
 
    if os.getuid() != 0:
179
 
        sys.stderr.write("Need to run as root\n")
180
 
        exit(1)
181
 
 
182
 
    p = get_proc(pid)
183
 
    if not p:
184
 
        exit(1)
185
 
 
186
 
    procname = os.path.basename(p['name'])
187
 
    if (health_check(pid, procname)):
188
 
        exit(1)
189
 
    else:
190
 
        exit(0)
191
 
 
192
 
if __name__ == '__main__':
193
 
    if len(sys.argv) != 2:
194
 
        sys.stderr.write("Usage: %s PID\n" % sys.argv[0])
195
 
        exit(1)
196
 
 
197
 
    pid = int(sys.argv[1])
198
 
    main(pid)