* Copyright (c) 2025 Bocloud Technologies Co., Ltd.
* installer is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain n copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
******************************************************************/
package scriptshelper
import (
"context"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
kerrors "k8s.io/apimachinery/pkg/util/errors"
"sigs.k8s.io/controller-runtime/pkg/client"
"gopkg.openfuyao.cn/cluster-api-provider-bke/utils"
"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/capbke/constant"
labelhelper "gopkg.openfuyao.cn/cluster-api-provider-bke/utils/capbke/label"
"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/log"
)
func isScriptFile(filename string) bool {
return strings.HasSuffix(filename, ".sh") || strings.HasSuffix(filename, ".py")
}
func CollectScriptFiles(scriptsDir string) (map[string]string, error) {
scripts := make(map[string]string)
err := filepath.Walk(scriptsDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if isScriptFile(info.Name()) {
scripts[info.Name()] = path
}
return nil
})
if err != nil {
return nil, errors.Wrapf(err, "scan directories failed: %s", scriptsDir)
}
return scripts, nil
}
func CreateScriptsConfigMaps(c client.Client) error {
scripts, err := CollectScriptFiles(constant.K8sScriptsDir)
if err != nil {
return err
}
var errs []error
for name, path := range scripts {
if err = createOrUpdateScriptConfigMap(c, name, path); err != nil {
errs = append(errs, err)
}
}
return kerrors.NewAggregate(errs)
}
func createOrUpdateScriptConfigMap(c client.Client, name, filePath string) error {
content, err := readAndNormalizeScript(filePath)
if err != nil {
return errors.Wrapf(err, "get scripts file failed: %s", filePath)
}
cm := buildScriptConfigMap(name, content)
if err = createOrUpdateConfigMap(c, cm); err != nil {
return errors.Wrapf(err, "deal config map failed: %s", name)
}
log.Infof("load env script file %q to configmap %q", name, utils.ClientObjNS(cm))
return nil
}
func readAndNormalizeScript(filePath string) (string, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
normalized := strings.ReplaceAll(string(content), "\r\n", "\n")
return normalized, nil
}
func buildScriptConfigMap(name, content string) *corev1.ConfigMap {
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: "cluster-system",
Labels: map[string]string{labelhelper.ScriptsLabelKey: ""},
},
Data: map[string]string{
name: content,
},
}
}
func createOrUpdateConfigMap(c client.Client, cm *corev1.ConfigMap) error {
if err := c.Create(context.Background(), cm); err != nil {
if !apierrors.IsAlreadyExists(err) {
return err
}
log.Infof("script file exist, update env init script file %q to configmap %q",
cm.Name, utils.ClientObjNS(cm))
if err = c.Update(context.Background(), cm); err != nil {
return err
}
}
return nil
}
func ListScriptsConfigMaps(c client.Client) ([]string, error) {
cmList := &corev1.ConfigMapList{}
err := c.List(context.Background(), cmList, &client.ListOptions{
Namespace: "cluster-system",
LabelSelector: labels.SelectorFromSet(
map[string]string{labelhelper.ScriptsLabelKey: ""},
),
})
if err != nil {
return nil, err
}
var names []string
for _, cm := range cmList.Items {
names = append(names, cm.Name)
}
return names, nil
}