From 6f894e001b1d6cc2567230903a33ccb3dfcc9335 Mon Sep 17 00:00:00 2001 From: SergioLangaritaBenitez Date: Tue, 6 Aug 2024 10:10:31 +0200 Subject: [PATCH 1/8] refactor Interlink to adapt into a new version 1 --- pkg/handlers/create.go | 5 ++ pkg/handlers/job.go | 18 ++++--- pkg/types/config.go | 4 +- pkg/types/interlink.go | 104 +++++++++++++++++++++++++++++++++++++++++ pkg/types/mount.go | 4 +- pkg/types/service.go | 2 +- 6 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 pkg/types/interlink.go diff --git a/pkg/handlers/create.go b/pkg/handlers/create.go index 79844911..3b296ce0 100644 --- a/pkg/handlers/create.go +++ b/pkg/handlers/create.go @@ -70,10 +70,13 @@ func MakeCreateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg) // Service is created by an EGI user + createLogger.Printf("Admin: %t", isAdminUser) + if !isAdminUser { uid, err := auth.GetUIDFromContext(c) if err != nil { c.String(http.StatusInternalServerError, fmt.Sprintln(err)) + return } // Set UID from owner @@ -83,6 +86,7 @@ func MakeCreateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand mc, err := auth.GetMultitenancyConfigFromContext(c) if err != nil { c.String(http.StatusInternalServerError, fmt.Sprintln(err)) + return } full_uid := auth.FormatUID(uid) @@ -93,6 +97,7 @@ func MakeCreateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand err := checkIdentity(&service, cfg, authHeader) if err != nil { c.String(http.StatusBadRequest, fmt.Sprintln(err)) + return } break } diff --git a/pkg/handlers/job.go b/pkg/handlers/job.go index 1fa48b5b..ab242f03 100644 --- a/pkg/handlers/job.go +++ b/pkg/handlers/job.go @@ -18,7 +18,6 @@ package handlers import ( "context" - "encoding/base64" "fmt" "io" "log" @@ -102,9 +101,10 @@ func MakeJobHandler(cfg *types.Config, kubeClientset *kubernetes.Clientset, back // Make event envVar event := v1.EnvVar{} - var args string + var args []string if cfg.InterLinkAvailable && service.InterLinkNodeName != "" { - event = v1.EnvVar{ + command, event, args, _ = types.SetInterlinkJob(podSpec, service, cfg, eventBytes) + /*event = v1.EnvVar{ Name: types.EventVariable, Value: base64.StdEncoding.EncodeToString([]byte(eventBytes)), } @@ -119,13 +119,17 @@ func MakeJobHandler(cfg *types.Config, kubeClientset *kubernetes.Clientset, back Key: InterLinkTolerationKey, Operator: InterLinkTolerationOperator, }, - } + }*/ } else { event = v1.EnvVar{ Name: types.EventVariable, Value: string(eventBytes), } - args = fmt.Sprintf("echo $%s | %s", types.EventVariable, service.GetSupervisorPath()) + if service.Mount.Provider != "" { + args = []string{"-c", fmt.Sprintf("echo $%s | %s", types.EventVariable, service.GetSupervisorPath()) + ";echo \"I finish\" > /tmpfolder/finish-file;"} + } else { + args = []string{"-c", fmt.Sprintf("echo $%s | %s", types.EventVariable, service.GetSupervisorPath())} + } } // Make JOB_UUID envVar @@ -150,7 +154,7 @@ func MakeJobHandler(cfg *types.Config, kubeClientset *kubernetes.Clientset, back for i, c := range podSpec.Containers { if c.Name == types.ContainerName { podSpec.Containers[i].Command = command - podSpec.Containers[i].Args = []string{"-c", args} + podSpec.Containers[i].Args = args podSpec.Containers[i].Env = append(podSpec.Containers[i].Env, event) podSpec.Containers[i].Env = append(podSpec.Containers[i].Env, jobUUIDVar) podSpec.Containers[i].Env = append(podSpec.Containers[i].Env, resourceIDVar) @@ -158,7 +162,7 @@ func MakeJobHandler(cfg *types.Config, kubeClientset *kubernetes.Clientset, back } if service.Mount.Provider != "" { types.SetMount(podSpec, *service, cfg) - podSpec.Containers[0].Args = []string{"-c", args + ";echo \"I finish\" > /tmpfolder/finish-file;"} + //podSpec.Containers[0].Args = []string{"-c", args + ";echo \"I finish\" > /tmpfolder/finish-file;"} } // Delegate job if can't be scheduled and has defined replicas diff --git a/pkg/types/config.go b/pkg/types/config.go index 3777791e..b871ba86 100644 --- a/pkg/types/config.go +++ b/pkg/types/config.go @@ -189,7 +189,7 @@ type Config struct { IngressHost string `json:"-"` // Github path of FaaS Supervisor (needed for Interlink config) - SupervisorURL string `json:"-"` + SupervisorKitImage string `json:"-"` //Path to additional OSCAR configuration setted by users AdditionalConfigPath string `json:"-"` @@ -238,7 +238,7 @@ var configVars = []configVar{ {"OIDCSubject", "OIDC_SUBJECT", false, stringType, ""}, {"OIDCGroups", "OIDC_GROUPS", false, stringSliceType, ""}, {"IngressHost", "INGRESS_HOST", false, stringType, ""}, - {"SupervisorURL", "SUPERVISOR_URL", false, stringType, "https://github.com/grycap/faas-supervisor/releases/download/1.5.8/supervisor"}, + {"SupervisorKitImage", "SUPERVISOR_KIT_IMAGE", false, stringType, ""}, {"AdditionalConfigPath", "ADDITIONAL_CONFIG_PATH", false, stringType, "config.yaml"}, } diff --git a/pkg/types/interlink.go b/pkg/types/interlink.go new file mode 100644 index 00000000..2bcd757f --- /dev/null +++ b/pkg/types/interlink.go @@ -0,0 +1,104 @@ +/* +Copyright (C) GRyCAP - I3M - UPV + +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 types + +import ( + "encoding/base64" + + v1 "k8s.io/api/core/v1" +) + +const ( + ContainerSupervisorName = "supervisor-container" + SupervisorMountPath = "/data" + SupervisorArg = "cp -r /supervisor/* " + SupervisorMountPath + //SupervisorCommand = [...]string{"/bin/sh", "-c"} + NameSupervisorVolume = "supervisor-share-data" + NodeSelectorKey = "kubernetes.io/hostname" + + // Annotations for InterLink nodes + InterLinkDNSPolicy = "ClusterFirst" + InterLinkRestartPolicy = "OnFailure" + InterLinkTolerationKey = "virtual-node.interlink/no-schedule" + InterLinkTolerationOperator = "Exists" +) + +var SupervisorCommand = []string{"/bin/sh", "-c"} +var OscarContainerCommand = []string{"echo $EVENT | base64 -d | " + SupervisorMountPath + "/supervisor"} + +// // job +func SetInterlinkJob(podSpec *v1.PodSpec, service *Service, cfg *Config, eventBytes []byte) ([]string, v1.EnvVar, []string, error) { + command := SupervisorCommand + event := v1.EnvVar{ + Name: EventVariable, + Value: base64.StdEncoding.EncodeToString([]byte(eventBytes)), + } + args := OscarContainerCommand + podSpec.NodeSelector = map[string]string{ + NodeSelectorKey: service.InterLinkNodeName, + } + podSpec.DNSPolicy = InterLinkDNSPolicy + podSpec.RestartPolicy = InterLinkRestartPolicy + podSpec.Tolerations = []v1.Toleration{ + { + Key: InterLinkTolerationKey, + Operator: InterLinkTolerationOperator, + }, + } + + addInitContainer(podSpec, cfg) + return command, event, args, nil +} + +// / service +func SetInterlinkService(podSpec *v1.PodSpec) error { + podSpec.Containers[0].ImagePullPolicy = "Always" + shareDataVolumeMount := v1.VolumeMount{ + Name: NameSupervisorVolume, + MountPath: SupervisorMountPath, + } + + podSpec.Containers[0].VolumeMounts = append(podSpec.Containers[0].VolumeMounts, shareDataVolumeMount) + + shareDataVolume := v1.Volume{ + Name: NameSupervisorVolume, + VolumeSource: v1.VolumeSource{ + EmptyDir: &v1.EmptyDirVolumeSource{}, + }, + } + podSpec.Volumes = append(podSpec.Volumes, shareDataVolume) + return nil + +} + +func addInitContainer(podSpec *v1.PodSpec, cfg *Config) error { + initContainer := v1.Container{ + Name: ContainerSupervisorName, + Command: SupervisorCommand, + Args: []string{SupervisorArg}, + Image: cfg.SupervisorKitImage, + ImagePullPolicy: v1.PullIfNotPresent, + VolumeMounts: []v1.VolumeMount{ + { + Name: NameSupervisorVolume, + MountPath: SupervisorMountPath, + }, + }, + } + podSpec.InitContainers = []v1.Container{initContainer} + return nil +} diff --git a/pkg/types/mount.go b/pkg/types/mount.go index 4c2e5621..630c2ee8 100644 --- a/pkg/types/mount.go +++ b/pkg/types/mount.go @@ -49,8 +49,8 @@ done` // SetMount Creates the sidecar container that mounts the source volume onto the pod volume func SetMount(podSpec *v1.PodSpec, service Service, cfg *Config) { podSpec.Containers = append(podSpec.Containers, sidecarPodSpec(service)) - termination := int64(5) - podSpec.TerminationGracePeriodSeconds = &termination + //termination := int64(5) + //podSpec.TerminationGracePeriodSeconds = &termination addVolume(podSpec) } diff --git a/pkg/types/service.go b/pkg/types/service.go index c4a1f021..8ece7696 100644 --- a/pkg/types/service.go +++ b/pkg/types/service.go @@ -300,7 +300,7 @@ func (service *Service) ToPodSpec(cfg *Config) (*v1.PodSpec, error) { } if cfg.InterLinkAvailable && service.InterLinkNodeName != "" { // Add specs of InterLink - podSpec.Containers[0].ImagePullPolicy = "Always" + _ = SetInterlinkService(podSpec) } else { // Add specs volumeMount := v1.VolumeMount{ From e5076d0b9f1d313b128997d4487124ca1448b47b Mon Sep 17 00:00:00 2001 From: SergioLangaritaBenitez Date: Tue, 13 Aug 2024 11:13:37 +0200 Subject: [PATCH 2/8] refactor list services --- pkg/backends/k8s.go | 8 ++++++++ pkg/backends/knative.go | 28 +++++++++++++++++++++++++++- pkg/handlers/list.go | 10 +++++++--- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/pkg/backends/k8s.go b/pkg/backends/k8s.go index 3c43088b..e8869502 100644 --- a/pkg/backends/k8s.go +++ b/pkg/backends/k8s.go @@ -364,6 +364,14 @@ func deleteServiceConfigMap(name string, namespace string, kubeClientset kuberne return nil } +func listServicesConfigMap(namespace string, kubeClientset kubernetes.Interface) (*v1.ConfigMapList, error) { + list, err := kubeClientset.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return nil, err + } + return list, nil +} + func deleteServiceJobs(name string, namespace string, kubeClientset kubernetes.Interface) error { // ListOptions to select all the associated jobs with the specified service listOpts := metav1.ListOptions{ diff --git a/pkg/backends/knative.go b/pkg/backends/knative.go index 9e1391e9..fd28f5a2 100644 --- a/pkg/backends/knative.go +++ b/pkg/backends/knative.go @@ -24,6 +24,7 @@ import ( "os" "strconv" + "github.com/goccy/go-yaml" "github.com/grycap/oscar/v3/pkg/imagepuller" "github.com/grycap/oscar/v3/pkg/types" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -76,6 +77,31 @@ func (kn *KnativeBackend) GetInfo() *types.ServerlessBackendInfo { // ListServices returns a slice with all services registered in the provided namespace func (kn *KnativeBackend) ListServices() ([]*types.Service, error) { // Get the list with all Knative services + list, err := listServicesConfigMap(kn.namespace, kn.kubeClientset) + if err != nil { + log.Printf("WARNING: %v\n", err) + } + services := []*types.Service{} + + for _, configMap := range list.Items { + serviceAux := &types.Service{} + + // Unmarshal the FDL stored in the configMap + if err = yaml.Unmarshal([]byte(configMap.Data[types.FDLFileName]), serviceAux); err != nil { + return nil, fmt.Errorf("the FDL cannot be read Unmarshal error: \"%s\"", configMap.Data[types.FDLFileName]) + } + if serviceAux.Name != "" { + // Add the script to the service from configmap's script value + serviceAux.Script = configMap.Data[types.ScriptFileName] + services = append(services, serviceAux) + } + } + + /*return service, nil + + if err != nil { + log.Printf("WARNING: %v\n", err) + } knSvcs, err := kn.knClientset.ServingV1().Services(kn.namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, err @@ -91,7 +117,7 @@ func (kn *KnativeBackend) ListServices() ([]*types.Service, error) { services = append(services, svc) } } - + */ return services, nil } diff --git a/pkg/handlers/list.go b/pkg/handlers/list.go index 2a5cb130..0ebcf2d3 100644 --- a/pkg/handlers/list.go +++ b/pkg/handlers/list.go @@ -19,6 +19,7 @@ package handlers import ( "fmt" "net/http" + "slices" "strings" "github.com/gin-gonic/gin" @@ -46,16 +47,19 @@ func MakeListHandler(back types.ServerlessBackend) gin.HandlerFunc { var allowedServicesForUser []*types.Service for _, service := range services { - if len(service.AllowedUsers) == 0 { + /*if len(service.AllowedUsers) == 0 { allowedServicesForUser = append(allowedServicesForUser, service) continue + }*/ + if len(service.AllowedUsers) == 0 || slices.Contains(service.AllowedUsers, uid) { + allowedServicesForUser = append(allowedServicesForUser, service) } - for _, id := range service.AllowedUsers { + /*for _, id := range service.AllowedUsers { if uid == id { allowedServicesForUser = append(allowedServicesForUser, service) break } - } + }*/ } c.JSON(http.StatusOK, allowedServicesForUser) From 48c98f39c3b0d10f2eaa7044cb6e97c92d49c64c Mon Sep 17 00:00:00 2001 From: SergioLangaritaBenitez Date: Wed, 14 Aug 2024 12:59:10 +0200 Subject: [PATCH 3/8] update test: list services knative --- pkg/backends/knative.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/backends/knative.go b/pkg/backends/knative.go index fd28f5a2..717aa762 100644 --- a/pkg/backends/knative.go +++ b/pkg/backends/knative.go @@ -80,6 +80,7 @@ func (kn *KnativeBackend) ListServices() ([]*types.Service, error) { list, err := listServicesConfigMap(kn.namespace, kn.kubeClientset) if err != nil { log.Printf("WARNING: %v\n", err) + return nil, err } services := []*types.Service{} From ff429f610298afb8c367f1ad77255d6c77b0ce5e Mon Sep 17 00:00:00 2001 From: catttam Date: Wed, 21 Aug 2024 09:54:30 +0200 Subject: [PATCH 4/8] Minor changes --- pkg/backends/k8s.go | 35 ++++++++++++++++++------------ pkg/backends/knative.go | 46 ++++++++++------------------------------ pkg/backends/openfaas.go | 24 ++++++++++++--------- pkg/handlers/create.go | 1 - pkg/handlers/list.go | 11 +--------- 5 files changed, 48 insertions(+), 69 deletions(-) diff --git a/pkg/backends/k8s.go b/pkg/backends/k8s.go index e8869502..2cbf6866 100644 --- a/pkg/backends/k8s.go +++ b/pkg/backends/k8s.go @@ -66,7 +66,12 @@ func (k *KubeBackend) ListServices() ([]*types.Service, error) { services := []*types.Service{} for _, podTemplate := range podTemplates.Items { // Get service from configMap's FDL - svc, err := getServiceFromFDL(podTemplate.Name, k.namespace, k.kubeClientset) + // Get the configMap of the Service + cm, err := k.kubeClientset.CoreV1().ConfigMaps(k.namespace).Get(context.TODO(), podTemplate.Name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the service \"%s\" does not have a registered ConfigMap", &podTemplate.Name) + } + svc, err := getServiceFromConfigMap(cm) if err != nil { log.Printf("WARNING: %v\n", err) } else { @@ -148,8 +153,14 @@ func (k *KubeBackend) ReadService(name string) (*types.Service, error) { return nil, err } + // Get the configMap of the Service + cm, err := k.kubeClientset.CoreV1().ConfigMaps(k.namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the service \"%s\" does not have a registered ConfigMap", name) + } + // Get service from configMap's FDL - svc, err := getServiceFromFDL(name, k.namespace, k.kubeClientset) + svc, err := getServiceFromConfigMap(cm) if err != nil { return nil, err } @@ -242,17 +253,12 @@ func (k *KubeBackend) DeleteService(service types.Service) error { return nil } -func getServiceFromFDL(name string, namespace string, kubeClientset kubernetes.Interface) (*types.Service, error) { - // Get the configMap of the Service - cm, err := kubeClientset.CoreV1().ConfigMaps(namespace).Get(context.TODO(), name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("the service \"%s\" does not have a registered ConfigMap", name) - } +func getServiceFromConfigMap(cm *v1.ConfigMap) (*types.Service, error) { service := &types.Service{} // Unmarshal the FDL stored in the configMap - if err = yaml.Unmarshal([]byte(cm.Data[types.FDLFileName]), service); err != nil { - return nil, fmt.Errorf("the FDL of the service \"%s\" cannot be read", name) + if err := yaml.Unmarshal([]byte(cm.Data[types.FDLFileName]), service); err != nil { + return nil, fmt.Errorf("the FDL of the service \"%s\" cannot be read", cm.Name) } // Add the script to the service from configmap's script value @@ -364,12 +370,15 @@ func deleteServiceConfigMap(name string, namespace string, kubeClientset kuberne return nil } -func listServicesConfigMap(namespace string, kubeClientset kubernetes.Interface) (*v1.ConfigMapList, error) { - list, err := kubeClientset.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{}) +func getAllServicesConfigMaps(namespace string, kubeClientset kubernetes.Interface) (*v1.ConfigMapList, error) { + listOpts := metav1.ListOptions{ + LabelSelector: "oscar_service", + } + configMapsList, err := kubeClientset.CoreV1().ConfigMaps(namespace).List(context.TODO(), listOpts) if err != nil { return nil, err } - return list, nil + return configMapsList, nil } func deleteServiceJobs(name string, namespace string, kubeClientset kubernetes.Interface) error { diff --git a/pkg/backends/knative.go b/pkg/backends/knative.go index 717aa762..08497817 100644 --- a/pkg/backends/knative.go +++ b/pkg/backends/knative.go @@ -24,7 +24,6 @@ import ( "os" "strconv" - "github.com/goccy/go-yaml" "github.com/grycap/oscar/v3/pkg/imagepuller" "github.com/grycap/oscar/v3/pkg/types" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -77,48 +76,20 @@ func (kn *KnativeBackend) GetInfo() *types.ServerlessBackendInfo { // ListServices returns a slice with all services registered in the provided namespace func (kn *KnativeBackend) ListServices() ([]*types.Service, error) { // Get the list with all Knative services - list, err := listServicesConfigMap(kn.namespace, kn.kubeClientset) + configmaps, err := getAllServicesConfigMaps(kn.namespace, kn.kubeClientset) if err != nil { log.Printf("WARNING: %v\n", err) return nil, err } services := []*types.Service{} - for _, configMap := range list.Items { - serviceAux := &types.Service{} - - // Unmarshal the FDL stored in the configMap - if err = yaml.Unmarshal([]byte(configMap.Data[types.FDLFileName]), serviceAux); err != nil { - return nil, fmt.Errorf("the FDL cannot be read Unmarshal error: \"%s\"", configMap.Data[types.FDLFileName]) - } - if serviceAux.Name != "" { - // Add the script to the service from configmap's script value - serviceAux.Script = configMap.Data[types.ScriptFileName] - services = append(services, serviceAux) - } - } - - /*return service, nil - - if err != nil { - log.Printf("WARNING: %v\n", err) - } - knSvcs, err := kn.knClientset.ServingV1().Services(kn.namespace).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, err - } - - services := []*types.Service{} - for _, knSvc := range knSvcs.Items { - // Get service from configMap's FDL - svc, err := getServiceFromFDL(knSvc.Name, kn.namespace, kn.kubeClientset) + for _, cm := range configmaps.Items { + service, err := getServiceFromConfigMap(&cm) if err != nil { - log.Printf("WARNING: %v\n", err) - } else { - services = append(services, svc) + return nil, err } + services = append(services, service) } - */ return services, nil } @@ -178,8 +149,13 @@ func (kn *KnativeBackend) ReadService(name string) (*types.Service, error) { return nil, err } + // Get the configMap of the Service + cm, err := kn.kubeClientset.CoreV1().ConfigMaps(kn.namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the service \"%s\" does not have a registered ConfigMap", name) + } // Get service from configMap's FDL - svc, err := getServiceFromFDL(name, kn.namespace, kn.kubeClientset) + svc, err := getServiceFromConfigMap(cm) if err != nil { return nil, err } diff --git a/pkg/backends/openfaas.go b/pkg/backends/openfaas.go index 89ab0402..d03db44c 100644 --- a/pkg/backends/openfaas.go +++ b/pkg/backends/openfaas.go @@ -83,21 +83,20 @@ func (of *OpenfaasBackend) GetInfo() *types.ServerlessBackendInfo { // ListServices returns a slice with all services registered in the provided namespace func (of *OpenfaasBackend) ListServices() ([]*types.Service, error) { - // Get the list with all deployments - deployments, err := of.kubeClientset.AppsV1().Deployments(of.namespace).List(context.TODO(), metav1.ListOptions{}) + // Get the list with all Knative services + configmaps, err := getAllServicesConfigMaps(of.namespace, of.kubeClientset) if err != nil { + log.Printf("WARNING: %v\n", err) return nil, err } - services := []*types.Service{} - for _, deployment := range deployments.Items { - // Get service from configMap's FDL - svc, err := getServiceFromFDL(deployment.Name, of.namespace, of.kubeClientset) + + for _, cm := range configmaps.Items { + service, err := getServiceFromConfigMap(&cm) if err != nil { - log.Printf("WARNING: %v\n", err) - } else { - services = append(services, svc) + return nil, err } + services = append(services, service) } return services, nil @@ -230,8 +229,13 @@ func (of *OpenfaasBackend) ReadService(name string) (*types.Service, error) { return nil, err } + // Get the configMap of the Service + cm, err := of.kubeClientset.CoreV1().ConfigMaps(of.namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the service \"%s\" does not have a registered ConfigMap", name) + } // Get service from configMap's FDL - svc, err := getServiceFromFDL(name, of.namespace, of.kubeClientset) + svc, err := getServiceFromConfigMap(cm) if err != nil { return nil, err } diff --git a/pkg/handlers/create.go b/pkg/handlers/create.go index 3b296ce0..37eb5453 100644 --- a/pkg/handlers/create.go +++ b/pkg/handlers/create.go @@ -70,7 +70,6 @@ func MakeCreateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg) // Service is created by an EGI user - createLogger.Printf("Admin: %t", isAdminUser) if !isAdminUser { uid, err := auth.GetUIDFromContext(c) diff --git a/pkg/handlers/list.go b/pkg/handlers/list.go index 0ebcf2d3..ba8ae64e 100644 --- a/pkg/handlers/list.go +++ b/pkg/handlers/list.go @@ -43,23 +43,14 @@ func MakeListHandler(back types.ServerlessBackend) gin.HandlerFunc { uid, err := auth.GetUIDFromContext(c) if err != nil { c.String(http.StatusInternalServerError, fmt.Sprintln(err)) + return } var allowedServicesForUser []*types.Service for _, service := range services { - /*if len(service.AllowedUsers) == 0 { - allowedServicesForUser = append(allowedServicesForUser, service) - continue - }*/ if len(service.AllowedUsers) == 0 || slices.Contains(service.AllowedUsers, uid) { allowedServicesForUser = append(allowedServicesForUser, service) } - /*for _, id := range service.AllowedUsers { - if uid == id { - allowedServicesForUser = append(allowedServicesForUser, service) - break - } - }*/ } c.JSON(http.StatusOK, allowedServicesForUser) From 56854ebb0b58abb18ab53c426640ff2e84ca078b Mon Sep 17 00:00:00 2001 From: catttam Date: Thu, 22 Aug 2024 09:45:20 +0200 Subject: [PATCH 5/8] Fixed tests --- pkg/backends/k8s.go | 23 ++++++++-------------- pkg/backends/k8s_test.go | 38 ------------------------------------ pkg/backends/knative_test.go | 11 ----------- pkg/handlers/job.go | 36 +++++++++------------------------- pkg/types/interlink.go | 19 ++++++++---------- pkg/types/mount.go | 2 -- pkg/types/service.go | 2 +- 7 files changed, 26 insertions(+), 105 deletions(-) diff --git a/pkg/backends/k8s.go b/pkg/backends/k8s.go index 2cbf6866..725616d1 100644 --- a/pkg/backends/k8s.go +++ b/pkg/backends/k8s.go @@ -57,28 +57,21 @@ func (k *KubeBackend) GetInfo() *types.ServerlessBackendInfo { // ListServices returns a slice with all services registered in the provided namespace func (k *KubeBackend) ListServices() ([]*types.Service, error) { - // Get the list with all podTemplates - podTemplates, err := k.kubeClientset.CoreV1().PodTemplates(k.namespace).List(context.TODO(), metav1.ListOptions{}) + // Get the list with all Knative services + configmaps, err := getAllServicesConfigMaps(k.namespace, k.kubeClientset) if err != nil { + log.Printf("WARNING: %v\n", err) return nil, err } - services := []*types.Service{} - for _, podTemplate := range podTemplates.Items { - // Get service from configMap's FDL - // Get the configMap of the Service - cm, err := k.kubeClientset.CoreV1().ConfigMaps(k.namespace).Get(context.TODO(), podTemplate.Name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("the service \"%s\" does not have a registered ConfigMap", &podTemplate.Name) - } - svc, err := getServiceFromConfigMap(cm) + + for _, cm := range configmaps.Items { + service, err := getServiceFromConfigMap(&cm) if err != nil { - log.Printf("WARNING: %v\n", err) - } else { - services = append(services, svc) + return nil, err } + services = append(services, service) } - return services, nil } diff --git a/pkg/backends/k8s_test.go b/pkg/backends/k8s_test.go index 1a967bda..e9e4f30b 100644 --- a/pkg/backends/k8s_test.go +++ b/pkg/backends/k8s_test.go @@ -113,29 +113,12 @@ func TestKubeGetInfo(t *testing.T) { } func TestKubeListServices(t *testing.T) { - validPodTemplateListReactor := func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { - podTemplateList := &v1.PodTemplateList{ - Items: []v1.PodTemplate{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "testnamespace", - }, - Template: v1.PodTemplateSpec{}, - }, - }, - } - return true, podTemplateList, nil - } t.Run("valid list", func(t *testing.T) { clientset := fake.NewSimpleClientset() back := MakeKubeBackend(clientset, testConfig) - // Return a valid PodTemplateList - back.kubeClientset.(*fake.Clientset).Fake.PrependReactor("list", "podtemplates", validPodTemplateListReactor) - // Return a valid configMap back.kubeClientset.(*fake.Clientset).Fake.PrependReactor("get", "configmaps", validConfigMapReaction) @@ -146,29 +129,11 @@ func TestKubeListServices(t *testing.T) { } }) - t.Run("listing podTemplates throws an error", func(t *testing.T) { - clientset := fake.NewSimpleClientset() - - back := MakeKubeBackend(clientset, testConfig) - - // Return an error listing PodTemplates - back.kubeClientset.(*fake.Clientset).Fake.PrependReactor("list", "podtemplates", errorReaction) - - // Call - _, err := back.ListServices() - if err == nil { - t.Error("expecting error, got: nil") - } - }) - t.Run("getServiceFromFDL throws error getting configMap", func(t *testing.T) { clientset := fake.NewSimpleClientset() back := MakeKubeBackend(clientset, testConfig) - // Return a valid PodTemplateList - back.kubeClientset.(*fake.Clientset).Fake.PrependReactor("list", "podtemplates", validPodTemplateListReactor) - // Return an error getting the configMap back.kubeClientset.(*fake.Clientset).Fake.PrependReactor("get", "configmaps", errorReaction) @@ -198,9 +163,6 @@ func TestKubeListServices(t *testing.T) { return true, validCM, nil } - // Return a valid PodTemplateList - back.kubeClientset.(*fake.Clientset).Fake.PrependReactor("list", "podtemplates", validPodTemplateListReactor) - // Return a valid configMap with invalid FDL back.kubeClientset.(*fake.Clientset).Fake.PrependReactor("get", "configmaps", validConfigMapWithInvalidFDLReactor) diff --git a/pkg/backends/knative_test.go b/pkg/backends/knative_test.go index d21f16b2..064da7af 100644 --- a/pkg/backends/knative_test.go +++ b/pkg/backends/knative_test.go @@ -144,17 +144,6 @@ func TestKnativeListServices(t *testing.T) { []k8stesting.SimpleReactor{knServiceListReactor}, false, }, - { - "Error listing knative services", - []k8stesting.SimpleReactor{}, - []k8stesting.SimpleReactor{ - { - Verb: "list", - Resource: "services", - Reaction: errorReaction, - }}, - true, - }, { "Error getting the configMap", []k8stesting.SimpleReactor{ diff --git a/pkg/handlers/job.go b/pkg/handlers/job.go index ab242f03..53654aeb 100644 --- a/pkg/handlers/job.go +++ b/pkg/handlers/job.go @@ -98,36 +98,22 @@ func MakeJobHandler(cfg *types.Config, kubeClientset *kubernetes.Clientset, back return } - // Make event envVar + // Initialize event envVar and args var event := v1.EnvVar{} - var args []string + if cfg.InterLinkAvailable && service.InterLinkNodeName != "" { - command, event, args, _ = types.SetInterlinkJob(podSpec, service, cfg, eventBytes) - /*event = v1.EnvVar{ - Name: types.EventVariable, - Value: base64.StdEncoding.EncodeToString([]byte(eventBytes)), - } - args = fmt.Sprintf("\" wget %s -O %s && chmod 0755 %s && echo \\$%s | base64 -d | %s \"", cfg.SupervisorURL, SupervisorPath, SupervisorPath, types.EventVariable, SupervisorPath) - podSpec.NodeSelector = map[string]string{ - NodeSelectorKey: service.InterLinkNodeName, - } - podSpec.DNSPolicy = InterLinkDNSPolicy - podSpec.RestartPolicy = InterLinkRestartPolicy - podSpec.Tolerations = []v1.Toleration{ - { - Key: InterLinkTolerationKey, - Operator: InterLinkTolerationOperator, - }, - }*/ + command, event, args = types.SetInterlinkJob(podSpec, service, cfg, eventBytes) } else { - event = v1.EnvVar{ - Name: types.EventVariable, - Value: string(eventBytes), - } + if service.Mount.Provider != "" { args = []string{"-c", fmt.Sprintf("echo $%s | %s", types.EventVariable, service.GetSupervisorPath()) + ";echo \"I finish\" > /tmpfolder/finish-file;"} + types.SetMount(podSpec, *service, cfg) } else { + event = v1.EnvVar{ + Name: types.EventVariable, + Value: string(eventBytes), + } args = []string{"-c", fmt.Sprintf("echo $%s | %s", types.EventVariable, service.GetSupervisorPath())} } } @@ -160,10 +146,6 @@ func MakeJobHandler(cfg *types.Config, kubeClientset *kubernetes.Clientset, back podSpec.Containers[i].Env = append(podSpec.Containers[i].Env, resourceIDVar) } } - if service.Mount.Provider != "" { - types.SetMount(podSpec, *service, cfg) - //podSpec.Containers[0].Args = []string{"-c", args + ";echo \"I finish\" > /tmpfolder/finish-file;"} - } // Delegate job if can't be scheduled and has defined replicas if rm != nil && service.HasReplicas() { diff --git a/pkg/types/interlink.go b/pkg/types/interlink.go index 2bcd757f..e80cbbea 100644 --- a/pkg/types/interlink.go +++ b/pkg/types/interlink.go @@ -26,9 +26,8 @@ const ( ContainerSupervisorName = "supervisor-container" SupervisorMountPath = "/data" SupervisorArg = "cp -r /supervisor/* " + SupervisorMountPath - //SupervisorCommand = [...]string{"/bin/sh", "-c"} - NameSupervisorVolume = "supervisor-share-data" - NodeSelectorKey = "kubernetes.io/hostname" + NameSupervisorVolume = "supervisor-share-data" + NodeSelectorKey = "kubernetes.io/hostname" // Annotations for InterLink nodes InterLinkDNSPolicy = "ClusterFirst" @@ -40,8 +39,8 @@ const ( var SupervisorCommand = []string{"/bin/sh", "-c"} var OscarContainerCommand = []string{"echo $EVENT | base64 -d | " + SupervisorMountPath + "/supervisor"} -// // job -func SetInterlinkJob(podSpec *v1.PodSpec, service *Service, cfg *Config, eventBytes []byte) ([]string, v1.EnvVar, []string, error) { +// SetInterlinkJob Return interlink configuration for kubernetes job and add Interlink variables to podSpec +func SetInterlinkJob(podSpec *v1.PodSpec, service *Service, cfg *Config, eventBytes []byte) ([]string, v1.EnvVar, []string) { command := SupervisorCommand event := v1.EnvVar{ Name: EventVariable, @@ -61,11 +60,11 @@ func SetInterlinkJob(podSpec *v1.PodSpec, service *Service, cfg *Config, eventBy } addInitContainer(podSpec, cfg) - return command, event, args, nil + return command, event, args } -// / service -func SetInterlinkService(podSpec *v1.PodSpec) error { +// SetInterlinkService Add InterLink configuration to podSpec +func SetInterlinkService(podSpec *v1.PodSpec) { podSpec.Containers[0].ImagePullPolicy = "Always" shareDataVolumeMount := v1.VolumeMount{ Name: NameSupervisorVolume, @@ -81,11 +80,10 @@ func SetInterlinkService(podSpec *v1.PodSpec) error { }, } podSpec.Volumes = append(podSpec.Volumes, shareDataVolume) - return nil } -func addInitContainer(podSpec *v1.PodSpec, cfg *Config) error { +func addInitContainer(podSpec *v1.PodSpec, cfg *Config) { initContainer := v1.Container{ Name: ContainerSupervisorName, Command: SupervisorCommand, @@ -100,5 +98,4 @@ func addInitContainer(podSpec *v1.PodSpec, cfg *Config) error { }, } podSpec.InitContainers = []v1.Container{initContainer} - return nil } diff --git a/pkg/types/mount.go b/pkg/types/mount.go index 630c2ee8..71915fe2 100644 --- a/pkg/types/mount.go +++ b/pkg/types/mount.go @@ -49,8 +49,6 @@ done` // SetMount Creates the sidecar container that mounts the source volume onto the pod volume func SetMount(podSpec *v1.PodSpec, service Service, cfg *Config) { podSpec.Containers = append(podSpec.Containers, sidecarPodSpec(service)) - //termination := int64(5) - //podSpec.TerminationGracePeriodSeconds = &termination addVolume(podSpec) } diff --git a/pkg/types/service.go b/pkg/types/service.go index 8ece7696..0fc8c157 100644 --- a/pkg/types/service.go +++ b/pkg/types/service.go @@ -300,7 +300,7 @@ func (service *Service) ToPodSpec(cfg *Config) (*v1.PodSpec, error) { } if cfg.InterLinkAvailable && service.InterLinkNodeName != "" { // Add specs of InterLink - _ = SetInterlinkService(podSpec) + SetInterlinkService(podSpec) } else { // Add specs volumeMount := v1.VolumeMount{ From b797b5bab85eb3fcd378748e033c9fa920bac6ea Mon Sep 17 00:00:00 2001 From: SergioLangaritaBenitez Date: Tue, 3 Sep 2024 11:39:10 +0200 Subject: [PATCH 6/8] update fix error for admin --- pkg/handlers/update.go | 50 ++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/pkg/handlers/update.go b/pkg/handlers/update.go index 6a5a96f0..f83bd8fa 100644 --- a/pkg/handlers/update.go +++ b/pkg/handlers/update.go @@ -45,7 +45,12 @@ func MakeUpdateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand // Check service values and set defaults checkValues(&newService, cfg) - + authHeader := c.GetHeader("Authorization") + if len(strings.Split(authHeader, "Bearer")) == 1 { + isAdminUser = true + newService.Owner = "cluster_admin" + createLogger.Printf("Updating service for user: %s", newService.Owner) + } // Read the current service oldService, err := back.ReadService(newService.Name) @@ -58,32 +63,35 @@ func MakeUpdateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand } return } + if !isAdminUser { + uid, err := auth.GetUIDFromContext(c) + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintln("Couldn't get UID from context")) + } - uid, err := auth.GetUIDFromContext(c) - if err != nil { - c.String(http.StatusInternalServerError, fmt.Sprintln("Couldn't get UID from context")) - } + if oldService.Owner != uid { + c.String(http.StatusForbidden, "User %s doesn't have permision to modify this service", uid) + return + } - if oldService.Owner != uid { - c.String(http.StatusForbidden, "User %s doesn't have permision to modify this service", uid) - return - } + // Set the owner on the new service definition + newService.Owner = oldService.Owner - // Set the owner on the new service definition - newService.Owner = oldService.Owner - - // If the service has changed VO check permisions again - if newService.VO != "" && newService.VO != oldService.VO { - for _, vo := range cfg.OIDCGroups { - if vo == newService.VO { - authHeader := c.GetHeader("Authorization") - err := checkIdentity(&newService, cfg, authHeader) - if err != nil { - c.String(http.StatusBadRequest, fmt.Sprintln(err)) + // If the service has changed VO check permisions again + if newService.VO != "" && newService.VO != oldService.VO { + for _, vo := range cfg.OIDCGroups { + if vo == newService.VO { + authHeader := c.GetHeader("Authorization") + err := checkIdentity(&newService, cfg, authHeader) + if err != nil { + c.String(http.StatusBadRequest, fmt.Sprintln(err)) + } + break } - break } } + } else { + newService.Owner = oldService.Owner } minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg) From d3ff5d5160908a9aa5b71579f99d0ebccfae8591 Mon Sep 17 00:00:00 2001 From: catttam Date: Thu, 5 Sep 2024 15:23:04 +0200 Subject: [PATCH 7/8] Update UI --- ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui b/ui index 98de936c..045c25fb 160000 --- a/ui +++ b/ui @@ -1 +1 @@ -Subproject commit 98de936c5923d3b3ccaef500c1a92f35009bbf53 +Subproject commit 045c25fbf3acfeaaefcb44c0b183098bf196c7f1 From 62629d6809a706ac0e8ca0a2ad42d092bc517885 Mon Sep 17 00:00:00 2001 From: catttam Date: Thu, 5 Sep 2024 15:40:03 +0200 Subject: [PATCH 8/8] Minor change --- pkg/handlers/update.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/handlers/update.go b/pkg/handlers/update.go index f83bd8fa..cd97f826 100644 --- a/pkg/handlers/update.go +++ b/pkg/handlers/update.go @@ -48,8 +48,7 @@ func MakeUpdateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand authHeader := c.GetHeader("Authorization") if len(strings.Split(authHeader, "Bearer")) == 1 { isAdminUser = true - newService.Owner = "cluster_admin" - createLogger.Printf("Updating service for user: %s", newService.Owner) + createLogger.Printf("[*] Updating service as admin user") } // Read the current service oldService, err := back.ReadService(newService.Name) @@ -90,10 +89,7 @@ func MakeUpdateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand } } } - } else { - newService.Owner = oldService.Owner } - minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg) // Update the service if err := back.UpdateService(newService); err != nil {