Skip to content
Open
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
38 changes: 38 additions & 0 deletions docs/gathered-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -1931,6 +1931,44 @@ None
4.21 - bugfix: pods with a status other than "Running" do not contain logs but were ignored


## RevisionedObjectCounts

collects revision counts for ConfigMap and Secret
objects with revision-based naming in specific namespaces.

It groups objects by base name (removing the -<number> suffix) and counts the
number of revisions per base name. This helps identify objects with excessive
historical revisions (>20 or >50) that may impact cluster performance and should
be cleaned up via a pruner.

Example output for openshift-kube-apiserver namespace:
- encryption-config: 590 revisions
- etcd-client: 608 revisions
- config: 609 revisions

The namespaces to monitor are defined in revisionedObjectNamespaces
and can be extended by modifying the const.go file.

### API Reference
- https://github.com/kubernetes/client-go/blob/master/kubernetes/typed/core/v1/configmap.go
- https://github.com/kubernetes/client-go/blob/master/kubernetes/typed/core/v1/secret.go

### Sample data
- [docs/insights-archive-sample/config/revisioned_objects.json](./insights-archive-sample/config/revisioned_objects.json)

### Location in archive
- `config/revisioned_objects.json`

### Config ID
`clusterconfig/revisioned_objects`

### Released version
- TBD

### Changes
None


## SAPConfig

