daemon: use exact-name lookup for VM-create uniqueness
reserveVM's duplicate-name guard routed through Daemon.FindVM, which falls back to prefix-matching on both ids and names when no exact match is found. That turns the uniqueness check into a correctness bug: a brand-new VM name can be rejected because it happens to prefix an existing VM's id, or an existing VM's name. So `vm create --name beta` fails when `beta-sandbox` already exists. Swap in a dedicated store.GetVMByName that does a literal `WHERE name = ?` lookup, and use it from reserveVM. FindVM keeps its prefix-matching behaviour for user-facing lookup paths (`vm ssh <partial>`, `vm stop <partial>`) where "did you mean" semantics are the feature. Tests: - TestReserveVMAllowsNameThatPrefixesExistingVM — seeds a VM whose id + name both start with "longname", then reserves two new VMs named "longname" and "longname-sandbox". Both must succeed. Under the old FindVM-based check, both would fail. - TestReserveVMRejectsExactDuplicateName — actual collisions are still rejected after the swap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
108f7a0600
commit
eba9a553bf
3 changed files with 105 additions and 2 deletions
|
|
@ -203,6 +203,20 @@ func (s *Store) GetVMByID(ctx context.Context, id string) (model.VMRecord, error
|
|||
return scanVMRow(row)
|
||||
}
|
||||
|
||||
// GetVMByName is the exact-name lookup used for creation-time
|
||||
// uniqueness checks. Unlike GetVM (which matches id OR name) and
|
||||
// Daemon.FindVM (which also falls back to prefix-matching), this
|
||||
// returns sql.ErrNoRows for anything except a literal name hit, so
|
||||
// a new VM can't be rejected just because its name prefixes an
|
||||
// existing VM's id or an existing VM's name.
|
||||
func (s *Store) GetVMByName(ctx context.Context, name string) (model.VMRecord, error) {
|
||||
row := s.db.QueryRowContext(ctx, `
|
||||
SELECT id, name, image_id, guest_ip, state, created_at, updated_at, last_touched_at,
|
||||
spec_json, runtime_json, stats_json
|
||||
FROM vms WHERE name = ?`, name)
|
||||
return scanVMRow(row)
|
||||
}
|
||||
|
||||
func (s *Store) ListVMs(ctx context.Context) ([]model.VMRecord, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT id, name, image_id, guest_ip, state, created_at, updated_at, last_touched_at,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue