ceph_helm_installer.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. Copyright 2021 The Rook Authors. All rights reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package installer
  14. import (
  15. "context"
  16. "fmt"
  17. "time"
  18. "github.com/pkg/errors"
  19. "github.com/stretchr/testify/assert"
  20. "gopkg.in/yaml.v2"
  21. kerrors "k8s.io/apimachinery/pkg/api/errors"
  22. v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. )
  24. const (
  25. OperatorChartName = "rook-ceph"
  26. CephClusterChartName = "rook-ceph-cluster"
  27. )
  28. // The Ceph Storage CustomResource and StorageClass names used in testing
  29. const (
  30. BlockPoolName = "ceph-block-test"
  31. BlockPoolSCName = "ceph-block-test-sc"
  32. FilesystemName = "ceph-filesystem-test"
  33. FilesystemSCName = "ceph-filesystem-test-sc"
  34. ObjectStoreName = "ceph-objectstore-test"
  35. ObjectStoreSCName = "ceph-bucket-test-sc"
  36. )
  37. // CreateRookOperatorViaHelm creates rook operator via Helm chart named local/rook present in local repo
  38. func (h *CephInstaller) CreateRookOperatorViaHelm() error {
  39. return h.configureRookOperatorViaHelm(false)
  40. }
  41. func (h *CephInstaller) UpgradeRookOperatorViaHelm() error {
  42. return h.configureRookOperatorViaHelm(true)
  43. }
  44. func (h *CephInstaller) configureRookOperatorViaHelm(upgrade bool) error {
  45. values := map[string]interface{}{
  46. "enableDiscoveryDaemon": h.settings.EnableDiscovery,
  47. "image": map[string]interface{}{"tag": h.settings.RookVersion},
  48. "monitoring": map[string]interface{}{"enabled": true},
  49. }
  50. values["csi"] = map[string]interface{}{
  51. "csiRBDProvisionerResource": nil,
  52. "csiRBDPluginResource": nil,
  53. "csiCephFSProvisionerResource": nil,
  54. "csiCephFSPluginResource": nil,
  55. }
  56. // create the operator namespace
  57. if err := h.k8shelper.CreateNamespace(h.settings.OperatorNamespace); err != nil {
  58. return errors.Errorf("failed to create namespace %s. %v", h.settings.Namespace, err)
  59. }
  60. if h.settings.RookVersion == LocalBuildTag {
  61. if err := h.helmHelper.InstallLocalHelmChart(upgrade, h.settings.OperatorNamespace, OperatorChartName, values); err != nil {
  62. return errors.Errorf("failed to install rook operator via helm, err : %v", err)
  63. }
  64. } else {
  65. // Install a specific version of the chart, from which the test will upgrade later
  66. if err := h.helmHelper.InstallVersionedChart(h.settings.OperatorNamespace, OperatorChartName, h.settings.RookVersion, values); err != nil {
  67. return errors.Errorf("failed to install rook operator via helm, err : %v", err)
  68. }
  69. }
  70. return nil
  71. }
  72. // CreateRookCephClusterViaHelm creates rook cluster via Helm
  73. func (h *CephInstaller) CreateRookCephClusterViaHelm() error {
  74. return h.configureRookCephClusterViaHelm(false)
  75. }
  76. func (h *CephInstaller) UpgradeRookCephClusterViaHelm() error {
  77. return h.configureRookCephClusterViaHelm(true)
  78. }
  79. func (h *CephInstaller) configureRookCephClusterViaHelm(upgrade bool) error {
  80. values := map[string]interface{}{
  81. "image": "rook/ceph:" + h.settings.RookVersion,
  82. }
  83. // Set the host path the first time, but use the same path for an upgrade
  84. if h.settings.DataDirHostPath == "" {
  85. var err error
  86. h.settings.DataDirHostPath, err = h.initTestDir(h.settings.Namespace)
  87. if err != nil {
  88. return err
  89. }
  90. }
  91. var clusterCRD map[string]interface{}
  92. if err := yaml.Unmarshal([]byte(h.Manifests.GetCephCluster()), &clusterCRD); err != nil {
  93. return err
  94. }
  95. values["cephClusterSpec"] = clusterCRD["spec"]
  96. values["operatorNamespace"] = h.settings.OperatorNamespace
  97. values["configOverride"] = clusterCustomSettings
  98. values["toolbox"] = map[string]interface{}{
  99. "enabled": true,
  100. "resources": nil,
  101. }
  102. values["monitoring"] = map[string]interface{}{
  103. "enabled": true,
  104. "createPrometheusRules": true,
  105. }
  106. values["ingress"] = map[string]interface{}{
  107. "dashboard": map[string]interface{}{
  108. "annotations": map[string]interface{}{
  109. "kubernetes.io/ingress-class": "nginx",
  110. "nginx.ingress.kubernetes.io/rewrite-target": "/ceph-dashboard/$2",
  111. },
  112. "host": map[string]interface{}{
  113. "name": "localhost",
  114. "path": "/ceph-dashboard(/|$)(.*)",
  115. },
  116. },
  117. }
  118. if err := h.CreateBlockPoolConfiguration(values, BlockPoolName, BlockPoolSCName); err != nil {
  119. return err
  120. }
  121. if err := h.CreateFileSystemConfiguration(values, FilesystemName, FilesystemSCName); err != nil {
  122. return err
  123. }
  124. if err := h.CreateObjectStoreConfiguration(values, ObjectStoreName, ObjectStoreSCName); err != nil {
  125. return err
  126. }
  127. logger.Infof("Creating ceph cluster using Helm with values: %+v", values)
  128. if h.settings.RookVersion == LocalBuildTag {
  129. if err := h.helmHelper.InstallLocalHelmChart(upgrade, h.settings.Namespace, CephClusterChartName, values); err != nil {
  130. return err
  131. }
  132. } else {
  133. // Install official version of the chart
  134. if err := h.helmHelper.InstallVersionedChart(h.settings.Namespace, CephClusterChartName, h.settings.RookVersion, values); err != nil {
  135. return err
  136. }
  137. }
  138. return nil
  139. }
  140. // removeCephClusterHelmResources tidies up the helm created CRs and Storage Classes, as they interfere with other tests.
  141. func (h *CephInstaller) removeCephClusterHelmResources() {
  142. if err := h.k8shelper.Clientset.StorageV1().StorageClasses().Delete(context.TODO(), BlockPoolSCName, v1.DeleteOptions{}); err != nil {
  143. assert.True(h.T(), kerrors.IsNotFound(err))
  144. }
  145. if err := h.k8shelper.Clientset.StorageV1().StorageClasses().Delete(context.TODO(), FilesystemSCName, v1.DeleteOptions{}); err != nil {
  146. assert.True(h.T(), kerrors.IsNotFound(err))
  147. }
  148. if err := h.k8shelper.Clientset.StorageV1().StorageClasses().Delete(context.TODO(), ObjectStoreSCName, v1.DeleteOptions{}); err != nil {
  149. assert.True(h.T(), kerrors.IsNotFound(err))
  150. }
  151. if err := h.k8shelper.RookClientset.CephV1().CephBlockPools(h.settings.Namespace).Delete(context.TODO(), BlockPoolName, v1.DeleteOptions{}); err != nil {
  152. assert.True(h.T(), kerrors.IsNotFound(err))
  153. }
  154. if err := h.k8shelper.RookClientset.CephV1().CephFilesystemSubVolumeGroups(h.settings.Namespace).Delete(context.TODO(), FilesystemName+"-csi", v1.DeleteOptions{}); err != nil {
  155. assert.True(h.T(), kerrors.IsNotFound(err))
  156. }
  157. if err := h.k8shelper.RookClientset.CephV1().CephFilesystems(h.settings.Namespace).Delete(context.TODO(), FilesystemName, v1.DeleteOptions{}); err != nil {
  158. assert.True(h.T(), kerrors.IsNotFound(err))
  159. }
  160. if err := h.k8shelper.RookClientset.CephV1().CephObjectStores(h.settings.Namespace).Delete(context.TODO(), ObjectStoreName, v1.DeleteOptions{}); err != nil {
  161. assert.True(h.T(), kerrors.IsNotFound(err))
  162. }
  163. if !h.k8shelper.WaitUntilPodWithLabelDeleted(fmt.Sprintf("rook_object_store=%s", ObjectStoreName), h.settings.Namespace) {
  164. assert.Fail(h.T(), "rgw did not stop via helm uninstall")
  165. }
  166. }
  167. // ConfirmHelmClusterInstalledCorrectly runs some validation to check whether the helm chart installed correctly.
  168. func (h *CephInstaller) ConfirmHelmClusterInstalledCorrectly() error {
  169. storageClassList, err := h.k8shelper.Clientset.StorageV1().StorageClasses().List(context.TODO(), v1.ListOptions{})
  170. if err != nil {
  171. return err
  172. }
  173. foundStorageClasses := 0
  174. for _, storageClass := range storageClassList.Items {
  175. if storageClass.Name == BlockPoolSCName {
  176. foundStorageClasses++
  177. } else if storageClass.Name == FilesystemSCName {
  178. foundStorageClasses++
  179. } else if storageClass.Name == ObjectStoreSCName {
  180. foundStorageClasses++
  181. }
  182. }
  183. if foundStorageClasses != 3 {
  184. return fmt.Errorf("did not find the three storage classes which should have been deployed")
  185. }
  186. // check that ObjectStore is created
  187. logger.Infof("Check that RGW pods are Running")
  188. for i := 0; i < 24 && !h.k8shelper.CheckPodCountAndState("rook-ceph-rgw", h.settings.Namespace, 2, "Running"); i++ {
  189. logger.Infof("(%d) RGW pod check sleeping for 5 seconds ...", i)
  190. time.Sleep(5 * time.Second)
  191. }
  192. if !h.k8shelper.CheckPodCountAndState("rook-ceph-rgw", h.settings.Namespace, 2, "Running") {
  193. return fmt.Errorf("did not find the rados gateway pod, which should have been deployed")
  194. }
  195. return nil
  196. }
  197. // CreateBlockPoolConfiguration creates a block store configuration
  198. func (h *CephInstaller) CreateBlockPoolConfiguration(values map[string]interface{}, name, scName string) error {
  199. testBlockPoolBytes := []byte(h.Manifests.GetBlockPool("testPool", "1"))
  200. var testBlockPoolCRD map[string]interface{}
  201. if err := yaml.Unmarshal(testBlockPoolBytes, &testBlockPoolCRD); err != nil {
  202. return err
  203. }
  204. storageClassBytes := []byte(h.Manifests.GetBlockStorageClass(name, scName, "Delete"))
  205. var testBlockSC map[string]interface{}
  206. if err := yaml.Unmarshal(storageClassBytes, &testBlockSC); err != nil {
  207. return err
  208. }
  209. values["cephBlockPools"] = []map[string]interface{}{
  210. {
  211. "name": name,
  212. "spec": testBlockPoolCRD["spec"],
  213. "storageClass": map[string]interface{}{
  214. "enabled": true,
  215. "isDefault": true,
  216. "name": scName,
  217. "parameters": testBlockSC["parameters"],
  218. "reclaimPolicy": "Delete",
  219. "allowVolumeExpansion": true,
  220. },
  221. },
  222. }
  223. return nil
  224. }
  225. // CreateFileSystemConfiguration creates a filesystem configuration
  226. func (h *CephInstaller) CreateFileSystemConfiguration(values map[string]interface{}, name, scName string) error {
  227. testFilesystemBytes := []byte(h.Manifests.GetFilesystem("testFilesystem", 1))
  228. var testFilesystemCRD map[string]interface{}
  229. if err := yaml.Unmarshal(testFilesystemBytes, &testFilesystemCRD); err != nil {
  230. return err
  231. }
  232. storageClassBytes := []byte(h.Manifests.GetFileStorageClass(name, scName))
  233. var testFileSystemSC map[string]interface{}
  234. if err := yaml.Unmarshal(storageClassBytes, &testFileSystemSC); err != nil {
  235. return err
  236. }
  237. values["cephFileSystems"] = []map[string]interface{}{
  238. {
  239. "name": name,
  240. "spec": testFilesystemCRD["spec"],
  241. "storageClass": map[string]interface{}{
  242. "enabled": true,
  243. "name": scName,
  244. "parameters": testFileSystemSC["parameters"],
  245. "reclaimPolicy": "Delete",
  246. },
  247. },
  248. }
  249. return nil
  250. }
  251. // CreateObjectStoreConfiguration creates an object store configuration
  252. func (h *CephInstaller) CreateObjectStoreConfiguration(values map[string]interface{}, name, scName string) error {
  253. testObjectStoreBytes := []byte(h.Manifests.GetObjectStore(name, 2, 8080, false))
  254. var testObjectStoreCRD map[string]interface{}
  255. if err := yaml.Unmarshal(testObjectStoreBytes, &testObjectStoreCRD); err != nil {
  256. return err
  257. }
  258. storageClassBytes := []byte(h.Manifests.GetBucketStorageClass(name, scName, "Delete"))
  259. var testObjectStoreSC map[string]interface{}
  260. if err := yaml.Unmarshal(storageClassBytes, &testObjectStoreSC); err != nil {
  261. return err
  262. }
  263. values["cephObjectStores"] = []map[string]interface{}{
  264. {
  265. "name": name,
  266. "spec": testObjectStoreCRD["spec"],
  267. "storageClass": map[string]interface{}{
  268. "enabled": true,
  269. "name": scName,
  270. "parameters": testObjectStoreSC["parameters"],
  271. "reclaimPolicy": "Delete",
  272. },
  273. },
  274. }
  275. return nil
  276. }