From 4d251fe90039c30ba8f762c8dc0a9169cdfd4122 Mon Sep 17 00:00:00 2001 From: Srikanth Rao Date: Tue, 13 Oct 2020 22:36:27 +0530 Subject: [PATCH] [Digital Ocean] Implement Delete Instance logic for rolling update (#10000) * Add delete Instance implementation for DO * Add warning for DeleteInstance usage * Use reconcile option for rolling update * Update pkg/instancegroups/instancegroups.go Co-authored-by: Ciprian Hacman Co-authored-by: Ciprian Hacman --- pkg/instancegroups/instancegroups.go | 3 +- pkg/resources/digitalocean/cloud.go | 47 +++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/pkg/instancegroups/instancegroups.go b/pkg/instancegroups/instancegroups.go index bc78a8acbf..dcf065ba89 100644 --- a/pkg/instancegroups/instancegroups.go +++ b/pkg/instancegroups/instancegroups.go @@ -387,7 +387,8 @@ func (c *RollingUpdateCluster) drainTerminateAndWait(u *cloudinstances.CloudInst } func (c *RollingUpdateCluster) reconcileInstanceGroup() error { - if api.CloudProviderID(c.Cluster.Spec.CloudProvider) != api.CloudProviderOpenstack { + if api.CloudProviderID(c.Cluster.Spec.CloudProvider) != api.CloudProviderOpenstack && + api.CloudProviderID(c.Cluster.Spec.CloudProvider) != api.CloudProviderDO { return nil } rto := fi.RunTasksOptions{} diff --git a/pkg/resources/digitalocean/cloud.go b/pkg/resources/digitalocean/cloud.go index 7d4df0fc61..d950108f57 100644 --- a/pkg/resources/digitalocean/cloud.go +++ b/pkg/resources/digitalocean/cloud.go @@ -23,6 +23,7 @@ import ( "os" "strconv" "strings" + "time" "github.com/digitalocean/godo" "golang.org/x/oauth2" @@ -95,7 +96,6 @@ func NewCloud(region string) (*Cloud, error) { }, nil } -// GetCloudGroups is not implemented yet, that needs to return the instances and groups that back a kops cluster. func (c *Cloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) { return getCloudGroups(c, cluster, instancegroups, warnUnmatched, nodes) } @@ -106,10 +106,45 @@ func (c *Cloud) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error { return fmt.Errorf("digital ocean cloud provider does not support deleting cloud groups at this time") } -// DeleteInstance is not implemented yet, is func needs to delete a DO instance. func (c *Cloud) DeleteInstance(i *cloudinstances.CloudInstance) error { - klog.V(8).Info("digitalocean cloud provider DeleteInstance not implemented yet") - return fmt.Errorf("digital ocean cloud provider does not support deleting cloud instances at this time") + dropletID, err := strconv.Atoi(i.ID) + if err != nil { + return fmt.Errorf("failed to convert droplet ID to int: %s", err) + } + + _, _, err = c.Client.DropletActions.Shutdown(context.TODO(), dropletID) + if err != nil { + return fmt.Errorf("error stopping instance %q: %v", dropletID, err) + } + + // Wait for 5 min to stop the instance + for i := 0; i < 5; i++ { + droplet, _, err := c.Client.Droplets.Get(context.TODO(), dropletID) + if err != nil { + return fmt.Errorf("error describing instance %q: %v", dropletID, err) + } + + klog.V(8).Infof("stopping DO instance %q, current Status: %q", droplet, droplet.Status) + + if droplet.Status == "off" { + break + } + + if i == 5 { + return fmt.Errorf("fail to stop DO instance %v in 5 mins", dropletID) + } + + time.Sleep(time.Minute * 1) + } + + _, err = c.Client.Droplets.Delete(context.TODO(), dropletID) + if err != nil { + return fmt.Errorf("error stopping instance %q: %v", dropletID, err) + } + + klog.V(8).Infof("deleted droplet instance %q", dropletID) + + return nil } // DetachInstance is not implemented yet. It needs to cause a cloud instance to no longer be counted against the group's size limits. @@ -147,6 +182,10 @@ func (c *Cloud) Droplets() godo.DropletsService { return c.Client.Droplets } +func (c *Cloud) DropletActions() godo.DropletActionsService { + return c.Client.DropletActions +} + func (c *Cloud) LoadBalancers() godo.LoadBalancersService { return c.Client.LoadBalancers }