]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | |
2 | from unittest import case | |
3 | import json | |
3efd9988 | 4 | import logging |
7c673cae FG |
5 | |
6 | from teuthology import misc | |
7 | from tasks.ceph_test_case import CephTestCase | |
8 | ||
3efd9988 | 9 | # TODO move definition of CephCluster away from the CephFS stuff |
7c673cae FG |
10 | from tasks.cephfs.filesystem import CephCluster |
11 | ||
12 | ||
3efd9988 FG |
13 | log = logging.getLogger(__name__) |
14 | ||
15 | ||
7c673cae FG |
16 | class MgrCluster(CephCluster): |
17 | def __init__(self, ctx): | |
18 | super(MgrCluster, self).__init__(ctx) | |
19 | self.mgr_ids = list(misc.all_roles_of_type(ctx.cluster, 'mgr')) | |
20 | ||
21 | if len(self.mgr_ids) == 0: | |
22 | raise RuntimeError( | |
23 | "This task requires at least one manager daemon") | |
24 | ||
25 | self.mgr_daemons = dict( | |
26 | [(mgr_id, self._ctx.daemons.get_daemon('mgr', mgr_id)) for mgr_id | |
27 | in self.mgr_ids]) | |
28 | ||
29 | def mgr_stop(self, mgr_id): | |
30 | self.mgr_daemons[mgr_id].stop() | |
31 | ||
32 | def mgr_fail(self, mgr_id): | |
33 | self.mon_manager.raw_cluster_cmd("mgr", "fail", mgr_id) | |
34 | ||
35 | def mgr_restart(self, mgr_id): | |
36 | self.mgr_daemons[mgr_id].restart() | |
37 | ||
38 | def get_mgr_map(self): | |
39 | status = json.loads( | |
40 | self.mon_manager.raw_cluster_cmd("status", "--format=json-pretty")) | |
41 | ||
42 | return status["mgrmap"] | |
43 | ||
44 | def get_active_id(self): | |
45 | return self.get_mgr_map()["active_name"] | |
46 | ||
47 | def get_standby_ids(self): | |
48 | return [s['name'] for s in self.get_mgr_map()["standbys"]] | |
49 | ||
b32b8144 FG |
50 | def set_module_conf(self, module, key, val): |
51 | self.mon_manager.raw_cluster_cmd("config-key", "set", | |
52 | "mgr/{0}/{1}".format( | |
53 | module, key | |
54 | ), val) | |
55 | ||
3efd9988 FG |
56 | def set_module_localized_conf(self, module, mgr_id, key, val): |
57 | self.mon_manager.raw_cluster_cmd("config-key", "set", | |
58 | "mgr/{0}/{1}/{2}".format( | |
59 | module, mgr_id, key | |
60 | ), val) | |
61 | ||
7c673cae FG |
62 | |
63 | class MgrTestCase(CephTestCase): | |
64 | MGRS_REQUIRED = 1 | |
65 | ||
66 | def setUp(self): | |
67 | super(MgrTestCase, self).setUp() | |
68 | ||
69 | # The test runner should have populated this | |
70 | assert self.mgr_cluster is not None | |
71 | ||
72 | if len(self.mgr_cluster.mgr_ids) < self.MGRS_REQUIRED: | |
73 | raise case.SkipTest("Only have {0} manager daemons, " | |
74 | "{1} are required".format( | |
75 | len(self.mgr_cluster.mgr_ids), self.MGRS_REQUIRED)) | |
76 | ||
77 | # Restart all the daemons | |
78 | for daemon in self.mgr_cluster.mgr_daemons.values(): | |
79 | daemon.stop() | |
80 | ||
81 | for mgr_id in self.mgr_cluster.mgr_ids: | |
82 | self.mgr_cluster.mgr_fail(mgr_id) | |
83 | ||
84 | for daemon in self.mgr_cluster.mgr_daemons.values(): | |
85 | daemon.restart() | |
86 | ||
87 | # Wait for an active to come up | |
88 | self.wait_until_true(lambda: self.mgr_cluster.get_active_id() != "", | |
89 | timeout=20) | |
90 | ||
91 | expect_standbys = set(self.mgr_cluster.mgr_ids) \ | |
92 | - {self.mgr_cluster.get_active_id()} | |
93 | self.wait_until_true( | |
94 | lambda: set(self.mgr_cluster.get_standby_ids()) == expect_standbys, | |
95 | timeout=20) | |
3efd9988 FG |
96 | |
97 | def _load_module(self, module_name): | |
98 | loaded = json.loads(self.mgr_cluster.mon_manager.raw_cluster_cmd( | |
99 | "mgr", "module", "ls"))['enabled_modules'] | |
100 | if module_name in loaded: | |
101 | # The enable command is idempotent, but our wait for a restart | |
102 | # isn't, so let's return now if it's already loaded | |
103 | return | |
104 | ||
105 | initial_gid = self.mgr_cluster.get_mgr_map()['active_gid'] | |
106 | self.mgr_cluster.mon_manager.raw_cluster_cmd("mgr", "module", "enable", | |
107 | module_name) | |
108 | ||
109 | # Wait for the module to load | |
110 | def has_restarted(): | |
111 | mgr_map = self.mgr_cluster.get_mgr_map() | |
112 | done = mgr_map['active_gid'] != initial_gid and mgr_map['available'] | |
113 | if done: | |
114 | log.info("Restarted after module load (new active {0}/{1})".format( | |
115 | mgr_map['active_name'] , mgr_map['active_gid'])) | |
116 | return done | |
117 | self.wait_until_true(has_restarted, timeout=30) | |
118 | ||
119 | ||
120 | def _get_uri(self, service_name): | |
121 | # Little dict hack so that I can assign into this from | |
122 | # the get_or_none function | |
123 | mgr_map = {'x': None} | |
124 | ||
125 | def _get_or_none(): | |
126 | mgr_map['x'] = self.mgr_cluster.get_mgr_map() | |
127 | result = mgr_map['x']['services'].get(service_name, None) | |
128 | return result | |
129 | ||
130 | self.wait_until_true(lambda: _get_or_none() is not None, 30) | |
131 | ||
132 | uri = mgr_map['x']['services'][service_name] | |
133 | ||
134 | log.info("Found {0} at {1} (daemon {2}/{3})".format( | |
135 | service_name, uri, mgr_map['x']['active_name'], | |
136 | mgr_map['x']['active_gid'])) | |
137 | ||
138 | return uri | |
139 | ||
140 | ||
141 | def _assign_ports(self, module_name, config_name, min_port=7789): | |
142 | """ | |
143 | To avoid the need to run lots of hosts in teuthology tests to | |
144 | get different URLs per mgr, we will hand out different ports | |
145 | to each mgr here. | |
146 | ||
147 | This is already taken care of for us when running in a vstart | |
148 | environment. | |
149 | """ | |
150 | # Start handing out ports well above Ceph's range. | |
151 | assign_port = min_port | |
152 | ||
153 | for mgr_id in self.mgr_cluster.mgr_ids: | |
154 | self.mgr_cluster.mgr_stop(mgr_id) | |
155 | self.mgr_cluster.mgr_fail(mgr_id) | |
156 | ||
157 | for mgr_id in self.mgr_cluster.mgr_ids: | |
158 | log.info("Using port {0} for {1} on mgr.{2}".format( | |
159 | assign_port, module_name, mgr_id | |
160 | )) | |
161 | self.mgr_cluster.set_module_localized_conf(module_name, mgr_id, | |
162 | config_name, | |
163 | str(assign_port)) | |
164 | assign_port += 1 | |
165 | ||
166 | for mgr_id in self.mgr_cluster.mgr_ids: | |
167 | self.mgr_cluster.mgr_restart(mgr_id) | |
168 | ||
169 | def is_available(): | |
170 | mgr_map = self.mgr_cluster.get_mgr_map() | |
171 | done = mgr_map['available'] | |
172 | if done: | |
173 | log.info("Available after assign ports (new active {0}/{1})".format( | |
174 | mgr_map['active_name'] , mgr_map['active_gid'])) | |
175 | return done | |
176 | self.wait_until_true(is_available, timeout=30) |