Skip to content

Commit

Permalink
(feat): track full diff for resources
Browse files Browse the repository at this point in the history
When in DryRun mode, Sveltos creates a ClusterReport containing the
list of changes compared to current configuration.
For raw Kubernetes resources this includes listing:
1. resources that would be created
2. resources that would be deleted
3. resources that would be updated

Sveltos now provides a more granular view of proposed changes during Dry Run mode
for updates. A detailed diff highlighting exact changes, such as added, modified,
or removed fields.

Example:

```yaml
    resourceReports:
    - action: Update
      message: |
        --- ClusterPolicy disallow-latest-tag
        +++ ClusterPolicy disallow-latest-tag
        @@ -49,7 +49,7 @@
                       name: validate-image-tag
                       skipBackgroundRequests: true
                       validate:
        -                message: Using a mutable image tag e.g. 'latest' is not allowed.
        +                message: Using a mutable image tag e.g. 'latest' is not allowed in produdction clusters.
                         pattern:
                             spec:
```
  • Loading branch information
mgianluc committed Nov 29, 2024
1 parent 3a20854 commit 9487bb8
Show file tree
Hide file tree
Showing 22 changed files with 277 additions and 137 deletions.
1 change: 1 addition & 0 deletions api/v1beta1/clustersummary_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ type ClusterSummaryStatus struct {
// +kubebuilder:resource:path=clustersummaries,scope=Namespaced
// +kubebuilder:subresource:status
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of ClusterSummary"
// +kubebuilder:printcolumn:name="HelmCharts",type="string",JSONPath=".status.featureSummaries[?(@.featureID==\"Helm\")].status",description="Indicates whether HelmCharts are all provisioned",priority=2
// +kubebuilder:printcolumn:name="KustomizeRefs",type="string",JSONPath=".status.featureSummaries[?(@.featureID==\"Kustomize\")].status",description="Indicates whether KustomizeRefs are all provisioned",priority=2
// +kubebuilder:printcolumn:name="PolicyRefs",type="string",JSONPath=".status.featureSummaries[?(@.featureID==\"Resources\")].status",description="Indicates whether PolicyRefs are all provisioned",priority=2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,10 @@ spec:
subresources:
status: {}
- additionalPrinterColumns:
- description: Time duration since creation of ClusterSummary
jsonPath: .metadata.creationTimestamp
name: Age
type: date
- description: Indicates whether HelmCharts are all provisioned
jsonPath: .status.featureSummaries[?(@.featureID=="Helm")].status
name: HelmCharts
Expand Down
4 changes: 3 additions & 1 deletion controllers/clustercache/cluster_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ var _ = Describe("Clustercache", func() {
Expect(cacheMgr.GetConfigFromMap(clusterObj)).To(BeNil())
Expect(cacheMgr.GetSecretForCluster(clusterObj)).To(BeNil())
Expect(cacheMgr.GetClusterFromSecret(secretObj)).To(BeNil())

})

It("RemoveSecret removes entries for all clusters using the modified secret", func() {
Expand Down Expand Up @@ -136,9 +135,12 @@ func createClusterResources(cluster *libsveltosv1beta1.SveltosCluster) *corev1.S
}

Expect(testEnv.Create(context.TODO(), ns)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv.Client, ns)).To(Succeed())

Expect(testEnv.Create(context.TODO(), cluster)).To(Succeed())
Expect(testEnv.Create(context.TODO(), secret)).To(Succeed())

Expect(waitForObject(context.TODO(), testEnv.Client, cluster)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv.Client, secret)).To(Succeed())
return secret
}
4 changes: 2 additions & 2 deletions controllers/clustercache/clustercache_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import (
"github.com/projectsveltos/addon-controller/internal/test/helpers"
libsveltosv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1"
libsveltoscrd "github.com/projectsveltos/libsveltos/lib/crd"
"github.com/projectsveltos/libsveltos/lib/utils"
"github.com/projectsveltos/libsveltos/lib/k8s_utils"
)

