(c *gin.Context)
| 1073 | if _, ok := fields["max_hot_idle_cpu"]; ok { |
| 1074 | merged.MaxHotIdleCPU = updates.MaxHotIdleCPU |
| 1075 | } |
| 1076 | if _, ok := fields["max_hot_idle_memory"]; ok { |
| 1077 | merged.MaxHotIdleMemory = updates.MaxHotIdleMemory |
| 1078 | } |
| 1079 | if _, ok := fields["hostname_alias"]; ok { |
| 1080 | merged.HostnameAlias = updates.HostnameAlias |
| 1081 | } |
| 1082 | if _, ok := fields["data_imports_table_naming_version"]; ok { |
| 1083 | merged.DataImportsTableNamingVersion = updates.DataImportsTableNamingVersion |
| 1084 | } |
| 1085 | // Audit detail: which fields changed and their old → new values, so the |
| 1086 | // console shows "max_workers 4 → 10" instead of a bare "org.update". These |
| 1087 | // are all non-sensitive config columns (no credentials among them). |
| 1088 | var changes []string |
| 1089 | addChange := func(key string, old, next any) { |
| 1090 | if _, ok := fields[key]; ok && old != next { |
| 1091 | changes = append(changes, fmt.Sprintf("%s %v → %v", key, old, next)) |
| 1092 | } |
| 1093 | } |
| 1094 | addChange("database_name", existing.DatabaseName, merged.DatabaseName) |
| 1095 | addChange("max_workers", existing.MaxWorkers, merged.MaxWorkers) |
| 1096 | addChange("max_vcpus", existing.MaxVCPUs, merged.MaxVCPUs) |
| 1097 | addChange("default_worker_cpu", orgStr(existing.DefaultWorkerCPU), orgStr(merged.DefaultWorkerCPU)) |
| 1098 | addChange("default_worker_memory", orgStr(existing.DefaultWorkerMemory), orgStr(merged.DefaultWorkerMemory)) |
| 1099 | addChange("default_worker_ttl", orgStr(existing.DefaultWorkerTTL), orgStr(merged.DefaultWorkerTTL)) |
| 1100 | addChange("default_worker_min_hot_idle", existing.DefaultWorkerMinHotIdle, merged.DefaultWorkerMinHotIdle) |
| 1101 | addChange("max_hot_idle_workers", existing.MaxHotIdleWorkers, merged.MaxHotIdleWorkers) |
| 1102 | addChange("max_hot_idle_cpu", orgStr(existing.MaxHotIdleCPU), orgStr(merged.MaxHotIdleCPU)) |
| 1103 | addChange("max_hot_idle_memory", orgStr(existing.MaxHotIdleMemory), orgStr(merged.MaxHotIdleMemory)) |
| 1104 | addChange("hostname_alias", orgStrPtr(existing.HostnameAlias), orgStrPtr(merged.HostnameAlias)) |
| 1105 | addChange("data_imports_table_naming_version", existing.DataImportsTableNamingVersion, merged.DataImportsTableNamingVersion) |
| 1106 | if len(changes) > 0 { |
| 1107 | setAuditDetail(c, strings.Join(changes, ", ")) |
| 1108 | } |
| 1109 | |
| 1110 | org, ok, err := h.store.UpdateOrg(name, merged) |
| 1111 | if err != nil { |
| 1112 | if configstore.IsUniqueViolationErr(err) { |
| 1113 | // database_name or hostname_alias unique index — same 409 the |
| 1114 | // create/provision surfaces map for the identical conflict. |
| 1115 | c.JSON(http.StatusConflict, gin.H{"error": "database_name or hostname_alias is already in use by another org"}) |
| 1116 | return |
| 1117 | } |
| 1118 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) |
| 1119 | return |
| 1120 | } |
| 1121 | if !ok { |
| 1122 | c.JSON(http.StatusNotFound, gin.H{"error": "org not found"}) |
| 1123 | return |
| 1124 | } |
| 1125 | // A database_name rename moves the org's managed hostname: without forcing |
| 1126 | // a reload, every replica routes on its stale snapshot until the next poll |
| 1127 | // (the new hostname 08006s while the API here already reported success). |
| 1128 | // Same snapshot-convergence contract as user/team mutations. |
| 1129 | if existing.DatabaseName != org.DatabaseName { |
| 1130 | if err := h.notifyPeersOfChange(c); err != nil { |
| 1131 | c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("renamed, but failed to reload the local snapshot: %v", err)}) |
| 1132 | return |
no test coverage detected