-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add vSphere IPI destroy #2893
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
Merged
Merged
Add vSphere IPI destroy #2893
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package vsphere | ||
|
|
||
| import ( | ||
| "github.com/openshift/installer/pkg/types" | ||
| "github.com/openshift/installer/pkg/types/vsphere" | ||
| ) | ||
|
|
||
| // Metadata converts an install configuration to vSphere metadata. | ||
| func Metadata(config *types.InstallConfig) *vsphere.Metadata { | ||
| return &vsphere.Metadata{ | ||
| VCenter: config.VSphere.VCenter, | ||
| Username: config.VSphere.Username, | ||
| Password: config.VSphere.Password, | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| // Package vsphere provides a cluster-destroyer for vsphere clusters | ||
| package vsphere |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // Package vsphere provides a cluster-destroyer for vsphere clusters. | ||
| package vsphere | ||
|
|
||
| import ( | ||
| "github.com/openshift/installer/pkg/destroy/providers" | ||
| ) | ||
|
|
||
| func init() { | ||
| providers.Registry["vsphere"] = New | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| package vsphere | ||
|
|
||
| import ( | ||
| "context" | ||
| "time" | ||
|
|
||
| "github.com/pkg/errors" | ||
| "github.com/sirupsen/logrus" | ||
|
|
||
| "github.com/vmware/govmomi/object" | ||
| "github.com/vmware/govmomi/property" | ||
| "github.com/vmware/govmomi/vapi/rest" | ||
| "github.com/vmware/govmomi/vapi/tags" | ||
| "github.com/vmware/govmomi/vim25" | ||
| "github.com/vmware/govmomi/vim25/mo" | ||
| "github.com/vmware/govmomi/vim25/types" | ||
|
|
||
| "github.com/openshift/installer/pkg/destroy/providers" | ||
| installertypes "github.com/openshift/installer/pkg/types" | ||
| vspheretypes "github.com/openshift/installer/pkg/types/vsphere" | ||
| ) | ||
|
|
||
| // ClusterUninstaller holds the various options for the cluster we want to delete. | ||
| type ClusterUninstaller struct { | ||
| ClusterID string | ||
| InfraID string | ||
|
|
||
| Client *vim25.Client | ||
| RestClient *rest.Client | ||
|
|
||
| Logger logrus.FieldLogger | ||
| } | ||
|
|
||
| // New returns an VSphere destroyer from ClusterMetadata. | ||
| func New(logger logrus.FieldLogger, metadata *installertypes.ClusterMetadata) (providers.Destroyer, error) { | ||
|
|
||
| vim25Client, restClient, err := vspheretypes.CreateVSphereClients(context.TODO(), | ||
| metadata.ClusterPlatformMetadata.VSphere.VCenter, | ||
| metadata.ClusterPlatformMetadata.VSphere.Username, | ||
| metadata.ClusterPlatformMetadata.VSphere.Password) | ||
|
|
||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return &ClusterUninstaller{ | ||
| ClusterID: metadata.ClusterID, | ||
| InfraID: metadata.InfraID, | ||
| Client: vim25Client, | ||
| RestClient: restClient, | ||
| Logger: logger, | ||
| }, nil | ||
| } | ||
|
|
||
| func deleteVirtualMachines(ctx context.Context, client *vim25.Client, virtualMachineMoList []mo.VirtualMachine, parentFolder mo.Folder, logger logrus.FieldLogger) error { | ||
| ctx, cancel := context.WithTimeout(ctx, time.Minute*30) | ||
| defer cancel() | ||
|
|
||
| if len(virtualMachineMoList) != 0 { | ||
| for _, vmMO := range virtualMachineMoList { | ||
| virtualMachineLogger := logger.WithField("VirtualMachine", vmMO.Name) | ||
| // Checking if the Folder mobRef is the same as the VirtualMachine parent mobRef | ||
| if parentFolder.Reference() == vmMO.Parent.Reference() { | ||
| vm := object.NewVirtualMachine(client, vmMO.Reference()) | ||
| if vmMO.Summary.Runtime.PowerState == "poweredOn" { | ||
| task, err := vm.PowerOff(ctx) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| task.Wait(ctx) | ||
| virtualMachineLogger.Debug("Powered off") | ||
| } | ||
|
|
||
| task, err := vm.Destroy(ctx) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| task.Wait(ctx) | ||
| virtualMachineLogger.Info("Destroyed") | ||
| } | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
| func deleteFolder(ctx context.Context, client *vim25.Client, folderMoList []mo.Folder, logger logrus.FieldLogger) error { | ||
| ctx, cancel := context.WithTimeout(ctx, time.Second*60) | ||
| defer cancel() | ||
|
|
||
| // If there are no children in the folder go ahead an remove it | ||
| if len(folderMoList[0].ChildEntity) == 0 { | ||
| folderLogger := logger.WithField("Folder", folderMoList[0].Name) | ||
|
|
||
| folder := object.NewFolder(client, folderMoList[0].Reference()) | ||
| task, err := folder.Destroy(ctx) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| task.Wait(ctx) | ||
| folderLogger.Info("Destroyed") | ||
| } else { | ||
| return errors.Errorf("Expected Folder %s to be empty", folderMoList[0].Name) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
| func getFolderManagedObjects(ctx context.Context, client *vim25.Client, moRef []types.ManagedObjectReference) ([]mo.Folder, error) { | ||
| var folderMoList []mo.Folder | ||
| pc := property.DefaultCollector(client) | ||
| err := pc.Retrieve(ctx, moRef, nil, &folderMoList) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return folderMoList, nil | ||
| } | ||
| func getVirtualMachineManagedObjects(ctx context.Context, client *vim25.Client, moRef []types.ManagedObjectReference) ([]mo.VirtualMachine, error) { | ||
| var virtualMachineMoList []mo.VirtualMachine | ||
|
|
||
| pc := property.DefaultCollector(client) | ||
| err := pc.Retrieve(ctx, moRef, nil, &virtualMachineMoList) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return virtualMachineMoList, nil | ||
| } | ||
|
|
||
| func getAttachedObjectsOnTag(ctx context.Context, client *rest.Client, tagName string) ([]tags.AttachedObjects, error) { | ||
| tagManager := tags.NewManager(client) | ||
| attached, err := tagManager.GetAttachedObjectsOnTags(ctx, []string{tagName}) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return attached, nil | ||
| } | ||
|
|
||
| // Run is the entrypoint to start the uninstall process. | ||
| func (o *ClusterUninstaller) Run() error { | ||
| var folderList []types.ManagedObjectReference | ||
| var virtualMachineList []types.ManagedObjectReference | ||
|
|
||
| o.Logger.Debug("find attached objects on tag") | ||
| tagAttachedObjects, err := getAttachedObjectsOnTag(context.TODO(), o.RestClient, o.InfraID) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Seperate the objects attached to the tag based on type | ||
| // We only need Folder and VirtualMachine | ||
| for _, attachedObject := range tagAttachedObjects { | ||
| for _, ref := range attachedObject.ObjectIDs { | ||
| if ref.Reference().Type == "Folder" { | ||
| folderList = append(folderList, ref.Reference()) | ||
| } | ||
| if ref.Reference().Type == "VirtualMachine" { | ||
| virtualMachineList = append(virtualMachineList, ref.Reference()) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // There should be exactly one Folder which is created by | ||
| // terraform. That is the parent to the VirtualMachines. | ||
| // If there are more or less fail with error message. | ||
| if len(folderList) != 1 { | ||
| return errors.Errorf("Expected 1 Folder per tag but got %d", len(folderList)) | ||
| } | ||
|
|
||
| o.Logger.Debug("find Folder objects") | ||
| folderMoList, err := getFolderManagedObjects(context.TODO(), o.Client, folderList) | ||
|
|
||
| o.Logger.Debug("find VirtualMachine objects") | ||
| virtualMachineMoList, err := getVirtualMachineManagedObjects(context.TODO(), o.Client, virtualMachineList) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| o.Logger.Debug("delete VirtualMachines") | ||
| err = deleteVirtualMachines(context.TODO(), o.Client, virtualMachineMoList, folderMoList[0], o.Logger) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // When removing virtual machines the mo.Folder object does not change | ||
| // We need to re-retrieve the list again | ||
| o.Logger.Debug("find Folder objects") | ||
| folderMoList = nil | ||
| folderMoList, err = getFolderManagedObjects(context.TODO(), o.Client, folderList) | ||
| if err != nil { | ||
| o.Logger.Errorln(err) | ||
| return err | ||
| } | ||
|
|
||
| o.Logger.Debug("delete Folder") | ||
| err = deleteFolder(context.TODO(), o.Client, folderMoList, o.Logger) | ||
| if err != nil { | ||
| o.Logger.Errorln(err) | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package vsphere | ||
|
|
||
| import ( | ||
| "context" | ||
| "net/url" | ||
| "time" | ||
|
|
||
| "github.com/vmware/govmomi" | ||
| "github.com/vmware/govmomi/vapi/rest" | ||
| "github.com/vmware/govmomi/vim25" | ||
| "github.com/vmware/govmomi/vim25/soap" | ||
| ) | ||
|
|
||
| // CreateVSphereClients creates the SOAP and REST client to access | ||
| // different portions of the vSphere API | ||
| // e.g. tags are only available in REST | ||
| func CreateVSphereClients(ctx context.Context, vcenter, username, password string) (*vim25.Client, *rest.Client, error) { | ||
| ctx, cancel := context.WithTimeout(ctx, 60*time.Second) | ||
| defer cancel() | ||
|
|
||
| u, err := soap.ParseURL(vcenter) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
| u.User = url.UserPassword(username, password) | ||
| c, err := govmomi.NewClient(ctx, u, false) | ||
|
|
||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
|
|
||
| restClient := rest.NewClient(c.Client) | ||
| err = restClient.Login(ctx, u.User) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
|
|
||
| return c.Client, restClient, nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package vsphere | ||
|
|
||
| // Metadata contains vSphere metadata (e.g. for uninstalling the cluster). | ||
| type Metadata struct { | ||
| // VCenter is the domain name or IP address of the vCenter. | ||
| VCenter string `json:"vCenter"` | ||
| // Username is the name of the user to use to connect to the vCenter. | ||
| Username string `json:"username"` | ||
| // Password is the password for the user to use to connect to the vCenter. | ||
| Password string `json:"password"` | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jstuever ^