]> git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/admin_socket.py
import quincy beta 17.1.0
[ceph.git] / ceph / qa / tasks / admin_socket.py
1 """
2 Admin Socket task -- used in rados, powercycle, and smoke testing
3 """
4
5 import json
6 import logging
7 import os
8 import time
9
10 from teuthology.exceptions import CommandFailedError
11 from teuthology.orchestra import run
12 from teuthology import misc as teuthology
13 from teuthology.parallel import parallel
14 from teuthology.config import config as teuth_config
15
16 log = logging.getLogger(__name__)
17
18
19 def task(ctx, config):
20 """
21 Run an admin socket command, make sure the output is json, and run
22 a test program on it. The test program should read json from
23 stdin. This task succeeds if the test program exits with status 0.
24
25 To run the same test on all clients::
26
27 tasks:
28 - ceph:
29 - rados:
30 - admin_socket:
31 all:
32 dump_requests:
33 test: http://example.com/script
34
35 To restrict it to certain clients::
36
37 tasks:
38 - ceph:
39 - rados: [client.1]
40 - admin_socket:
41 client.1:
42 dump_requests:
43 test: http://example.com/script
44
45 If an admin socket command has arguments, they can be specified as
46 a list::
47
48 tasks:
49 - ceph:
50 - rados: [client.0]
51 - admin_socket:
52 client.0:
53 dump_requests:
54 test: http://example.com/script
55 help:
56 test: http://example.com/test_help_version
57 args: [version]
58
59 Note that there must be a ceph client with an admin socket running
60 before this task is run. The tests are parallelized at the client
61 level. Tests for a single client are run serially.
62
63 :param ctx: Context
64 :param config: Configuration
65 """
66 assert isinstance(config, dict), \
67 'admin_socket task requires a dict for configuration'
68 teuthology.replace_all_with_clients(ctx.cluster, config)
69
70 with parallel() as ptask:
71 for client, tests in config.items():
72 ptask.spawn(_run_tests, ctx, client, tests)
73
74
75 def _socket_command(ctx, remote, socket_path, command, args):
76 """
77 Run an admin socket command and return the result as a string.
78
79 :param ctx: Context
80 :param remote: Remote site
81 :param socket_path: path to socket
82 :param command: command to be run remotely
83 :param args: command arguments
84
85 :returns: output of command in json format
86 """
87 testdir = teuthology.get_testdir(ctx)
88 max_tries = 120
89 sub_commands = [c.strip() for c in command.split('||')]
90 ex = None
91 for _ in range(max_tries):
92 for sub_command in sub_commands:
93 try:
94 out = remote.sh([
95 'sudo',
96 'adjust-ulimits',
97 'ceph-coverage',
98 '{tdir}/archive/coverage'.format(tdir=testdir),
99 'ceph',
100 '--admin-daemon', socket_path,
101 ] + sub_command.split(' ') + args)
102 except CommandFailedError as e:
103 ex = e
104 log.info('ceph cli "%s" returned an error %s, '
105 'command not registered yet?', sub_command, e)
106 else:
107 log.debug('admin socket command %s returned %s',
108 sub_command, out)
109 return json.loads(out)
110 else:
111 # exhausted all commands
112 log.info('sleeping and retrying ...')
113 time.sleep(1)
114 else:
115 # i tried max_tries times..
116 assert ex is not None
117 raise ex
118
119
120 def _run_tests(ctx, client, tests):
121 """
122 Create a temp directory and wait for a client socket to be created.
123 For each test, copy the executable locally and run the test.
124 Remove temp directory when finished.
125
126 :param ctx: Context
127 :param client: client machine to run the test
128 :param tests: list of tests to run
129 """
130 testdir = teuthology.get_testdir(ctx)
131 log.debug('Running admin socket tests on %s', client)
132 (remote,) = ctx.cluster.only(client).remotes.keys()
133 socket_path = '/var/run/ceph/ceph-{name}.asok'.format(name=client)
134 overrides = ctx.config.get('overrides', {}).get('admin_socket', {})
135
136 try:
137 tmp_dir = os.path.join(
138 testdir,
139 'admin_socket_{client}'.format(client=client),
140 )
141 remote.run(
142 args=[
143 'mkdir',
144 '--',
145 tmp_dir,
146 run.Raw('&&'),
147 # wait for client process to create the socket
148 'while', 'test', '!', '-e', socket_path, run.Raw(';'),
149 'do', 'sleep', '1', run.Raw(';'), 'done',
150 ],
151 )
152
153 for command, config in tests.items():
154 if config is None:
155 config = {}
156 teuthology.deep_merge(config, overrides)
157 log.debug('Testing %s with config %s', command, str(config))
158
159 test_path = None
160 if 'test' in config:
161 # hack: the git_url is always ceph-ci or ceph
162 git_url = teuth_config.get_ceph_git_url()
163 repo_name = 'ceph.git'
164 if git_url.count('ceph-ci'):
165 repo_name = 'ceph-ci.git'
166 url = config['test'].format(
167 branch=config.get('branch', 'master'),
168 repo=repo_name,
169 )
170 test_path = os.path.join(tmp_dir, command)
171 remote.run(
172 args=[
173 'wget',
174 '-q',
175 '-O',
176 test_path,
177 '--',
178 url,
179 run.Raw('&&'),
180 'chmod',
181 'u=rx',
182 '--',
183 test_path,
184 ],
185 )
186
187 args = config.get('args', [])
188 assert isinstance(args, list), \
189 'admin socket command args must be a list'
190 sock_out = _socket_command(ctx, remote, socket_path, command, args)
191 if test_path is not None:
192 remote.run(
193 args=[
194 test_path,
195 ],
196 stdin=json.dumps(sock_out),
197 )
198
199 finally:
200 remote.run(
201 args=[
202 'rm', '-rf', '--', tmp_dir,
203 ],
204 )