feat: add support for annotations in func.yaml (#314)

This commit adds limited support for annotations in the func.yaml
config file. The feature is limited, because it's only additive. A
user can add an annotation `foo: bar` in the config and deploy the
function, successfully setting that annotation on the Service.
However, if they subsequently remove `foo: bar` from the config
file, it will _not_ be removed from the deployment. This is because
it's not possible to know, from the set of annotations that currently
exist on the deployment, which ones were set by us and which were not.
So, removing any annotations that are not in func.yaml is unsafe.

It may be possible to store in a hidden file somewhere all of the
user-supplied annotations, allowing us to diff func.yaml with that file,
but I'm not sure I want to go down that path. It might just be best to
document this limitation.

We may also want to document that annotations added through func.yaml
should be user supplied settings/values, and not annotations that are
managed by knative (e.g. the autoscaling annotations).

Fixes: https://github.com/boson-project/func/issues/307

Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
Lance Ball 2021-04-28 13:59:03 -04:00 committed by GitHub
parent 255b4fb33c
commit 5feb0e20f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 19 additions and 5 deletions

View File

@ -23,6 +23,7 @@ type config struct {
Builder string `yaml:"builder"`
BuilderMap map[string]string `yaml:"builderMap"`
Env map[string]string `yaml:"env"`
Annotations map[string]string `yaml:"annotations"`
// Add new values to the toConfig/fromConfig functions.
}
@ -61,6 +62,7 @@ func fromConfig(c config) (f Function) {
Builder: c.Builder,
BuilderMap: c.BuilderMap,
Env: c.Env,
Annotations: c.Annotations,
}
}
@ -76,6 +78,7 @@ func toConfig(f Function) config {
Builder: f.Builder,
BuilderMap: f.BuilderMap,
Env: f.Env,
Annotations: f.Annotations,
}
}

View File

@ -53,6 +53,10 @@ type Function struct {
BuilderMap map[string]string
Env map[string]string
// Map containing user-supplied annotations
// Example: { "division": "finance" }
Annotations map[string]string
}
// NewFunction loads a Function from a path on disk. use .Initialized() to determine if

View File

@ -52,7 +52,7 @@ func (d *Deployer) Deploy(ctx context.Context, f bosonFunc.Function) (err error)
if d.Verbose {
fmt.Printf("Creating Knative Service: %v\n", f.Name)
}
service, err := generateNewService(f.Name, f.ImageWithDigest(), f.Runtime, f.Env)
service, err := generateNewService(f.Name, f.ImageWithDigest(), f.Runtime, f.Env, f.Annotations)
if err != nil {
err = fmt.Errorf("knative deployer failed to generate the service: %v", err)
return err
@ -86,7 +86,7 @@ func (d *Deployer) Deploy(ctx context.Context, f bosonFunc.Function) (err error)
}
} else {
// Update the existing Service
err = client.UpdateServiceWithRetry(f.Name, updateService(f.ImageWithDigest(), f.Env), 3)
err = client.UpdateServiceWithRetry(f.Name, updateService(f.ImageWithDigest(), f.Env, f.Annotations), 3)
if err != nil {
err = fmt.Errorf("knative deployer failed to update the service: %v", err)
return err
@ -114,7 +114,7 @@ func probeFor(url string) *corev1.Probe {
}
}
func generateNewService(name, image, runtime string, env map[string]string) (*servingv1.Service, error) {
func generateNewService(name, image, runtime string, env map[string]string, annotations map[string]string) (*servingv1.Service, error) {
containers := []corev1.Container{
{
Image: image,
@ -133,6 +133,7 @@ func generateNewService(name, image, runtime string, env map[string]string) (*se
"boson.dev/function": "true",
"boson.dev/runtime": runtime,
},
Annotations: annotations,
},
Spec: v1.ServiceSpec{
ConfigurationSpec: v1.ConfigurationSpec{
@ -150,12 +151,18 @@ func generateNewService(name, image, runtime string, env map[string]string) (*se
return setEnv(service, env)
}
func updateService(image string, env map[string]string) func(service *servingv1.Service) (*servingv1.Service, error) {
func updateService(image string, env map[string]string, annotations map[string]string) func(service *servingv1.Service) (*servingv1.Service, error) {
return func(service *servingv1.Service) (*servingv1.Service, error) {
// Removing the name so the k8s server can fill it in with generated name,
// this prevents conflicts in Revision name when updating the KService from multiple places.
service.Spec.Template.Name = ""
// Don't bother being as clever as we are with env variables
// Just set the annotations to be whatever we find in func.yaml
for k, v := range annotations {
service.ObjectMeta.Annotations[k] = v
}
err := flags.UpdateImage(&service.Spec.Template.Spec.PodSpec, image)
if err != nil {
return service, err

File diff suppressed because one or more lines are too long