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:
Thales Maciel 2026-04-20 14:00:33 -03:00
parent 108f7a0600
commit eba9a553bf
No known key found for this signature in database
GPG key ID: 33112E6833C34679
3 changed files with 105 additions and 2 deletions

View file

@ -115,9 +115,12 @@ func (d *Daemon) reserveVM(ctx context.Context, requestedName string, image mode
}
name = generated
}
if _, err := d.FindVM(ctx, name); err == nil {
// Exact-name lookup. Using FindVM here would also match a new name
// that merely prefixes some existing VM's id or another VM's name,
// falsely rejecting perfectly valid names.
if _, err := d.store.GetVMByName(ctx, name); err == nil {
return model.VMRecord{}, fmt.Errorf("vm name already exists: %s", name)
} else if !errors.Is(err, sql.ErrNoRows) && !strings.Contains(err.Error(), "not found") {
} else if !errors.Is(err, sql.ErrNoRows) {
return model.VMRecord{}, err
}