]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/rgw/test_multi.py
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_az
import AZone
as AZone
22 from rgw_multi
.zone_az
import AZoneConfig
as AZoneConfig
24 # make tests from rgw_multi.tests available to nose
25 from rgw_multi
.tests
import *
26 from rgw_multi
.tests_es
import *
27 from rgw_multi
.tests_az
import *
29 mstart_path
= os
.getenv('MSTART_PATH')
30 if mstart_path
is None:
31 mstart_path
= os
.path
.normpath(os
.path
.dirname(os
.path
.realpath(__file__
)) + '/../..') + '/'
33 test_path
= os
.path
.normpath(os
.path
.dirname(os
.path
.realpath(__file__
))) + '/'
35 # configure logging for the tests module
36 log
= logging
.getLogger('rgw_multi.tests')
38 def bash(cmd
, **kwargs
):
39 log
.debug('running cmd: %s', ' '.join(cmd
))
40 check_retcode
= kwargs
.pop('check_retcode', True)
41 kwargs
['stdout'] = subprocess
.PIPE
42 process
= subprocess
.Popen(cmd
, **kwargs
)
43 s
= process
.communicate()[0].decode('utf-8')
44 log
.debug('command returned status=%d stdout=%s', process
.returncode
, s
)
46 assert(process
.returncode
== 0)
47 return (s
, process
.returncode
)
49 class Cluster(multisite
.Cluster
):
50 """ cluster implementation based on mstart/mrun scripts """
51 def __init__(self
, cluster_id
):
52 super(Cluster
, self
).__init
__()
53 self
.cluster_id
= cluster_id
54 self
.needs_reset
= True
56 def admin(self
, args
= None, **kwargs
):
57 """ radosgw-admin command """
58 cmd
= [test_path
+ 'test-rgw-call.sh', 'call_rgw_admin', self
.cluster_id
]
61 cmd
+= ['--debug-rgw=' + str(kwargs
.pop('debug_rgw', 0))]
62 cmd
+= ['--debug-ms=' + str(kwargs
.pop('debug_ms', 0))]
63 if kwargs
.pop('read_only', False):
64 cmd
+= ['--rgw-cache-enabled=false']
65 return bash(cmd
, **kwargs
)
68 cmd
= [mstart_path
+ 'mstart.sh', self
.cluster_id
]
71 env
= os
.environ
.copy()
72 env
['CEPH_NUM_MDS'] = '0'
75 # cmd += ['rgw_cache_enabled=false']
77 self
.needs_reset
= False
80 cmd
= [mstart_path
+ 'mstop.sh', self
.cluster_id
]
83 class Gateway(multisite
.Gateway
):
84 """ gateway implementation based on mrgw/mstop scripts """
85 def __init__(self
, client_id
= None, *args
, **kwargs
):
86 super(Gateway
, self
).__init
__(*args
, **kwargs
)
89 def start(self
, args
= None):
90 """ start the gateway """
92 env
= os
.environ
.copy()
93 # to change frontend, set RGW_FRONTEND env variable
94 # e.g. RGW_FRONTEND=civetweb
95 # to run test under valgrind memcheck, set RGW_VALGRIND to 'yes'
96 # e.g. RGW_VALGRIND=yes
97 cmd
= [mstart_path
+ 'mrgw.sh', self
.cluster
.cluster_id
, str(self
.port
), str(self
.ssl_port
)]
99 cmd
+= ['-i', self
.id]
100 cmd
+= ['--debug-rgw=20', '--debug-ms=1']
106 """ stop the gateway """
108 cmd
= [mstart_path
+ 'mstop.sh', self
.cluster
.cluster_id
, 'radosgw', str(self
.port
)]
111 def gen_access_key():
112 return ''.join(random
.choice(string
.ascii_uppercase
+ string
.digits
) for _
in range(16))
115 return ''.join(random
.choice(string
.ascii_uppercase
+ string
.ascii_lowercase
+ string
.digits
) for _
in range(32))
117 def gen_credentials():
118 return multisite
.Credentials(gen_access_key(), gen_secret())
120 def cluster_name(cluster_num
):
121 return 'c' + str(cluster_num
)
123 def zonegroup_name(zonegroup_num
):
124 return string
.ascii_lowercase
[zonegroup_num
]
126 def zone_name(zonegroup_num
, zone_num
):
127 return zonegroup_name(zonegroup_num
) + str(zone_num
+ 1)
129 def gateway_port(zonegroup_num
, gateway_num
):
130 return 8000 + 100 * zonegroup_num
+ gateway_num
132 def gateway_name(zonegroup_num
, zone_num
, gateway_num
):
133 return zone_name(zonegroup_num
, zone_num
) + '-' + str(gateway_num
+ 1)
135 def zone_endpoints(zonegroup_num
, zone_num
, gateways_per_zone
):
137 base
= gateway_port(zonegroup_num
, zone_num
* gateways_per_zone
)
138 for i
in range(0, gateways_per_zone
):
139 endpoints
.append('http://localhost:' + str(base
+ i
))
142 def get_log_level(log_level
):
151 return logging
.CRITICAL
153 def setup_logging(log_level_console
, log_file
, log_level_file
):
155 formatter
= logging
.Formatter('%(asctime)s %(levelname)s %(message)s')
156 fh
= logging
.FileHandler(log_file
)
157 fh
.setFormatter(formatter
)
158 fh
.setLevel(get_log_level(log_level_file
))
161 formatter
= logging
.Formatter('%(levelname)s %(message)s')
162 ch
= logging
.StreamHandler()
163 ch
.setFormatter(formatter
)
164 ch
.setLevel(get_log_level(log_level_console
))
166 log
.setLevel(get_log_level(log_level_console
))
168 def init(parse_args
):
169 cfg
= configparser
.RawConfigParser({
173 'gateways_per_zone': 2,
174 'no_bootstrap': 'false',
177 'file_log_level': 20,
179 'checkpoint_retries': 60,
180 'checkpoint_delay': 5,
181 'reconfigure_delay': 5,
185 path
= os
.environ
['RGW_MULTI_TEST_CONF']
187 path
= test_path
+ 'test_multi.conf'
190 with
open(path
) as f
:
193 print('WARNING: error reading test config. Path can be set through the RGW_MULTI_TEST_CONF env variable')
196 parser
= argparse
.ArgumentParser(
197 description
='Run rgw multi-site tests',
198 usage
='test_multi [--num-zonegroups <num>] [--num-zones <num>] [--no-bootstrap]')
201 parser
.add_argument('--num-zonegroups', type=int, default
=cfg
.getint(section
, 'num_zonegroups'))
202 parser
.add_argument('--num-zones', type=int, default
=cfg
.getint(section
, 'num_zones'))
203 parser
.add_argument('--gateways-per-zone', type=int, default
=cfg
.getint(section
, 'gateways_per_zone'))
204 parser
.add_argument('--no-bootstrap', action
='store_true', default
=cfg
.getboolean(section
, 'no_bootstrap'))
205 parser
.add_argument('--log-level', type=int, default
=cfg
.getint(section
, 'log_level'))
206 parser
.add_argument('--log-file', type=str, default
=cfg
.get(section
, 'log_file'))
207 parser
.add_argument('--file-log-level', type=int, default
=cfg
.getint(section
, 'file_log_level'))
208 parser
.add_argument('--tenant', type=str, default
=cfg
.get(section
, 'tenant'))
209 parser
.add_argument('--checkpoint-retries', type=int, default
=cfg
.getint(section
, 'checkpoint_retries'))
210 parser
.add_argument('--checkpoint-delay', type=int, default
=cfg
.getint(section
, 'checkpoint_delay'))
211 parser
.add_argument('--reconfigure-delay', type=int, default
=cfg
.getint(section
, 'reconfigure_delay'))
212 parser
.add_argument('--use-ssl', type=bool, default
=cfg
.getboolean(section
, 'use_ssl'))
219 for s
in cfg
.sections():
220 if s
.startswith('elasticsearch'):
221 es_cfg
.append(ESZoneConfig(cfg
, s
))
222 elif s
.startswith('cloud'):
223 cloud_cfg
.append(CloudZoneConfig(cfg
, s
))
224 elif s
.startswith('archive'):
225 az_cfg
.append(AZoneConfig(cfg
, s
))
233 args
= parser
.parse_args(argv
)
234 bootstrap
= not args
.no_bootstrap
236 setup_logging(args
.log_level
, args
.log_file
, args
.file_log_level
)
238 # start first cluster
239 c1
= Cluster(cluster_name(1))
245 admin_creds
= gen_credentials()
246 admin_user
= multisite
.User('zone.user')
248 user_creds
= gen_credentials()
249 user
= multisite
.User('tester', tenant
=args
.tenant
)
251 realm
= multisite
.Realm('r')
253 # create the realm on c1
257 period
= multisite
.Period(realm
=realm
)
258 realm
.current_period
= period
260 num_es_zones
= len(es_cfg
)
261 num_cloud_zones
= len(cloud_cfg
)
262 num_az_zones
= cfg
.getint(section
, 'num_az_zones')
264 num_zones
= args
.num_zones
+ num_es_zones
+ num_cloud_zones
+ num_az_zones
266 use_ssl
= cfg
.getboolean(section
, 'use_ssl')
268 if use_ssl
and bootstrap
:
269 cmd
= ['openssl', 'req',
271 '-newkey', 'rsa:4096',
274 '-keyout', 'key.pem',
276 '-subj', '/CN=localhost',
280 fkey
= open('./key.pem', 'r')
282 fcert
= open('./cert.pem', 'a')
283 fcert
.write(fkey
.read())
287 for zg
in range(0, args
.num_zonegroups
):
288 zonegroup
= multisite
.ZoneGroup(zonegroup_name(zg
), period
)
289 period
.zonegroups
.append(zonegroup
)
291 is_master_zg
= zg
== 0
293 period
.master_zonegroup
= zonegroup
295 for z
in range(0, num_zones
):
297 # start a cluster, or use c1 for first zone
299 if is_master_zg
and is_master
:
302 cluster
= Cluster(cluster_name(len(clusters
) + 1))
303 clusters
.append(cluster
)
306 # pull realm configuration from the master's gateway
307 gateway
= realm
.meta_master_zone().gateways
[0]
308 realm
.pull(cluster
, gateway
, admin_creds
)
310 endpoints
= zone_endpoints(zg
, z
, args
.gateways_per_zone
)
313 # create the zonegroup on its first zone's cluster
317 if len(endpoints
): # use master zone's endpoints
318 arg
+= ['--endpoints', ','.join(endpoints
)]
319 zonegroup
.create(cluster
, arg
)
321 zonegroup
.get(cluster
)
323 es_zone
= (z
>= args
.num_zones
and z
< args
.num_zones
+ num_es_zones
)
324 cloud_zone
= (z
>= args
.num_zones
+ num_es_zones
and z
< args
.num_zones
+ num_es_zones
+ num_cloud_zones
)
325 az_zone
= (z
>= args
.num_zones
+ num_es_zones
+ num_cloud_zones
)
327 # create the zone in its zonegroup
328 zone
= multisite
.Zone(zone_name(zg
, z
), zonegroup
, cluster
)
330 zone_index
= z
- args
.num_zones
331 zone
= ESZone(zone_name(zg
, z
), es_cfg
[zone_index
].endpoint
, zonegroup
, cluster
)
333 zone_index
= z
- args
.num_zones
- num_es_zones
334 ccfg
= cloud_cfg
[zone_index
]
335 zone
= CloudZone(zone_name(zg
, z
), ccfg
.endpoint
, ccfg
.credentials
, ccfg
.source_bucket
,
336 ccfg
.target_path
, zonegroup
, cluster
)
338 zone_index
= z
- args
.num_zones
- num_es_zones
- num_cloud_zones
339 zone
= AZone(zone_name(zg
, z
), zonegroup
, cluster
)
341 zone
= RadosZone(zone_name(zg
, z
), zonegroup
, cluster
)
344 arg
= admin_creds
.credential_args()
348 arg
+= ['--endpoints', ','.join(endpoints
)]
349 zone
.create(cluster
, arg
)
352 zonegroup
.zones
.append(zone
)
354 zonegroup
.master_zone
= zone
356 zonegroup
.zones_by_type
.setdefault(zone
.tier_type(), []).append(zone
)
358 if zone
.is_read_only():
359 zonegroup
.ro_zones
.append(zone
)
361 zonegroup
.rw_zones
.append(zone
)
363 # update/commit the period
365 period
.update(zone
, commit
=True)
367 ssl_port_offset
= 1000
369 for g
in range(0, args
.gateways_per_zone
):
370 port
= gateway_port(zg
, g
+ z
* args
.gateways_per_zone
)
371 client_id
= gateway_name(zg
, z
, g
)
372 gateway
= Gateway(client_id
, 'localhost', port
, cluster
, zone
,
373 ssl_port
= port
+ssl_port_offset
if use_ssl
else 0)
376 zone
.gateways
.append(gateway
)
378 if is_master_zg
and is_master
:
381 arg
= ['--display-name', '"Zone User"', '--system']
382 arg
+= admin_creds
.credential_args()
383 admin_user
.create(zone
, arg
)
385 arg
= ['--display-name', '"Test User"', '--caps', 'roles=*']
386 arg
+= user_creds
.credential_args()
387 user
.create(zone
, arg
)
389 # read users and update keys
390 admin_user
.info(zone
)
391 admin_creds
= admin_user
.credentials
[0]
394 user_creds
= user
.credentials
[0]
399 config
= Config(checkpoint_retries
=args
.checkpoint_retries
,
400 checkpoint_delay
=args
.checkpoint_delay
,
401 reconfigure_delay
=args
.reconfigure_delay
,
403 init_multi(realm
, user
, config
)
408 if __name__
== "__main__":