mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 21:00:06 +01:00
most of the working app
This commit is contained in:
191
internal/handlers/clusters/funcs.go
Normal file
191
internal/handlers/clusters/funcs.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/glueops/autoglue/internal/db"
|
||||
"github.com/glueops/autoglue/internal/db/models"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func ensureNodePoolsBelongToOrg(orgID uuid.UUID, ids []uuid.UUID) error {
|
||||
if len(ids) == 0 {
|
||||
return errors.New("empty ids")
|
||||
}
|
||||
var count int64
|
||||
if err := db.DB.Model(&models.NodePool{}).
|
||||
Where("organization_id = ? AND id IN ?", orgID, ids).
|
||||
Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count != int64(len(ids)) {
|
||||
return errors.New("some node pools do not belong to org")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureServerBelongsToOrgWithRole(orgID uuid.UUID, id uuid.UUID, role string) error {
|
||||
var count int64
|
||||
if err := db.DB.Model(&models.Server{}).
|
||||
Where("organization_id = ? AND id = ? AND role = ?", orgID, id, role).
|
||||
Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count != 1 {
|
||||
return errors.New("server not found in org or role mismatch")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toResp(c models.Cluster, includePools, includeBastion bool) clusterResponse {
|
||||
out := clusterResponse{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Provider: c.Provider,
|
||||
Region: c.Region,
|
||||
Status: c.Status,
|
||||
ClusterLoadBalancer: c.ClusterLoadBalancer,
|
||||
ControlLoadBalancer: c.ControlLoadBalancer,
|
||||
}
|
||||
if includePools {
|
||||
out.NodePools = make([]nodePoolBrief, 0, len(c.NodePools))
|
||||
for _, p := range c.NodePools {
|
||||
nb := nodePoolBrief{ID: p.ID, Name: p.Name}
|
||||
fmt.Printf("node pool %s\n", p.Name)
|
||||
fmt.Printf("node pool labels %d\n", len(p.Labels))
|
||||
if len(p.Labels) > 0 {
|
||||
nb.Labels = make([]labelBrief, 0, len(p.Labels))
|
||||
for _, l := range p.Labels {
|
||||
nb.Labels = append(nb.Labels, labelBrief{ID: l.ID, Key: l.Key, Value: l.Value})
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("node pool annotations %d\n", len(p.Annotations))
|
||||
|
||||
if len(p.Annotations) > 0 {
|
||||
nb.Annotations = make([]annotationBrief, 0, len(p.Annotations))
|
||||
for _, a := range p.Annotations {
|
||||
nb.Annotations = append(nb.Annotations, annotationBrief{ID: a.ID, Key: a.Key, Value: a.Value})
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("node pool taints %d\n", len(p.Taints))
|
||||
|
||||
if len(p.Taints) > 0 {
|
||||
nb.Taints = make([]taintBrief, 0, len(p.Taints))
|
||||
for _, t := range p.Taints {
|
||||
nb.Taints = append(nb.Taints, taintBrief{ID: t.ID, Key: t.Key, Value: t.Value, Effect: t.Effect})
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.Servers) > 0 {
|
||||
nb.Servers = make([]serverBrief, 0, len(p.Servers))
|
||||
for _, s := range p.Servers {
|
||||
nb.Servers = append(nb.Servers, serverBrief{ID: s.ID, Hostname: s.Hostname, Role: s.Role, Status: s.Status, IP: s.IPAddress})
|
||||
}
|
||||
}
|
||||
|
||||
out.NodePools = append(out.NodePools, nb)
|
||||
}
|
||||
}
|
||||
if includeBastion && c.BastionServer != nil {
|
||||
out.BastionServer = &serverBrief{
|
||||
ID: c.BastionServer.ID,
|
||||
Hostname: c.BastionServer.Hostname,
|
||||
IP: c.BastionServer.IPAddress,
|
||||
Role: c.BastionServer.Role,
|
||||
Status: c.BastionServer.Status,
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func contains(xs []string, want string) bool {
|
||||
for _, x := range xs {
|
||||
if strings.TrimSpace(x) == want {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func errorsIsNotFound(err error) bool { return err == gorm.ErrRecordNotFound }
|
||||
|
||||
func parseUUIDs(ids []string) ([]uuid.UUID, error) {
|
||||
out := make([]uuid.UUID, 0, len(ids))
|
||||
for _, s := range ids {
|
||||
u, err := uuid.Parse(strings.TrimSpace(s))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, u)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
const maxJSONBytes int64 = 1 << 20
|
||||
|
||||
func readJSON(w http.ResponseWriter, r *http.Request, dst any) bool {
|
||||
if ct := r.Header.Get("Content-Type"); ct != "" {
|
||||
mt, _, err := mime.ParseMediaType(ct)
|
||||
if err != nil || mt != "application/json" {
|
||||
http.Error(w, "Content-Type must be application/json", http.StatusUnsupportedMediaType)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxJSONBytes)
|
||||
defer r.Body.Close()
|
||||
|
||||
dec := json.NewDecoder(r.Body)
|
||||
dec.DisallowUnknownFields()
|
||||
|
||||
if err := dec.Decode(dst); err != nil {
|
||||
var syntaxErr *json.SyntaxError
|
||||
var typeErr *json.UnmarshalTypeError
|
||||
var maxErr *http.MaxBytesError
|
||||
|
||||
switch {
|
||||
case errors.As(err, &maxErr):
|
||||
http.Error(w, fmt.Sprintf("request body too large (max %d bytes)", maxJSONBytes), http.StatusRequestEntityTooLarge)
|
||||
case errors.Is(err, io.EOF):
|
||||
http.Error(w, "request body must not be empty", http.StatusBadRequest)
|
||||
case errors.As(err, &syntaxErr):
|
||||
http.Error(w, fmt.Sprintf("malformed JSON at character %d", syntaxErr.Offset), http.StatusBadRequest)
|
||||
case errors.Is(err, io.ErrUnexpectedEOF):
|
||||
http.Error(w, "malformed JSON", http.StatusBadRequest)
|
||||
case errors.As(err, &typeErr):
|
||||
// Example: expected string but got number for field "name"
|
||||
field := typeErr.Field
|
||||
if field == "" && len(typeErr.Struct) > 0 {
|
||||
field = typeErr.Struct
|
||||
}
|
||||
http.Error(w, fmt.Sprintf("invalid value for %q (expected %s)", field, typeErr.Type.String()), http.StatusBadRequest)
|
||||
case strings.HasPrefix(err.Error(), "json: unknown field "):
|
||||
// Extract the field name from the error message.
|
||||
field := strings.Trim(strings.TrimPrefix(err.Error(), "json: unknown field "), "\"")
|
||||
http.Error(w, fmt.Sprintf("unknown field %q", field), http.StatusBadRequest)
|
||||
default:
|
||||
http.Error(w, "invalid json", http.StatusBadRequest)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if dec.More() {
|
||||
// Try to read one more token/value; if not EOF, there was extra content.
|
||||
var extra any
|
||||
if err := dec.Decode(&extra); err != io.EOF {
|
||||
http.Error(w, "body must contain only a single JSON object", http.StatusBadRequest)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user