Skip to content

Commit f5bfa30

Browse files
committed
refactor: updated IP controller for new ipam
1 parent 1d7ef60 commit f5bfa30

File tree

25 files changed

+435
-227
lines changed

25 files changed

+435
-227
lines changed

apis/ipam/v1alpha1/ip_types.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ type IPSpec struct {
4949
// IP is the local IP.
5050
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="IP field is immutable"
5151
IP networkingv1beta1.IP `json:"ip"`
52-
// CIDR is the network CIDR where the desired IP should be allocated from.
52+
// NetworkRef is the reference to the Network CR containing the CIDR where the desired IP should be allocated from.
5353
// It is optional, if left empty the IP will be allocated in a default network CIDR (e.g., external CIDR).
5454
// +kubebuilder:validation:Optional
55-
CIDR *networkingv1beta1.CIDR `json:"cidr,omitempty"`
55+
NetworkRef *v1.ObjectReference `json:"cidr,omitempty"`
5656
// ServiceTemplate contains the template to create the associated service (and endpointslice) for the IP endopoint.
5757
// If empty the creation of the service is disabled (default).
5858
// +kubebuilder:validation:Optional
@@ -65,8 +65,6 @@ type IPSpec struct {
6565

6666
// IPStatus defines remapped IPs.
6767
type IPStatus struct {
68-
// IPMappings contains the mapping of the local IP for each remote cluster.
69-
IPMappings map[string]networkingv1beta1.IP `json:"ipMappings,omitempty"`
7068
// IP is the remapped IP.
7169
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="IP field is immutable"
7270
IP networkingv1beta1.IP `json:"ip"`

apis/ipam/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/liqo-controller-manager/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ func main() {
260260
ipamClient = ipam.NewIPAMClient(conn)
261261
}
262262

263-
if err := modules.SetupNetworkingModule(ctx, mgr, &modules.NetworkingOption{
263+
if err := modules.SetupNetworkingModule(mgr, &modules.NetworkingOption{
264264
DynClient: dynClient,
265265
Factory: factory,
266266

cmd/liqo-controller-manager/modules/networking.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
package modules
1616

1717
import (
18-
"context"
19-
2018
"k8s.io/client-go/dynamic"
2119
"k8s.io/klog/v2"
2220
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -35,6 +33,7 @@ import (
3533
nodecontroller "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/internal-network/node-controller"
3634
"github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/internal-network/route"
3735
internalservercontroller "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/internal-network/server-controller"
36+
ipctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/ip-controller"
3837
networkctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/network-controller"
3938
dynamicutils "github.com/liqotech/liqo/pkg/utils/dynamic"
4039
)
@@ -60,19 +59,18 @@ type NetworkingOption struct {
6059
}
6160

6261
// SetupNetworkingModule setup the networking module and initializes its controllers .
63-
func SetupNetworkingModule(ctx context.Context, mgr manager.Manager, opts *NetworkingOption) error {
62+
func SetupNetworkingModule(mgr manager.Manager, opts *NetworkingOption) error {
6463
networkReconciler := networkctrl.NewNetworkReconciler(mgr.GetClient(), mgr.GetScheme(), opts.IpamClient)
6564
if err := networkReconciler.SetupWithManager(mgr, opts.NetworkWorkers); err != nil {
6665
klog.Errorf("Unable to start the networkReconciler: %v", err)
6766
return err
6867
}
6968

70-
// TODO: refactor IP reconciler with the new IPAM client.
71-
// ipReconciler := ipctrl.NewIPReconciler(mgr.GetClient(), mgr.GetScheme(), opts.IpamClient)
72-
// if err := ipReconciler.SetupWithManager(ctx, mgr, opts.IPWorkers); err != nil {
73-
// klog.Errorf("Unable to start the ipReconciler: %v", err)
74-
// return err
75-
// }
69+
ipReconciler := ipctrl.NewIPReconciler(mgr.GetClient(), mgr.GetScheme(), opts.IpamClient)
70+
if err := ipReconciler.SetupWithManager(mgr, opts.IPWorkers); err != nil {
71+
klog.Errorf("Unable to start the ipReconciler: %v", err)
72+
return err
73+
}
7674

7775
cfgReconciler := configuration.NewConfigurationReconciler(mgr.GetClient(), mgr.GetScheme(),
7876
mgr.GetEventRecorderFor("configuration-controller"))

deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_ips.yaml

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,49 @@ spec:
5454
properties:
5555
cidr:
5656
description: |-
57-
CIDR is the network CIDR where the desired IP should be allocated from.
57+
NetworkRef is the reference to the Network CR containing the CIDR where the desired IP should be allocated from.
5858
It is optional, if left empty the IP will be allocated in a default network CIDR (e.g., external CIDR).
59-
format: cidr
60-
type: string
59+
properties:
60+
apiVersion:
61+
description: API version of the referent.
62+
type: string
63+
fieldPath:
64+
description: |-
65+
If referring to a piece of an object instead of an entire object, this string
66+
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
67+
For example, if the object reference is to a container within a pod, this would take on a value like:
68+
"spec.containers{name}" (where "name" refers to the name of the container that triggered
69+
the event) or if no container name is specified "spec.containers[2]" (container with
70+
index 2 in this pod). This syntax is chosen only to have some well-defined way of
71+
referencing a part of an object.
72+
type: string
73+
kind:
74+
description: |-
75+
Kind of the referent.
76+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
77+
type: string
78+
name:
79+
description: |-
80+
Name of the referent.
81+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
82+
type: string
83+
namespace:
84+
description: |-
85+
Namespace of the referent.
86+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
87+
type: string
88+
resourceVersion:
89+
description: |-
90+
Specific resourceVersion to which this reference is made, if any.
91+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
92+
type: string
93+
uid:
94+
description: |-
95+
UID of the referent.
96+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
97+
type: string
98+
type: object
99+
x-kubernetes-map-type: atomic
61100
ip:
62101
description: IP is the local IP.
63102
format: ipv4
@@ -456,14 +495,6 @@ spec:
456495
x-kubernetes-validations:
457496
- message: IP field is immutable
458497
rule: self == oldSelf
459-
ipMappings:
460-
additionalProperties:
461-
description: IP defines a syntax validated IP.
462-
format: ipv4
463-
type: string
464-
description: IPMappings contains the mapping of the local IP for each
465-
remote cluster.
466-
type: object
467498
required:
468499
- ip
469500
type: object

pkg/ipam/sync_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
. "github.com/onsi/gomega"
2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2424
"k8s.io/client-go/kubernetes/scheme"
25-
"k8s.io/utils/ptr"
2625
"sigs.k8s.io/controller-runtime/pkg/client/fake"
2726

2827
ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
@@ -81,8 +80,7 @@ var _ = Describe("Sync routine tests", func() {
8180
Namespace: testNamespace,
8281
},
8382
Spec: ipamv1alpha1.IPSpec{
84-
IP: networkingv1beta1.IP(ip),
85-
CIDR: ptr.To(networkingv1beta1.CIDR(cidr)),
83+
IP: networkingv1beta1.IP(ip),
8684
},
8785
Status: ipamv1alpha1.IPStatus{
8886
IP: networkingv1beta1.IP(ip),

pkg/ipam/utils/doc.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2019-2024 The Liqo Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package utils contain utility functions for the IPAM package.
16+
package utils

pkg/ipam/utils/utils.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2019-2024 The Liqo Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package utils
16+
17+
import (
18+
"fmt"
19+
"net"
20+
"net/netip"
21+
22+
"go4.org/netipx"
23+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
24+
25+
"github.com/liqotech/liqo/pkg/consts"
26+
)
27+
28+
// MapIPToNetwork creates a new IP address obtained by means of the old IP address and the new network.
29+
func MapIPToNetwork(newNetwork, oldIP string) (newIP string, err error) {
30+
if newNetwork == consts.DefaultCIDRValue {
31+
return oldIP, nil
32+
}
33+
// Parse newNetwork
34+
ip, network, err := net.ParseCIDR(newNetwork)
35+
if err != nil {
36+
return "", err
37+
}
38+
// Get mask
39+
mask := network.Mask
40+
// Get slice of bytes for newNetwork
41+
// Type net.IP has underlying type []byte
42+
parsedNewIP := ip.To4()
43+
// Get oldIP as slice of bytes
44+
parsedOldIP := net.ParseIP(oldIP)
45+
if parsedOldIP == nil {
46+
return "", fmt.Errorf("cannot parse oldIP")
47+
}
48+
parsedOldIP = parsedOldIP.To4()
49+
// Substitute the last 32-mask bits of newNetwork with bits taken by the old ip
50+
for i := 0; i < len(mask); i++ {
51+
// Step 1: NOT(mask[i]) = mask[i] ^ 0xff. They are the 'host' bits
52+
// Step 2: BITWISE AND between the host bits and parsedOldIP[i] zeroes the network bits in parsedOldIP[i]
53+
// Step 3: BITWISE OR copies the result of step 2 in newIP[i]
54+
parsedNewIP[i] |= (mask[i] ^ 0xff) & parsedOldIP[i]
55+
}
56+
newIP = parsedNewIP.String()
57+
return
58+
}
59+
60+
// GetMask retrieves the mask from a CIDR.
61+
func GetMask(network string) uint8 {
62+
_, subnet, err := net.ParseCIDR(network)
63+
utilruntime.Must(err)
64+
ones, _ := subnet.Mask.Size()
65+
return uint8(ones)
66+
}
67+
68+
// SetMask forges a new cidr from a network cidr and a mask.
69+
func SetMask(network string, mask uint8) string {
70+
_, n, err := net.ParseCIDR(network)
71+
utilruntime.Must(err)
72+
newMask := net.CIDRMask(int(mask), 32)
73+
n.Mask = newMask
74+
return n.String()
75+
}
76+
77+
// Next used to get the second half of a given network.
78+
func Next(network string) string {
79+
prefix, err := netip.ParsePrefix(network)
80+
utilruntime.Must(err)
81+
// Step 1: Get last IP address of network
82+
// Step 2: Get next IP address
83+
firstIP := netipx.RangeOfPrefix(prefix).To().Next()
84+
prefix = netip.PrefixFrom(firstIP, prefix.Bits())
85+
return prefix.String()
86+
}
87+
88+
// IsValidCIDR returns an error if the received CIDR is invalid.
89+
func IsValidCIDR(cidr string) error {
90+
_, _, err := net.ParseCIDR(cidr)
91+
return err
92+
}
93+
94+
// SplitNetwork returns the two halves that make up a given network.
95+
func SplitNetwork(network string) []string {
96+
halves := make([]string, 2)
97+
98+
// Get halves mask length.
99+
mask := GetMask(network)
100+
mask++
101+
102+
// Get first half CIDR.
103+
halves[0] = SetMask(network, mask)
104+
105+
// Get second half CIDR.
106+
halves[1] = Next(halves[0])
107+
108+
return halves
109+
}

pkg/ipam/utils/utils_suite_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2019-2024 The Liqo Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package utils_test
16+
17+
import (
18+
"testing"
19+
20+
. "github.com/onsi/ginkgo/v2"
21+
. "github.com/onsi/gomega"
22+
)
23+
24+
func TestUtils(t *testing.T) {
25+
RegisterFailHandler(Fail)
26+
RunSpecs(t, "Utils Suite")
27+
}

0 commit comments

Comments
 (0)