1
0
Fork 0
mirror of https://github.com/external-secrets/external-secrets.git synced 2024-12-14 11:57:59 +00:00
external-secrets/pkg/controllers/externalsecret/externalsecret_controller_template.go
Gergely Brautigam d6e24a82bd
feat: add templating to PushSecret (#2926)
* feat: add templating to PushSecret

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

* adding unit tests around templating basic concepts and verifying output

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

* extracting some of the common functions of the parser

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

* remove some more duplication

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

* removed commented out code segment

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

* added documentation for templating feature

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

* simplified the templating for annotations and labels

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

---------

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
2023-12-22 21:45:34 +01:00

126 lines
4 KiB
Go

/*
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 externalsecret
import (
"context"
"fmt"
v1 "k8s.io/api/core/v1"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
"github.com/external-secrets/external-secrets/pkg/controllers/templating"
_ "github.com/external-secrets/external-secrets/pkg/provider/register" // Loading registered providers.
"github.com/external-secrets/external-secrets/pkg/template"
"github.com/external-secrets/external-secrets/pkg/utils"
)
// merge template in the following order:
// * template.Data (highest precedence)
// * template.templateFrom
// * secret via es.data or es.dataFrom.
func (r *Reconciler) applyTemplate(ctx context.Context, es *esv1beta1.ExternalSecret, secret *v1.Secret, dataMap map[string][]byte) error {
if err := setMetadata(secret, es); err != nil {
return err
}
// no template: copy data and return
if es.Spec.Target.Template == nil {
secret.Data = dataMap
return nil
}
// Merge Policy should merge secrets
if es.Spec.Target.Template.MergePolicy == esv1beta1.MergePolicyMerge {
for k, v := range dataMap {
secret.Data[k] = v
}
}
execute, err := template.EngineForVersion(es.Spec.Target.Template.EngineVersion)
if err != nil {
return err
}
p := templating.Parser{
Client: r.Client,
TargetSecret: secret,
DataMap: dataMap,
Exec: execute,
}
// apply templates defined in template.templateFrom
err = p.MergeTemplateFrom(ctx, es.Namespace, es.Spec.Target.Template)
if err != nil {
return fmt.Errorf(errFetchTplFrom, err)
}
// explicitly defined template.Data takes precedence over templateFrom
err = p.MergeMap(es.Spec.Target.Template.Data, esv1beta1.TemplateTargetData)
if err != nil {
return fmt.Errorf(errExecTpl, err)
}
// get template data for labels
err = p.MergeMap(es.Spec.Target.Template.Metadata.Labels, esv1beta1.TemplateTargetLabels)
if err != nil {
return fmt.Errorf(errExecTpl, err)
}
// get template data for annotations
err = p.MergeMap(es.Spec.Target.Template.Metadata.Annotations, esv1beta1.TemplateTargetAnnotations)
if err != nil {
return fmt.Errorf(errExecTpl, err)
}
// if no data was provided by template fallback
// to value from the provider
if len(es.Spec.Target.Template.Data) == 0 && len(es.Spec.Target.Template.TemplateFrom) == 0 {
secret.Data = dataMap
}
return nil
}
// setMetadata sets Labels and Annotations to the given secret.
func setMetadata(secret *v1.Secret, es *esv1beta1.ExternalSecret) error {
if secret.Labels == nil {
secret.Labels = make(map[string]string)
}
if secret.Annotations == nil {
secret.Annotations = make(map[string]string)
}
// Clean up Labels and Annotations added by the operator
// so that it won't leave outdated ones
labelKeys, err := templating.GetManagedLabelKeys(secret, es.Name)
if err != nil {
return err
}
for _, key := range labelKeys {
delete(secret.ObjectMeta.Labels, key)
}
annotationKeys, err := templating.GetManagedAnnotationKeys(secret, es.Name)
if err != nil {
return err
}
for _, key := range annotationKeys {
delete(secret.ObjectMeta.Annotations, key)
}
if es.Spec.Target.Template == nil {
utils.MergeStringMap(secret.ObjectMeta.Labels, es.ObjectMeta.Labels)
utils.MergeStringMap(secret.ObjectMeta.Annotations, es.ObjectMeta.Annotations)
return nil
}
secret.Type = es.Spec.Target.Template.Type
utils.MergeStringMap(secret.ObjectMeta.Labels, es.Spec.Target.Template.Metadata.Labels)
utils.MergeStringMap(secret.ObjectMeta.Annotations, es.Spec.Target.Template.Metadata.Annotations)
return nil
}