Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional Labels and Annotations #458

Merged
merged 1 commit into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions api/v1alpha1/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,4 +420,22 @@ type Spec struct {
// the managed cluster to validate the state of those add-ons/applications
// is healthy
ValidateHealths []ValidateHealth `json:"validateHealths,omitempty"`

// ExtraLabels: These labels will be added by Sveltos to all Kubernetes resources deployed in
// a managed cluster based on this ClusterProfile/Profile instance.
// **Important:** If a resource deployed by Sveltos already has a label with a key present in
// `ExtraLabels`, the value from `ExtraLabels` will override the existing value.
// **Important:** ExtraLabels do not trigger a reconciliation. Changing ExtraLabels after resources
// are deployed won't trigegr Sveltos to redeploy those
// +optional
ExtraLabels map[string]string `json:"extraLabels,omitempty"`

// ExtraAnnotations: These annotations will be added by Sveltos to all Kubernetes resources
// deployed in a managed cluster based on this ClusterProfile/Profile instance.
// **Important:** If a resource deployed by Sveltos already has a annotation with a key present in
// `ExtraAnnotations`, the value from `ExtraAnnotations` will override the existing value.
// **Important:** ExtraAnnotations do not trigger a reconciliation. Changing ExtraAnnotations after
// resources are deployed won't trigegr Sveltos to redeploy those
// +optional
ExtraAnnotations map[string]string `json:"extraAnnotations,omitempty"`
}
14 changes: 14 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions config/crd/bases/config.projectsveltos.io_clusterprofiles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,30 @@ spec:
items:
type: string
type: array
extraAnnotations:
additionalProperties:
type: string
description: 'ExtraAnnotations: These annotations will be added by
Sveltos to all Kubernetes resources deployed in a managed cluster
based on this ClusterProfile/Profile instance. **Important:** If
a resource deployed by Sveltos already has a annotation with a key
present in `ExtraAnnotations`, the value from `ExtraAnnotations`
will override the existing value. **Important:** ExtraAnnotations
do not trigger a reconciliation. Changing ExtraAnnotations after
resources are deployed won''t trigegr Sveltos to redeploy those'
type: object
extraLabels:
additionalProperties:
type: string
description: 'ExtraLabels: These labels will be added by Sveltos to
all Kubernetes resources deployed in a managed cluster based on
this ClusterProfile/Profile instance. **Important:** If a resource
deployed by Sveltos already has a label with a key present in `ExtraLabels`,
the value from `ExtraLabels` will override the existing value. **Important:**
ExtraLabels do not trigger a reconciliation. Changing ExtraLabels
after resources are deployed won''t trigegr Sveltos to redeploy
those'
type: object
helmCharts:
description: Helm charts is a list of helm charts that need to be
deployed
Expand Down
24 changes: 24 additions & 0 deletions config/crd/bases/config.projectsveltos.io_clustersummaries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,30 @@ spec:
items:
type: string
type: array
extraAnnotations:
additionalProperties:
type: string
description: 'ExtraAnnotations: These annotations will be added
by Sveltos to all Kubernetes resources deployed in a managed
cluster based on this ClusterProfile/Profile instance. **Important:**
If a resource deployed by Sveltos already has a annotation with
a key present in `ExtraAnnotations`, the value from `ExtraAnnotations`
will override the existing value. **Important:** ExtraAnnotations
do not trigger a reconciliation. Changing ExtraAnnotations after
resources are deployed won''t trigegr Sveltos to redeploy those'
type: object
extraLabels:
additionalProperties:
type: string
description: 'ExtraLabels: These labels will be added by Sveltos
to all Kubernetes resources deployed in a managed cluster based
on this ClusterProfile/Profile instance. **Important:** If a
resource deployed by Sveltos already has a label with a key
present in `ExtraLabels`, the value from `ExtraLabels` will
override the existing value. **Important:** ExtraLabels do not
trigger a reconciliation. Changing ExtraLabels after resources
are deployed won''t trigegr Sveltos to redeploy those'
type: object
helmCharts:
description: Helm charts is a list of helm charts that need to
be deployed
Expand Down
24 changes: 24 additions & 0 deletions config/crd/bases/config.projectsveltos.io_profiles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,30 @@ spec:
items:
type: string
type: array
extraAnnotations:
additionalProperties:
type: string
description: 'ExtraAnnotations: These annotations will be added by
Sveltos to all Kubernetes resources deployed in a managed cluster
based on this ClusterProfile/Profile instance. **Important:** If
a resource deployed by Sveltos already has a annotation with a key
present in `ExtraAnnotations`, the value from `ExtraAnnotations`
will override the existing value. **Important:** ExtraAnnotations
do not trigger a reconciliation. Changing ExtraAnnotations after
resources are deployed won''t trigegr Sveltos to redeploy those'
type: object
extraLabels:
additionalProperties:
type: string
description: 'ExtraLabels: These labels will be added by Sveltos to
all Kubernetes resources deployed in a managed cluster based on
this ClusterProfile/Profile instance. **Important:** If a resource
deployed by Sveltos already has a label with a key present in `ExtraLabels`,
the value from `ExtraLabels` will override the existing value. **Important:**
ExtraLabels do not trigger a reconciliation. Changing ExtraLabels
after resources are deployed won''t trigegr Sveltos to redeploy
those'
type: object
helmCharts:
description: Helm charts is a list of helm charts that need to be
deployed
Expand Down
3 changes: 3 additions & 0 deletions controllers/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ var (
GetReferenceResourceNamespace = getReferenceResourceNamespace
ReadFiles = readFiles

AddExtraLabels = addExtraLabels
AddExtraAnnotations = addExtraAnnotations

ResourcesHash = resourcesHash
GetResourceRefs = getResourceRefs

Expand Down
62 changes: 62 additions & 0 deletions controllers/handlers_helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/retry"
"k8s.io/klog/v2/textlogger"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -1039,6 +1041,11 @@ func doInstallRelease(ctx context.Context, clusterSummary *configv1alpha1.Cluste
return err
}

if clusterSummary.Spec.ClusterProfileSpec.ExtraLabels != nil ||
clusterSummary.Spec.ClusterProfileSpec.ExtraAnnotations != nil {

return addExtraMetadata(ctx, requestedChart, clusterSummary, kubeconfig, logger)
}
return nil
}

