Skip to content

Commit e9d8065

Browse files
[Multi_K8s-Plugin] Fix livestate drift detection and resource filtering (#6673)
* Implement livestate drift detection ignore and include/exclude resource filtering Signed-off-by: Mohammed Firdous <124298708+mohammedfirdouss@users.noreply.github.com> * Fix gofmt formatting in provider/kubernetes.go Signed-off-by: Mohammed Firdous <124298708+mohammedfirdouss@users.noreply.github.com> --------- Signed-off-by: Mohammed Firdous <124298708+mohammedfirdouss@users.noreply.github.com> Co-authored-by: Khanh Tran <32532742+khanhtc1202@users.noreply.github.com>
1 parent 366de96 commit e9d8065

3 files changed

Lines changed: 104 additions & 8 deletions

File tree

pkg/app/pipedv1/plugin/kubernetes_multicluster/config/application.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,28 @@ type KubernetesDeployTargetConfig struct {
138138
KubeConfigPath string `json:"kubeConfigPath,omitempty"`
139139
// Version of kubectl will be used.
140140
KubectlVersion string `json:"kubectlVersion"`
141+
// Configuration for application resource informer.
142+
AppStateInformer KubernetesAppStateInformer `json:"appStateInformer"`
143+
}
144+
145+
// KubernetesAppStateInformer represents the configuration for application resource informer.
146+
type KubernetesAppStateInformer struct {
147+
// Only watches the specified namespace.
148+
// Empty means watching all namespaces.
149+
Namespace string `json:"namespace,omitempty"`
150+
// List of resources that should be added to the watching targets.
151+
IncludeResources []KubernetesResourceMatcher `json:"includeResources,omitempty"`
152+
// List of resources that should be ignored from the watching targets.
153+
ExcludeResources []KubernetesResourceMatcher `json:"excludeResources,omitempty"`
154+
}
155+
156+
// KubernetesResourceMatcher represents the matcher for a Kubernetes resource.
157+
type KubernetesResourceMatcher struct {
158+
// The APIVersion of the kubernetes resource.
159+
APIVersion string `json:"apiVersion,omitempty"`
160+
// The kind name of the kubernetes resource.
161+
// Empty means all kinds are matching.
162+
Kind string `json:"kind,omitempty"`
141163
}
142164

143165
// K8sSyncStageOptions contains all configurable values for a K8S_SYNC stage.

pkg/app/pipedv1/plugin/kubernetes_multicluster/livestate/plugin.go

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,17 @@ func (p Plugin) GetLivestate(ctx context.Context, _ *sdk.ConfigNone, deployTarge
9595
// Create the kubectl wrapper for the target cluster.
9696
kubectl := provider.NewKubectl(kubectlPath)
9797

98-
// TODO: We need to implement including/excluding resources.
99-
// ref; https://pipecd.dev/docs-v0.50.x/user-guide/managing-piped/configuration-reference/#kubernetesappstateinformer
10098
namespacedLiveResources, clusterScopedLiveResources, err := provider.GetLiveResources(ctx, kubectl, tc.deployTarget.Config.KubeConfigPath, input.Request.ApplicationID)
10199
if err != nil {
102100
input.Logger.Error("Failed to get live resources", zap.Error(err))
103101
return nil, err
104102
}
105103

104+
// Filter live resources by include/exclude rules from the deploy target's AppStateInformer config.
105+
informer := tc.deployTarget.Config.AppStateInformer
106+
namespacedLiveResources = filterByAppStateInformer(namespacedLiveResources, informer)
107+
clusterScopedLiveResources = filterByAppStateInformer(clusterScopedLiveResources, informer)
108+
106109
liveState := p.makeAppLivestate(namespacedLiveResources, clusterScopedLiveResources, tc.deployTarget)
107110
liveStates = append(liveStates, liveState)
108111

@@ -157,9 +160,11 @@ func (p Plugin) makeAppLivestate(namespacedLiveResources, clusterScopedLiveResou
157160
}
158161

159162
func (p Plugin) makeAppSyncState(liveManifests, gitManifests []provider.Manifest, dt *sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig], commit string, logger *zap.Logger) (sdk.ApplicationSyncState, error) {
160-
// Calculate SyncState by comparing live manifests with desired manifests
161-
// TODO: Implement drift detection ignore configs
162-
diffResult, err := provider.DiffList(liveManifests, gitManifests, logger,
163+
// Filter out resources annotated to be ignored from drift detection.
164+
diffResult, err := provider.DiffList(
165+
filterIgnoringManifests(liveManifests),
166+
filterIgnoringManifests(gitManifests),
167+
logger,
163168
diff.WithEquateEmpty(),
164169
diff.WithIgnoreAddingMapKeys(),
165170
diff.WithCompareNumberAndNumericString(),
@@ -171,6 +176,72 @@ func (p Plugin) makeAppSyncState(liveManifests, gitManifests []provider.Manifest
171176
return calculateSyncState(diffResult, commit, dt), nil
172177
}
173178

179+
// filterIgnoringManifests removes manifests that are annotated to be excluded from drift detection.
180+
// Resources with the annotation pipecd.dev/ignore-drift-detection=true are skipped.
181+
func filterIgnoringManifests(manifests []provider.Manifest) []provider.Manifest {
182+
out := make([]provider.Manifest, 0, len(manifests))
183+
for _, m := range manifests {
184+
if m.GetAnnotations()[provider.LabelIgnoreDriftDirection] == provider.IgnoreDriftDetectionTrue {
185+
continue
186+
}
187+
out = append(out, m)
188+
}
189+
return out
190+
}
191+
192+
// filterByAppStateInformer filters live resources based on include/exclude rules
193+
// from the deploy target's AppStateInformer config.
194+
// If IncludeResources is set, only resources matching at least one entry are kept.
195+
// If ExcludeResources is set, resources matching any entry are removed.
196+
// If neither is set, all resources are returned unchanged.
197+
func filterByAppStateInformer(manifests []provider.Manifest, informer kubeconfig.KubernetesAppStateInformer) []provider.Manifest {
198+
if len(informer.IncludeResources) == 0 && len(informer.ExcludeResources) == 0 {
199+
return manifests
200+
}
201+
202+
out := make([]provider.Manifest, 0, len(manifests))
203+
for _, m := range manifests {
204+
if len(informer.IncludeResources) > 0 {
205+
included := false
206+
for _, matcher := range informer.IncludeResources {
207+
if matchesResourceMatcher(m, matcher) {
208+
included = true
209+
break
210+
}
211+
}
212+
if !included {
213+
continue
214+
}
215+
}
216+
217+
excluded := false
218+
for _, matcher := range informer.ExcludeResources {
219+
if matchesResourceMatcher(m, matcher) {
220+
excluded = true
221+
break
222+
}
223+
}
224+
if excluded {
225+
continue
226+
}
227+
228+
out = append(out, m)
229+
}
230+
return out
231+
}
232+
233+
// matchesResourceMatcher returns true if the manifest matches the given resource matcher.
234+
// An empty APIVersion or Kind in the matcher acts as a wildcard for that field.
235+
func matchesResourceMatcher(m provider.Manifest, matcher kubeconfig.KubernetesResourceMatcher) bool {
236+
if matcher.APIVersion != "" && m.APIVersion() != matcher.APIVersion {
237+
return false
238+
}
239+
if matcher.Kind != "" && m.Kind() != matcher.Kind {
240+
return false
241+
}
242+
return true
243+
}
244+
174245
func calculateSyncState(diffResult *provider.DiffListResult, commit string, dt *sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig]) sdk.ApplicationSyncState {
175246
if diffResult.NoChanges() {
176247
return sdk.ApplicationSyncState{

pkg/app/pipedv1/plugin/kubernetes_multicluster/provider/kubernetes.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ const (
3636
AnnotationOrder = "pipecd.dev/order" // The order number of resource used to sort them before using.
3737
AnnotationConfigHash = "pipecd.dev/config-hash" // The hash value of all mouting config resources.
3838

39+
LabelIgnoreDriftDirection = "pipecd.dev/ignore-drift-detection" // Whether the drift detection should ignore this resource.
40+
3941
// label/annotation values
40-
ManagedByPiped = "piped"
41-
UseReplaceEnabled = "enabled"
42-
UseServerSideApply = "true"
42+
ManagedByPiped = "piped"
43+
UseReplaceEnabled = "enabled"
44+
UseServerSideApply = "true"
45+
IgnoreDriftDetectionTrue = "true"
4346
)

0 commit comments

Comments
 (0)