]>
Commit | Line | Data |
---|---|---|
3efd9988 FG |
1 | import logging |
2 | import random | |
3 | ||
4 | ||
5 | log = logging.getLogger(__name__) | |
6 | ||
7 | ||
8 | def pg_num_in_all_states(pgs, *states): | |
9 | return sum(1 for state in pgs.itervalues() | |
10 | if all(s in state for s in states)) | |
11 | ||
12 | ||
13 | def pg_num_in_any_state(pgs, *states): | |
14 | return sum(1 for state in pgs.itervalues() | |
15 | if any(s in state for s in states)) | |
16 | ||
17 | ||
18 | def test_create_from_mon(ctx, config): | |
19 | """ | |
20 | osd should stop creating new pools if the number of pg it servers | |
21 | exceeds the max-pg-per-osd setting, and it should resume the previously | |
22 | suspended pg creations once the its pg number drops down below the setting | |
23 | How it works:: | |
24 | 1. set the hard limit of pg-per-osd to "2" | |
25 | 2. create pool.a with pg_num=2 | |
26 | # all pgs should be active+clean | |
27 | 2. create pool.b with pg_num=2 | |
28 | # new pgs belonging to this pool should be unknown (the primary osd | |
29 | reaches the limit) or creating (replica osd reaches the limit) | |
30 | 3. remove pool.a | |
31 | 4. all pg belonging to pool.b should be active+clean | |
32 | """ | |
33 | pg_num = config.get('pg_num', 2) | |
34 | manager = ctx.managers['ceph'] | |
35 | log.info('1. creating pool.a') | |
36 | pool_a = manager.create_pool_with_unique_name(pg_num) | |
28e407b8 AA |
37 | pg_states = manager.wait_till_pg_convergence(300) |
38 | pg_created = pg_num_in_all_states(pg_states, 'active', 'clean') | |
39 | assert pg_created == pg_num | |
3efd9988 FG |
40 | |
41 | log.info('2. creating pool.b') | |
42 | pool_b = manager.create_pool_with_unique_name(pg_num) | |
43 | pg_states = manager.wait_till_pg_convergence(300) | |
44 | pg_created = pg_num_in_all_states(pg_states, 'active', 'clean') | |
45 | assert pg_created == pg_num | |
46 | pg_pending = pg_num_in_any_state(pg_states, 'unknown', 'creating') | |
47 | assert pg_pending == pg_num | |
48 | ||
49 | log.info('3. removing pool.a') | |
50 | manager.remove_pool(pool_a) | |
51 | pg_states = manager.wait_till_pg_convergence(300) | |
52 | assert len(pg_states) == pg_num | |
53 | pg_created = pg_num_in_all_states(pg_states, 'active', 'clean') | |
54 | assert pg_created == pg_num | |
55 | ||
56 | # cleanup | |
57 | manager.remove_pool(pool_b) | |
58 | ||
59 | ||
60 | def test_create_from_peer(ctx, config): | |
61 | """ | |
62 | osd should stop creating new pools if the number of pg it servers | |
63 | exceeds the max-pg-per-osd setting, and it should resume the previously | |
64 | suspended pg creations once the its pg number drops down below the setting | |
65 | ||
66 | How it works:: | |
67 | 0. create 4 OSDs. | |
68 | 1. create pool.a with pg_num=1, size=2 | |
69 | pg will be mapped to osd.0, and osd.1, and it should be active+clean | |
70 | 2. create pool.b with pg_num=1, size=2. | |
71 | if the pgs stuck in creating, delete the pool since the pool and try | |
72 | again, eventually we'll get the pool to land on the other 2 osds that | |
73 | aren't occupied by pool.a. (this will also verify that pgs for deleted | |
74 | pools get cleaned out of the creating wait list.) | |
75 | 3. mark an osd out. verify that some pgs get stuck stale or peering. | |
76 | 4. delete a pool, verify pgs go active. | |
77 | """ | |
78 | pg_num = config.get('pg_num', 1) | |
79 | pool_size = config.get('pool_size', 2) | |
80 | from_primary = config.get('from_primary', True) | |
81 | ||
82 | manager = ctx.managers['ceph'] | |
83 | log.info('1. creating pool.a') | |
84 | pool_a = manager.create_pool_with_unique_name(pg_num) | |
28e407b8 AA |
85 | pg_states = manager.wait_till_pg_convergence(300) |
86 | pg_created = pg_num_in_all_states(pg_states, 'active', 'clean') | |
87 | assert pg_created == pg_num | |
3efd9988 FG |
88 | |
89 | log.info('2. creating pool.b') | |
90 | while True: | |
91 | pool_b = manager.create_pool_with_unique_name(pg_num) | |
92 | pg_states = manager.wait_till_pg_convergence(300) | |
93 | pg_created = pg_num_in_all_states(pg_states, 'active', 'clean') | |
94 | assert pg_created >= pg_num | |
95 | pg_pending = pg_num_in_any_state(pg_states, 'unknown', 'creating') | |
96 | assert pg_pending == pg_num * 2 - pg_created | |
97 | if pg_created == pg_num * 2: | |
98 | break | |
99 | manager.remove_pool(pool_b) | |
100 | ||
101 | log.info('3. mark an osd out') | |
102 | pg_stats = manager.get_pg_stats() | |
103 | pg = random.choice(pg_stats) | |
104 | if from_primary: | |
105 | victim = pg['acting'][-1] | |
106 | else: | |
107 | victim = pg['acting'][0] | |
108 | manager.mark_out_osd(victim) | |
109 | pg_states = manager.wait_till_pg_convergence(300) | |
110 | pg_stuck = pg_num_in_any_state(pg_states, 'activating', 'stale', 'peering') | |
111 | assert pg_stuck > 0 | |
112 | ||
113 | log.info('4. removing pool.b') | |
114 | manager.remove_pool(pool_b) | |
115 | manager.wait_for_clean(30) | |
116 | ||
117 | # cleanup | |
118 | manager.remove_pool(pool_a) | |
119 | ||
120 | ||
121 | def task(ctx, config): | |
122 | assert isinstance(config, dict), \ | |
123 | 'osd_max_pg_per_osd task only accepts a dict for config' | |
124 | manager = ctx.managers['ceph'] | |
125 | if config.get('test_create_from_mon', True): | |
126 | test_create_from_mon(ctx, config) | |
127 | else: | |
128 | test_create_from_peer(ctx, config) |