Expand Down Expand Up @@ -1096,6 +1103,12 @@ func doUpgradeRelease(ctx context.Context, clusterSummary *configv1alpha1.Cluste
return err
}

if clusterSummary.Spec.ClusterProfileSpec.ExtraLabels != nil ||
clusterSummary.Spec.ClusterProfileSpec.ExtraAnnotations != nil {

return addExtraMetadata(ctx, requestedChart, clusterSummary, kubeconfig, logger)
}

return nil
}

Expand Down Expand Up @@ -1636,3 +1649,52 @@ func getHelmUpgradeClient(requestedChart *configv1alpha1.HelmChart, actionConfig

return upgradeClient, nil
}

func addExtraMetadata(ctx context.Context, requestedChart *configv1alpha1.HelmChart,
clusterSummary *configv1alpha1.ClusterSummary, kubeconfig string, logger logr.Logger) error {

actionConfig, err := actionConfigInit(requestedChart.ReleaseNamespace, kubeconfig)
if err != nil {
return err
}

statusObject := action.NewStatus(actionConfig)
results, err := statusObject.Run(requestedChart.ReleaseName)
if err != nil {
return err
}

resources, err := collectHelmContent(results.Manifest, logger)
if err != nil {
return err
}

config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
logger.Error(err, "BuildConfigFromFlags")
return err
}

logger.V(logs.LogDebug).Info("adding extra labels/annotations to %d resources", len(resources))
for i := range resources {
r := resources[i]

var dr dynamic.ResourceInterface
dr, err = utils.GetDynamicResourceInterface(config, r.GroupVersionKind(), r.GetNamespace())
if err != nil {
return err
}

addExtraLabels(r, clusterSummary.Spec.ClusterProfileSpec.ExtraLabels)
addExtraAnnotations(r, clusterSummary.Spec.ClusterProfileSpec.ExtraAnnotations)

err = updateResource(ctx, dr, clusterSummary, r, logger)
if err != nil {
logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to update resource %s %s/%s: %v",
r.GetKind(), r.GetNamespace(), r.GetName(), err))
return err
}
}

