diff --git a/pkg/client/client.go b/pkg/client/client.go index 96086c5..cb3d2a9 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -35,6 +35,13 @@ type Server struct { DatacenterID string } +type Volume struct { + ID string + Name string + ServerID string + DatacenterID string +} + func New(datacenterId string, secret []byte) (IONOSClient, error) { var cfg *ionoscloud.Configuration if secret[0] == '{' { @@ -72,6 +79,35 @@ func (a *IONOSClient) GetServer(ctx context.Context, providerID string) (*cloudp return a.convertServerToInstanceMetadata(ctx, &server) } +func (a *IONOSClient) GetServerVolumes(ctx context.Context, providerID string) ([]Volume, error) { + if a.client == nil { + return nil, errors.New("client isn't initialized") + } + volumesReq := a.client.ServersApi.DatacentersServersVolumesGet(ctx, a.DatacenterId, providerID) + volumes, req, err := volumesReq.Depth(1).Execute() + if err != nil || req != nil && req.StatusCode == 404 { + if err != nil { + return nil, nil + } + return nil, err + } + + var list []Volume + + for _, volume := range *volumes.Items { + if volume.Properties == nil { + continue + } + list = append(list, Volume{ + DatacenterID: a.DatacenterId, + ServerID: providerID, + ID: *volume.Id, + Name: *volume.Properties.Name, + }) + } + return list, nil +} + func (a *IONOSClient) RemoveIPFromNode(ctx context.Context, loadBalancerIP, providerID string) error { if a.client == nil { return errors.New("client isn't initialized") diff --git a/pkg/ionos/instances.go b/pkg/ionos/instances.go index c4fa75a..1b628c2 100644 --- a/pkg/ionos/instances.go +++ b/pkg/ionos/instances.go @@ -1,79 +1,100 @@ package ionos import ( - "context" - "errors" - "fmt" - "strings" + "context" + "errors" + "fmt" + "strings" - v1 "k8s.io/api/core/v1" - cloudprovider "k8s.io/cloud-provider" - "k8s.io/klog/v2" + v1 "k8s.io/api/core/v1" + cloudprovider "k8s.io/cloud-provider" + "k8s.io/klog/v2" - client2 "github.com/GDATASoftwareAG/cloud-provider-ionoscloud/pkg/client" - "github.com/GDATASoftwareAG/cloud-provider-ionoscloud/pkg/config" + client2 "github.com/GDATASoftwareAG/cloud-provider-ionoscloud/pkg/client" + "github.com/GDATASoftwareAG/cloud-provider-ionoscloud/pkg/config" ) var _ cloudprovider.InstancesV2 = &instances{} func GetUUIDFromNode(node *v1.Node) string { - if node == nil { - return "" - } - withoutPrefix := strings.TrimPrefix(node.Spec.ProviderID, config.ProviderPrefix) - return strings.ToLower(strings.TrimSpace(withoutPrefix)) + if node == nil { + return "" + } + return ProviderIDWitPrefix(node.Spec.ProviderID) +} + +func ProviderIDWitPrefix(providerID string) string { + withoutPrefix := strings.TrimPrefix(providerID, config.ProviderPrefix) + return strings.ToLower(strings.TrimSpace(withoutPrefix)) } func (i instances) AddClient(datacenterId string, token []byte) error { - if i.ionosClients[datacenterId] == nil { - c, err := client2.New(datacenterId, token) - if err != nil { - return err - } - i.ionosClients[datacenterId] = &c - } - return nil + if i.ionosClients[datacenterId] == nil { + c, err := client2.New(datacenterId, token) + if err != nil { + return err + } + i.ionosClients[datacenterId] = &c + } + return nil } // no caching -func (i instances) discoverNode(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) { - for _, client := range i.ionosClients { - var err error - var server *cloudprovider.InstanceMetadata - providerID := GetUUIDFromNode(node) - klog.Infof("discoverNode (datacenterId %s) %s %s", client.DatacenterId, node.Name, providerID) - if providerID != "" { - server, err = client.GetServer(ctx, providerID) - } else { - server, err = client.GetServerByName(ctx, node.Name) - } - if err != nil { - return nil, fmt.Errorf("failed to discoverNode %v", err) - } - if server == nil { - continue - } - return server, nil - } - return nil, errors.New("failed to discoverNode") +func (i instances) discoverNode(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, *client2.IONOSClient, error) { + for _, client := range i.ionosClients { + var err error + var server *cloudprovider.InstanceMetadata + providerID := GetUUIDFromNode(node) + klog.Infof("discoverNode (datacenterId %s) %s %s", client.DatacenterId, node.Name, providerID) + if providerID != "" { + server, err = client.GetServer(ctx, providerID) + } else { + server, err = client.GetServerByName(ctx, node.Name) + } + if err != nil { + return nil, nil, fmt.Errorf("failed to discoverNode %v", err) + } + if server == nil { + continue + } + return server, client, nil + } + return nil, nil, nil } func (i instances) InstanceExists(ctx context.Context, node *v1.Node) (bool, error) { - klog.Infof("InstanceExists %s", node.Name) - server, err := i.discoverNode(ctx, node) - klog.InfoDepth(1, server) - return server != nil, err + klog.Infof("InstanceExists %s", node.Name) + server, _, err := i.discoverNode(ctx, node) + klog.InfoDepth(1, server) + return server != nil, err } -func (i instances) InstanceShutdown(_ context.Context, node *v1.Node) (bool, error) { - klog.Infof("InstanceShutdown %s", node.Name) - // TODO check here for mounted volumes - return true, nil +func (i instances) InstanceShutdown(ctx context.Context, node *v1.Node) (bool, error) { + klog.Infof("InstanceShutdown %s", node.Name) + server, client, err := i.discoverNode(ctx, node) + if (server == nil && err == nil) || server == nil { + return true, nil + } + + volumes, err := client.GetServerVolumes(ctx, ProviderIDWitPrefix(server.ProviderID)) + if err != nil { + return false, err + } + + for _, volume := range volumes { + if strings.HasPrefix(volume.Name, "csi-pv.k8s.") { + return false, nil + } + } + return true, nil } func (i instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) { - klog.Infof("InstanceMetadata %s", node.Name) - server, err := i.discoverNode(ctx, node) - klog.InfoDepth(1, server) - return server, err + klog.Infof("InstanceMetadata %s", node.Name) + server, _, err := i.discoverNode(ctx, node) + if server == nil && err == nil { + return nil, errors.New("failed to discoverNode") + } + klog.InfoDepth(1, server) + return server, err }