mirror_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. Copyright 2020 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 client
  14. import (
  15. "testing"
  16. "github.com/pkg/errors"
  17. cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
  18. "github.com/rook/rook/pkg/clusterd"
  19. exectest "github.com/rook/rook/pkg/util/exec/test"
  20. "github.com/stretchr/testify/assert"
  21. )
  22. var (
  23. bootstrapPeerToken = `eyJmc2lkIjoiYzZiMDg3ZjItNzgyOS00ZGJiLWJjZmMtNTNkYzM0ZTBiMzVkIiwiY2xpZW50X2lkIjoicmJkLW1pcnJvci1wZWVyIiwia2V5IjoiQVFBV1lsWmZVQ1Q2RGhBQVBtVnAwbGtubDA5YVZWS3lyRVV1NEE9PSIsIm1vbl9ob3N0IjoiW3YyOjE5Mi4xNjguMTExLjEwOjMzMDAsdjE6MTkyLjE2OC4xMTEuMTA6Njc4OV0sW3YyOjE5Mi4xNjguMTExLjEyOjMzMDAsdjE6MTkyLjE2OC4xMTEuMTI6Njc4OV0sW3YyOjE5Mi4xNjguMTExLjExOjMzMDAsdjE6MTkyLjE2OC4xMTEuMTE6Njc4OV0ifQ==` //nolint:gosec // This is just a var name, not a real token
  24. mirrorStatus = `{"summary":{"health":"WARNING","daemon_health":"OK","image_health":"WARNING","states":{"starting_replay":1,"replaying":1}}}`
  25. mirrorInfo = `{"mode":"image","site_name":"39074576-5884-4ef3-8a4d-8a0c5ed33031","peers":[{"uuid":"4a6983c0-3c9d-40f5-b2a9-2334a4659827","direction":"rx-tx","site_name":"ocs","mirror_uuid":"","client_name":"client.rbd-mirror-peer"}]}`
  26. snapshotScheduleStatus = `[{"schedule_time": "14:00:00-05:00", "image": "foo"}, {"schedule_time": "08:00:00-05:00", "image": "bar"}]`
  27. snapshotScheduleList = `[{"interval":"3d","start_time":""},{"interval":"1d","start_time":"14:00:00-05:00"}]`
  28. snapshotScheduleListRecursive = `[{"pool":"replicapool","namespace":"-","image":"-","items":[{"interval":"1d","start_time":"14:00:00-05:00"}]},{"pool":"replicapool","namespace":"","image":"snapeuh","items":[{"interval":"1d","start_time":"14:00:00-05:00"},{"interval":"4h","start_time":"14:00:00-05:00"},{"interval":"4h","start_time":"04:00:00-05:00"}]}]`
  29. )
  30. func TestCreateRBDMirrorBootstrapPeer(t *testing.T) {
  31. pool := "pool-test"
  32. executor := &exectest.MockExecutor{}
  33. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  34. if args[0] == "mirror" {
  35. assert.Equal(t, "pool", args[1])
  36. assert.Equal(t, "peer", args[2])
  37. assert.Equal(t, "bootstrap", args[3])
  38. assert.Equal(t, "create", args[4])
  39. assert.Equal(t, pool, args[5])
  40. return bootstrapPeerToken, nil
  41. }
  42. return "", errors.New("unknown command")
  43. }
  44. context := &clusterd.Context{Executor: executor}
  45. c := AdminTestClusterInfo("mycluster")
  46. c.FSID = "4fe04ebb-ec0c-46c2-ac55-9eb52ebbfb82"
  47. token, err := CreateRBDMirrorBootstrapPeer(context, c, pool)
  48. assert.NoError(t, err)
  49. assert.Equal(t, bootstrapPeerToken, string(token))
  50. }
  51. func TestEnablePoolMirroring(t *testing.T) {
  52. pool := cephv1.NamedPoolSpec{
  53. Name: "pool-test",
  54. PoolSpec: cephv1.PoolSpec{
  55. Mirroring: cephv1.MirroringSpec{Mode: "image"},
  56. },
  57. }
  58. executor := &exectest.MockExecutor{}
  59. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  60. if args[0] == "mirror" {
  61. assert.Equal(t, "pool", args[1])
  62. assert.Equal(t, "enable", args[2])
  63. assert.Equal(t, pool.Name, args[3])
  64. assert.Equal(t, pool.Mirroring.Mode, args[4])
  65. return "", nil
  66. }
  67. return "", errors.New("unknown command")
  68. }
  69. context := &clusterd.Context{Executor: executor}
  70. err := enablePoolMirroring(context, AdminTestClusterInfo("mycluster"), pool)
  71. assert.NoError(t, err)
  72. }
  73. func TestGetPoolMirroringStatus(t *testing.T) {
  74. pool := "pool-test"
  75. executor := &exectest.MockExecutor{}
  76. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  77. if args[0] == "mirror" {
  78. assert.Equal(t, "pool", args[1])
  79. assert.Equal(t, "status", args[2])
  80. assert.Equal(t, pool, args[3])
  81. return mirrorStatus, nil
  82. }
  83. return "", errors.New("unknown command")
  84. }
  85. context := &clusterd.Context{Executor: executor}
  86. poolMirrorStatus, err := GetPoolMirroringStatus(context, AdminTestClusterInfo("mycluster"), pool)
  87. assert.NoError(t, err)
  88. assert.Equal(t, "WARNING", poolMirrorStatus.Summary.Health)
  89. assert.Equal(t, "OK", poolMirrorStatus.Summary.DaemonHealth)
  90. }
  91. func TestImportRBDMirrorBootstrapPeer(t *testing.T) {
  92. pool := "pool-test"
  93. executor := &exectest.MockExecutor{}
  94. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  95. if args[0] == "mirror" {
  96. assert.Equal(t, "pool", args[1])
  97. assert.Equal(t, "peer", args[2])
  98. assert.Equal(t, "bootstrap", args[3])
  99. assert.Equal(t, "import", args[4])
  100. assert.Equal(t, pool, args[5])
  101. assert.Equal(t, 11, len(args))
  102. return mirrorStatus, nil
  103. }
  104. return "", errors.New("unknown command")
  105. }
  106. context := &clusterd.Context{Executor: executor}
  107. err := ImportRBDMirrorBootstrapPeer(context, AdminTestClusterInfo("mycluster"), pool, "", []byte(bootstrapPeerToken))
  108. assert.NoError(t, err)
  109. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  110. if args[0] == "mirror" {
  111. assert.Equal(t, "pool", args[1])
  112. assert.Equal(t, "peer", args[2])
  113. assert.Equal(t, "bootstrap", args[3])
  114. assert.Equal(t, "import", args[4])
  115. assert.Equal(t, pool, args[5])
  116. assert.Equal(t, "--direction", args[7])
  117. assert.Equal(t, "rx-tx", args[8])
  118. assert.Equal(t, 13, len(args))
  119. return mirrorStatus, nil
  120. }
  121. return "", errors.New("unknown command")
  122. }
  123. context = &clusterd.Context{Executor: executor}
  124. err = ImportRBDMirrorBootstrapPeer(context, AdminTestClusterInfo("mycluster"), pool, "rx-tx", []byte(bootstrapPeerToken))
  125. assert.NoError(t, err)
  126. }
  127. func TestGetPoolMirroringInfo(t *testing.T) {
  128. pool := "pool-test"
  129. executor := &exectest.MockExecutor{}
  130. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  131. if args[0] == "mirror" {
  132. assert.Equal(t, "pool", args[1])
  133. assert.Equal(t, "info", args[2])
  134. assert.Equal(t, pool, args[3])
  135. return mirrorInfo, nil
  136. }
  137. return "", errors.New("unknown command")
  138. }
  139. context := &clusterd.Context{Executor: executor}
  140. poolMirrorInfo, err := GetPoolMirroringInfo(context, AdminTestClusterInfo("mycluster"), pool)
  141. assert.NoError(t, err)
  142. assert.Equal(t, "image", poolMirrorInfo.Mode)
  143. assert.Equal(t, 1, len(poolMirrorInfo.Peers))
  144. }
  145. func TestEnableSnapshotSchedule(t *testing.T) {
  146. pool := "pool-test"
  147. interval := "24h"
  148. // Schedule with Interval
  149. {
  150. executor := &exectest.MockExecutor{}
  151. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  152. logger.Infof("Command: %v %v", command, args)
  153. if args[0] == "mirror" {
  154. assert.Equal(t, "snapshot", args[1])
  155. assert.Equal(t, "schedule", args[2])
  156. assert.Equal(t, "add", args[3])
  157. assert.Equal(t, "--pool", args[4])
  158. assert.Equal(t, pool, args[5])
  159. assert.Equal(t, interval, args[6])
  160. assert.Equal(t, len(args), 11)
  161. return "success", nil
  162. }
  163. return "", errors.New("unknown command")
  164. }
  165. context := &clusterd.Context{Executor: executor}
  166. poolSpec := &cephv1.PoolSpec{Mirroring: cephv1.MirroringSpec{SnapshotSchedules: []cephv1.SnapshotScheduleSpec{{Interval: interval}}}}
  167. err := enableSnapshotSchedule(context, AdminTestClusterInfo("mycluster"), poolSpec.Mirroring.SnapshotSchedules[0], pool)
  168. assert.NoError(t, err)
  169. }
  170. // Schedule with Interval and start time
  171. {
  172. startTime := "14:00:00-05:00"
  173. executor := &exectest.MockExecutor{}
  174. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  175. logger.Infof("Command: %v %v", command, args)
  176. if args[0] == "mirror" {
  177. assert.Equal(t, "snapshot", args[1])
  178. assert.Equal(t, "schedule", args[2])
  179. assert.Equal(t, "add", args[3])
  180. assert.Equal(t, "--pool", args[4])
  181. assert.Equal(t, pool, args[5])
  182. assert.Equal(t, interval, args[6])
  183. assert.Equal(t, startTime, args[7])
  184. assert.Equal(t, len(args), 12)
  185. return "success", nil
  186. }
  187. return "", errors.New("unknown command")
  188. }
  189. context := &clusterd.Context{Executor: executor}
  190. poolSpec := &cephv1.PoolSpec{Mirroring: cephv1.MirroringSpec{SnapshotSchedules: []cephv1.SnapshotScheduleSpec{{Interval: interval, StartTime: startTime}}}}
  191. err := enableSnapshotSchedule(context, AdminTestClusterInfo("mycluster"), poolSpec.Mirroring.SnapshotSchedules[0], pool)
  192. assert.NoError(t, err)
  193. }
  194. }
  195. func TestListSnapshotSchedules(t *testing.T) {
  196. pool := "pool-test"
  197. executor := &exectest.MockExecutor{}
  198. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  199. logger.Infof("Command: %v %v", command, args)
  200. if args[0] == "mirror" {
  201. assert.Equal(t, "snapshot", args[1])
  202. assert.Equal(t, "schedule", args[2])
  203. assert.Equal(t, "ls", args[3])
  204. assert.Equal(t, "--pool", args[4])
  205. assert.Equal(t, pool, args[5])
  206. return snapshotScheduleStatus, nil
  207. }
  208. return "", errors.New("unknown command")
  209. }
  210. context := &clusterd.Context{Executor: executor}
  211. snapshotScheduleStatus, err := listSnapshotSchedules(context, AdminTestClusterInfo("mycluster"), pool)
  212. assert.NoError(t, err)
  213. assert.Equal(t, 2, len(snapshotScheduleStatus))
  214. }
  215. func TestListSnapshotSchedulesRecursively(t *testing.T) {
  216. pool := "pool-test"
  217. executor := &exectest.MockExecutor{}
  218. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  219. logger.Infof("Command: %v %v", command, args)
  220. if args[0] == "mirror" {
  221. assert.Equal(t, "snapshot", args[1])
  222. assert.Equal(t, "schedule", args[2])
  223. assert.Equal(t, "ls", args[3])
  224. assert.Equal(t, "--pool", args[4])
  225. assert.Equal(t, pool, args[5])
  226. assert.Equal(t, "--recursive", args[6])
  227. return snapshotScheduleListRecursive, nil
  228. }
  229. return "", errors.New("unknown command")
  230. }
  231. context := &clusterd.Context{Executor: executor}
  232. snapshotScheduleStatus, err := ListSnapshotSchedulesRecursively(context, AdminTestClusterInfo("mycluster"), pool)
  233. assert.NoError(t, err)
  234. assert.Equal(t, 2, len(snapshotScheduleStatus))
  235. }
  236. func TestRemoveSnapshotSchedule(t *testing.T) {
  237. pool := "pool-test"
  238. executor := &exectest.MockExecutor{}
  239. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  240. logger.Infof("Command: %v %v", command, args)
  241. if args[0] == "mirror" {
  242. assert.Equal(t, "snapshot", args[1])
  243. assert.Equal(t, "schedule", args[2])
  244. assert.Equal(t, "remove", args[3])
  245. assert.Equal(t, "--pool", args[4])
  246. assert.Equal(t, pool, args[5])
  247. return "", nil
  248. }
  249. return "", errors.New("unknown command")
  250. }
  251. context := &clusterd.Context{Executor: executor}
  252. snapScheduleResponse := cephv1.SnapshotSchedule{StartTime: "14:00:00-05:00", Interval: "1d"}
  253. err := removeSnapshotSchedule(context, AdminTestClusterInfo("mycluster"), snapScheduleResponse, pool)
  254. assert.NoError(t, err)
  255. }
  256. func TestRemoveSnapshotSchedules(t *testing.T) {
  257. interval := "24h"
  258. startTime := "14:00:00-05:00"
  259. executor := &exectest.MockExecutor{}
  260. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  261. logger.Infof("Command: %v %v", command, args)
  262. if args[0] == "mirror" {
  263. switch args[3] {
  264. case "ls":
  265. return snapshotScheduleList, nil
  266. case "remove":
  267. return "success", nil
  268. }
  269. }
  270. return "", errors.New("unknown command")
  271. }
  272. context := &clusterd.Context{Executor: executor}
  273. pool := cephv1.NamedPoolSpec{
  274. Name: "pool-test",
  275. PoolSpec: cephv1.PoolSpec{
  276. Mirroring: cephv1.MirroringSpec{
  277. SnapshotSchedules: []cephv1.SnapshotScheduleSpec{
  278. {Interval: interval, StartTime: startTime},
  279. },
  280. },
  281. },
  282. }
  283. err := removeSnapshotSchedules(context, AdminTestClusterInfo("mycluster"), pool)
  284. assert.NoError(t, err)
  285. }
  286. func TestDisableMirroring(t *testing.T) {
  287. pool := "pool-test"
  288. executor := &exectest.MockExecutor{}
  289. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  290. if args[0] == "mirror" {
  291. assert.Equal(t, "pool", args[1])
  292. assert.Equal(t, "disable", args[2])
  293. assert.Equal(t, pool, args[3])
  294. return "", nil
  295. }
  296. return "", errors.New("unknown command")
  297. }
  298. context := &clusterd.Context{Executor: executor}
  299. err := disablePoolMirroring(context, AdminTestClusterInfo("mycluster"), pool)
  300. assert.NoError(t, err)
  301. }
  302. func TestRemoveClusterPeer(t *testing.T) {
  303. pool := "pool-test"
  304. peerUUID := "39ae33fb-1dd6-4f9b-8ed7-0e4517068900"
  305. executor := &exectest.MockExecutor{}
  306. executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) {
  307. if args[0] == "mirror" {
  308. assert.Equal(t, "pool", args[1])
  309. assert.Equal(t, "peer", args[2])
  310. assert.Equal(t, "remove", args[3])
  311. assert.Equal(t, pool, args[4])
  312. assert.Equal(t, peerUUID, args[5])
  313. return "", nil
  314. }
  315. return "", errors.New("unknown command")
  316. }
  317. context := &clusterd.Context{Executor: executor}
  318. err := removeClusterPeer(context, AdminTestClusterInfo("mycluster"), pool, peerUUID)
  319. assert.NoError(t, err)
  320. }