Skip to content

Commit e3c9c26

Browse files
committed
initialize ipam
1 parent 1dd9d1f commit e3c9c26

File tree

5 files changed

+194
-5
lines changed

5 files changed

+194
-5
lines changed

apis/ipam/v1alpha1/ip_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ type IPSpec struct {
6363
type IPStatus struct {
6464
// IPMappings contains the mapping of the local IP for each remote cluster.
6565
IPMappings map[string]networkingv1beta1.IP `json:"ipMappings,omitempty"`
66+
// IP is the remapped IP.
67+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="IP field is immutable"
68+
IP networkingv1beta1.IP `json:"ip"`
69+
// CIDR is the network CIDR where the IP is allocated.
70+
CIDR networkingv1beta1.CIDR `json:"cidr,omitempty"`
6671
}
6772

6873
// +kubebuilder:object:root=true

cmd/ipam/main.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"k8s.io/client-go/tools/record"
3232
"k8s.io/klog/v2"
3333
ctrl "sigs.k8s.io/controller-runtime"
34+
"sigs.k8s.io/controller-runtime/pkg/client"
3435
"sigs.k8s.io/controller-runtime/pkg/log"
3536

3637
ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
@@ -101,6 +102,12 @@ func run(cmd *cobra.Command, _ []string) error {
101102

102103
// Get the rest config.
103104
cfg := restcfg.SetRateLimiter(ctrl.GetConfigOrDie())
105+
options.Config = cfg
106+
cl, err := client.New(cfg, client.Options{})
107+
if err != nil {
108+
return err
109+
}
110+
options.Client = cl
104111

105112
if options.EnableLeaderElection {
106113
if leader, err := leaderelection.Blocking(ctx, cfg, record.NewBroadcaster(), &leaderelection.Opts{
@@ -123,7 +130,10 @@ func run(cmd *cobra.Command, _ []string) error {
123130
hs := health.NewServer()
124131
options.HealthServer = hs
125132

126-
liqoIPAM := ipam.New(&options)
133+
liqoIPAM, err := ipam.New(ctx, &options)
134+
if err != nil {
135+
return err
136+
}
127137

128138
lis, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", options.Port))
129139
if err != nil {

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,17 @@ spec:
439439
status:
440440
description: IPStatus defines remapped IPs.
441441
properties:
442+
cidr:
443+
description: CIDR is the network CIDR where the IP is allocated.
444+
format: cidr
445+
type: string
446+
ip:
447+
description: IP is the remapped IP.
448+
format: ipv4
449+
type: string
450+
x-kubernetes-validations:
451+
- message: IP field is immutable
452+
rule: self == oldSelf
442453
ipMappings:
443454
additionalProperties:
444455
description: IP defines a syntax validated IP.
@@ -447,6 +458,8 @@ spec:
447458
description: IPMappings contains the mapping of the local IP for each
448459
remote cluster.
449460
type: object
461+
required:
462+
- ip
450463
type: object
451464
required:
452465
- spec

pkg/ipam/initialize.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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 ipam
16+
17+
import (
18+
"context"
19+
20+
klog "k8s.io/klog/v2"
21+
"sigs.k8s.io/controller-runtime/pkg/client"
22+
23+
ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
24+
"github.com/liqotech/liqo/pkg/consts"
25+
)
26+
27+
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=ips,verbs=get;list;watch
28+
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks,verbs=get;list;watch
29+
30+
type ipCidr struct {
31+
ip string
32+
cidr string
33+
}
34+
35+
func (lipam *LiqoIPAM) initialize(ctx context.Context) error {
36+
if err := lipam.initializeNetworks(ctx); err != nil {
37+
return err
38+
}
39+
40+
if err := lipam.initializeIPs(ctx); err != nil {
41+
return err
42+
}
43+
44+
klog.Info("IPAM initialized")
45+
return nil
46+
}
47+
48+
func (lipam *LiqoIPAM) initializeNetworks(ctx context.Context) error {
49+
// Initialize the networks.
50+
nets, err := lipam.getReservedNetworks(ctx)
51+
if err != nil {
52+
return err
53+
}
54+
55+
for _, net := range nets {
56+
if err := lipam.reserveNetwork(net); err != nil {
57+
klog.Errorf("Failed to reserve network %s: %v", net, err)
58+
return err
59+
}
60+
}
61+
62+
return nil
63+
}
64+
65+
func (lipam *LiqoIPAM) initializeIPs(ctx context.Context) error {
66+
// Initialize the IPs.
67+
ips, err := lipam.getReservedIPs(ctx)
68+
if err != nil {
69+
return err
70+
}
71+
72+
for _, ip := range ips {
73+
if err := lipam.reserveIP(ip.ip, ip.cidr); err != nil {
74+
klog.Errorf("Failed to reserve IP %s in network %s: %v", ip.ip, ip.cidr, err)
75+
return err
76+
}
77+
}
78+
79+
return nil
80+
}
81+
82+
func (lipam *LiqoIPAM) getReservedNetworks(ctx context.Context) ([]string, error) {
83+
var nets []string
84+
var networks ipamv1alpha1.NetworkList
85+
if err := lipam.Options.Client.List(ctx, &networks); err != nil {
86+
return nil, err
87+
}
88+
89+
for i := range networks.Items {
90+
net := &networks.Items[i]
91+
92+
var cidr string
93+
switch {
94+
case net.Labels != nil && net.Labels[consts.NetworkNotRemappedLabelKey] == consts.NetworkNotRemappedLabelValue:
95+
cidr = net.Spec.CIDR.String()
96+
default:
97+
cidr = net.Status.CIDR.String()
98+
}
99+
if cidr == "" {
100+
klog.Warningf("Network %s has no CIDR", net.Name)
101+
continue
102+
}
103+
104+
nets = append(nets, cidr)
105+
}
106+
107+
return nets, nil
108+
}
109+
110+
func (lipam *LiqoIPAM) getReservedIPs(ctx context.Context) ([]ipCidr, error) {
111+
var ips []ipCidr
112+
var ipList ipamv1alpha1.IPList
113+
if err := lipam.Options.Client.List(ctx, &ipList); err != nil {
114+
return nil, err
115+
}
116+
117+
for i := range ipList.Items {
118+
ip := &ipList.Items[i]
119+
120+
address := ip.Status.IP.String()
121+
if address == "" {
122+
klog.Warningf("IP %s has no address", ip.Name)
123+
continue
124+
}
125+
126+
cidr := ip.Status.CIDR.String()
127+
if cidr == "" {
128+
klog.Warningf("IP %s has no CIDR", ip.Name)
129+
continue
130+
}
131+
132+
ips = append(ips, ipCidr{ip: address, cidr: cidr})
133+
}
134+
135+
return ips, nil
136+
}
137+
138+
func (lipam *LiqoIPAM) reserveNetwork(cidr string) error {
139+
// TODO: Reserve the network.
140+
klog.Infof("Reserved network %s", cidr)
141+
return nil
142+
}
143+
144+
func (lipam *LiqoIPAM) reserveIP(ip string, cidr string) error {
145+
// TODO: Reserve the IP.
146+
klog.Infof("Reserved IP %s in network %s", ip, cidr)
147+
return nil
148+
}

pkg/ipam/ipam.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,27 @@
1515
package ipam
1616

1717
import (
18+
"context"
1819
"time"
1920

2021
"google.golang.org/grpc/health"
2122
"google.golang.org/grpc/health/grpc_health_v1"
23+
"k8s.io/client-go/rest"
24+
"sigs.k8s.io/controller-runtime/pkg/client"
2225
)
2326

2427
// LiqoIPAM is the struct implementing the IPAM interface.
2528
type LiqoIPAM struct {
2629
UnimplementedIPAMServer
30+
31+
Options *Options
2732
}
2833

2934
// Options contains the options to configure the IPAM.
3035
type Options struct {
31-
Port int
36+
Port int
37+
Config *rest.Config
38+
Client client.Client
3239

3340
EnableLeaderElection bool
3441
LeaderElectionNamespace string
@@ -42,11 +49,17 @@ type Options struct {
4249
}
4350

4451
// New creates a new instance of the LiqoIPAM.
45-
func New(opts *Options) *LiqoIPAM {
52+
func New(ctx context.Context, opts *Options) (*LiqoIPAM, error) {
4653
opts.HealthServer.SetServingStatus(IPAM_ServiceDesc.ServiceName, grpc_health_v1.HealthCheckResponse_NOT_SERVING)
4754

48-
// TODO: add here the initialization logic
55+
lipam := &LiqoIPAM{
56+
Options: opts,
57+
}
58+
59+
if err := lipam.initialize(ctx); err != nil {
60+
return nil, err
61+
}
4962

5063
opts.HealthServer.SetServingStatus(IPAM_ServiceDesc.ServiceName, grpc_health_v1.HealthCheckResponse_SERVING)
51-
return &LiqoIPAM{}
64+
return lipam, nil
5265
}

0 commit comments

Comments
 (0)