working on adding lease handouts
This commit is contained in:
@@ -15,7 +15,7 @@ type LeaseInfo struct {
|
||||
Expires time.Time `yaml:"expires"`
|
||||
}
|
||||
|
||||
type sortableLease []LeaseInfo
|
||||
type sortableLease []*LeaseInfo
|
||||
|
||||
func (a sortableLease) Len() int { return len(a) }
|
||||
func (a sortableLease) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
@@ -33,14 +33,14 @@ func (li *LeaseInfo) Expire() {
|
||||
li.Expires = time.Time{}
|
||||
}
|
||||
|
||||
func SortLeases(leases []LeaseInfo) []LeaseInfo {
|
||||
func SortLeases(leases []*LeaseInfo) []*LeaseInfo {
|
||||
sortable := sortableLease(leases)
|
||||
sort.Sort(sortable)
|
||||
|
||||
return []LeaseInfo(sortable)
|
||||
return []*LeaseInfo(sortable)
|
||||
}
|
||||
|
||||
func (lease LeaseInfo) Reset() LeaseInfo {
|
||||
func (lease *LeaseInfo) Reset() *LeaseInfo {
|
||||
lease.Expires = time.Time{}
|
||||
lease.HardwareAddress = nil
|
||||
return lease
|
||||
|
||||
111
iptools/pool.go
111
iptools/pool.go
@@ -1,58 +1,141 @@
|
||||
package iptools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.wntrmute.dev/kyle/goutils/assert"
|
||||
)
|
||||
|
||||
const DefaultExpiry = 168 * time.Hour
|
||||
|
||||
type Pool struct {
|
||||
Name string `yaml:"name"`
|
||||
Range *Range `yaml:"range"`
|
||||
Expiry time.Duration `yaml:"expiry"`
|
||||
Available []LeaseInfo `yaml:"available"`
|
||||
Active map[netip.Addr]LeaseInfo `yaml:"active"`
|
||||
Limbo map[netip.Addr]LeaseInfo `yaml:"limbo"` // leases that are currently being offered
|
||||
Name string `yaml:"name"`
|
||||
Range *Range `yaml:"range"`
|
||||
Expiry time.Duration `yaml:"expiry"`
|
||||
Available []*LeaseInfo `yaml:"available"`
|
||||
Active map[netip.Addr]*LeaseInfo `yaml:"active"`
|
||||
Limbo map[netip.Addr]*LeaseInfo `yaml:"limbo"` // leases that are currently being offered
|
||||
NoHostName bool `yaml:"no_hostname"` // don't set the hostname
|
||||
mtx *sync.Mutex
|
||||
}
|
||||
|
||||
func NewPool(name string, exp time.Duration, r *Range) (*Pool, error) {
|
||||
func (p *Pool) lock() {
|
||||
if p.lock == nil {
|
||||
p.mtx = &sync.Mutex{}
|
||||
}
|
||||
|
||||
p.mtx.Lock()
|
||||
}
|
||||
|
||||
func (p *Pool) unlock() {
|
||||
if p.mtx == nil {
|
||||
panic("pool: attempted to unlock uninitialized mutex")
|
||||
}
|
||||
|
||||
p.mtx.Unlock()
|
||||
}
|
||||
|
||||
func NewPool(name string, r *Range) (*Pool, error) {
|
||||
if r.Expiry == 0 {
|
||||
r.Expiry = DefaultExpiry
|
||||
}
|
||||
|
||||
p := &Pool{
|
||||
Name: name,
|
||||
Expiry: exp,
|
||||
Available: enumerateRange(name, r, true),
|
||||
Name: name,
|
||||
Expiry: r.Expiry,
|
||||
NoHostName: r.NoHostName,
|
||||
Available: enumerateRange(name, r, true),
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *Pool) Sort() {
|
||||
func (p *Pool) sort() {
|
||||
p.Available = SortLeases(p.Available)
|
||||
}
|
||||
|
||||
func (p *Pool) Sort() {
|
||||
p.lock()
|
||||
defer p.unlock()
|
||||
|
||||
p.sort()
|
||||
}
|
||||
|
||||
func (p *Pool) IsAddressAvailable() bool {
|
||||
return len(p.Available) > 0
|
||||
}
|
||||
|
||||
func (p *Pool) Peek(t time.Time, waitFor time.Duration) netip.Addr {
|
||||
// Peek returns the first available address from the pool and moves it
|
||||
// from available to limbo. When the client is given the address, Accept
|
||||
// should be called on the address to move it from limbo to active.
|
||||
func (p *Pool) Peek(t time.Time, waitFor time.Duration) *LeaseInfo {
|
||||
p.lock()
|
||||
defer p.unlock()
|
||||
|
||||
li := p.peek(t, waitFor)
|
||||
return li
|
||||
}
|
||||
|
||||
func (p *Pool) peek(t time.Time, waitFor time.Duration) *LeaseInfo {
|
||||
if len(p.Available) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
lease := p.Available[0]
|
||||
p.Available = p.Available[1:]
|
||||
lease.ResetExpiry(t, waitFor)
|
||||
|
||||
p.Limbo[lease.Addr] = lease
|
||||
|
||||
return lease.Addr
|
||||
return lease
|
||||
}
|
||||
|
||||
func (p *Pool) accept(addr netip.Addr) error {
|
||||
assert.Bool(p.Active[addr] == nil, fmt.Sprintf("limbo address %s is already active: %#v", addr, *p.Active[addr]))
|
||||
|
||||
p.Active[addr] = p.Limbo[addr]
|
||||
delete(p.Limbo, addr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Accept will move an address out limbo and mark it as active.
|
||||
func (p *Pool) Accept(addr netip.Addr, t time.Time) error {
|
||||
p.lock()
|
||||
defer p.unlock()
|
||||
|
||||
p.update(t)
|
||||
p.accept(addr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update checks expirations on leases, moving any expired leases back
|
||||
// to the available pool and removing any limbo leases that are expired.
|
||||
func (p *Pool) Update(t time.Time) {
|
||||
p.lock()
|
||||
defer p.unlock()
|
||||
|
||||
p.update(t)
|
||||
}
|
||||
|
||||
func (p *Pool) update(t time.Time) {
|
||||
evictedHosts := []netip.Addr{}
|
||||
|
||||
for k, v := range p.Active {
|
||||
if v.IsExpired(t) {
|
||||
delete(p.Active, k)
|
||||
evictedHosts = append(evictedHosts, k)
|
||||
v = v.Reset()
|
||||
p.Available = append(p.Available, v)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ip := range evictedHosts {
|
||||
delete(p.Active, ip)
|
||||
}
|
||||
|
||||
for k, v := range p.Limbo {
|
||||
if v.IsExpired(t) {
|
||||
delete(p.Limbo, k)
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -18,7 +17,7 @@ func TestBasicPool(t *testing.T) {
|
||||
End: poolTestIP2,
|
||||
}
|
||||
|
||||
p, err := NewPool("cluster", 24*time.Hour, r)
|
||||
p, err := NewPool("cluster", r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package iptools
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -10,9 +11,11 @@ const (
|
||||
)
|
||||
|
||||
type Range struct {
|
||||
Start netip.Addr `yaml:"start"`
|
||||
End netip.Addr `yaml:"end"`
|
||||
Network netip.Prefix `yaml:"network"`
|
||||
Start netip.Addr `yaml:"start"`
|
||||
End netip.Addr `yaml:"end"`
|
||||
Network netip.Prefix `yaml:"network"`
|
||||
Expiry time.Duration `yaml:"expiry"`
|
||||
NoHostName bool `yaml:"no_hostname"` // don't set the hostname
|
||||
}
|
||||
|
||||
func (r *Range) Validate() error {
|
||||
@@ -54,7 +57,7 @@ func (r *Range) numHosts() int {
|
||||
hosts := 0
|
||||
for cur.Compare(r.End) < 1 {
|
||||
hosts++
|
||||
cur.Next()
|
||||
cur = cur.Next()
|
||||
}
|
||||
|
||||
return hosts
|
||||
|
||||
@@ -47,3 +47,16 @@ func TestBasicValidation(t *testing.T) {
|
||||
t.Fatal("range 4 should be invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNumHosts(t *testing.T) {
|
||||
r := &Range{
|
||||
Start: rangeTestIP1,
|
||||
End: rangeTestIP2,
|
||||
}
|
||||
expected := 15
|
||||
|
||||
numHosts := r.numHosts()
|
||||
if numHosts != expected {
|
||||
t.Fatalf("have %d hosts, expected %d", numHosts, expected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package iptools
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func enumerateRange(name string, r *Range, startFromOne bool) []LeaseInfo {
|
||||
func enumerateRange(name string, r *Range, startFromOne bool) []*LeaseInfo {
|
||||
start := r.Start
|
||||
cur := start
|
||||
lenfmt := fmt.Sprintf("%%s%%0%dd", len(fmt.Sprintf("%d", r.numHosts())))
|
||||
@@ -10,11 +12,12 @@ func enumerateRange(name string, r *Range, startFromOne bool) []LeaseInfo {
|
||||
if startFromOne {
|
||||
i++
|
||||
}
|
||||
leases := []LeaseInfo{}
|
||||
leases := []*LeaseInfo{}
|
||||
|
||||
for r.End.Compare(cur) >= 0 {
|
||||
leases = append(leases, LeaseInfo{
|
||||
HostName: fmt.Sprintf(lenfmt, name, i),
|
||||
hostName := fmt.Sprintf(lenfmt, name, i)
|
||||
leases = append(leases, &LeaseInfo{
|
||||
HostName: hostName,
|
||||
Addr: cur,
|
||||
})
|
||||
i++
|
||||
|
||||
Reference in New Issue
Block a user