Skip to content

Commit

Permalink
dhcp: experimentally make leases scope-scoped
Browse files Browse the repository at this point in the history
  • Loading branch information
BeryJu committed Nov 22, 2024
1 parent 13469f5 commit c9546c3
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 49 deletions.
9 changes: 4 additions & 5 deletions pkg/roles/dhcp/api_leases.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ func (r *Role) APILeasesGet() usecase.Interactor {

leaseKey := r.i.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
input.ScopeName,
)
if input.Identifier == "" {
leaseKey = leaseKey.Prefix(true)
Expand All @@ -67,9 +68,6 @@ func (r *Role) APILeasesGet() usecase.Interactor {
r.log.Warn("failed to parse lease", zap.Error(err))
continue
}
if l.ScopeKey != input.ScopeName {
continue
}
al := &APILease{
Identifier: l.Identifier,
Address: l.Address,
Expand Down Expand Up @@ -186,7 +184,8 @@ func (r *Role) APILeasesDelete() usecase.Interactor {
u := usecase.NewInteractor(func(ctx context.Context, input APILeasesDeleteInput, output *struct{}) error {
key := r.i.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
input.Scope,
input.Identifier,
)
_, err := r.i.KV().Delete(
Expand Down
12 changes: 8 additions & 4 deletions pkg/roles/dhcp/api_leases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ func TestAPILeasesGet(t *testing.T) {
ctx,
inst.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
scope.Name,
lease.Identifier,
).String(),
tests.MustJSON(lease),
Expand Down Expand Up @@ -83,7 +84,8 @@ func TestAPILeasesPut(t *testing.T) {
inst.KV(),
inst.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
scope.Name,
name,
),
dhcp.Lease{
Expand Down Expand Up @@ -116,7 +118,8 @@ func TestAPILeasesDelete(t *testing.T) {
ctx,
inst.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
scope.Name,
lease.Identifier,
).String(),
tests.MustJSON(lease),
Expand All @@ -132,7 +135,8 @@ func TestAPILeasesDelete(t *testing.T) {
inst.KV(),
inst.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
scope.Name,
lease.Identifier,
),
)
Expand Down
43 changes: 16 additions & 27 deletions pkg/roles/dhcp/api_scopes.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,28 +56,6 @@ func (r *Role) APIScopesGet() usecase.Interactor {
r.log.Warn("failed to get scopes", zap.Error(err))
return status.Wrap(errors.New("failed to get scopes"), status.Internal)
}
// Fetch all leases for statistics
rawLeases, err := r.i.KV().Get(
ctx,
r.i.KV().Key(
types.KeyRole,
types.KeyLeases,
).String(),
clientv3.WithPrefix(),
)
if err != nil {
r.log.Warn("failed to get leases", zap.Error(err))
return status.Wrap(errors.New("failed to get leases"), status.Internal)
}
leases := []*Lease{}
for _, rl := range rawLeases.Kvs {
l, err := r.leaseFromKV(rl)
if err != nil {
r.log.Warn("failed to parse lease", zap.Error(err))
continue
}
leases = append(leases, l)
}

// Generate summarized statistics
sum := APIScopeStatistics{}
Expand All @@ -92,12 +70,23 @@ func (r *Role) APIScopesGet() usecase.Interactor {
Usable: sc.ipam.UsableSize().Uint64(),
Used: 0,
}
for _, l := range leases {
if l.ScopeKey != sc.Name {
continue
}
stat.Used += 1
// Fetch all leases for statistics
rawLeases, err := r.i.KV().Get(
ctx,
r.i.KV().Key(
types.KeyRole,
types.KeyScopes,
sc.Name,
).Prefix(true).String(),
clientv3.WithPrefix(),
clientv3.WithCountOnly(),
)
if err != nil {
r.log.Warn("failed to get leases", zap.Error(err))
return status.Wrap(errors.New("failed to get leases"), status.Internal)
}
stat.Used = uint64(len(rawLeases.Kvs))

sum.Usable += stat.Usable
sum.Used += stat.Used
output.Scopes = append(output.Scopes, &APIScope{
Expand Down
3 changes: 2 additions & 1 deletion pkg/roles/dhcp/api_scopes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ func TestAPIScopesGet(t *testing.T) {
ctx,
inst.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
"test",
lease.Identifier,
).String(),
tests.MustJSON(lease),
Expand Down
3 changes: 2 additions & 1 deletion pkg/roles/dhcp/ipam_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ func TestIPAMInternal_NextFreeAddress_UniqueParallel(t *testing.T) {
ctx,
inst.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
scope.Name,
lease.Identifier,
).String(),
tests.MustJSON(lease),
Expand Down
8 changes: 5 additions & 3 deletions pkg/roles/dhcp/leases.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ func (l *Lease) setLeaseIP(req *Request4) {
func (r *Role) leaseFromKV(raw *mvccpb.KeyValue) (*Lease, error) {
prefix := r.i.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
).Prefix(true).String()
identifier := strings.TrimPrefix(string(raw.Key), prefix)
keyParts := strings.SplitN(prefix, "/", 2)
identifier := strings.TrimPrefix(string(raw.Key), prefix+"/"+keyParts[0])
l := r.NewLease(identifier)
err := json.Unmarshal(raw.Value, &l)
if err != nil {
Expand Down Expand Up @@ -152,7 +153,8 @@ func (l *Lease) Put(ctx context.Context, expiry int64, opts ...clientv3.OpOption

leaseKey := l.inst.KV().Key(
types.KeyRole,
types.KeyLeases,
types.KeyScopes,
l.ScopeKey,
l.Identifier,
)
_, err = l.inst.KV().Put(
Expand Down
24 changes: 19 additions & 5 deletions pkg/roles/dhcp/leases_watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dhcp
import (
"context"
"errors"
"strings"
"time"

"beryju.io/gravity/pkg/roles/dhcp/types"
Expand Down Expand Up @@ -32,12 +33,13 @@ func (r *Role) handleLeaseOp(ev *clientv3.Event) {
}

func (r *Role) loadInitialLeases(ctx context.Context) {
prefix := r.i.KV().Key(
types.KeyRole,
types.KeyScopes,
).Prefix(true).String()
leases, err := r.i.KV().Get(
ctx,
r.i.KV().Key(
types.KeyRole,
types.KeyLeases,
).Prefix(true).String(),
prefix,
clientv3.WithPrefix(),
)
if err != nil {
Expand All @@ -49,6 +51,10 @@ func (r *Role) loadInitialLeases(ctx context.Context) {
return
}
for _, lease := range leases.Kvs {
relKey := strings.ReplaceAll(string(lease.Key), prefix, "")
if !strings.Contains("/", relKey) {
continue
}
r.handleLeaseOp(&clientv3.Event{
Type: mvccpb.PUT,
Kv: lease,
Expand All @@ -57,13 +63,21 @@ func (r *Role) loadInitialLeases(ctx context.Context) {
}

func (r *Role) startWatchLeases() {
prefix := r.i.KV().Key(
types.KeyRole,
types.KeyScopes,
).Prefix(true).String()
watchChan := r.i.KV().Watch(
r.ctx,
r.i.KV().Key(types.KeyRole, types.KeyLeases).Prefix(true).String(),
prefix,
clientv3.WithPrefix(),
)
for watchResp := range watchChan {
for _, event := range watchResp.Events {
relKey := strings.ReplaceAll(string(event.Kv.Key), prefix, "")
if !strings.Contains("/", relKey) {
continue
}
r.handleLeaseOp(event)
}
}
Expand Down
1 change: 0 additions & 1 deletion pkg/roles/dhcp/types/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ package types

const (
KeyRole = "dhcp"
KeyLeases = "leases"
KeyScopes = "scopes"
)
6 changes: 4 additions & 2 deletions pkg/roles/discovery/api_devices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ func TestDeviceApplyDHCP(t *testing.T) {
inst.KV(),
inst.KV().Key(
dhcpTypes.KeyRole,
dhcpTypes.KeyLeases,
dhcpTypes.KeyScopes,
name,
"aa:bb:cc",
),
dhcp.Lease{
Expand Down Expand Up @@ -193,7 +194,8 @@ func TestDeviceApplyDHCPWithDNS(t *testing.T) {
inst.KV(),
inst.KV().Key(
dhcpTypes.KeyRole,
dhcpTypes.KeyLeases,
dhcpTypes.KeyScopes,
name,
"aa:bb:cc",
),
dhcp.Lease{
Expand Down

0 comments on commit c9546c3

Please sign in to comment.