|
1 | 1 | import pytest |
2 | 2 | import logging |
| 3 | +import re |
| 4 | +import time |
3 | 5 |
|
4 | 6 | from cassandra import Unauthorized |
5 | 7 | from dtest import Tester |
|
12 | 14 |
|
13 | 15 | class TestSystemKeyspaces(Tester): |
14 | 16 |
|
| 17 | + @since('3.0') |
| 18 | + def test_host_id_is_set(self): |
| 19 | + """ |
| 20 | + @jira_ticket CASSANDRA-18153 |
| 21 | +
|
| 22 | + Test that the host ID in system.local is set after startup. |
| 23 | + """ |
| 24 | + cluster = self.cluster |
| 25 | + cluster.set_configuration_options(values={'commitlog_sync_period_in_ms': 500}) |
| 26 | + cluster.populate(1).start() |
| 27 | + node = cluster.nodelist()[0] |
| 28 | + node.nodetool("disableautocompaction") |
| 29 | + |
| 30 | + session = self.patient_cql_connection(node) |
| 31 | + host_id_in_system_local = str(session.execute("SELECT host_id FROM system.local")[0].host_id) |
| 32 | + |
| 33 | + session.execute("CREATE KEYSPACE ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}") |
| 34 | + session.execute("CREATE TABLE ks.cf (k int PRIMARY KEY, v int)") |
| 35 | + node.nodetool("disableautocompaction ks cf") |
| 36 | + |
| 37 | + session.execute("INSERT INTO ks.cf (k, v) VALUES (0, 0)") |
| 38 | + node.flush() |
| 39 | + |
| 40 | + self.assert_host_id_in_all_sstables(host_id_in_system_local, node) |
| 41 | + |
| 42 | + # let's have something in the commitlog which was not flushed to sstable |
| 43 | + session.execute("INSERT INTO ks.cf (k, v) VALUES (1, 1)") |
| 44 | + |
| 45 | + # wait for the commitlog to be synced and kill the node |
| 46 | + time.sleep(2) |
| 47 | + cluster.stop(gently=False) |
| 48 | + |
| 49 | + cluster.start(wait_for_binary_proto=True) |
| 50 | + session = self.patient_cql_connection(node) |
| 51 | + assert host_id_in_system_local == str(session.execute("SELECT host_id FROM system.local")[0].host_id), "Host ID in system.local changed after restart" |
| 52 | + |
| 53 | + node.flush() |
| 54 | + self.assert_host_id_in_all_sstables(host_id_in_system_local, node) |
| 55 | + |
| 56 | + @since('3.0') |
| 57 | + def test_consistent_host_id(self): |
| 58 | + """ |
| 59 | + @jira_ticket CASSANDRA-18153 |
| 60 | +
|
| 61 | + Test that the host ID in system.local is consistent across restarts. |
| 62 | + """ |
| 63 | + cluster = self.cluster |
| 64 | + cluster.set_configuration_options(values={'commitlog_sync_period_in_ms': 500}) |
| 65 | + cluster.populate(1).start() |
| 66 | + node = cluster.nodelist()[0] |
| 67 | + |
| 68 | + session = self.patient_cql_connection(node) |
| 69 | + host_id_in_system_local = str(session.execute("SELECT host_id FROM system.local")[0].host_id) |
| 70 | + logger.info("Host ID in system.local: {}".format(host_id_in_system_local)) |
| 71 | + |
| 72 | + session.execute("CREATE KEYSPACE ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}") |
| 73 | + session.execute("CREATE TABLE ks.cf (k int PRIMARY KEY, v int)") |
| 74 | + |
| 75 | + session.execute("INSERT INTO ks.cf (k, v) VALUES (0, 0)") |
| 76 | + node.flush() |
| 77 | + |
| 78 | + # let's do something nasty - system.local is flushed without host ID |
| 79 | + session.execute("UPDATE system.local SET host_id = NULL WHERE key = 'local'") |
| 80 | + node.flush() |
| 81 | + node.compact() |
| 82 | + |
| 83 | + # let's generate some random host ID and leave it only in the commitlog |
| 84 | + random_host_id = "12345678-1234-1234-1234-123456789012" |
| 85 | + session.execute("UPDATE system.local SET host_id = {} WHERE key = 'local'".format(random_host_id)) |
| 86 | + |
| 87 | + # wait for the commitlog to be synced and kill the node |
| 88 | + time.sleep(2) |
| 89 | + cluster.stop(gently=False) |
| 90 | + |
| 91 | + cluster.start(wait_for_binary_proto=True) |
| 92 | + session = self.patient_cql_connection(node) |
| 93 | + |
| 94 | + host_id_in_system_local_after_restart = str(session.execute("SELECT host_id FROM system.local")[0].host_id) |
| 95 | + logger.info("Host ID in system.local after restart: {}".format(host_id_in_system_local_after_restart)) |
| 96 | + # now we expect that although system.local has no host ID, it wasn't generated at startup because there was something in the commitlog |
| 97 | + # eventually, we should read that new host ID from the commitlog |
| 98 | + assert host_id_in_system_local_after_restart == random_host_id, "Host ID in system.local changed after restart: {} != {}".format(host_id_in_system_local_after_restart, random_host_id) |
| 99 | + |
| 100 | + def get_host_id_from_sstable_metadata(self, node, sstable_paths): |
| 101 | + host_ids = {} |
| 102 | + for sstable_path in sstable_paths: |
| 103 | + (out, err, rc) = node.run_sstablemetadata(datafiles=[sstable_path]) |
| 104 | + assert rc == 0, "sstablemetadata failed with error: {}".format(err) |
| 105 | + # extract host id from out using "Originating host id: (\\S*)" regex |
| 106 | + host_id = re.search("Originating host id: (\\S*)", out) |
| 107 | + if host_id is None: |
| 108 | + logger.info("Could not find host ID in sstablemetadata output: {}".format(out)) |
| 109 | + else: |
| 110 | + if sstable_path in host_ids: |
| 111 | + logger.info("Duplicate sstable path: {}".format(sstable_path)) |
| 112 | + host_ids[sstable_path] = host_id.group(1) |
| 113 | + |
| 114 | + return host_ids |
| 115 | + |
| 116 | + def assert_host_id_in_all_sstables(self, expected_host_id, node): |
| 117 | + keyspaces = node.list_keyspaces() |
| 118 | + # we need to explicitly add local system keyspace to the list |
| 119 | + keyspaces.append("system") |
| 120 | + |
| 121 | + sstable_paths = [] |
| 122 | + for keyspace in keyspaces: |
| 123 | + sstable_paths.extend(node.get_sstables(keyspace, "")) |
| 124 | + |
| 125 | + host_ids = self.get_host_id_from_sstable_metadata(node, sstable_paths) |
| 126 | + assert len(host_ids) == len(sstable_paths), "Expected to find host ID in all sstables: {} != {}".format( |
| 127 | + len(host_ids), len(sstable_paths)) |
| 128 | + |
| 129 | + # assert that host IDs in system.local and sstables are the same |
| 130 | + for sstable_path in sstable_paths: |
| 131 | + assert expected_host_id == host_ids[sstable_path], \ |
| 132 | + "Host ID in system.local and sstable {} are different: {} != {}".format(sstable_path, |
| 133 | + expected_host_id, |
| 134 | + host_ids[sstable_path]) |
| 135 | + |
15 | 136 | @since('3.0') |
16 | 137 | def test_local_system_keyspaces(self): |
17 | 138 | cluster = self.cluster |
|
0 commit comments