From 6c1a1804664c13513511e6737c6f6df0c160a62c Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Fri, 11 Oct 2024 02:07:45 +0200 Subject: [PATCH 1/2] cluster: mark leadership pinning as an enterprise feature Leadership pinning is considered enabled if the user changes the default leaders_preference or redpanda.leaders.preference for one of the topics. --- src/v/cluster/controller.cc | 1 + src/v/cluster/feature_manager.cc | 17 +++++++++++++++++ src/v/cluster/feature_manager.h | 2 ++ src/v/features/enterprise_features.cc | 2 ++ src/v/features/enterprise_features.h | 1 + 5 files changed, 23 insertions(+) diff --git a/src/v/cluster/controller.cc b/src/v/cluster/controller.cc index 3c727cc304184..c3a351ac0a03b 100644 --- a/src/v/cluster/controller.cc +++ b/src/v/cluster/controller.cc @@ -625,6 +625,7 @@ ss::future<> controller::start( std::ref(_feature_table), std::ref(_connections), std::ref(_roles), + std::ref(_tp_state), _raft0->group()); co_await _health_manager.start_single( diff --git a/src/v/cluster/feature_manager.cc b/src/v/cluster/feature_manager.cc index b67c0be7cdae1..ad43fe5ddf72f 100644 --- a/src/v/cluster/feature_manager.cc +++ b/src/v/cluster/feature_manager.cc @@ -52,6 +52,7 @@ feature_manager::feature_manager( ss::sharded& table, ss::sharded& connection_cache, ss::sharded& role_store, + ss::sharded& topic_table, raft::group_id raft0_group) : _stm(stm) , _as(as) @@ -62,6 +63,7 @@ feature_manager::feature_manager( , _feature_table(table) , _connection_cache(connection_cache) , _role_store(role_store) + , _topic_table(topic_table) , _raft0_group(raft0_group) , _barrier_state( *config::node().node_id(), @@ -225,6 +227,18 @@ feature_manager::report_enterprise_features() const { auto has_non_default_roles = n_roles >= 2 || (n_roles == 1 && !_role_store.local().contains(security::default_role)); + auto leadership_pinning_enabled = [&cfg, this]() { + if (cfg.default_leaders_preference() != config::leaders_preference{}) { + return true; + } + for (const auto& topic : _topic_table.local().topics_map()) { + if (topic.second.get_configuration() + .properties.leaders_preference) { + return true; + } + } + return false; + }; features::enterprise_feature_report report; report.set( @@ -249,6 +263,9 @@ feature_manager::report_enterprise_features() const { report.set( features::license_required_feature::datalake_iceberg, cfg.iceberg_enabled()); + report.set( + features::license_required_feature::leadership_pinning, + leadership_pinning_enabled()); return report; } diff --git a/src/v/cluster/feature_manager.h b/src/v/cluster/feature_manager.h index 0a188f9e752d7..c2a4deea6e4ef 100644 --- a/src/v/cluster/feature_manager.h +++ b/src/v/cluster/feature_manager.h @@ -67,6 +67,7 @@ class feature_manager { ss::sharded& table, ss::sharded& connection_cache, ss::sharded& role_store, + ss::sharded&, raft::group_id raft0_group); /** @@ -165,6 +166,7 @@ class feature_manager { ss::sharded& _feature_table; ss::sharded& _connection_cache; ss::sharded& _role_store; + ss::sharded& _topic_table; raft::group_id _raft0_group; version_map _updates; diff --git a/src/v/features/enterprise_features.cc b/src/v/features/enterprise_features.cc index 82e81957a408f..5b2ff2f6397a6 100644 --- a/src/v/features/enterprise_features.cc +++ b/src/v/features/enterprise_features.cc @@ -39,6 +39,8 @@ std::ostream& operator<<(std::ostream& os, license_required_feature f) { return os << "fips"; case license_required_feature::datalake_iceberg: return os << "datalake_iceberg"; + case license_required_feature::leadership_pinning: + return os << "leadership_pinning"; } __builtin_unreachable(); } diff --git a/src/v/features/enterprise_features.h b/src/v/features/enterprise_features.h index 048f4a35af6d6..b869c23090a9c 100644 --- a/src/v/features/enterprise_features.h +++ b/src/v/features/enterprise_features.h @@ -29,6 +29,7 @@ enum class license_required_feature { rbac, fips, datalake_iceberg, + leadership_pinning, }; std::ostream& operator<<(std::ostream&, license_required_feature); From 6c4ecab570f9463fdd24d8ba4f58bedf5006a9f0 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Fri, 11 Oct 2024 02:09:54 +0200 Subject: [PATCH 2/2] tests: add license check test case for leadership pinning --- tests/rptest/tests/enterprise_features_license_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/rptest/tests/enterprise_features_license_test.py b/tests/rptest/tests/enterprise_features_license_test.py index 39e4f279d3130..eef8d4cade24e 100644 --- a/tests/rptest/tests/enterprise_features_license_test.py +++ b/tests/rptest/tests/enterprise_features_license_test.py @@ -3,6 +3,7 @@ from enum import IntEnum from rptest.utils.rpenv import sample_license +from rptest.clients.rpk import RpkTool from rptest.services.admin import Admin, EnterpriseLicenseStatus, RolesList, RoleDescription from rptest.services.redpanda import RESTART_LOG_ALLOW_LIST, SecurityConfig, SchemaRegistryConfig from rptest.tests.redpanda_test import RedpandaTest @@ -38,6 +39,7 @@ class Features(IntEnum): rbac = 7 fips = 8 datalake_iceberg = 9 + leadership_pinning = 10 SKIP_FEATURES = [ @@ -191,6 +193,12 @@ def has_role(r: str): elif feature == Features.datalake_iceberg: self.redpanda.set_cluster_config({'iceberg_enabled': 'true'}, expect_restart=True) + elif feature == Features.leadership_pinning: + RpkTool(self.redpanda).create_topic( + "foo", + partitions=1, + replicas=1, + config={"redpanda.leaders.preference": "racks:rack1"}) else: assert False, f"Unexpected feature={feature}"