kubekey/pkg/variable/variable.go
joyceliu 2eed0820d7 fix: add operator
Signed-off-by: joyceliu <joyceliu@yunify.com>
2024-05-29 10:32:02 +08:00

139 lines
4.5 KiB
Go

/*
Copyright 2023 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package variable
import (
"context"
"encoding/json"
"fmt"
"path/filepath"
"strings"
"k8s.io/apimachinery/pkg/types"
cgcache "k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
kubekeyv1 "github.com/kubesphere/kubekey/v4/pkg/apis/kubekey/v1"
_const "github.com/kubesphere/kubekey/v4/pkg/const"
"github.com/kubesphere/kubekey/v4/pkg/variable/source"
)
type GetFunc func(Variable) (any, error)
type MergeFunc func(Variable) error
type Variable interface {
Key() string
Get(GetFunc) (any, error)
Merge(MergeFunc) error
}
// New variable. generate value from config args. and render to source.
func New(client ctrlclient.Client, pipeline kubekeyv1.Pipeline) (Variable, error) {
// new source
s, err := source.New(filepath.Join(_const.RuntimeDirFromPipeline(pipeline), _const.RuntimePipelineVariableDir))
if err != nil {
klog.V(4).ErrorS(err, "create file source failed", "path", filepath.Join(_const.RuntimeDirFromPipeline(pipeline), _const.RuntimePipelineVariableDir), "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
// get config
var config = &kubekeyv1.Config{}
if err := client.Get(context.Background(), types.NamespacedName{Namespace: pipeline.Spec.ConfigRef.Namespace, Name: pipeline.Spec.ConfigRef.Name}, config); err != nil {
klog.V(4).ErrorS(err, "get config from pipeline error", "config", pipeline.Spec.ConfigRef, "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
// get inventory
var inventory = &kubekeyv1.Inventory{}
if err := client.Get(context.Background(), types.NamespacedName{Namespace: pipeline.Spec.InventoryRef.Namespace, Name: pipeline.Spec.InventoryRef.Name}, inventory); err != nil {
klog.V(4).ErrorS(err, "get inventory from pipeline error", "inventory", pipeline.Spec.InventoryRef, "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
v := &variable{
key: string(pipeline.UID),
source: s,
value: &value{
Config: *config,
Inventory: *inventory,
Hosts: make(map[string]host),
},
}
for _, hostname := range convertGroup(*inventory)["all"].([]string) {
v.value.Hosts[hostname] = host{
RemoteVars: make(map[string]any),
RuntimeVars: make(map[string]any),
}
}
// read data from source
data, err := v.source.Read()
if err != nil {
klog.V(4).ErrorS(err, "read data from source error", "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
for k, d := range data {
// set hosts
h := host{}
if err := json.Unmarshal(d, &h); err != nil {
klog.V(4).ErrorS(err, "unmarshal host error", "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
v.value.Hosts[strings.TrimSuffix(k, ".json")] = h
}
return v, nil
}
// Cache is a cache for variable
var Cache = cgcache.NewStore(func(obj interface{}) (string, error) {
v, ok := obj.(Variable)
if !ok {
return "", fmt.Errorf("cannot convert %v to variable", obj)
}
return v.Key(), nil
})
func GetVariable(client ctrlclient.Client, pipeline kubekeyv1.Pipeline) (Variable, error) {
vars, ok, err := Cache.GetByKey(string(pipeline.UID))
if err != nil {
klog.V(5).ErrorS(err, "get variable error", "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
if ok {
return vars.(Variable), nil
}
// add new variable to cache
nv, err := New(client, pipeline)
if err != nil {
klog.V(5).ErrorS(err, "create variable error", "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
if err := Cache.Add(nv); err != nil {
klog.V(5).ErrorS(err, "add variable to store error", "pipeline", ctrlclient.ObjectKeyFromObject(&pipeline))
return nil, err
}
return nv, nil
}
func CleanVariable(p *kubekeyv1.Pipeline) {
if _, ok, err := Cache.GetByKey(string(p.UID)); err == nil && ok {
if err := Cache.Delete(string(p.UID)); err != nil {
klog.ErrorS(err, "delete variable from cache error", "pipeline", ctrlclient.ObjectKeyFromObject(p))
}
}
}