ipam

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2024 License: MIT Imports: 11 Imported by: 0

README

go-ipam

modify from github.com/metal-stack/go-ipam

Documentation

Overview

Package ipam is a ip address management library for ip's and prefixes (networks).

It uses either memory or postgresql database to store the ip's and prefixes. You can also bring you own Storage implementation as you need.

Example usage:

package main

import (
	"context"
	"fmt"
	goipam "github.com/Lmineor/goipam"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func main() {
	ctx := context.Background()
	namespace := "namespace1"
	db := getBackend()
	gormImpl := goipam.NewGormStorage(db, 50)
	ipam := goipam.NewWithStorage(gormImpl)

	err := ipam.CreateNamespace(ctx, namespace)
	if err != nil {
		panic(err)
	}

	ctx = goipam.NewContextWithNamespace(ctx, namespace)
	p, err := ipam.NewPrefix(ctx, "192.168.0.1/16")
	if err != nil {
		panic(err)
	}
	ip, err := ipam.AcquireIP(ctx, p.ID)
	if err != nil {
		panic(err)
	}
	fmt.Printf("got IP %s\n", ip.IP)
	p, err = ipam.ReleaseIP(ctx, ip)
	if err != nil {
		panic(err)
	}
	fmt.Printf("release IP %s\n", ip.IP)

}

func getBackend() *gorm.DB {
	dbName := "test"
	db := gormMysql(dbName)
	RegisterTables(db)
	return db
}

// RegisterTables register table to mysql if not exist
func RegisterTables(db *gorm.DB) {
	db.Exec("DROP TABLE namespaces")
	db.Exec("DROP TABLE prefixes")
	err := db.AutoMigrate(
		&goipam.IPStorage{},
		&goipam.Namespace{},
		&goipam.Prefix{},
	)
	if err != nil {
		fmt.Printf("register table failed %s\n", err)
	}
}

func gormMysql(dbName string) *gorm.DB {
	username := "root"
	password := "123456"
	path := "127.0.0.1"
	port := "3306"
	config := "charset=utf8&parseTime=True&loc=Local"
	maxIdleConns := 10
	maxOpenConns := 100
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", username, password, path, port, dbName, config)
	mysqlConfig := mysql.Config{
		DSN:                       dsn,
		DefaultStringSize:         191,
		SkipInitializeWithVersion: false,
	}
	if db, err := gorm.Open(mysql.New(mysqlConfig)); err != nil {
		return nil
	} else {
		sqlDB, _ := db.DB()
		sqlDB.SetMaxIdleConns(maxIdleConns)
		sqlDB.SetMaxOpenConns(maxOpenConns)
		return db
	}
}

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is returned if prefix or cidr was not found
	ErrNotFound = errors.New("NotFound")
	// ErrNoIPAvailable is returned if no IP is available anymore
	ErrNoIPAvailable = errors.New("NoIPAvailableError")
	// ErrAlreadyAllocated is returned if the requested address is not available
	ErrAlreadyAllocated = errors.New("AlreadyAllocatedError")
	// ErrNamespaceDoesNotExist is returned when an operation is perfomed in a namespace that does not exist.
	ErrNamespaceDoesNotExist = errors.New("NamespaceDoesNotExist")
	// ErrNamespaceExist is returned when an operation is perfomed in a namespace that exist.
	ErrNamespaceExist = errors.New("NamespaceDoesExist")
	// ErrNameTooLong is returned when a name exceeds the databases max identifier length
	ErrNameTooLong = errors.New("NameTooLong")
	//ErrNamespaceInconsistent is returned when namespace provided inconsistent with namespace in context
	ErrNamespaceInconsistent = errors.New("prefix namespace inconsistent with context")

	//ErrDbNil is returned when db is nil
	ErrDbNil = errors.New("db is nil")

	//ErrPrefixHasIP is returned when prefix has allocated ip
	ErrPrefixHasIP = errors.New("prefix has allocated ip")
)

Functions

