in pkg/trait/gc.go [245:330]
func (t *gcTrait) getDeletableTypes(e *Environment) (map[schema.GroupVersionKind]struct{}, error) {
lock.Lock()
defer lock.Unlock()
// Return a fresh map even when returning cached collectables
GVKs := make(map[schema.GroupVersionKind]struct{})
// Rate limit to avoid Discovery and SelfSubjectRulesReview requests at every reconciliation.
if !rateLimiter.Allow() {
// Return the cached set of garbage collectable GVKs.
maps.Copy(GVKs, collectableGVKs)
return GVKs, nil
}
// We rely on the discovery API to retrieve all the resources GVK,
// that results in an unbounded set that can impact garbage collection latency when scaling up.
resources, err := t.Client.Discovery().ServerPreferredNamespacedResources()
// Swallow group discovery errors, e.g., Knative serving exposes
// an aggregated API for custom.metrics.k8s.io that requires special
// authentication scheme while discovering preferred resources.
if err != nil && !discovery.IsGroupDiscoveryFailedError(err) {
return nil, err
}
// We only take types that support the "delete" verb,
// to prevents from performing queries that we know are going to return "MethodNotAllowed".
APIResourceLists := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"delete"}}, resources)
// Retrieve the permissions granted to the operator service account.
// We assume the operator has only to garbage collect the resources it has created.
ssrr := &authorization.SelfSubjectRulesReview{
Spec: authorization.SelfSubjectRulesReviewSpec{
Namespace: e.Integration.Namespace,
},
}
ssrr, err = e.Client.AuthorizationV1().SelfSubjectRulesReviews().Create(e.Ctx, ssrr, metav1.CreateOptions{})
if err != nil {
return nil, err
}
for _, APIResourceList := range APIResourceLists {
for _, resource := range APIResourceList.APIResources {
resourceGroup := resource.Group
if resourceGroup == "" {
// Empty implies the group of the containing resource list should be used
gv, err := schema.ParseGroupVersion(APIResourceList.GroupVersion)
if err != nil {
return nil, err
}
resourceGroup = gv.Group
}
rule:
for _, rule := range ssrr.Status.ResourceRules {
if !util.StringSliceContainsAnyOf(rule.Verbs, "delete", "*") {
continue
}
for _, ruleGroup := range rule.APIGroups {
for _, ruleResource := range rule.Resources {
if (resourceGroup == ruleGroup || ruleGroup == "*") && (resource.Name == ruleResource || ruleResource == "*") {
GVK := schema.FromAPIVersionAndKind(APIResourceList.GroupVersion, resource.Kind)
GVKs[GVK] = struct{}{}
break rule
}
}
}
}
}
}
if len(GVKs) == 0 {
// Auto discovery of deletable types has no results (probably an error)
// Make sure to at least use a minimal set of deletable types for garbage collection
t.L.ForIntegration(e.Integration).Debugf("Auto discovery of deletable types returned no results. " +
"Using default minimal set of deletable types for garbage collection")
maps.Copy(GVKs, defaultDeletableTypes)
}
collectableGVKs = make(map[schema.GroupVersionKind]struct{})
maps.Copy(collectableGVKs, GVKs)
for gvk := range GVKs {
log.Debugf("Found deletable type: %s", gvk.String())
}
return GVKs, nil
}