114 lines
2.3 KiB
Go
114 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) {
|
|
|
|
// 1. Inline
|
|
if src != nil && src.Inline != "" {
|
|
return parseCatalog([]byte(src.Inline))
|
|
}
|
|
|
|
// 2. 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))
|
|
}
|
|
|
|
// 3. 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)
|
|
}
|
|
|
|
// 4. cached fallback
|
|
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
|
|
}
|