diff --git a/internal/api/virt.go b/internal/api/virt.go index 56b2467..a997c41 100644 --- a/internal/api/virt.go +++ b/internal/api/virt.go @@ -388,6 +388,12 @@ func (s *Server) virtConfig(w http.ResponseWriter, r *http.Request) { return } var set, unset []string + desc, hasDesc := body["description"] + delete(body, "description") + if hasDesc && (len(desc) > 200 || strings.ContainsAny(desc, "\n\r")) { + jsonErr(w, 400, "bad value for description") + return + } for k, v := range body { v = strings.TrimSpace(v) ok := false @@ -400,8 +406,6 @@ func (s *Server) virtConfig(w http.ResponseWriter, r *http.Request) { ok = incus.ValidCron(v) case "snapshots.expiry": ok = incus.ValidExpiry(v) - case "description": - ok = len(v) <= 200 && !strings.ContainsAny(v, "\n\r") case "boot.autostart": ok = v == "" || v == "true" || v == "false" } @@ -429,6 +433,14 @@ func (s *Server) virtConfig(w http.ResponseWriter, r *http.Request) { for _, k := range unset { _, _ = s.virt.Cmd(ctx, "config", "unset", name, k).CombinedOutput() // unsetting what isn't set is fine } + if hasDesc { + // the description is a field of the instance, not a config key, so it goes in through the API + patch, _ := json.Marshal(map[string]string{"description": strings.TrimSpace(desc)}) + if out, err := s.virt.Cmd(ctx, "query", "-X", "PATCH", "-d", string(patch), "/1.0/instances/"+name).CombinedOutput(); err != nil { + jsonErr(w, 409, strings.TrimPrefix(strings.TrimSpace(string(out)), "Error: ")) + return + } + } log.Printf("virt: config %s set %v unset %v (from %s)", name, set, unset, clientIP(r)) w.WriteHeader(204) }