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 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) elif not in_place: # Kubernetes will manage the lifecycle, but we still need to modify the tokens cassandra.replaceTokensInCassandraYamlAndDisableBootstrap(tokens) # Clean the restored data from local temporary folder clean_path(download_dir, use_sudo, keep_folder=False) return node_backup