mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 04:40:05 +01:00
feat: add credentials management
Signed-off-by: allanice001 <allanice001@gmail.com>
This commit is contained in:
186
internal/handlers/clusters.go
Normal file
186
internal/handlers/clusters.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/glueops/autoglue/internal/api/httpmiddleware"
|
||||
"github.com/glueops/autoglue/internal/common"
|
||||
"github.com/glueops/autoglue/internal/handlers/dto"
|
||||
"github.com/glueops/autoglue/internal/models"
|
||||
"github.com/glueops/autoglue/internal/utils"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ListClusters godoc
|
||||
//
|
||||
// @ID ListClusters
|
||||
// @Summary List clusters (org scoped)
|
||||
// @Description Returns clusters for the organization in X-Org-ID. Filter by `q` (name contains).
|
||||
// @Tags Clusters
|
||||
// @Produce json
|
||||
// @Param X-Org-ID header string false "Organization UUID"
|
||||
// @Param q query string false "Name contains (case-insensitive)"
|
||||
// @Success 200 {array} dto.ClusterResponse
|
||||
// @Failure 401 {string} string "Unauthorized"
|
||||
// @Failure 403 {string} string "organization required"
|
||||
// @Failure 500 {string} string "failed to list clusters"
|
||||
// @Router /clusters [get]
|
||||
// @Security BearerAuth
|
||||
// @Security OrgKeyAuth
|
||||
// @Security OrgSecretAuth
|
||||
func ListClusters(db *gorm.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
orgID, ok := httpmiddleware.OrgIDFrom(r.Context())
|
||||
if !ok {
|
||||
utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID")
|
||||
return
|
||||
}
|
||||
|
||||
q := db.Where("organization_id = ?", orgID)
|
||||
if needle := strings.TrimSpace(r.URL.Query().Get("q")); needle != "" {
|
||||
q = q.Where(`name ILIKE ?`, "%"+needle+"%")
|
||||
}
|
||||
|
||||
var rows []models.Cluster
|
||||
if err := q.
|
||||
Preload("NodePools").
|
||||
Preload("NodePools.Labels").
|
||||
Preload("NodePools.Annotations").
|
||||
Preload("NodePools.Labels").
|
||||
Preload("NodePools.Taints").
|
||||
Preload("NodePools.Servers").
|
||||
Preload("BastionServer").
|
||||
Find(&rows).Error; err != nil {
|
||||
utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error")
|
||||
return
|
||||
}
|
||||
|
||||
out := make([]dto.ClusterResponse, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
out = append(out, clusterToDTO(row))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CreateCluster godoc
|
||||
//
|
||||
// @ID CreateCluster
|
||||
// @Summary Create cluster (org scoped)
|
||||
// @Description Creates a cluster. If `kubeconfig` is provided, it will be encrypted per-organization and stored securely (never returned).
|
||||
// @Tags Clusters
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param X-Org-ID header string false "Organization UUID"
|
||||
// @Param body body dto.CreateClusterRequest true "payload"
|
||||
// @Success 201 {object} dto.ClusterResponse
|
||||
// @Failure 400 {string} string "invalid json"
|
||||
// @Failure 401 {string} string "Unauthorized"
|
||||
// @Failure 403 {string} string "organization required"
|
||||
// @Failure 500 {string} string "create failed"
|
||||
// @Router /clusters [post]
|
||||
// @Security BearerAuth
|
||||
// @Security OrgKeyAuth
|
||||
// @Security OrgSecretAuth
|
||||
func CreateCluster(db *gorm.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
// -- Helpers
|
||||
|
||||
func clusterToDTO(c models.Cluster) dto.ClusterResponse {
|
||||
var bastion *dto.ServerResponse
|
||||
if c.BastionServer != nil {
|
||||
b := serverToDTO(*c.BastionServer)
|
||||
bastion = &b
|
||||
}
|
||||
|
||||
nps := make([]dto.NodePoolResponse, 0, len(c.NodePools))
|
||||
for _, np := range c.NodePools {
|
||||
nps = append(nps, nodePoolToDTO(np))
|
||||
}
|
||||
|
||||
return dto.ClusterResponse{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Provider: c.Provider,
|
||||
Region: c.Region,
|
||||
Status: c.Status,
|
||||
CaptainDomain: c.CaptainDomain,
|
||||
ClusterLoadBalancer: c.ClusterLoadBalancer,
|
||||
RandomToken: c.RandomToken,
|
||||
CertificateKey: c.CertificateKey,
|
||||
ControlLoadBalancer: c.ControlLoadBalancer,
|
||||
NodePools: nps,
|
||||
BastionServer: bastion,
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func nodePoolToDTO(np models.NodePool) dto.NodePoolResponse {
|
||||
labels := make([]dto.LabelResponse, 0, len(np.Labels))
|
||||
for _, l := range np.Labels {
|
||||
labels = append(labels, dto.LabelResponse{
|
||||
Key: l.Key,
|
||||
Value: l.Value,
|
||||
})
|
||||
}
|
||||
|
||||
annotations := make([]dto.AnnotationResponse, 0, len(np.Annotations))
|
||||
for _, a := range np.Annotations {
|
||||
annotations = append(annotations, dto.AnnotationResponse{
|
||||
Key: a.Key,
|
||||
Value: a.Value,
|
||||
})
|
||||
}
|
||||
|
||||
taints := make([]dto.TaintResponse, 0, len(np.Taints))
|
||||
for _, t := range np.Taints {
|
||||
taints = append(taints, dto.TaintResponse{
|
||||
Key: t.Key,
|
||||
Value: t.Value,
|
||||
Effect: t.Effect,
|
||||
})
|
||||
}
|
||||
|
||||
servers := make([]dto.ServerResponse, 0, len(np.Servers))
|
||||
for _, s := range np.Servers {
|
||||
servers = append(servers, serverToDTO(s))
|
||||
}
|
||||
|
||||
return dto.NodePoolResponse{
|
||||
AuditFields: common.AuditFields{
|
||||
ID: np.ID,
|
||||
OrganizationID: np.OrganizationID,
|
||||
CreatedAt: np.CreatedAt,
|
||||
UpdatedAt: np.UpdatedAt,
|
||||
},
|
||||
Name: np.Name,
|
||||
Role: dto.NodeRole(np.Role),
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
Taints: taints,
|
||||
Servers: servers,
|
||||
}
|
||||
}
|
||||
|
||||
func serverToDTO(s models.Server) dto.ServerResponse {
|
||||
return dto.ServerResponse{
|
||||
ID: s.ID,
|
||||
Hostname: s.Hostname,
|
||||
PrivateIPAddress: s.PrivateIPAddress,
|
||||
PublicIPAddress: s.PublicIPAddress,
|
||||
Role: s.Role,
|
||||
Status: s.Status,
|
||||
SSHUser: s.SSHUser,
|
||||
SshKeyID: s.SshKeyID,
|
||||
CreatedAt: s.CreatedAt.UTC().Format(time.RFC3339),
|
||||
UpdatedAt: s.UpdatedAt.UTC().Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user