]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/rgw/test_multi.py
e32d00f0da31740cbeb584388c791ed4f803b5eb
11 import ConfigParser
as configparser
15 from rgw_multi
import multisite
16 from rgw_multi
.zone_rados
import RadosZone
as RadosZone
17 from rgw_multi
.zone_es
import ESZone
as ESZone
18 from rgw_multi
.zone_es
import ESZoneConfig
as ESZoneConfig
19 from rgw_multi
.zone_cloud
import CloudZone
as CloudZone
20 from rgw_multi
.zone_cloud
import CloudZoneConfig
as CloudZoneConfig
21 from rgw_multi
.zone_ps
import PSZone
as PSZone
22 from rgw_multi
.zone_ps
import PSZoneConfig
as PSZoneConfig
23 from rgw_multi
.zone_az
import AZone
as AZone
24 from rgw_multi
.zone_az
import AZoneConfig
as AZoneConfig
26 # make tests from rgw_multi.tests available to nose
27 from rgw_multi
.tests
import *
28 from rgw_multi
.tests_es
import *
29 from rgw_multi
.tests_ps
import *
30 from rgw_multi
.tests_az
import *
32 mstart_path
= os
.getenv('MSTART_PATH')
33 if mstart_path
is None:
34 mstart_path
= os
.path
.normpath(os
.path
.dirname(os
.path
.realpath(__file__
)) + '/../..') + '/'
36 test_path
= os
.path
.normpath(os
.path
.dirname(os
.path
.realpath(__file__
))) + '/'
38 # configure logging for the tests module
39 log
= logging
.getLogger('rgw_multi.tests')
41 def bash(cmd
, **kwargs
):
42 log
.debug('running cmd: %s', ' '.join(cmd
))
43 check_retcode
= kwargs
.pop('check_retcode', True)
44 kwargs
['stdout'] = subprocess
.PIPE
45 process
= subprocess
.Popen(cmd
, **kwargs
)
46 s
= process
.communicate()[0].decode('utf-8')
47 log
.debug('command returned status=%d stdout=%s', process
.returncode
, s
)
49 assert(process
.returncode
== 0)
50 return (s
, process
.returncode
)
52 class Cluster(multisite
.Cluster
):
53 """ cluster implementation based on mstart/mrun scripts """
54 def __init__(self
, cluster_id
):
55 super(Cluster
, self
).__init
__()
56 self
.cluster_id
= cluster_id
57 self
.needs_reset
= True
59 def admin(self
, args
= None, **kwargs
):
60 """ radosgw-admin command """
61 cmd
= [test_path
+ 'test-rgw-call.sh', 'call_rgw_admin', self
.cluster_id
]
64 cmd
+= ['--debug-rgw=' + str(kwargs
.pop('debug_rgw', 0))]
65 cmd
+= ['--debug-ms=' + str(kwargs
.pop('debug_ms', 0))]
66 if kwargs
.pop('read_only', False):
67 cmd
+= ['--rgw-cache-enabled=false']
68 return bash(cmd
, **kwargs
)
71 cmd
= [mstart_path
+ 'mstart.sh', self
.cluster_id
]
74 env
= os
.environ
.copy()
75 env
['CEPH_NUM_MDS'] = '0'
78 # cmd += ['rgw_cache_enabled=false']
80 self
.needs_reset
= False
83 cmd
= [mstart_path
+ 'mstop.sh', self
.cluster_id
]
86 class Gateway(multisite
.Gateway
):
87 """ gateway implementation based on mrgw/mstop scripts """
88 def __init__(self
, client_id
= None, *args
, **kwargs
):
89 super(Gateway
, self
).__init
__(*args
, **kwargs
)
92 def start(self
, args
= None):
93 """ start the gateway """
95 env
= os
.environ
.copy()
96 # to change frontend, set RGW_FRONTEND env variable
97 # e.g. RGW_FRONTEND=civetweb
98 # to run test under valgrind memcheck, set RGW_VALGRIND to 'yes'
99 # e.g. RGW_VALGRIND=yes
100 cmd
= [mstart_path
+ 'mrgw.sh', self
.cluster
.cluster_id
, str(self
.port
), str(self
.ssl_port
)]
102 cmd
+= ['-i', self
.id]
103 cmd
+= ['--debug-rgw=20', '--debug-ms=1']
109 """ stop the gateway """
111 cmd
= [mstart_path
+ 'mstop.sh', self
.cluster
.cluster_id
, 'radosgw', str(self
.port
)]
114 def gen_access_key():
115 return ''.join(random
.choice(string
.ascii_uppercase
+ string
.digits
) for _
in range(16))
118 return ''.join(random
.choice(string
.ascii_uppercase
+ string
.ascii_lowercase
+ string
.digits
) for _
in range(32))
120 def gen_credentials():
121 return multisite
.Credentials(gen_access_key(), gen_secret())
123 def cluster_name(cluster_num
):
124 return 'c' + str(cluster_num
)
126 def zonegroup_name(zonegroup_num
):
127 return string
.ascii_lowercase
[zonegroup_num
]
129 def zone_name(zonegroup_num
, zone_num
):
130 return zonegroup_name(zonegroup_num
) + str(zone_num
+ 1)
132 def gateway_port(zonegroup_num
, gateway_num
):
133 return 8000 + 100 * zonegroup_num
+ gateway_num
135 def gateway_name(zonegroup_num
, zone_num
, gateway_num
):
136 return zone_name(zonegroup_num
, zone_num
) + '-' + str(gateway_num
+ 1)
138 def zone_endpoints(zonegroup_num
, zone_num
, gateways_per_zone
):
140 base
= gateway_port(zonegroup_num
, zone_num
* gateways_per_zone
)
141 for i
in range(0, gateways_per_zone
):
142 endpoints
.append('http://localhost:' + str(base
+ i
))
145 def get_log_level(log_level
):
154 return logging
.CRITICAL
156 def setup_logging(log_level_console
, log_file
, log_level_file
):
158 formatter
= logging
.Formatter('%(asctime)s %(levelname)s %(message)s')
159 fh
= logging
.FileHandler(log_file
)
160 fh
.setFormatter(formatter
)
161 fh
.setLevel(get_log_level(log_level_file
))
164 formatter
= logging
.Formatter('%(levelname)s %(message)s')
165 ch
= logging
.StreamHandler()
166 ch
.setFormatter(formatter
)
167 ch
.setLevel(get_log_level(log_level_console
))
169 log
.setLevel(get_log_level(log_level_console
))
171 def init(parse_args
):
172 cfg
= configparser
.RawConfigParser({
177 'gateways_per_zone': 2,
178 'no_bootstrap': 'false',
181 'file_log_level': 20,
183 'checkpoint_retries': 60,
184 'checkpoint_delay': 5,
185 'reconfigure_delay': 5,
189 path
= os
.environ
['RGW_MULTI_TEST_CONF']
191 path
= test_path
+ 'test_multi.conf'
194 with
open(path
) as f
:
197 print('WARNING: error reading test config. Path can be set through the RGW_MULTI_TEST_CONF env variable')
200 parser
= argparse
.ArgumentParser(
201 description
='Run rgw multi-site tests',
202 usage
='test_multi [--num-zonegroups <num>] [--num-zones <num>] [--no-bootstrap]')
205 parser
.add_argument('--num-zonegroups', type=int, default
=cfg
.getint(section
, 'num_zonegroups'))
206 parser
.add_argument('--num-zones', type=int, default
=cfg
.getint(section
, 'num_zones'))
207 parser
.add_argument('--gateways-per-zone', type=int, default
=cfg
.getint(section
, 'gateways_per_zone'))
208 parser
.add_argument('--no-bootstrap', action
='store_true', default
=cfg
.getboolean(section
, 'no_bootstrap'))
209 parser
.add_argument('--log-level', type=int, default
=cfg
.getint(section
, 'log_level'))
210 parser
.add_argument('--log-file', type=str, default
=cfg
.get(section
, 'log_file'))
211 parser
.add_argument('--file-log-level', type=int, default
=cfg
.getint(section
, 'file_log_level'))
212 parser
.add_argument('--tenant', type=str, default
=cfg
.get(section
, 'tenant'))
213 parser
.add_argument('--checkpoint-retries', type=int, default
=cfg
.getint(section
, 'checkpoint_retries'))
214 parser
.add_argument('--checkpoint-delay', type=int, default
=cfg
.getint(section
, 'checkpoint_delay'))
215 parser
.add_argument('--reconfigure-delay', type=int, default
=cfg
.getint(section
, 'reconfigure_delay'))
216 parser
.add_argument('--num-ps-zones', type=int, default
=cfg
.getint(section
, 'num_ps_zones'))
217 parser
.add_argument('--use-ssl', type=bool, default
=cfg
.getboolean(section
, 'use_ssl'))
225 for s
in cfg
.sections():
226 if s
.startswith('elasticsearch'):
227 es_cfg
.append(ESZoneConfig(cfg
, s
))
228 elif s
.startswith('cloud'):
229 cloud_cfg
.append(CloudZoneConfig(cfg
, s
))
230 elif s
.startswith('pubsub'):
231 ps_cfg
.append(PSZoneConfig(cfg
, s
))
232 elif s
.startswith('archive'):
233 az_cfg
.append(AZoneConfig(cfg
, s
))
241 args
= parser
.parse_args(argv
)
242 bootstrap
= not args
.no_bootstrap
244 setup_logging(args
.log_level
, args
.log_file
, args
.file_log_level
)
246 # start first cluster
247 c1
= Cluster(cluster_name(1))
253 admin_creds
= gen_credentials()
254 admin_user
= multisite
.User('zone.user')
256 user_creds
= gen_credentials()
257 user
= multisite
.User('tester', tenant
=args
.tenant
)
259 realm
= multisite
.Realm('r')
261 # create the realm on c1
265 period
= multisite
.Period(realm
=realm
)
266 realm
.current_period
= period
268 num_es_zones
= len(es_cfg
)
269 num_cloud_zones
= len(cloud_cfg
)
270 num_ps_zones_from_conf
= len(ps_cfg
)
271 num_az_zones
= cfg
.getint(section
, 'num_az_zones')
273 num_ps_zones
= args
.num_ps_zones
if num_ps_zones_from_conf
== 0 else num_ps_zones_from_conf
275 num_zones
= args
.num_zones
+ num_es_zones
+ num_cloud_zones
+ num_ps_zones
+ num_az_zones
277 use_ssl
= cfg
.getboolean(section
, 'use_ssl')
279 if use_ssl
and bootstrap
:
280 cmd
= ['openssl', 'req',
282 '-newkey', 'rsa:4096',
285 '-keyout', 'key.pem',
287 '-subj', '/CN=localhost',
291 fkey
= open('./key.pem', 'r')
293 fcert
= open('./cert.pem', 'a')
294 fcert
.write(fkey
.read())
298 for zg
in range(0, args
.num_zonegroups
):
299 zonegroup
= multisite
.ZoneGroup(zonegroup_name(zg
), period
)
300 period
.zonegroups
.append(zonegroup
)
302 is_master_zg
= zg
== 0
304 period
.master_zonegroup
= zonegroup
306 for z
in range(0, num_zones
):
308 # start a cluster, or use c1 for first zone
310 if is_master_zg
and is_master
:
313 cluster
= Cluster(cluster_name(len(clusters
) + 1))
314 clusters
.append(cluster
)
317 # pull realm configuration from the master's gateway
318 gateway
= realm
.meta_master_zone().gateways
[0]
319 realm
.pull(cluster
, gateway
, admin_creds
)
321 endpoints
= zone_endpoints(zg
, z
, args
.gateways_per_zone
)
324 # create the zonegroup on its first zone's cluster
328 if len(endpoints
): # use master zone's endpoints
329 arg
+= ['--endpoints', ','.join(endpoints
)]
330 zonegroup
.create(cluster
, arg
)
332 zonegroup
.get(cluster
)
334 es_zone
= (z
>= args
.num_zones
and z
< args
.num_zones
+ num_es_zones
)
335 cloud_zone
= (z
>= args
.num_zones
+ num_es_zones
and z
< args
.num_zones
+ num_es_zones
+ num_cloud_zones
)
336 ps_zone
= (z
>= args
.num_zones
+ num_es_zones
+ num_cloud_zones
and z
< args
.num_zones
+ num_es_zones
+ num_cloud_zones
+ num_ps_zones
)
337 az_zone
= (z
>= args
.num_zones
+ num_es_zones
+ num_cloud_zones
+ num_ps_zones
)
339 # create the zone in its zonegroup
340 zone
= multisite
.Zone(zone_name(zg
, z
), zonegroup
, cluster
)
342 zone_index
= z
- args
.num_zones
343 zone
= ESZone(zone_name(zg
, z
), es_cfg
[zone_index
].endpoint
, zonegroup
, cluster
)
345 zone_index
= z
- args
.num_zones
- num_es_zones
346 ccfg
= cloud_cfg
[zone_index
]
347 zone
= CloudZone(zone_name(zg
, z
), ccfg
.endpoint
, ccfg
.credentials
, ccfg
.source_bucket
,
348 ccfg
.target_path
, zonegroup
, cluster
)
350 zone_index
= z
- args
.num_zones
- num_es_zones
- num_cloud_zones
351 if num_ps_zones_from_conf
== 0:
352 zone
= PSZone(zone_name(zg
, z
), zonegroup
, cluster
)
354 pscfg
= ps_cfg
[zone_index
]
355 zone
= PSZone(zone_name(zg
, z
), zonegroup
, cluster
,
356 full_sync
=pscfg
.full_sync
, retention_days
=pscfg
.retention_days
)
358 zone_index
= z
- args
.num_zones
- num_es_zones
- num_cloud_zones
- num_ps_zones
359 zone
= AZone(zone_name(zg
, z
), zonegroup
, cluster
)
361 zone
= RadosZone(zone_name(zg
, z
), zonegroup
, cluster
)
364 arg
= admin_creds
.credential_args()
368 arg
+= ['--endpoints', ','.join(endpoints
)]
369 zone
.create(cluster
, arg
)
372 zonegroup
.zones
.append(zone
)
374 zonegroup
.master_zone
= zone
376 zonegroup
.zones_by_type
.setdefault(zone
.tier_type(), []).append(zone
)
378 if zone
.is_read_only():
379 zonegroup
.ro_zones
.append(zone
)
381 zonegroup
.rw_zones
.append(zone
)
383 # update/commit the period
385 period
.update(zone
, commit
=True)
387 ssl_port_offset
= 1000
389 for g
in range(0, args
.gateways_per_zone
):
390 port
= gateway_port(zg
, g
+ z
* args
.gateways_per_zone
)
391 client_id
= gateway_name(zg
, z
, g
)
392 gateway
= Gateway(client_id
, 'localhost', port
, cluster
, zone
,
393 ssl_port
= port
+ssl_port_offset
if use_ssl
else 0)
396 zone
.gateways
.append(gateway
)
398 if is_master_zg
and is_master
:
401 arg
= ['--display-name', '"Zone User"', '--system']
402 arg
+= admin_creds
.credential_args()
403 admin_user
.create(zone
, arg
)
405 arg
= ['--display-name', '"Test User"']
406 arg
+= user_creds
.credential_args()
407 user
.create(zone
, arg
)
409 # read users and update keys
410 admin_user
.info(zone
)
411 admin_creds
= admin_user
.credentials
[0]
414 user_creds
= user
.credentials
[0]
419 config
= Config(checkpoint_retries
=args
.checkpoint_retries
,
420 checkpoint_delay
=args
.checkpoint_delay
,
421 reconfigure_delay
=args
.reconfigure_delay
,
423 init_multi(realm
, user
, config
)
428 if __name__
== "__main__":