]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/workunits/mon/test_mon_config_key.py
3 # test_mon_config_key - Test 'ceph config-key' interface
5 # Copyright (C) 2013 Inktank
7 # This is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License version 2.1, as published by the Free Software
10 # Foundation. See file COPYING.
25 # Accepted Environment variables:
26 # CEPH_TEST_VERBOSE - be more verbose; '1' enables; '0' disables
27 # CEPH_TEST_DURATION - test duration in seconds
28 # CEPH_TEST_SEED - seed to be used during the test
30 # Accepted arguments and options (see --help):
31 # -v, --verbose - be more verbose
32 # -d, --duration SECS - test duration in seconds
33 # -s, --seed SEED - seed to be used during the test
37 LOG
= logging
.getLogger(os
.path
.basename(sys
.argv
[0].replace('.py', '')))
51 # tests will be randomly selected from the keys here, and the test
52 # suboperation will be randomly selected from the list in the values
53 # here. i.e. 'exists/existing' would test that a key the test put into
54 # the store earlier actually does still exist in the config store,
55 # and that's a separate test case from 'exists/enoent', which tests
56 # nonexistence of a key known to not be present.
59 'put': ['existing', 'new'],
60 'del': ['existing', 'enoent'],
61 'exists': ['existing', 'enoent'],
62 'get': ['existing', 'enoent'],
63 'list': ['existing', 'enoent'],
64 'dump': ['existing', 'enoent'],
67 CONFIG_PUT
= [] # list: keys
68 CONFIG_DEL
= [] # list: keys
69 CONFIG_EXISTING
= {} # map: key -> size
72 def run_cmd(cmd
, expects
=0):
73 full_cmd
= ['ceph', 'config-key'] + cmd
78 cmdlog
= LOG
.getChild('run_cmd')
79 cmdlog
.debug('{fc}'.format(fc
=' '.join(full_cmd
)))
81 proc
= subprocess
.Popen(full_cmd
,
82 stdout
=subprocess
.PIPE
,
83 stderr
=subprocess
.PIPE
)
89 out
, err
= proc
.communicate()
91 stdout
+= out
.decode().split('\n')
92 cmdlog
.debug('stdout: {s}'.format(s
=out
))
94 stdout
+= err
.decode().split('\n')
95 cmdlog
.debug('stderr: {s}'.format(s
=err
))
101 cmdlog
.error('cmd > {cmd}'.format(cmd
=full_cmd
))
102 cmdlog
.error("expected return '{expected}' got '{got}'".format(
103 expected
=expects
, got
=ret
))
104 cmdlog
.error('stdout')
106 cmdlog
.error('{x}'.format(x
=i
))
107 cmdlog
.error('stderr')
109 cmdlog
.error('{x}'.format(x
=i
))
114 def gen_data(size
, rnd
):
115 chars
= string
.ascii_letters
+ string
.digits
116 return ''.join(rnd
.choice(chars
) for _
in range(size
))
120 return gen_data(20, rnd
)
123 def gen_tmp_file_path(rnd
):
124 file_name
= gen_data(20, rnd
)
125 file_path
= os
.path
.join('/tmp', 'ceph-test.' + file_name
)
129 def destroy_tmp_file(fpath
):
130 if os
.path
.exists(fpath
) and os
.path
.isfile(fpath
):
134 def write_data_file(data
, rnd
):
135 file_path
= gen_tmp_file_path(rnd
)
136 data_file
= open(file_path
, 'a+')
138 data_file
.write(data
)
143 # end write_data_file
145 def choose_random_op(rnd
):
149 sop
= rnd
.choice(OPS
[op
])
153 def parse_args(args
):
154 parser
= argparse
.ArgumentParser(
155 description
="Test the monitor's 'config-key' API",
160 help='be more verbose',
165 help='use SEED instead of generating it in run-time',
170 help='run test for SECS seconds (default: 300)',
177 return parser
.parse_args(args
)
181 args
= parse_args(sys
.argv
[1:])
183 verbose
= args
.verbose
184 if os
.environ
.get('CEPH_TEST_VERBOSE') is not None:
185 verbose
= (os
.environ
.get('CEPH_TEST_VERBOSE') == '1')
187 duration
= int(os
.environ
.get('CEPH_TEST_DURATION', args
.duration
))
188 seed
= os
.environ
.get('CEPH_TEST_SEED', args
.seed
)
189 seed
= int(time
.time()) if seed
is None else int(seed
)
191 rnd
= random
.Random()
194 loglevel
= logging
.INFO
196 loglevel
= logging
.DEBUG
198 logging
.basicConfig(level
=loglevel
)
200 LOG
.info('seed: {s}'.format(s
=seed
))
204 while (time
.time() - start
) < duration
:
205 (op
, sop
) = choose_random_op(rnd
)
207 LOG
.info('{o}({s})'.format(o
=op
, s
=sop
))
208 op_log
= LOG
.getChild('{o}({s})'.format(o
=op
, s
=sop
))
211 via_file
= (rnd
.uniform(0, 100) < 50.0)
217 if sop
== 'existing':
218 if len(CONFIG_EXISTING
) == 0:
219 op_log
.debug('no existing keys; continue')
221 key
= rnd
.choice(CONFIG_PUT
)
222 assert key
in CONFIG_EXISTING
, \
223 "key '{k_}' not in CONFIG_EXISTING".format(k_
=key
)
225 expected
= 0 # the store just overrides the value if the key exists
226 # end if sop == 'existing'
228 for x
in range(0, 10):
230 if key
not in CONFIG_EXISTING
:
234 op_log
.error('unable to generate an unique key -- try again later.')
237 assert key
not in CONFIG_PUT
and key
not in CONFIG_EXISTING
, \
238 'key {k} was not supposed to exist!'.format(k
=key
)
240 assert key
is not None, \
241 'key must be != None'
245 (size
, error
) = rnd
.choice(SIZES
)
249 data
= gen_data(size
, rnd
)
251 if error
== 0: # only add if we expect the put to be successful
253 CONFIG_PUT
.append(key
)
254 CONFIG_EXISTING
[key
] = size
258 data_file
= write_data_file(data
, rnd
)
259 cmd
+= ['-i', data_file
]
263 op_log
.debug('size: {sz}, via: {v}'.format(
265 v
='file: {f}'.format(f
=data_file
) if via_file
== True else 'cli')
267 run_cmd(cmd
, expects
=expected
)
269 destroy_tmp_file(data_file
)
277 if sop
== 'existing':
278 if len(CONFIG_EXISTING
) == 0:
279 op_log
.debug('no existing keys; continue')
281 key
= rnd
.choice(CONFIG_PUT
)
282 assert key
in CONFIG_EXISTING
, \
283 "key '{k_}' not in CONFIG_EXISTING".format(k_
=key
)
286 for x
in range(0, 10):
287 key
= base64
.b64encode(os
.urandom(20)).decode()
288 if key
not in CONFIG_EXISTING
:
292 op_log
.error('unable to generate an unique key -- try again later.')
294 assert key
not in CONFIG_PUT
and key
not in CONFIG_EXISTING
, \
295 'key {k} was not supposed to exist!'.format(k
=key
)
296 expected
= 0 # deleting a non-existent key succeeds
298 assert key
is not None, \
299 'key must be != None'
302 op_log
.debug('key: {k}'.format(k
=key
))
303 run_cmd(cmd
, expects
=expected
)
304 if sop
== 'existing':
305 CONFIG_DEL
.append(key
)
306 CONFIG_PUT
.remove(key
)
307 del CONFIG_EXISTING
[key
]
315 if sop
== 'existing':
316 if len(CONFIG_EXISTING
) == 0:
317 op_log
.debug('no existing keys; continue')
319 key
= rnd
.choice(CONFIG_PUT
)
320 assert key
in CONFIG_EXISTING
, \
321 "key '{k_}' not in CONFIG_EXISTING".format(k_
=key
)
324 for x
in range(0, 10):
325 key
= base64
.b64encode(os
.urandom(20)).decode()
326 if key
not in CONFIG_EXISTING
:
330 op_log
.error('unable to generate an unique key -- try again later.')
332 assert key
not in CONFIG_PUT
and key
not in CONFIG_EXISTING
, \
333 'key {k} was not supposed to exist!'.format(k
=key
)
334 expected
= -errno
.ENOENT
336 assert key
is not None, \
337 'key must be != None'
340 op_log
.debug('key: {k}'.format(k
=key
))
341 run_cmd(cmd
, expects
=expected
)
349 if sop
== 'existing':
350 if len(CONFIG_EXISTING
) == 0:
351 op_log
.debug('no existing keys; continue')
353 key
= rnd
.choice(CONFIG_PUT
)
354 assert key
in CONFIG_EXISTING
, \
355 "key '{k_}' not in CONFIG_EXISTING".format(k_
=key
)
358 for x
in range(0, 10):
359 key
= base64
.b64encode(os
.urandom(20)).decode()
360 if key
not in CONFIG_EXISTING
:
364 op_log
.error('unable to generate an unique key -- try again later.')
366 assert key
not in CONFIG_PUT
and key
not in CONFIG_EXISTING
, \
367 'key {k} was not supposed to exist!'.format(k
=key
)
368 expected
= -errno
.ENOENT
370 assert key
is not None, \
371 'key must be != None'
373 file_path
= gen_tmp_file_path(rnd
)
374 cmd
+= [key
, '-o', file_path
]
375 op_log
.debug('key: {k}'.format(k
=key
))
376 run_cmd(cmd
, expects
=expected
)
377 if sop
== 'existing':
379 temp_file
= open(file_path
, 'r+')
380 except IOError as err
:
381 if err
.errno
== errno
.ENOENT
:
382 assert CONFIG_EXISTING
[key
] == 0, \
383 "error opening '{fp}': {e}".format(fp
=file_path
, e
=err
)
387 'some error occurred: {e}'.format(e
=err
)
390 read_data
= temp_file
.read()
393 cnt
+= len(read_data
)
394 assert cnt
== CONFIG_EXISTING
[key
], \
395 "wrong size from store for key '{k}': {sz}, expected {es}".format(
396 k
=key
, sz
=cnt
, es
=CONFIG_EXISTING
[key
])
397 destroy_tmp_file(file_path
)
400 elif op
== 'list' or op
== 'dump':
405 if sop
== 'existing':
406 if len(CONFIG_EXISTING
) == 0:
407 op_log
.debug('no existing keys; continue')
409 key
= rnd
.choice(CONFIG_PUT
)
410 assert key
in CONFIG_EXISTING
, \
411 "key '{k_}' not in CONFIG_EXISTING".format(k_
=key
)
414 for x
in range(0, 10):
415 key
= base64
.b64encode(os
.urandom(20)).decode()
416 if key
not in CONFIG_EXISTING
:
420 op_log
.error('unable to generate an unique key -- try again later.')
422 assert key
not in CONFIG_PUT
and key
not in CONFIG_EXISTING
, \
423 'key {k} was not supposed to exist!'.format(k
=key
)
425 assert key
is not None, \
426 'key must be != None'
428 file_path
= gen_tmp_file_path(rnd
)
429 cmd
+= ['-o', file_path
]
430 op_log
.debug('key: {k}'.format(k
=key
))
431 run_cmd(cmd
, expects
=expected
)
433 temp_file
= open(file_path
, 'r+')
434 except IOError as err
:
435 if err
.errno
== errno
.ENOENT
:
436 assert CONFIG_EXISTING
[key
] == 0, \
437 "error opening '{fp}': {e}".format(fp
=file_path
, e
=err
)
441 'some error occurred: {e}'.format(e
=err
)
444 read_data
= json
.load(temp_file
)
447 assert False, "{op} output was not valid JSON:\n{filedata}".format(op
, temp_file
.readlines())
449 if sop
== 'existing':
450 assert key
in read_data
, "key '{k}' not found in list/dump output".format(k
=key
)
452 cnt
= len(read_data
[key
])
453 assert cnt
== CONFIG_EXISTING
[key
], \
454 "wrong size from list for key '{k}': {sz}, expected {es}".format(
455 k
=key
, sz
=cnt
, es
=CONFIG_EXISTING
[key
])
456 elif sop
== 'enoent':
457 assert key
not in read_data
, "key '{k}' found in list/dump output".format(k
=key
)
458 destroy_tmp_file(file_path
)
461 assert False, 'unknown op {o}'.format(o
=op
)
463 # check if all keys in 'CONFIG_PUT' exist and
464 # if all keys on 'CONFIG_DEL' don't.
465 # but first however, remove all keys in CONFIG_PUT that might
466 # be in CONFIG_DEL as well.
467 config_put_set
= set(CONFIG_PUT
)
468 config_del_set
= set(CONFIG_DEL
).difference(config_put_set
)
470 LOG
.info('perform sanity checks on store')
472 for k
in config_put_set
:
473 LOG
.getChild('check(puts)').debug('key: {k_}'.format(k_
=k
))
474 run_cmd(['exists', k
], expects
=0)
475 for k
in config_del_set
:
476 LOG
.getChild('check(dels)').debug('key: {k_}'.format(k_
=k
))
477 run_cmd(['exists', k
], expects
=-errno
.ENOENT
)
480 if __name__
== "__main__":