/* * Copyright 2024 the KubeSphere Authors. * Please refer to the LICENSE file in the root directory of the project. * https://github.com/kubesphere/kubesphere/blob/master/LICENSE */ package v2 import ( "bufio" "bytes" "errors" "io" "strings" "github.com/emicklei/go-restful/v3" "kubesphere.io/kubesphere/pkg/apiserver/request" v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/klog/v2" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "k8s.io/client-go/dynamic" appv2 "kubesphere.io/api/application/v2" clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" "kubesphere.io/kubesphere/pkg/simple/client/application" ) const ( Status = "status" ) func parseRequest(createRequest application.AppRequest, validate bool) (appRequest application.AppRequest, err error) { if createRequest.AppType == appv2.AppTypeHelm { req, err := parseHelmRequest(createRequest, validate) return req, err } _, err = application.ReadYaml(createRequest.Package) return createRequest, err } func parseHelmRequest(createRequest application.AppRequest, validate bool) (req application.AppRequest, err error) { if createRequest.Package == nil || len(createRequest.Package) == 0 { return req, errors.New("package is empty") } chartPack, err := loader.LoadArchive(bytes.NewReader(createRequest.Package)) if err != nil { return createRequest, err } if validate { createRequest, err = getCrdInfo(createRequest, chartPack) if err != nil { klog.Errorf("failed to get crd info from %s: %v", chartPack.Metadata.Name, err) return createRequest, err } } shortName := application.GenerateShortNameMD5Hash(chartPack.Metadata.Name) fillEmptyFields(&createRequest, chartPack, shortName) return createRequest, nil } func getCrdInfo(createRequest application.AppRequest, chartPack *chart.Chart) (application.AppRequest, error) { crdFiles := chartPack.CRDObjects() for _, i := range crdFiles { dataList, err := readYaml(i.File.Data) if err != nil { klog.Errorf("failed to read %s yaml: %v", i.Filename, err) return createRequest, err } for _, d := range dataList { decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(d), 1024) crd := v1.CustomResourceDefinition{} err = decoder.Decode(&crd) if err != nil { klog.Error(err, "Failed to decode crd file") return application.AppRequest{}, err } var servedVersion *v1.CustomResourceDefinitionVersion for _, v := range crd.Spec.Versions { if v.Served && v.Storage { servedVersion = &v } } if servedVersion == nil { klog.Warningf("no served and storage version found in crd %s", crd.Name) continue } ins := appv2.GroupVersionResource{ Group: crd.Spec.Group, Version: servedVersion.Name, Resource: crd.Spec.Names.Plural, } createRequest.Resources = append(createRequest.Resources, ins) } } return createRequest, nil } func readYaml(data []byte) (yamlList [][]byte, err error) { // Read yaml file which has multi line yaml and split it into a list of yaml documents. r := yaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(data))) for { d, err := r.Read() if err == io.EOF { break } if err != nil { klog.Errorf("failed to read yaml: %v", err) return nil, err } //skip empty yaml or empty --- if len(strings.TrimSpace(string(d))) > 3 { yamlList = append(yamlList, d) } } return yamlList, nil } func fillEmptyFields(createRequest *application.AppRequest, chartPack *chart.Chart, shortName string) { if createRequest.AppName == "" { createRequest.AppName = application.GetUuid36(shortName + "-") } if createRequest.OriginalName == "" { createRequest.OriginalName = chartPack.Metadata.Name } if createRequest.AppHome == "" { createRequest.AppHome = chartPack.Metadata.Home } if createRequest.Icon == "" { createRequest.Icon = chartPack.Metadata.Icon } if createRequest.VersionName == "" { createRequest.VersionName = chartPack.Metadata.Version } if createRequest.Maintainers == nil || len(createRequest.Maintainers) == 0 { createRequest.Maintainers = application.GetMaintainers(chartPack.Metadata.Maintainers) } if createRequest.RepoName == "" { createRequest.RepoName = appv2.UploadRepoKey } if createRequest.Description == "" { createRequest.Description = chartPack.Metadata.Description } if createRequest.Abstraction == "" { createRequest.Abstraction = chartPack.Metadata.Description } if createRequest.AliasName == "" { createRequest.AliasName = chartPack.Metadata.Name } } func (h *appHandler) getCluster(req *restful.Request, clusterName string) (runtimeclient.Client, *dynamic.DynamicClient, *clusterv1alpha1.Cluster, error) { klog.Infof("get cluster %s", clusterName) runtimeClient, err := h.clusterClient.GetRuntimeClient(clusterName) if err != nil { return nil, nil, nil, err } clusterClient, err := h.clusterClient.GetClusterClient(clusterName) if err != nil { return nil, nil, nil, err } userInfo, _ := request.UserFrom(req.Request.Context()) user := "" if userInfo != nil { user = userInfo.GetName() } conf := clusterClient.RestConfig conf.Impersonate.UserName = user dynamicClient, err := dynamic.NewForConfig(conf) if err != nil { return nil, nil, nil, err } cluster, err := h.clusterClient.Get(clusterName) if err != nil { return nil, nil, nil, err } return runtimeClient, dynamicClient, cluster, nil }