Remove unused hostname_prefix from server types and add duplicate checking
The HostnamePrefix field on ServerType was loaded from YAML but never used — hostnames are user-provided. This removes the field and adds explicit duplicate checks (hostname + MAC) with clear per-field error messages in both the JSON API and web UI, backed by a new GetByHostname store method with case-insensitive matching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -134,7 +134,6 @@ func mustLoadServerTypes(t *testing.T, dir string) *config.ServerTypeRegistry {
|
||||
boot_disk: "/dev/sda"
|
||||
management_nic: "eth0"
|
||||
gpu: false
|
||||
hostname_prefix: "pve-test"
|
||||
`)
|
||||
if err := writeTestFile(path, content); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -337,6 +336,82 @@ func TestOperationNotFound(t *testing.T) {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
func TestDuplicateHostnameRejected(t *testing.T) {
|
||||
ts := newTestServer(t)
|
||||
defer ts.Close()
|
||||
|
||||
body := `{"hostname":"pve-dup-01","mac":"aa:bb:cc:dd:ee:d1","server_type":"test-type"}`
|
||||
resp, err := http.Post(ts.URL+"/api/hosts", "application/json", bytes.NewBufferString(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("first create: got %d, want %d", resp.StatusCode, http.StatusCreated)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
body = `{"hostname":"pve-dup-01","mac":"aa:bb:cc:dd:ee:d2","server_type":"test-type"}`
|
||||
resp, err = http.Post(ts.URL+"/api/hosts", "application/json", bytes.NewBufferString(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusConflict {
|
||||
t.Fatalf("dup hostname: got %d, want %d", resp.StatusCode, http.StatusConflict)
|
||||
}
|
||||
var errResp map[string]any
|
||||
json.NewDecoder(resp.Body).Decode(&errResp)
|
||||
resp.Body.Close()
|
||||
if msg, _ := errResp["error"].(string); msg != "a host with this hostname already exists" {
|
||||
t.Fatalf("dup hostname error = %q, want specific hostname message", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateMACRejected(t *testing.T) {
|
||||
ts := newTestServer(t)
|
||||
defer ts.Close()
|
||||
|
||||
body := `{"hostname":"pve-mac-01","mac":"aa:bb:cc:dd:ee:e1","server_type":"test-type"}`
|
||||
resp, err := http.Post(ts.URL+"/api/hosts", "application/json", bytes.NewBufferString(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("first create: got %d, want %d", resp.StatusCode, http.StatusCreated)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
body = `{"hostname":"pve-mac-02","mac":"aa:bb:cc:dd:ee:e1","server_type":"test-type"}`
|
||||
resp, err = http.Post(ts.URL+"/api/hosts", "application/json", bytes.NewBufferString(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusConflict {
|
||||
t.Fatalf("dup MAC: got %d, want %d", resp.StatusCode, http.StatusConflict)
|
||||
}
|
||||
var errResp map[string]any
|
||||
json.NewDecoder(resp.Body).Decode(&errResp)
|
||||
resp.Body.Close()
|
||||
if msg, _ := errResp["error"].(string); msg != "a host with this MAC address already exists" {
|
||||
t.Fatalf("dup MAC error = %q, want specific MAC message", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateHostnameCaseInsensitive(t *testing.T) {
|
||||
ts := newTestServer(t)
|
||||
defer ts.Close()
|
||||
|
||||
body := `{"hostname":"pve-case-01","mac":"aa:bb:cc:dd:ee:c1","server_type":"test-type"}`
|
||||
resp, _ := http.Post(ts.URL+"/api/hosts", "application/json", bytes.NewBufferString(body))
|
||||
resp.Body.Close()
|
||||
|
||||
body = `{"hostname":"PVE-CASE-01","mac":"aa:bb:cc:dd:ee:c2","server_type":"test-type"}`
|
||||
resp, _ = http.Post(ts.URL+"/api/hosts", "application/json", bytes.NewBufferString(body))
|
||||
if resp.StatusCode != http.StatusConflict {
|
||||
t.Fatalf("case-insensitive dup: got %d, want %d", resp.StatusCode, http.StatusConflict)
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
func itoa(i int64) string {
|
||||
return fmt.Sprintf("%d", i)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user