Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ github.com/diskfs/go-diskfs v1.4.0/go.mod h1:G8cyy+ngM+3yKlqjweMmtqvE+TxsnIo1xum
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 h1:tR3jsKPiO/mb6ntzk/dJlHZtm37CPfVp1C9KIo534+4=
github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02/go.mod h1:7NQ3kWOx2cZOSjtcveTa5nqupVr2s6/83sG+rTlI7uA=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1UgjJdAAhj+uPL68n7XASS6bU+07ZX1WJvVS2eyoeY=
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw=
Expand Down
63 changes: 62 additions & 1 deletion pkg/destroy/vsphere/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"time"

"github.com/pkg/errors"
"github.com/vmware/govmomi/cns"
cnstypes "github.com/vmware/govmomi/cns/types"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/pbm"
Expand Down Expand Up @@ -36,12 +38,15 @@ type API interface {
DeleteTag(ctx context.Context, id string) error
DeleteTagCategory(ctx context.Context, id string) error
DeleteHostZoneObjects(ctx context.Context, infraID string) error
DeleteCnsVolumes(ctx context.Context, volume cnstypes.CnsVolume) error
GetCnsVolumes(ctx context.Context, infraID string) ([]cnstypes.CnsVolume, error)
}

// Client makes calls to the Azure API.
type Client struct {
client *vim25.Client
restClient *rest.Client
cnsClient *cns.Client
cleanup vsphere.ClientLogout
}

Expand All @@ -59,10 +64,16 @@ func NewClient(vCenter, username, password string) (*Client, error) {
return nil, err
}

cnsClient, err := cns.NewClient(context.TODO(), vim25Client)
if err != nil {
return nil, err
}

return &Client{
client: vim25Client,
restClient: restClient,
cleanup: cleanup,
cnsClient: cnsClient,
}, nil
}

Expand Down Expand Up @@ -105,7 +116,7 @@ func (c *Client) getVirtualMachineManagedObjects(ctx context.Context, moRef []ty
var virtualMachineMoList []mo.VirtualMachine
if len(moRef) > 0 {
pc := property.DefaultCollector(c.client)
err := pc.Retrieve(ctx, moRef, nil, &virtualMachineMoList)
err := pc.Retrieve(ctx, moRef, []string{"name"}, &virtualMachineMoList)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -356,3 +367,53 @@ func (c *Client) DeleteHostZoneObjects(ctx context.Context, infraID string) erro

return nil
}

// GetCnsVolumes returns the list of CNS volumes associated with the cluster
// that is being destroyed.
func (c *Client) GetCnsVolumes(ctx context.Context, infraID string) ([]cnstypes.CnsVolume, error) {
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()

// Only return the volumes created with the cluster
// being destroyed
cnsQueryFilter := cnstypes.CnsQueryFilter{
ContainerClusterIds: []string{infraID},
}
cnsQuerySelection := cnstypes.CnsQuerySelection{}

volumes, err := c.cnsClient.QueryAllVolume(ctx, cnsQueryFilter, cnsQuerySelection)
if err != nil {
return nil, err
}

cnsVolumes := make([]cnstypes.CnsVolume, 0, len(volumes.Volumes))

for _, v := range volumes.Volumes {
// This must be called to retrieve the ClusterId
result, err := c.cnsClient.QueryVolume(ctx, cnstypes.CnsQueryFilter{VolumeIds: []cnstypes.CnsVolumeId{v.VolumeId}})
if err != nil {
return nil, err
}

// Confirm that the cluster id matches the infraid
for _, rv := range result.Volumes {
if rv.Metadata.ContainerCluster.ClusterId == infraID {
cnsVolumes = append(cnsVolumes, rv)
}
}
}
return cnsVolumes, nil
}

// DeleteCnsVolumes deletes the CNS volume.
func (c *Client) DeleteCnsVolumes(ctx context.Context, volume cnstypes.CnsVolume) error {
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()

// More odd VMware APIs. This is a slice but it can only take a single volume
task, err := c.cnsClient.DeleteVolume(ctx, []cnstypes.CnsVolumeId{volume.VolumeId}, true)
if err != nil {
return err
}
return task.Wait(ctx)
}
31 changes: 31 additions & 0 deletions pkg/destroy/vsphere/mock/vsphereclient_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 54 additions & 16 deletions pkg/destroy/vsphere/vsphere.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ type ClusterUninstaller struct {
ClusterID string
InfraID string
terraformPlatform string

Logger logrus.FieldLogger
clients []API
Logger logrus.FieldLogger
clients []API
}

// New returns an VSphere destroyer from ClusterMetadata.
Expand Down Expand Up @@ -51,14 +50,16 @@ func New(logger logrus.FieldLogger, metadata *installertypes.ClusterMetadata) (p
}

func newWithClient(logger logrus.FieldLogger, metadata *installertypes.ClusterMetadata, clients []API) *ClusterUninstaller {
return &ClusterUninstaller{
clusterUninstaller := &ClusterUninstaller{
ClusterID: metadata.ClusterID,
InfraID: metadata.InfraID,
terraformPlatform: metadata.VSphere.TerraformPlatform,

Logger: logger,
clients: clients,
Logger: logger,
}

return clusterUninstaller
}

func (o *ClusterUninstaller) deleteFolder(ctx context.Context) error {
Expand Down Expand Up @@ -244,22 +245,59 @@ func (o *ClusterUninstaller) deleteHostZoneObjects(ctx context.Context) error {
return utilerrors.NewAggregate(errs)
}

func (o *ClusterUninstaller) deleteCnsVolumes(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, time.Minute*30)
defer cancel()
o.Logger.Debug("Delete CNS Volumes")

for _, client := range o.clients {
cnsVolumes, err := client.GetCnsVolumes(ctx, o.InfraID)
if err != nil {
return err
}

for _, cv := range cnsVolumes {
cnsVolumeLogger := o.Logger.WithField("CNS Volume", cv.VolumeId.Id)
err := client.DeleteCnsVolumes(ctx, cv)
if err != nil {
return err
}
cnsVolumeLogger.Info("Destroyed")
}
}

return nil
}

func (o *ClusterUninstaller) destroyCluster(ctx context.Context) (bool, error) {
stagedFuncs := [][]struct {
name string
execute func(context.Context) error
}{{
{name: "Stop virtual machines", execute: o.stopVirtualMachines},
}, {
{name: "Virtual Machines", execute: o.deleteVirtualMachines},
}, {
{name: "Folder", execute: o.deleteFolder},
}, {
{name: "Storage Policy", execute: o.deleteStoragePolicy},
{name: "Tag", execute: o.deleteTag},
{name: "Tag Category", execute: o.deleteTagCategory},
}, {
{name: "VM Groups and VM Host Rules", execute: o.deleteHostZoneObjects},
{
name: "Stop virtual machines", execute: o.stopVirtualMachines,
},
{
name: "Delete Virtual Machines", execute: o.deleteVirtualMachines,
},
{
name: "Delete CNS Volumes", execute: o.deleteCnsVolumes,
},
{
name: "Folder", execute: o.deleteFolder,
},
{
name: "Storage Policy", execute: o.deleteStoragePolicy,
},
{
name: "Tag", execute: o.deleteTag,
},
{
name: "Tag Category", execute: o.deleteTagCategory,
},
{
name: "VM Groups and VM Host Rules", execute: o.deleteHostZoneObjects,
},
}}

stageFailed := false
Expand Down
1 change: 1 addition & 0 deletions vendor/github.com/vmware/govmomi/cns/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading