diff --git a/pkg/executor/executortype/newdeploy/newdeploymgr.go b/pkg/executor/executortype/newdeploy/newdeploymgr.go index d4acb99c..951e381b 100644 --- a/pkg/executor/executortype/newdeploy/newdeploymgr.go +++ b/pkg/executor/executortype/newdeploy/newdeploymgr.go @@ -47,6 +47,7 @@ import ( fetcherConfig "github.com/fission/fission/pkg/fetcher/config" "github.com/fission/fission/pkg/throttler" "github.com/fission/fission/pkg/utils" + "github.com/fission/fission/pkg/utils/maps" ) var _ executortype.ExecutorType = &NewDeploy{} @@ -426,7 +427,7 @@ func (deploy *NewDeploy) fnCreate(fn *fv1.Function) (*fscache.FuncSvc, error) { objName := deploy.getObjName(fn) deployLabels := deploy.getDeployLabels(fn.ObjectMeta, env.ObjectMeta) - deployAnnotations := deploy.getDeployAnnotations(fn.ObjectMeta) + deployAnnotations := deploy.getDeployAnnotations(fn.ObjectMeta, env.ObjectMeta) // to support backward compatibility, if the function was created in default ns, we fall back to creating the // deployment of the function in fission-function ns @@ -666,7 +667,7 @@ func (deploy *NewDeploy) updateFuncDeployment(fn *fv1.Function, env *fv1.Environ // Therefore, the deployment update will trigger a rolling update. newDeployment, err := deploy.getDeploymentSpec(fn, env, existingDepl.Spec.Replicas, // use current replicas instead of minscale in the ExecutionStrategy. - fnObjName, ns, deployLabels, deploy.getDeployAnnotations(fn.ObjectMeta)) + fnObjName, ns, deployLabels, deploy.getDeployAnnotations(fn.ObjectMeta, env.ObjectMeta)) if err != nil { deploy.updateStatus(fn, err, "failed to get new deployment spec while updating function") return err @@ -724,7 +725,7 @@ func (deploy *NewDeploy) getObjName(fn *fv1.Function) string { } func (deploy *NewDeploy) getDeployLabels(fnMeta metav1.ObjectMeta, envMeta metav1.ObjectMeta) map[string]string { - return map[string]string{ + deployLabels := map[string]string{ fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypeNewdeploy), fv1.ENVIRONMENT_NAME: envMeta.Name, fv1.ENVIRONMENT_NAMESPACE: envMeta.Namespace, @@ -733,13 +734,17 @@ func (deploy *NewDeploy) getDeployLabels(fnMeta metav1.ObjectMeta, envMeta metav fv1.FUNCTION_NAMESPACE: fnMeta.Namespace, fv1.FUNCTION_UID: string(fnMeta.UID), } + for k, v := range envMeta.Labels { + deployLabels[k] = v + } + return deployLabels } -func (deploy *NewDeploy) getDeployAnnotations(fnMeta metav1.ObjectMeta) map[string]string { - return map[string]string{ - fv1.EXECUTOR_INSTANCEID_LABEL: deploy.instanceID, - fv1.FUNCTION_RESOURCE_VERSION: fnMeta.ResourceVersion, - } +func (deploy *NewDeploy) getDeployAnnotations(fnMeta metav1.ObjectMeta, envMeta metav1.ObjectMeta) map[string]string { + deployAnnotations := maps.CopyStringMap(envMeta.Annotations) + deployAnnotations[fv1.EXECUTOR_INSTANCEID_LABEL] = deploy.instanceID + deployAnnotations[fv1.FUNCTION_RESOURCE_VERSION] = fnMeta.ResourceVersion + return deployAnnotations } // updateStatus is a function which updates status of update. diff --git a/pkg/executor/executortype/poolmgr/gp.go b/pkg/executor/executortype/poolmgr/gp.go index a4627b89..3efd0744 100644 --- a/pkg/executor/executortype/poolmgr/gp.go +++ b/pkg/executor/executortype/poolmgr/gp.go @@ -50,6 +50,7 @@ import ( fetcherClient "github.com/fission/fission/pkg/fetcher/client" fetcherConfig "github.com/fission/fission/pkg/fetcher/config" "github.com/fission/fission/pkg/utils" + "github.com/fission/fission/pkg/utils/maps" ) type ( @@ -155,19 +156,19 @@ func MakeGenericPool( } func (gp *GenericPool) getEnvironmentPoolLabels() map[string]string { - return map[string]string{ - fv1.EXECUTOR_TYPE: string(fv1.ExecutorTypePoolmgr), - fv1.ENVIRONMENT_NAME: gp.env.ObjectMeta.Name, - fv1.ENVIRONMENT_NAMESPACE: gp.env.ObjectMeta.Namespace, - fv1.ENVIRONMENT_UID: string(gp.env.ObjectMeta.UID), - "managed": "true", // this allows us to easily find pods managed by the deployment - } + envLabels := maps.CopyStringMap(gp.env.ObjectMeta.Labels) + envLabels[fv1.EXECUTOR_TYPE] = string(fv1.ExecutorTypePoolmgr) + envLabels[fv1.ENVIRONMENT_NAME] = gp.env.ObjectMeta.Name + envLabels[fv1.ENVIRONMENT_NAMESPACE] = gp.env.ObjectMeta.Namespace + envLabels[fv1.ENVIRONMENT_UID] = string(gp.env.ObjectMeta.UID) + envLabels["managed"] = "true" // this allows us to easily find pods managed by the deployment + return envLabels } func (gp *GenericPool) getDeployAnnotations() map[string]string { - return map[string]string{ - fv1.EXECUTOR_INSTANCEID_LABEL: gp.instanceID, - } + deployAnnotations := maps.CopyStringMap(gp.env.Annotations) + deployAnnotations[fv1.EXECUTOR_INSTANCEID_LABEL] = gp.instanceID + return deployAnnotations } func (gp *GenericPool) checkMetricsApi() bool { diff --git a/pkg/fission-cli/cmd/environment/command.go b/pkg/fission-cli/cmd/environment/command.go index 7cd20eef..8ad5b146 100644 --- a/pkg/fission-cli/cmd/environment/command.go +++ b/pkg/fission-cli/cmd/environment/command.go @@ -31,10 +31,13 @@ func Commands() *cobra.Command { } wrapper.SetFlags(createCmd, flag.FlagSet{ Required: []flag.Flag{flag.EnvName, flag.EnvImage}, - Optional: []flag.Flag{flag.EnvPoolsize, flag.EnvBuilderImage, flag.EnvBuildCmd, + Optional: []flag.Flag{ + flag.EnvPoolsize, flag.EnvBuilderImage, flag.EnvBuildCmd, flag.RunTimeMinCPU, flag.RunTimeMaxCPU, flag.RunTimeMinMemory, flag.RunTimeMaxMemory, - flag.EnvTerminationGracePeriod, flag.EnvVersion, flag.EnvImagePullSecret, - flag.EnvExternalNetwork, flag.EnvKeepArchive, flag.NamespaceEnvironment, flag.SpecSave, flag.SpecDry}, + flag.EnvTerminationGracePeriod, flag.EnvVersion, flag.EnvImagePullSecret, flag.EnvKeepArchive, + flag.NamespaceEnvironment, flag.EnvExternalNetwork, + flag.Labels, flag.Annotation, + flag.SpecSave, flag.SpecDry}, }) getCmd := &cobra.Command{ @@ -57,7 +60,9 @@ func Commands() *cobra.Command { Optional: []flag.Flag{flag.EnvImage, flag.EnvPoolsize, flag.EnvBuilderImage, flag.EnvBuildCmd, flag.EnvImagePullSecret, flag.RunTimeMinCPU, flag.RunTimeMaxCPU, flag.RunTimeMinMemory, flag.RunTimeMaxMemory, - flag.EnvTerminationGracePeriod, flag.EnvKeepArchive, flag.NamespaceEnvironment, flag.EnvExternalNetwork}, + flag.EnvTerminationGracePeriod, flag.EnvKeepArchive, + flag.NamespaceEnvironment, flag.EnvExternalNetwork, + flag.Labels, flag.Annotation}, }) deleteCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/environment/create.go b/pkg/fission-cli/cmd/environment/create.go index 44f73bd7..56bca9c5 100644 --- a/pkg/fission-cli/cmd/environment/create.go +++ b/pkg/fission-cli/cmd/environment/create.go @@ -179,6 +179,10 @@ func createEnvironmentFromCmd(input cli.Input) (*fv1.Environment, error) { }, } + err = util.ApplyLabelsAndAnnotations(input, &env.ObjectMeta) + if err != nil { + return nil, err + } err = env.Validate() if err != nil { return nil, fv1.AggregateValidationErrors("Environment", err) diff --git a/pkg/fission-cli/cmd/environment/update.go b/pkg/fission-cli/cmd/environment/update.go index e113b28b..8e05d09b 100644 --- a/pkg/fission-cli/cmd/environment/update.go +++ b/pkg/fission-cli/cmd/environment/update.go @@ -31,6 +31,7 @@ import ( "github.com/fission/fission/pkg/fission-cli/cmd" "github.com/fission/fission/pkg/fission-cli/console" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" + "github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/utils" ) @@ -66,6 +67,11 @@ func (opts *UpdateSubCommand) complete(input cli.Input) error { } opts.env = env + + err = util.ApplyLabelsAndAnnotations(input, &opts.env.ObjectMeta) + if err != nil { + return err + } return nil } diff --git a/pkg/fission-cli/cmd/function/command.go b/pkg/fission-cli/cmd/function/command.go index 8cc3b6cd..3b075ac1 100644 --- a/pkg/fission-cli/cmd/function/command.go +++ b/pkg/fission-cli/cmd/function/command.go @@ -36,7 +36,7 @@ func Commands() *cobra.Command { flag.FnExecutorType, flag.FnCfgMap, flag.FnSecret, flag.FnSpecializationTimeout, flag.FnExecutionTimeout, flag.FnIdleTimeout, flag.FnConcurrency, flag.FnRequestsPerPod, - flag.FnOnceOnly, + flag.FnOnceOnly, flag.Labels, flag.Annotation, // TODO retired pkg & trigger related flags from function cmd flag.PkgCode, flag.PkgSrcArchive, flag.PkgDeployArchive, @@ -88,7 +88,7 @@ func Commands() *cobra.Command { flag.FnExecutorType, flag.FnSecret, flag.FnCfgMap, flag.FnSpecializationTimeout, flag.FnExecutionTimeout, flag.FnIdleTimeout, flag.FnConcurrency, flag.FnRequestsPerPod, - flag.FnOnceOnly, + flag.FnOnceOnly, flag.Labels, flag.Annotation, flag.PkgCode, flag.PkgSrcArchive, flag.PkgDeployArchive, flag.PkgSrcChecksum, flag.PkgDeployChecksum, flag.PkgInsecure, diff --git a/pkg/fission-cli/cmd/function/create.go b/pkg/fission-cli/cmd/function/create.go index 7fbd2e73..c34c34cc 100644 --- a/pkg/fission-cli/cmd/function/create.go +++ b/pkg/fission-cli/cmd/function/create.go @@ -309,6 +309,11 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { }, } + err = util.ApplyLabelsAndAnnotations(input, &opts.function.ObjectMeta) + if err != nil { + return err + } + return nil } diff --git a/pkg/fission-cli/cmd/function/update.go b/pkg/fission-cli/cmd/function/update.go index c8ef7f49..1975549d 100644 --- a/pkg/fission-cli/cmd/function/update.go +++ b/pkg/fission-cli/cmd/function/update.go @@ -243,6 +243,11 @@ func (opts *UpdateSubCommand) complete(input cli.Input) error { opts.function = function + err = util.ApplyLabelsAndAnnotations(input, &opts.function.ObjectMeta) + if err != nil { + return err + } + return nil } diff --git a/pkg/fission-cli/flag/flag.go b/pkg/fission-cli/flag/flag.go index fbbcf822..94103f69 100644 --- a/pkg/fission-cli/flag/flag.go +++ b/pkg/fission-cli/flag/flag.go @@ -74,6 +74,9 @@ var ( KubeContext = Flag{Type: String, Name: flagkey.KubeContext, Usage: "Kubernetes context to be used for the execution of Fission commands", DefaultValue: ""} + Labels = Flag{Type: String, Name: flagkey.Labels, Usage: "Comma separated labels to apply to the function. Eg. --labels=\"environment=dev,application=analytics\""} + Annotation = Flag{Type: StringSlice, Name: flagkey.Annotation, Usage: "Annotation to apply to the function. To mention multiple annotations --annotation=\"abc.com/team=dev\" --annotation=\"foo=bar\""} + NamespaceFunction = Flag{Type: String, Name: flagkey.NamespaceFunction, Aliases: []string{"fns"}, Usage: "Namespace for function object", DefaultValue: metav1.NamespaceDefault} NamespaceEnvironment = Flag{Type: String, Name: flagkey.NamespaceEnvironment, Aliases: []string{"envns"}, Usage: "Namespace for environment object", DefaultValue: metav1.NamespaceDefault} NamespacePackage = Flag{Type: String, Name: flagkey.NamespacePackage, Aliases: []string{"pkgns"}, Usage: "Namespace for package object", DefaultValue: metav1.NamespaceDefault} diff --git a/pkg/fission-cli/flag/key/key.go b/pkg/fission-cli/flag/key/key.go index c2338701..b4c5de6b 100644 --- a/pkg/fission-cli/flag/key/key.go +++ b/pkg/fission-cli/flag/key/key.go @@ -26,6 +26,9 @@ const ( force = "force" Output = "output" + Labels = "labels" + Annotation = "annotation" + NamespaceFunction = "fnNamespace" NamespaceEnvironment = "envNamespace" NamespacePackage = "pkgNamespace" diff --git a/pkg/fission-cli/util/util.go b/pkg/fission-cli/util/util.go index 933c7b06..37ec661c 100644 --- a/pkg/fission-cli/util/util.go +++ b/pkg/fission-cli/util/util.go @@ -32,6 +32,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -350,3 +351,52 @@ func UrlForFunction(name, namespace string) string { } return fmt.Sprintf("%v/%v", prefix, name) } + +func ParseAnnotations(annotations []string) (map[string]string, error) { + var invalidAnnotations string + annotationMap := make(map[string]string) + for _, arg := range annotations { + if strings.Contains(arg, "=") && arg[0] != '=' { + parts := strings.SplitN(arg, "=", 2) + if len(parts) == 2 { + annotationMap[parts[0]] = parts[1] + } else { + if invalidAnnotations != "" { + invalidAnnotations = fmt.Sprintf("%s,%s", invalidAnnotations, arg) + } else { + invalidAnnotations = arg + } + } + } else { + if invalidAnnotations != "" { + invalidAnnotations = fmt.Sprintf("%s,%s", invalidAnnotations, arg) + } else { + invalidAnnotations = arg + } + } + } + if invalidAnnotations != "" { + return nil, errors.Errorf("invalid annotations: %s", invalidAnnotations) + } + return annotationMap, nil +} + +func ApplyLabelsAndAnnotations(input cli.Input, objectMeta *metav1.ObjectMeta) error { + labelStr := input.String(flagkey.Labels) + if labelStr != "" { + set, err := labels.ConvertSelectorToLabelsMap(labelStr) + if err != nil { + return err + } + objectMeta.Labels = set + } + annotationStr := input.StringSlice(flagkey.Annotation) + if len(annotationStr) > 0 { + set, err := ParseAnnotations(annotationStr) + if err != nil { + return err + } + objectMeta.Annotations = set + } + return nil +} diff --git a/pkg/utils/maps/map.go b/pkg/utils/maps/map.go new file mode 100644 index 00000000..d52ee34f --- /dev/null +++ b/pkg/utils/maps/map.go @@ -0,0 +1,24 @@ +/* +Copyright 2021 The Fission Authors. + +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 maps + +func CopyStringMap(m map[string]string) map[string]string { + n := make(map[string]string) + for k, v := range m { + n[k] = v + } + return n +}