def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = {'host_file_separator': ','} config['cassandra'] = { 'config_file': os.path.join( os.path.dirname(__file__), 'resources/yaml/work/cassandra_with_tokens_and_autobootstrap.yaml' ), 'start_cmd': '/etc/init.d/cassandra start', 'stop_cmd': '/etc/init.d/cassandra stop', 'is_ccm': '1', 'resolve_ip_addresses': 'False' } self.config = MedusaConfig( storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None)
def test_nodetool_command_with_ssl_false(self): config = configparser.ConfigParser(interpolation=None) config['cassandra'] = { 'nodetool_ssl': 'false', 'nodetool_username': '******', 'nodetool_password': '******', 'nodetool_password_file_path': '/etc/cassandra/jmx.password', 'nodetool_host': '127.0.0.1', 'nodetool_port': '7199' } config["grpc"] = {"enabled": "0"} config['kubernetes'] = {"enabled": "0"} medusa_config = MedusaConfig( storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) n = Nodetool(medusa_config.cassandra).nodetool expected = [ 'nodetool', '-u', 'cassandra', '-pw', 'password', '-pwf', '/etc/cassandra/jmx.password', '-h', '127.0.0.1', '-p', '7199' ] self.assertEqual(n, expected)
def setUp(self): if os.path.isdir(self.local_storage_dir): shutil.rmtree(self.local_storage_dir) if os.path.isdir(self.medusa_bucket_dir): shutil.rmtree(self.medusa_bucket_dir) os.makedirs(self.local_storage_dir) config = configparser.ConfigParser(interpolation=None) config['storage'] = { 'host_file_separator': ',', 'bucket_name': 'medusa_test_bucket', 'key_file': '', 'storage_provider': 'local', 'fqdn': '127.0.0.1', 'api_key_or_username': '', 'api_secret_or_password': '', 'base_path': '/tmp', 'prefix': 'pre' } config['cassandra'] = {'is_ccm': 1} self.config = MedusaConfig( storage=_namedtuple_from_dict(StorageConfig, config['storage']), cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), monitoring={}, ssh=None, checks=None, logging=None, grpc=None, kubernetes=None, ) self.storage = Storage(config=self.config.storage)
def test_build_restore_command_kubernetes(self): """Ensure Kubernetes mode does not generate a command line with sudo""" medusa_config_file = pathlib.Path( __file__).parent / "resources/config/medusa-kubernetes.ini" cassandra_yaml = pathlib.Path( __file__).parent / "resources/config/cassandra.yaml" args = {'config_file': str(cassandra_yaml)} config = parse_config(args, medusa_config_file) medusa_config = MedusaConfig( file_path=medusa_config_file, storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) restore_job = RestoreJob(Mock(), medusa_config, self.tmp_dir, None, None, False, False, None) cmd = restore_job._build_restore_cmd() assert evaluate_boolean(medusa_config.kubernetes.enabled) assert 'sudo' not in cmd, 'Kubernetes mode should not generate command line with sudo' assert str(medusa_config_file) in cmd
def test_seed_parsing(self): shutil.copyfile('tests/resources/yaml/original/cassandra_with_tokens_and_autobootstrap.yaml', 'tests/resources/yaml/work/cassandra_with_tokens_and_autobootstrap.yaml') config = configparser.ConfigParser(interpolation=None) config['cassandra'] = { 'config_file': os.path.join(os.path.dirname(__file__), 'resources/yaml/work/cassandra_with_tokens_and_autobootstrap.yaml'), 'start_cmd': '/etc/init.d/cassandra start', 'stop_cmd': '/etc/init.d/cassandra stop', 'is_ccm': '1' } config["grpc"] = { "enabled": "0" } config['kubernetes'] = { "enabled": "0" } medusa_config = MedusaConfig( file_path=None, storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) cassandra = Cassandra(medusa_config) self.assertEqual(["127.0.0.1", "127.0.0.2"], sorted(cassandra.seeds))
def get_simple_medusa_config(yaml_file='resources/yaml/original/default-c4.yaml', is_ccm_active='1', config_checks=None): config = configparser.ConfigParser(interpolation=None) config['cassandra'] = { 'config_file': os.path.join(os.path.dirname(__file__), yaml_file), 'start_cmd': '/etc/init.d/cassandra start', 'stop_cmd': '/etc/init.d/cassandra stop', 'is_ccm': is_ccm_active } config["grpc"] = { "enabled": "0" } config['kubernetes'] = { "enabled": "0" } checks_set = None if config_checks: config["checks"] = config_checks checks_set = _namedtuple_from_dict(ChecksConfig, config['checks']) medusa_config = MedusaConfig( file_path=None, storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ssh=None, checks=checks_set, logging=None, ) return medusa_config
def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = { 'host_file_separator': ',' } config['cassandra'] = { 'resolve_ip_addresses': 'False' } config["grpc"] = { "enabled": "0" } config['kubernetes'] = { "enabled": "0" } self.config = MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), )
def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = {'host_file_separator': ','} config['cassandra'] = { 'config_file': os.path.join( os.path.dirname(__file__), 'resources/yaml/work/cassandra_with_tokens_and_autobootstrap.yaml' ), 'start_cmd': '/etc/init.d/cassandra start', 'stop_cmd': '/etc/init.d/cassandra stop', 'is_ccm': '1', 'resolve_ip_addresses': 'False' } config["grpc"] = {"enabled": "0"} config['kubernetes'] = {"enabled": "0"} self.config = config self.medusa_config = MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) self.tmp_dir = Path(tempfile.gettempdir())
def i_am_using_storage_provider_with_grpc_server(context, storage_provider, client_encryption): config = parse_medusa_config(context, storage_provider, client_encryption, "http://127.0.0.1:8778/jolokia/", grpc=1, use_mgmt_api=1) GRPCServer.destroy() context.grpc_server = GRPCServer.init(config) context.grpc_client = medusa.service.grpc.client.Client( "127.0.0.1:50051", channel_options=[('grpc.enable_retries', 0)]) context.medusa_config = MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, config["storage"]), cassandra=_namedtuple_from_dict(CassandraConfig, config["cassandra"]), monitoring=_namedtuple_from_dict(MonitoringConfig, config["monitoring"]), ssh=None, checks=_namedtuple_from_dict(ChecksConfig, config["checks"]), logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config["grpc"]), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) cleanup_storage(context, storage_provider) # sleep for a few seconds to give gRPC server a chance to initialize time.sleep(3)
def setUp(self): self.config = self._build_config_parser() self.medusa_config = MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, self.config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, self.config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, self.config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, self.config['kubernetes']), ) self.tmp_dir = pathlib.Path(tempfile.gettempdir()) # Useful for a couple of tests self.default_restore_job = RestoreJob(cluster_backup=Mock(), config=self.medusa_config, temp_dir=self.tmp_dir, host_list=None, seed_target=None, keep_auth=False, verify=False, parallel_restores=None)
def test_yaml_token_enforcement_with_tokens_and_autobootstrap(self): with open('tests/resources/yaml/original/cassandra_with_tokens.yaml', 'r') as f: shutil.copyfile('tests/resources/yaml/original/cassandra_with_tokens_and_autobootstrap.yaml', 'tests/resources/yaml/work/cassandra_with_tokens_and_autobootstrap.yaml') config = configparser.ConfigParser(interpolation=None) config['cassandra'] = { 'config_file': os.path.join(os.path.dirname(__file__), 'resources/yaml/work/cassandra_with_tokens_and_autobootstrap.yaml'), 'start_cmd': '/etc/init.d/cassandra start', 'stop_cmd': '/etc/init.d/cassandra stop', 'is_ccm': '1' } medusa_config = MedusaConfig( storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None ) cassandra = Cassandra(medusa_config.cassandra) tokens = ['1', '2', '3'] cassandra.replaceTokensInCassandraYamlAndDisableBootstrap(tokens) with open('tests/resources/yaml/work/cassandra_with_tokens_and_autobootstrap.yaml', 'r') as f: modified_yaml = yaml.load(f, Loader=yaml.BaseLoader) self.assertEqual(modified_yaml.get('num_tokens'), '3') self.assertEqual(modified_yaml.get('initial_token'), '1,2,3') self.assertEqual(modified_yaml.get('auto_bootstrap'), 'false')
def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = {'host_file_separator': ','} self.config = MedusaConfig(storage=_namedtuple_from_dict( StorageConfig, config['storage']), monitoring={}, cassandra=None, ssh=None, restore=None)
def i_am_using_storage_provider_with_grpc_server_and_mgmt_api( context, storage_provider, client_encryption): config = parse_medusa_config( context, storage_provider, client_encryption, "http://127.0.0.1:8080/api/v0/ops/node/snapshots", use_mgmt_api=1, grpc=1) GRPCServer.destroy() context.grpc_server = GRPCServer.init(config) context.grpc_client = medusa.service.grpc.client.Client( "127.0.0.1:50051", channel_options=[('grpc.enable_retries', 0)]) MgmtApiServer.destroy() context.mgmt_api_server = MgmtApiServer.init(config, context.cluster_name) context.medusa_config = MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, config["storage"]), cassandra=_namedtuple_from_dict(CassandraConfig, config["cassandra"]), monitoring=_namedtuple_from_dict(MonitoringConfig, config["monitoring"]), ssh=None, checks=_namedtuple_from_dict(ChecksConfig, config["checks"]), logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config["grpc"]), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) cleanup_storage(context, storage_provider) is_client_encryption_enable = False if client_encryption == 'with_client_encryption': is_client_encryption_enable = True # sleep for a few seconds to give gRPC server a chance to initialize ready_count = 0 while ready_count < 20: ready = 0 try: ready = requests.get( "http://127.0.0.1:8080/api/v0/probes/readiness").status_code except Exception: # wait for the server to be ready time.sleep(1) ready_count += 1 if ready == 200: # server is ready, re-establish the session context.session = connect_cassandra(is_client_encryption_enable) break else: # wait for Cassandra to be ready time.sleep(1)
def test_nodetool_command_without_parameter(self): config = configparser.ConfigParser(interpolation=None) config['cassandra'] = {} medusa_config = MedusaConfig(storage=None, monitoring=None, cassandra=_namedtuple_from_dict( CassandraConfig, config['cassandra']), ssh=None, restore=None, logging=None) n = Nodetool(medusa_config.cassandra).nodetool self.assertEqual(n, ['nodetool'])
def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = {'host_file_separator': ','} config['cassandra'] = {'resolve_ip_addresses': False} self.config = MedusaConfig( storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(StorageConfig, config['cassandra']), ssh=None, checks=None, logging=None)
def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = {'host_file_separator': ','} self.config = MedusaConfig(file_path=None, storage=_namedtuple_from_dict( StorageConfig, config['storage']), monitoring={}, cassandra=None, ssh=None, checks=None, logging=None, grpc=None, kubernetes=None)
def _build_medusa_config(config): return MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=_namedtuple_from_dict(SSHConfig, config['ssh']), checks=None, logging=None, grpc=None, kubernetes=None, )
def _i_can_verify_the_restore_verify_query_restored_rows(context, query, expected_rows): restore_config = { 'health_check': 'cql', 'query': query, 'expected_rows': expected_rows } custom_config = MedusaConfig( storage=context.medusa_config.storage, cassandra=context.medusa_config.cassandra, monitoring=context.medusa_config.monitoring, restore=_namedtuple_from_dict(ChecksConfig, restore_config), ssh=None ) medusa.verify_restore.verify_restore(['localhost'], custom_config)
def _i_can_verify_the_restore_verify_query_returned_rows(context, query, expected_rows): restore_config = { "health_check": "cql", "query": query, "expected_rows": expected_rows, } custom_config = MedusaConfig( storage=context.medusa_config.storage, cassandra=context.medusa_config.cassandra, monitoring=context.medusa_config.monitoring, restore=_namedtuple_from_dict(ChecksConfig, restore_config), ssh=None, ) medusa.verify_restore.verify_restore(["localhost"], custom_config)
def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = { 'host_file_separator': ',', 'storage_provider': 'local', 'base_path': '/tmp', 'bucket_name': 'purge_test' } self.config = MedusaConfig(storage=_namedtuple_from_dict( StorageConfig, config['storage']), monitoring={}, cassandra=None, ssh=None, restore=None) self.storage = Storage(config=self.config.storage)
def test_cmd_with_custom_config_path(self): """Ensure that custom config file is honored during a restore""" config = MedusaConfig( file_path=pathlib.Path('/custom/path/to/medusa.ini'), storage=_namedtuple_from_dict(StorageConfig, self.config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, self.config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, self.config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, self.config['kubernetes']), ) restore_job = RestoreJob(Mock(), config, self.tmp_dir, None, None, False, False, None) cmd = restore_job._build_restore_cmd() assert '--config-file /custom/path/to/medusa.ini' in cmd
def test_parsing_custom_seed_provider(self): # patch a sample yaml to have a custom seed provider with open('tests/resources/yaml/original/cassandra_with_tokens.yaml', 'r') as fi: yaml_dict = yaml.load(fi, Loader=yaml.FullLoader) yaml_dict['seed_provider'] = [{ 'class_name': 'org.foo.bar.CustomSeedProvider' }] with open( 'tests/resources/yaml/work/cassandra_with_custom_seedprovider.yaml', 'w') as fo: yaml.safe_dump(yaml_dict, fo) # pass the patched yaml to cassandra config config = configparser.ConfigParser(interpolation=None) config['cassandra'] = { 'config_file': os.path.join( os.path.dirname(__file__), 'resources/yaml/work/cassandra_with_custom_seedprovider.yaml'), 'start_cmd': '/etc/init.d/cassandra start', 'stop_cmd': '/etc/init.d/cassandra stop', 'is_ccm': '1' } config["grpc"] = {"enabled": "0"} config['kubernetes'] = {"enabled": "0"} medusa_config = MedusaConfig( storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) cassandra = Cassandra(medusa_config) self.assertEqual([], sorted(cassandra.seeds))
def test_nodetool_command_without_parameter(self): config = configparser.ConfigParser(interpolation=None) config['cassandra'] = {} config["grpc"] = {"enabled": "0"} config['kubernetes'] = {"enabled": "0"} medusa_config = MedusaConfig( storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) n = Nodetool(medusa_config.cassandra).nodetool self.assertEqual(n, ['nodetool'])
def _i_can_verify_the_restore_verify_query_returned_rows( context, query, expected_rows): restore_config = { "health_check": "cql", "query": query, "expected_rows": expected_rows, } custom_config = MedusaConfig( file_path=None, storage=context.medusa_config.storage, cassandra=context.medusa_config.cassandra, monitoring=context.medusa_config.monitoring, checks=_namedtuple_from_dict(ChecksConfig, restore_config), ssh=None, logging=None, grpc=None, kubernetes=None, ) medusa.verify_restore.verify_restore(["127.0.0.1"], custom_config)
def test_build_restore_command_without_sudo(self): """Ensure that a restore can be done without using sudo""" config = self._build_config_parser() config['cassandra']['use_sudo'] = 'False' medusa_config = MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) restore_job = RestoreJob(Mock(), medusa_config, self.tmp_dir, None, None, False, False, None) cmd = restore_job._build_restore_cmd() assert not evaluate_boolean(medusa_config.cassandra.use_sudo) assert 'sudo' not in cmd, 'command line should not contain sudo when use_sudo is explicitly set to False'
def setUp(self): config = configparser.ConfigParser(interpolation=None) config['storage'] = { 'host_file_separator': ',', 'storage_provider': 'local', 'base_path': '/tmp', 'bucket_name': 'purge_test', 'fqdn': 'node1' } self.config = MedusaConfig( file_path=None, storage=_namedtuple_from_dict(StorageConfig, config['storage']), monitoring={}, cassandra=None, ssh=None, checks=None, logging=None, grpc=None, kubernetes=None, ) self.storage = Storage(config=self.config.storage)
def test_nodetool_command_with_parameters(self): config = configparser.ConfigParser(interpolation=None) config['cassandra'] = { 'nodetool_ssl': 'true', 'nodetool_username': '******', 'nodetool_password': '******', 'nodetool_password_file_path': '/etc/cassandra/jmx.password', 'nodetool_host': '127.0.0.1', 'nodetool_port': '7199' } medusa_config = MedusaConfig( storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None ) n = Nodetool(medusa_config.cassandra).nodetool expected = ['nodetool', '--ssl', '-u', 'cassandra', '-pw', 'password', '-pwf', '/etc/cassandra/jmx.password', '-h', '127.0.0.1', '-p', '7199'] self.assertEqual(n, expected)
def test_yaml_token_enforcement_no_tokens(self): with open('tests/resources/yaml/original/cassandra_no_tokens.yaml', 'r') as f: shutil.copyfile('tests/resources/yaml/original/cassandra_no_tokens.yaml', 'tests/resources/yaml/work/cassandra_no_tokens.yaml') config = configparser.ConfigParser(interpolation=None) config['cassandra'] = { 'config_file': os.path.join(os.path.dirname(__file__), 'resources/yaml/work/cassandra_no_tokens.yaml'), 'start_cmd': '/etc/init.d/cassandra start', 'stop_cmd': '/etc/init.d/cassandra stop', 'is_ccm': '1' } config["grpc"] = { "enabled": "0" } config['kubernetes'] = { "enabled": "0" } medusa_config = MedusaConfig( file_path=None, storage=None, monitoring=None, cassandra=_namedtuple_from_dict(CassandraConfig, config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, config['kubernetes']), ) cassandra = Cassandra(medusa_config) tokens = ['1', '2', '3'] cassandra.replace_tokens_in_cassandra_yaml_and_disable_bootstrap(tokens) with open('tests/resources/yaml/work/cassandra_no_tokens.yaml', 'r') as f: modified_yaml = yaml.load(f, Loader=yaml.BaseLoader) self.assertEqual(modified_yaml.get('num_tokens'), '3') self.assertEqual(modified_yaml.get('initial_token'), '1,2,3') self.assertEqual(modified_yaml.get('auto_bootstrap'), 'false')
def setUp(self): self.config = config._build_default_config() self.config['grpc'] = { 'enabled': 'True' } self.config['cassandra'] = { 'config_file': MagicMock(), } self.config['storage'] = { 'host_file_separator': ',', 'storage_provider': 'local' } self.medusa_config = MedusaConfig( file_path=os.getcwd(), storage=namedtuple_from_dict(StorageConfig, self.config['storage']), cassandra=namedtuple_from_dict(CassandraConfig, self.config['cassandra']), ssh=namedtuple_from_dict(SSHConfig, self.config['ssh']), checks=namedtuple_from_dict(ChecksConfig, self.config['checks']), monitoring=namedtuple_from_dict(MonitoringConfig, self.config['monitoring']), logging=namedtuple_from_dict(LoggingConfig, self.config['logging']), grpc=namedtuple_from_dict(GrpcConfig, self.config['grpc']), kubernetes=namedtuple_from_dict(KubernetesConfig, self.config['kubernetes']) )
def test_cmd_with_custom_config_path(self): with open("tests/resources/restore_cluster_tokenmap.json", 'r') as f: cluster_backup = Mock() tokenmap = json.loads(f.read()) cluster_backup.tokenmap.return_value = tokenmap host_list = "tests/resources/restore_cluster_host_list.txt" config = MedusaConfig( file_path='/custom/path/to/medusa.ini', storage=_namedtuple_from_dict(StorageConfig, self.config['storage']), monitoring={}, cassandra=_namedtuple_from_dict(CassandraConfig, self.config['cassandra']), ssh=None, checks=None, logging=None, grpc=_namedtuple_from_dict(GrpcConfig, self.config['grpc']), kubernetes=_namedtuple_from_dict(KubernetesConfig, self.config['kubernetes']), ) restore_job = RestoreJob(cluster_backup, config, self.tmp_dir, host_list, None, False, False, None) cmd = restore_job._build_restore_cmd() assert '--config-file /custom/path/to/medusa.ini' in cmd