Add Ceph Native driver

This driver enables use of the Ceph filesystem for
Manila shares.  Clients require a native CephFS
client to access the share.  The interface
to Ceph is CephFSVolumeClient, included in
the 'Jewel' Ceph release and later.

APIImpact
The API microversion is bumped to 2.13 to add a
new access type, cephx, supported by the driver.

Co-Authored-By: Ramana Raja <rraja@redhat.com>

Implements: blueprint cephfs-driver
Change-Id: I33801215f64eacb9dade4d92f11f659173abb7f5
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 3f8c08a..c0c38bd 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -36,7 +36,7 @@
                help="The minimum api microversion is configured to be the "
                     "value of the minimum microversion supported by Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="2.12",
+               default="2.13",
                help="The maximum api microversion is configured to be the "
                     "value of the latest microversion supported by Manila."),
     cfg.StrOpt("region",
@@ -73,6 +73,9 @@
     cfg.ListOpt("enable_cert_rules_for_protocols",
                 default=["glusterfs", ],
                 help="Protocols that should be covered with cert rule tests."),
+    cfg.ListOpt("enable_cephx_rules_for_protocols",
+                default=["cephfs", ],
+                help="Protocols to be covered with cephx rule tests."),
     cfg.StrOpt("username_for_user_rules",
                default="Administrator",
                help="Username, that will be used in user tests."),
diff --git a/manila_tempest_tests/tests/api/admin/test_share_manage.py b/manila_tempest_tests/tests/api/admin/test_share_manage.py
index bbd98bc..3651564 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_manage.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_manage.py
@@ -196,3 +196,7 @@
 
 class ManageHDFSShareTest(ManageNFSShareTest):
     protocol = 'hdfs'
+
+
+class ManageCephFSShareTest(ManageNFSShareTest):
+    protocol = 'cephfs'
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 8ee5ddd..524f248 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -86,7 +86,7 @@
     """Base test case class for all Manila API tests."""
 
     force_tenant_isolation = False
-    protocols = ["nfs", "cifs", "glusterfs", "hdfs"]
+    protocols = ["nfs", "cifs", "glusterfs", "hdfs", "cephfs"]
 
     # Will be cleaned up in resource_cleanup
     class_resources = []
diff --git a/manila_tempest_tests/tests/api/test_rules.py b/manila_tempest_tests/tests/api/test_rules.py
index 0b0bc08..5fc99a2 100644
--- a/manila_tempest_tests/tests/api/test_rules.py
+++ b/manila_tempest_tests/tests/api/test_rules.py
@@ -359,6 +359,41 @@
 
 
 @ddt.ddt
+class ShareCephxRulesForCephFSTest(base.BaseSharesTest):
+    protocol = "cephfs"
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareCephxRulesForCephFSTest, cls).resource_setup()
+        if (cls.protocol not in CONF.share.enable_protocols or
+                cls.protocol not in
+                CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("Cephx rule tests for %s protocol are disabled." %
+                   cls.protocol)
+            raise cls.skipException(msg)
+        cls.share = cls.create_share(cls.protocol)
+        cls.access_type = "cephx"
+        # Provide access to a client identified by a cephx auth id.
+        cls.access_to = "bob"
+
+    @test.attr(type=["gate", ])
+    @ddt.data("alice", "alice_bob", "alice bob")
+    def test_create_delete_cephx_rule(self, access_to):
+        rule = self.shares_v2_client.create_access_rule(
+            self.share["id"], self.access_type, access_to)
+
+        self.assertEqual('rw', rule['access_level'])
+        for key in ('deleted', 'deleted_at', 'instance_mappings'):
+            self.assertNotIn(key, rule.keys())
+        self.shares_v2_client.wait_for_access_rule_status(
+            self.share["id"], rule["id"], "active")
+
+        self.shares_v2_client.delete_access_rule(self.share["id"], rule["id"])
+        self.shares_v2_client.wait_for_resource_deletion(
+            rule_id=rule["id"], share_id=self.share['id'])
+
+
+@ddt.ddt
 class ShareRulesTest(base.BaseSharesTest):
 
     @classmethod
@@ -369,6 +404,8 @@
                 any(p in CONF.share.enable_user_rules_for_protocols
                     for p in cls.protocols) or
                 any(p in CONF.share.enable_cert_rules_for_protocols
+                    for p in cls.protocols) or
+                any(p in CONF.share.enable_cephx_rules_for_protocols
                     for p in cls.protocols)):
             cls.message = "Rule tests are disabled"
             raise cls.skipException(cls.message)
@@ -384,12 +421,21 @@
             cls.protocol = CONF.share.enable_cert_rules_for_protocols[0]
             cls.access_type = "cert"
             cls.access_to = "client3.com"
+        elif CONF.share.enable_cephx_rules_for_protocols:
+            cls.protocol = CONF.share.enable_cephx_rules_for_protocols[0]
+            cls.access_type = "cephx"
+            cls.access_to = "alice"
         cls.shares_v2_client.share_protocol = cls.protocol
         cls.share = cls.create_share()
 
     @test.attr(type=["gate", ])
     @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
     def test_list_access_rules(self, version):
