Skip to content

Commit

Permalink
cluster: upgrade to v.7 creates cluster_uuid
Browse files Browse the repository at this point in the history
New feature `seeds_driven_bootstrap_capable` to control cluster upgrade.
Raft0 leader issues `bootstrap_cluster_cmd` if controller log is
non-empty and no cluster_uuid. This is done in a detached fiber
waiting on the new feature to be enabled.
  • Loading branch information
dlex committed Nov 3, 2022
1 parent 2c856ac commit 1f01d0c
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 6 deletions.
34 changes: 28 additions & 6 deletions src/v/cluster/controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,11 @@ ss::future<> controller::create_cluster() {
}
}

bool controller::controller_log_exists() const {
return _raft0->last_visible_index() > model::offset{}
|| _raft0->config().brokers().size() > 1;
}

/**
* This function provides for writing the controller log immediately
* after it has been created, before anything else has been written
Expand All @@ -537,10 +542,29 @@ ss::future<> controller::cluster_creation_hook(cluster_discovery& discovery) {
vassert(
config::node().seed_servers().empty(), "We are not on the root node");

if (
_raft0->last_visible_index() > model::offset{}
|| _raft0->config().brokers().size() > 1) {
if (controller_log_exists()) {
// The controller log has already been written to
if (!_storage.local().get_cluster_uuid()) { // HERE: ctrllog done?
// No cluster UUID - we are upgrading an existing cluster
vlog(
clusterlog.info,
"Cluster will be upgraded once all nodes are upgraded");
ssx::background
= _feature_table.local()
.await_feature(
features::feature::seeds_driven_bootstrap_capable,
_as.local())
.then([this] { return create_cluster(); })
.then([] {
vlog(clusterlog.info, "Cluster has been upgraded");
})
.handle_exception([](const std::exception_ptr e) {
vlog(
clusterlog.warn,
"Error upgrading the cluster. {}",
e);
});
}
co_return;
}

Expand Down Expand Up @@ -572,9 +596,7 @@ ss::future<> controller::cluster_creation_hook(cluster_discovery& discovery) {
co_return;
}

if (
_raft0->last_visible_index() > model::offset{}
|| _raft0->config().brokers().size() > 1) {
if (controller_log_exists()) {
// The controller log has already been written to
// TODO: create_cluster() but use the metrics' cluster_id
}
Expand Down
2 changes: 2 additions & 0 deletions src/v/cluster/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ class controller {
*/
ss::future<> create_cluster();

bool controller_log_exists() const;

ss::future<> cluster_creation_hook(cluster_discovery& discovery);

config_manager::preload_result _config_preload;
Expand Down
2 changes: 2 additions & 0 deletions src/v/features/feature_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ std::string_view to_string_view(feature f) {
return "replication_factor_change";
case feature::ephemeral_secrets:
return "ephemeral_secrets";
case feature::seeds_driven_bootstrap_capable:
return "seeds_driven_bootstrap_capable";
case feature::test_alpha:
return "__test_alpha";
}
Expand Down
7 changes: 7 additions & 0 deletions src/v/features/feature_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ enum class feature : std::uint64_t {
node_id_assignment = 0x1000,
replication_factor_change = 0x2000,
ephemeral_secrets = 0x4000,
seeds_driven_bootstrap_capable = 0x8000,

// Dummy features for testing only
test_alpha = uint64_t(1) << 63,
Expand Down Expand Up @@ -188,6 +189,12 @@ constexpr static std::array feature_schema{
feature::ephemeral_secrets,
feature_spec::available_policy::always,
feature_spec::prepare_policy::always},
feature_spec{