summaryrefslogtreecommitdiffstats
path: root/src/ceph/qa/workunits/mon/ping.py
blob: 1773c7369317d0d88fa57cfa4a77e5597aa7d712 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/python

import json
import shlex
import subprocess
import sys

if sys.version_info[0] == 2:
    string = basestring
    unicode = unicode
elif sys.version_info[0] == 3:
    string = str
    unicode = str


class UnexpectedReturn(Exception):
    def __init__(self, cmd, ret, expected, msg):
        if isinstance(cmd, list):
            self.cmd = ' '.join(cmd)
        else:
            assert isinstance(cmd, string) or isinstance(cmd, unicode), \
                'cmd needs to be either a list or a str'
            self.cmd = cmd
        self.cmd = str(self.cmd)
        self.ret = int(ret)
        self.expected = int(expected)
        self.msg = str(msg)

    def __str__(self):
        return repr('{c}: expected return {e}, got {r} ({o})'.format(
            c=self.cmd, e=self.expected, r=self.ret, o=self.msg))


def call(cmd):
    if isinstance(cmd, list):
        args = cmd
    elif isinstance(cmd, string) or isinstance(cmd, unicode):
        args = shlex.split(cmd)
    else:
        assert False, 'cmd is not a string/unicode nor a list!'

    print('call: {0}'.format(args))
    proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    procout, procerr = proc.communicate(None)

    return proc.returncode, procout, procerr


def expect(cmd, expected_ret):
    try:
        (r, out, err) = call(cmd)
    except ValueError as e:
        assert False, \
            'unable to run {c}: {err}'.format(c=repr(cmd), err=str(e))

    if r != expected_ret:
        raise UnexpectedReturn(repr(cmd), r, expected_ret, err)

    return out.decode() if isinstance(out, bytes) else out


def get_quorum_status(timeout=300):
    cmd = 'ceph quorum_status'
    if timeout > 0:
        cmd += ' --connect-timeout {0}'.format(timeout)

    out = expect(cmd, 0)
    j = json.loads(out)
    return j


def main():
    quorum_status = get_quorum_status()
    mon_names = [mon['name'] for mon in quorum_status['monmap']['mons']]

    print('ping all monitors')
    for m in mon_names:
        print('ping mon.{0}'.format(m))
        out = expect('ceph ping mon.{0}'.format(m), 0)
        reply = json.loads(out)

        assert reply['mon_status']['name'] == m, \
            'reply obtained from mon.{0}, expected mon.{1}'.format(
                reply['mon_status']['name'], m)

    print('test out-of-quorum reply')
    for m in mon_names:
        print('testing mon.{0}'.format(m))
        expect('ceph daemon mon.{0} quorum exit'.format(m), 0)

        quorum_status = get_quorum_status()
        assert m not in quorum_status['quorum_names'], \
            'mon.{0} was not supposed to be in quorum ({1})'.format(
                m, quorum_status['quorum_names'])

        out = expect('ceph ping mon.{0}'.format(m), 0)
        reply = json.loads(out)
        mon_status = reply['mon_status']

        assert mon_status['name'] == m, \
            'reply obtained from mon.{0}, expected mon.{1}'.format(
                mon_status['name'], m)

        assert mon_status['state'] == 'electing', \
            'mon.{0} is in state {1}, expected electing'.format(
                m, mon_status['state'])

        expect('ceph daemon mon.{0} quorum enter'.format(m), 0)

    print('OK')


if __name__ == '__main__':
    main()