Files
monok8s/clitools/pkg/catalog/resolver.go
2026-04-04 02:45:46 +08:00

112 lines
2.3 KiB
Go

package catalog
import (
"context"
"fmt"
"io"
"net/http"
"os"
"sigs.k8s.io/yaml"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
monov1alpha1 "example.com/monok8s/pkg/apis/monok8s/v1alpha1"
)
const (
DefaultCachePath = "/var/lib/monok8s/catalog.yaml"
)
// ResolveCatalog resolves catalog using priority:
// Inline > ConfigMap > URL > cached
func ResolveCatalog(ctx context.Context,
kubeClient kubernetes.Interface,
namespace string, src *monov1alpha1.VersionCatalogSource,
) (*VersionCatalog, error) {
// Inline
if src != nil && src.Inline != "" {
return parseCatalog([]byte(src.Inline))
}
// ConfigMap
if src != nil && src.ConfigMap != "" {
cm, err := kubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, src.ConfigMap, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("get catalog configmap: %w", err)
}
data, ok := cm.Data["catalog.yaml"]
if !ok {
return nil, fmt.Errorf("configmap %s missing key catalog.yaml", src.ConfigMap)
}
return parseCatalog([]byte(data))
}
// URL
if src != nil && src.URL != "" {
cat, err := fetchCatalog(src.URL)
if err == nil {
_ = os.WriteFile(DefaultCachePath, mustMarshal(cat), 0644)
return cat, nil
}
// fallback to cache
if cached, err2 := loadCached(); err2 == nil {
return cached, nil
}
return nil, fmt.Errorf("fetch catalog failed and no cache: %w", err)
}
// fallback cache
if cached, err := loadCached(); err == nil {
return cached, nil
}
return nil, fmt.Errorf("no catalog source available")
}
func fetchCatalog(url string) (*VersionCatalog, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("http %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return parseCatalog(body)
}
func loadCached() (*VersionCatalog, error) {
data, err := os.ReadFile(DefaultCachePath)
if err != nil {
return nil, err
}
return parseCatalog(data)
}
func parseCatalog(data []byte) (*VersionCatalog, error) {
var c VersionCatalog
if err := yaml.Unmarshal(data, &c); err != nil {
return nil, fmt.Errorf("parse catalog: %w", err)
}
return &c, nil
}
func mustMarshal(c *VersionCatalog) []byte {
b, _ := yaml.Marshal(c)
return b
}