func NewContextWithNamespace

func NewContextWithNamespace(ctx context.Context, namespace string) context.Context

func NewGormStorage added in v0.0.2

func NewGormStorage(db *gorm.DB, namespaceLen int) *gormStorage

NewGormStorage return a implement for gorm

func PrefixesOverlapping

func PrefixesOverlapping(existingPrefixes []string, newPrefixes []string) error

PrefixesOverlapping will check if one ore more prefix of newPrefixes is overlapping with one of existingPrefixes

func RegisterTables added in v0.0.3

func RegisterTables(db *gorm.DB) error

Types

type IPStorage

type IPStorage struct {
	IP           string `json:"ip"`
	ParentPrefix string `json:"parent_prefix"`
	Namespace    string `json:"namespace"`
}

IPStorage is a single ipaddress.

type Ipamer

type Ipamer interface {
	// NewPrefix creates a new Prefix from a string notation.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	NewPrefix(ctx context.Context, cidr string) (*Prefix, error)
	// DeletePrefix delete a Prefix from a prefix cidr.
	// If the Prefix is not found an NotFoundError is returned.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	DeletePrefix(ctx context.Context, cidr string) (*Prefix, error)
	// AcquireChildPrefix will return a Prefix with a smaller length from the given parent prefix(id).
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	AcquireChildPrefix(ctx context.Context, parentID uint, length uint8) (*Prefix, error)
	// AcquireSpecificChildPrefix will return a Prefix with a smaller length from the given parent prefix(id).
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	AcquireSpecificChildPrefix(ctx context.Context, parentID uint, childCidr string) (*Prefix, error)
	// ReleaseChildPrefix will mark this child Prefix as available again.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	ReleaseChildPrefix(ctx context.Context, child *Prefix) error
	// GetPrefixByCidr will return a known Prefix.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	GetPrefixByCidr(ctx context.Context, cidr string) *Prefix
	// AcquireSpecificIP will acquire given IP and mark this IP as used, if already in use, return nil.
	// If specificIP is empty, the next free IP is returned.
	// If there is no free IP an NoIPAvailableError is returned.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	AcquireSpecificIP(ctx context.Context, cidr string, specificIP string) (*IPStorage, error)
	// AcquireIP will return the next unused IP from this Prefix.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	AcquireIP(ctx context.Context, cidr string) (*IPStorage, error)
	// ReleaseIP will release the given IP for later usage and returns the updated Prefix.
	// If the IP is not found an NotFoundError is returned.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	ReleaseIP(ctx context.Context, ip *IPStorage) (*Prefix, error)
	// ReleaseIPFromPrefix will release the given IP for later usage.
	// If the Prefix or the IP is not found an NotFoundError is returned.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	ReleaseIPFromPrefix(ctx context.Context, prefixCidr, ip string) error
	// ListAllPrefix all stored prefixes as json formatted string
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	ListAllPrefix(ctx context.Context) (Prefixes, error)
	// ReadAllPrefixCidrs retrieves all existing Prefix CIDRs from the underlying storage.
	// This operation is scoped to the root namespace unless a different namespace is provided in the context.
	ReadAllPrefixCidrs(ctx context.Context) ([]string, error)
	// CreateNamespace creates a namespace with the given name.
	// Any namespace provided in the context is ignored for this operation.
	// It is idempotent, so attempts to create a namespace which already exists will not return an error.
	CreateNamespace(ctx context.Context, namespace string) error
	// ListNamespaces returns a list of all namespaces.
	// Any namespace provided in the context is ignored for this operation.
	ListNamespaces(ctx context.Context) ([]string, error)
	// DeleteNamespace deletes the namespace with the given name.
	// Any namespace provided in the context is ignored for this operation.
	// It not idempotent, so attempts to delete a namespace which does not exist will return an error.
	DeleteNamespace(ctx context.Context, namespace string) error
	// AllocatedIPs list all allocated IPS of prefix
	// Any namespace provided in the context is ignored for this operation.
	// It not idempotent, so attempts to delete a namespace which does not exist will return an error.
	AllocatedIPs(ctx context.Context, prefix Prefix) ([]IPStorage, error)
}

