From: John Mulligan Date: Mon, 15 Jul 2024 19:41:43 +0000 (-0400) Subject: mgr/smb: add a cluster resource field to manage clustering X-Git-Tag: v20.0.0~1223^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4ef7a48e55910830725e1bf7b7fcbeda5e89b74d;p=ceph.git mgr/smb: add a cluster resource field to manage clustering Add a new `clustering` field to the smb cluster resource. This field can be used to select either automatic clustering with ctdb, or disable it, or require it. The default is automatic and is based on the count value in the placement spec. A count of 1 disables clustering and any other value it is enabled. Signed-off-by: John Mulligan --- diff --git a/src/pybind/mgr/smb/enums.py b/src/pybind/mgr/smb/enums.py index 175af98d4993..f362219221be 100644 --- a/src/pybind/mgr/smb/enums.py +++ b/src/pybind/mgr/smb/enums.py @@ -77,3 +77,9 @@ class LoginAccess(_StrEnum): if self == self.READ_WRITE_SHORT: return LoginAccess(self.READ_WRITE) return self + + +class SMBClustering(_StrEnum): + DEFAULT = 'default' + ALWAYS = 'always' + NEVER = 'never' diff --git a/src/pybind/mgr/smb/module.py b/src/pybind/mgr/smb/module.py index 2ade91d2278f..91069c07d573 100644 --- a/src/pybind/mgr/smb/module.py +++ b/src/pybind/mgr/smb/module.py @@ -17,7 +17,12 @@ from . import ( sqlite_store, utils, ) -from .enums import AuthMode, JoinSourceType, UserGroupSourceType +from .enums import ( + AuthMode, + JoinSourceType, + SMBClustering, + UserGroupSourceType, +) from .proto import AccessAuthorizer, ConfigStore, Simplified if TYPE_CHECKING: @@ -151,6 +156,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): define_user_pass: Optional[List[str]] = None, custom_dns: Optional[List[str]] = None, placement: Optional[str] = None, + clustering: Optional[SMBClustering] = None, ) -> results.Result: """Create an smb cluster""" domain_settings = None @@ -245,6 +251,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): user_group_settings=user_group_settings, custom_dns=custom_dns, placement=pspec, + clustering=clustering, ) to_apply.append(cluster) return self._handler.apply(to_apply, create_only=True).squash(cluster) diff --git a/src/pybind/mgr/smb/resources.py b/src/pybind/mgr/smb/resources.py index 7ef25f4f0a22..3f74ed04f276 100644 --- a/src/pybind/mgr/smb/resources.py +++ b/src/pybind/mgr/smb/resources.py @@ -16,6 +16,7 @@ from .enums import ( JoinSourceType, LoginAccess, LoginCategory, + SMBClustering, UserGroupSourceType, ) from .proto import Self, Simplified @@ -358,6 +359,8 @@ class Cluster(_RBase): custom_smb_global_options: Optional[Dict[str, str]] = None # embedded orchestration placement spec placement: Optional[WrappedPlacementSpec] = None + # control if the cluster is really a cluster + clustering: Optional[SMBClustering] = None def validate(self) -> None: if not self.cluster_id: @@ -395,6 +398,23 @@ class Cluster(_RBase): def cleaned_custom_smb_global_options(self) -> Optional[Dict[str, str]]: return validation.clean_custom_options(self.custom_smb_global_options) + @property + def clustering_mode(self) -> SMBClustering: + return self.clustering if self.clustering else SMBClustering.DEFAULT + + def is_clustered(self) -> bool: + """Return true if smbd instance should use (CTDB) clustering.""" + if self.clustering_mode == SMBClustering.ALWAYS: + return True + if self.clustering_mode == SMBClustering.NEVER: + return False + # do clustering automatically, based on the placement spec's count value + count = 0 + if self.placement and self.placement.count: + count = self.placement.count + # clustering enabled unless we're deploying a single instance "cluster" + return count != 1 + @resourcelib.resource('ceph.smb.join.auth') class JoinAuth(_RBase): diff --git a/src/pybind/mgr/smb/tests/test_handler.py b/src/pybind/mgr/smb/tests/test_handler.py index 5cfafe93f135..ec9b6669d13a 100644 --- a/src/pybind/mgr/smb/tests/test_handler.py +++ b/src/pybind/mgr/smb/tests/test_handler.py @@ -3,6 +3,12 @@ import pytest import smb +def _cluster(**kwargs): + if 'clustering' not in kwargs: + kwargs['clustering'] = smb.enums.SMBClustering.NEVER + return smb.resources.Cluster(**kwargs) + + @pytest.fixture def thandler(): ext_store = smb.config_store.MemConfigStore() @@ -26,7 +32,7 @@ def test_shares_empty(thandler): def test_internal_apply_cluster(thandler): - cluster = smb.resources.Cluster( + cluster = _cluster( cluster_id='foo', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -41,7 +47,7 @@ def test_internal_apply_cluster(thandler): def test_cluster_add(thandler): - cluster = smb.resources.Cluster( + cluster = _cluster( cluster_id='foo', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -59,7 +65,7 @@ def test_cluster_add(thandler): def test_internal_apply_cluster_and_share(thandler): - cluster = smb.resources.Cluster( + cluster = _cluster( cluster_id='foo', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -95,6 +101,7 @@ def test_internal_apply_remove_cluster(thandler): 'cluster_id': 'foo', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'empty', @@ -126,6 +133,7 @@ def test_internal_apply_remove_shares(thandler): 'cluster_id': 'foo', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'empty', @@ -206,6 +214,7 @@ def test_internal_apply_add_joinauth(thandler): 'cluster_id': 'foo', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'empty', @@ -237,6 +246,7 @@ def test_internal_apply_add_usergroups(thandler): 'cluster_id': 'foo', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'empty', @@ -583,7 +593,7 @@ def test_apply_full_cluster_create(thandler): password='Passw0rd', ), ), - smb.resources.Cluster( + _cluster( cluster_id='mycluster1', auth_mode=smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_settings=smb.resources.DomainSettings( @@ -708,7 +718,7 @@ def test_apply_update_password(thandler): def test_apply_add_second_cluster(thandler): test_apply_full_cluster_create(thandler) to_apply = [ - smb.resources.Cluster( + _cluster( cluster_id='coolcluster', auth_mode=smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_settings=smb.resources.DomainSettings( @@ -880,7 +890,7 @@ def test_apply_remove_all_clusters(thandler): groups=[], ), ), - smb.resources.Cluster( + _cluster( cluster_id='mycluster2', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -890,7 +900,7 @@ def test_apply_remove_all_clusters(thandler): ), ], ), - smb.resources.Cluster( + _cluster( cluster_id='mycluster3', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -1166,7 +1176,7 @@ def test_apply_cluster_linked_auth(thandler): ), linked_to_cluster='mycluster1', ), - smb.resources.Cluster( + _cluster( cluster_id='mycluster1', auth_mode=smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_settings=smb.resources.DomainSettings( @@ -1228,7 +1238,7 @@ def test_apply_cluster_bad_linked_auth(thandler): ), linked_to_cluster='mycluster2', ), - smb.resources.Cluster( + _cluster( cluster_id='mycluster1', auth_mode=smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_settings=smb.resources.DomainSettings( @@ -1261,7 +1271,7 @@ def test_apply_cluster_bad_linked_ug(thandler): ), linked_to_cluster='mycluster2', ), - smb.resources.Cluster( + _cluster( cluster_id='mycluster1', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -1287,7 +1297,7 @@ def test_apply_with_create_only(thandler): test_apply_full_cluster_create(thandler) to_apply = [ - smb.resources.Cluster( + _cluster( cluster_id='mycluster1', auth_mode=smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_settings=smb.resources.DomainSettings( @@ -1635,6 +1645,7 @@ def test_share_name_in_use(thandler, params): 'cluster_id': 'c1', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'resource', @@ -1647,6 +1658,7 @@ def test_share_name_in_use(thandler, params): 'cluster_id': 'c2', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'resource', diff --git a/src/pybind/mgr/smb/tests/test_smb.py b/src/pybind/mgr/smb/tests/test_smb.py index 3375e304913f..547e6c712bce 100644 --- a/src/pybind/mgr/smb/tests/test_smb.py +++ b/src/pybind/mgr/smb/tests/test_smb.py @@ -5,6 +5,12 @@ import pytest import smb +def _cluster(**kwargs): + if 'clustering' not in kwargs: + kwargs['clustering'] = smb.enums.SMBClustering.NEVER + return smb.resources.Cluster(**kwargs) + + @pytest.fixture def tmodule(): internal_store = smb.config_store.MemConfigStore() @@ -34,7 +40,7 @@ def test_share_ls_empty(tmodule): def test_internal_apply_cluster(tmodule): - cluster = smb.resources.Cluster( + cluster = _cluster( cluster_id='foo', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -49,7 +55,7 @@ def test_internal_apply_cluster(tmodule): def test_cluster_add_cluster_ls(tmodule): - cluster = smb.resources.Cluster( + cluster = _cluster( cluster_id='foo', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -67,7 +73,7 @@ def test_cluster_add_cluster_ls(tmodule): def test_internal_apply_cluster_and_share(tmodule): - cluster = smb.resources.Cluster( + cluster = _cluster( cluster_id='foo', auth_mode=smb.enums.AuthMode.USER, user_group_settings=[ @@ -134,6 +140,7 @@ def test_internal_apply_remove_shares(tmodule): 'cluster_id': 'foo', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'empty', @@ -214,6 +221,7 @@ def test_internal_apply_add_joinauth(tmodule): 'cluster_id': 'foo', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'empty', @@ -245,6 +253,7 @@ def test_internal_apply_add_usergroups(tmodule): 'cluster_id': 'foo', 'auth_mode': 'user', 'intent': 'present', + 'clustering': 'never', 'user_group_settings': [ { 'source_type': 'empty', @@ -276,6 +285,7 @@ def _example_cfg_1(tmodule): 'cluster_id': 'foo', 'auth_mode': 'active-directory', 'intent': 'present', + 'clustering': 'never', 'domain_settings': { 'realm': 'dom1.example.com', 'join_sources': [ @@ -473,6 +483,7 @@ def test_cluster_create_ad1(tmodule): smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_realm='fizzle.example.net', domain_join_user_pass=['Administrator%Passw0rd'], + clustering='never', ) assert result.success assert result.status['state'] == 'created' @@ -519,6 +530,7 @@ def test_cluster_create_ad2(tmodule): smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_realm='sizzle.example.net', domain_join_ref=['jaad2'], + clustering='never', ) assert result.success assert result.status['state'] == 'created' @@ -549,6 +561,7 @@ def test_cluster_create_user1(tmodule): 'dizzle', smb.enums.AuthMode.USER, user_group_ref=['ug1'], + clustering='never', ) assert result.success assert result.status['state'] == 'created' @@ -563,6 +576,7 @@ def test_cluster_create_user2(tmodule): 'dizzle', smb.enums.AuthMode.USER, define_user_pass=['alice%123letmein', 'bob%1n0wh4t1t15'], + clustering='never', ) assert result.success assert result.status['state'] == 'created' @@ -583,6 +597,7 @@ def test_cluster_create_badpass(tmodule): smb.enums.AuthMode.ACTIVE_DIRECTORY, domain_realm='fizzle.example.net', domain_join_user_pass=['Administrator'], + clustering='never', ) @@ -641,7 +656,8 @@ def test_cmd_show_resource_json(tmodule): "ref": "foo" } ] - } + }, + "clustering": "never" } """.strip() ) @@ -666,6 +682,7 @@ domain_settings: join_sources: - source_type: resource ref: foo +clustering: never """.strip() )