diff --git a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go index ba20d75070..cd29836cbb 100644 --- a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go +++ b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go @@ -458,8 +458,9 @@ type DeployModuleInfo struct { } type DeployVariableConfig struct { - VariableKey string `bson:"variable_key" json:"variable_key" yaml:"variable_key"` - UseGlobalVariable bool `bson:"use_global_variable" json:"use_global_variable" yaml:"use_global_variable"` + VariableKey string `bson:"variable_key" json:"variable_key" yaml:"variable_key"` + Source string `bson:"source" json:"source" yaml:"source"` + Value string `bson:"value" json:"value" yaml:"value"` } type ServiceKeyVal struct { diff --git a/pkg/microservice/aslan/core/common/service/kube/render.go b/pkg/microservice/aslan/core/common/service/kube/render.go index 4b15dcc9d3..63c0604731 100644 --- a/pkg/microservice/aslan/core/common/service/kube/render.go +++ b/pkg/microservice/aslan/core/common/service/kube/render.go @@ -19,18 +19,15 @@ package kube import ( "bytes" "fmt" + "regexp" "strings" - "github.com/koderover/zadig/v2/pkg/tool/clientmanager" "github.com/pkg/errors" - "gopkg.in/yaml.v2" - appsv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - batchv1beta1 "k8s.io/api/batch/v1beta1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - yamlutil "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/cli-runtime/pkg/printers" "k8s.io/helm/pkg/releaseutil" + yaml "sigs.k8s.io/yaml/goyaml.v3" "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/models" commonmodels "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/models" @@ -42,10 +39,10 @@ import ( commonutil "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/util" "github.com/koderover/zadig/v2/pkg/setting" kubeclient "github.com/koderover/zadig/v2/pkg/shared/kube/client" + "github.com/koderover/zadig/v2/pkg/tool/clientmanager" "github.com/koderover/zadig/v2/pkg/tool/kube/getter" "github.com/koderover/zadig/v2/pkg/tool/kube/serializer" "github.com/koderover/zadig/v2/pkg/tool/log" - "github.com/koderover/zadig/v2/pkg/types" "github.com/koderover/zadig/v2/pkg/util" "github.com/koderover/zadig/v2/pkg/util/converter" ) @@ -126,150 +123,121 @@ func ReplaceWorkloadImages(rawYaml string, images []*commonmodels.Container) (st imageMap[image.Name] = image } + customKVRegExp := regexp.MustCompile(`{{\.(\w+(\.\w+)*)}}`) + restoreRegExp := regexp.MustCompile(`TEMP_PLACEHOLDER_(\w+(\.\w+)*)`) + splitYams := util.SplitYaml(rawYaml) yamlStrs := make([]string, 0) - var err error workloadRes := make([]*WorkloadResource, 0) for _, yamlStr := range splitYams { + modifiedYamlStr := customKVRegExp.ReplaceAll([]byte(yamlStr), []byte("TEMP_PLACEHOLDER_$1")) - resKind := new(types.KubeResourceKind) - if err := yaml.Unmarshal([]byte(yamlStr), &resKind); err != nil { - return "", nil, fmt.Errorf("unmarshal ResourceKind error: %v", err) + var rawData map[string]interface{} + err := yaml.Unmarshal(modifiedYamlStr, &rawData) + if err != nil { + return "", nil, fmt.Errorf("decode yaml error: %s", err) } - decoder := yamlutil.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(yamlStr)), 5*1024*1024) - switch resKind.Kind { - case setting.Deployment: - deployment := &appsv1.Deployment{} - if err := decoder.Decode(deployment); err != nil { - return "", nil, fmt.Errorf("unmarshal Deployment error: %v", err) - } - workloadRes = append(workloadRes, &WorkloadResource{ - Name: resKind.Metadata.Name, - Type: resKind.Kind, - }) - for i, container := range deployment.Spec.Template.Spec.Containers { - containerName := container.Name - if image, ok := imageMap[containerName]; ok { - deployment.Spec.Template.Spec.Containers[i].Image = image.Image - } + cleanedData := util.ConvertIntsToInt64(rawData).(map[string]interface{}) + + var obj unstructured.Unstructured + obj.Object = cleanedData + + resourceName := obj.GetName() + resourceKind := obj.GetKind() + + workloadRes = append(workloadRes, &WorkloadResource{ + Name: resourceName, + Type: resourceKind, + }) + + switch obj.GetKind() { + case setting.Deployment, setting.StatefulSet, setting.Job: + containers, _, err := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "containers") + if err != nil { + return "", nil, fmt.Errorf("failed to find containers in deployment, sts or job, error: %s", err) } - for i, container := range deployment.Spec.Template.Spec.InitContainers { - containerName := container.Name + + for i, c := range containers { + container := c.(map[string]interface{}) + containerName := container["name"].(string) if image, ok := imageMap[containerName]; ok { - deployment.Spec.Template.Spec.InitContainers[i].Image = image.Image + container["image"] = image.Image + containers[i] = container } } - yamlStr, err = resourceToYaml(deployment) + err = unstructured.SetNestedSlice(obj.Object, containers, "spec", "template", "spec", "containers") if err != nil { - return "", nil, err - } - case setting.StatefulSet: - statefulSet := &appsv1.StatefulSet{} - if err := decoder.Decode(statefulSet); err != nil { - return "", nil, fmt.Errorf("unmarshal StatefulSet error: %v", err) + return "", nil, fmt.Errorf("failed to set containers in deployment, sts or job, error: %s", err) } - workloadRes = append(workloadRes, &WorkloadResource{ - Name: resKind.Metadata.Name, - Type: resKind.Kind, - }) - for i, container := range statefulSet.Spec.Template.Spec.Containers { - containerName := container.Name - if image, ok := imageMap[containerName]; ok { - statefulSet.Spec.Template.Spec.Containers[i].Image = image.Image - } + + initContainers, _, err := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "initContainers") + if err != nil { + return "", nil, fmt.Errorf("failed to find init containers in deployment, sts or job, error: %s", err) } - for i, container := range statefulSet.Spec.Template.Spec.InitContainers { - containerName := container.Name + + for i, c := range initContainers { + container := c.(map[interface{}]interface{}) + containerName := container["name"].(string) if image, ok := imageMap[containerName]; ok { - statefulSet.Spec.Template.Spec.InitContainers[i].Image = image.Image + container["image"] = image.Image + initContainers[i] = container } } - yamlStr, err = resourceToYaml(statefulSet) + + err = unstructured.SetNestedSlice(obj.Object, initContainers, "spec", "template", "spec", "initContainers") if err != nil { - return "", nil, err + return "", nil, fmt.Errorf("failed to set init containers in deployment, sts or job, error: %s", err) } - case setting.Job: - job := &batchv1.Job{} - if err := decoder.Decode(job); err != nil { - return "", nil, fmt.Errorf("unmarshal Job error: %v", err) + + case setting.CronJob: + containers, _, err := unstructured.NestedSlice(obj.Object, "spec", "jobTemplate", "spec", "template", "spec", "containers") + if err != nil { + return "", nil, fmt.Errorf("failed to find containers in cronjob, error: %s", err) } - workloadRes = append(workloadRes, &WorkloadResource{ - Name: resKind.Metadata.Name, - Type: resKind.Kind, - }) - for i, container := range job.Spec.Template.Spec.Containers { - containerName := container.Name + + for i, c := range containers { + container := c.(map[interface{}]interface{}) + containerName := container["name"].(string) if image, ok := imageMap[containerName]; ok { - job.Spec.Template.Spec.Containers[i].Image = image.Image + container["image"] = image.Image + containers[i] = container } } - for i, container := range job.Spec.Template.Spec.InitContainers { - containerName := container.Name - if image, ok := imageMap[containerName]; ok { - job.Spec.Template.Spec.InitContainers[i].Image = image.Image - } + + err = unstructured.SetNestedSlice(obj.Object, containers, "spec", "jobTemplate", "spec", "template", "spec", "containers") + if err != nil { + return "", nil, fmt.Errorf("failed to set containers in cronjob, error: %s", err) } - yamlStr, err = resourceToYaml(job) + + initContainers, _, err := unstructured.NestedSlice(obj.Object, "spec", "jobTemplate", "spec", "template", "spec", "initContainers") if err != nil { - return "", nil, err + return "", nil, fmt.Errorf("failed to find init containers in cronjob, error: %s", err) } - case setting.CronJob: - if resKind.APIVersion == batchv1beta1.SchemeGroupVersion.String() { - cronJob := &batchv1beta1.CronJob{} - if err := decoder.Decode(cronJob); err != nil { - return "", nil, fmt.Errorf("unmarshal CronJob error: %v", err) - } - workloadRes = append(workloadRes, &WorkloadResource{ - Name: resKind.Metadata.Name, - Type: resKind.Kind, - }) - for i, val := range cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers { - containerName := val.Name - if image, ok := imageMap[containerName]; ok { - cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers[i].Image = image.Image - } - } - for i, val := range cronJob.Spec.JobTemplate.Spec.Template.Spec.InitContainers { - containerName := val.Name - if image, ok := imageMap[containerName]; ok { - cronJob.Spec.JobTemplate.Spec.Template.Spec.InitContainers[i].Image = image.Image - } - } - yamlStr, err = resourceToYaml(cronJob) - if err != nil { - return "", nil, err - } - } else { - cronJob := &batchv1.CronJob{} - if err := decoder.Decode(cronJob); err != nil { - return "", nil, fmt.Errorf("unmarshal CronJob error: %v", err) - } - workloadRes = append(workloadRes, &WorkloadResource{ - Name: resKind.Metadata.Name, - Type: resKind.Kind, - }) - for i, val := range cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers { - containerName := val.Name - if image, ok := imageMap[containerName]; ok { - cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers[i].Image = image.Image - } - } - for i, val := range cronJob.Spec.JobTemplate.Spec.Template.Spec.InitContainers { - containerName := val.Name - if image, ok := imageMap[containerName]; ok { - cronJob.Spec.JobTemplate.Spec.Template.Spec.InitContainers[i].Image = image.Image - } - } - yamlStr, err = resourceToYaml(cronJob) - if err != nil { - return "", nil, err + + for i, c := range initContainers { + container := c.(map[interface{}]interface{}) + containerName := container["name"].(string) + if image, ok := imageMap[containerName]; ok { + container["image"] = image.Image + initContainers[i] = container } } + err = unstructured.SetNestedSlice(obj.Object, initContainers, "spec", "jobTemplate", "spec", "template", "spec", "initContainers") + if err != nil { + return "", nil, fmt.Errorf("failed to set init containers in cronjob, error: %s", err) + } + } + + updatedYaml, err := yaml.Marshal(obj.Object) + if err != nil { + return "", nil, fmt.Errorf("updated resource cannot be marshaled into a YAML, error: %s", err) } - yamlStrs = append(yamlStrs, yamlStr) + + finalYaml := restoreRegExp.ReplaceAll(updatedYaml, []byte("{{.$1}}")) + yamlStrs = append(yamlStrs, string(finalYaml)) } return util.JoinYamls(yamlStrs), workloadRes, nil diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/job/job_deploy.go b/pkg/microservice/aslan/core/workflow/service/workflow/job/job_deploy.go index 1ea208f951..b2ccc5783c 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/job/job_deploy.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/job/job_deploy.go @@ -311,6 +311,14 @@ func (j *DeployJob) SetPreset() error { j.spec.Services = svcResp } + for _, svc := range j.spec.Services { + for _, cfg := range svc.VariableConfigs { + if cfg.Source == "" { + cfg.Source = "runtime" + } + } + } + j.job.Spec = j.spec return nil } diff --git a/pkg/util/yaml.go b/pkg/util/yaml.go index c4eabc0573..39448e2592 100644 --- a/pkg/util/yaml.go +++ b/pkg/util/yaml.go @@ -63,3 +63,22 @@ func JoinYamls(files []string) string { func SplitYaml(yaml string) []string { return strings.Split(yaml, setting.YamlFileSeperator) } + +func ConvertIntsToInt64(data interface{}) interface{} { + switch v := data.(type) { + case map[string]interface{}: + for key, value := range v { + v[key] = ConvertIntsToInt64(value) + } + return v + case []interface{}: + for i, value := range v { + v[i] = ConvertIntsToInt64(value) + } + return v + case int: + return int64(v) + default: + return v + } +}