Skip to content

Commit 8f6b530

Browse files
authored
Merge pull request #39 from GDATASoftwareAG/lb
draft: Add loadbalancer functionality
2 parents 716446e + 63c9fe5 commit 8f6b530

File tree

5 files changed

+394
-12
lines changed

5 files changed

+394
-12
lines changed

pkg/client/client.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ type userpassword struct {
2828
Tokens []string `json:"tokens,omitempty"`
2929
}
3030

31+
type Server struct {
32+
Name string
33+
ProviderID string
34+
DatacenterID string
35+
}
36+
3137
func New(datacenterId string, secret []byte) (IONOSClient, error) {
3238
var cfg *ionoscloud.Configuration
3339
if secret[0] == '{' {
@@ -65,6 +71,119 @@ func (a *IONOSClient) GetServer(ctx context.Context, providerID string) (*cloudp
6571
return a.convertServerToInstanceMetadata(ctx, &server)
6672
}
6773

74+
func (a *IONOSClient) RemoveIPFromNode(ctx context.Context, loadBalancerIP, providerID string) error {
75+
if a.client == nil {
76+
return errors.New("client isn't initialized")
77+
}
78+
79+
serverReq := a.client.NetworkInterfacesApi.DatacentersServersNicsGet(ctx, a.DatacenterId, providerID)
80+
nics, req, err := serverReq.Depth(3).Execute()
81+
if err != nil {
82+
if req != nil && req.StatusCode == 404 {
83+
return nil
84+
}
85+
return err
86+
}
87+
88+
if !nics.HasItems() {
89+
return errors.New("node has no nics")
90+
}
91+
92+
primaryNic := getPrimaryNic(*nics.Items)
93+
ips := *primaryNic.Properties.Ips
94+
95+
for idx, v := range ips {
96+
if v == loadBalancerIP {
97+
ips = append(ips[:idx], ips[idx+1:]...)
98+
}
99+
}
100+
101+
_, _, err = a.client.NetworkInterfacesApi.DatacentersServersNicsPatch(ctx, a.DatacenterId, providerID, *primaryNic.Id).Nic(ionoscloud.NicProperties{
102+
Ips: &ips,
103+
}).Execute()
104+
105+
return err
106+
}
107+
108+
func getPrimaryNic(nics []ionoscloud.Nic) *ionoscloud.Nic {
109+
for _, nic := range nics {
110+
if *nic.Properties.PciSlot == 6 {
111+
return &nic
112+
}
113+
}
114+
return nil
115+
}
116+
117+
func (a *IONOSClient) AttachIPToNode(ctx context.Context, loadBalancerIP, providerID string) (bool, error) {
118+
if a.client == nil {
119+
return false, errors.New("client isn't initialized")
120+
}
121+
122+
serverReq := a.client.NetworkInterfacesApi.DatacentersServersNicsGet(ctx, a.DatacenterId, providerID)
123+
nics, req, err := serverReq.Depth(3).Execute()
124+
if err != nil {
125+
if req != nil && req.StatusCode == 404 {
126+
return false, nil
127+
}
128+
return false, err
129+
}
130+
131+
if !nics.HasItems() {
132+
return false, errors.New("node has no nics")
133+
}
134+
135+
primaryNic := getPrimaryNic(*nics.Items)
136+
ips := *primaryNic.Properties.Ips
137+
ips = append(ips, loadBalancerIP)
138+
139+
_, _, err = a.client.NetworkInterfacesApi.DatacentersServersNicsPatch(ctx, a.DatacenterId, providerID, *primaryNic.Id).Nic(ionoscloud.NicProperties{
140+
Ips: &ips,
141+
}).Execute()
142+
143+
return true, err
144+
}
145+
146+
func (a *IONOSClient) GetServerByIP(ctx context.Context, loadBalancerIP string) (*Server, error) {
147+
if a.client == nil {
148+
return nil, errors.New("client isn't initialized")
149+
}
150+
151+
serverReq := a.client.ServersApi.DatacentersServersGet(ctx, a.DatacenterId)
152+
servers, _, err := serverReq.Depth(3).Execute()
153+
if err != nil {
154+
return nil, err
155+
}
156+
157+
if !servers.HasItems() {
158+
return nil, nil
159+
}
160+
161+
for _, server := range *servers.Items {
162+
klog.Infof("Checking server %s", server.Properties.Name)
163+
if !server.Entities.HasNics() {
164+
continue
165+
}
166+
for _, nic := range *server.Entities.Nics.Items {
167+
if nic.Properties.HasIps() {
168+
for _, ip := range *nic.Properties.Ips {
169+
klog.Infof("Found ip %s", ip)
170+
if loadBalancerIP == ip {
171+
klog.Info("Its a match!")
172+
return &Server{
173+
Name: *server.Properties.Name,
174+
ProviderID: *server.Id,
175+
DatacenterID: a.DatacenterId,
176+
}, nil
177+
}
178+
}
179+
}
180+
}
181+
}
182+
klog.Infof("IP %s not found on any node in datacenter %s", loadBalancerIP, a.DatacenterId)
183+
184+
return nil, nil
185+
}
186+
68187
func (a *IONOSClient) datacenterLocation(ctx context.Context) (string, error) {
69188
if a.client == nil {
70189
return "", errors.New("client isn't initialized")

pkg/ionos/cloud.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
func init() {
1515
cloudprovider.RegisterCloudProvider(config.RegisteredProviderName, func(cfg io.Reader) (cloudprovider.Interface, error) {
16+
1617
byConfig, err := io.ReadAll(cfg)
1718
if err != nil {
1819
klog.Errorf("ReadAll failed: %s", err)
@@ -34,19 +35,22 @@ func newProvider(config config.Config) cloudprovider.Interface {
3435
return IONOS{
3536
config: config,
3637
instances: instances{
37-
clients: map[string]*client2.IONOSClient{},
38+
ionosClients: map[string]*client2.IONOSClient{},
39+
},
40+
loadbalancer: loadbalancer{
41+
ionosClients: map[string]*client2.IONOSClient{},
3842
},
3943
}
4044
}
4145

4246
func (p IONOS) Initialize(clientBuilder cloudprovider.ControllerClientBuilder, _ <-chan struct{}) {
4347
ctx := context.Background()
44-
client, err := clientBuilder.Client(config.ClientName)
48+
k8sClient, err := clientBuilder.Client(config.ClientName)
4549
if err != nil {
4650
klog.Errorf("Kubernetes Client Init Failed: %v", err)
4751
return
4852
}
49-
secret, err := client.CoreV1().Secrets(p.config.TokenSecretNamespace).Get(ctx, p.config.TokenSecretName, metav1.GetOptions{})
53+
secret, err := k8sClient.CoreV1().Secrets(p.config.TokenSecretNamespace).Get(ctx, p.config.TokenSecretName, metav1.GetOptions{})
5054
if err != nil {
5155
klog.Errorf("Failed to get secret %s/%s: %v", p.config.TokenSecretNamespace, p.config.TokenSecretName, err)
5256
return
@@ -58,12 +62,17 @@ func (p IONOS) Initialize(clientBuilder cloudprovider.ControllerClientBuilder, _
5862
klog.Errorf("Failed to create client for datacenter %s: %v", key, err)
5963
return
6064
}
65+
66+
err = p.loadbalancer.AddClient(key, token)
67+
if err != nil {
68+
klog.Errorf("Failed to create client for datacenter %s: %v", key, err)
69+
return
70+
}
6171
}
6272
}
6373

6474
func (p IONOS) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
65-
klog.Warning("The IONOS cloud provider does not support load balancers")
66-
return nil, false
75+
return p.loadbalancer, true
6776
}
6877

6978
func (p IONOS) Instances() (cloudprovider.Instances, bool) {

pkg/ionos/instances.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@ func GetUUIDFromNode(node *v1.Node) string {
2323
}
2424

2525
func (i instances) AddClient(datacenterId string, token []byte) error {
26-
if i.clients[datacenterId] == nil {
26+
if i.ionosClients[datacenterId] == nil {
2727
c, err := client2.New(datacenterId, token)
2828
if err != nil {
2929
return err
3030
}
31-
i.clients[datacenterId] = &c
31+
i.ionosClients[datacenterId] = &c
3232
}
3333
return nil
3434
}
3535

3636
// no caching
3737
func (i instances) discoverNode(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
38-
for _, client := range i.clients {
38+
for _, client := range i.ionosClients {
3939
var err error
4040
var server *cloudprovider.InstanceMetadata
4141
providerID := GetUUIDFromNode(node)

0 commit comments

Comments
 (0)