Files
garage-ui/backend/internal/services/admin_factory.go
T
Noste 390ccd7893 Support garage v1 (#31)
* feat: support garage v1
2026-04-24 09:53:56 +02:00

94 lines
2.3 KiB
Go

package services
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"Noooste/garage-ui/internal/config"
"Noooste/garage-ui/pkg/logger"
"github.com/Noooste/azuretls-client"
)
var ErrUnsupported = errors.New("operation not supported by this Garage version")
type Capabilities struct {
ClusterStatistics bool `json:"clusterStatistics"`
NodeInfo bool `json:"nodeInfo"`
NodeStatistics bool `json:"nodeStatistics"`
}
func CapabilitiesV2() Capabilities {
return Capabilities{
ClusterStatistics: true,
NodeInfo: true,
NodeStatistics: true,
}
}
func CapabilitiesV1() Capabilities {
return Capabilities{}
}
type AdminServiceResult struct {
Service AdminService
Capabilities Capabilities
APIVersion string
}
func NewAdminService(cfg *config.GarageConfig, logLevel string) (*AdminServiceResult, error) {
if err := probeEndpoint(cfg, "/v2/GetClusterHealth"); err == nil {
logger.Info().Str("api_version", "v2").Msg("Detected Garage admin API v2")
svc := NewGarageV2AdminService(cfg, logLevel)
return &AdminServiceResult{
Service: svc,
Capabilities: CapabilitiesV2(),
APIVersion: "v2",
}, nil
}
if err := probeEndpoint(cfg, "/v1/health"); err == nil {
logger.Info().
Str("api_version", "v1").
Msg("Detected Garage admin API v1 — cluster statistics and per-node details will be unavailable")
svc := NewGarageV1AdminService(cfg, logLevel)
return &AdminServiceResult{
Service: svc,
Capabilities: CapabilitiesV1(),
APIVersion: "v1",
}, nil
}
return nil, fmt.Errorf(
"could not connect to Garage admin API at %s. Ensure Garage v1.1+ is running and the admin API is enabled",
cfg.AdminEndpoint,
)
}
func probeEndpoint(cfg *config.GarageConfig, path string) error {
session := azuretls.NewSession()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := session.Do(&azuretls.Request{
Method: http.MethodGet,
Url: cfg.AdminEndpoint + path,
IgnoreBody: true,
OrderedHeaders: azuretls.OrderedHeaders{
{"Authorization", fmt.Sprintf("Bearer %s", cfg.AdminToken)},
},
}, ctx)
if err != nil {
return err
}
defer resp.RawBody.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("probe %s returned status %d", path, resp.StatusCode)
}
return nil
}