return nil
}
49 changes: 49 additions & 0 deletions controllers/handlers_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ func deployUnstructured(ctx context.Context, deployingToMgmtCluster bool, destCo

deployer.AddOwnerReference(policy, profile)

addExtraLabels(policy, clusterSummary.Spec.ClusterProfileSpec.ExtraLabels)
addExtraAnnotations(policy, clusterSummary.Spec.ClusterProfileSpec.ExtraAnnotations)

if deployingToMgmtCluster {
// When deploying resources in the management cluster, just setting ClusterProfile as OwnerReference is
// not enough. We also need to track which ClusterSummary is creating the resource. Otherwise while
Expand Down Expand Up @@ -340,6 +343,52 @@ func deployUnstructured(ctx context.Context, deployingToMgmtCluster bool, destCo
return reports, nil
}

// addExtraLabels adds ExtraLabels to policy.
// If policy already has a label with a key present in `ExtraLabels`, the value from `ExtraLabels` will
// override the existing value.
func addExtraLabels(policy *unstructured.Unstructured, extraLabels map[string]string) {
if extraLabels == nil {
return
}

if len(extraLabels) == 0 {
return
}

lbls := policy.GetLabels()
if lbls == nil {
lbls = map[string]string{}
}
for k := range extraLabels {
lbls[k] = extraLabels[k]
}

policy.SetLabels(lbls)
}

// addExtraAnnotations adds ExtraAnnotations to policy.
// If policy already has an annotation with a key present in `ExtraAnnotations`, the value from `ExtraAnnotations`
// will override the existing value.
func addExtraAnnotations(policy *unstructured.Unstructured, extraAnnotations map[string]string) {
if extraAnnotations == nil {
return
}

if len(extraAnnotations) == 0 {
return
}

annotations := policy.GetAnnotations()
if annotations == nil {
annotations = map[string]string{}
}
for k := range extraAnnotations {
annotations[k] = extraAnnotations[k]
}

policy.SetAnnotations(annotations)
}

// getResource returns sveltos Resource and the resource hash hash
func getResource(policy *unstructured.Unstructured, referencedObject *corev1.ObjectReference,
featureID configv1alpha1.FeatureID, logger logr.Logger) (resource *configv1alpha1.Resource, policyHash string) {
Expand Down
56 changes: 56 additions & 0 deletions controllers/handlers_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,62 @@ var _ = Describe("HandlersUtils", func() {
Expect(controllers.CanDelete(depl, map[string]configv1alpha1.Resource{name: {}})).To(BeFalse())
})

It("addExtraLabels adds extra labels on unstructured", func() {
u := &unstructured.Unstructured{}
extraLabels := map[string]string{
randomString(): randomString(),
randomString(): randomString(),
}

controllers.AddExtraLabels(u, extraLabels)
labels := u.GetLabels()
Expect(labels).ToNot(BeNil())
for k := range extraLabels {
Expect(labels[k]).To(Equal(extraLabels[k]))
}

// Add extra labels again
extraLabels = map[string]string{
randomString(): randomString(),
randomString(): randomString(),
}

controllers.AddExtraLabels(u, extraLabels)
labels = u.GetLabels()
Expect(labels).ToNot(BeNil())
for k := range extraLabels {
Expect(labels[k]).To(Equal(extraLabels[k]))
}
})

It("addExtraAnnotations adds extra annotations on unstructured", func() {
u := &unstructured.Unstructured{}
extraAnnotations := map[string]string{
randomString(): randomString(),
randomString(): randomString(),
}

controllers.AddExtraAnnotations(u, extraAnnotations)
annotations := u.GetAnnotations()
Expect(annotations).ToNot(BeNil())
for k := range extraAnnotations {
Expect(annotations[k]).To(Equal(extraAnnotations[k]))
}

// Add extra annotations again
extraAnnotations = map[string]string{
randomString(): randomString(),
randomString(): randomString(),
}

controllers.AddExtraAnnotations(u, extraAnnotations)
annotations = u.GetAnnotations()
Expect(annotations).ToNot(BeNil())
for k := range extraAnnotations {
Expect(annotations[k]).To(Equal(extraAnnotations[k]))
}
})

It("readFiles loads content of all files in a directory", func() {
dir, err := os.MkdirTemp("", "my-temp-dir")
Expect(err).To(BeNil())
Expand Down
Loading