Skip to content
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

draft: Add loadbalancer functionality #39

Merged
merged 2 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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
Loading