@@ -12,15 +12,15 @@ import (
12
12
"os"
13
13
"reflect"
14
14
"strings"
15
+ "time"
16
+
17
+ "k8s.io/apimachinery/pkg/util/wait"
15
18
16
19
"github.com/ironcore-dev/fedhcp/internal/kubernetes"
17
20
ipamv1alpha1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1"
18
- ipam "github.com/ironcore-dev/ipam/clientgo/ipam"
19
- "github.com/pkg/errors"
20
21
corev1 "k8s.io/api/core/v1"
21
22
apierrors "k8s.io/apimachinery/pkg/api/errors"
22
23
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23
- "k8s.io/apimachinery/pkg/watch"
24
24
"k8s.io/client-go/kubernetes/scheme"
25
25
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
26
26
"k8s.io/client-go/tools/record"
@@ -33,22 +33,15 @@ const (
33
33
34
34
type K8sClient struct {
35
35
Client client.Client
36
- Clientset ipam.Clientset
37
36
Namespace string
38
37
SubnetNames []string
39
- Ctx context.Context
40
38
EventRecorder record.EventRecorder
41
39
}
42
40
43
41
func NewK8sClient (namespace string , subnetNames []string ) (* K8sClient , error ) {
44
42
cfg := kubernetes .GetConfig ()
45
43
cl := kubernetes .GetClient ()
46
44
47
- clientset , err := ipam .NewForConfig (cfg )
48
- if err != nil {
49
- return nil , fmt .Errorf ("failed to create IPAM clientset: %w" , err )
50
- }
51
-
52
45
corev1Client , err := corev1client .NewForConfig (cfg )
53
46
if err != nil {
54
47
return nil , fmt .Errorf ("failed to create core client: %w" , err )
@@ -66,20 +59,18 @@ func NewK8sClient(namespace string, subnetNames []string) (*K8sClient, error) {
66
59
67
60
k8sClient := K8sClient {
68
61
Client : cl ,
69
- Clientset : * clientset ,
70
62
Namespace : namespace ,
71
63
SubnetNames : subnetNames ,
72
- Ctx : context .Background (),
73
64
EventRecorder : recorder ,
74
65
}
75
66
return & k8sClient , nil
76
67
}
77
68
78
- func (k K8sClient ) createIpamIP (ipaddr net.IP , mac net.HardwareAddr ) error {
69
+ func (k K8sClient ) createIpamIP (ctx context. Context , ipaddr net.IP , mac net.HardwareAddr ) error {
79
70
// select the subnet matching the CIDR of the request
80
71
subnetMatch := false
81
72
for _ , subnetName := range k .SubnetNames {
82
- subnet , err := k .getMatchingSubnet (subnetName , ipaddr )
73
+ subnet , err := k .getMatchingSubnet (ctx , subnetName , ipaddr )
83
74
if err != nil {
84
75
return err
85
76
}
@@ -90,12 +81,12 @@ func (k K8sClient) createIpamIP(ipaddr net.IP, mac net.HardwareAddr) error {
90
81
subnetMatch = true
91
82
92
83
var ipamIP * ipamv1alpha1.IP
93
- ipamIP , err = k .prepareCreateIpamIP (subnetName , ipaddr , mac )
84
+ ipamIP , err = k .prepareCreateIpamIP (ctx , subnetName , ipaddr , mac )
94
85
if err != nil {
95
86
return err
96
87
}
97
88
if ipamIP != nil {
98
- err = k .doCreateIpamIP (ipamIP )
89
+ err = k .doCreateIpamIP (ctx , ipamIP )
99
90
if err != nil {
100
91
return err
101
92
}
@@ -111,15 +102,15 @@ func (k K8sClient) createIpamIP(ipaddr net.IP, mac net.HardwareAddr) error {
111
102
return nil
112
103
}
113
104
114
- func (k K8sClient ) getMatchingSubnet (subnetName string , ipaddr net.IP ) (* ipamv1alpha1.Subnet , error ) {
105
+ func (k K8sClient ) getMatchingSubnet (ctx context. Context , subnetName string , ipaddr net.IP ) (* ipamv1alpha1.Subnet , error ) {
115
106
subnet := & ipamv1alpha1.Subnet {
116
107
ObjectMeta : metav1.ObjectMeta {
117
108
Name : subnetName ,
118
109
Namespace : k .Namespace ,
119
110
},
120
111
}
121
112
existingSubnet := subnet .DeepCopy ()
122
- err := k .Client .Get (k . Ctx , client .ObjectKeyFromObject (subnet ), existingSubnet )
113
+ err := k .Client .Get (ctx , client .ObjectKeyFromObject (subnet ), existingSubnet )
123
114
if err != nil && ! apierrors .IsNotFound (err ) {
124
115
return nil , fmt .Errorf ("failed to get subnet %s/%s: %w" , k .Namespace , subnetName , err )
125
116
}
@@ -135,10 +126,7 @@ func (k K8sClient) getMatchingSubnet(subnetName string, ipaddr net.IP) (*ipamv1a
135
126
return subnet , nil
136
127
}
137
128
138
- func (k K8sClient ) prepareCreateIpamIP (
139
- subnetName string ,
140
- ipaddr net.IP ,
141
- mac net.HardwareAddr ) (* ipamv1alpha1.IP , error ) {
129
+ func (k K8sClient ) prepareCreateIpamIP (ctx context.Context , subnetName string , ipaddr net.IP , mac net.HardwareAddr ) (* ipamv1alpha1.IP , error ) {
142
130
ip , err := ipamv1alpha1 .IPAddrFromString (ipaddr .String ())
143
131
if err != nil {
144
132
return nil , fmt .Errorf ("failed to parse IP %s: %w" , ipaddr , err )
@@ -169,7 +157,7 @@ func (k K8sClient) prepareCreateIpamIP(
169
157
}
170
158
171
159
existingIpamIP := ipamIP .DeepCopy ()
172
- err = k .Client .Get (k . Ctx , client .ObjectKeyFromObject (ipamIP ), existingIpamIP )
160
+ err = k .Client .Get (ctx , client .ObjectKeyFromObject (ipamIP ), existingIpamIP )
173
161
if err != nil && ! apierrors .IsNotFound (err ) {
174
162
return nil , fmt .Errorf ("failed to get IP %s/%s: %w" , existingIpamIP .Namespace , existingIpamIP .Name , err )
175
163
}
@@ -183,14 +171,18 @@ func (k K8sClient) prepareCreateIpamIP(
183
171
prettyFormat (ipamIP .Spec ))
184
172
log .Infof ("Deleting old IP %s/%s" , existingIpamIP .Namespace , existingIpamIP .Name )
185
173
// delete old IP object
186
- err = k .Client .Delete (k . Ctx , existingIpamIP )
174
+ err = k .Client .Delete (ctx , existingIpamIP )
187
175
if err != nil {
188
176
return nil , fmt .Errorf ("failed to delete IP %s/%s: %w" , existingIpamIP .Namespace ,
189
177
existingIpamIP .Name , err )
190
178
}
191
179
192
- err = k .waitForDeletion (existingIpamIP )
193
- if err != nil {
180
+ if err := wait .PollUntilContextTimeout (ctx , 1 * time .Second , 30 * time .Second , true , func (ctx context.Context ) (bool , error ) {
181
+ if err := k .Client .Get (ctx , client .ObjectKeyFromObject (existingIpamIP ), existingIpamIP ); ! apierrors .IsNotFound (err ) {
182
+ return false , err
183
+ }
184
+ return true , nil
185
+ }); err != nil {
194
186
return nil , fmt .Errorf ("failed to delete IP %s/%s: %w" , existingIpamIP .Namespace ,
195
187
existingIpamIP .Name , err )
196
188
}
@@ -208,37 +200,8 @@ func (k K8sClient) prepareCreateIpamIP(
208
200
return ipamIP , nil
209
201
}
210
202
211
- func (k K8sClient ) waitForDeletion (ipamIP * ipamv1alpha1.IP ) error {
212
- // Define the namespace and resource name (if you want to watch a specific resource)
213
- namespace := ipamIP .Namespace
214
- resourceName := ipamIP .Name
215
- fieldSelector := "metadata.name=" + resourceName + ",metadata.namespace=" + namespace
216
- timeout := int64 (5 )
217
-
218
- // watch for deletion finished event
219
- watcher , err := k .Clientset .IpamV1alpha1 ().IPs (namespace ).Watch (context .TODO (), metav1.ListOptions {
220
- FieldSelector : fieldSelector ,
221
- TimeoutSeconds : & timeout ,
222
- })
223
- if err != nil {
224
- log .Errorf ("Error watching for IP: %v" , err )
225
- }
226
-
227
- log .Debugf ("Watching for changes to IP %s/%s..." , namespace , resourceName )
228
-
229
- for event := range watcher .ResultChan () {
230
- log .Debugf ("Type: %s, Object: %v\n " , event .Type , event .Object )
231
- foundIpamIP := event .Object .(* ipamv1alpha1.IP )
232
- if event .Type == watch .Deleted && reflect .DeepEqual (ipamIP .Spec , foundIpamIP .Spec ) {
233
- log .Infof ("IP %s/%s deleted" , foundIpamIP .Namespace , foundIpamIP .Name )
234
- return nil
235
- }
236
- }
237
- return errors .New ("timeout reached, IP not deleted" )
238
- }
239
-
240
- func (k K8sClient ) doCreateIpamIP (ipamIP * ipamv1alpha1.IP ) error {
241
- err := k .Client .Create (k .Ctx , ipamIP )
203
+ func (k K8sClient ) doCreateIpamIP (ctx context.Context , ipamIP * ipamv1alpha1.IP ) error {
204
+ err := k .Client .Create (ctx , ipamIP )
242
205
if err != nil && ! apierrors .IsAlreadyExists (err ) {
243
206
return fmt .Errorf ("failed to create IP %s/%s: %w" , ipamIP .Namespace , ipamIP .Name , err )
244
207
}
0 commit comments