]> git.proxmox.com Git - ceph.git/blame - ceph/qa/tasks/admin_socket.py
import quincy beta 17.1.0
[ceph.git] / ceph / qa / tasks / admin_socket.py
CommitLineData
7c673cae
FG
1"""
2Admin Socket task -- used in rados, powercycle, and smoke testing
3"""
7c673cae
FG
4
5import json
6import logging
7import os
8import time
9
9f95a23c 10from teuthology.exceptions import CommandFailedError
7c673cae
FG
11from teuthology.orchestra import run
12from teuthology import misc as teuthology
13from teuthology.parallel import parallel
14from teuthology.config import config as teuth_config
15
16log = logging.getLogger(__name__)
17
18
19def 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:
9f95a23c 71 for client, tests in config.items():
7c673cae
FG
72 ptask.spawn(_run_tests, ctx, client, tests)
73
74
75def _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 """
7c673cae
FG
87 testdir = teuthology.get_testdir(ctx)
88 max_tries = 120
20effc67
TL
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
9f95a23c
TL
112 log.info('sleeping and retrying ...')
113 time.sleep(1)
20effc67
TL
114 else:
115 # i tried max_tries times..
116 assert ex is not None
117 raise ex
118
7c673cae
FG
119
120def _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)
9f95a23c 132 (remote,) = ctx.cluster.only(client).remotes.keys()
7c673cae
FG
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
9f95a23c 153 for command, config in tests.items():
7c673cae
FG
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 )