diff --git a/internal/store/builder.go b/internal/store/builder.go index db4e06baa9..0155da480a 100644 --- a/internal/store/builder.go +++ b/internal/store/builder.go @@ -65,9 +65,10 @@ var _ ksmtypes.BuilderInterface = &Builder{} // Builder helps to build store. It follows the builder pattern // (https://en.wikipedia.org/wiki/Builder_pattern). type Builder struct { - kubeClient clientset.Interface - customResourceClients map[string]interface{} - namespaces options.NamespaceList + kubeClient clientset.Interface + metadataOnlyKubeClient clientset.Interface + customResourceClients map[string]interface{} + namespaces options.NamespaceList // namespaceFilter is inside fieldSelectorFilter fieldSelectorFilter string ctx context.Context @@ -157,6 +158,11 @@ func (b *Builder) WithKubeClient(c clientset.Interface) { b.kubeClient = c } +// WithMetadataOnlyKubeClient sets the metadataOnlyKubeClient property of a Builder. +func (b *Builder) WithMetadataOnlyKubeClient(c clientset.Interface) { + b.metadataOnlyKubeClient = c +} + // WithCustomResourceClients sets the customResourceClients property of a Builder. func (b *Builder) WithCustomResourceClients(cs map[string]interface{}) { b.customResourceClients = cs @@ -362,143 +368,143 @@ func availableResources() []string { } func (b *Builder) buildConfigMapStores() []cache.Store { - return b.buildStoresFunc(configMapMetricFamilies(b.allowAnnotationsList["configmaps"], b.allowLabelsList["configmaps"]), &v1.ConfigMap{}, createConfigMapListWatch, b.useAPIServerCache) + return b.buildStoresFunc(configMapMetricFamilies(b.allowAnnotationsList["configmaps"], b.allowLabelsList["configmaps"]), &v1.ConfigMap{}, createConfigMapListWatch, b.useAPIServerCache, true) } func (b *Builder) buildCronJobStores() []cache.Store { - return b.buildStoresFunc(cronJobMetricFamilies(b.allowAnnotationsList["cronjobs"], b.allowLabelsList["cronjobs"]), &batchv1.CronJob{}, createCronJobListWatch, b.useAPIServerCache) + return b.buildStoresFunc(cronJobMetricFamilies(b.allowAnnotationsList["cronjobs"], b.allowLabelsList["cronjobs"]), &batchv1.CronJob{}, createCronJobListWatch, b.useAPIServerCache, false) } func (b *Builder) buildDaemonSetStores() []cache.Store { - return b.buildStoresFunc(daemonSetMetricFamilies(b.allowAnnotationsList["daemonsets"], b.allowLabelsList["daemonsets"]), &appsv1.DaemonSet{}, createDaemonSetListWatch, b.useAPIServerCache) + return b.buildStoresFunc(daemonSetMetricFamilies(b.allowAnnotationsList["daemonsets"], b.allowLabelsList["daemonsets"]), &appsv1.DaemonSet{}, createDaemonSetListWatch, b.useAPIServerCache, false) } func (b *Builder) buildDeploymentStores() []cache.Store { - return b.buildStoresFunc(deploymentMetricFamilies(b.allowAnnotationsList["deployments"], b.allowLabelsList["deployments"]), &appsv1.Deployment{}, createDeploymentListWatch, b.useAPIServerCache) + return b.buildStoresFunc(deploymentMetricFamilies(b.allowAnnotationsList["deployments"], b.allowLabelsList["deployments"]), &appsv1.Deployment{}, createDeploymentListWatch, b.useAPIServerCache, false) } func (b *Builder) buildEndpointsStores() []cache.Store { - return b.buildStoresFunc(endpointMetricFamilies(b.allowAnnotationsList["endpoints"], b.allowLabelsList["endpoints"]), &v1.Endpoints{}, createEndpointsListWatch, b.useAPIServerCache) + return b.buildStoresFunc(endpointMetricFamilies(b.allowAnnotationsList["endpoints"], b.allowLabelsList["endpoints"]), &v1.Endpoints{}, createEndpointsListWatch, b.useAPIServerCache, false) } func (b *Builder) buildEndpointSlicesStores() []cache.Store { - return b.buildStoresFunc(endpointSliceMetricFamilies(b.allowAnnotationsList["endpointslices"], b.allowLabelsList["endpointslices"]), &discoveryv1.EndpointSlice{}, createEndpointSliceListWatch, b.useAPIServerCache) + return b.buildStoresFunc(endpointSliceMetricFamilies(b.allowAnnotationsList["endpointslices"], b.allowLabelsList["endpointslices"]), &discoveryv1.EndpointSlice{}, createEndpointSliceListWatch, b.useAPIServerCache, false) } func (b *Builder) buildHPAStores() []cache.Store { - return b.buildStoresFunc(hpaMetricFamilies(b.allowAnnotationsList["horizontalpodautoscalers"], b.allowLabelsList["horizontalpodautoscalers"]), &autoscaling.HorizontalPodAutoscaler{}, createHPAListWatch, b.useAPIServerCache) + return b.buildStoresFunc(hpaMetricFamilies(b.allowAnnotationsList["horizontalpodautoscalers"], b.allowLabelsList["horizontalpodautoscalers"]), &autoscaling.HorizontalPodAutoscaler{}, createHPAListWatch, b.useAPIServerCache, false) } func (b *Builder) buildIngressStores() []cache.Store { - return b.buildStoresFunc(ingressMetricFamilies(b.allowAnnotationsList["ingresses"], b.allowLabelsList["ingresses"]), &networkingv1.Ingress{}, createIngressListWatch, b.useAPIServerCache) + return b.buildStoresFunc(ingressMetricFamilies(b.allowAnnotationsList["ingresses"], b.allowLabelsList["ingresses"]), &networkingv1.Ingress{}, createIngressListWatch, b.useAPIServerCache, false) } func (b *Builder) buildJobStores() []cache.Store { - return b.buildStoresFunc(jobMetricFamilies(b.allowAnnotationsList["jobs"], b.allowLabelsList["jobs"]), &batchv1.Job{}, createJobListWatch, b.useAPIServerCache) + return b.buildStoresFunc(jobMetricFamilies(b.allowAnnotationsList["jobs"], b.allowLabelsList["jobs"]), &batchv1.Job{}, createJobListWatch, b.useAPIServerCache, false) } func (b *Builder) buildLimitRangeStores() []cache.Store { - return b.buildStoresFunc(limitRangeMetricFamilies, &v1.LimitRange{}, createLimitRangeListWatch, b.useAPIServerCache) + return b.buildStoresFunc(limitRangeMetricFamilies, &v1.LimitRange{}, createLimitRangeListWatch, b.useAPIServerCache, false) } func (b *Builder) buildMutatingWebhookConfigurationStores() []cache.Store { - return b.buildStoresFunc(mutatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.MutatingWebhookConfiguration{}, createMutatingWebhookConfigurationListWatch, b.useAPIServerCache) + return b.buildStoresFunc(mutatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.MutatingWebhookConfiguration{}, createMutatingWebhookConfigurationListWatch, b.useAPIServerCache, false) } func (b *Builder) buildNamespaceStores() []cache.Store { - return b.buildStoresFunc(namespaceMetricFamilies(b.allowAnnotationsList["namespaces"], b.allowLabelsList["namespaces"]), &v1.Namespace{}, createNamespaceListWatch, b.useAPIServerCache) + return b.buildStoresFunc(namespaceMetricFamilies(b.allowAnnotationsList["namespaces"], b.allowLabelsList["namespaces"]), &v1.Namespace{}, createNamespaceListWatch, b.useAPIServerCache, false) } func (b *Builder) buildNetworkPolicyStores() []cache.Store { - return b.buildStoresFunc(networkPolicyMetricFamilies(b.allowAnnotationsList["networkpolicies"], b.allowLabelsList["networkpolicies"]), &networkingv1.NetworkPolicy{}, createNetworkPolicyListWatch, b.useAPIServerCache) + return b.buildStoresFunc(networkPolicyMetricFamilies(b.allowAnnotationsList["networkpolicies"], b.allowLabelsList["networkpolicies"]), &networkingv1.NetworkPolicy{}, createNetworkPolicyListWatch, b.useAPIServerCache, false) } func (b *Builder) buildNodeStores() []cache.Store { - return b.buildStoresFunc(nodeMetricFamilies(b.allowAnnotationsList["nodes"], b.allowLabelsList["nodes"]), &v1.Node{}, createNodeListWatch, b.useAPIServerCache) + return b.buildStoresFunc(nodeMetricFamilies(b.allowAnnotationsList["nodes"], b.allowLabelsList["nodes"]), &v1.Node{}, createNodeListWatch, b.useAPIServerCache, false) } func (b *Builder) buildPersistentVolumeClaimStores() []cache.Store { - return b.buildStoresFunc(persistentVolumeClaimMetricFamilies(b.allowAnnotationsList["persistentvolumeclaims"], b.allowLabelsList["persistentvolumeclaims"]), &v1.PersistentVolumeClaim{}, createPersistentVolumeClaimListWatch, b.useAPIServerCache) + return b.buildStoresFunc(persistentVolumeClaimMetricFamilies(b.allowAnnotationsList["persistentvolumeclaims"], b.allowLabelsList["persistentvolumeclaims"]), &v1.PersistentVolumeClaim{}, createPersistentVolumeClaimListWatch, b.useAPIServerCache, false) } func (b *Builder) buildPersistentVolumeStores() []cache.Store { - return b.buildStoresFunc(persistentVolumeMetricFamilies(b.allowAnnotationsList["persistentvolumes"], b.allowLabelsList["persistentvolumes"]), &v1.PersistentVolume{}, createPersistentVolumeListWatch, b.useAPIServerCache) + return b.buildStoresFunc(persistentVolumeMetricFamilies(b.allowAnnotationsList["persistentvolumes"], b.allowLabelsList["persistentvolumes"]), &v1.PersistentVolume{}, createPersistentVolumeListWatch, b.useAPIServerCache, false) } func (b *Builder) buildPodDisruptionBudgetStores() []cache.Store { - return b.buildStoresFunc(podDisruptionBudgetMetricFamilies(b.allowAnnotationsList["poddisruptionbudgets"], b.allowLabelsList["poddisruptionbudgets"]), &policyv1.PodDisruptionBudget{}, createPodDisruptionBudgetListWatch, b.useAPIServerCache) + return b.buildStoresFunc(podDisruptionBudgetMetricFamilies(b.allowAnnotationsList["poddisruptionbudgets"], b.allowLabelsList["poddisruptionbudgets"]), &policyv1.PodDisruptionBudget{}, createPodDisruptionBudgetListWatch, b.useAPIServerCache, false) } func (b *Builder) buildReplicaSetStores() []cache.Store { - return b.buildStoresFunc(replicaSetMetricFamilies(b.allowAnnotationsList["replicasets"], b.allowLabelsList["replicasets"]), &appsv1.ReplicaSet{}, createReplicaSetListWatch, b.useAPIServerCache) + return b.buildStoresFunc(replicaSetMetricFamilies(b.allowAnnotationsList["replicasets"], b.allowLabelsList["replicasets"]), &appsv1.ReplicaSet{}, createReplicaSetListWatch, b.useAPIServerCache, false) } func (b *Builder) buildReplicationControllerStores() []cache.Store { - return b.buildStoresFunc(replicationControllerMetricFamilies, &v1.ReplicationController{}, createReplicationControllerListWatch, b.useAPIServerCache) + return b.buildStoresFunc(replicationControllerMetricFamilies, &v1.ReplicationController{}, createReplicationControllerListWatch, b.useAPIServerCache, false) } func (b *Builder) buildResourceQuotaStores() []cache.Store { - return b.buildStoresFunc(resourceQuotaMetricFamilies(b.allowAnnotationsList["resourcequotas"], b.allowLabelsList["resourcequotas"]), &v1.ResourceQuota{}, createResourceQuotaListWatch, b.useAPIServerCache) + return b.buildStoresFunc(resourceQuotaMetricFamilies(b.allowAnnotationsList["resourcequotas"], b.allowLabelsList["resourcequotas"]), &v1.ResourceQuota{}, createResourceQuotaListWatch, b.useAPIServerCache, false) } func (b *Builder) buildSecretStores() []cache.Store { - return b.buildStoresFunc(secretMetricFamilies(b.allowAnnotationsList["secrets"], b.allowLabelsList["secrets"]), &v1.Secret{}, createSecretListWatch, b.useAPIServerCache) + return b.buildStoresFunc(secretMetricFamilies(b.allowAnnotationsList["secrets"], b.allowLabelsList["secrets"]), &v1.Secret{}, createSecretListWatch, b.useAPIServerCache, true) } func (b *Builder) buildServiceAccountStores() []cache.Store { - return b.buildStoresFunc(serviceAccountMetricFamilies(b.allowAnnotationsList["serviceaccounts"], b.allowLabelsList["serviceaccounts"]), &v1.ServiceAccount{}, createServiceAccountListWatch, b.useAPIServerCache) + return b.buildStoresFunc(serviceAccountMetricFamilies(b.allowAnnotationsList["serviceaccounts"], b.allowLabelsList["serviceaccounts"]), &v1.ServiceAccount{}, createServiceAccountListWatch, b.useAPIServerCache, false) } func (b *Builder) buildServiceStores() []cache.Store { - return b.buildStoresFunc(serviceMetricFamilies(b.allowAnnotationsList["services"], b.allowLabelsList["services"]), &v1.Service{}, createServiceListWatch, b.useAPIServerCache) + return b.buildStoresFunc(serviceMetricFamilies(b.allowAnnotationsList["services"], b.allowLabelsList["services"]), &v1.Service{}, createServiceListWatch, b.useAPIServerCache, false) } func (b *Builder) buildStatefulSetStores() []cache.Store { - return b.buildStoresFunc(statefulSetMetricFamilies(b.allowAnnotationsList["statefulsets"], b.allowLabelsList["statefulsets"]), &appsv1.StatefulSet{}, createStatefulSetListWatch, b.useAPIServerCache) + return b.buildStoresFunc(statefulSetMetricFamilies(b.allowAnnotationsList["statefulsets"], b.allowLabelsList["statefulsets"]), &appsv1.StatefulSet{}, createStatefulSetListWatch, b.useAPIServerCache, false) } func (b *Builder) buildStorageClassStores() []cache.Store { - return b.buildStoresFunc(storageClassMetricFamilies(b.allowAnnotationsList["storageclasses"], b.allowLabelsList["storageclasses"]), &storagev1.StorageClass{}, createStorageClassListWatch, b.useAPIServerCache) + return b.buildStoresFunc(storageClassMetricFamilies(b.allowAnnotationsList["storageclasses"], b.allowLabelsList["storageclasses"]), &storagev1.StorageClass{}, createStorageClassListWatch, b.useAPIServerCache, false) } func (b *Builder) buildPodStores() []cache.Store { - return b.buildStoresFunc(podMetricFamilies(b.allowAnnotationsList["pods"], b.allowLabelsList["pods"]), &v1.Pod{}, createPodListWatch, b.useAPIServerCache) + return b.buildStoresFunc(podMetricFamilies(b.allowAnnotationsList["pods"], b.allowLabelsList["pods"]), &v1.Pod{}, createPodListWatch, b.useAPIServerCache, false) } func (b *Builder) buildCsrStores() []cache.Store { - return b.buildStoresFunc(csrMetricFamilies(b.allowAnnotationsList["certificatesigningrequests"], b.allowLabelsList["certificatesigningrequests"]), &certv1.CertificateSigningRequest{}, createCSRListWatch, b.useAPIServerCache) + return b.buildStoresFunc(csrMetricFamilies(b.allowAnnotationsList["certificatesigningrequests"], b.allowLabelsList["certificatesigningrequests"]), &certv1.CertificateSigningRequest{}, createCSRListWatch, b.useAPIServerCache, false) } func (b *Builder) buildValidatingWebhookConfigurationStores() []cache.Store { - return b.buildStoresFunc(validatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.ValidatingWebhookConfiguration{}, createValidatingWebhookConfigurationListWatch, b.useAPIServerCache) + return b.buildStoresFunc(validatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.ValidatingWebhookConfiguration{}, createValidatingWebhookConfigurationListWatch, b.useAPIServerCache, false) } func (b *Builder) buildVolumeAttachmentStores() []cache.Store { - return b.buildStoresFunc(volumeAttachmentMetricFamilies, &storagev1.VolumeAttachment{}, createVolumeAttachmentListWatch, b.useAPIServerCache) + return b.buildStoresFunc(volumeAttachmentMetricFamilies, &storagev1.VolumeAttachment{}, createVolumeAttachmentListWatch, b.useAPIServerCache, false) } func (b *Builder) buildLeasesStores() []cache.Store { - return b.buildStoresFunc(leaseMetricFamilies, &coordinationv1.Lease{}, createLeaseListWatch, b.useAPIServerCache) + return b.buildStoresFunc(leaseMetricFamilies, &coordinationv1.Lease{}, createLeaseListWatch, b.useAPIServerCache, false) } func (b *Builder) buildClusterRoleStores() []cache.Store { - return b.buildStoresFunc(clusterRoleMetricFamilies(b.allowAnnotationsList["clusterroles"], b.allowLabelsList["clusterroles"]), &rbacv1.ClusterRole{}, createClusterRoleListWatch, b.useAPIServerCache) + return b.buildStoresFunc(clusterRoleMetricFamilies(b.allowAnnotationsList["clusterroles"], b.allowLabelsList["clusterroles"]), &rbacv1.ClusterRole{}, createClusterRoleListWatch, b.useAPIServerCache, false) } func (b *Builder) buildRoleStores() []cache.Store { - return b.buildStoresFunc(roleMetricFamilies(b.allowAnnotationsList["roles"], b.allowLabelsList["roles"]), &rbacv1.Role{}, createRoleListWatch, b.useAPIServerCache) + return b.buildStoresFunc(roleMetricFamilies(b.allowAnnotationsList["roles"], b.allowLabelsList["roles"]), &rbacv1.Role{}, createRoleListWatch, b.useAPIServerCache, false) } func (b *Builder) buildClusterRoleBindingStores() []cache.Store { - return b.buildStoresFunc(clusterRoleBindingMetricFamilies(b.allowAnnotationsList["clusterrolebindings"], b.allowLabelsList["clusterrolebindings"]), &rbacv1.ClusterRoleBinding{}, createClusterRoleBindingListWatch, b.useAPIServerCache) + return b.buildStoresFunc(clusterRoleBindingMetricFamilies(b.allowAnnotationsList["clusterrolebindings"], b.allowLabelsList["clusterrolebindings"]), &rbacv1.ClusterRoleBinding{}, createClusterRoleBindingListWatch, b.useAPIServerCache, false) } func (b *Builder) buildRoleBindingStores() []cache.Store { - return b.buildStoresFunc(roleBindingMetricFamilies(b.allowAnnotationsList["rolebindings"], b.allowLabelsList["rolebindings"]), &rbacv1.RoleBinding{}, createRoleBindingListWatch, b.useAPIServerCache) + return b.buildStoresFunc(roleBindingMetricFamilies(b.allowAnnotationsList["rolebindings"], b.allowLabelsList["rolebindings"]), &rbacv1.RoleBinding{}, createRoleBindingListWatch, b.useAPIServerCache, false) } func (b *Builder) buildIngressClassStores() []cache.Store { - return b.buildStoresFunc(ingressClassMetricFamilies(b.allowAnnotationsList["ingressclasses"], b.allowLabelsList["ingressclasses"]), &networkingv1.IngressClass{}, createIngressClassListWatch, b.useAPIServerCache) + return b.buildStoresFunc(ingressClassMetricFamilies(b.allowAnnotationsList["ingressclasses"], b.allowLabelsList["ingressclasses"]), &networkingv1.IngressClass{}, createIngressClassListWatch, b.useAPIServerCache, false) } func (b *Builder) buildStores( @@ -506,6 +512,7 @@ func (b *Builder) buildStores( expectedType interface{}, listWatchFunc func(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher, useAPIServerCache bool, + metadataOnly bool, ) []cache.Store { metricFamilies = generator.FilterFamilyGenerators(b.familyGeneratorFilter, metricFamilies) composedMetricGenFuncs := generator.ComposeMetricGenFuncs(metricFamilies) @@ -519,7 +526,11 @@ func (b *Builder) buildStores( if b.fieldSelectorFilter != "" { klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter) } - listWatcher := listWatchFunc(b.kubeClient, v1.NamespaceAll, b.fieldSelectorFilter) + kubeClient := b.kubeClient + if metadataOnly { + kubeClient = b.metadataOnlyKubeClient + } + listWatcher := listWatchFunc(kubeClient, v1.NamespaceAll, b.fieldSelectorFilter) b.startReflector(expectedType, store, listWatcher, useAPIServerCache) return []cache.Store{store} } diff --git a/pkg/app/server.go b/pkg/app/server.go index 98bb11df01..f68881cb4d 100644 --- a/pkg/app/server.go +++ b/pkg/app/server.go @@ -275,6 +275,12 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error { } storeBuilder.WithKubeClient(kubeClient) + metadataOnlyKubeClient, err := util.CreateMetadataOnlyKubeClient(opts.Apiserver, opts.Kubeconfig) + if err != nil { + return fmt.Errorf("failed to create metadata-only client: %v", err) + } + storeBuilder.WithMetadataOnlyKubeClient(metadataOnlyKubeClient) + storeBuilder.WithSharding(opts.Shard, opts.TotalShards) if err := storeBuilder.WithAllowAnnotations(opts.AnnotationsAllowList); err != nil { return fmt.Errorf("failed to set up annotations allowlist: %v", err) diff --git a/pkg/builder/builder.go b/pkg/builder/builder.go index 43a09b57e0..4efc3799f9 100644 --- a/pkg/builder/builder.go +++ b/pkg/builder/builder.go @@ -84,6 +84,11 @@ func (b *Builder) WithKubeClient(c clientset.Interface) { b.internal.WithKubeClient(c) } +// WithMetadataOnlyKubeClient sets the metadataOnlyKubeClient property of a Builder. +func (b *Builder) WithMetadataOnlyKubeClient(c clientset.Interface) { + b.internal.WithMetadataOnlyKubeClient(c) +} + // WithCustomResourceClients sets the customResourceClients property of a Builder. func (b *Builder) WithCustomResourceClients(cs map[string]interface{}) { b.internal.WithCustomResourceClients(cs) diff --git a/pkg/builder/types/interfaces.go b/pkg/builder/types/interfaces.go index b7ba595da1..b4b3f55cd8 100644 --- a/pkg/builder/types/interfaces.go +++ b/pkg/builder/types/interfaces.go @@ -38,6 +38,7 @@ type BuilderInterface interface { WithFieldSelectorFilter(fieldSelectors string) WithSharding(shard int32, totalShards int) WithContext(ctx context.Context) + WithMetadataOnlyKubeClient(c clientset.Interface) WithKubeClient(c clientset.Interface) WithCustomResourceClients(cs map[string]interface{}) WithUsingAPIServerCache(u bool) @@ -58,6 +59,7 @@ type BuildStoresFunc func(metricFamilies []generator.FamilyGenerator, expectedType interface{}, listWatchFunc func(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher, useAPIServerCache bool, + metadataOnly bool, ) []cache.Store // BuildCustomResourceStoresFunc function signature that is used to return a list of custom resource cache.Store diff --git a/pkg/util/utils.go b/pkg/util/utils.go index e10afdcd25..fa3f6f1355 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -38,6 +38,7 @@ import ( var config *rest.Config var currentKubeClient clientset.Interface +var currentMetadataOnlyKubeClient clientset.Interface var currentDiscoveryClient *discovery.DiscoveryClient // CreateKubeClient creates a Kubernetes clientset and a custom resource clientset. @@ -79,6 +80,45 @@ func CreateKubeClient(apiserver string, kubeconfig string) (clientset.Interface, return kubeClient, nil } +// CreateMetadataOnlyKubeClient creates a Kubernetes clientset and a custom resource clientset. +func CreateMetadataOnlyKubeClient(apiserver string, kubeconfig string) (clientset.Interface, error) { + if currentMetadataOnlyKubeClient != nil { + return currentMetadataOnlyKubeClient, nil + } + + var err error + + if config == nil { + config, err = clientcmd.BuildConfigFromFlags(apiserver, kubeconfig) + if err != nil { + return nil, err + } + } + + config.UserAgent = fmt.Sprintf("%s/%s (%s/%s) kubernetes/%s", "kube-state-metrics (metadataonly)", version.Version, runtime.GOOS, runtime.GOARCH, version.Revision) + config.AcceptContentTypes = "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1" + config.ContentType = "application/vnd.kubernetes.protobuf" + + kubeClient, err := clientset.NewForConfig(config) + if err != nil { + return nil, err + } + + // Informers don't seem to do a good job logging error messages when it + // can't reach the server, making debugging hard. This makes it easier to + // figure out if apiserver is configured incorrectly. + klog.InfoS("Tested communication with server", "client", "metadata-only") + v, err := kubeClient.Discovery().ServerVersion() + if err != nil { + return nil, fmt.Errorf("error while trying to communicate with apiserver: %w", err) + } + klog.InfoS("Run with Kubernetes cluster version", "major", v.Major, "minor", v.Minor, "gitVersion", v.GitVersion, "gitTreeState", v.GitTreeState, "gitCommit", v.GitCommit, "platform", v.Platform, "client", "metadata-only") + klog.InfoS("Communication with server successfull", "client", "metadata-only") + + currentMetadataOnlyKubeClient = kubeClient + return kubeClient, nil +} + // CreateCustomResourceClients creates a custom resource clientset. func CreateCustomResourceClients(apiserver string, kubeconfig string, factories ...customresource.RegistryFactory) (map[string]interface{}, error) { // Not relying on memoized clients here because the factories are subject to change.