Collects selected security context constraints
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"openshift-kube-apiserver": {
"configmaps": {
"bound-sa-token-signing-certs": 609,
"config": 609,
"etcd-serving-ca": 608,
"kube-apiserver-audit-policies": 608,
"kube-apiserver-cert-syncer-kubeconfig": 610,
"kube-apiserver-pod": 610,
"kube-apiserver-server-ca": 608,
"kubelet-serving-ca": 604,
"oauth-metadata": 608,
"sa-token-signing-certs": 608
},
"secrets": {
"encryption-config": 590,
"etcd-client": 608,
"localhost-recovery-client-token": 607,
"localhost-recovery-serving-certkey": 607,
"webhook-authenticator": 608
}
}
}
1 change: 1 addition & 0 deletions pkg/gatherers/clusterconfig/clusterconfig_gatherer.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var gatheringFunctions = map[string]gathererFuncPtr{
"pod_network_connectivity_checks": (*Gatherer).GatherPodNetworkConnectivityChecks,
"proxies": (*Gatherer).GatherClusterProxy,
"qemu_kubevirt_launcher_logs": (*Gatherer).GatherQEMUKubeVirtLauncherLogs,
"revisioned_objects": (*Gatherer).GatherRevisionedObjectCounts,
"sap_config": (*Gatherer).GatherSAPConfig,
"sap_datahubs": (*Gatherer).GatherSAPDatahubs,
"sap_pods": (*Gatherer).GatherSAPPods,
Expand Down
4 changes: 3 additions & 1 deletion pkg/gatherers/clusterconfig/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ var (
// logNodeMaxLines sets the maximum number of lines of the node log to be stored per node
logNodeMaxLines = 50

defaultNamespaces = []string{"default", "kube-system", "kube-public", "openshift"}
defaultNamespaces = []string{"default", "kube-system", "kube-public", "openshift"}
// Namespaces to monitor for revisioned ConfigMap and Secret objects counts.
revisionedObjectNamespaces = []string{"openshift-kube-apiserver"}
datahubGroupVersionResource = schema.GroupVersionResource{
Group: "installers.datahub.sap.com", Version: "v1alpha1", Resource: "datahubs",
}
Expand Down
135 changes: 135 additions & 0 deletions pkg/gatherers/clusterconfig/gather_revisioned_objects.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package clusterconfig

import (
"context"
"regexp"
"strings"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/klog/v2"

"github.com/openshift/insights-operator/pkg/record"
)

// Regex used to remove a trailing hyphen and number suffix (e.g., "-123" at the end of a string)
var revisionSuffixRegex = regexp.MustCompile(`-\d+$`)

// GatherRevisionedObjectCounts collects revision counts for ConfigMap and Secret
// objects with revision-based naming in specific namespaces.
//
// It groups objects by base name (removing the -<number> suffix) and counts the
// number of revisions per base name. This helps identify objects with excessive
// historical revisions (>20 or >50) that may impact cluster performance and should
// be cleaned up via a pruner.
//
// Example output for openshift-kube-apiserver namespace:
// - encryption-config: 590 revisions
// - etcd-client: 608 revisions
// - config: 609 revisions
//
// The namespaces to monitor are defined in revisionedObjectNamespaces
// and can be extended by modifying the const.go file.
//
// ### API Reference
// - https://github.com/kubernetes/client-go/blob/master/kubernetes/typed/core/v1/configmap.go
// - https://github.com/kubernetes/client-go/blob/master/kubernetes/typed/core/v1/secret.go
//
// ### Sample data
// - docs/insights-archive-sample/config/versioned_object_revision_counts.json
//
// ### Location in archive
// - `config/versioned_object_revision_counts.json`
//
// ### Config ID
// `clusterconfig/revisioned_objects`
//
// ### Released version
// - TBD
//
// ### Changes
// None
func (g *Gatherer) GatherRevisionedObjectCounts(ctx context.Context) ([]record.Record, []error) {
gatherKubeClient, err := kubernetes.NewForConfig(g.gatherProtoKubeConfig)
if err != nil {
return nil, []error{err}
}

return gatherRevisionedObjectCounts(ctx, gatherKubeClient.CoreV1())
}

func gatherRevisionedObjectCounts(ctx context.Context, coreClient corev1client.CoreV1Interface) ([]record.Record, []error) {
namespaceCounts := make(map[string]*NamespaceRevisionCounts)

for _, namespace := range revisionedObjectNamespaces {
nsCounts := &NamespaceRevisionCounts{
ConfigMaps: make(map[string]int),
Secrets: make(map[string]int),
}

// Gather ConfigMap counts
configMaps, err := coreClient.ConfigMaps(namespace).List(ctx, metav1.ListOptions{})
if err != nil {
klog.V(2).Infof("Unable to read ConfigMaps in namespace %s: %v", namespace, err)
} else {
for i := range configMaps.Items {
cm := &configMaps.Items[i]
if hasRevisionStatusOwner(cm.OwnerReferences) {
baseName := extractBaseName(cm.Name)
nsCounts.ConfigMaps[baseName]++
}
}
}

// Gather Secret counts
secrets, err := coreClient.Secrets(namespace).List(ctx, metav1.ListOptions{})
if err != nil {
klog.V(2).Infof("Unable to read Secrets in namespace %s: %v", namespace, err)
} else {
for i := range secrets.Items {
secret := &secrets.Items[i]
if hasRevisionStatusOwner(secret.OwnerReferences) {
baseName := extractBaseName(secret.Name)
nsCounts.Secrets[baseName]++
}
}
}

// Only add namespace to output if it has any revisioned objects
if len(nsCounts.ConfigMaps) > 0 || len(nsCounts.Secrets) > 0 {
namespaceCounts[namespace] = nsCounts
}
}

// Return single record with all counts
return []record.Record{{
Name: "config/versioned_object_revision_counts",
Item: record.JSONMarshaller{Object: namespaceCounts},
}}, nil
}

// extractBaseName removes the revision suffix (-123) from object names
// e.g., "encryption-config-590" -> "encryption-config"
func extractBaseName(name string) string {
return revisionSuffixRegex.ReplaceAllString(name, "")
}

// hasRevisionStatusOwner checks if object has ownerReference starting with "revision-status-"
func hasRevisionStatusOwner(ownerRefs []metav1.OwnerReference) bool {
if len(ownerRefs) == 0 {
return false
}
for _, ref := range ownerRefs {
if strings.HasPrefix(ref.Name, "revision-status-") {
return true
}
}
return false
}

// NamespaceRevisionCounts contains revision counts for ConfigMaps and Secrets
type NamespaceRevisionCounts struct {
ConfigMaps map[string]int `json:"configmaps"`
Secrets map[string]int `json:"secrets"`
}
Loading