Ipamer can be used to do IPAM stuff.

func NewWithStorage

func NewWithStorage(storage Storage) Ipamer

NewWithStorage allows you to create a Ipamer instance with your Storage implementation. The Storage interface must be implemented.

type Namespace

type Namespace struct {
	Namespace string `gorm:"namespace;uniqueIndex:namespace_idx"`
}

type Prefix

type Prefix struct {
	ID        uint   `gorm:"primarykey"`
	Cidr      string `gorm:"primaryKey;uniqueIndex:cidr_parent_cidr_namespace_idx"` // The Cidr of this prefix
	ParentID  uint   `gorm:"column:parent_id;foreignKey:ID"`
	IsParent  bool   // if this Prefix has child prefixes, this is set to true
	Version   int64  // Version is used for optimistic locking
	Namespace string `gorm:"uniqueIndex:cidr_parent_cidr_namespace_idx"` // the namespace of this prefix
}

Prefix is a expression of a ip with length and forms a classless network. nolint:musttag

func (*Prefix) GobDecode

func (p *Prefix) GobDecode(buf []byte) error

GobDecode implements GobDecode for Prefix

func (*Prefix) GobEncode

func (p *Prefix) GobEncode() ([]byte, error)

GobEncode implements GobEncode for Prefix

func (*Prefix) Network

func (p *Prefix) Network() (netip.Addr, error)

Network return the net.IP part of the Prefix

func (*Prefix) String

func (p *Prefix) String() string

func (*Prefix) Usage

func (p *Prefix) Usage() Usage

Usage report Prefix usage.

type Prefixes

type Prefixes []Prefix

type Storage

type Storage interface {
	Name() string
	CreatePrefix(ctx context.Context, prefix Prefix) (Prefix, error)
	ReadPrefix(ctx context.Context, prefix string) (Prefix, error)
	ReadPrefixByID(ctx context.Context, id uint) (Prefix, error)
	ReadAllChildPrefixByParentID(ctx context.Context, id uint) (Prefixes, error)
	DeleteAllPrefixes(ctx context.Context) error
	ReadAllPrefixes(ctx context.Context) (Prefixes, error)
	ReadAllPrefixCidrs(ctx context.Context) ([]string, error)
	UpdatePrefix(ctx context.Context, prefix Prefix) (Prefix, error)
	DeletePrefix(ctx context.Context, prefix Prefix) (Prefix, error)
	CreateNamespace(ctx context.Context, namespace string) error
	ListNamespaces(ctx context.Context) ([]string, error)
	DeleteNamespace(ctx context.Context, namespace string) error
	PutIPAddress(ctx context.Context, prefix Prefix, ip string) error
	DeleteIPAddress(ctx context.Context, prefix Prefix, ip string) error
	IPAllocated(ctx context.Context, prefix Prefix, ip string) bool
	AllocatedIPS(ctx context.Context, prefix Prefix) ([]IPStorage, error)
}

Storage is a interface to store ipam objects.

type Usage

type Usage struct {
	// AvailableIPs the number of available IPs if this is not a parent prefix
	// No more than 2^31 available IPs are reported
	AvailableIPs uint64
	// AcquiredIPs the number of acquired IPs if this is not a parent prefix
	AcquiredIPs uint64
	// AvailableSmallestPrefixes is the count of available Prefixes with 2 countable Bits
	// No more than 2^31 available Prefixes are reported
	AvailableSmallestPrefixes uint64
	// AvailablePrefixes is a list of prefixes which are available
	AvailablePrefixes []string
	// AcquiredPrefixes the number of acquired prefixes if this is a parent prefix
	AcquiredPrefixes uint64
}

Usage of ips and child Prefixes of a Prefix

func (*Usage) String

func (u *Usage) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL