Labels and annotation support for functions and environments (#2113)

1. Support for adding labels and annotations to functions & environment via fission CLI through create & update command.
2. Change ensures labels and annotations assigned to the environment would reflect on pods created via executor type pool manager and new deploy.

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
This commit is contained in:
Sanket Sudake
2021-07-15 17:22:01 +05:30
committed by GitHub
parent 2e0bb9304a
commit ece0475808
12 changed files with 135 additions and 24 deletions
@@ -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.
+11 -10
View File
@@ -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 {
+9 -4
View File
@@ -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{
@@ -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)
@@ -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
}
+2 -2
View File
@@ -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,
+5
View File
@@ -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
}
+5
View File
@@ -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
}
+3
View File
@@ -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}
+3
View File
@@ -26,6 +26,9 @@ const (
force = "force"
Output = "output"
Labels = "labels"
Annotation = "annotation"
NamespaceFunction = "fnNamespace"
NamespaceEnvironment = "envNamespace"
NamespacePackage = "pkgNamespace"
+50
View File
@@ -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
}
+24
View File
@@ -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
}