]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/smb: add a cluster resource field to manage clustering
authorJohn Mulligan <jmulligan@redhat.com>
Mon, 15 Jul 2024 19:41:43 +0000 (15:41 -0400)
committerJohn Mulligan <jmulligan@redhat.com>
Tue, 20 Aug 2024 13:53:57 +0000 (09:53 -0400)
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 <jmulligan@redhat.com>
src/pybind/mgr/smb/enums.py
src/pybind/mgr/smb/module.py
src/pybind/mgr/smb/resources.py
src/pybind/mgr/smb/tests/test_handler.py
src/pybind/mgr/smb/tests/test_smb.py

index 175af98d49938202477703191e27f694c61d53ba..f362219221be55a01fe5334fb9d076e15f769f0c 100644 (file)
@@ -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'
index 2ade91d2278f4b09960d9f7c3b2f7eb07f2af677..91069c07d573f18b3e7509007ec8ac3a848fce3e 100644 (file)
@@ -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)
index 7ef25f4f0a22e7e2807377ffc4823878d62c129f..3f74ed04f2768565b111572353ec97e76dacb0bd 100644 (file)
@@ -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):
index 5cfafe93f135f8d9d390c2d9ecfb3af48085adde..ec9b6669d13a66594e67ccc30e62127b382b258d 100644 (file)
@@ -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',
index 3375e304913f32b3b4da8edec020e17036d7e2e0..547e6c712bce4c4f084b0ac21b558dcf0c12e347 100644 (file)
@@ -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()
     )