]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rgw/test_multi.py
update sources to v12.2.3
[ceph.git] / ceph / src / test / rgw / test_multi.py
CommitLineData
7c673cae
FG
1import subprocess
2import os
3import random
4import string
5import argparse
6import sys
7import logging
8try:
9 import configparser
10except ImportError:
11 import ConfigParser as configparser
12
13import nose.core
14
15from rgw_multi import multisite
31f18b77
FG
16from rgw_multi.zone_rados import RadosZone as RadosZone
17from rgw_multi.zone_es import ESZone as ESZone
18
7c673cae
FG
19# make tests from rgw_multi.tests available to nose
20from rgw_multi.tests import *
31f18b77 21from rgw_multi.tests_es import *
7c673cae
FG
22
23mstart_path = os.getenv('MSTART_PATH')
24if mstart_path is None:
25 mstart_path = os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + '/../..') + '/'
26
27test_path = os.path.normpath(os.path.dirname(os.path.realpath(__file__))) + '/'
28
29# configure logging for the tests module
30log = logging.getLogger('rgw_multi.tests')
31
32def bash(cmd, **kwargs):
33 log.debug('running cmd: %s', ' '.join(cmd))
34 check_retcode = kwargs.pop('check_retcode', True)
35 kwargs['stdout'] = subprocess.PIPE
36 process = subprocess.Popen(cmd, **kwargs)
37 s = process.communicate()[0]
38 log.debug('command returned status=%d stdout=%s', process.returncode, s.decode('utf-8'))
39 if check_retcode:
40 assert(process.returncode == 0)
41 return (s, process.returncode)
42
43class Cluster(multisite.Cluster):
44 """ cluster implementation based on mstart/mrun scripts """
45 def __init__(self, cluster_id):
46 super(Cluster, self).__init__()
47 self.cluster_id = cluster_id
48 self.needs_reset = True
49
50 def admin(self, args = None, **kwargs):
51 """ radosgw-admin command """
52 cmd = [test_path + 'test-rgw-call.sh', 'call_rgw_admin', self.cluster_id]
53 if args:
54 cmd += args
b32b8144
FG
55 cmd += ['--debug-rgw', str(kwargs.pop('debug_rgw', 0))]
56 cmd += ['--debug-ms', str(kwargs.pop('debug_ms', 0))]
7c673cae
FG
57 if kwargs.pop('read_only', False):
58 cmd += ['--rgw-cache-enabled', 'false']
59 return bash(cmd, **kwargs)
60
61 def start(self):
62 cmd = [mstart_path + 'mstart.sh', self.cluster_id]
63 if self.needs_reset:
64 cmd += ['-n', '--mds_num', '0']
65 bash(cmd)
66 self.needs_reset = False
67
68 def stop(self):
69 cmd = [mstart_path + 'mstop.sh', self.cluster_id]
70 bash(cmd)
71
72class Gateway(multisite.Gateway):
73 """ gateway implementation based on mrgw/mstop scripts """
74 def __init__(self, client_id = None, *args, **kwargs):
75 super(Gateway, self).__init__(*args, **kwargs)
76 self.id = client_id
77
78 def start(self, args = None):
79 """ start the gateway """
80 assert(self.cluster)
81 cmd = [mstart_path + 'mrgw.sh', self.cluster.cluster_id, str(self.port)]
82 if self.id:
83 cmd += ['-i', self.id]
84 cmd += ['--debug-rgw=20', '--debug-ms=1']
85 if args:
86 cmd += args
87 bash(cmd)
88
89 def stop(self):
90 """ stop the gateway """
91 assert(self.cluster)
92 cmd = [mstart_path + 'mstop.sh', self.cluster.cluster_id, 'radosgw', self.id]
93 bash(cmd)
94
95def gen_access_key():
96 return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16))
97
98def gen_secret():
99 return ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(32))
100
101def gen_credentials():
102 return multisite.Credentials(gen_access_key(), gen_secret())
103
104def cluster_name(cluster_num):
105 return 'c' + str(cluster_num)
106
107def zonegroup_name(zonegroup_num):
108 return string.ascii_lowercase[zonegroup_num]
109
110def zone_name(zonegroup_num, zone_num):
111 return zonegroup_name(zonegroup_num) + str(zone_num + 1)
112
113def gateway_port(zonegroup_num, gateway_num):
114 return 8000 + 100 * zonegroup_num + gateway_num
115
116def gateway_name(zonegroup_num, zone_num, gateway_num):
117 return zone_name(zonegroup_num, zone_num) + '-' + str(gateway_num + 1)
118
119def zone_endpoints(zonegroup_num, zone_num, gateways_per_zone):
120 endpoints = []
121 base = gateway_port(zonegroup_num, zone_num * gateways_per_zone)
122 for i in range(0, gateways_per_zone):
123 endpoints.append('http://localhost:' + str(base + i))
124 return endpoints
125
126def get_log_level(log_level):
127 if log_level >= 20:
128 return logging.DEBUG
129 if log_level >= 10:
130 return logging.INFO
131 if log_level >= 5:
132 return logging.WARN
133 if log_level >= 1:
134 return logging.ERROR
135 return logging.CRITICAL
136
137def setup_logging(log_level_console, log_file, log_level_file):
138 if log_file:
139 formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
140 fh = logging.FileHandler(log_file)
141 fh.setFormatter(formatter)
142 fh.setLevel(get_log_level(log_level_file))
143 log.addHandler(fh)
144
145 formatter = logging.Formatter('%(levelname)s %(message)s')
146 ch = logging.StreamHandler()
147 ch.setFormatter(formatter)
148 ch.setLevel(get_log_level(log_level_console))
149 log.addHandler(ch)
150
151def init(parse_args):
152 cfg = configparser.RawConfigParser({
153 'num_zonegroups': 1,
154 'num_zones': 3,
31f18b77 155 'num_es_zones': 0,
7c673cae
FG
156 'gateways_per_zone': 2,
157 'no_bootstrap': 'false',
158 'log_level': 20,
159 'log_file': None,
160 'file_log_level': 20,
161 'tenant': None,
31f18b77
FG
162 'checkpoint_retries': 60,
163 'checkpoint_delay': 5,
164 'reconfigure_delay': 5,
165 'es_endpoint': None,
7c673cae
FG
166 })
167 try:
168 path = os.environ['RGW_MULTI_TEST_CONF']
169 except KeyError:
31f18b77 170 path = test_path + 'test_multi.conf'
7c673cae
FG
171
172 try:
173 with open(path) as f:
174 cfg.readfp(f)
175 except:
176 print('WARNING: error reading test config. Path can be set through the RGW_MULTI_TEST_CONF env variable')
177 pass
178
179 parser = argparse.ArgumentParser(
180 description='Run rgw multi-site tests',
181 usage='test_multi [--num-zonegroups <num>] [--num-zones <num>] [--no-bootstrap]')
182
183 section = 'DEFAULT'
184 parser.add_argument('--num-zonegroups', type=int, default=cfg.getint(section, 'num_zonegroups'))
185 parser.add_argument('--num-zones', type=int, default=cfg.getint(section, 'num_zones'))
31f18b77 186 parser.add_argument('--num-es-zones', type=int, default=cfg.getint(section, 'num_es_zones'))
7c673cae
FG
187 parser.add_argument('--gateways-per-zone', type=int, default=cfg.getint(section, 'gateways_per_zone'))
188 parser.add_argument('--no-bootstrap', action='store_true', default=cfg.getboolean(section, 'no_bootstrap'))
189 parser.add_argument('--log-level', type=int, default=cfg.getint(section, 'log_level'))
190 parser.add_argument('--log-file', type=str, default=cfg.get(section, 'log_file'))
191 parser.add_argument('--file-log-level', type=int, default=cfg.getint(section, 'file_log_level'))
192 parser.add_argument('--tenant', type=str, default=cfg.get(section, 'tenant'))
31f18b77
FG
193 parser.add_argument('--checkpoint-retries', type=int, default=cfg.getint(section, 'checkpoint_retries'))
194 parser.add_argument('--checkpoint-delay', type=int, default=cfg.getint(section, 'checkpoint_delay'))
195 parser.add_argument('--reconfigure-delay', type=int, default=cfg.getint(section, 'reconfigure_delay'))
196 parser.add_argument('--es-endpoint', type=str, default=cfg.get(section, 'es_endpoint'))
7c673cae
FG
197
198 argv = []
199
200 if parse_args:
201 argv = sys.argv[1:]
202
203 args = parser.parse_args(argv)
204 bootstrap = not args.no_bootstrap
205
31f18b77
FG
206 # if num_es_zones is defined, need to have es_endpoint defined too
207 assert(args.num_es_zones == 0 or args.es_endpoint)
208
7c673cae
FG
209 setup_logging(args.log_level, args.log_file, args.file_log_level)
210
211 # start first cluster
212 c1 = Cluster(cluster_name(1))
213 if bootstrap:
214 c1.start()
215 clusters = []
216 clusters.append(c1)
217
218 admin_creds = gen_credentials()
219 admin_user = multisite.User('zone.user')
220
221 user_creds = gen_credentials()
222 user = multisite.User('tester')
223
224 realm = multisite.Realm('r')
225 if bootstrap:
226 # create the realm on c1
227 realm.create(c1)
228 else:
229 realm.get(c1)
230 period = multisite.Period(realm=realm)
231 realm.current_period = period
232
31f18b77
FG
233 num_zones = args.num_zones + args.num_es_zones
234
7c673cae
FG
235 for zg in range(0, args.num_zonegroups):
236 zonegroup = multisite.ZoneGroup(zonegroup_name(zg), period)
237 period.zonegroups.append(zonegroup)
238
239 is_master_zg = zg == 0
240 if is_master_zg:
241 period.master_zonegroup = zonegroup
242
31f18b77 243 for z in range(0, num_zones):
7c673cae
FG
244 is_master = z == 0
245 # start a cluster, or use c1 for first zone
246 cluster = None
247 if is_master_zg and is_master:
248 cluster = c1
249 else:
250 cluster = Cluster(cluster_name(len(clusters) + 1))
251 clusters.append(cluster)
252 if bootstrap:
253 cluster.start()
254 # pull realm configuration from the master's gateway
255 gateway = realm.meta_master_zone().gateways[0]
256 realm.pull(cluster, gateway, admin_creds)
257
258 endpoints = zone_endpoints(zg, z, args.gateways_per_zone)
259 if is_master:
260 if bootstrap:
261 # create the zonegroup on its first zone's cluster
262 arg = []
263 if is_master_zg:
264 arg += ['--master']
265 if len(endpoints): # use master zone's endpoints
266 arg += ['--endpoints', ','.join(endpoints)]
267 zonegroup.create(cluster, arg)
268 else:
269 zonegroup.get(cluster)
270
31f18b77
FG
271 es_zone = (z >= args.num_zones)
272
7c673cae
FG
273 # create the zone in its zonegroup
274 zone = multisite.Zone(zone_name(zg, z), zonegroup, cluster)
31f18b77
FG
275 if es_zone:
276 zone = ESZone(zone_name(zg, z), args.es_endpoint, zonegroup, cluster)
277 else:
278 zone = RadosZone(zone_name(zg, z), zonegroup, cluster)
279
7c673cae
FG
280 if bootstrap:
281 arg = admin_creds.credential_args()
282 if is_master:
283 arg += ['--master']
284 if len(endpoints):
285 arg += ['--endpoints', ','.join(endpoints)]
286 zone.create(cluster, arg)
287 else:
288 zone.get(cluster)
289 zonegroup.zones.append(zone)
290 if is_master:
291 zonegroup.master_zone = zone
292
31f18b77
FG
293 zonegroup.zones_by_type.setdefault(zone.tier_type(), []).append(zone)
294
295 if zone.is_read_only():
296 zonegroup.ro_zones.append(zone)
297 else:
298 zonegroup.rw_zones.append(zone)
299
7c673cae
FG
300 # update/commit the period
301 if bootstrap:
302 period.update(zone, commit=True)
303
304 # start the gateways
305 for g in range(0, args.gateways_per_zone):
306 port = gateway_port(zg, g + z * args.gateways_per_zone)
307 client_id = gateway_name(zg, z, g)
308 gateway = Gateway(client_id, 'localhost', port, cluster, zone)
309 if bootstrap:
310 gateway.start()
311 zone.gateways.append(gateway)
312
313 if is_master_zg and is_master:
314 if bootstrap:
315 # create admin user
316 arg = ['--display-name', '"Zone User"', '--system']
317 arg += admin_creds.credential_args()
318 admin_user.create(zone, arg)
319 # create test user
320 arg = ['--display-name', '"Test User"']
321 arg += user_creds.credential_args()
322 if args.tenant:
323 cmd += ['--tenant', args.tenant]
324 user.create(zone, arg)
325 else:
326 # read users and update keys
327 admin_user.info(zone)
328 admin_creds = admin_user.credentials[0]
329 user.info(zone)
330 user_creds = user.credentials[0]
331
332 if not bootstrap:
333 period.get(c1)
334
31f18b77
FG
335 config = Config(checkpoint_retries=args.checkpoint_retries,
336 checkpoint_delay=args.checkpoint_delay,
337 reconfigure_delay=args.reconfigure_delay)
338 init_multi(realm, user, config)
7c673cae
FG
339
340def setup_module():
341 init(False)
342
343if __name__ == "__main__":
344 init(True)