From c51f31e187bc5c6918db4b8514964fc040e5425b Mon Sep 17 00:00:00 2001 From: Vignesh Goutham Ganesh Date: Wed, 7 Feb 2024 15:44:50 -0600 Subject: [PATCH] Cleanup CloudStack network resources pre-test --- cmd/eks-a-tool/cmd/cloudstackrmvms.go | 2 +- .../buildspecs/cloudstack-test-eks-a-cli.yml | 3 +- cmd/integration_test/cmd/cleanupcloudstack.go | 14 +- cmd/integration_test/cmd/cleanupvsphere.go | 2 + internal/test/cleanup/cleanup.go | 111 ++++++++-- pkg/executables/cmk.go | 94 +++++++++ pkg/executables/cmk_cmd_builder.go | 4 + pkg/executables/cmk_test.go | 194 ++++++++++++++++++ .../testdata/cmk_list_routers.json | 74 +++++++ .../testdata/cmk_list_routers_none.json | 5 + test/framework/cloudstack.go | 2 +- 11 files changed, 478 insertions(+), 27 deletions(-) create mode 100644 pkg/executables/testdata/cmk_list_routers.json create mode 100644 pkg/executables/testdata/cmk_list_routers_none.json diff --git a/cmd/eks-a-tool/cmd/cloudstackrmvms.go b/cmd/eks-a-tool/cmd/cloudstackrmvms.go index ea2ee6d8a9d7e..8120b305a24ff 100644 --- a/cmd/eks-a-tool/cmd/cloudstackrmvms.go +++ b/cmd/eks-a-tool/cmd/cloudstackrmvms.go @@ -25,7 +25,7 @@ var cloudstackRmVmsCmd = &cobra.Command{ if err != nil { return err } - err = cleanup.CleanUpCloudstackTestResources(cmd.Context(), clusterName, viper.GetBool(dryRunFlag)) + err = cleanup.CloudStackRmVms(cmd.Context(), clusterName, viper.GetBool(dryRunFlag)) if err != nil { log.Fatalf("Error removing vms: %v", err) } diff --git a/cmd/integration_test/build/buildspecs/cloudstack-test-eks-a-cli.yml b/cmd/integration_test/build/buildspecs/cloudstack-test-eks-a-cli.yml index 42fe891003446..ddf2f43b85999 100644 --- a/cmd/integration_test/build/buildspecs/cloudstack-test-eks-a-cli.yml +++ b/cmd/integration_test/build/buildspecs/cloudstack-test-eks-a-cli.yml @@ -81,7 +81,8 @@ phases: fi - > ./bin/test e2e cleanup cloudstack - -n ${CLUSTER_NAME_PREFIX} + -c ${CLUSTER_NAME_PREFIX} + -n "${T_CLOUDSTACK_NETWORK},${T_CLOUDSTACK_NETWORK_2},${T_CLOUDSTACK_NETWORK_3}" -v 4 build: commands: diff --git a/cmd/integration_test/cmd/cleanupcloudstack.go b/cmd/integration_test/cmd/cleanupcloudstack.go index ba5b83344fd29..5d2cfbe7db561 100644 --- a/cmd/integration_test/cmd/cleanupcloudstack.go +++ b/cmd/integration_test/cmd/cleanupcloudstack.go @@ -37,12 +37,16 @@ func preRunCleanUpCloudstackSetup(cmd *cobra.Command, args []string) { }) } -var requiredCloudstackCleanUpFlags = []string{clusterNameFlagName} +var requiredCloudstackCleanUpFlags = []string{ + clusterNameFlagName, + networkNameFlagName, +} func init() { cleanUpInstancesCmd.AddCommand(cleanUpCloudstackCmd) - cleanUpCloudstackCmd.Flags().StringP(clusterNameFlagName, "n", "", "Cluster name for associated vms") - + cleanUpCloudstackCmd.Flags().StringP(clusterNameFlagName, "c", "", "Cluster name for associated vms") + cleanUpCloudstackCmd.Flags().StringP(networkNameFlagName, "n", "", "Comma seperated network names to be cleaned") + cleanUpCloudstackCmd.Flags().Bool(dryRunFlagName, false, "Dry run") for _, flag := range requiredCloudstackCleanUpFlags { if err := cleanUpCloudstackCmd.MarkFlagRequired(flag); err != nil { log.Fatalf("Error marking flag %s as required: %v", flag, err) @@ -52,7 +56,9 @@ func init() { func cleanUpCloudstackTestResources(ctx context.Context) error { clusterName := viper.GetString(clusterNameFlagName) - err := cleanup.CleanUpCloudstackTestResources(ctx, clusterName, false) + networkNames := viper.GetString(networkNameFlagName) + dryRun := viper.GetBool(dryRunFlagName) + err := cleanup.CleanUpCloudstackTestResources(ctx, clusterName, networkNames, dryRun) if err != nil { return fmt.Errorf("running cleanup for cloudstack vms: %v", err) } diff --git a/cmd/integration_test/cmd/cleanupvsphere.go b/cmd/integration_test/cmd/cleanupvsphere.go index 3d37c441f849d..2b33ca660caa4 100644 --- a/cmd/integration_test/cmd/cleanupvsphere.go +++ b/cmd/integration_test/cmd/cleanupvsphere.go @@ -15,6 +15,8 @@ import ( const ( clusterNameFlagName = "cluster-name" + networkNameFlagName = "network-name" + dryRunFlagName = "dry-run" ) var cleanUpVsphereCmd = &cobra.Command{ diff --git a/internal/test/cleanup/cleanup.go b/internal/test/cleanup/cleanup.go index fb2a42db833da..73c0d0f4604ca 100644 --- a/internal/test/cleanup/cleanup.go +++ b/internal/test/cleanup/cleanup.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strconv" + "strings" "time" "github.com/aws/aws-sdk-go/aws/session" @@ -22,8 +23,11 @@ import ( ) const ( - cleanupRetries = 5 - retryBackoff = 10 * time.Second + cleanupRetries = 5 + retryBackoff = 10 * time.Second + cloudStackNetworkType = "Shared" + cloudStackNetworkReadyState = "Setup" + cloudStackAdminProfileName = "global" ) func CleanUpAwsTestResources(storageBucket string, maxAge string, tag string) error { @@ -95,25 +99,16 @@ func VsphereRmVms(ctx context.Context, clusterName string, opts ...executables.G return govc.CleanupVms(ctx, clusterName, false) } -func CleanUpCloudstackTestResources(ctx context.Context, clusterName string, dryRun bool) error { - executableBuilder, close, err := executables.InitInDockerExecutablesBuilder(ctx, executables.DefaultEksaImage()) - if err != nil { - return fmt.Errorf("unable to initialize executables: %v", err) - } - defer close.CheckErr(ctx) - tmpWriter, err := filewriter.NewWriter("rmvms") - if err != nil { - return fmt.Errorf("creating filewriter for directory rmvms: %v", err) - } - execConfig, err := decoder.ParseCloudStackCredsFromEnv() - if err != nil { - return fmt.Errorf("parsing cloudstack credentials from environment: %v", err) - } - cmk, err := executableBuilder.BuildCmkExecutable(tmpWriter, execConfig) +func CloudStackRmVms(ctx context.Context, clusterName string, dryRun bool) error { + cmk, close, execConfig, err := initCmk(ctx) if err != nil { - return fmt.Errorf("building cmk executable: %v", err) + return err } - defer cmk.Close(ctx) + defer func() { + cmk.Close(ctx) + close.CheckErr(ctx) + }() + cleanupRetrier := retrier.NewWithMaxRetries(cleanupRetries, retryBackoff) errorsMap := map[string]error{} @@ -124,13 +119,89 @@ func CleanUpCloudstackTestResources(ctx context.Context, clusterName string, dry errorsMap[profile.Name] = err } } - if len(errorsMap) > 0 { return fmt.Errorf("cleaning up VMs: %+v", errorsMap) } return nil } +func cleanUpCloudStackNetwork(ctx context.Context, networkNames string, dryRun bool) error { + cmk, close, execConfig, err := initCmk(ctx) + if err != nil { + return err + } + defer func() { + cmk.Close(ctx) + close.CheckErr(ctx) + }() + cleanupRetrier := retrier.NewWithMaxRetries(cleanupRetries, retryBackoff) + + for _, profile := range execConfig.Profiles { + if profile.Name == cloudStackAdminProfileName { + networks := strings.Split(networkNames, ",") + for _, network := range networks { + logger.Info("Cleaning network", "network name", network) + // Network cleanup. Delete router + if err := cmk.DeleteVirtualRouter(ctx, profile.Name, network, dryRun); err != nil { + return err + } + + // Restart network and wait till network status is "Setup" + logger.V(4).Info("Restarting network", "network name", network) + if err := cmk.RestartNetwork(ctx, profile.Name, network, cloudStackNetworkType, dryRun); err != nil { + return err + } + if err := cleanupRetrier.Retry(func() error { + cloudstackNetwork, err := cmk.GetNetwork(ctx, profile.Name, network, cloudStackNetworkType) + if err != nil { + return err + } + if cloudstackNetwork.State != cloudStackNetworkReadyState { + return fmt.Errorf("network has not finished restarting") + } + return nil + }); err != nil { + return err + } + logger.Info("Finished cleaning network", "network name", network) + } + } + } + return nil +} + +func CleanUpCloudstackTestResources(ctx context.Context, clusterName, networkNames string, dryRun bool) error { + err := CloudStackRmVms(ctx, clusterName, dryRun) + if err != nil { + return err + } + err = cleanUpCloudStackNetwork(ctx, networkNames, dryRun) + if err != nil { + return err + } + return nil +} + +func initCmk(ctx context.Context) (*executables.Cmk, executables.Closer, *decoder.CloudStackExecConfig, error) { + executableBuilder, close, err := executables.InitInDockerExecutablesBuilder(ctx, executables.DefaultEksaImage()) + if err != nil { + return nil, nil, nil, fmt.Errorf("unable to initialize executables: %v", err) + } + tmpWriter, err := filewriter.NewWriter("rmvms") + if err != nil { + return nil, nil, nil, fmt.Errorf("creating filewriter for directory rmvms: %v", err) + } + execConfig, err := decoder.ParseCloudStackCredsFromEnv() + if err != nil { + return nil, nil, nil, fmt.Errorf("parsing cloudstack credentials from environment: %v", err) + } + cmk, err := executableBuilder.BuildCmkExecutable(tmpWriter, execConfig) + if err != nil { + return nil, nil, nil, fmt.Errorf("building cmk executable: %v", err) + } + return cmk, close, execConfig, nil +} + // NutanixTestResourcesCleanup cleans up any leftover VMs in Nutanix after a test run. func NutanixTestResourcesCleanup(ctx context.Context, clusterName, endpoint, port string, insecure, ignoreErrors bool) error { creds := nutanix.GetCredsFromEnv() diff --git a/pkg/executables/cmk.go b/pkg/executables/cmk.go index 1cb4cc67bf83f..3c8a778940c54 100644 --- a/pkg/executables/cmk.go +++ b/pkg/executables/cmk.go @@ -395,6 +395,93 @@ func (c *Cmk) GetManagementApiEndpoint(profile string) (string, error) { return "", fmt.Errorf("profile %s does not exist", profile) } +// DeleteVirtualRouter finds the virtual router for the provided network name and deletes the router only if found. +func (c *Cmk) DeleteVirtualRouter(ctx context.Context, profile, networkName string, dryRun bool) error { + command := newCmkCommand("list routers") + applyCmkArgs(&command, withCloudStackKeyword(networkName), appendArgs("listall=true")) + result, err := c.exec(ctx, profile, command...) + if err != nil { + return fmt.Errorf("listing virtual routers with networkName %s: %s: %v", networkName, result.String(), err) + } + response := struct { + VirtualRouters []cmkResourceIdentifier `json:"router"` + }{} + if err = json.Unmarshal(result.Bytes(), &response); err != nil { + return fmt.Errorf("parsing response into json: %v", err) + } + if len(response.VirtualRouters) == 0 { + logger.Info("virtual routers not found", "network name", networkName) + return nil + } + for _, router := range response.VirtualRouters { + if dryRun { + logger.Info("Found ", "virtual router name", router.Name) + continue + } + destroyCommand := newCmkCommand("destroy router") + applyCmkArgs(&destroyCommand, withCloudStackId(router.Id)) + destroyResult, err := c.exec(ctx, profile, destroyCommand...) + if err != nil { + return fmt.Errorf("destroying virtual router with name %s and id %s: %s: %v", router.Name, router.Id, destroyResult.String(), err) + } + logger.Info("Deleted ", "router name:", router.Name, "router id", router.Id) + } + return nil +} + +// RestartNetwork finds the network on CloudStack with provided name, if found will restart the network. +func (c *Cmk) RestartNetwork(ctx context.Context, profile, networkName, networkType string, dryRun bool) error { + network, err := c.GetNetwork(ctx, profile, networkName, networkType) + if err != nil { + return err + } + if network == nil { + logger.Info("No network found to restart", "network name", networkName) + return nil + } + + if dryRun { + logger.Info("Found ", "network name", network.Name, "network id", network.Id) + return nil + } + restartCommand := newCmkCommand("restart network") + applyCmkArgs(&restartCommand, withCloudStackId(network.Id)) + result, err := c.exec(ctx, profile, restartCommand...) + if err != nil { + return fmt.Errorf("restarting network %s: %s: %v", network.Name, result.String(), err) + } + logger.Info("Restarted", "network name", network.Name, "network id", network.Id) + + return nil +} + +// GetNetwork searches CloudStack for network with provided name and type and returns the network object only when +// one network was found with the provided name. Returns error if multiple networks with same name are found. +// Returns nil if no networks are found. +func (c *Cmk) GetNetwork(ctx context.Context, profile, networkName, networkType string) (*cmkNetwork, error) { + command := newCmkCommand("list networks") + applyCmkArgs(&command, withCloudStackName(networkName), withCloudStackNetworkType(networkType), appendArgs("listall=true")) + result, err := c.exec(ctx, profile, command...) + if err != nil { + return nil, fmt.Errorf("listing networks with name %s: %s: %v", networkName, result.String(), err) + } + response := struct { + Networks []cmkNetwork `json:"network"` + }{} + if err = json.Unmarshal(result.Bytes(), &response); err != nil { + return nil, fmt.Errorf("parsing response into json: %v", err) + } + if len(response.Networks) == 0 { + logger.Info("networks not found", "networkName", networkName) + return nil, nil + } + if len(response.Networks) > 1 { + logger.Info("More then one network found", "network name", networkName) + return nil, fmt.Errorf("multiple networks with same name found") + } + return &response.Networks[0], nil +} + func (c *Cmk) CleanupVms(ctx context.Context, profile string, clusterName string, dryRun bool) error { command := newCmkCommand("list virtualmachines") applyCmkArgs(&command, withCloudStackKeyword(clusterName), appendArgs("listall=true")) @@ -495,6 +582,13 @@ type cmkResourceIdentifier struct { Name string `json:"name"` } +type cmkNetwork struct { + State string `json:"state"` + Type string `json:"type"` + + cmkResourceIdentifier +} + type cmkDiskOffering struct { Id string `json:"id"` Name string `json:"name"` diff --git a/pkg/executables/cmk_cmd_builder.go b/pkg/executables/cmk_cmd_builder.go index 672d2b1dc8594..d6dfaf0cb96ad 100644 --- a/pkg/executables/cmk_cmd_builder.go +++ b/pkg/executables/cmk_cmd_builder.go @@ -46,3 +46,7 @@ func withCloudStackName(name string) cmkCommandArgs { func withCloudStackKeyword(keyword string) cmkCommandArgs { return appendArgs(fmt.Sprintf("keyword=\"%s\"", keyword)) } + +func withCloudStackNetworkType(networkType string) cmkCommandArgs { + return appendArgs(fmt.Sprintf("type=\"%s\"", networkType)) +} diff --git a/pkg/executables/cmk_test.go b/pkg/executables/cmk_test.go index 01c9843b40044..0ab32e766c4c3 100644 --- a/pkg/executables/cmk_test.go +++ b/pkg/executables/cmk_test.go @@ -102,6 +102,127 @@ var diskOfferingCustomSizeInGB = v1alpha1.CloudStackResourceDiskOffering{ Label: "data_disk", } +func TestDeleteVirtualRouter(t *testing.T) { + _, writer := test.NewWriter(t) + configFilePath, _ := filepath.Abs(filepath.Join(writer.Dir(), "generated", cmkConfigFileName)) + tests := []struct { + testName string + listRouterJsonFile string + routerId string + networkName string + mockDestroyRouterError error + wantErr error + }{ + { + testName: "Router restarted", + listRouterJsonFile: "testdata/cmk_list_routers.json", + routerId: "2ddda113-2ca3-496a-abde-a4dbcddfbc3f", + networkName: "test-network", + }, + { + testName: "No router found", + listRouterJsonFile: "testdata/cmk_list_routers_none.json", + networkName: "test-network", + }, + { + testName: "Router failed to restart", + listRouterJsonFile: "testdata/cmk_list_routers.json", + networkName: "test-network", + routerId: "2ddda113-2ca3-496a-abde-a4dbcddfbc3f", + mockDestroyRouterError: fmt.Errorf("Unable to reach cloudstack management server"), + wantErr: fmt.Errorf("destroying virtual router with name r-355629-VM and id 2ddda113-2ca3-496a-abde-a4dbcddfbc3f: output from cloudstack: Unable to reach cloudstack management server"), + }, + } + for _, tt := range tests { + t.Run(tt.testName, func(t *testing.T) { + listRouterFileContent := test.ReadFile(t, tt.listRouterJsonFile) + + ctx := context.Background() + mockCtrl := gomock.NewController(t) + + executable := mockexecutables.NewMockExecutable(mockCtrl) + listRouterExecCall := []string{ + "-c", configFilePath, + "list", "routers", fmt.Sprintf("keyword=\"%s\"", tt.networkName), "listall=true", + } + executable.EXPECT().Execute(ctx, listRouterExecCall). + Return(*bytes.NewBufferString(listRouterFileContent), nil) + if tt.routerId != "" { + deleteRouterExecCall := []string{ + "-c", configFilePath, + "destroy", "router", fmt.Sprintf("id=\"%s\"", tt.routerId), + } + executable.EXPECT().Execute(ctx, deleteRouterExecCall). + Return(*bytes.NewBufferString("output from cloudstack"), tt.mockDestroyRouterError) + } + + cmk, _ := executables.NewCmk(executable, writer, execConfig) + err := cmk.DeleteVirtualRouter(ctx, execConfig.Profiles[0].Name, tt.networkName, false) + if tt.wantErr != nil && err == nil || err != nil && tt.wantErr == nil { + t.Fatalf("Error mismatch: Got: %v, Want: %v", err, tt.wantErr) + } + }) + } +} + +func TestRestartNetwork(t *testing.T) { + _, writer := test.NewWriter(t) + configFilePath, _ := filepath.Abs(filepath.Join(writer.Dir(), "generated", cmkConfigFileName)) + networkName := "Test-network" + networkType := "Shared" + tests := []struct { + testName string + networkId string + mockRestartNetworkError error + wantErr error + }{ + { + testName: "Successful network restart", + networkId: "aeb3a5e6-2e80-4a73-900f-d01bbd4874b5", + }, + { + testName: "Network not found", + }, + { + testName: "Network restart failed", + networkId: "aeb3a5e6-2e80-4a73-900f-d01bbd4874b5", + mockRestartNetworkError: fmt.Errorf("Unable to reach cloudstack management server"), + wantErr: fmt.Errorf("restarting network TEST_RESOURCE: restart network result: Unable to reach cloudstack management server"), + }, + } + for _, tt := range tests { + t.Run(tt.testName, func(t *testing.T) { + mockCtrl := gomock.NewController(t) + ctx := context.Background() + executable := mockexecutables.NewMockExecutable(mockCtrl) + getNetworkExecCall := []string{ + "-c", configFilePath, + "list", "networks", fmt.Sprintf("name=\"%s\"", networkName), + fmt.Sprintf("type=\"%s\"", networkType), "listall=true", + } + getNetworkJsonFileContent := test.ReadFile(t, "testdata/cmk_list_network_singular.json") + if tt.networkId == "" { + getNetworkJsonFileContent = "{}" + } + executable.EXPECT().Execute(ctx, getNetworkExecCall). + Return(*bytes.NewBufferString(getNetworkJsonFileContent), nil) + if tt.networkId != "" { + restartNetworkExecCall := []string{ + "-c", configFilePath, + "restart", "network", fmt.Sprintf("id=\"%s\"", tt.networkId), + } + executable.EXPECT().Execute(ctx, restartNetworkExecCall). + Return(*bytes.NewBufferString("restart network result"), tt.mockRestartNetworkError) + } + cmk, _ := executables.NewCmk(executable, writer, execConfig) + err := cmk.RestartNetwork(ctx, execConfig.Profiles[0].Name, networkName, networkType, false) + if tt.wantErr != nil && err == nil || err != nil && tt.wantErr == nil { + t.Fatalf("Error mismatch: Got: %v, Want: %v", err, tt.wantErr) + } + }) + } +} + func TestCmkCleanupVms(t *testing.T) { _, writer := test.NewWriter(t) configFilePath, _ := filepath.Abs(filepath.Join(writer.Dir(), "generated", cmkConfigFileName)) @@ -215,6 +336,79 @@ func TestCmkCleanupVms(t *testing.T) { } } +func TestGetNetwork(t *testing.T) { + _, writer := test.NewWriter(t) + configFilePath, _ := filepath.Abs(filepath.Join(writer.Dir(), "generated", cmkConfigFileName)) + tests := []struct { + testName string + argumentsExecCall []string + jsonResponseFile string + networkName string + networkType string + wantErr error + }{ + { + testName: "Get single shared network", + networkName: "TEST_RESOURCE", + networkType: "Shared", + jsonResponseFile: "testdata/cmk_list_network_singular.json", + wantErr: nil, + }, + { + testName: "Error on multiple networks found", + networkName: "TEST_RESOURCE", + networkType: "Shared", + jsonResponseFile: "testdata/cmk_list_network_multiple.json", + wantErr: fmt.Errorf("multiple networks with same name found"), + }, + { + testName: "No network found", + networkName: "TEST_RESOURCE", + networkType: "Shared", + jsonResponseFile: "testdata/cmk_list_network_none.json", + wantErr: nil, + }, + { + testName: "Bad response from Cloudstack", + networkName: "TEST_RESOURCE", + networkType: "Shared", + jsonResponseFile: "testdata/cmk_list_empty_response.json", + wantErr: fmt.Errorf("parsing response into json: unexpected end of JSON input"), + }, + } + for _, tt := range tests { + t.Run(tt.testName, func(t *testing.T) { + fileContent := test.ReadFile(t, tt.jsonResponseFile) + + ctx := context.Background() + mockCtrl := gomock.NewController(t) + + executable := mockexecutables.NewMockExecutable(mockCtrl) + execCall := []string{ + "-c", configFilePath, + "list", "networks", fmt.Sprintf("name=\"%s\"", tt.networkName), + fmt.Sprintf("type=\"%s\"", tt.networkType), "listall=true", + } + executable.EXPECT().Execute(ctx, execCall). + Return(*bytes.NewBufferString(fileContent), nil) + + cmk, _ := executables.NewCmk(executable, writer, execConfig) + gotNetwork, err := cmk.GetNetwork(ctx, execConfig.Profiles[0].Name, tt.networkName, tt.networkType) + if tt.wantErr != nil && err == nil || err != nil && tt.wantErr == nil { + t.Fatalf("Error mismatch: Got: %v, Want: %v", err, tt.wantErr) + } + if err == nil && gotNetwork != nil { + if gotNetwork.Name != tt.networkName { + t.Fatalf("Network name does not match. Got: %s, Want: %s", gotNetwork.Name, tt.networkName) + } + if gotNetwork.Type != tt.networkType { + t.Fatalf("Network type does not match. Got: %s, Want: %s", gotNetwork.Type, tt.networkType) + } + } + }) + } +} + func TestNewCmkNilConfig(t *testing.T) { _, err := executables.NewCmk(nil, nil, nil) if err == nil { diff --git a/pkg/executables/testdata/cmk_list_routers.json b/pkg/executables/testdata/cmk_list_routers.json new file mode 100644 index 0000000000000..b9f4b05751ce3 --- /dev/null +++ b/pkg/executables/testdata/cmk_list_routers.json @@ -0,0 +1,74 @@ +{ + "count": 1, + "router": [ + { + "account": "system", + "created": "2024-02-08T12:29:37-0700", + "dns1": "10.80.99.250", + "dns2": "10.80.148.250", + "domain": "ROOT", + "domainid": "ea2653ab-19d4-11ee-9da4-6805cac336f4", + "guestipaddress": "10.80.212.5", + "guestmacaddress": "1e:00:84:00:00:1f", + "guestnetmask": "255.255.252.0", + "guestnetworkid": "13b501c1-5629-40e1-ba1e-a31caa9aead4", + "guestnetworkname": "test-network", + "hasannotations": false, + "healthchecksfailed": true, + "hostcontrolstate": "Enabled", + "hostid": "7089b4dd-74fd-4c8e-b20e-c0e79e256b1c", + "hostname": "eksa-cs-ci2.den080.eksalab.net", + "hypervisor": "KVM", + "id": "2ddda113-2ca3-496a-abde-a4dbcddfbc3f", + "isredundantrouter": false, + "linklocalip": "169.254.187.103", + "linklocalmacaddress": "0e:00:a9:fe:bb:67", + "linklocalnetmask": "255.255.0.0", + "linklocalnetworkid": "097151fd-7fa8-41a3-9986-b0c149aad923", + "name": "r-355629-VM", + "networkdomain": "cs1cloud.internal", + "nic": [ + { + "broadcasturi": "vlan://212", + "gateway": "10.80.212.1", + "id": "a1869b05-a5d8-4ff6-8c15-0ed33c2d4165", + "ipaddress": "10.80.212.5", + "isdefault": true, + "isolationuri": "vlan://212", + "macaddress": "1e:00:84:00:00:1f", + "mtu": 1500, + "netmask": "255.255.252.0", + "networkid": "13b501c1-5629-40e1-ba1e-a31caa9aead4", + "networkname": "eksa-cloudstack-ci-net", + "traffictype": "Guest", + "type": "Shared" + }, + { + "gateway": "169.254.0.1", + "id": "99e091a3-ab02-4460-ae83-1df2bf573a88", + "ipaddress": "169.254.187.103", + "isdefault": false, + "macaddress": "0e:00:a9:fe:bb:67", + "netmask": "255.255.0.0", + "networkid": "097151fd-7fa8-41a3-9986-b0c149aad923", + "traffictype": "Control" + } + ], + "podid": "b8f5a429-1fd5-4c5e-9c1b-7ab67dc6ddf1", + "podname": "Pod1", + "redundantstate": "UNKNOWN", + "requiresupgrade": false, + "role": "VIRTUAL_ROUTER", + "scriptsversion": "0a5566b10abb5a343b24ef06213c629f\n", + "serviceofferingid": "50dde680-19c4-4f51-af15-c0176be978ae", + "serviceofferingname": "System Offering for Software Router Large - Local Storage ", + "softwareversion": "4.18.1.0", + "state": "Running", + "templateid": "7bc9cbc5-f4a5-40dd-b2d1-19f360c7c356", + "templatename": "systemvm-kvm-4.18.1", + "version": "4.18.1", + "zoneid": "f1138152-15bd-448f-8110-d73cf6540fc2", + "zonename": "Zone1" + } + ] +} \ No newline at end of file diff --git a/pkg/executables/testdata/cmk_list_routers_none.json b/pkg/executables/testdata/cmk_list_routers_none.json new file mode 100644 index 0000000000000..39c40a76fee9a --- /dev/null +++ b/pkg/executables/testdata/cmk_list_routers_none.json @@ -0,0 +1,5 @@ +{ + "count": 0, + "router": [ + ] +} diff --git a/test/framework/cloudstack.go b/test/framework/cloudstack.go index bc18b68baebf6..782bf759eb3de 100644 --- a/test/framework/cloudstack.go +++ b/test/framework/cloudstack.go @@ -245,7 +245,7 @@ func (c *CloudStack) ClusterConfigUpdates() []api.ClusterConfigFiller { } func (c *CloudStack) CleanupVMs(clusterName string) error { - return cleanup.CleanUpCloudstackTestResources(context.Background(), clusterName, false) + return cleanup.CloudStackRmVms(context.Background(), clusterName, false) } func (c *CloudStack) WithProviderUpgrade(fillers ...api.CloudStackFiller) ClusterE2ETestOpt {