def test_cassandra_start(self, subproc_mock, replace_tokens_mock): subproc_mock.return_value = None replace_tokens_mock.return_value = None subproc_mock.call_count = 0 replace_tokens_mock.call_count = 0 medusa_config_v4 = self.get_simple_medusa_config(is_ccm_active="0", yaml_file='resources/yaml/original/default-c4.yaml') cassandra_v4 = Cassandra(medusa_config_v4, release_version="4") cassandra_v4.start(['test-token']) # When start invoked with ccm active, expect both check_output and replace tokens are # invoked. assert subproc_mock.call_count == 1 and replace_tokens_mock.call_count == 1 # And, when start invoked with ccm active, expect that only check_output is called # as there is no need to replace tokens in c* yaml and disabling bootstrap. subproc_mock.call_count = 0 replace_tokens_mock.call_count = 0 medusa_config_v4 = self.get_simple_medusa_config(is_ccm_active="1", yaml_file='resources/yaml/original/default-c4.yaml') cassandra_v4 = Cassandra(medusa_config_v4, release_version="4") cassandra_v4.start(['test-token']) assert subproc_mock.call_count == 1 and replace_tokens_mock.call_count == 0
def restore_node_locally(config, temp_dir, backup_name, in_place, keep_auth, seeds, storage, keyspaces, tables): differential_blob = storage.storage_driver.get_blob( os.path.join(config.storage.fqdn, backup_name, 'meta', 'differential')) node_backup = storage.get_node_backup( fqdn=config.storage.fqdn, name=backup_name, differential_mode=True if differential_blob is not None else False) if not node_backup.exists(): logging.error('No such backup') sys.exit(1) fqtns_to_restore = get_fqtns_to_restore(keyspaces, tables, node_backup.manifest) if len(fqtns_to_restore) == 0: logging.error('There is nothing to restore') sys.exit(0) cassandra = Cassandra(config.cassandra) # Download the backup download_dir = temp_dir / 'medusa-restore-{}'.format(uuid.uuid4()) logging.info('Downloading data from backup to {}'.format(download_dir)) download_data(config.storage, node_backup, fqtns_to_restore, destination=download_dir) logging.info('Stopping Cassandra') cassandra.shutdown() # Clean the commitlogs, the saved cache to prevent any kind of conflict # especially around system tables. clean_path(cassandra.commit_logs_path) clean_path(cassandra.saved_caches_path) # move backup data to Cassandra data directory according to system table logging.info('Moving backup data to Cassandra data directory') manifest = json.loads(node_backup.manifest) for section in manifest: fqtn = "{}.{}".format(section['keyspace'], section['columnfamily']) if fqtn not in fqtns_to_restore: logging.debug('Skipping restore for {}'.format(fqtn)) continue maybe_restore_section(section, download_dir, cassandra.root, in_place, keep_auth) node_fqdn = storage.config.fqdn token_map_file = download_dir / 'tokenmap.json' with open(str(token_map_file), 'r') as f: tokens = get_node_tokens(node_fqdn, f) logging.debug("Parsed tokens: {}".format(tokens)) # possibly wait for seeds if seeds is not None: wait_for_seeds(config, seeds) else: logging.info('No --seeds specified so we will not wait for any') # Start up Cassandra logging.info('Starting Cassandra') # restoring in place retains system.local, which has tokens in it. no need to specify extra if in_place: cassandra.start_with_implicit_token() else: cassandra.start(tokens) return node_backup
def restore_node_locally(config, temp_dir, backup_name, in_place, keep_auth, seeds, storage, keyspaces, tables): storage.storage_driver.prepare_download() differential_blob = storage.storage_driver.get_blob( os.path.join(config.storage.fqdn, backup_name, 'meta', 'differential')) node_backup = storage.get_node_backup( fqdn=config.storage.fqdn, name=backup_name, differential_mode=True if differential_blob is not None else False) if not node_backup.exists(): logging.error('No such backup') sys.exit(1) fqtns_to_restore, ignored_fqtns = filter_fqtns(keyspaces, tables, node_backup.manifest) for fqtns in ignored_fqtns: logging.info('Skipping restore of {}'.format(fqtns)) if len(fqtns_to_restore) == 0: logging.error('There is nothing to restore') sys.exit(0) cassandra = Cassandra(config) # Download the backup download_dir = temp_dir / 'medusa-restore-{}'.format(uuid.uuid4()) logging.info('Downloading data from backup to {}'.format(download_dir)) download_data(config.storage, node_backup, fqtns_to_restore, destination=download_dir) if not medusa.utils.evaluate_boolean(config.kubernetes.enabled): logging.info('Stopping Cassandra') cassandra.shutdown() wait_for_node_to_go_down(config, cassandra.hostname) # Clean the commitlogs, the saved cache to prevent any kind of conflict # especially around system tables. use_sudo = not medusa.utils.evaluate_boolean(config.kubernetes.enabled) clean_path(cassandra.commit_logs_path, use_sudo, keep_folder=True) clean_path(cassandra.saved_caches_path, use_sudo, keep_folder=True) # move backup data to Cassandra data directory according to system table logging.info('Moving backup data to Cassandra data directory') manifest = json.loads(node_backup.manifest) for section in manifest: fqtn = "{}.{}".format(section['keyspace'], section['columnfamily']) if fqtn not in fqtns_to_restore: logging.debug('Skipping restore for {}'.format(fqtn)) continue maybe_restore_section(section, download_dir, cassandra.root, in_place, keep_auth, use_sudo) node_fqdn = storage.config.fqdn token_map_file = download_dir / 'tokenmap.json' with open(str(token_map_file), 'r') as f: tokens = get_node_tokens(node_fqdn, f) logging.debug("Parsed tokens: {}".format(tokens)) # possibly wait for seeds # # In a Kubernetes deployment we can assume that seed nodes will be started first. It will # handled either by the statefulset controller or by the controller of a Cassandra # operator. if not medusa.utils.evaluate_boolean(config.kubernetes.enabled): if seeds is not None: wait_for_seeds(config, seeds) else: logging.info('No --seeds specified so we will not wait for any') # Start up Cassandra logging.info('Starting Cassandra') # restoring in place retains system.local, which has tokens in it. no need to specify extra if in_place: cassandra.start_with_implicit_token() else: cassandra.start(tokens) # Clean the restored data from local temporary folder clean_path(download_dir, use_sudo, keep_folder=False) return node_backup