diff --git a/internal/tools/orchestrator/scheduler/executor/plugins/k8s/instanceinfosync/pod.go b/internal/tools/orchestrator/scheduler/executor/plugins/k8s/instanceinfosync/pod.go index 53436ba43d6..dde28213991 100644 --- a/internal/tools/orchestrator/scheduler/executor/plugins/k8s/instanceinfosync/pod.go +++ b/internal/tools/orchestrator/scheduler/executor/plugins/k8s/instanceinfosync/pod.go @@ -498,7 +498,6 @@ func updatePodAndInstance(dbclient *instanceinfo.Client, podlist *corev1.PodList } } } else { - logrus.Infof("get [currentContainerID] from mainContainer") currentTerminatedContainer := mainContainer.State.Terminated if currentTerminatedContainer != nil { if len(strings.Split(mainContainer.ContainerID, "://")) == 2 { diff --git a/internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go b/internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go index 6ed74201327..64193d44f74 100644 --- a/internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go +++ b/internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go @@ -84,6 +84,7 @@ import ( "github.com/erda-project/erda/pkg/k8sclient" k8sclientconfig "github.com/erda-project/erda/pkg/k8sclient/config" "github.com/erda-project/erda/pkg/k8sclient/scheme" + "github.com/erda-project/erda/pkg/parser/diceyml" "github.com/erda-project/erda/pkg/schedule/schedulepolicy/cpupolicy" "github.com/erda-project/erda/pkg/strutil" ) @@ -789,6 +790,13 @@ func (k *Kubernetes) createOne(ctx context.Context, service *apistructs.Service, } } var err error + + if err = k.runAsDefaultUser(service); err != nil { + return err + } + + logrus.Infof("after %v", service.K8SSnippet.Container.SecurityContext) + switch service.WorkLoad { case types.ServicePerNode: err = k.createDaemonSet(ctx, service, sg) @@ -903,6 +911,12 @@ func (k *Kubernetes) updateOneByOne(ctx context.Context, sg *apistructs.ServiceG } for _, svc := range sg.Services { + svc := svc + + if err := k.runAsDefaultUser(&svc); err != nil { + return err + } + svc.Namespace = ns runtimeServiceName := util.GetDeployName(&svc) // Existing in the old service collection, do the put operation @@ -2058,3 +2072,22 @@ func (k *Kubernetes) DeployInEdgeCluster() bool { return true } + +// run as default user +func (k *Kubernetes) runAsDefaultUser(service *apistructs.Service) error { + snippet := diceyml.K8SSnippet{ + Container: &diceyml.ContainerSnippet{ + SecurityContext: &apiv1.SecurityContext{ + RunAsUser: &types.DefaultContainerUserId, + RunAsGroup: &types.DefaultContainerGroupId, + }, + }, + } + + if service.K8SSnippet == nil { + service.K8SSnippet = &snippet + return nil + } + + return util.MergeStruct(service.K8SSnippet, &snippet) +} diff --git a/internal/tools/orchestrator/scheduler/executor/plugins/k8s/types/type.go b/internal/tools/orchestrator/scheduler/executor/plugins/k8s/types/type.go index 668afac40ad..a880114276c 100644 --- a/internal/tools/orchestrator/scheduler/executor/plugins/k8s/types/type.go +++ b/internal/tools/orchestrator/scheduler/executor/plugins/k8s/types/type.go @@ -42,6 +42,11 @@ const ( DiceWorkSpace = "DICE_WORKSPACE" ) +var ( + DefaultContainerUserId int64 = 1000 // `dice` user + DefaultContainerGroupId int64 = 1000 // `dice` group +) + var EnvReg = regexp.MustCompile(`\$\{([^}]+?)\}`) type StatefulsetInfo struct { diff --git a/internal/tools/orchestrator/scheduler/executor/util/util.go b/internal/tools/orchestrator/scheduler/executor/util/util.go index 68fa5e1c249..4dfacd7dfe8 100644 --- a/internal/tools/orchestrator/scheduler/executor/util/util.go +++ b/internal/tools/orchestrator/scheduler/executor/util/util.go @@ -17,6 +17,7 @@ package util import ( "encoding/base64" "fmt" + "reflect" "sort" "strconv" "strings" @@ -369,3 +370,97 @@ func GetDeployName(service *apistructs.Service) string { } return service.Name } + +var ( + ErrorNotPointer = errors.New("must be a pointer") + ErrorNotSameType = errors.New("dst and src are not same type") + ErrorValueIsNil = errors.New("value is nil") +) + +func MergeStruct(dst, src any) error { + dstTpy := reflect.TypeOf(dst) + if dstTpy.Kind() != reflect.Ptr { + return ErrorNotPointer + } + dstTpy = dstTpy.Elem() + + srcTpy := reflect.TypeOf(src) + if srcTpy.Kind() != reflect.Ptr { + return ErrorNotPointer + } + srcTpy = srcTpy.Elem() + + if srcTpy != dstTpy { + return ErrorNotSameType + } + + if isBaseType(srcTpy) { + return nil + } + + dstVal := reflect.ValueOf(dst) + if dstVal.IsNil() { + return ErrorValueIsNil + } + if dstVal.Kind() != reflect.Ptr { + return ErrorNotPointer + } + dstVal = dstVal.Elem() + + srcVal := reflect.ValueOf(src) + if srcVal.IsNil() { + return ErrorValueIsNil + } + if srcVal.Kind() != reflect.Ptr { + return ErrorNotPointer + } + srcVal = srcVal.Elem() + + for i := 0; i < dstTpy.NumField(); i++ { + if dstTpy.Field(i).Type.Kind() == reflect.Ptr { + // source data is nil, skip merge + if srcVal.Field(i).IsNil() { + continue + } + + // dst and src are not nil, continue recursively + if !dstVal.Field(i).IsNil() && !srcVal.Field(i).IsNil() { + if err := MergeStruct(dstVal.Field(i).Interface(), srcVal.Field(i).Interface()); err != nil { + return err + } + continue + } + + // dst is nil and src is not nil, set value directly + if dstVal.Field(i).IsNil() && !srcVal.Field(i).IsNil() { + dstVal.Field(i).Set(srcVal.Field(i)) + continue + } + + } + } + return nil +} + +func isBaseType(typ reflect.Type) bool { + switch typ.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.Bool: + return true + case reflect.String: + return true + case reflect.Slice, reflect.Array: + return true + case reflect.Map: + return true + case reflect.Chan: + return true + default: + return false + } +} diff --git a/internal/tools/orchestrator/scheduler/executor/util/util_test.go b/internal/tools/orchestrator/scheduler/executor/util/util_test.go index a1ba82a868d..fde3b2130db 100644 --- a/internal/tools/orchestrator/scheduler/executor/util/util_test.go +++ b/internal/tools/orchestrator/scheduler/executor/util/util_test.go @@ -15,13 +15,17 @@ package util import ( + "encoding/json" "fmt" "strings" "testing" "github.com/stretchr/testify/assert" + apiv1 "k8s.io/api/core/v1" "github.com/erda-project/erda/apistructs" + "github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/types" + "github.com/erda-project/erda/pkg/parser/diceyml" ) func TestParsePreserveProjects(t *testing.T) { @@ -209,3 +213,35 @@ func Test_ParseAnnotationFromEnv(t *testing.T) { }) } } + +func TestMergeStructValue(t *testing.T) { + + dstRunAsUser := int64(0) + want := `{"container":{"securityContext":{"runAsUser":0,"runAsGroup":1000}}}` + dst := apistructs.Service{ + K8SSnippet: &diceyml.K8SSnippet{ + Container: &diceyml.ContainerSnippet{ + SecurityContext: &apiv1.SecurityContext{ + RunAsUser: &dstRunAsUser, + }, + }, + }, + } + + src := apistructs.Service{ + K8SSnippet: &diceyml.K8SSnippet{ + Container: &diceyml.ContainerSnippet{ + SecurityContext: &apiv1.SecurityContext{ + RunAsUser: &types.DefaultContainerUserId, + RunAsGroup: &types.DefaultContainerGroupId, + }, + }, + }, + } + err := MergeStruct(&dst, &src) + assert.NoError(t, err) + + marshal, _ := json.Marshal(dst.K8SSnippet) + fmt.Println(string(marshal)) + assert.Equal(t, want, string(marshal)) +}