+        if (utils.is_microversion_lt(version, '2.13') and
+                CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("API version %s does not support cephx access type, "
+                   "need version greater than 2.13." % version)
+            raise self.skipException(msg)
 
         # create rule
         if utils.is_microversion_eq(version, '1.0'):
@@ -447,6 +493,11 @@
     @test.attr(type=["gate", ])
     @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
     def test_access_rules_deleted_if_share_deleted(self, version):
+        if (utils.is_microversion_lt(version, '2.13') and
+                CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("API version %s does not support cephx access type, "
+                   "need version greater than 2.13." % version)
+            raise self.skipException(msg)
 
         # create share
         share = self.create_share()
diff --git a/manila_tempest_tests/tests/api/test_rules_negative.py b/manila_tempest_tests/tests/api/test_rules_negative.py
index 47f5a52..8e7f620 100644
--- a/manila_tempest_tests/tests/api/test_rules_negative.py
+++ b/manila_tempest_tests/tests/api/test_rules_negative.py
@@ -19,6 +19,7 @@
 from tempest_lib import exceptions as lib_exc
 import testtools
 
+from manila_tempest_tests import share_exceptions
 from manila_tempest_tests.tests.api import base
 from manila_tempest_tests import utils
 
@@ -317,6 +318,48 @@
 
 
 @ddt.ddt
+class ShareCephxRulesForCephFSNegativeTest(base.BaseSharesTest):
+    protocol = "cephfs"
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareCephxRulesForCephFSNegativeTest, cls).resource_setup()
+        if not (cls.protocol in CONF.share.enable_protocols and
+                cls.protocol in CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("CEPHX rule tests for %s protocol are disabled" %
+                   cls.protocol)
+            raise cls.skipException(msg)
+        # create share
+        cls.share = cls.create_share(cls.protocol)
+        cls.access_type = "cephx"
+        cls.access_to = "david"
+
+    @test.attr(type=["negative", "gate", ])
+    @ddt.data('jane.doe', u"bj\u00F6rn")
+    def test_create_access_rule_cephx_with_invalid_cephx_id(self, access_to):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.create_access_rule,
+                          self.share["id"], self.access_type, access_to)
+
+    @test.attr(type=["negative", "gate", ])
+    def test_create_access_rule_cephx_with_wrong_level(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.create_access_rule,
+                          self.share["id"], self.access_type, self.access_to,
+                          access_level="su")
+
+    @test.attr(type=["negative", "gate", ])
+    def test_create_access_rule_cephx_with_unsupported_access_level_ro(self):
+        rule = self.shares_v2_client.create_access_rule(
+            self.share["id"], self.access_type, self.access_to,
+            access_level="ro")
+        self.assertRaises(
+            share_exceptions.AccessRuleBuildErrorException,
+            self.shares_client.wait_for_access_rule_status,
+            self.share['id'], rule['id'], "active")
+
+
+@ddt.ddt
 class ShareRulesNegativeTest(base.BaseSharesTest):
     # Tests independent from rule type and share protocol
 
@@ -328,6 +371,8 @@
                 any(p in CONF.share.enable_user_rules_for_protocols
                     for p in cls.protocols) or
                 any(p in CONF.share.enable_cert_rules_for_protocols
+                    for p in cls.protocols) or
+                any(p in CONF.share.enable_cephx_rules_for_protocols
                     for p in cls.protocols)):
             cls.message = "Rule tests are disabled"
             raise cls.skipException(cls.message)
@@ -337,9 +382,21 @@
             # create snapshot
             cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
 
+    def skip_if_cephx_access_type_not_supported_by_client(self, client):
+        if client == 'shares_client':
+            version = '1.0'
+        else:
+            version = LATEST_MICROVERSION
+        if (CONF.share.enable_cephx_rules_for_protocols and
+                utils.is_microversion_lt(version, '2.13')):
+            msg = ("API version %s does not support cephx access type, "
+                   "need version greater than 2.13." % version)
+            raise self.skipException(msg)
+
     @test.attr(type=["negative", "gate", ])
     @ddt.data('shares_client', 'shares_v2_client')
     def test_delete_access_rule_with_wrong_id(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.NotFound,
                           getattr(self, client_name).delete_access_rule,
                           self.share["id"], "wrong_rule_id")
@@ -347,6 +404,7 @@
     @test.attr(type=["negative", "gate", ])
     @ddt.data('shares_client', 'shares_v2_client')
     def test_create_access_rule_ip_with_wrong_type(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.BadRequest,
                           getattr(self, client_name).create_access_rule,
                           self.share["id"], "wrong_type", "1.2.3.4")
@@ -354,6 +412,7 @@
     @test.attr(type=["negative", "gate", ])
     @ddt.data('shares_client', 'shares_v2_client')
     def test_create_access_rule_ip_with_wrong_share_id(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.NotFound,
                           getattr(self, client_name).create_access_rule,
                           "wrong_share_id")
@@ -363,6 +422,7 @@
     @testtools.skipUnless(CONF.share.run_snapshot_tests,
                           "Snapshot tests are disabled.")
     def test_create_access_rule_ip_to_snapshot(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.NotFound,
                           getattr(self, client_name).create_access_rule,
                           self.snap["id"])
diff --git a/manila_tempest_tests/tests/api/test_shares.py b/manila_tempest_tests/tests/api/test_shares.py
index 46d1558..db829a1 100644
--- a/manila_tempest_tests/tests/api/test_shares.py
+++ b/manila_tempest_tests/tests/api/test_shares.py
@@ -187,3 +187,8 @@
 class SharesHDFSTest(SharesNFSTest):
     """Covers share functionality that is related to HDFS share type."""
     protocol = "hdfs"
+
+
+class SharesCephFSTest(SharesNFSTest):
+    """Covers share functionality that is related to CEPHFS share type."""
+    protocol = "cephfs"