github.com/gophercloud/gophercloud@v1.11.0/internal/acceptance/openstack/clustering/v1/clusters_test.go (about) 1 //go:build acceptance || clustering || policies 2 // +build acceptance clustering policies 3 4 package v1 5 6 import ( 7 "sort" 8 "strings" 9 "testing" 10 11 "github.com/gophercloud/gophercloud/internal/acceptance/clients" 12 "github.com/gophercloud/gophercloud/internal/acceptance/tools" 13 "github.com/gophercloud/gophercloud/openstack/clustering/v1/actions" 14 "github.com/gophercloud/gophercloud/openstack/clustering/v1/clusters" 15 th "github.com/gophercloud/gophercloud/testhelper" 16 ) 17 18 func TestClustersCRUD(t *testing.T) { 19 client, err := clients.NewClusteringV1Client() 20 th.AssertNoErr(t, err) 21 22 profile, err := CreateProfile(t, client) 23 th.AssertNoErr(t, err) 24 defer DeleteProfile(t, client, profile.ID) 25 26 cluster, err := CreateCluster(t, client, profile.ID) 27 th.AssertNoErr(t, err) 28 defer DeleteCluster(t, client, cluster.ID) 29 30 // Test clusters list 31 allPages, err := clusters.List(client, nil).AllPages() 32 th.AssertNoErr(t, err) 33 34 allClusters, err := clusters.ExtractClusters(allPages) 35 th.AssertNoErr(t, err) 36 37 var found bool 38 for _, v := range allClusters { 39 if v.ID == cluster.ID { 40 found = true 41 } 42 } 43 44 th.AssertEquals(t, found, true) 45 46 // Test cluster update 47 updateOpts := clusters.UpdateOpts{ 48 Name: cluster.Name + "-UPDATED", 49 } 50 51 res := clusters.Update(client, cluster.ID, updateOpts) 52 th.AssertNoErr(t, res.Err) 53 54 actionID, err := GetActionID(res.Header) 55 th.AssertNoErr(t, err) 56 57 err = WaitForAction(client, actionID) 58 th.AssertNoErr(t, err) 59 60 newCluster, err := clusters.Get(client, cluster.ID).Extract() 61 th.AssertNoErr(t, err) 62 th.AssertEquals(t, newCluster.Name, cluster.Name+"-UPDATED") 63 64 tools.PrintResource(t, newCluster) 65 66 // Test cluster health 67 actionID, err = clusters.Check(client, cluster.ID).Extract() 68 th.AssertNoErr(t, err) 69 70 err = WaitForAction(client, actionID) 71 th.AssertNoErr(t, err) 72 } 73 74 func TestClustersResize(t *testing.T) { 75 client, err := clients.NewClusteringV1Client() 76 th.AssertNoErr(t, err) 77 78 profile, err := CreateProfile(t, client) 79 th.AssertNoErr(t, err) 80 defer DeleteProfile(t, client, profile.ID) 81 82 cluster, err := CreateCluster(t, client, profile.ID) 83 th.AssertNoErr(t, err) 84 defer DeleteCluster(t, client, cluster.ID) 85 86 iTrue := true 87 resizeOpts := clusters.ResizeOpts{ 88 AdjustmentType: clusters.ChangeInCapacityAdjustment, 89 Number: 1, 90 Strict: &iTrue, 91 } 92 93 actionID, err := clusters.Resize(client, cluster.ID, resizeOpts).Extract() 94 th.AssertNoErr(t, err) 95 96 err = WaitForAction(client, actionID) 97 th.AssertNoErr(t, err) 98 99 newCluster, err := clusters.Get(client, cluster.ID).Extract() 100 th.AssertNoErr(t, err) 101 th.AssertEquals(t, newCluster.DesiredCapacity, 2) 102 103 tools.PrintResource(t, newCluster) 104 } 105 106 func TestClustersScale(t *testing.T) { 107 client, err := clients.NewClusteringV1Client() 108 th.AssertNoErr(t, err) 109 110 profile, err := CreateProfile(t, client) 111 th.AssertNoErr(t, err) 112 defer DeleteProfile(t, client, profile.ID) 113 114 cluster, err := CreateCluster(t, client, profile.ID) 115 th.AssertNoErr(t, err) 116 defer DeleteCluster(t, client, cluster.ID) 117 118 // increase cluster size to 2 119 scaleOutOpts := clusters.ScaleOutOpts{ 120 Count: 1, 121 } 122 actionID, err := clusters.ScaleOut(client, cluster.ID, scaleOutOpts).Extract() 123 th.AssertNoErr(t, err) 124 125 err = WaitForAction(client, actionID) 126 th.AssertNoErr(t, err) 127 128 newCluster, err := clusters.Get(client, cluster.ID).Extract() 129 th.AssertNoErr(t, err) 130 th.AssertEquals(t, newCluster.DesiredCapacity, 2) 131 132 // reduce cluster size to 0 133 count := 2 134 scaleInOpts := clusters.ScaleInOpts{ 135 Count: &count, 136 } 137 138 actionID, err = clusters.ScaleIn(client, cluster.ID, scaleInOpts).Extract() 139 th.AssertNoErr(t, err) 140 141 err = WaitForAction(client, actionID) 142 th.AssertNoErr(t, err) 143 144 newCluster, err = clusters.Get(client, cluster.ID).Extract() 145 th.AssertNoErr(t, err) 146 th.AssertEquals(t, newCluster.DesiredCapacity, 0) 147 148 tools.PrintResource(t, newCluster) 149 } 150 151 func TestClustersPolicies(t *testing.T) { 152 client, err := clients.NewClusteringV1Client() 153 th.AssertNoErr(t, err) 154 client.Microversion = "1.5" 155 156 profile, err := CreateProfile(t, client) 157 th.AssertNoErr(t, err) 158 defer DeleteProfile(t, client, profile.ID) 159 160 cluster, err := CreateCluster(t, client, profile.ID) 161 th.AssertNoErr(t, err) 162 defer DeleteCluster(t, client, cluster.ID) 163 164 policy, err := CreatePolicy(t, client) 165 th.AssertNoErr(t, err) 166 defer DeletePolicy(t, client, policy.ID) 167 168 iTrue := true 169 attachPolicyOpts := clusters.AttachPolicyOpts{ 170 PolicyID: policy.ID, 171 Enabled: &iTrue, 172 } 173 174 actionID, err := clusters.AttachPolicy(client, cluster.ID, attachPolicyOpts).Extract() 175 th.AssertNoErr(t, err) 176 177 err = WaitForAction(client, actionID) 178 th.AssertNoErr(t, err) 179 180 // List all policies in the cluster to see if the policy was 181 // successfully attached. 182 allPages, err := clusters.ListPolicies(client, cluster.ID, nil).AllPages() 183 th.AssertNoErr(t, err) 184 185 allPolicies, err := clusters.ExtractClusterPolicies(allPages) 186 th.AssertNoErr(t, err) 187 188 var found bool 189 for _, v := range allPolicies { 190 tools.PrintResource(t, v) 191 if v.PolicyID == policy.ID { 192 found = true 193 } 194 } 195 196 th.AssertEquals(t, found, true) 197 198 // Set the policy to disabled 199 iFalse := false 200 updatePolicyOpts := clusters.UpdatePolicyOpts{ 201 PolicyID: policy.ID, 202 Enabled: &iFalse, 203 } 204 205 actionID, err = clusters.UpdatePolicy(client, cluster.ID, updatePolicyOpts).Extract() 206 th.AssertNoErr(t, err) 207 208 err = WaitForAction(client, actionID) 209 th.AssertNoErr(t, err) 210 211 clusterPolicy, err := clusters.GetPolicy(client, cluster.ID, policy.ID).Extract() 212 th.AssertNoErr(t, err) 213 th.AssertEquals(t, clusterPolicy.Enabled, false) 214 215 // Detach the policy 216 detachPolicyOpts := clusters.DetachPolicyOpts{ 217 PolicyID: policy.ID, 218 } 219 220 actionID, err = clusters.DetachPolicy(client, cluster.ID, detachPolicyOpts).Extract() 221 th.AssertNoErr(t, err) 222 223 err = WaitForAction(client, actionID) 224 th.AssertNoErr(t, err) 225 226 // List all policies in the cluster to see if the policy was 227 // successfully detached. 228 allPages, err = clusters.ListPolicies(client, cluster.ID, nil).AllPages() 229 th.AssertNoErr(t, err) 230 231 allPolicies, err = clusters.ExtractClusterPolicies(allPages) 232 th.AssertNoErr(t, err) 233 234 found = false 235 for _, v := range allPolicies { 236 tools.PrintResource(t, v) 237 if v.PolicyID == policy.ID { 238 found = true 239 } 240 } 241 242 th.AssertEquals(t, found, false) 243 } 244 245 func TestClustersRecovery(t *testing.T) { 246 client, err := clients.NewClusteringV1Client() 247 th.AssertNoErr(t, err) 248 249 profile, err := CreateProfile(t, client) 250 th.AssertNoErr(t, err) 251 defer DeleteProfile(t, client, profile.ID) 252 253 cluster, err := CreateCluster(t, client, profile.ID) 254 th.AssertNoErr(t, err) 255 defer DeleteCluster(t, client, cluster.ID) 256 257 recoverOpts := clusters.RecoverOpts{ 258 Operation: clusters.RebuildRecovery, 259 } 260 261 actionID, err := clusters.Recover(client, cluster.ID, recoverOpts).Extract() 262 th.AssertNoErr(t, err) 263 264 err = WaitForAction(client, actionID) 265 th.AssertNoErr(t, err) 266 267 newCluster, err := clusters.Get(client, cluster.ID).Extract() 268 th.AssertNoErr(t, err) 269 270 tools.PrintResource(t, newCluster) 271 } 272 273 func TestClustersAddNode(t *testing.T) { 274 client, err := clients.NewClusteringV1Client() 275 th.AssertNoErr(t, err) 276 277 profile, err := CreateProfile(t, client) 278 th.AssertNoErr(t, err) 279 defer DeleteProfile(t, client, profile.ID) 280 281 cluster, err := CreateCluster(t, client, profile.ID) 282 th.AssertNoErr(t, err) 283 defer DeleteCluster(t, client, cluster.ID) 284 285 node1, err := CreateNode(t, client, "", profile.ID) 286 th.AssertNoErr(t, err) 287 // Even tho deleting the cluster will delete the nodes but only if added into cluster successfully. 288 defer DeleteNode(t, client, node1.ID) 289 290 node2, err := CreateNode(t, client, "", profile.ID) 291 th.AssertNoErr(t, err) 292 // Even tho deleting the cluster will delete the nodes but only if added into cluster successfully. 293 defer DeleteNode(t, client, node2.ID) 294 295 cluster, err = clusters.Get(client, cluster.ID).Extract() 296 th.AssertNoErr(t, err) 297 298 nodeIDs := []string{node1.ID, node2.ID} 299 nodeIDs = append(nodeIDs, cluster.Nodes...) 300 301 nodeNames := []string{node1.Name, node2.Name} 302 addNodesOpts := clusters.AddNodesOpts{ 303 Nodes: nodeNames, 304 } 305 actionID, err := clusters.AddNodes(client, cluster.ID, addNodesOpts).Extract() 306 if err != nil { 307 t.Fatalf("Unable to add nodes to cluster: %v", err) 308 } 309 310 err = WaitForAction(client, actionID) 311 th.AssertNoErr(t, err) 312 313 cluster, err = clusters.Get(client, cluster.ID).Extract() 314 th.AssertNoErr(t, err) 315 316 sort.Strings(nodeIDs) 317 sort.Strings(cluster.Nodes) 318 319 tools.PrintResource(t, nodeIDs) 320 tools.PrintResource(t, cluster.Nodes) 321 322 th.AssertDeepEquals(t, nodeIDs, cluster.Nodes) 323 324 tools.PrintResource(t, cluster) 325 } 326 327 func TestClustersRemoveNodeFromCluster(t *testing.T) { 328 client, err := clients.NewClusteringV1Client() 329 th.AssertNoErr(t, err) 330 331 profile, err := CreateProfile(t, client) 332 th.AssertNoErr(t, err) 333 defer DeleteProfile(t, client, profile.ID) 334 335 cluster, err := CreateCluster(t, client, profile.ID) 336 th.AssertNoErr(t, err) 337 defer DeleteCluster(t, client, cluster.ID) 338 339 cluster, err = clusters.Get(client, cluster.ID).Extract() 340 th.AssertNoErr(t, err) 341 tools.PrintResource(t, cluster) 342 343 opt := clusters.RemoveNodesOpts{Nodes: cluster.Nodes} 344 actionID, err := clusters.RemoveNodes(client, cluster.ID, opt).Extract() 345 if err != nil { 346 t.Fatalf("Unable to remove nodes to cluster: %v", err) 347 } 348 349 for _, n := range cluster.Nodes { 350 defer DeleteNode(t, client, n) 351 } 352 353 err = WaitForAction(client, actionID) 354 th.AssertNoErr(t, err) 355 356 cluster, err = clusters.Get(client, cluster.ID).Extract() 357 th.AssertNoErr(t, err) 358 359 th.AssertEquals(t, 0, len(cluster.Nodes)) 360 361 tools.PrintResource(t, cluster) 362 } 363 364 func TestClustersReplaceNode(t *testing.T) { 365 client, err := clients.NewClusteringV1Client() 366 th.AssertNoErr(t, err) 367 client.Microversion = "1.3" 368 369 profile, err := CreateProfile(t, client) 370 th.AssertNoErr(t, err) 371 defer DeleteProfile(t, client, profile.ID) 372 373 cluster, err := CreateCluster(t, client, profile.ID) 374 th.AssertNoErr(t, err) 375 defer DeleteCluster(t, client, cluster.ID) 376 377 node1, err := CreateNode(t, client, "", profile.ID) 378 th.AssertNoErr(t, err) 379 defer DeleteNode(t, client, node1.ID) 380 381 cluster, err = clusters.Get(client, cluster.ID).Extract() 382 th.AssertNoErr(t, err) 383 th.AssertEquals(t, true, len(cluster.Nodes) > 0) 384 for _, n := range cluster.Nodes { 385 defer DeleteNode(t, client, n) 386 } 387 388 nodeIDToBeReplaced := cluster.Nodes[0] 389 opts := clusters.ReplaceNodesOpts{Nodes: map[string]string{nodeIDToBeReplaced: node1.ID}} 390 actionID, err := clusters.ReplaceNodes(client, cluster.ID, opts).Extract() 391 th.AssertNoErr(t, err) 392 err = WaitForAction(client, actionID) 393 th.AssertNoErr(t, err) 394 395 cluster, err = clusters.Get(client, cluster.ID).Extract() 396 th.AssertNoErr(t, err) 397 398 clusterNodes := strings.Join(cluster.Nodes, ",") 399 th.AssertEquals(t, true, strings.Contains(clusterNodes, node1.ID)) 400 th.AssertEquals(t, false, strings.Contains(clusterNodes, nodeIDToBeReplaced)) 401 tools.PrintResource(t, cluster) 402 } 403 404 func TestClustersCollectAttributes(t *testing.T) { 405 client, err := clients.NewClusteringV1Client() 406 th.AssertNoErr(t, err) 407 client.Microversion = "1.2" 408 409 profile, err := CreateProfile(t, client) 410 th.AssertNoErr(t, err) 411 defer DeleteProfile(t, client, profile.ID) 412 413 cluster, err := CreateCluster(t, client, profile.ID) 414 th.AssertNoErr(t, err) 415 defer DeleteCluster(t, client, cluster.ID) 416 417 cluster, err = clusters.Get(client, cluster.ID).Extract() 418 th.AssertNoErr(t, err) 419 th.AssertEquals(t, true, len(cluster.Nodes) > 0) 420 421 _, err = CreateNode(t, client, cluster.ID, profile.ID) 422 th.AssertNoErr(t, err) 423 424 cluster, err = clusters.Get(client, cluster.ID).Extract() 425 th.AssertNoErr(t, err) 426 th.AssertEquals(t, true, len(cluster.Nodes) > 0) 427 428 for _, n := range cluster.Nodes { 429 defer DeleteNode(t, client, n) 430 } 431 432 opts := clusters.CollectOpts{ 433 Path: "status", 434 } 435 attrs, err := clusters.Collect(client, cluster.ID, opts).Extract() 436 th.AssertNoErr(t, err) 437 for _, attr := range attrs { 438 th.AssertEquals(t, attr.Value, "ACTIVE") 439 } 440 441 opts = clusters.CollectOpts{ 442 Path: "data.placement.zone", 443 } 444 attrs, err = clusters.Collect(client, cluster.ID, opts).Extract() 445 th.AssertNoErr(t, err) 446 for _, attr := range attrs { 447 th.AssertEquals(t, attr.Value, "nova") 448 } 449 450 } 451 452 // Performs an operation on a cluster 453 func TestClustersOps(t *testing.T) { 454 choices, err := clients.AcceptanceTestChoicesFromEnv() 455 th.AssertNoErr(t, err) 456 457 client, err := clients.NewClusteringV1Client() 458 th.AssertNoErr(t, err) 459 client.Microversion = "1.4" 460 461 profile, err := CreateProfile(t, client) 462 th.AssertNoErr(t, err) 463 defer DeleteProfile(t, client, profile.ID) 464 465 cluster, err := CreateCluster(t, client, profile.ID) 466 th.AssertNoErr(t, err) 467 defer DeleteCluster(t, client, cluster.ID) 468 469 node, err := CreateNode(t, client, cluster.ID, profile.ID) 470 th.AssertNoErr(t, err) 471 defer DeleteNode(t, client, node.ID) 472 473 ops := []clusters.OperationOpts{ 474 // TODO: Commented out due to backend returns error, as of 2019-01-09 475 //{Operation: clusters.RebuildOperation}, // Error in set_admin_password in nova log 476 //{Operation: clusters.EvacuateOperation, Params: clusters.OperationParams{"host": cluster.ID, "force": "True"}}, 477 //{Operation: clusters.ChangePasswordOperation, Params: clusters.OperationParams{"admin_pass": "test"}}, // QEMU guest agent is not enabled. 478 {Operation: clusters.RebootOperation, Params: clusters.OperationParams{"type": "SOFT"}}, 479 {Operation: clusters.LockOperation}, 480 {Operation: clusters.UnlockOperation}, 481 {Operation: clusters.SuspendOperation}, 482 {Operation: clusters.ResumeOperation}, 483 {Operation: clusters.RescueOperation, Params: clusters.OperationParams{"image_ref": choices.ImageID}}, 484 {Operation: clusters.PauseOperation}, 485 {Operation: clusters.UnpauseOperation}, 486 {Operation: clusters.StopOperation}, 487 {Operation: clusters.StartOperation}, 488 } 489 490 for _, op := range ops { 491 opName := string(op.Operation) 492 t.Logf("Attempting to perform '%s' on cluster: %s", opName, cluster.ID) 493 actionID, res := clusters.Ops(client, cluster.ID, op).Extract() 494 th.AssertNoErr(t, res) 495 496 err = WaitForAction(client, actionID) 497 th.AssertNoErr(t, err) 498 499 action, err := actions.Get(client, actionID).Extract() 500 th.AssertNoErr(t, err) 501 th.AssertEquals(t, "SUCCEEDED", action.Status) 502 503 t.Logf("Successfully performed '%s' on cluster: %s", opName, cluster.ID) 504 } 505 506 cluster, err = clusters.Get(client, cluster.ID).Extract() 507 th.AssertNoErr(t, err) 508 tools.PrintResource(t, cluster) 509 }