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:
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -26,6 +26,9 @@ const (
|
||||
force = "force"
|
||||
Output = "output"
|
||||
|
||||
Labels = "labels"
|
||||
Annotation = "annotation"
|
||||
|
||||
NamespaceFunction = "fnNamespace"
|
||||
NamespaceEnvironment = "envNamespace"
|
||||
NamespacePackage = "pkgNamespace"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user