Skip to content

Commit 1577c1e

Browse files
committed
feat: ipam sync routine
1 parent 811882a commit 1577c1e

File tree

7 files changed

+316
-95
lines changed

7 files changed

+316
-95
lines changed

cmd/ipam/main.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323

2424
"github.com/spf13/cobra"
2525
"google.golang.org/grpc"
26-
"google.golang.org/grpc/health"
2726
"google.golang.org/grpc/health/grpc_health_v1"
2827
corev1 "k8s.io/api/core/v1"
2928
"k8s.io/apimachinery/pkg/runtime"
@@ -71,6 +70,8 @@ func main() {
7170
restcfg.InitFlags(cmd.Flags())
7271

7372
cmd.Flags().IntVar(&options.Port, "port", consts.IpamPort, "The port on which to listen for incoming gRPC requests.")
73+
cmd.Flags().DurationVar(&options.SyncFrequency, "interval", consts.SyncFrequency,
74+
"The interval at which the IPAM will synchronize the IPAM storage.")
7475
cmd.Flags().BoolVar(&options.EnableLeaderElection, "leader-election", false, "Enable leader election for IPAM. "+
7576
"Enabling this will ensure there is only one active IPAM.")
7677
cmd.Flags().StringVar(&options.LeaderElectionNamespace, "leader-election-namespace", consts.DefaultLiqoNamespace,
@@ -102,14 +103,12 @@ func run(cmd *cobra.Command, _ []string) error {
102103

103104
// Get the rest config.
104105
cfg := restcfg.SetRateLimiter(ctrl.GetConfigOrDie())
105-
options.Config = cfg
106106
cl, err := client.New(cfg, client.Options{
107107
Scheme: scheme,
108108
})
109109
if err != nil {
110110
return err
111111
}
112-
options.Client = cl
113112

114113
if options.EnableLeaderElection {
115114
if leader, err := leaderelection.Blocking(ctx, cfg, record.NewBroadcaster(), &leaderelection.Opts{
@@ -129,10 +128,7 @@ func run(cmd *cobra.Command, _ []string) error {
129128
}
130129
}
131130

132-
hs := health.NewServer()
133-
options.HealthServer = hs
134-
135-
liqoIPAM, err := ipam.New(ctx, &options)
131+
liqoIPAM, err := ipam.New(ctx, cl, cfg, &options)
136132
if err != nil {
137133
return err
138134
}
@@ -145,7 +141,7 @@ func run(cmd *cobra.Command, _ []string) error {
145141
server := grpc.NewServer()
146142

147143
// Register health service
148-
grpc_health_v1.RegisterHealthServer(server, hs)
144+
grpc_health_v1.RegisterHealthServer(server, liqoIPAM.HealthServer)
149145

150146
// Register IPAM service
151147
ipam.RegisterIPAMServer(server, liqoIPAM)

pkg/consts/ipam.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414

1515
package consts
1616

17+
import "time"
18+
1719
// NetworkType indicates the type of Network.
1820
type NetworkType string
1921

2022
const (
2123
// IpamPort is the port used by the IPAM gRPC server.
22-
IpamPort = 50051
24+
IpamPort = 6000
25+
// SyncFrequency is the frequency at which the IPAM should periodically sync its status.
26+
SyncFrequency = 2 * time.Minute
2327

2428
// NetworkNotRemappedLabelKey is the label key used to mark a Network that does not need CIDR remapping.
2529
NetworkNotRemappedLabelKey = "ipam.liqo.io/network-not-remapped"

pkg/ipam/initialize.go

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,11 @@ import (
1818
"context"
1919

2020
klog "k8s.io/klog/v2"
21-
22-
ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
23-
"github.com/liqotech/liqo/pkg/consts"
2421
)
2522

2623
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=ips,verbs=get;list;watch
2724
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks,verbs=get;list;watch
2825

29-
type ipCidr struct {
30-
ip string
31-
cidr string
32-
}
33-
3426
func (lipam *LiqoIPAM) initialize(ctx context.Context) error {
3527
if err := lipam.initializeNetworks(ctx); err != nil {
3628
return err
@@ -77,71 +69,3 @@ func (lipam *LiqoIPAM) initializeIPs(ctx context.Context) error {
7769

7870
return nil
7971
}
80-
81-
func (lipam *LiqoIPAM) getReservedNetworks(ctx context.Context) ([]string, error) {
82-
var nets []string
83-
var networks ipamv1alpha1.NetworkList
84-
if err := lipam.Options.Client.List(ctx, &networks); err != nil {
85-
return nil, err
86-
}
87-
88-
for i := range networks.Items {
89-
net := &networks.Items[i]
90-
91-
var cidr string
92-
switch {
93-
case net.Labels != nil && net.Labels[consts.NetworkNotRemappedLabelKey] == consts.NetworkNotRemappedLabelValue:
94-
cidr = net.Spec.CIDR.String()
95-
default:
96-
cidr = net.Status.CIDR.String()
97-
}
98-
if cidr == "" {
99-
klog.Warningf("Network %s has no CIDR", net.Name)
100-
continue
101-
}
102-
103-
nets = append(nets, cidr)
104-
}
105-
106-
return nets, nil
107-
}
108-
109-
func (lipam *LiqoIPAM) getReservedIPs(ctx context.Context) ([]ipCidr, error) {
110-
var ips []ipCidr
111-
var ipList ipamv1alpha1.IPList
112-
if err := lipam.Options.Client.List(ctx, &ipList); err != nil {
113-
return nil, err
114-
}
115-
116-
for i := range ipList.Items {
117-
ip := &ipList.Items[i]
118-
119-
address := ip.Status.IP.String()
120-
if address == "" {
121-
klog.Warningf("IP %s has no address", ip.Name)
122-
continue
123-
}
124-
125-
cidr := ip.Status.CIDR.String()
126-
if cidr == "" {
127-
klog.Warningf("IP %s has no CIDR", ip.Name)
128-
continue
129-
}
130-
131-
ips = append(ips, ipCidr{ip: address, cidr: cidr})
132-
}
133-
134-
return ips, nil
135-
}
136-
137-
func (lipam *LiqoIPAM) reserveNetwork(cidr string) error {
138-
// TODO: Reserve the network.
139-
klog.Infof("Reserved network %s", cidr)
140-
return nil
141-
}
142-
143-
func (lipam *LiqoIPAM) reserveIP(ip, cidr string) error {
144-
// TODO: Reserve the IP.
145-
klog.Infof("Reserved IP %s in network %s", ip, cidr)
146-
return nil
147-
}

pkg/ipam/ipam.go

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package ipam
1616

1717
import (
1818
"context"
19+
"sync"
1920
"time"
2021

2122
"google.golang.org/grpc/health"
@@ -27,15 +28,21 @@ import (
2728
// LiqoIPAM is the struct implementing the IPAM interface.
2829
type LiqoIPAM struct {
2930
UnimplementedIPAMServer
31+
HealthServer *health.Server
32+
33+
client.Client
34+
*rest.Config
3035

31-
Options *Options
36+
options *Options
37+
cacheNetworks map[string]networkInfo
38+
cacheIPs map[string]ipInfo
39+
mutex sync.Mutex
3240
}
3341

3442
// Options contains the options to configure the IPAM.
3543
type Options struct {
36-
Port int
37-
Config *rest.Config
38-
Client client.Client
44+
Port int
45+
SyncFrequency time.Duration
3946

4047
EnableLeaderElection bool
4148
LeaderElectionNamespace string
@@ -44,23 +51,34 @@ type Options struct {
4451
RenewDeadline time.Duration
4552
RetryPeriod time.Duration
4653
PodName string
47-
48-
HealthServer *health.Server
4954
}
5055

5156
// New creates a new instance of the LiqoIPAM.
52-
func New(ctx context.Context, opts *Options) (*LiqoIPAM, error) {
53-
opts.HealthServer.SetServingStatus(IPAM_ServiceDesc.ServiceName, grpc_health_v1.HealthCheckResponse_NOT_SERVING)
57+
func New(ctx context.Context, cl client.Client, cfg *rest.Config, opts *Options) (*LiqoIPAM, error) {
58+
hs := health.NewServer()
59+
hs.SetServingStatus(IPAM_ServiceDesc.ServiceName, grpc_health_v1.HealthCheckResponse_NOT_SERVING)
5460

5561
lipam := &LiqoIPAM{
56-
Options: opts,
62+
HealthServer: hs,
63+
64+
Config: cfg,
65+
Client: cl,
66+
67+
options: opts,
68+
cacheNetworks: make(map[string]networkInfo),
69+
cacheIPs: make(map[string]ipInfo),
5770
}
5871

72+
// Initialize the IPAM instance
5973
if err := lipam.initialize(ctx); err != nil {
6074
return nil, err
6175
}
6276

63-
opts.HealthServer.SetServingStatus(IPAM_ServiceDesc.ServiceName, grpc_health_v1.HealthCheckResponse_SERVING)
77+
// Launch sync routine
78+
go lipam.sync(ctx, opts.SyncFrequency)
79+
80+
hs.SetServingStatus(IPAM_ServiceDesc.ServiceName, grpc_health_v1.HealthCheckResponse_SERVING)
81+
6482
return lipam, nil
6583
}
6684

pkg/ipam/ips.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
"time"
20+
21+
klog "k8s.io/klog/v2"
22+
23+
ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
24+
)
25+
26+
type ipInfo struct {
27+
ipCidr
28+
creationTimestamp time.Time
29+
}
30+
31+
func (i *ipInfo) String() string {
32+
return i.ipCidr.String()
33+
}
34+
35+
type ipCidr struct {
36+
ip string
37+
cidr string
38+
}
39+
40+
func (i *ipCidr) String() string {
41+
return i.ip + "-" + i.cidr
42+
}
43+
44+
func (lipam *LiqoIPAM) reserveIP(ip, cidr string) error {
45+
lipam.mutex.Lock()
46+
defer lipam.mutex.Unlock()
47+
48+
if lipam.cacheIPs == nil {
49+
lipam.cacheIPs = make(map[string]ipInfo)
50+
}
51+
52+
// TODO: add correct logic.
53+
ipI := ipInfo{
54+
ipCidr: ipCidr{ip: ip, cidr: cidr},
55+
creationTimestamp: time.Now(),
56+
}
57+
58+
// Save IP in cache.
59+
lipam.cacheIPs[ipI.String()] = ipI
60+
klog.Infof("Reserved IP %s in network %s", ip, cidr)
61+
62+
return nil
63+
}
64+
65+
func (lipam *LiqoIPAM) getReservedIPs(ctx context.Context) ([]ipCidr, error) {
66+
var ips []ipCidr
67+
var ipList ipamv1alpha1.IPList
68+
if err := lipam.Client.List(ctx, &ipList); err != nil {
69+
return nil, err
70+
}
71+
72+
for i := range ipList.Items {
73+
ip := &ipList.Items[i]
74+
75+
address := ip.Status.IP.String()
76+
if address == "" {
77+
klog.Warningf("IP %s has no address", ip.Name)
78+
continue
79+
}
80+
81+
cidr := ip.Status.CIDR.String()
82+
if cidr == "" {
83+
klog.Warningf("IP %s has no CIDR", ip.Name)
84+
continue
85+
}
86+
87+
ips = append(ips, ipCidr{ip: address, cidr: cidr})
88+
}
89+
90+
return ips, nil
91+
}

0 commit comments

Comments
 (0)