@@ -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
159162func (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+
174245func calculateSyncState (diffResult * provider.DiffListResult , commit string , dt * sdk.DeployTarget [kubeconfig.KubernetesDeployTargetConfig ]) sdk.ApplicationSyncState {
175246 if diffResult .NoChanges () {
176247 return sdk.ApplicationSyncState {
0 commit comments