var (
Expand Down Expand Up @@ -95,7 +95,7 @@ var _ = BeforeSuite(func() {
}()

var sveltosCRD *unstructured.Unstructured
sveltosCRD, err = utils.GetUnstructured(libsveltoscrd.GetSveltosClusterCRDYAML())
sveltosCRD, err = k8s_utils.GetUnstructured(libsveltoscrd.GetSveltosClusterCRDYAML())
Expect(err).To(BeNil())
Expect(testEnv.Create(context.TODO(), sveltosCRD)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv, sveltosCRD)).To(Succeed())
Expand Down
2 changes: 1 addition & 1 deletion controllers/clustersummary_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ func (r *ClusterSummaryReconciler) reconcileNormal(
err = r.removeResourceSummary(ctx, clusterSummaryScope, logger)
if err != nil {
logger.V(logs.LogInfo).Error(err, "failed to remove ResourceSummary.")
return reconcile.Result{Requeue: true, RequeueAfter: deleteRequeueAfter}, nil
return reconcile.Result{Requeue: true, RequeueAfter: normalRequeueAfter}, nil
}
}

Expand Down
14 changes: 7 additions & 7 deletions controllers/controllers_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ import (
"github.com/projectsveltos/libsveltos/lib/clusterproxy"
libsveltoscrd "github.com/projectsveltos/libsveltos/lib/crd"
"github.com/projectsveltos/libsveltos/lib/deployer"
"github.com/projectsveltos/libsveltos/lib/k8s_utils"
libsveltosset "github.com/projectsveltos/libsveltos/lib/set"
"github.com/projectsveltos/libsveltos/lib/utils"
)

var (
Expand Down Expand Up @@ -92,37 +92,37 @@ var _ = BeforeSuite(func() {
}()

var sveltosCRD *unstructured.Unstructured
sveltosCRD, err = utils.GetUnstructured(libsveltoscrd.GetSveltosClusterCRDYAML())
sveltosCRD, err = k8s_utils.GetUnstructured(libsveltoscrd.GetSveltosClusterCRDYAML())
Expect(err).To(BeNil())
Expect(testEnv.Create(context.TODO(), sveltosCRD)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv, sveltosCRD)).To(Succeed())

var resourceSummaryCRD *unstructured.Unstructured
resourceSummaryCRD, err = utils.GetUnstructured(libsveltoscrd.GetResourceSummaryCRDYAML())
resourceSummaryCRD, err = k8s_utils.GetUnstructured(libsveltoscrd.GetResourceSummaryCRDYAML())
Expect(err).To(BeNil())
Expect(testEnv.Create(context.TODO(), resourceSummaryCRD)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv, resourceSummaryCRD)).To(Succeed())

var dcCRD *unstructured.Unstructured
dcCRD, err = utils.GetUnstructured(libsveltoscrd.GetDebuggingConfigurationCRDYAML())
dcCRD, err = k8s_utils.GetUnstructured(libsveltoscrd.GetDebuggingConfigurationCRDYAML())
Expect(err).To(BeNil())
Expect(testEnv.Create(context.TODO(), dcCRD)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv, dcCRD)).To(Succeed())

var reloaderCRD *unstructured.Unstructured
reloaderCRD, err = utils.GetUnstructured(libsveltoscrd.GetReloaderCRDYAML())
reloaderCRD, err = k8s_utils.GetUnstructured(libsveltoscrd.GetReloaderCRDYAML())
Expect(err).To(BeNil())
Expect(testEnv.Create(context.TODO(), reloaderCRD)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv, reloaderCRD)).To(Succeed())

var setCRD *unstructured.Unstructured
setCRD, err = utils.GetUnstructured(libsveltoscrd.GetSetCRDYAML())
setCRD, err = k8s_utils.GetUnstructured(libsveltoscrd.GetSetCRDYAML())
Expect(err).To(BeNil())
Expect(testEnv.Create(context.TODO(), setCRD)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv, setCRD)).To(Succeed())

