Reservation lease time; reservations by MAC address or client ID
- A reservation can have its own lease time (--lease-time, the reservation dialog), over the subnet's. Schema migration 6. - A reservation with a MAC address and a client ID matches either one (a dual-boot machine sends two client IDs from one MAC); before, it was found by MAC and then refused. A lease of the reserved address by the client's other identity counts as its own. - The Leases page shows a client's client ID; reserving a lease uses both, or one with --by / the dialog's choice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
abb2ee0fd7
commit
4fd72998ec
20 files changed
+252
-65
No files matched your search
@@ -434,3 +434,45 @@ func TestAddressOrderAPI(t *testing.T) {
|
||||
t.Errorf("bad pool order: %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReserveByClientID(t *testing.T) {
|
||||
e := newEnv(t)
|
||||
e.call(e.token, "POST", "/subnets", api.SubnetInput{Prefix: ptr("10.0.20.0/24"), Interface: ptr("eth0.20"), Pools: &[]string{"10.0.20.100-10.0.20.110"}}, nil)
|
||||
get := func(id byte) netip.Addr {
|
||||
m := net.HardwareAddr{0xaa, 0, 0, 0, 0, id}
|
||||
disc := dhcp4.NewRequest(dhcp4.Discover, m, 1)
|
||||
disc.Set(dhcp4.OptClientID, []byte{0xff, id})
|
||||
off := e.dhcp.Handle(context.Background(), "eth0.20", disc)
|
||||
req := dhcp4.NewRequest(dhcp4.Request, m, 2)
|
||||
req.Set(dhcp4.OptClientID, []byte{0xff, id})
|
||||
req.Set(dhcp4.OptServerID, dhcp4.IP(netip.MustParseAddr("10.0.20.1")))
|
||||
req.Set(dhcp4.OptRequestedIP, dhcp4.IP(off.Packet.YIAddr))
|
||||
e.dhcp.Handle(context.Background(), "eth0.20", req)
|
||||
return off.Packet.YIAddr
|
||||
}
|
||||
a, b := get(1), get(2)
|
||||
var mr api.MutationResponse
|
||||
if code := e.call(e.token, "POST", "/leases/"+a.String()+"/reserve", map[string]any{}, &mr); code != 201 {
|
||||
t.Fatalf("reserve: %d", code)
|
||||
}
|
||||
var rv api.Reservation
|
||||
json.Unmarshal(mr.Object, &rv)
|
||||
if rv.MAC != "aa:00:00:00:00:01" || rv.ClientID != "ff01" {
|
||||
t.Errorf("both: %+v", rv)
|
||||
}
|
||||
if code := e.call(e.token, "POST", "/leases/"+b.String()+"/reserve", map[string]any{"by": "client_id"}, &mr); code != 201 {
|
||||
t.Fatalf("reserve by id: %d", code)
|
||||
}
|
||||
rv = api.Reservation{}
|
||||
json.Unmarshal(mr.Object, &rv)
|
||||
if rv.MAC != "" || rv.ClientID != "ff02" {
|
||||
t.Errorf("by client id: %+v", rv)
|
||||
}
|
||||
var eb api.ErrorBody
|
||||
if code := e.call(e.token, "PATCH", "/reservations/"+itoa(rv.ID), api.ReservationInput{LeaseTime: ptr(10)}, &eb); code != 422 || eb.Error.Problems[0].Code != "lease_time_range" {
|
||||
t.Errorf("short lease time: %d %+v", code, eb)
|
||||
}
|
||||
if code := e.call(e.token, "PATCH", "/reservations/"+itoa(rv.ID), api.ReservationInput{LeaseTime: ptr(7 * 86400)}, nil); code != 200 || e.eng.State().ReservationByID(rv.ID).LeaseTime != 7*86400 {
|
||||
t.Errorf("lease time: %d", code)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user