mirror of https://github.com/knative/func.git
Adds labels and annotations from func.yaml to pipeline resources (#1205)
* adds labels from func.yaml to pipeline resources * Unify function labels across resources (kService and tekton pipelines) * Adds function annotations to pipeline resources * Remove refactored function
This commit is contained in:
parent
17625b7c0d
commit
7e96146840
57
function.go
57
function.go
|
@ -11,6 +11,8 @@ import (
|
|||
"time"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
fnlabels "knative.dev/kn-plugin-func/k8s/labels"
|
||||
"knative.dev/pkg/ptr"
|
||||
)
|
||||
|
||||
// FunctionFile is the file used for the serialized form of a function.
|
||||
|
@ -344,6 +346,61 @@ func (f Function) ImageWithDigest() string {
|
|||
return part1 + strings.Split(part2, ":")[0] + "@" + f.ImageDigest
|
||||
}
|
||||
|
||||
// LabelsMap combines default labels with the labels slice provided.
|
||||
// It will the resulting slice with ValidateLabels and return a key/value map.
|
||||
// - key: EXAMPLE1 # Label directly from a value
|
||||
// value: value1
|
||||
// - key: EXAMPLE2 # Label from the local ENV var
|
||||
// value: {{ env:MY_ENV }}
|
||||
func (f Function) LabelsMap() (map[string]string, error) {
|
||||
defaultLabels := []Label{
|
||||
{
|
||||
Key: ptr.String(fnlabels.FunctionKey),
|
||||
Value: ptr.String(fnlabels.FunctionValue),
|
||||
},
|
||||
{
|
||||
Key: ptr.String(fnlabels.FunctionNameKey),
|
||||
Value: ptr.String(f.Name),
|
||||
},
|
||||
{
|
||||
Key: ptr.String(fnlabels.FunctionRuntimeKey),
|
||||
Value: ptr.String(f.Runtime),
|
||||
},
|
||||
// --- handle usage of deprecated labels (`boson.dev/function`, `boson.dev/runtime`)
|
||||
{
|
||||
Key: ptr.String(fnlabels.DeprecatedFunctionKey),
|
||||
Value: ptr.String(fnlabels.FunctionValue),
|
||||
},
|
||||
{
|
||||
Key: ptr.String(fnlabels.DeprecatedFunctionRuntimeKey),
|
||||
Value: ptr.String(f.Runtime),
|
||||
},
|
||||
// --- end of handling usage of deprecated runtime labels
|
||||
}
|
||||
|
||||
labels := append(defaultLabels, f.Labels...)
|
||||
if err := ValidateLabels(labels); len(err) != 0 {
|
||||
return nil, errors.New(strings.Join(err, " "))
|
||||
}
|
||||
|
||||
l := map[string]string{}
|
||||
for _, label := range labels {
|
||||
if label.Value == nil {
|
||||
l[*label.Key] = ""
|
||||
} else {
|
||||
if strings.HasPrefix(*label.Value, "{{") {
|
||||
// env variable format is validated above in ValidateLabels
|
||||
match := regLocalEnv.FindStringSubmatch(*label.Value)
|
||||
l[*label.Key] = os.Getenv(match[1])
|
||||
} else {
|
||||
l[*label.Key] = *label.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// assertEmptyRoot ensures that the directory is empty enough to be used for
|
||||
// initializing a new function.
|
||||
func assertEmptyRoot(path string) (err error) {
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
fnlabels "knative.dev/kn-plugin-func/k8s/labels"
|
||||
. "knative.dev/kn-plugin-func/testing"
|
||||
)
|
||||
|
||||
func TestFunction_ImageWithDigest(t *testing.T) {
|
||||
|
@ -82,3 +86,126 @@ func TestFunction_ImageName(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_LabelsMap(t *testing.T) {
|
||||
key1 := "key1"
|
||||
key2 := "key2"
|
||||
value1 := "value1"
|
||||
value2 := "value2"
|
||||
|
||||
defer WithEnvVar(t, "BAD_EXAMPLE", ":invalid")()
|
||||
valueLocalEnvIncorrect4 := "{{env:BAD_EXAMPLE}}"
|
||||
|
||||
defer WithEnvVar(t, "GOOD_EXAMPLE", "valid")()
|
||||
valueLocalEnv4 := "{{env:GOOD_EXAMPLE}}"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
labels []Label
|
||||
expectErr bool
|
||||
expectedMap map[string]string
|
||||
}{
|
||||
{
|
||||
name: "invalid Labels should return err",
|
||||
labels: []Label{
|
||||
{
|
||||
Value: &value1,
|
||||
},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "with valid env var",
|
||||
labels: []Label{
|
||||
{
|
||||
Key: &key1,
|
||||
Value: &valueLocalEnv4,
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
expectedMap: map[string]string{
|
||||
key1: "valid",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with invalid env var",
|
||||
labels: []Label{
|
||||
{
|
||||
Key: &key1,
|
||||
Value: &valueLocalEnvIncorrect4,
|
||||
},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty labels allowed. returns default labels",
|
||||
labels: []Label{
|
||||
{
|
||||
Key: &key1,
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
expectedMap: map[string]string{
|
||||
key1: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "full set of labels",
|
||||
labels: []Label{
|
||||
{
|
||||
Key: &key1,
|
||||
Value: &value1,
|
||||
},
|
||||
{
|
||||
Key: &key2,
|
||||
Value: &value2,
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
expectedMap: map[string]string{
|
||||
key1: value1,
|
||||
key2: value2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
f := Function{
|
||||
Name: "some-function",
|
||||
Runtime: "golang",
|
||||
Labels: tt.labels,
|
||||
}
|
||||
got, err := f.LabelsMap()
|
||||
|
||||
if tt.expectErr {
|
||||
if err == nil {
|
||||
t.Error("expected error but didn't get an error from LabelsMap")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("got unexpected err: %s", err)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
defaultLabels := expectedDefaultLabels(f)
|
||||
for k, v := range defaultLabels {
|
||||
tt.expectedMap[k] = v
|
||||
}
|
||||
if res := reflect.DeepEqual(got, tt.expectedMap); !res {
|
||||
t.Errorf("mismatch in actual and expected labels return. actual: %#v, expected: %#v", got, tt.expectedMap)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func expectedDefaultLabels(f Function) map[string]string {
|
||||
return map[string]string{
|
||||
fnlabels.FunctionKey: fnlabels.FunctionValue,
|
||||
fnlabels.FunctionNameKey: f.Name,
|
||||
fnlabels.FunctionRuntimeKey: f.Runtime,
|
||||
fnlabels.DeprecatedFunctionKey: fnlabels.FunctionValue,
|
||||
fnlabels.DeprecatedFunctionRuntimeKey: f.Runtime,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ func GetPersistentVolumeClaim(ctx context.Context, name, namespaceOverride strin
|
|||
return client.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func CreatePersistentVolumeClaim(ctx context.Context, name, namespaceOverride string, labels map[string]string, accessMode corev1.PersistentVolumeAccessMode, resourceRequest resource.Quantity) (err error) {
|
||||
func CreatePersistentVolumeClaim(ctx context.Context, name, namespaceOverride string, labels map[string]string, annotations map[string]string, accessMode corev1.PersistentVolumeAccessMode, resourceRequest resource.Quantity) (err error) {
|
||||
client, namespace, err := NewClientAndResolvedNamespace(namespaceOverride)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -25,9 +25,10 @@ func CreatePersistentVolumeClaim(ctx context.Context, name, namespaceOverride st
|
|||
|
||||
pvc := &corev1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
},
|
||||
Spec: corev1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []corev1.PersistentVolumeAccessMode{accessMode},
|
||||
|
|
|
@ -83,7 +83,7 @@ func DeleteSecrets(ctx context.Context, namespaceOverride string, listOptions me
|
|||
return client.CoreV1().Secrets(namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, listOptions)
|
||||
}
|
||||
|
||||
func EnsureDockerRegistrySecretExist(ctx context.Context, name, namespaceOverride string, labels map[string]string, username, password, server string) (err error) {
|
||||
func EnsureDockerRegistrySecretExist(ctx context.Context, name, namespaceOverride string, labels map[string]string, annotations map[string]string, username, password, server string) (err error) {
|
||||
client, namespace, err := NewClientAndResolvedNamespace(namespaceOverride)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -110,9 +110,10 @@ func EnsureDockerRegistrySecretExist(ctx context.Context, name, namespaceOverrid
|
|||
if createSecret || !bytes.Equal(currentSecret.Data[secretKey], dockerConfigJSONContent) {
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
},
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
Data: map[string][]byte{},
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
|
||||
fn "knative.dev/kn-plugin-func"
|
||||
"knative.dev/kn-plugin-func/k8s"
|
||||
"knative.dev/kn-plugin-func/k8s/labels"
|
||||
)
|
||||
|
||||
const LIVENESS_ENDPOINT = "/health/liveness"
|
||||
|
@ -294,10 +293,13 @@ func generateNewService(f fn.Function, decorator DeployDecorator) (*v1.Service,
|
|||
}
|
||||
container.VolumeMounts = newVolumeMounts
|
||||
|
||||
labels, err := processLabels(f, decorator)
|
||||
labels, err := f.LabelsMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if decorator != nil {
|
||||
labels = decorator.UpdateLabels(f, labels)
|
||||
}
|
||||
|
||||
annotations := f.Annotations
|
||||
if decorator != nil {
|
||||
|
@ -374,10 +376,14 @@ func updateService(f fn.Function, newEnv []corev1.EnvVar, newEnvFrom []corev1.En
|
|||
return service, err
|
||||
}
|
||||
|
||||
labels, err := processLabels(f, decorator)
|
||||
labels, err := f.LabelsMap()
|
||||
if err != nil {
|
||||
return service, err
|
||||
return nil, err
|
||||
}
|
||||
if decorator != nil {
|
||||
labels = decorator.UpdateLabels(f, labels)
|
||||
}
|
||||
|
||||
service.ObjectMeta.Labels = labels
|
||||
service.Spec.Template.ObjectMeta.Labels = labels
|
||||
|
||||
|
@ -395,54 +401,6 @@ func updateService(f fn.Function, newEnv []corev1.EnvVar, newEnvFrom []corev1.En
|
|||
}
|
||||
}
|
||||
|
||||
// processLabels generates a map of labels as key/value pairs from a function config
|
||||
// labels:
|
||||
// - key: EXAMPLE1 # Label directly from a value
|
||||
// value: value1
|
||||
// - key: EXAMPLE2 # Label from the local ENV var
|
||||
// value: {{ env:MY_ENV }}
|
||||
func processLabels(f fn.Function, decorator DeployDecorator) (map[string]string, error) {
|
||||
labels := map[string]string{
|
||||
labels.FunctionKey: labels.FunctionValue,
|
||||
labels.FunctionNameKey: f.Name,
|
||||
labels.FunctionRuntimeKey: f.Runtime,
|
||||
|
||||
// --- handle usage of deprecated labels (`boson.dev/function`, `boson.dev/runtime`)
|
||||
labels.DeprecatedFunctionKey: labels.FunctionValue,
|
||||
labels.DeprecatedFunctionRuntimeKey: f.Runtime,
|
||||
// --- end of handling usage of deprecated runtime labels
|
||||
}
|
||||
|
||||
if decorator != nil {
|
||||
labels = decorator.UpdateLabels(f, labels)
|
||||
}
|
||||
|
||||
for _, label := range f.Labels {
|
||||
if label.Key != nil && label.Value != nil {
|
||||
if strings.HasPrefix(*label.Value, "{{") {
|
||||
slices := strings.Split(strings.Trim(*label.Value, "{} "), ":")
|
||||
if len(slices) == 2 {
|
||||
// label from the local ENV var, eg. author={{ env:$USER }}
|
||||
localValue, err := processLocalEnvValue(*label.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
labels[*label.Key] = localValue
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// a standard label with key and value, eg. author=alice@example.com
|
||||
labels[*label.Key] = *label.Value
|
||||
continue
|
||||
}
|
||||
} else if label.Key != nil && label.Value == nil {
|
||||
labels[*label.Key] = ""
|
||||
}
|
||||
}
|
||||
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
// processEnvs generates array of EnvVars and EnvFromSources from a function config
|
||||
// envs:
|
||||
// - name: EXAMPLE1 # ENV directly from a value
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
fn "knative.dev/kn-plugin-func"
|
||||
"knative.dev/kn-plugin-func/docker"
|
||||
"knative.dev/kn-plugin-func/k8s"
|
||||
"knative.dev/kn-plugin-func/k8s/labels"
|
||||
fnlabels "knative.dev/kn-plugin-func/k8s/labels"
|
||||
"knative.dev/kn-plugin-func/knative"
|
||||
"knative.dev/pkg/apis"
|
||||
)
|
||||
|
@ -97,12 +97,15 @@ func (pp *PipelinesProvider) Run(ctx context.Context, f fn.Function) error {
|
|||
pp.namespace = namespace
|
||||
|
||||
// let's specify labels that will be applied to every resouce that is created for a Pipeline
|
||||
labels := map[string]string{labels.FunctionNameKey: f.Name}
|
||||
labels, err := f.LabelsMap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pp.decorator != nil {
|
||||
labels = pp.decorator.UpdateLabels(f, labels)
|
||||
}
|
||||
|
||||
err = k8s.CreatePersistentVolumeClaim(ctx, getPipelinePvcName(f), pp.namespace, labels, corev1.ReadWriteOnce, *resource.NewQuantity(DefaultPersistentVolumeClaimSize, resource.DecimalSI))
|
||||
err = k8s.CreatePersistentVolumeClaim(ctx, getPipelinePvcName(f), pp.namespace, labels, f.Annotations, corev1.ReadWriteOnce, *resource.NewQuantity(DefaultPersistentVolumeClaimSize, resource.DecimalSI))
|
||||
if err != nil {
|
||||
if !errors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("problem creating persistent volume claim: %v", err)
|
||||
|
@ -135,7 +138,7 @@ func (pp *PipelinesProvider) Run(ctx context.Context, f fn.Function) error {
|
|||
registry = authn.DefaultAuthKey
|
||||
}
|
||||
|
||||
err = k8s.EnsureDockerRegistrySecretExist(ctx, getPipelineSecretName(f), pp.namespace, labels, creds.Username, creds.Password, registry)
|
||||
err = k8s.EnsureDockerRegistrySecretExist(ctx, getPipelineSecretName(f), pp.namespace, labels, f.Annotations, creds.Username, creds.Password, registry)
|
||||
if err != nil {
|
||||
return fmt.Errorf("problem in creating secret: %v", err)
|
||||
}
|
||||
|
@ -182,7 +185,7 @@ func (pp *PipelinesProvider) Run(ctx context.Context, f fn.Function) error {
|
|||
|
||||
func (pp *PipelinesProvider) Remove(ctx context.Context, f fn.Function) error {
|
||||
|
||||
l := k8slabels.SelectorFromSet(k8slabels.Set(map[string]string{labels.FunctionNameKey: f.Name}))
|
||||
l := k8slabels.SelectorFromSet(k8slabels.Set(map[string]string{fnlabels.FunctionNameKey: f.Name}))
|
||||
listOptions := metav1.ListOptions{
|
||||
LabelSelector: l.String(),
|
||||
}
|
||||
|
|
|
@ -98,8 +98,9 @@ func generatePipeline(f fn.Function, labels map[string]string) *pplnv1beta1.Pipe
|
|||
|
||||
return &pplnv1beta1.Pipeline{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: pipelineName,
|
||||
Labels: labels,
|
||||
Name: pipelineName,
|
||||
Labels: labels,
|
||||
Annotations: f.Annotations,
|
||||
},
|
||||
Spec: pplnv1beta1.PipelineSpec{
|
||||
Params: params,
|
||||
|
@ -200,6 +201,7 @@ func generatePipelineRun(f fn.Function, labels map[string]string) *pplnv1beta1.P
|
|||
ObjectMeta: v1.ObjectMeta{
|
||||
GenerateName: fmt.Sprintf("%s-run-", getPipelineName(f)),
|
||||
Labels: labels,
|
||||
Annotations: f.Annotations,
|
||||
},
|
||||
Spec: pplnv1beta1.PipelineRunSpec{
|
||||
PipelineRef: &pplnv1beta1.PipelineRef{
|
||||
|
|
Loading…
Reference in New Issue