Skip to content

Commit

Permalink
Merge pull request #39 from GDATASoftwareAG/lb
Browse files Browse the repository at this point in the history
draft: Add loadbalancer functionality
  • Loading branch information
Mattes83 authored Jul 4, 2024
2 parents 716446e + 63c9fe5 commit 8f6b530
Show file tree
Hide file tree
Showing 5 changed files with 394 additions and 12 deletions.
119 changes: 119 additions & 0 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ type userpassword struct {
Tokens []string `json:"tokens,omitempty"`
}

type Server struct {
Name string
ProviderID string
DatacenterID string
}

func New(datacenterId string, secret []byte) (IONOSClient, error) {
var cfg *ionoscloud.Configuration
if secret[0] == '{' {
Expand Down Expand Up @@ -65,6 +71,119 @@ func (a *IONOSClient) GetServer(ctx context.Context, providerID string) (*cloudp
return a.convertServerToInstanceMetadata(ctx, &server)
}

func (a *IONOSClient) RemoveIPFromNode(ctx context.Context, loadBalancerIP, providerID string) error {
if a.client == nil {
return errors.New("client isn't initialized")
}

serverReq := a.client.NetworkInterfacesApi.DatacentersServersNicsGet(ctx, a.DatacenterId, providerID)
nics, req, err := serverReq.Depth(3).Execute()
if err != nil {
if req != nil && req.StatusCode == 404 {
return nil
}
return err
}

if !nics.HasItems() {
return errors.New("node has no nics")
}

primaryNic := getPrimaryNic(*nics.Items)
ips := *primaryNic.Properties.Ips

for idx, v := range ips {
if v == loadBalancerIP {
ips = append(ips[:idx], ips[idx+1:]...)
}
}

_, _, err = a.client.NetworkInterfacesApi.DatacentersServersNicsPatch(ctx, a.DatacenterId, providerID, *primaryNic.Id).Nic(ionoscloud.NicProperties{
Ips: &ips,
}).Execute()

return err
}

func getPrimaryNic(nics []ionoscloud.Nic) *ionoscloud.Nic {
for _, nic := range nics {
if *nic.Properties.PciSlot == 6 {
return &nic
}
}
return nil
}

func (a *IONOSClient) AttachIPToNode(ctx context.Context, loadBalancerIP, providerID string) (bool, error) {
if a.client == nil {
return false, errors.New("client isn't initialized")
}

serverReq := a.client.NetworkInterfacesApi.DatacentersServersNicsGet(ctx, a.DatacenterId, providerID)
nics, req, err := serverReq.Depth(3).Execute()
if err != nil {
if req != nil && req.StatusCode == 404 {
return false, nil
}
return false, err
}

if !nics.HasItems() {
return false, errors.New("node has no nics")
}

primaryNic := getPrimaryNic(*nics.Items)
ips := *primaryNic.Properties.Ips
ips = append(ips, loadBalancerIP)

_, _, err = a.client.NetworkInterfacesApi.DatacentersServersNicsPatch(ctx, a.DatacenterId, providerID, *primaryNic.Id).Nic(ionoscloud.NicProperties{
Ips: &ips,
}).Execute()

return true, err
}

func (a *IONOSClient) GetServerByIP(ctx context.Context, loadBalancerIP string) (*Server, error) {
if a.client == nil {
return nil, errors.New("client isn't initialized")
}

serverReq := a.client.ServersApi.DatacentersServersGet(ctx, a.DatacenterId)
servers, _, err := serverReq.Depth(3).Execute()
if err != nil {
return nil, err
}

if !servers.HasItems() {
return nil, nil
}

for _, server := range *servers.Items {
klog.Infof("Checking server %s", server.Properties.Name)
if !server.Entities.HasNics() {
continue
}
for _, nic := range *server.Entities.Nics.Items {
if nic.Properties.HasIps() {
for _, ip := range *nic.Properties.Ips {
klog.Infof("Found ip %s", ip)
if loadBalancerIP == ip {
klog.Info("Its a match!")
return &Server{
Name: *server.Properties.Name,
ProviderID: *server.Id,
DatacenterID: a.DatacenterId,
}, nil
}
}
}
}
}
klog.Infof("IP %s not found on any node in datacenter %s", loadBalancerIP, a.DatacenterId)

return nil, nil
}

func (a *IONOSClient) datacenterLocation(ctx context.Context) (string, error) {
if a.client == nil {
return "", errors.New("client isn't initialized")
Expand Down
19 changes: 14 additions & 5 deletions pkg/ionos/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

func init() {
cloudprovider.RegisterCloudProvider(config.RegisteredProviderName, func(cfg io.Reader) (cloudprovider.Interface, error) {

byConfig, err := io.ReadAll(cfg)
if err != nil {
klog.Errorf("ReadAll failed: %s", err)
Expand All @@ -34,19 +35,22 @@ func newProvider(config config.Config) cloudprovider.Interface {
return IONOS{
config: config,
instances: instances{
clients: map[string]*client2.IONOSClient{},
ionosClients: map[string]*client2.IONOSClient{},
},
loadbalancer: loadbalancer{
ionosClients: map[string]*client2.IONOSClient{},
},
}
}

func (p IONOS) Initialize(clientBuilder cloudprovider.ControllerClientBuilder, _ <-chan struct{}) {
ctx := context.Background()
client, err := clientBuilder.Client(config.ClientName)
k8sClient, err := clientBuilder.Client(config.ClientName)
if err != nil {
klog.Errorf("Kubernetes Client Init Failed: %v", err)
return
}
secret, err := client.CoreV1().Secrets(p.config.TokenSecretNamespace).Get(ctx, p.config.TokenSecretName, metav1.GetOptions{})
secret, err := k8sClient.CoreV1().Secrets(p.config.TokenSecretNamespace).Get(ctx, p.config.TokenSecretName, metav1.GetOptions{})
if err != nil {
klog.Errorf("Failed to get secret %s/%s: %v", p.config.TokenSecretNamespace, p.config.TokenSecretName, err)
return
Expand All @@ -58,12 +62,17 @@ func (p IONOS) Initialize(clientBuilder cloudprovider.ControllerClientBuilder, _
klog.Errorf("Failed to create client for datacenter %s: %v", key, err)
return
}

err = p.loadbalancer.AddClient(key, token)
if err != nil {
klog.Errorf("Failed to create client for datacenter %s: %v", key, err)
return
}
}
}

func (p IONOS) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
klog.Warning("The IONOS cloud provider does not support load balancers")
return nil, false
return p.loadbalancer, true
}

func (p IONOS) Instances() (cloudprovider.Instances, bool) {
Expand Down
6 changes: 3 additions & 3 deletions pkg/ionos/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ func GetUUIDFromNode(node *v1.Node) string {
}

func (i instances) AddClient(datacenterId string, token []byte) error {
if i.clients[datacenterId] == nil {
if i.ionosClients[datacenterId] == nil {
c, err := client2.New(datacenterId, token)
if err != nil {
return err
}
i.clients[datacenterId] = &c
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.clients {
for _, client := range i.ionosClients {
var err error
var server *cloudprovider.InstanceMetadata
providerID := GetUUIDFromNode(node)
Expand Down
Loading

0 comments on commit 8f6b530

Please sign in to comment.