github.com/webmeshproj/webmesh-cni@v0.0.27/internal/ipam/ipam.go (about)

     1  /*
     2  Copyright 2023 Avi Zimmerman <avi.zimmerman@gmail.com>.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package IPAM provides IPv4 address allocation against the mesh database.
    18  package ipam
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"net/netip"
    24  
    25  	v1 "github.com/webmeshproj/api/go/v1"
    26  	meshplugins "github.com/webmeshproj/webmesh/pkg/plugins"
    27  	meshtypes "github.com/webmeshproj/webmesh/pkg/storage/types"
    28  	"k8s.io/client-go/rest"
    29  )
    30  
    31  // Allocator is the interface for an IPAM allocator.
    32  type Allocator interface {
    33  	// Allocate allocates an IP address for the given node ID.
    34  	Allocate(ctx context.Context, nodeID meshtypes.NodeID) (netip.Prefix, error)
    35  	// Locker returns the underlying Locker. Locks should be acquired before
    36  	// calls to allocate. They are provided as separate methods to ensure
    37  	// the caller has time to write the allocation to the DB. Allocate simply
    38  	// observes the current state and respond with an available address.
    39  	Locker() Locker
    40  }
    41  
    42  // Config is the configuration for the allocator.
    43  type Config struct {
    44  	// IPAM is the IPAM configuration.
    45  	IPAM meshplugins.IPAMConfig
    46  	// Lock is the lock configuration.
    47  	Lock LockConfig
    48  	// Network is the IPv4 network to allocate addresses in.
    49  	Network netip.Prefix
    50  }
    51  
    52  var (
    53  	// ErrNoNetwork is returned when no network is configured.
    54  	ErrNoNetwork = fmt.Errorf("no network configured")
    55  	// ErrNoStorage is returned when no storage is configured.
    56  	ErrNoStorage = fmt.Errorf("no storage configured")
    57  )
    58  
    59  // NewAllocator creates a new IPAM allocator. The given configuration
    60  // will be copied and modified.
    61  func NewAllocator(cfg *rest.Config, conf Config) (Allocator, error) {
    62  	if conf.Network == (netip.Prefix{}) {
    63  		return nil, ErrNoNetwork
    64  	}
    65  	if conf.IPAM.Storage == nil {
    66  		return nil, ErrNoStorage
    67  	}
    68  	lock, err := NewLock(rest.CopyConfig(cfg), conf.Lock)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	ipam := meshplugins.NewBuiltinIPAM(conf.IPAM)
    73  	return &allocator{
    74  		ipam:    ipam,
    75  		lock:    lock,
    76  		network: conf.Network,
    77  	}, nil
    78  }
    79  
    80  type allocator struct {
    81  	ipam    *meshplugins.BuiltinIPAM
    82  	lock    Locker
    83  	network netip.Prefix
    84  }
    85  
    86  func (a *allocator) Allocate(ctx context.Context, nodeID meshtypes.NodeID) (netip.Prefix, error) {
    87  	alloc, err := a.ipam.Allocate(ctx, &v1.AllocateIPRequest{
    88  		NodeID: nodeID.String(),
    89  		Subnet: a.network.String(),
    90  	})
    91  	if err != nil {
    92  		return netip.Prefix{}, err
    93  	}
    94  	return netip.ParsePrefix(alloc.GetIp())
    95  }
    96  
    97  func (a *allocator) Locker() Locker {
    98  	return a.lock
    99  }