Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: delete instance permanently using reclamation id #914

Merged
merged 10 commits into from
Jan 27, 2025
Merged
8 changes: 4 additions & 4 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "go.sum|package-lock.json|^.secrets.baseline$",
"lines": null
},
"generated_at": "2025-01-24T15:40:02Z",
"generated_at": "2025-01-24T16:21:04Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -128,23 +128,23 @@
"hashed_secret": "892bd503fb45f6fcafb1c7003d88291fc0b20208",
"is_secret": false,
"is_verified": false,
"line_number": 284,
"line_number": 291,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "5da5a31d49370df43eff521b39c10db1466fae44",
"is_secret": false,
"is_verified": false,
"line_number": 287,
"line_number": 294,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030",
"is_secret": false,
"is_verified": false,
"line_number": 488,
"line_number": 495,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
54 changes: 53 additions & 1 deletion cloudinfo/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,25 @@ func (mock *iamPolicyServiceMock) DeletePolicy(deletePolicyOptions *iampolicyman
// RESOURCE CONTROLLER SERVICE MOCK
type resourceControllerServiceMock struct {
mock.Mock
mockResourceList *resourcecontrollerv2.ResourceInstancesList
mockResourceList *resourcecontrollerv2.ResourceInstancesList
mockReclamationList *resourcecontrollerv2.ReclamationsList
mockReclamation *resourcecontrollerv2.Reclamation
}

func (mock *resourceControllerServiceMock) NewListResourceInstancesOptions() *resourcecontrollerv2.ListResourceInstancesOptions {
return &resourcecontrollerv2.ListResourceInstancesOptions{}
}

func (mock *resourceControllerServiceMock) NewListReclamationsOptions() *resourcecontrollerv2.ListReclamationsOptions {

return &resourcecontrollerv2.ListReclamationsOptions{}
}

func (mock *resourceControllerServiceMock) NewRunReclamationActionOptions(id string, action string) *resourcecontrollerv2.RunReclamationActionOptions {

return &resourcecontrollerv2.RunReclamationActionOptions{ID: core.StringPtr(id), ActionName: core.StringPtr(action)}
}

func (mock *resourceControllerServiceMock) ListResourceInstances(options *resourcecontrollerv2.ListResourceInstancesOptions) (*resourcecontrollerv2.ResourceInstancesList, *core.DetailedResponse, error) {
var retList *resourcecontrollerv2.ResourceInstancesList
var mockCount int64 = 0
Expand All @@ -146,6 +158,46 @@ func (mock *resourceControllerServiceMock) ListResourceInstances(options *resour
return retList, nil, nil
}

func (mock *resourceControllerServiceMock) ListReclamations(options *resourcecontrollerv2.ListReclamationsOptions) (*resourcecontrollerv2.ReclamationsList, *core.DetailedResponse, error) {

var recList *resourcecontrollerv2.ReclamationsList
var mockID string = "mock-reclamation-id"
mockReclamation := resourcecontrollerv2.Reclamation{ID: &mockID}
mockReclamationList := []resourcecontrollerv2.Reclamation{mockReclamation}

if options.ResourceInstanceID != nil && *options.ResourceInstanceID == "ERROR" {
return nil, nil, errors.New("mock Resource is error")
}

if mock.mockReclamationList == nil {

recList = &resourcecontrollerv2.ReclamationsList{

Resources: mockReclamationList,
}
} else {
recList = mock.mockReclamationList
}

return recList, nil, nil
}

func (mock *resourceControllerServiceMock) RunReclamationAction(options *resourcecontrollerv2.RunReclamationActionOptions) (*resourcecontrollerv2.Reclamation, *core.DetailedResponse, error) {

var reclamation *resourcecontrollerv2.Reclamation
var mockID string = "mock-reclamation-id"
mockReclamation := resourcecontrollerv2.Reclamation{ID: &mockID}

if mock.mockReclamation == nil {

reclamation = &mockReclamation
} else {
reclamation = mock.mockReclamation
}

return reclamation, nil, nil
}

// Resource Manager mock
type resourceManagerServiceMock struct {
mockResourceGroupList *resourcemanagerv2.ResourceGroupList
Expand Down
78 changes: 77 additions & 1 deletion cloudinfo/resourcecontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package cloudinfo

import (
"fmt"
bluemix_crn "github.com/IBM-Cloud/bluemix-go/crn"
"strings"

bluemix_crn "github.com/IBM-Cloud/bluemix-go/crn"

"github.com/IBM/go-sdk-core/v5/core"
"github.com/IBM/platform-services-go-sdk/resourcecontrollerv2"
)
Expand Down Expand Up @@ -66,6 +67,81 @@ func (infoSvc *CloudInfoService) ListResourcesByGroupID(resourceGroupId string)
return allResources, nil
}

func (infoSvc *CloudInfoService) GetReclamationIdFromCRN(CRN string) (string, error) {
Vipin654 marked this conversation as resolved.
Show resolved Hide resolved

parsed_crn := strings.Split(CRN, ":")

if len(parsed_crn) < 8 {

return "", fmt.Errorf("invalid crn, instance guid is not present")
}
resourceInstanceID := parsed_crn[7]
Vipin654 marked this conversation as resolved.
Show resolved Hide resolved

listReclamationsOptions := infoSvc.resourceControllerService.NewListReclamationsOptions()
listReclamationsOptions = listReclamationsOptions.SetResourceInstanceID(resourceInstanceID)
reclamationsList, _, err := infoSvc.resourceControllerService.ListReclamations(listReclamationsOptions)
if err != nil {

return "", err
}

if len(reclamationsList.Resources) == 0 {

return "", nil

}

reclamationID := *reclamationsList.Resources[0].ID

fmt.Println("reclamation id is ", reclamationID)
return reclamationID, nil
}

func (infoSvc *CloudInfoService) DeleteInstanceFromReclamationId(reclamationID string) error {

fmt.Println("Deleting the instance using reclamation id")

runReclamationActionOptions := infoSvc.resourceControllerService.NewRunReclamationActionOptions(
reclamationID,
"reclaim",
)

_, _, err := infoSvc.resourceControllerService.RunReclamationAction(runReclamationActionOptions)
if err != nil {

return err
}

fmt.Println("Instance reclaimed successfully")

return nil
}

func (infoSvc *CloudInfoService) DeleteInstanceFromReclamationByCRN(CRN string) error {

reclamationID, err := infoSvc.GetReclamationIdFromCRN(CRN)

if err != nil {

return err
}

if reclamationID == "" {

fmt.Println("No reclamation found for the given CRN")
return nil
}

err = infoSvc.DeleteInstanceFromReclamationId(reclamationID)

if err != nil {
return err
}

return nil

}

// listResourceInstances will retrieve all resources of a given type for an account
func listResourceInstances(infoSvc *CloudInfoService, options *resourcecontrollerv2.ListResourceInstancesOptions) ([]resourcecontrollerv2.ResourceInstance, error) {
// this API is paginated, but there is no pager support in the library at this time.
Expand Down
37 changes: 36 additions & 1 deletion cloudinfo/resourcecontroller_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package cloudinfo

import (
"github.com/IBM/platform-services-go-sdk/resourcemanagerv2"
"testing"

"github.com/IBM/platform-services-go-sdk/resourcemanagerv2"

"github.com/IBM/platform-services-go-sdk/resourcecontrollerv2"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -158,3 +159,37 @@ func TestListResourcesByGroupName(t *testing.T) {
assert.Equal(t, len(twoTotalList), 2)
})
}

func TestGetReclamationIDFromCrn(t *testing.T) {

infoSvc := CloudInfoService{
resourceControllerService: &resourceControllerServiceMock{},
}

var CRN string = "crn:v1:bluemix:public:my-service:theregion:a/accountnum:guid::"

_, err := infoSvc.GetReclamationIdFromCRN(CRN)
assert.Nil(t, err)

}

func TestDeleteInstanceFromReclamation(t *testing.T) {

infoSvc := CloudInfoService{
resourceControllerService: &resourceControllerServiceMock{},
}

err := infoSvc.DeleteInstanceFromReclamationId("abc")
assert.Nil(t, err)

}

func TestDeleteInstanceFromReclamationByCrn(t *testing.T) {

infoSvc := CloudInfoService{
resourceControllerService: &resourceControllerServiceMock{},
}

err := infoSvc.DeleteInstanceFromReclamationByCRN("crn:v1:bluemix:public:my-service:theregion:a/accountnum:guid::")
assert.Nil(t, err)
}
7 changes: 7 additions & 0 deletions cloudinfo/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ type CloudInfoServiceI interface {
GetSchematicsJobFileData(jobID string, fileType string, location string) (*schematics.JobFileData, error)
GetSchematicsJobPlanJson(jobID string, location string) (string, error)
GetSchematicsServiceByLocation(location string) (schematicsService, error)
GetReclamationIdFromCRN(CRN string) (string, error)
DeleteInstanceFromReclamationId(reclamationID string) error
DeleteInstanceFromReclamationByCRN(CRN string) error
}

// CloudInfoServiceOptions structure used as input params for service constructor.
Expand Down Expand Up @@ -144,7 +147,11 @@ type iamPolicyService interface {
// resourceControllerService for external Resource Controller V2 Service API. Used for mocking.
type resourceControllerService interface {
NewListResourceInstancesOptions() *resourcecontrollerv2.ListResourceInstancesOptions
NewListReclamationsOptions() *resourcecontrollerv2.ListReclamationsOptions
NewRunReclamationActionOptions(string, string) *resourcecontrollerv2.RunReclamationActionOptions
ListReclamations(*resourcecontrollerv2.ListReclamationsOptions) (*resourcecontrollerv2.ReclamationsList, *core.DetailedResponse, error)
ListResourceInstances(*resourcecontrollerv2.ListResourceInstancesOptions) (*resourcecontrollerv2.ResourceInstancesList, *core.DetailedResponse, error)
RunReclamationAction(*resourcecontrollerv2.RunReclamationActionOptions) (*resourcecontrollerv2.Reclamation, *core.DetailedResponse, error)
}

// resourceManagerService for external Resource Manager V2 Service API. Used for mocking.
Expand Down