Disable reservations; subnet enable/disable buttons; page-head CSS fix
release / release (push) Successful in 5m53s
release / release (push) Successful in 5m53s
- A disabled reservation is kept but ignored: the client gets a pool address like any other (steward reservation disable|enable, buttons and a checkbox in the web UI). Schema migration 3. - Subnets get Disable/Enable buttons on their page and in the list. - A rule left without its selector in style.css broke the page heading's layout, so the New ... buttons sat cramped under the description. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7b3f0f764c
commit
6ad1bb9a0d
21 files changed
+165
-37
No files matched your search
@@ -50,7 +50,7 @@ func (s *Store) LoadState(ctx context.Context) (*model.State, error) {
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows, err = s.db.QueryContext(ctx, `SELECT id, mac, client_id, ip, hostname, options, comment FROM reservations ORDER BY id`)
|
||||
rows, err = s.db.QueryContext(ctx, `SELECT id, mac, client_id, ip, hostname, options, disabled, comment FROM reservations ORDER BY id`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -58,10 +58,12 @@ func (s *Store) LoadState(ctx context.Context) (*model.State, error) {
|
||||
for rows.Next() {
|
||||
r := &model.Reservation{}
|
||||
var ip, opts string
|
||||
if err := rows.Scan(&r.ID, &r.MAC, &r.ClientID, &ip, &r.Hostname, &opts, &r.Comment); err != nil {
|
||||
var disabled int
|
||||
if err := rows.Scan(&r.ID, &r.MAC, &r.ClientID, &ip, &r.Hostname, &opts, &disabled, &r.Comment); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.IP, _ = netip.ParseAddr(ip)
|
||||
r.Disabled = disabled != 0
|
||||
if err := json.Unmarshal([]byte(opts), &r.Options); err != nil {
|
||||
return nil, fmt.Errorf("reservation %d options: %w", r.ID, err)
|
||||
}
|
||||
@@ -158,10 +160,10 @@ func applyChange(ctx context.Context, tx *sql.Tx, c model.Change) error {
|
||||
if err := json.Unmarshal(c.After, &r); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := tx.ExecContext(ctx, `INSERT INTO reservations (id, mac, client_id, ip, hostname, options, comment) VALUES (?,?,?,?,?,?,?)
|
||||
_, err := tx.ExecContext(ctx, `INSERT INTO reservations (id, mac, client_id, ip, hostname, options, disabled, comment) VALUES (?,?,?,?,?,?,?,?)
|
||||
ON CONFLICT(id) DO UPDATE SET mac = excluded.mac, client_id = excluded.client_id, ip = excluded.ip, hostname = excluded.hostname,
|
||||
options = excluded.options, comment = excluded.comment`,
|
||||
r.ID, r.MAC, r.ClientID, r.IP.String(), r.Hostname, jsonText(nonNilOpts(r.Options)), r.Comment)
|
||||
options = excluded.options, disabled = excluded.disabled, comment = excluded.comment`,
|
||||
r.ID, r.MAC, r.ClientID, r.IP.String(), r.Hostname, jsonText(nonNilOpts(r.Options)), boolInt(r.Disabled), r.Comment)
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("unknown kind %q", c.Kind)
|
||||
|
||||
@@ -193,6 +193,10 @@ CREATE INDEX audit_time ON audit (time);
|
||||
ALTER TABLE tokens ADD COLUMN rotated_at TEXT;
|
||||
ALTER TABLE tokens ADD COLUMN prev_secret_hash TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE tokens ADD COLUMN prev_expires_at TEXT;
|
||||
`,
|
||||
// 3: disabled reservations.
|
||||
`
|
||||
ALTER TABLE reservations ADD COLUMN disabled INTEGER NOT NULL DEFAULT 0;
|
||||
`,
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestStateHistoryAndLeases(t *testing.T) {
|
||||
sn := &model.Subnet{ID: ids[0], Name: "office", Interface: "eth0", Prefix: netip.MustParsePrefix("10.0.10.0/24"),
|
||||
Pools: []model.Pool{{Start: netip.MustParseAddr("10.0.10.100"), End: netip.MustParseAddr("10.0.10.199")}},
|
||||
Options: []model.OptionValue{{Code: 3, Value: "10.0.10.1"}}}
|
||||
r := &model.Reservation{ID: ids[1], MAC: "aa:bb:cc:dd:ee:01", IP: netip.MustParseAddr("10.0.10.20"), Hostname: "nas"}
|
||||
r := &model.Reservation{ID: ids[1], MAC: "aa:bb:cc:dd:ee:01", IP: netip.MustParseAddr("10.0.10.20"), Hostname: "nas", Disabled: true}
|
||||
set := st.Settings
|
||||
set.LeaseTime = 3600
|
||||
e := &model.HistoryEntry{Time: time.Now(), Username: "admin", Via: "cli", Description: "add office",
|
||||
@@ -51,7 +51,7 @@ func TestStateHistoryAndLeases(t *testing.T) {
|
||||
if len(st.Subnets) != 1 || st.Subnets[0].Pools[0].Size() != 100 || st.Subnets[0].Options[0].Value != "10.0.10.1" {
|
||||
t.Errorf("subnets %+v", st.Subnets)
|
||||
}
|
||||
if len(st.Reservations) != 1 || st.Reservations[0].Hostname != "nas" || st.Settings.LeaseTime != 3600 {
|
||||
if len(st.Reservations) != 1 || st.Reservations[0].Hostname != "nas" || !st.Reservations[0].Disabled || st.Settings.LeaseTime != 3600 {
|
||||
t.Errorf("reservations %+v settings %+v", st.Reservations, st.Settings)
|
||||
}
|
||||
// Undo: the inverse changes, marked as a revert.
|
||||
|
||||
Reference in new issue
Block a user