var clusterSetCRD *unstructured.Unstructured
clusterSetCRD, err = utils.GetUnstructured(libsveltoscrd.GetClusterSetCRDYAML())
clusterSetCRD, err = k8s_utils.GetUnstructured(libsveltoscrd.GetClusterSetCRDYAML())
Expect(err).To(BeNil())
Expect(testEnv.Create(context.TODO(), clusterSetCRD)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv, clusterSetCRD)).To(Succeed())
Expand Down
10 changes: 5 additions & 5 deletions controllers/handlers_helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ import (
libsveltosv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1"
"github.com/projectsveltos/libsveltos/lib/clusterproxy"
"github.com/projectsveltos/libsveltos/lib/deployer"
"github.com/projectsveltos/libsveltos/lib/k8s_utils"
logs "github.com/projectsveltos/libsveltos/lib/logsettings"
"github.com/projectsveltos/libsveltos/lib/patcher"
libsveltostemplate "github.com/projectsveltos/libsveltos/lib/template"
"github.com/projectsveltos/libsveltos/lib/utils"
)

var (
Expand Down Expand Up @@ -1186,7 +1186,7 @@ func upgradeCRDs(ctx context.Context, requestedChart *configv1beta1.HelmChart, k
return err
}

dr, err := utils.GetDynamicResourceInterface(destConfig, apiextensionsv1.SchemeGroupVersion.WithKind("CustomResourceDefinition"), "")
dr, err := k8s_utils.GetDynamicResourceInterface(destConfig, apiextensionsv1.SchemeGroupVersion.WithKind("CustomResourceDefinition"), "")
if err != nil {
return err
}
Expand Down Expand Up @@ -1933,7 +1933,7 @@ func collectHelmContent(manifest string, logger logr.Logger) ([]*unstructured.Un
resources := make([]*unstructured.Unstructured, 0, len(elements))

for i := range elements {
policy, err := utils.GetUnstructured([]byte(elements[i]))
policy, err := k8s_utils.GetUnstructured([]byte(elements[i]))
if err != nil {
logger.Error(err, fmt.Sprintf("failed to get policy from Data %.100s", elements[i]))
return nil, err
Expand Down Expand Up @@ -2350,15 +2350,15 @@ func addExtraMetadata(ctx context.Context, requestedChart *configv1beta1.HelmCha
}

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

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

err = updateResource(ctx, dr, clusterSummary, r, []string{}, logger)
_, err = updateResource(ctx, dr, clusterSummary, r, []string{}, 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))
Expand Down
4 changes: 2 additions & 2 deletions controllers/handlers_kustomize.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ import (
"github.com/projectsveltos/libsveltos/lib/clusterproxy"
"github.com/projectsveltos/libsveltos/lib/deployer"
"github.com/projectsveltos/libsveltos/lib/funcmap"
"github.com/projectsveltos/libsveltos/lib/k8s_utils"
logs "github.com/projectsveltos/libsveltos/lib/logsettings"
libsveltostemplate "github.com/projectsveltos/libsveltos/lib/template"
"github.com/projectsveltos/libsveltos/lib/utils"
)

const (
Expand Down Expand Up @@ -663,7 +663,7 @@ func getKustomizedResources(ctx context.Context, c client.Client, clusterSummary
}

var u *unstructured.Unstructured
u, err = utils.GetUnstructured(yaml)
u, err = k8s_utils.GetUnstructured(yaml)
if err != nil {
logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to get unstructured %v", err))
return nil, nil, nil, err
Expand Down
1 change: 0 additions & 1 deletion controllers/handlers_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,6 @@ func updateClusterReportWithResourceReports(ctx context.Context, c client.Client
} else if featureID == configv1beta1.FeatureKustomize {
clusterReport.Status.KustomizeResourceReports = resourceReports
}

return c.Status().Update(ctx, clusterReport)
})
return err
Expand Down
Loading

0 comments on commit 9487bb8

Please sign in to comment.