OSUpgrade: Version Planning
This commit is contained in:
113
clitools/pkg/catalog/resolver.go
Normal file
113
clitools/pkg/catalog/resolver.go
Normal file
@@ -0,0 +1,113 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user