From 141e9a2da99abc3a6d5881142c8becb9e1c742cd Mon Sep 17 00:00:00 2001 From: Andrii Chubatiuk Date: Wed, 17 Dec 2025 19:22:45 +0200 Subject: [PATCH] introduce scraping support for vmsingle * moved scrape configs management to a separate vmscrapes package * added scraping support for vmsingle, which is disabled by default (ingestOnlyMode should be explicitly set to false to enable scraping) --- api/operator/v1beta1/common_scrapeparams.go | 48 +- api/operator/v1beta1/owner.go | 4 + api/operator/v1beta1/vmagent_types.go | 4 +- api/operator/v1beta1/vmextra_types.go | 1 + api/operator/v1beta1/vmsingle_types.go | 83 + api/operator/v1beta1/zz_generated.deepcopy.go | 8 + config/crd/overlay/crd.yaml | 1397 ++++++++++- docs/CHANGELOG.md | 1 + docs/api.md | 156 +- .../operator/factory/build/defaults.go | 4 + .../operator/factory/finalize/vmagent.go | 12 +- .../operator/factory/finalize/vmauth.go | 6 + .../operator/factory/finalize/vmsingle.go | 33 + .../operator/factory/vmagent/rbac.go | 16 +- .../operator/factory/vmagent/rbac_test.go | 12 +- ...t_scrapeconfig_test.go => scrapes_test.go} | 90 +- .../operator/factory/vmagent/vmagent.go | 148 +- .../operator/factory/vmagent/vmagent_test.go | 1 - .../{vmagent => vmscrapes}/nodescrape.go | 4 +- .../{vmagent => vmscrapes}/nodescrape_test.go | 6 +- .../factory/{vmagent => vmscrapes}/objects.go | 30 +- .../{vmagent => vmscrapes}/objects_test.go | 8 +- .../{vmagent => vmscrapes}/podscrape.go | 4 +- .../{vmagent => vmscrapes}/podscrape_test.go | 6 +- .../factory/{vmagent => vmscrapes}/probe.go | 4 +- .../{vmagent => vmscrapes}/probe_test.go | 10 +- .../{vmagent => vmscrapes}/scrapeconfig.go | 2 +- .../scrapeconfig_test.go | 8 +- .../{vmagent => vmscrapes}/servicescrape.go | 4 +- .../servicescrape_test.go | 30 +- .../{vmagent => vmscrapes}/staticscrape.go | 2 +- .../staticscrape_test.go | 8 +- .../vmscrapes.go} | 112 +- .../factory/vmscrapes/vmscrapes_test.go | 110 + .../operator/factory/vmsingle/rbac.go | 276 +++ .../operator/factory/vmsingle/rbac_test.go | 230 ++ .../operator/factory/vmsingle/scrapes_test.go | 2161 +++++++++++++++++ .../operator/factory/vmsingle/vmsingle.go | 296 ++- .../controller/operator/vmagent_controller.go | 50 + .../operator/vmnodescrape_controller.go | 51 +- .../operator/vmpodscrape_controller.go | 54 +- .../controller/operator/vmprobe_controller.go | 54 +- .../vmprometheusconverter_controller.go | 10 +- .../operator/vmscrapeconfig_controller.go | 52 +- .../operator/vmservicescrape_controller.go | 53 +- .../operator/vmsingle_controller.go | 73 +- .../operator/vmstaticscrape_controller.go | 55 +- test/e2e/vmagent_test.go | 2 +- 48 files changed, 5001 insertions(+), 788 deletions(-) rename internal/controller/operator/factory/vmagent/{vmagent_scrapeconfig_test.go => scrapes_test.go} (96%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/nodescrape.go (99%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/nodescrape_test.go (98%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/objects.go (95%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/objects_test.go (98%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/podscrape.go (99%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/podscrape_test.go (98%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/probe.go (99%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/probe_test.go (98%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/scrapeconfig.go (99%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/scrapeconfig_test.go (98%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/servicescrape.go (99%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/servicescrape_test.go (98%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/staticscrape.go (99%) rename internal/controller/operator/factory/{vmagent => vmscrapes}/staticscrape_test.go (98%) rename internal/controller/operator/factory/{vmagent/vmagent_scrapeconfig.go => vmscrapes/vmscrapes.go} (86%) create mode 100644 internal/controller/operator/factory/vmscrapes/vmscrapes_test.go create mode 100644 internal/controller/operator/factory/vmsingle/rbac.go create mode 100644 internal/controller/operator/factory/vmsingle/rbac_test.go create mode 100644 internal/controller/operator/factory/vmsingle/scrapes_test.go diff --git a/api/operator/v1beta1/common_scrapeparams.go b/api/operator/v1beta1/common_scrapeparams.go index f2405cdca..4e65b9f74 100644 --- a/api/operator/v1beta1/common_scrapeparams.go +++ b/api/operator/v1beta1/common_scrapeparams.go @@ -14,12 +14,12 @@ import ( // AttachMetadata configures metadata attachment type AttachMetadata struct { - // Node instructs vmagent to add node specific metadata from service discovery + // Node instructs vmagent or vmsingle to add node specific metadata from service discovery // Valid for roles: pod, endpoints, endpointslice. // +optional Node *bool `json:"node,omitempty"` - // Namespace instructs vmagent to add namespace specific metadata from service discovery + // Namespace instructs vmagent or vmsingle to add namespace specific metadata from service discovery // Valid for roles: pod, service, endpoints, endpointslice, ingress. Namespace *bool `json:"namespace,omitempty"` } @@ -52,7 +52,7 @@ type VMScrapeParams struct { // must be in of semicolon separated header with it's value // eg: // headerName: headerValue - // vmagent supports since 1.79.0 version + // vmagent and vmsingle support since 1.79.0 version // +optional Headers []string `json:"headers,omitempty"` } @@ -283,7 +283,7 @@ type EndpointScrapeParams struct { // HonorLabels chooses the metric's labels on collisions with target labels. // +optional HonorLabels bool `json:"honorLabels,omitempty"` - // HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. + // HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. // +optional HonorTimestamps *bool `json:"honorTimestamps,omitempty"` // MaxScrapeSize defines a maximum size of scraped data for a job @@ -360,7 +360,7 @@ type CommonScrapeSecurityEnforcements struct { EnforcedNamespaceLabel string `json:"enforcedNamespaceLabel,omitempty"` // ArbitraryFSAccessThroughSMs configures whether configuration // based on EndpointAuth can access arbitrary files on the file system - // of the VMAgent container e.g. bearer token files, basic auth, tls certs + // of the VMAgent or VMSingle container e.g. bearer token files, basic auth, tls certs // +optional ArbitraryFSAccessThroughSMs ArbitraryFSAccessThroughSMsConfig `json:"arbitraryFSAccessThroughSMs,omitempty"` } @@ -391,56 +391,56 @@ type CommonScrapeParams struct { SelectAllByDefault bool `json:"selectAllByDefault,omitempty"` // ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery. // Works in combination with NamespaceSelector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional ServiceScrapeSelector *metav1.LabelSelector `json:"serviceScrapeSelector,omitempty"` // ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery. // Works in combination with Selector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional ServiceScrapeNamespaceSelector *metav1.LabelSelector `json:"serviceScrapeNamespaceSelector,omitempty"` // PodScrapeSelector defines PodScrapes to be selected for target discovery. // Works in combination with NamespaceSelector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional PodScrapeSelector *metav1.LabelSelector `json:"podScrapeSelector,omitempty"` // PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery. // Works in combination with Selector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional PodScrapeNamespaceSelector *metav1.LabelSelector `json:"podScrapeNamespaceSelector,omitempty"` // ProbeSelector defines VMProbe to be selected for target probing. // Works in combination with NamespaceSelector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional ProbeSelector *metav1.LabelSelector `json:"probeSelector,omitempty"` // ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery. // Works in combination with Selector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional ProbeNamespaceSelector *metav1.LabelSelector `json:"probeNamespaceSelector,omitempty"` // NodeScrapeSelector defines VMNodeScrape to be selected for scraping. // Works in combination with NamespaceSelector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional NodeScrapeSelector *metav1.LabelSelector `json:"nodeScrapeSelector,omitempty"` // NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery. // Works in combination with Selector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional @@ -448,13 +448,13 @@ type CommonScrapeParams struct { // StaticScrapeSelector defines VMStaticScrape to be selected for target discovery. // Works in combination with NamespaceSelector. // If both nil - match everything. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // +optional StaticScrapeSelector *metav1.LabelSelector `json:"staticScrapeSelector,omitempty"` // StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery. // Works in combination with NamespaceSelector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional @@ -465,16 +465,16 @@ type CommonScrapeParams struct { ScrapeConfigSelector *metav1.LabelSelector `json:"scrapeConfigSelector,omitempty"` // ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery. // Works in combination with Selector. - // NamespaceSelector nil - only objects at VMAgent namespace. + // NamespaceSelector nil - only objects at VMAgent or VMSingle namespace. // Selector nil - only objects at NamespaceSelector namespaces. // If both nil - behaviour controlled by selectAllByDefault // +optional ScrapeConfigNamespaceSelector *metav1.LabelSelector `json:"scrapeConfigNamespaceSelector,omitempty"` // InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it // is valid. Note that using this feature may expose the possibility to - // break upgrades of VMAgent. It is advised to review VMAgent release + // break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release // notes to ensure that no incompatible scrape configs are going to break - // VMAgent after the upgrade. + // VMAgent or VMSingle after the upgrade. // it should be defined as single yaml file. // inlineScrapeConfig: | // - job_name: "prometheus" @@ -484,9 +484,9 @@ type CommonScrapeParams struct { InlineScrapeConfig string `json:"inlineScrapeConfig,omitempty"` // AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it // is valid. Note that using this feature may expose the possibility to - // break upgrades of VMAgent. It is advised to review VMAgent release + // break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release // notes to ensure that no incompatible scrape configs are going to break - // VMAgent after the upgrade. + // VMAgent or VMSingle after the upgrade. // +optional AdditionalScrapeConfigs *corev1.SecretKeySelector `json:"additionalScrapeConfigs,omitempty"` // ServiceScrapeRelabelTemplate defines relabel config, that will be added to each VMServiceScrape. @@ -536,16 +536,16 @@ type CommonScrapeParams struct { // _not_ be added when value is set to empty string (`""`). // +optional ExternalLabelName *string `json:"externalLabelName,omitempty"` - // ExternalLabels The labels to add to any time series scraped by vmagent. + // ExternalLabels The labels to add to any time series scraped by vmagent or vmsingle. // it doesn't affect metrics ingested directly by push API's // +optional ExternalLabels map[string]string `json:"externalLabels,omitempty"` - // IngestOnlyMode switches vmagent into unmanaged mode + // IngestOnlyMode switches vmagent or vmsingle into unmanaged mode // it disables any config generation for scraping - // Currently it prevents vmagent from managing tls and auth options for remote write + // Currently it prevents vmagent or vmsingle from managing tls and auth options for remote write // +optional IngestOnlyMode *bool `json:"ingestOnlyMode,omitempty"` - // EnableKubernetesAPISelectors instructs vmagent to use CRD scrape objects spec.selectors for + // EnableKubernetesAPISelectors instructs vmagent or vmsingle to use CRD scrape objects spec.selectors for // Kubernetes API list and watch requests. // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering // It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. diff --git a/api/operator/v1beta1/owner.go b/api/operator/v1beta1/owner.go index b669ea7e7..87cf2582c 100644 --- a/api/operator/v1beta1/owner.go +++ b/api/operator/v1beta1/owner.go @@ -15,12 +15,14 @@ type CRDName int const ( VMAgentCRD CRDName = iota VLAgentCRD + VMSingleCRD ) func (c CRDName) String() string { return []string{ "vmagents.operator.victoriametrics.com", "vlagents.operator.victoriametrics.com", + "vmsingles.operator.victoriametrics.com", }[c] } @@ -46,6 +48,8 @@ func Init(ctx context.Context, rclient client.Client) error { n = VMAgentCRD case "vlagents.operator.victoriametrics.com": n = VLAgentCRD + case "vmsingles.operator.victoriametrics.com": + n = VMSingleCRD default: continue } diff --git a/api/operator/v1beta1/vmagent_types.go b/api/operator/v1beta1/vmagent_types.go index 672b3a3f4..148aaec6c 100644 --- a/api/operator/v1beta1/vmagent_types.go +++ b/api/operator/v1beta1/vmagent_types.go @@ -348,7 +348,7 @@ type VMAgentRemoteWriteSpec struct { // +optional BearerTokenSecret *corev1.SecretKeySelector `json:"bearerTokenSecret,omitempty"` - // ConfigMap with relabeling config which is applied to metrics before sending them to the corresponding -remoteWrite.url + // ConfigMap with relabeling config which is applied to metrics before sending them to the corresponding -remoteWrite.url. // +optional // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Key at Configmap with relabelConfig for remoteWrite",xDescriptors="urn:alm:descriptor:io.kubernetes:ConfigMapKeySelector" UrlRelabelConfig *corev1.ConfigMapKeySelector `json:"urlRelabelConfig,omitempty"` @@ -569,7 +569,7 @@ func (cr *VMAgent) IsOwnsServiceAccount() bool { return cr.Spec.ServiceAccountName == "" } -func (cr *VMAgent) GetClusterRoleName() string { +func (cr *VMAgent) GetRBACName() string { return fmt.Sprintf("monitoring:%s:%s", cr.Namespace, cr.PrefixedName()) } diff --git a/api/operator/v1beta1/vmextra_types.go b/api/operator/v1beta1/vmextra_types.go index 477d9793a..486bbb44e 100644 --- a/api/operator/v1beta1/vmextra_types.go +++ b/api/operator/v1beta1/vmextra_types.go @@ -71,6 +71,7 @@ const ( LastAppliedSpecAnnotation = "operator.victoriametrics/last-applied-spec" VMAuthLBServiceProxyTargetLabel = "operator.victoriametrics.com/vmauthlb-proxy-name" VMAuthLBServiceProxyJobNameLabel = "operator.victoriametrics.com/vmauthlb-proxy-job-name" + KubeNodeEnvName = "KUBE_NODE_NAME" ) const ( diff --git a/api/operator/v1beta1/vmsingle_types.go b/api/operator/v1beta1/vmsingle_types.go index 2dc2621b3..0c4a77620 100644 --- a/api/operator/v1beta1/vmsingle_types.go +++ b/api/operator/v1beta1/vmsingle_types.go @@ -79,12 +79,21 @@ type VMSingleSpec struct { *EmbeddedProbes `json:",inline"` // StreamAggrConfig defines stream aggregation configuration for VMSingle StreamAggrConfig *StreamAggrConfig `json:"streamAggrConfig,omitempty"` + // APIServerConfig allows specifying a host and auth methods to access apiserver. + // If left empty, VMSingle is assumed to run inside of the cluster + // and will discover API servers automatically and use the pod's CA certificate + // and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. + // +optional + APIServerConfig *APIServerConfig `json:"apiServerConfig,omitempty"` // ServiceAccountName is the name of the ServiceAccount to use to run the pods // +optional ServiceAccountName string `json:"serviceAccountName,omitempty"` + CommonRelabelParams `json:",inline,omitempty"` + CommonScrapeParams `json:",inline,omitempty"` CommonDefaultableParams `json:",inline"` + CommonConfigReloaderParams `json:",inline,omitempty"` CommonApplicationDeploymentParams `json:",inline"` } @@ -93,11 +102,76 @@ func (cr *VMSingle) HasAnyStreamAggrRule() bool { return cr.Spec.StreamAggrConfig.HasAnyRule() } +// HasAnyRelabellingConfigs checks if vmagent has any defined relabeling rules +func (cr *VMSingle) HasAnyRelabellingConfigs() bool { + return cr.Spec.HasAnyRelabellingConfigs() +} + // SetLastSpec implements objectWithLastAppliedState interface func (cr *VMSingle) SetLastSpec(prevSpec VMSingleSpec) { cr.ParsedLastAppliedSpec = &prevSpec } +// ScrapeSelectors gets object and namespace sepectors +func (cr *VMSingle) ScrapeSelectors(scrape client.Object) (*metav1.LabelSelector, *metav1.LabelSelector) { + return cr.Spec.ScrapeSelectors(scrape) +} + +// IsUnmanaged checks if object should managed any config objects +func (cr *VMSingle) IsUnmanaged(scrape client.Object) bool { + if !cr.DeletionTimestamp.IsZero() || cr.Spec.ParsingError != "" { + return true + } + if scrape == nil { + return cr.Spec.isUnmanaged() + } + switch s := scrape.(type) { + case *VMNodeScrape: + return cr.Spec.isNodeScrapeUnmanaged() + case *VMServiceScrape: + return cr.Spec.isServiceScrapeUnmanaged() + case *VMPodScrape: + return cr.Spec.isPodScrapeUnmanaged() + case *VMProbe: + return cr.Spec.isProbeUnmanaged() + case *VMStaticScrape: + return cr.Spec.isStaticScrapeUnmanaged() + case *VMScrapeConfig: + return cr.Spec.isScrapeConfigUnmanaged() + default: + panic(fmt.Sprintf("BUG: scrape kind %T is not supported", s)) + } + +} + +// ExternalLabels returns external labels for scraping +func (cr *VMSingle) ExternalLabels() map[string]string { + return cr.Spec.externalLabels(fmt.Sprintf("%s/%s", cr.Namespace, cr.Name)) +} + +// GetReloadURL implements reloadable interface +func (cr *VMSingle) GetReloadURL(host string) string { + return BuildLocalURL(reloadAuthKeyFlag, host, cr.Spec.Port, reloadPath, cr.Spec.ExtraArgs) +} + +// GetReloaderParams implements reloadable interface +func (cr *VMSingle) GetReloaderParams() *CommonConfigReloaderParams { + return &cr.Spec.CommonConfigReloaderParams +} + +// UseProxyProtocol implements reloadable interface +func (cr *VMSingle) UseProxyProtocol() bool { + if v, ok := cr.Spec.ExtraArgs["httpListenAddr.useProxyProtocol"]; ok && v == "true" { + return true + } + return false +} + +// AutomountServiceAccountToken implements reloadable interface +func (cr *VMSingle) AutomountServiceAccountToken() bool { + return !cr.Spec.DisableAutomountServiceAccountToken +} + // UnmarshalJSON implements json.Unmarshaler interface func (cr *VMSingle) UnmarshalJSON(src []byte) error { type pcr VMSingle @@ -151,6 +225,11 @@ type VMSingle struct { Status VMSingleStatus `json:"status,omitempty"` } +// AsCRDOwner implements interface +func (*VMSingle) AsCRDOwner() *metav1.OwnerReference { + return GetCRDAsOwner(VMSingleCRD) +} + // GetStatus implements reconcile.ObjectWithDeepCopyAndStatus interface func (cr *VMSingle) GetStatus() *VMSingleStatus { return &cr.Status @@ -280,6 +359,10 @@ func (cr *VMSingle) IsOwnsServiceAccount() bool { return cr.Spec.ServiceAccountName == "" } +func (cr *VMSingle) GetRBACName() string { + return fmt.Sprintf("monitoring:%s:%s", cr.Namespace, cr.PrefixedName()) +} + func (cr *VMSingle) AsURL() string { port := cr.Spec.Port if port == "" { diff --git a/api/operator/v1beta1/zz_generated.deepcopy.go b/api/operator/v1beta1/zz_generated.deepcopy.go index 0adeb9ccf..b221abc78 100644 --- a/api/operator/v1beta1/zz_generated.deepcopy.go +++ b/api/operator/v1beta1/zz_generated.deepcopy.go @@ -6813,7 +6813,15 @@ func (in *VMSingleSpec) DeepCopyInto(out *VMSingleSpec) { *out = new(StreamAggrConfig) (*in).DeepCopyInto(*out) } + if in.APIServerConfig != nil { + in, out := &in.APIServerConfig, &out.APIServerConfig + *out = new(APIServerConfig) + (*in).DeepCopyInto(*out) + } + in.CommonRelabelParams.DeepCopyInto(&out.CommonRelabelParams) + in.CommonScrapeParams.DeepCopyInto(&out.CommonScrapeParams) in.CommonDefaultableParams.DeepCopyInto(&out.CommonDefaultableParams) + in.CommonConfigReloaderParams.DeepCopyInto(&out.CommonConfigReloaderParams) in.CommonApplicationDeploymentParams.DeepCopyInto(&out.CommonApplicationDeploymentParams) } diff --git a/config/crd/overlay/crd.yaml b/config/crd/overlay/crd.yaml index c4138be8f..5c61b9535 100644 --- a/config/crd/overlay/crd.yaml +++ b/config/crd/overlay/crd.yaml @@ -34532,13 +34532,231 @@ spec: type: object spec: properties: + additionalScrapeConfigs: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic affinity: type: object x-kubernetes-preserve-unknown-fields: true + apiServerConfig: + properties: + authorization: + properties: + credentials: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + credentialsFile: + type: string + type: + type: string + type: object + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerToken: + type: string + bearerTokenFile: + type: string + host: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + required: + - host + type: object + arbitraryFSAccessThroughSMs: + properties: + deny: + type: boolean + type: object configMaps: items: type: string type: array + configReloadAuthKeySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + configReloaderExtraArgs: + additionalProperties: + type: string + type: object + configReloaderImage: + type: string + configReloaderImageTag: + type: string + configReloaderResources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object containers: items: required: @@ -34577,6 +34795,16 @@ spec: type: object dnsPolicy: type: string + enableKubernetesAPISelectors: + type: boolean + enforcedNamespaceLabel: + type: string + externalLabelName: + type: string + externalLabels: + additionalProperties: + type: string + type: object extraArgs: additionalProperties: type: string @@ -34618,36 +34846,110 @@ spec: x-kubernetes-map-type: atomic type: object type: array - host_aliases: + globalScrapeMetricRelabelConfigs: items: properties: - hostnames: - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: + action: type: string - required: - - ip - type: object - type: array - hostAliases: - items: - properties: - hostnames: - items: + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: type: string - type: array - x-kubernetes-list-type: atomic - ip: + type: object + match: type: string - required: + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + globalScrapeRelabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: - ip type: object type: array hostNetwork: type: boolean + ignoreNamespaceSelectors: + type: boolean image: properties: pullPolicy: @@ -34666,6 +34968,8 @@ spec: type: object x-kubernetes-map-type: atomic type: array + ingestOnlyMode: + type: boolean initContainers: items: required: @@ -34673,6 +34977,44 @@ spec: type: object x-kubernetes-preserve-unknown-fields: true type: array + inlineRelabelConfig: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + inlineScrapeConfig: + type: string insertPorts: properties: graphitePort: @@ -34733,101 +35075,882 @@ spec: type: string type: object type: object - minReadySeconds: - format: int32 - type: integer - nodeSelector: - additionalProperties: + maxScrapeInterval: + type: string + minReadySeconds: + format: int32 + type: integer + minScrapeInterval: + type: string + nodeScrapeNamespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + nodeScrapeRelabelTemplate: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + nodeScrapeSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + nodeSelector: + additionalProperties: + type: string + type: object + overrideHonorLabels: + type: boolean + overrideHonorTimestamps: + type: boolean + paused: + type: boolean + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + podScrapeNamespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + podScrapeRelabelTemplate: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + podScrapeSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + port: + type: string + priorityClassName: + type: string + probeNamespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + probeScrapeRelabelTemplate: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + probeSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + relabelConfig: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + removePvcAfterDelete: + type: boolean + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + retentionPeriod: + pattern: ^[0-9]+(h|d|w|y)?$ + type: string + revisionHistoryLimitCount: + format: int32 + type: integer + runtimeClassName: + type: string + sampleLimit: + type: integer + schedulerName: + type: string + scrapeClasses: + items: + properties: + attachMetadata: + properties: + namespace: + type: boolean + node: + type: boolean + type: object + authorization: + properties: + credentials: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + credentialsFile: + type: string + type: + type: string + type: object + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenFile: + type: string + bearerTokenSecret: + nullable: true + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + default: + type: boolean + metricRelabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + name: + minLength: 1 + type: string + oauth2: + properties: + client_id: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + client_secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + client_secret_file: + type: string + endpoint_params: + additionalProperties: + type: string + type: object + proxy_url: + type: string + scopes: + items: + type: string + type: array + tls_config: + x-kubernetes-preserve-unknown-fields: true + token_url: + minLength: 1 + type: string + required: + - client_id + - token_url + type: object + relabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + scrapeConfigNamespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + scrapeConfigRelabelTemplate: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + scrapeConfigSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + scrapeInterval: + pattern: '[0-9]+(ms|s|m|h)' + type: string + scrapeTimeout: + pattern: '[0-9]+(ms|s|m|h)' + type: string + secrets: + items: type: string + type: array + securityContext: type: object - paused: + x-kubernetes-preserve-unknown-fields: true + selectAllByDefault: type: boolean - podMetadata: + serviceAccountName: + type: string + serviceScrapeNamespaceSelector: properties: - annotations: - additionalProperties: - type: string - type: object - labels: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: additionalProperties: type: string type: object - name: - type: string type: object - port: - type: string - priorityClassName: - type: string - readinessGates: + x-kubernetes-map-type: atomic + serviceScrapeRelabelTemplate: items: properties: - conditionType: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: type: string - required: - - conditionType type: object type: array - readinessProbe: - type: object - x-kubernetes-preserve-unknown-fields: true - removePvcAfterDelete: - type: boolean - replicaCount: - format: int32 - type: integer - resources: + serviceScrapeSelector: properties: - claims: + matchExpressions: items: properties: - name: + key: type: string - request: + operator: type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic required: - - name + - key + - operator type: object type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - requests: + x-kubernetes-list-type: atomic + matchLabels: additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true + type: string type: object type: object - retentionPeriod: - pattern: ^[0-9]+(h|d|w|y)?$ - type: string - revisionHistoryLimitCount: - format: int32 - type: integer - runtimeClassName: - type: string - schedulerName: - type: string - secrets: - items: - type: string - type: array - securityContext: - type: object - x-kubernetes-preserve-unknown-fields: true - serviceAccountName: - type: string + x-kubernetes-map-type: atomic serviceScrapeSpec: required: - endpoints @@ -34859,6 +35982,94 @@ spec: startupProbe: type: object x-kubernetes-preserve-unknown-fields: true + staticScrapeNamespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + staticScrapeRelabelTemplate: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + staticScrapeSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic storage: properties: accessModes: @@ -35146,6 +36357,10 @@ spec: type: boolean useStrictSecurity: type: boolean + useVMConfigReloader: + type: boolean + vmAgentExternalLabelName: + type: string vmBackup: properties: acceptEULA: diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9b9e75316..b7340602e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -28,6 +28,7 @@ aliases: * FEATURE: [vmprobe](https://docs.victoriametrics.com/operator/resources/vmprobe/): added `spec.targets.kubernetes` property, that allows to configure probe for `ingress`, `pod` and `service` roles. See [#1078](https://github.com/VictoriaMetrics/operator/issues/1078) and [#1716](https://github.com/VictoriaMetrics/operator/issues/1716). * FEATURE: [vmscrapeconfig](https://docs.victoriametrics.com/operator/resources/vmscrapeconfig/): added nomad_sd_config support. See [#1809](https://github.com/VictoriaMetrics/operator/issues/1809). * FEATURE: [vmoperator](https://docs.victoriametrics.com/operator/): support VPA for vmcluster, vtcluster, vlcluster and vmauth. See [#1795](https://github.com/VictoriaMetrics/operator/issues/1795). Thanks to the @dctrwatson for the pull request [#1803](https://github.com/VictoriaMetrics/operator/pull/1803). +* FEATURE: [vmsingle](https://docs.victoriametrics.com/operator/resources/vmsingle/): VMSingle reuses vmagent implementation to allow scraping and relabelling. See [#1694](https://github.com/VictoriaMetrics/operator/issues/1694) * BUGFIX: [vmagent](https://docs.victoriametrics.com/operator/resources/vmagent/): previously the operator requested `nodes/proxy` RBAC permissions even though vmagent did not use them; now this permission is no longer required, reducing the default privilege footprint for users running vmagent. See [#1753](https://github.com/VictoriaMetrics/operator/issues/1753). * BUGFIX: [vmalert](https://docs.victoriametrics.com/operator/resources/vmalert/): throw error if no notifiers found. See [#1757](https://github.com/VictoriaMetrics/operator/issues/1757). diff --git a/docs/api.md b/docs/api.md index bd5874196..5d9630237 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1412,7 +1412,7 @@ Package v1beta1 contains API Schema definitions for the victoriametrics v1beta1 APIServerConfig defines a host and auth methods to access apiserver. -Appears in: [VMAgentSpec](#vmagentspec) +Appears in: [VMAgentSpec](#vmagentspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | @@ -1474,7 +1474,7 @@ in the vmagent container. Those secrets would then be sent with a scrape request by vmagent to a malicious target. Denying the above would prevent the attack, users can instead use the BearerTokenSecret field. -Appears in: [CommonScrapeParams](#commonscrapeparams), [CommonScrapeSecurityEnforcements](#commonscrapesecurityenforcements), [VMAgentSpec](#vmagentspec) +Appears in: [CommonScrapeParams](#commonscrapeparams), [CommonScrapeSecurityEnforcements](#commonscrapesecurityenforcements), [VMAgentSpec](#vmagentspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | @@ -1491,8 +1491,8 @@ Appears in: [Endpoint](#endpoint), [KubernetesSDConfig](#kubernetessdconfig), [P | Field | Description | | --- | --- | -| namespace#
_boolean_ | _(Required)_
Namespace instructs vmagent to add namespace specific metadata from service discovery
Valid for roles: pod, service, endpoints, endpointslice, ingress. | -| node#
_boolean_ | _(Optional)_
Node instructs vmagent to add node specific metadata from service discovery
Valid for roles: pod, endpoints, endpointslice. | +| namespace#
_boolean_ | _(Required)_
Namespace instructs vmagent or vmsingle to add namespace specific metadata from service discovery
Valid for roles: pod, service, endpoints, endpointslice, ingress. | +| node#
_boolean_ | _(Optional)_
Node instructs vmagent or vmsingle to add node specific metadata from service discovery
Valid for roles: pod, endpoints, endpointslice. | #### Authorization @@ -1655,7 +1655,7 @@ Appears in: [VLAgentSpec](#vlagentspec), [VLInsert](#vlinsert), [VLSelect](#vlse -Appears in: [VMAgentSpec](#vmagentspec), [VMAlertSpec](#vmalertspec), [VMAlertmanagerSpec](#vmalertmanagerspec), [VMAuthLoadBalancerSpec](#vmauthloadbalancerspec), [VMAuthSpec](#vmauthspec) +Appears in: [VMAgentSpec](#vmagentspec), [VMAlertSpec](#vmalertspec), [VMAlertmanagerSpec](#vmalertmanagerspec), [VMAuthLoadBalancerSpec](#vmauthloadbalancerspec), [VMAuthSpec](#vmauthspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | @@ -1692,7 +1692,7 @@ Appears in: [VLAgentSpec](#vlagentspec), [VLInsert](#vlinsert), [VLSelect](#vlse CommonRelabelParams defines params for relabelling -Appears in: [VMAgentSpec](#vmagentspec) +Appears in: [VMAgentSpec](#vmagentspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | @@ -1706,48 +1706,48 @@ Appears in: [VMAgentSpec](#vmagentspec) -Appears in: [VMAgentSpec](#vmagentspec) +Appears in: [VMAgentSpec](#vmagentspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | -| additionalScrapeConfigs#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent. It is advised to review VMAgent release
notes to ensure that no incompatible scrape configs are going to break
VMAgent after the upgrade. | -| arbitraryFSAccessThroughSMs#
_[ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig)_ | _(Optional)_
ArbitraryFSAccessThroughSMs configures whether configuration
based on EndpointAuth can access arbitrary files on the file system
of the VMAgent container e.g. bearer token files, basic auth, tls certs | -| enableKubernetesAPISelectors#
_boolean_ | _(Optional)_
EnableKubernetesAPISelectors instructs vmagent to use CRD scrape objects spec.selectors for
Kubernetes API list and watch requests.
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering
It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. | +| additionalScrapeConfigs#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release
notes to ensure that no incompatible scrape configs are going to break
VMAgent or VMSingle after the upgrade. | +| arbitraryFSAccessThroughSMs#
_[ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig)_ | _(Optional)_
ArbitraryFSAccessThroughSMs configures whether configuration
based on EndpointAuth can access arbitrary files on the file system
of the VMAgent or VMSingle container e.g. bearer token files, basic auth, tls certs | +| enableKubernetesAPISelectors#
_boolean_ | _(Optional)_
EnableKubernetesAPISelectors instructs vmagent or vmsingle to use CRD scrape objects spec.selectors for
Kubernetes API list and watch requests.
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering
It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. | | enforcedNamespaceLabel#
_string_ | _(Optional)_
EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert
and metric that is user created. The label value will always be the namespace of the object that is
being created. | | externalLabelName#
_string_ | _(Optional)_
ExternalLabelName Name of external label used to denote scraping agent instance
name. Defaults to the value of `prometheus`. External label will
_not_ be added when value is set to empty string (`""`). | -| externalLabels#
_object (keys:string, values:string)_ | _(Optional)_
ExternalLabels The labels to add to any time series scraped by vmagent.
it doesn't affect metrics ingested directly by push API's | +| externalLabels#
_object (keys:string, values:string)_ | _(Optional)_
ExternalLabels The labels to add to any time series scraped by vmagent or vmsingle.
it doesn't affect metrics ingested directly by push API's | | globalScrapeMetricRelabelConfigs#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
GlobalScrapeMetricRelabelConfigs is a global metric relabel configuration, which is applied to each scrape job. | | globalScrapeRelabelConfigs#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
GlobalScrapeRelabelConfigs is a global relabel configuration, which is applied to each samples of each scrape job during service discovery. | | ignoreNamespaceSelectors#
_boolean_ | _(Optional)_
IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from
scrape objects, and they will only discover endpoints
within their current namespace. Defaults to false. | -| ingestOnlyMode#
_boolean_ | _(Optional)_
IngestOnlyMode switches vmagent into unmanaged mode
it disables any config generation for scraping
Currently it prevents vmagent from managing tls and auth options for remote write | -| inlineScrapeConfig#
_string_ | _(Optional)_
InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent. It is advised to review VMAgent release
notes to ensure that no incompatible scrape configs are going to break
VMAgent after the upgrade.
it should be defined as single yaml file.
inlineScrapeConfig: \|
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"] | +| ingestOnlyMode#
_boolean_ | _(Optional)_
IngestOnlyMode switches vmagent or vmsingle into unmanaged mode
it disables any config generation for scraping
Currently it prevents vmagent or vmsingle from managing tls and auth options for remote write | +| inlineScrapeConfig#
_string_ | _(Optional)_
InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release
notes to ensure that no incompatible scrape configs are going to break
VMAgent or VMSingle after the upgrade.
it should be defined as single yaml file.
inlineScrapeConfig: \|
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"] | | maxScrapeInterval#
_string_ | _(Required)_
MaxScrapeInterval allows limiting maximum scrape interval for VMServiceScrape, VMPodScrape and other scrapes
If interval is higher than defined limit, `maxScrapeInterval` will be used. | | minScrapeInterval#
_string_ | _(Required)_
MinScrapeInterval allows limiting minimal scrape interval for VMServiceScrape, VMPodScrape and other scrapes
If interval is lower than defined limit, `minScrapeInterval` will be used. | -| nodeScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| nodeScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | nodeScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
NodeScrapeRelabelTemplate defines relabel config, that will be added to each VMNodeScrape.
it's useful for adding specific labels to all targets | -| nodeScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeSelector defines VMNodeScrape to be selected for scraping.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| nodeScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeSelector defines VMNodeScrape to be selected for scraping.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | overrideHonorLabels#
_boolean_ | _(Optional)_
OverrideHonorLabels if set to true overrides all user configured honor_labels.
If HonorLabels is set in scrape objects to true, this overrides honor_labels to false. | | overrideHonorTimestamps#
_boolean_ | _(Optional)_
OverrideHonorTimestamps allows to globally enforce honoring timestamps in all scrape configs. | -| podScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| podScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | podScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
PodScrapeRelabelTemplate defines relabel config, that will be added to each VMPodScrape.
it's useful for adding specific labels to all targets | -| podScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeSelector defines PodScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | -| probeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| podScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeSelector defines PodScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| probeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | probeScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ProbeScrapeRelabelTemplate defines relabel config, that will be added to each VMProbeScrape.
it's useful for adding specific labels to all targets | -| probeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeSelector defines VMProbe to be selected for target probing.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| probeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeSelector defines VMProbe to be selected for target probing.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | sampleLimit#
_integer_ | _(Optional)_
SampleLimit defines global per target limit of scraped samples | | scrapeClasses#
_[ScrapeClass](#scrapeclass) array_ | _(Optional)_
ScrapeClasses defines the list of scrape classes to expose to scraping objects such as
PodScrapes, ServiceScrapes, Probes and ScrapeConfigs. | -| scrapeConfigNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| scrapeConfigNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | scrapeConfigRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ScrapeConfigRelabelTemplate defines relabel config, that will be added to each VMScrapeConfig.
it's useful for adding specific labels to all targets | | scrapeConfigSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigSelector defines VMScrapeConfig to be selected for target discovery.
Works in combination with NamespaceSelector. | | scrapeInterval#
_string_ | _(Optional)_
ScrapeInterval defines how often scrape targets by default | | scrapeTimeout#
_string_ | _(Optional)_
ScrapeTimeout defines global timeout for targets scrape | | selectAllByDefault#
_boolean_ | _(Optional)_
SelectAllByDefault changes default behavior for empty CRD selectors, such ServiceScrapeSelector.
with selectAllByDefault: true and empty serviceScrapeSelector and ServiceScrapeNamespaceSelector
Operator selects all exist serviceScrapes
with selectAllByDefault: false - selects nothing | -| serviceScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| serviceScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | serviceScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ServiceScrapeRelabelTemplate defines relabel config, that will be added to each VMServiceScrape.
it's useful for adding specific labels to all targets | -| serviceScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | -| staticScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| serviceScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| staticScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | staticScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
StaticScrapeRelabelTemplate defines relabel config, that will be added to each VMStaticScrape.
it's useful for adding specific labels to all targets | -| staticScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeSelector defines VMStaticScrape to be selected for target discovery.
Works in combination with NamespaceSelector.
If both nil - match everything.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces. | +| staticScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeSelector defines VMStaticScrape to be selected for target discovery.
Works in combination with NamespaceSelector.
If both nil - match everything.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces. | | vmAgentExternalLabelName#
_string_ | _(Optional)_
VMAgentExternalLabelName Name of vmAgent external label used to denote vmAgent instance
name. Defaults to the value of `prometheus`. External label will
_not_ be added when value is set to empty string (`""`).
Deprecated: since version v0.67.0 will be removed in v0.69.0 use externalLabelName instead
| @@ -1757,11 +1757,11 @@ Appears in: [VMAgentSpec](#vmagentspec) CommonScrapeSecurityEnforcements defines security configuration for endpoint scrapping -Appears in: [CommonScrapeParams](#commonscrapeparams), [VMAgentSpec](#vmagentspec) +Appears in: [CommonScrapeParams](#commonscrapeparams), [VMAgentSpec](#vmagentspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | -| arbitraryFSAccessThroughSMs#
_[ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig)_ | _(Optional)_
ArbitraryFSAccessThroughSMs configures whether configuration
based on EndpointAuth can access arbitrary files on the file system
of the VMAgent container e.g. bearer token files, basic auth, tls certs | +| arbitraryFSAccessThroughSMs#
_[ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig)_ | _(Optional)_
ArbitraryFSAccessThroughSMs configures whether configuration
based on EndpointAuth can access arbitrary files on the file system
of the VMAgent or VMSingle container e.g. bearer token files, basic auth, tls certs | | enforcedNamespaceLabel#
_string_ | _(Optional)_
EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert
and metric that is user created. The label value will always be the namespace of the object that is
being created. | | ignoreNamespaceSelectors#
_boolean_ | _(Optional)_
IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from
scrape objects, and they will only discover endpoints
within their current namespace. Defaults to false. | | overrideHonorLabels#
_boolean_ | _(Optional)_
OverrideHonorLabels if set to true overrides all user configured honor_labels.
If HonorLabels is set in scrape objects to true, this overrides honor_labels to false. | @@ -2122,7 +2122,7 @@ Appears in: [VMServiceScrapeSpec](#vmservicescrapespec) | bearerTokenSecret#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
Secret to mount to read bearer token for scraping targets. The secret
needs to be in the same namespace as the scrape object and accessible by
the victoria-metrics operator. | | follow_redirects#
_boolean_ | _(Optional)_
FollowRedirects controls redirects for scraping. | | honorLabels#
_boolean_ | _(Optional)_
HonorLabels chooses the metric's labels on collisions with target labels. | -| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | +| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. | | interval#
_string_ | _(Optional)_
Interval at which metrics should be scraped | | max_scrape_size#
_string_ | _(Optional)_
MaxScrapeSize defines a maximum size of scraped data for a job | | metricRelabelConfigs#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
MetricRelabelConfigs to apply to samples after scrapping. | @@ -2186,7 +2186,7 @@ Appears in: [Endpoint](#endpoint), [PodMetricsEndpoint](#podmetricsendpoint), [T | --- | --- | | follow_redirects#
_boolean_ | _(Optional)_
FollowRedirects controls redirects for scraping. | | honorLabels#
_boolean_ | _(Optional)_
HonorLabels chooses the metric's labels on collisions with target labels. | -| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | +| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. | | interval#
_string_ | _(Optional)_
Interval at which metrics should be scraped | | max_scrape_size#
_string_ | _(Optional)_
MaxScrapeSize defines a maximum size of scraped data for a job | | params#
_object (keys:string, values:string array)_ | _(Optional)_
Optional HTTP URL parameters | @@ -2748,7 +2748,7 @@ Appears in: [VMPodScrapeSpec](#vmpodscrapespec) | filterRunning#
_boolean_ | _(Optional)_
FilterRunning applies filter with pod status == running
it prevents from scrapping metrics at failed or succeed state pods.
enabled by default | | follow_redirects#
_boolean_ | _(Optional)_
FollowRedirects controls redirects for scraping. | | honorLabels#
_boolean_ | _(Optional)_
HonorLabels chooses the metric's labels on collisions with target labels. | -| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | +| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. | | interval#
_string_ | _(Optional)_
Interval at which metrics should be scraped | | max_scrape_size#
_string_ | _(Optional)_
MaxScrapeSize defines a maximum size of scraped data for a job | | metricRelabelConfigs#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
MetricRelabelConfigs to apply to samples after scrapping. | @@ -2864,7 +2864,7 @@ Appears in: [VMAlertmanagerConfigSpec](#vmalertmanagerconfigspec) RelabelConfig allows dynamic rewriting of the label set More info: https://docs.victoriametrics.com/victoriametrics/#relabeling -Appears in: [CommonRelabelParams](#commonrelabelparams), [CommonScrapeParams](#commonscrapeparams), [Endpoint](#endpoint), [EndpointRelabelings](#endpointrelabelings), [PodMetricsEndpoint](#podmetricsendpoint), [ScrapeClass](#scrapeclass), [StreamAggrRule](#streamaggrrule), [TargetEndpoint](#targetendpoint), [VMAgentRemoteWriteSpec](#vmagentremotewritespec), [VMAgentSpec](#vmagentspec), [VMNodeScrapeSpec](#vmnodescrapespec), [VMProbeSpec](#vmprobespec), [VMProbeTargetKubernetes](#vmprobetargetkubernetes), [VMProbeTargetStatic](#vmprobetargetstatic), [VMScrapeConfigSpec](#vmscrapeconfigspec) +Appears in: [CommonRelabelParams](#commonrelabelparams), [CommonScrapeParams](#commonscrapeparams), [Endpoint](#endpoint), [EndpointRelabelings](#endpointrelabelings), [PodMetricsEndpoint](#podmetricsendpoint), [ScrapeClass](#scrapeclass), [StreamAggrRule](#streamaggrrule), [TargetEndpoint](#targetendpoint), [VMAgentRemoteWriteSpec](#vmagentremotewritespec), [VMAgentSpec](#vmagentspec), [VMNodeScrapeSpec](#vmnodescrapespec), [VMProbeSpec](#vmprobespec), [VMProbeTargetKubernetes](#vmprobetargetkubernetes), [VMProbeTargetStatic](#vmprobetargetstatic), [VMScrapeConfigSpec](#vmscrapeconfigspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | @@ -3023,7 +3023,7 @@ Appears in: [VMRuleSpec](#vmrulespec) -Appears in: [CommonScrapeParams](#commonscrapeparams), [VMAgentSpec](#vmagentspec) +Appears in: [CommonScrapeParams](#commonscrapeparams), [VMAgentSpec](#vmagentspec), [VMSingleSpec](#vmsinglespec) | Field | Description | | --- | --- | @@ -3402,7 +3402,7 @@ Appears in: [VMStaticScrapeSpec](#vmstaticscrapespec) | bearerTokenSecret#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
Secret to mount to read bearer token for scraping targets. The secret
needs to be in the same namespace as the scrape object and accessible by
the victoria-metrics operator. | | follow_redirects#
_boolean_ | _(Optional)_
FollowRedirects controls redirects for scraping. | | honorLabels#
_boolean_ | _(Optional)_
HonorLabels chooses the metric's labels on collisions with target labels. | -| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | +| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. | | interval#
_string_ | _(Optional)_
Interval at which metrics should be scraped | | labels#
_object (keys:string, values:string)_ | _(Optional)_
Labels static labels for targets. | | max_scrape_size#
_string_ | _(Optional)_
MaxScrapeSize defines a maximum size of scraped data for a job | @@ -3705,7 +3705,7 @@ Appears in: [VMAgentSpec](#vmagentspec) | streamAggrConfig#
_[StreamAggrConfig](#streamaggrconfig)_ | _(Optional)_
StreamAggrConfig defines stream aggregation configuration for VMAgent for -remoteWrite.url | | tlsConfig#
_[TLSConfig](#tlsconfig)_ | _(Optional)_
TLSConfig describes tls configuration for remote write target | | url#
_string_ | _(Required)_
URL of the endpoint to send samples to. | -| urlRelabelConfig#
_[ConfigMapKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#configmapkeyselector-v1-core)_ | _(Optional)_
ConfigMap with relabeling config which is applied to metrics before sending them to the corresponding -remoteWrite.url | +| urlRelabelConfig#
_[ConfigMapKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#configmapkeyselector-v1-core)_ | _(Optional)_
ConfigMap with relabeling config which is applied to metrics before sending them to the corresponding -remoteWrite.url. | #### VMAgentSpec @@ -3718,10 +3718,10 @@ Appears in: [VMAgent](#vmagent) | Field | Description | | --- | --- | -| additionalScrapeConfigs#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent. It is advised to review VMAgent release
notes to ensure that no incompatible scrape configs are going to break
VMAgent after the upgrade. | +| additionalScrapeConfigs#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release
notes to ensure that no incompatible scrape configs are going to break
VMAgent or VMSingle after the upgrade. | | affinity#
_[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#affinity-v1-core)_ | _(Optional)_
Affinity If specified, the pod's scheduling constraints. | | apiServerConfig#
_[APIServerConfig](#apiserverconfig)_ | _(Optional)_
APIServerConfig allows specifying a host and auth methods to access apiserver.
If left empty, VMAgent is assumed to run inside of the cluster
and will discover API servers automatically and use the pod's CA certificate
and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. | -| arbitraryFSAccessThroughSMs#
_[ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig)_ | _(Optional)_
ArbitraryFSAccessThroughSMs configures whether configuration
based on EndpointAuth can access arbitrary files on the file system
of the VMAgent container e.g. bearer token files, basic auth, tls certs | +| arbitraryFSAccessThroughSMs#
_[ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig)_ | _(Optional)_
ArbitraryFSAccessThroughSMs configures whether configuration
based on EndpointAuth can access arbitrary files on the file system
of the VMAgent or VMSingle container e.g. bearer token files, basic auth, tls certs | | claimTemplates#
_[PersistentVolumeClaim](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#persistentvolumeclaim-v1-core) array_ | _(Required)_
ClaimTemplates allows adding additional VolumeClaimTemplates for VMAgent in StatefulMode | | configMaps#
_string array_ | _(Optional)_
ConfigMaps is a list of ConfigMaps in the same namespace as the Application
object, which shall be mounted into the Application container
at /etc/vm/configs/CONFIGMAP_NAME folder | | configReloadAuthKeySecret#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
ConfigReloadAuthKeySecret defines optional secret reference authKey for /-/reload API requests.
Given secret reference will be added to the application and vm-config-reloader as volume
available since v0.57.0 version | @@ -3735,10 +3735,10 @@ Appears in: [VMAgent](#vmagent) | disableSelfServiceScrape#
_boolean_ | _(Optional)_
DisableSelfServiceScrape controls creation of VMServiceScrape by operator
for the application.
Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable | | dnsConfig#
_[PodDNSConfig](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#poddnsconfig-v1-core)_ | _(Optional)_
Specifies the DNS parameters of a pod.
Parameters specified here will be merged to the generated DNS
configuration based on DNSPolicy. | | dnsPolicy#
_[DNSPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#dnspolicy-v1-core)_ | _(Optional)_
DNSPolicy sets DNS policy for the pod | -| enableKubernetesAPISelectors#
_boolean_ | _(Optional)_
EnableKubernetesAPISelectors instructs vmagent to use CRD scrape objects spec.selectors for
Kubernetes API list and watch requests.
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering
It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. | +| enableKubernetesAPISelectors#
_boolean_ | _(Optional)_
EnableKubernetesAPISelectors instructs vmagent or vmsingle to use CRD scrape objects spec.selectors for
Kubernetes API list and watch requests.
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering
It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. | | enforcedNamespaceLabel#
_string_ | _(Optional)_
EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert
and metric that is user created. The label value will always be the namespace of the object that is
being created. | | externalLabelName#
_string_ | _(Optional)_
ExternalLabelName Name of external label used to denote scraping agent instance
name. Defaults to the value of `prometheus`. External label will
_not_ be added when value is set to empty string (`""`). | -| externalLabels#
_object (keys:string, values:string)_ | _(Optional)_
ExternalLabels The labels to add to any time series scraped by vmagent.
it doesn't affect metrics ingested directly by push API's | +| externalLabels#
_object (keys:string, values:string)_ | _(Optional)_
ExternalLabels The labels to add to any time series scraped by vmagent or vmsingle.
it doesn't affect metrics ingested directly by push API's | | extraArgs#
_object (keys:string, values:string)_ | _(Optional)_
ExtraArgs that will be passed to the application container
for example remoteWrite.tmpDataPath: /tmp | | extraEnvs#
_[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#envvar-v1-core) array_ | _(Optional)_
ExtraEnvs that will be passed to the application container | | extraEnvsFrom#
_[EnvFromSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#envfromsource-v1-core) array_ | _(Optional)_
ExtraEnvsFrom defines source of env variables for the application container
could either be secret or configmap | @@ -3750,10 +3750,10 @@ Appears in: [VMAgent](#vmagent) | ignoreNamespaceSelectors#
_boolean_ | _(Optional)_
IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from
scrape objects, and they will only discover endpoints
within their current namespace. Defaults to false. | | image#
_[Image](#image)_ | _(Optional)_
Image - docker image settings
if no specified operator uses default version from operator config | | imagePullSecrets#
_[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#localobjectreference-v1-core) array_ | _(Optional)_
ImagePullSecrets An optional list of references to secrets in the same namespace
to use for pulling images from registries
see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod | -| ingestOnlyMode#
_boolean_ | _(Optional)_
IngestOnlyMode switches vmagent into unmanaged mode
it disables any config generation for scraping
Currently it prevents vmagent from managing tls and auth options for remote write | +| ingestOnlyMode#
_boolean_ | _(Optional)_
IngestOnlyMode switches vmagent or vmsingle into unmanaged mode
it disables any config generation for scraping
Currently it prevents vmagent or vmsingle from managing tls and auth options for remote write | | initContainers#
_[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#container-v1-core) array_ | _(Optional)_
InitContainers allows adding initContainers to the pod definition.
Any errors during the execution of an initContainer will lead to a restart of the Pod.
More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | | inlineRelabelConfig#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
InlineRelabelConfig - defines GlobalRelabelConfig for vmagent, can be defined directly at CRD. | -| inlineScrapeConfig#
_string_ | _(Optional)_
InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent. It is advised to review VMAgent release
notes to ensure that no incompatible scrape configs are going to break
VMAgent after the upgrade.
it should be defined as single yaml file.
inlineScrapeConfig: \|
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"] | +| inlineScrapeConfig#
_string_ | _(Optional)_
InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release
notes to ensure that no incompatible scrape configs are going to break
VMAgent or VMSingle after the upgrade.
it should be defined as single yaml file.
inlineScrapeConfig: \|
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"] | | insertPorts#
_[InsertPorts](#insertports)_ | _(Required)_
InsertPorts - additional listen ports for data ingestion. | | license#
_[License](#license)_ | _(Optional)_
License allows to configure license key to be used for enterprise features.
Using license key is supported starting from VictoriaMetrics v1.94.0.
See [here](https://docs.victoriametrics.com/victoriametrics/enterprise/) | | logFormat#
_string_ | _(Optional)_
LogFormat for VMAgent to be configured with. | @@ -3762,9 +3762,9 @@ Appears in: [VMAgent](#vmagent) | maxScrapeInterval#
_string_ | _(Required)_
MaxScrapeInterval allows limiting maximum scrape interval for VMServiceScrape, VMPodScrape and other scrapes
If interval is higher than defined limit, `maxScrapeInterval` will be used. | | minReadySeconds#
_integer_ | _(Optional)_
MinReadySeconds defines a minimum number of seconds to wait before starting update next pod
if previous in healthy state
Has no effect for VLogs and VMSingle | | minScrapeInterval#
_string_ | _(Required)_
MinScrapeInterval allows limiting minimal scrape interval for VMServiceScrape, VMPodScrape and other scrapes
If interval is lower than defined limit, `minScrapeInterval` will be used. | -| nodeScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| nodeScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | nodeScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
NodeScrapeRelabelTemplate defines relabel config, that will be added to each VMNodeScrape.
it's useful for adding specific labels to all targets | -| nodeScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeSelector defines VMNodeScrape to be selected for scraping.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| nodeScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeSelector defines VMNodeScrape to be selected for scraping.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | nodeSelector#
_object (keys:string, values:string)_ | _(Optional)_
NodeSelector Define which Nodes the Pods are scheduled on. | | overrideHonorLabels#
_boolean_ | _(Optional)_
OverrideHonorLabels if set to true overrides all user configured honor_labels.
If HonorLabels is set in scrape objects to true, this overrides honor_labels to false. | | overrideHonorTimestamps#
_boolean_ | _(Optional)_
OverrideHonorTimestamps allows to globally enforce honoring timestamps in all scrape configs. | @@ -3772,14 +3772,14 @@ Appears in: [VMAgent](#vmagent) | persistentVolumeClaimRetentionPolicy#
_[StatefulSetPersistentVolumeClaimRetentionPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#statefulsetpersistentvolumeclaimretentionpolicy-v1-apps)_ | _(Optional)_
PersistentVolumeClaimRetentionPolicy allows configuration of PVC retention policy | | podDisruptionBudget#
_[EmbeddedPodDisruptionBudgetSpec](#embeddedpoddisruptionbudgetspec)_ | _(Optional)_
PodDisruptionBudget created by operator | | podMetadata#
_[EmbeddedObjectMetadata](#embeddedobjectmetadata)_ | _(Optional)_
PodMetadata configures Labels and Annotations which are propagated to the vmagent pods. | -| podScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| podScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | podScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
PodScrapeRelabelTemplate defines relabel config, that will be added to each VMPodScrape.
it's useful for adding specific labels to all targets | -| podScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeSelector defines PodScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| podScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeSelector defines PodScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | port#
_string_ | _(Optional)_
Port listen address | | priorityClassName#
_string_ | _(Optional)_
PriorityClassName class assigned to the Pods | -| probeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| probeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | probeScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ProbeScrapeRelabelTemplate defines relabel config, that will be added to each VMProbeScrape.
it's useful for adding specific labels to all targets | -| probeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeSelector defines VMProbe to be selected for target probing.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| probeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeSelector defines VMProbe to be selected for target probing.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | readinessGates#
_[PodReadinessGate](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#podreadinessgate-v1-core) array_ | _(Required)_
ReadinessGates defines pod readiness gates | | relabelConfig#
_[ConfigMapKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#configmapkeyselector-v1-core)_ | _(Optional)_
RelabelConfig ConfigMap with global relabel config -remoteWrite.relabelConfig
This relabeling is applied to all the collected metrics before sending them to remote storage. | | remoteWrite#
_[VMAgentRemoteWriteSpec](#vmagentremotewritespec) array_ | _(Required)_
RemoteWrite list of victoria metrics /some other remote write system
for vm it must looks like: http://victoria-metrics-single:8428/api/v1/write
or for cluster different url
https://docs.victoriametrics.com/victoriametrics/vmagent/#splitting-data-streams-among-multiple-systems | @@ -3792,7 +3792,7 @@ Appears in: [VMAgent](#vmagent) | sampleLimit#
_integer_ | _(Optional)_
SampleLimit defines global per target limit of scraped samples | | schedulerName#
_string_ | _(Optional)_
SchedulerName - defines kubernetes scheduler name | | scrapeClasses#
_[ScrapeClass](#scrapeclass) array_ | _(Optional)_
ScrapeClasses defines the list of scrape classes to expose to scraping objects such as
PodScrapes, ServiceScrapes, Probes and ScrapeConfigs. | -| scrapeConfigNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| scrapeConfigNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | scrapeConfigRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ScrapeConfigRelabelTemplate defines relabel config, that will be added to each VMScrapeConfig.
it's useful for adding specific labels to all targets | | scrapeConfigSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigSelector defines VMScrapeConfig to be selected for target discovery.
Works in combination with NamespaceSelector. | | scrapeInterval#
_string_ | _(Optional)_
ScrapeInterval defines how often scrape targets by default | @@ -3801,18 +3801,18 @@ Appears in: [VMAgent](#vmagent) | securityContext#
_[SecurityContext](#securitycontext)_ | _(Optional)_
SecurityContext holds pod-level security attributes and common container settings.
This defaults to the default PodSecurityContext. | | selectAllByDefault#
_boolean_ | _(Optional)_
SelectAllByDefault changes default behavior for empty CRD selectors, such ServiceScrapeSelector.
with selectAllByDefault: true and empty serviceScrapeSelector and ServiceScrapeNamespaceSelector
Operator selects all exist serviceScrapes
with selectAllByDefault: false - selects nothing | | serviceAccountName#
_string_ | _(Optional)_
ServiceAccountName is the name of the ServiceAccount to use to run the pods | -| serviceScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| serviceScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | serviceScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ServiceScrapeRelabelTemplate defines relabel config, that will be added to each VMServiceScrape.
it's useful for adding specific labels to all targets | -| serviceScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| serviceScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | serviceScrapeSpec#
_[VMServiceScrapeSpec](#vmservicescrapespec)_ | _(Optional)_
ServiceScrapeSpec that will be added to vmagent VMServiceScrape spec | | serviceSpec#
_[AdditionalServiceSpec](#additionalservicespec)_ | _(Optional)_
ServiceSpec that will be added to vmagent service spec | | shardCount#
_integer_ | _(Optional)_
ShardCount - numbers of shards of VMAgent
in this case operator will use 1 deployment/sts per shard with
replicas count according to spec.replicas,
see [here](https://docs.victoriametrics.com/victoriametrics/vmagent/#scraping-big-number-of-targets) | | statefulMode#
_boolean_ | _(Optional)_
StatefulMode enables StatefulSet for `VMAgent` instead of Deployment
it allows using persistent storage for vmagent's persistentQueue | | statefulRollingUpdateStrategy#
_[StatefulSetUpdateStrategyType](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#statefulsetupdatestrategytype-v1-apps)_ | _(Optional)_
StatefulRollingUpdateStrategy allows configuration for strategyType
set it to RollingUpdate for disabling operator statefulSet rollingUpdate | | statefulStorage#
_[StorageSpec](#storagespec)_ | _(Optional)_
StatefulStorage configures storage for StatefulSet | -| staticScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| staticScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | staticScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
StaticScrapeRelabelTemplate defines relabel config, that will be added to each VMStaticScrape.
it's useful for adding specific labels to all targets | -| staticScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeSelector defines VMStaticScrape to be selected for target discovery.
Works in combination with NamespaceSelector.
If both nil - match everything.
NamespaceSelector nil - only objects at VMAgent namespace.
Selector nil - only objects at NamespaceSelector namespaces. | +| staticScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeSelector defines VMStaticScrape to be selected for target discovery.
Works in combination with NamespaceSelector.
If both nil - match everything.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces. | | streamAggrConfig#
_[StreamAggrConfig](#streamaggrconfig)_ | _(Optional)_
StreamAggrConfig defines global stream aggregation configuration for VMAgent | | terminationGracePeriodSeconds#
_integer_ | _(Optional)_
TerminationGracePeriodSeconds period for container graceful termination | | tolerations#
_[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#toleration-v1-core) array_ | _(Optional)_
Tolerations If specified, the pod's tolerations. | @@ -4578,7 +4578,7 @@ Appears in: [VMNodeScrape](#vmnodescrape) | bearerTokenSecret#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
Secret to mount to read bearer token for scraping targets. The secret
needs to be in the same namespace as the scrape object and accessible by
the victoria-metrics operator. | | follow_redirects#
_boolean_ | _(Optional)_
FollowRedirects controls redirects for scraping. | | honorLabels#
_boolean_ | _(Optional)_
HonorLabels chooses the metric's labels on collisions with target labels. | -| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | +| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. | | interval#
_string_ | _(Optional)_
Interval at which metrics should be scraped | | jobLabel#
_string_ | _(Optional)_
The label to use to retrieve the job name from. | | max_scrape_size#
_string_ | _(Optional)_
MaxScrapeSize defines a maximum size of scraped data for a job | @@ -4674,7 +4674,7 @@ Appears in: [VMProbe](#vmprobe) | bearerTokenSecret#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
Secret to mount to read bearer token for scraping targets. The secret
needs to be in the same namespace as the scrape object and accessible by
the victoria-metrics operator. | | follow_redirects#
_boolean_ | _(Optional)_
FollowRedirects controls redirects for scraping. | | honorLabels#
_boolean_ | _(Optional)_
HonorLabels chooses the metric's labels on collisions with target labels. | -| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | +| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. | | interval#
_string_ | _(Optional)_
Interval at which metrics should be scraped | | jobName#
_string_ | _(Required)_
The job name assigned to scraped metrics by default. | | max_scrape_size#
_string_ | _(Optional)_
MaxScrapeSize defines a maximum size of scraped data for a job | @@ -4852,7 +4852,7 @@ Appears in: [VMScrapeConfig](#vmscrapeconfig) | follow_redirects#
_boolean_ | _(Optional)_
FollowRedirects controls redirects for scraping. | | gceSDConfigs#
_[GCESDConfig](#gcesdconfig) array_ | _(Optional)_
GCESDConfigs defines a list of GCE service discovery configurations. | | honorLabels#
_boolean_ | _(Optional)_
HonorLabels chooses the metric's labels on collisions with target labels. | -| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | +| honorTimestamps#
_boolean_ | _(Optional)_
HonorTimestamps controls whether vmagent or vmsingle respects the timestamps present in scraped data. | | httpSDConfigs#
_[HTTPSDConfig](#httpsdconfig) array_ | _(Optional)_
HTTPSDConfigs defines a list of HTTP service discovery configurations. | | interval#
_string_ | _(Optional)_
Interval at which metrics should be scraped | | kubernetesSDConfigs#
_[KubernetesSDConfig](#kubernetessdconfig) array_ | _(Optional)_
KubernetesSDConfigs defines a list of Kubernetes service discovery configurations. | @@ -4889,7 +4889,7 @@ Appears in: [Endpoint](#endpoint), [EndpointScrapeParams](#endpointscrapeparams) | --- | --- | | disable_compression#
_boolean_ | _(Optional)_
DisableCompression | | disable_keep_alive#
_boolean_ | _(Optional)_
disable_keepalive allows disabling HTTP keep-alive when scraping targets.
By default, HTTP keep-alive is enabled, so TCP connections to scrape targets
could be reused.
See https://docs.victoriametrics.com/victoriametrics/vmagent/#scrape_config-enhancements | -| headers#
_string array_ | _(Optional)_
Headers allows sending custom headers to scrape targets
must be in of semicolon separated header with it's value
eg:
headerName: headerValue
vmagent supports since 1.79.0 version | +| headers#
_string array_ | _(Optional)_
Headers allows sending custom headers to scrape targets
must be in of semicolon separated header with it's value
eg:
headerName: headerValue
vmagent and vmsingle support since 1.79.0 version | | no_stale_markers#
_boolean_ | _(Optional)_
| | proxy_client_config#
_[ProxyAuth](#proxyauth)_ | _(Optional)_
ProxyClientConfig configures proxy auth settings for scraping
See feature description https://docs.victoriametrics.com/victoriametrics/vmagent/#scraping-targets-via-a-proxy | | scrape_align_interval#
_string_ | _(Optional)_
| @@ -5028,46 +5028,92 @@ Appears in: [VMSingle](#vmsingle) | Field | Description | | --- | --- | +| additionalScrapeConfigs#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release
notes to ensure that no incompatible scrape configs are going to break
VMAgent or VMSingle after the upgrade. | | affinity#
_[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#affinity-v1-core)_ | _(Optional)_
Affinity If specified, the pod's scheduling constraints. | +| apiServerConfig#
_[APIServerConfig](#apiserverconfig)_ | _(Optional)_
APIServerConfig allows specifying a host and auth methods to access apiserver.
If left empty, VMSingle is assumed to run inside of the cluster
and will discover API servers automatically and use the pod's CA certificate
and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. | +| arbitraryFSAccessThroughSMs#
_[ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig)_ | _(Optional)_
ArbitraryFSAccessThroughSMs configures whether configuration
based on EndpointAuth can access arbitrary files on the file system
of the VMAgent or VMSingle container e.g. bearer token files, basic auth, tls certs | | configMaps#
_string array_ | _(Optional)_
ConfigMaps is a list of ConfigMaps in the same namespace as the Application
object, which shall be mounted into the Application container
at /etc/vm/configs/CONFIGMAP_NAME folder | +| configReloadAuthKeySecret#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#secretkeyselector-v1-core)_ | _(Optional)_
ConfigReloadAuthKeySecret defines optional secret reference authKey for /-/reload API requests.
Given secret reference will be added to the application and vm-config-reloader as volume
available since v0.57.0 version | +| configReloaderExtraArgs#
_object (keys:string, values:string)_ | _(Optional)_
ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container
for example resync-interval: "30s" | +| configReloaderImage#
_string_ | _(Optional)_
ConfigReloaderImage defines image:tag for config-reloader container | +| configReloaderImageTag#
_string_ | _(Optional)_
ConfigReloaderImageTag defines image:tag for config-reloader container
Deprecated: since version v0.67.0 will be removed in v0.69.0 use configReloaderImage instead
| +| configReloaderResources#
_[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#resourcerequirements-v1-core)_ | _(Optional)_
ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
if not defined default resources from operator config will be used | | containers#
_[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#container-v1-core) array_ | _(Optional)_
Containers property allows to inject additions sidecars or to patch existing containers.
It can be useful for proxies, backup, etc. | | disableAutomountServiceAccountToken#
_boolean_ | _(Optional)_
DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0).
Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access.
For example, vmagent and vm-config-reloader requires k8s API access.
Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed.
And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. | | disableSelfServiceScrape#
_boolean_ | _(Optional)_
DisableSelfServiceScrape controls creation of VMServiceScrape by operator
for the application.
Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable | | dnsConfig#
_[PodDNSConfig](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#poddnsconfig-v1-core)_ | _(Optional)_
Specifies the DNS parameters of a pod.
Parameters specified here will be merged to the generated DNS
configuration based on DNSPolicy. | | dnsPolicy#
_[DNSPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#dnspolicy-v1-core)_ | _(Optional)_
DNSPolicy sets DNS policy for the pod | +| enableKubernetesAPISelectors#
_boolean_ | _(Optional)_
EnableKubernetesAPISelectors instructs vmagent or vmsingle to use CRD scrape objects spec.selectors for
Kubernetes API list and watch requests.
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering
It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. | +| enforcedNamespaceLabel#
_string_ | _(Optional)_
EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert
and metric that is user created. The label value will always be the namespace of the object that is
being created. | +| externalLabelName#
_string_ | _(Optional)_
ExternalLabelName Name of external label used to denote scraping agent instance
name. Defaults to the value of `prometheus`. External label will
_not_ be added when value is set to empty string (`""`). | +| externalLabels#
_object (keys:string, values:string)_ | _(Optional)_
ExternalLabels The labels to add to any time series scraped by vmagent or vmsingle.
it doesn't affect metrics ingested directly by push API's | | extraArgs#
_object (keys:string, values:string)_ | _(Optional)_
ExtraArgs that will be passed to the application container
for example remoteWrite.tmpDataPath: /tmp | | extraEnvs#
_[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#envvar-v1-core) array_ | _(Optional)_
ExtraEnvs that will be passed to the application container | | extraEnvsFrom#
_[EnvFromSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#envfromsource-v1-core) array_ | _(Optional)_
ExtraEnvsFrom defines source of env variables for the application container
could either be secret or configmap | +| globalScrapeMetricRelabelConfigs#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
GlobalScrapeMetricRelabelConfigs is a global metric relabel configuration, which is applied to each scrape job. | +| globalScrapeRelabelConfigs#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
GlobalScrapeRelabelConfigs is a global relabel configuration, which is applied to each samples of each scrape job during service discovery. | | hostAliases#
_[HostAlias](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#hostalias-v1-core) array_ | _(Optional)_
HostAliases provides mapping for ip and hostname,
that would be propagated to pod,
cannot be used with HostNetwork. | | hostNetwork#
_boolean_ | _(Optional)_
HostNetwork controls whether the pod may use the node network namespace | | host_aliases#
_[HostAlias](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#hostalias-v1-core) array_ | _(Optional)_
HostAliasesUnderScore provides mapping for ip and hostname,
that would be propagated to pod,
cannot be used with HostNetwork.
Has Priority over hostAliases field | +| ignoreNamespaceSelectors#
_boolean_ | _(Optional)_
IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from
scrape objects, and they will only discover endpoints
within their current namespace. Defaults to false. | | image#
_[Image](#image)_ | _(Optional)_
Image - docker image settings
if no specified operator uses default version from operator config | | imagePullSecrets#
_[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#localobjectreference-v1-core) array_ | _(Optional)_
ImagePullSecrets An optional list of references to secrets in the same namespace
to use for pulling images from registries
see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod | +| ingestOnlyMode#
_boolean_ | _(Optional)_
IngestOnlyMode switches vmagent or vmsingle into unmanaged mode
it disables any config generation for scraping
Currently it prevents vmagent or vmsingle from managing tls and auth options for remote write | | initContainers#
_[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#container-v1-core) array_ | _(Optional)_
InitContainers allows adding initContainers to the pod definition.
Any errors during the execution of an initContainer will lead to a restart of the Pod.
More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | +| inlineRelabelConfig#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
InlineRelabelConfig - defines GlobalRelabelConfig for vmagent, can be defined directly at CRD. | +| inlineScrapeConfig#
_string_ | _(Optional)_
InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it
is valid. Note that using this feature may expose the possibility to
break upgrades of VMAgent or VMSingle. It is advised to review VMAgent or VMSingle release
notes to ensure that no incompatible scrape configs are going to break
VMAgent or VMSingle after the upgrade.
it should be defined as single yaml file.
inlineScrapeConfig: \|
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"] | | insertPorts#
_[InsertPorts](#insertports)_ | _(Required)_
InsertPorts - additional listen ports for data ingestion. | | license#
_[License](#license)_ | _(Optional)_
License allows to configure license key to be used for enterprise features.
Using license key is supported starting from VictoriaMetrics v1.94.0.
See [here](https://docs.victoriametrics.com/victoriametrics/enterprise/) | | logFormat#
_string_ | _(Optional)_
LogFormat for VMSingle to be configured with. | | logLevel#
_string_ | _(Optional)_
LogLevel for victoria metrics single to be configured with. | | managedMetadata#
_[ManagedObjectsMetadata](#managedobjectsmetadata)_ | _(Required)_
ManagedMetadata defines metadata that will be added to the all objects
created by operator for the given CustomResource | +| maxScrapeInterval#
_string_ | _(Required)_
MaxScrapeInterval allows limiting maximum scrape interval for VMServiceScrape, VMPodScrape and other scrapes
If interval is higher than defined limit, `maxScrapeInterval` will be used. | | minReadySeconds#
_integer_ | _(Optional)_
MinReadySeconds defines a minimum number of seconds to wait before starting update next pod
if previous in healthy state
Has no effect for VLogs and VMSingle | +| minScrapeInterval#
_string_ | _(Required)_
MinScrapeInterval allows limiting minimal scrape interval for VMServiceScrape, VMPodScrape and other scrapes
If interval is lower than defined limit, `minScrapeInterval` will be used. | +| nodeScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| nodeScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
NodeScrapeRelabelTemplate defines relabel config, that will be added to each VMNodeScrape.
it's useful for adding specific labels to all targets | +| nodeScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
NodeScrapeSelector defines VMNodeScrape to be selected for scraping.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | nodeSelector#
_object (keys:string, values:string)_ | _(Optional)_
NodeSelector Define which Nodes the Pods are scheduled on. | +| overrideHonorLabels#
_boolean_ | _(Optional)_
OverrideHonorLabels if set to true overrides all user configured honor_labels.
If HonorLabels is set in scrape objects to true, this overrides honor_labels to false. | +| overrideHonorTimestamps#
_boolean_ | _(Optional)_
OverrideHonorTimestamps allows to globally enforce honoring timestamps in all scrape configs. | | paused#
_boolean_ | _(Optional)_
Paused If set to true all actions on the underlying managed objects are not
going to be performed, except for delete actions. | | podMetadata#
_[EmbeddedObjectMetadata](#embeddedobjectmetadata)_ | _(Optional)_
PodMetadata configures Labels and Annotations which are propagated to the VMSingle pods. | +| podScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| podScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
PodScrapeRelabelTemplate defines relabel config, that will be added to each VMPodScrape.
it's useful for adding specific labels to all targets | +| podScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
PodScrapeSelector defines PodScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | port#
_string_ | _(Optional)_
Port listen address | | priorityClassName#
_string_ | _(Optional)_
PriorityClassName class assigned to the Pods | +| probeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| probeScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ProbeScrapeRelabelTemplate defines relabel config, that will be added to each VMProbeScrape.
it's useful for adding specific labels to all targets | +| probeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ProbeSelector defines VMProbe to be selected for target probing.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | readinessGates#
_[PodReadinessGate](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#podreadinessgate-v1-core) array_ | _(Required)_
ReadinessGates defines pod readiness gates | +| relabelConfig#
_[ConfigMapKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#configmapkeyselector-v1-core)_ | _(Optional)_
RelabelConfig ConfigMap with global relabel config -remoteWrite.relabelConfig
This relabeling is applied to all the collected metrics before sending them to remote storage. | | removePvcAfterDelete#
_boolean_ | _(Optional)_
RemovePvcAfterDelete - if true, controller adds ownership to pvc
and after VMSingle object deletion - pvc will be garbage collected
by controller manager | | replicaCount#
_integer_ | _(Optional)_
ReplicaCount is the expected size of the Application. | | resources#
_[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#resourcerequirements-v1-core)_ | _(Optional)_
Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
if not defined default resources from operator config will be used | | retentionPeriod#
_string_ | _(Optional)_
RetentionPeriod defines how long to retain stored metrics, specified as a duration (e.g., "1d", "1w", "1m").
Data with timestamps outside the RetentionPeriod is automatically deleted. The minimum allowed value is 1d, or 24h.
The default value is 1 (one month).
See [retention](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#retention) docs for details. | | revisionHistoryLimitCount#
_integer_ | _(Optional)_
The number of old ReplicaSets to retain to allow rollback in deployment or
maximum number of revisions that will be maintained in the Deployment revision history.
Has no effect at StatefulSets
Defaults to 10. | | runtimeClassName#
_string_ | _(Optional)_
RuntimeClassName - defines runtime class for kubernetes pod.
https://kubernetes.io/docs/concepts/containers/runtime-class/ | +| sampleLimit#
_integer_ | _(Optional)_
SampleLimit defines global per target limit of scraped samples | | schedulerName#
_string_ | _(Optional)_
SchedulerName - defines kubernetes scheduler name | +| scrapeClasses#
_[ScrapeClass](#scrapeclass) array_ | _(Optional)_
ScrapeClasses defines the list of scrape classes to expose to scraping objects such as
PodScrapes, ServiceScrapes, Probes and ScrapeConfigs. | +| scrapeConfigNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| scrapeConfigRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ScrapeConfigRelabelTemplate defines relabel config, that will be added to each VMScrapeConfig.
it's useful for adding specific labels to all targets | +| scrapeConfigSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ScrapeConfigSelector defines VMScrapeConfig to be selected for target discovery.
Works in combination with NamespaceSelector. | +| scrapeInterval#
_string_ | _(Optional)_
ScrapeInterval defines how often scrape targets by default | +| scrapeTimeout#
_string_ | _(Optional)_
ScrapeTimeout defines global timeout for targets scrape | | secrets#
_string array_ | _(Optional)_
Secrets is a list of Secrets in the same namespace as the Application
object, which shall be mounted into the Application container
at /etc/vm/secrets/SECRET_NAME folder | | securityContext#
_[SecurityContext](#securitycontext)_ | _(Optional)_
SecurityContext holds pod-level security attributes and common container settings.
This defaults to the default PodSecurityContext. | +| selectAllByDefault#
_boolean_ | _(Optional)_
SelectAllByDefault changes default behavior for empty CRD selectors, such ServiceScrapeSelector.
with selectAllByDefault: true and empty serviceScrapeSelector and ServiceScrapeNamespaceSelector
Operator selects all exist serviceScrapes
with selectAllByDefault: false - selects nothing | | serviceAccountName#
_string_ | _(Optional)_
ServiceAccountName is the name of the ServiceAccount to use to run the pods | +| serviceScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery.
Works in combination with Selector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| serviceScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
ServiceScrapeRelabelTemplate defines relabel config, that will be added to each VMServiceScrape.
it's useful for adding specific labels to all targets | +| serviceScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | | serviceScrapeSpec#
_[VMServiceScrapeSpec](#vmservicescrapespec)_ | _(Optional)_
ServiceScrapeSpec that will be added to vmsingle VMServiceScrape spec | | serviceSpec#
_[AdditionalServiceSpec](#additionalservicespec)_ | _(Optional)_
ServiceSpec that will be added to vmsingle service spec | +| staticScrapeNamespaceSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery.
Works in combination with NamespaceSelector.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces.
If both nil - behaviour controlled by selectAllByDefault | +| staticScrapeRelabelTemplate#
_[RelabelConfig](#relabelconfig) array_ | _(Optional)_
StaticScrapeRelabelTemplate defines relabel config, that will be added to each VMStaticScrape.
it's useful for adding specific labels to all targets | +| staticScrapeSelector#
_[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | _(Optional)_
StaticScrapeSelector defines VMStaticScrape to be selected for target discovery.
Works in combination with NamespaceSelector.
If both nil - match everything.
NamespaceSelector nil - only objects at VMAgent or VMSingle namespace.
Selector nil - only objects at NamespaceSelector namespaces. | | storage#
_[PersistentVolumeClaimSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#persistentvolumeclaimspec-v1-core)_ | _(Optional)_
Storage is the definition of how storage will be used by the VMSingle
by default it`s empty dir
this option is ignored if storageDataPath is set | | storageDataPath#
_string_ | _(Optional)_
StorageDataPath disables spec.storage option and overrides arg for victoria-metrics binary --storageDataPath,
its users responsibility to mount proper device into given path.
It requires to provide spec.volumes and spec.volumeMounts with at least 1 value | | storageMetadata#
_[EmbeddedObjectMetadata](#embeddedobjectmetadata)_ | _(Optional)_
StorageMeta defines annotations and labels attached to PVC for given vmsingle CR | @@ -5077,6 +5123,8 @@ Appears in: [VMSingle](#vmsingle) | topologySpreadConstraints#
_[TopologySpreadConstraint](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#topologyspreadconstraint-v1-core) array_ | _(Optional)_
TopologySpreadConstraints embedded kubernetes pod configuration option,
controls how pods are spread across your cluster among failure-domains
such as regions, zones, nodes, and other user-defined topology domains
https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ | | useDefaultResources#
_boolean_ | _(Optional)_
UseDefaultResources controls resource settings
By default, operator sets built-in resource requirements | | useStrictSecurity#
_boolean_ | _(Optional)_
UseStrictSecurity enables strict security mode for component
it restricts disk writes access
uses non-root user out of the box
drops not needed security permissions | +| useVMConfigReloader#
_boolean_ | _(Optional)_
UseVMConfigReloader replaces prometheus-like config-reloader
with vm one. It uses secrets watch instead of file watch
which greatly increases speed of config updates
Removed since v0.67.0: this property is ignored and no longer needed | +| vmAgentExternalLabelName#
_string_ | _(Optional)_
VMAgentExternalLabelName Name of vmAgent external label used to denote vmAgent instance
name. Defaults to the value of `prometheus`. External label will
_not_ be added when value is set to empty string (`""`).
Deprecated: since version v0.67.0 will be removed in v0.69.0 use externalLabelName instead
| | vmBackup#
_[VMBackup](#vmbackup)_ | _(Optional)_
VMBackup configuration for backup | | volumeMounts#
_[VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#volumemount-v1-core) array_ | _(Optional)_
VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition.
VolumeMounts specified will be appended to other VolumeMounts in the Application container | | volumes#
_[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#volume-v1-core) array_ | _(Required)_
Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition.
Volumes specified will be appended to other volumes that are generated.
/ +optional | diff --git a/internal/controller/operator/factory/build/defaults.go b/internal/controller/operator/factory/build/defaults.go index 8a04d6471..d6075dd6a 100644 --- a/internal/controller/operator/factory/build/defaults.go +++ b/internal/controller/operator/factory/build/defaults.go @@ -261,9 +261,13 @@ func addVMSingleDefaults(objI any) { useBackupDefaultResources := c.VMBackup.UseDefaultResources cv := config.ApplicationDefaults(c.VMSingle) addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, cr.Spec.License, &cv) + addDefaultsToConfigReloader(&cr.Spec.CommonConfigReloaderParams, ptr.Deref(cr.Spec.UseDefaultResources, false)) if cr.Spec.UseDefaultResources != nil { useBackupDefaultResources = *cr.Spec.UseDefaultResources } + if cr.Spec.IngestOnlyMode == nil { + cr.Spec.IngestOnlyMode = ptr.To(true) + } bv := config.ApplicationDefaults(c.VMBackup) addDefaultsToVMBackup(cr.Spec.VMBackup, useBackupDefaultResources, &bv) } diff --git a/internal/controller/operator/factory/finalize/vmagent.go b/internal/controller/operator/factory/finalize/vmagent.go index b2cdb81d3..5b3a07fe9 100644 --- a/internal/controller/operator/factory/finalize/vmagent.go +++ b/internal/controller/operator/factory/finalize/vmagent.go @@ -68,24 +68,24 @@ func OnVMAgentDelete(ctx context.Context, rclient client.Client, cr *vmv1beta1.V } // remove vmagents service discovery rbac. if config.IsClusterWideAccessAllowed() { - if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.ClusterRoleBinding{}, cr.GetClusterRoleName(), cr.GetNamespace()); err != nil { + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.ClusterRoleBinding{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { return err } - if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.ClusterRole{}, cr.GetClusterRoleName(), cr.GetNamespace()); err != nil { + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.ClusterRole{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { return err } - if err := SafeDelete(ctx, rclient, &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: cr.GetClusterRoleName(), Namespace: cr.GetNamespace()}}); err != nil { + if err := SafeDelete(ctx, rclient, &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: cr.GetRBACName(), Namespace: cr.GetNamespace()}}); err != nil { return err } - if err := SafeDelete(ctx, rclient, &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: cr.GetClusterRoleName(), Namespace: cr.GetNamespace()}}); err != nil { + if err := SafeDelete(ctx, rclient, &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: cr.GetRBACName(), Namespace: cr.GetNamespace()}}); err != nil { return err } } else { - if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.RoleBinding{}, cr.GetClusterRoleName(), cr.GetNamespace()); err != nil { + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.RoleBinding{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { return err } - if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.Role{}, cr.GetClusterRoleName(), cr.GetNamespace()); err != nil { + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.Role{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { return err } } diff --git a/internal/controller/operator/factory/finalize/vmauth.go b/internal/controller/operator/factory/finalize/vmauth.go index 839b8a594..2bc7ca35e 100644 --- a/internal/controller/operator/factory/finalize/vmauth.go +++ b/internal/controller/operator/factory/finalize/vmauth.go @@ -72,6 +72,12 @@ func OnVMAuthDelete(ctx context.Context, rclient client.Client, cr *vmv1beta1.VM } } + if cfg.VPAAPIEnabled { + if err := removeFinalizeObjByName(ctx, rclient, &vpav1.VerticalPodAutoscaler{}, cr.PrefixedName(), cr.Namespace); err != nil { + return err + } + } + if err := deleteSA(ctx, rclient, cr); err != nil { return err } diff --git a/internal/controller/operator/factory/finalize/vmsingle.go b/internal/controller/operator/factory/finalize/vmsingle.go index d7f9cb0b2..2eec746f3 100644 --- a/internal/controller/operator/factory/finalize/vmsingle.go +++ b/internal/controller/operator/factory/finalize/vmsingle.go @@ -5,9 +5,12 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" + "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" ) @@ -31,9 +34,39 @@ func OnVMSingleDelete(ctx context.Context, rclient client.Client, cr *vmv1beta1. return err } } + if err := removeFinalizeObjByName(ctx, rclient, &corev1.ConfigMap{}, build.ResourceName(build.RelabelConfigResourceKind, cr), cr.Namespace); err != nil { + return err + } if err := removeFinalizeObjByName(ctx, rclient, &corev1.ConfigMap{}, build.ResourceName(build.StreamAggrConfigResourceKind, cr), cr.Namespace); err != nil { return err } + if config.IsClusterWideAccessAllowed() { + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.ClusterRoleBinding{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { + return err + } + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.ClusterRole{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { + return err + } + if err := SafeDelete(ctx, rclient, &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: cr.GetRBACName(), Namespace: cr.GetNamespace()}}); err != nil { + return err + } + if err := SafeDelete(ctx, rclient, &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: cr.GetRBACName(), Namespace: cr.GetNamespace()}}); err != nil { + return err + } + } else { + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.RoleBinding{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { + return err + } + if err := removeFinalizeObjByName(ctx, rclient, &rbacv1.Role{}, cr.GetRBACName(), cr.GetNamespace()); err != nil { + return err + } + } + + if cr.Spec.AdditionalScrapeConfigs != nil { + if err := removeFinalizeObjByName(ctx, rclient, &corev1.Secret{}, cr.Spec.AdditionalScrapeConfigs.Name, cr.Namespace); err != nil { + return err + } + } if err := deleteSA(ctx, rclient, cr); err != nil { return err } diff --git a/internal/controller/operator/factory/vmagent/rbac.go b/internal/controller/operator/factory/vmagent/rbac.go index eb6057ea3..d8d6cd773 100644 --- a/internal/controller/operator/factory/vmagent/rbac.go +++ b/internal/controller/operator/factory/vmagent/rbac.go @@ -103,7 +103,7 @@ func createK8sAPIAccess(ctx context.Context, rclient client.Client, cr, prevCR * } if err := ensureRoleExist(ctx, rclient, cr, prevCR); err != nil { - return fmt.Errorf("cannot ensure state of vmagent's cluster role: %w", err) + return fmt.Errorf("cannot ensure state of vmagent's role: %w", err) } if err := ensureRBExist(ctx, rclient, cr, prevCR); err != nil { return fmt.Errorf("cannot ensure state of vmagent's role binding: %w", err) @@ -136,7 +136,7 @@ func ensureCRBExist(ctx context.Context, rclient client.Client, cr, prevCR *vmv1 func migrateRBAC(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent, clusterWide bool) error { const prevNamingPrefix = "monitoring:vmagent-cluster-access-" prevVersionName := prevNamingPrefix + cr.Name - currentVersionName := cr.GetClusterRoleName() + currentVersionName := cr.GetRBACName() owner := cr.AsOwner() // explicitly set namespace via ObjetMeta for unit tests @@ -170,7 +170,7 @@ func migrateRBAC(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAge func buildCRB(cr *vmv1beta1.VMAgent) *rbacv1.ClusterRoleBinding { r := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Labels: cr.FinalLabels(), Annotations: cr.FinalAnnotations(), Finalizers: []string{vmv1beta1.FinalizerName}, @@ -184,7 +184,7 @@ func buildCRB(cr *vmv1beta1.VMAgent) *rbacv1.ClusterRoleBinding { }, RoleRef: rbacv1.RoleRef{ APIGroup: rbacv1.GroupName, - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Kind: "ClusterRole", }, } @@ -198,7 +198,7 @@ func buildCRB(cr *vmv1beta1.VMAgent) *rbacv1.ClusterRoleBinding { func buildCR(cr *vmv1beta1.VMAgent) *rbacv1.ClusterRole { r := &rbacv1.ClusterRole{ ObjectMeta: metav1.ObjectMeta{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Labels: cr.FinalLabels(), Annotations: cr.FinalAnnotations(), Finalizers: []string{vmv1beta1.FinalizerName}, @@ -235,7 +235,7 @@ func ensureRBExist(ctx context.Context, rclient client.Client, cr, prevCR *vmv1b func buildRole(cr *vmv1beta1.VMAgent) *rbacv1.Role { return &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Namespace: cr.GetNamespace(), Labels: cr.FinalLabels(), Annotations: cr.FinalAnnotations(), @@ -249,7 +249,7 @@ func buildRole(cr *vmv1beta1.VMAgent) *rbacv1.Role { func buildRB(cr *vmv1beta1.VMAgent) *rbacv1.RoleBinding { return &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Namespace: cr.GetNamespace(), Labels: cr.FinalLabels(), Annotations: cr.FinalAnnotations(), @@ -265,7 +265,7 @@ func buildRB(cr *vmv1beta1.VMAgent) *rbacv1.RoleBinding { }, RoleRef: rbacv1.RoleRef{ APIGroup: rbacv1.GroupName, - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Kind: "Role", }, } diff --git a/internal/controller/operator/factory/vmagent/rbac_test.go b/internal/controller/operator/factory/vmagent/rbac_test.go index 5199b25bf..d04f67838 100644 --- a/internal/controller/operator/factory/vmagent/rbac_test.go +++ b/internal/controller/operator/factory/vmagent/rbac_test.go @@ -47,7 +47,7 @@ func TestCreateVMAgentRBAC(t *testing.T) { validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) { var got rbacv1.ClusterRole nsn := types.NamespacedName{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), } assert.NoError(t, rclient.Get(ctx, nsn, &got)) assert.Len(t, got.Rules, 6) @@ -67,7 +67,7 @@ func TestCreateVMAgentRBAC(t *testing.T) { validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) { var got rbacv1.Role nsn := types.NamespacedName{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Namespace: cr.Namespace, } assert.NoError(t, rclient.Get(ctx, nsn, &got)) @@ -100,7 +100,7 @@ func TestCreateVMAgentRBAC(t *testing.T) { validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) { var got rbacv1.ClusterRole nsn := types.NamespacedName{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), } assert.NoError(t, rclient.Get(ctx, nsn, &got)) assert.Len(t, got.Rules, 1) @@ -132,7 +132,7 @@ func TestCreateVMAgentRBAC(t *testing.T) { validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) { var got rbacv1.Role nsn := types.NamespacedName{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Namespace: cr.Namespace, } assert.NoError(t, rclient.Get(ctx, nsn, &got)) @@ -157,7 +157,7 @@ func TestCreateVMAgentRBAC(t *testing.T) { validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) { var got rbacv1.ClusterRole nsn := types.NamespacedName{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), } assert.NoError(t, rclient.Get(ctx, nsn, &got)) assert.Empty(t, got.Rules) @@ -181,7 +181,7 @@ func TestCreateVMAgentRBAC(t *testing.T) { validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) { var got rbacv1.Role nsn := types.NamespacedName{ - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Namespace: cr.Namespace, } assert.NoError(t, rclient.Get(ctx, nsn, &got)) diff --git a/internal/controller/operator/factory/vmagent/vmagent_scrapeconfig_test.go b/internal/controller/operator/factory/vmagent/scrapes_test.go similarity index 96% rename from internal/controller/operator/factory/vmagent/vmagent_scrapeconfig_test.go rename to internal/controller/operator/factory/vmagent/scrapes_test.go index bb499dc5f..1c4763125 100644 --- a/internal/controller/operator/factory/vmagent/vmagent_scrapeconfig_test.go +++ b/internal/controller/operator/factory/vmagent/scrapes_test.go @@ -2,11 +2,9 @@ package vmagent import ( "context" - "encoding/json" "testing" "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -20,87 +18,6 @@ import ( "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" ) -func Test_generateRelabelConfig(t *testing.T) { - f := func(rc *vmv1beta1.RelabelConfig, want string) { - // related fields only filled during json unmarshal - j, err := json.Marshal(rc) - if err != nil { - t.Fatalf("cannot serialize relabelConfig: %s", err) - } - var rlbCfg vmv1beta1.RelabelConfig - if err := json.Unmarshal(j, &rlbCfg); err != nil { - t.Fatalf("cannot parse relabelConfig: %s", err) - } - got := generateRelabelConfig(&rlbCfg) - gotBytes, err := yaml.Marshal(got) - if err != nil { - t.Errorf("cannot marshal generateRelabelConfig to yaml: %e", err) - return - } - assert.Equal(t, want, string(gotBytes)) - } - - // ok base cfg - f(&vmv1beta1.RelabelConfig{ - TargetLabel: "address", - SourceLabels: []string{"__address__"}, - Action: "replace", - }, `source_labels: -- __address__ -target_label: address -action: replace -`) - - // ok base with underscore - f(&vmv1beta1.RelabelConfig{ - UnderScoreTargetLabel: "address", - UnderScoreSourceLabels: []string{"__address__"}, - Action: "replace", - }, `source_labels: -- __address__ -target_label: address -action: replace -`) - - // ok base with graphite match labels - f(&vmv1beta1.RelabelConfig{ - UnderScoreTargetLabel: "address", - UnderScoreSourceLabels: []string{"__address__"}, - Action: "graphite", - Labels: map[string]string{"job": "$1", "instance": "${2}:8080"}, - Match: `foo.*.*.bar`, - }, `source_labels: -- __address__ -target_label: address -action: graphite -match: foo.*.*.bar -labels: - instance: ${2}:8080 - job: $1 -`) - - // with empty replacement and separator - f(&vmv1beta1.RelabelConfig{ - UnderScoreTargetLabel: "address", - UnderScoreSourceLabels: []string{"__address__"}, - Action: "graphite", - Labels: map[string]string{"job": "$1", "instance": "${2}:8080"}, - Match: `foo.*.*.bar`, - Separator: ptr.To(""), - Replacement: ptr.To(""), - }, `source_labels: -- __address__ -separator: "" -target_label: address -replacement: "" -action: graphite -match: foo.*.*.bar -labels: - instance: ${2}:8080 - job: $1 -`) -} - func TestCreateOrUpdateScrapeConfig(t *testing.T) { type opts struct { cr *vmv1beta1.VMAgent @@ -947,7 +864,6 @@ scrape_configs: UnderScoreSourceLabels: []string{"test2"}, }, }, - GlobalScrapeMetricRelabelConfigs: []*vmv1beta1.RelabelConfig{ { UnderScoreSourceLabels: []string{"test1"}, @@ -1704,7 +1620,7 @@ scrape_configs: Targets: vmv1beta1.VMProbeTargets{ Kubernetes: []*vmv1beta1.VMProbeTargetKubernetes{ { - Role: k8sSDRoleIngress, + Role: "ingress", Selector: *metav1.SetAsLabelSelector(map[string]string{ "alb.ingress.kubernetes.io/tags": "Environment=devl", }), @@ -2234,7 +2150,7 @@ scrape_configs: [] } ac := getAssetsCache(ctx, testClient, cr) if err := createOrUpdateScrapeConfig(ctx, testClient, cr, nil, nil, ac); err != nil { - t.Errorf("CreateOrUpdateConfigurationSecret() error = %s", err) + t.Errorf("createOrUpdateScrapeConfig() error = %s", err) } var configSecret corev1.Secret if err := testClient.Get(ctx, types.NamespacedName{Namespace: cr.Namespace, Name: cr.PrefixedName()}, &configSecret); err != nil { @@ -2269,7 +2185,7 @@ scrape_configs: [] Targets: vmv1beta1.VMProbeTargets{ Kubernetes: []*vmv1beta1.VMProbeTargetKubernetes{ { - Role: k8sSDRoleIngress, + Role: "ingress", Selector: *metav1.SetAsLabelSelector(map[string]string{"alb.ingress.kubernetes.io/tags": "Environment=devl"}), }, }, diff --git a/internal/controller/operator/factory/vmagent/vmagent.go b/internal/controller/operator/factory/vmagent/vmagent.go index de2c568d0..6748087b6 100644 --- a/internal/controller/operator/factory/vmagent/vmagent.go +++ b/internal/controller/operator/factory/vmagent/vmagent.go @@ -27,25 +27,23 @@ import ( "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/reconcile" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmscrapes" ) const ( - vmAgentConfDir = "/etc/vmagent/config" - vmAgentConfOutDir = "/etc/vmagent/config_out" - vmAgentPersistentQueueDir = "/tmp/vmagent-remotewrite-data" - vmAgentPersistentQueueSTSDir = "/vmagent_pq/vmagent-remotewrite-data" - vmAgentPersistentQueueMountName = "persistent-queue-data" - globalRelabelingName = "global_relabeling.yaml" - urlRelabelingName = "url_relabeling-%d.yaml" - globalAggregationConfigName = "global_aggregation.yaml" + confDir = "/etc/vmagent/config" + confOutDir = "/etc/vmagent/config_out" + persistentQueueDir = "/tmp/vmagent-remotewrite-data" + persistentQueueSTSDir = "/vmagent_pq/vmagent-remotewrite-data" + persistentQueueMountName = "persistent-queue-data" + globalRelabelingName = "global_relabeling.yaml" + urlRelabelingName = "url_relabeling-%d.yaml" + globalAggregationConfigName = "global_aggregation.yaml" tlsAssetsDir = "/etc/vmagent-tls/certs" scrapeGzippedFilename = "vmagent.yaml.gz" configFilename = "vmagent.yaml" defaultMaxDiskUsage = "1073741824" - - kubeNodeEnvName = "KUBE_NODE_NAME" - kubeNodeEnvTemplate = "%{" + kubeNodeEnvName + "}" ) func buildVMAgentServiceScrape(cr *vmv1beta1.VMAgent, svc *corev1.Service) *vmv1beta1.VMServiceScrape { @@ -435,7 +433,7 @@ func newK8sApp(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (client.Object, err } build.StatefulSetAddCommonParams(stsSpec, useStrictSecurity, &cr.Spec.CommonApplicationDeploymentParams) stsSpec.Spec.Template.Spec.Volumes = build.AddServiceAccountTokenVolume(stsSpec.Spec.Template.Spec.Volumes, &cr.Spec.CommonApplicationDeploymentParams) - cr.Spec.StatefulStorage.IntoSTSVolume(vmAgentPersistentQueueMountName, &stsSpec.Spec) + cr.Spec.StatefulStorage.IntoSTSVolume(persistentQueueMountName, &stsSpec.Spec) stsSpec.Spec.VolumeClaimTemplates = append(stsSpec.Spec.VolumeClaimTemplates, cr.Spec.ClaimTemplates...) return stsSpec, nil } @@ -520,7 +518,7 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec, if cr.Spec.DaemonSetMode { envs = append(envs, corev1.EnvVar{ - Name: kubeNodeEnvName, + Name: vmv1beta1.KubeNodeEnvName, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "spec.nodeName", @@ -537,13 +535,13 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec, var crMounts []corev1.VolumeMount // mount data path any way, even if user changes its value // we cannot rely on value of remoteWriteSettings. - pqMountPath := vmAgentPersistentQueueDir + pqMountPath := persistentQueueDir if cr.Spec.StatefulMode { - pqMountPath = vmAgentPersistentQueueSTSDir + pqMountPath = persistentQueueSTSDir } agentVolumeMounts = append(agentVolumeMounts, corev1.VolumeMount{ - Name: vmAgentPersistentQueueMountName, + Name: persistentQueueMountName, MountPath: pqMountPath, }, ) @@ -553,7 +551,7 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec, // in case for sts, we have to use persistentVolumeClaimTemplate instead if !cr.Spec.StatefulMode { volumes = append(volumes, corev1.Volume{ - Name: vmAgentPersistentQueueMountName, + Name: persistentQueueMountName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, @@ -564,7 +562,7 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec, if !ptr.Deref(cr.Spec.IngestOnlyMode, false) { args = append(args, - fmt.Sprintf("-promscrape.config=%s", path.Join(vmAgentConfOutDir, configFilename))) + fmt.Sprintf("-promscrape.config=%s", path.Join(confOutDir, configFilename))) // preserve order of volumes and volumeMounts // it must prevent vmagent restarts during operator version change @@ -594,7 +592,7 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec, m := corev1.VolumeMount{ Name: "config-out", - MountPath: vmAgentConfOutDir, + MountPath: confOutDir, } crMounts = append(crMounts, m) m.ReadOnly = true @@ -606,7 +604,7 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec, }) agentVolumeMounts = append(agentVolumeMounts, corev1.VolumeMount{ Name: string(build.SecretConfigResourceKind), - MountPath: vmAgentConfDir, + MountPath: confDir, ReadOnly: true, }) @@ -765,7 +763,7 @@ func buildRelabelingsAssets(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*core } // global section if len(cr.Spec.InlineRelabelConfig) > 0 { - rcs := addRelabelConfigs(nil, cr.Spec.InlineRelabelConfig) + rcs := vmscrapes.AddRelabelConfigs(nil, cr.Spec.InlineRelabelConfig) data, err := yaml.Marshal(rcs) if err != nil { return nil, fmt.Errorf("cannot serialize relabelConfig as yaml: %w", err) @@ -788,7 +786,7 @@ func buildRelabelingsAssets(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*core for i := range cr.Spec.RemoteWrite { rw := cr.Spec.RemoteWrite[i] if len(rw.InlineUrlRelabelConfig) > 0 { - rcs := addRelabelConfigs(nil, rw.InlineUrlRelabelConfig) + rcs := vmscrapes.AddRelabelConfigs(nil, rw.InlineUrlRelabelConfig) data, err := yaml.Marshal(rcs) if err != nil { return nil, fmt.Errorf("cannot serialize urlRelabelConfig as yaml: %w", err) @@ -929,9 +927,9 @@ func buildRemoteWriteArgs(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) ([]strin var hasAnyDiskUsagesSet bool var storageLimit int64 - pqMountPath := vmAgentPersistentQueueDir + pqMountPath := persistentQueueDir if cr.Spec.StatefulMode { - pqMountPath = vmAgentPersistentQueueSTSDir + pqMountPath = persistentQueueSTSDir if cr.Spec.StatefulStorage != nil { if storage, ok := cr.Spec.StatefulStorage.VolumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage]; ok { storageInt, ok := storage.AsInt64() @@ -1186,7 +1184,7 @@ func deleteOrphaned(ctx context.Context, rclient client.Client, cr *vmv1beta1.VM return fmt.Errorf("cannot remove serviceaccount: %w", err) } - rbacMeta := metav1.ObjectMeta{Name: cr.GetClusterRoleName(), Namespace: cr.Namespace} + rbacMeta := metav1.ObjectMeta{Name: cr.GetRBACName(), Namespace: cr.Namespace} var objects []client.Object if config.IsClusterWideAccessAllowed() { objects = []client.Object{ @@ -1222,3 +1220,103 @@ func removeStaleDaemonSet(ctx context.Context, rclient client.Client, cr *vmv1be owner := cr.AsOwner() return finalize.SafeDeleteWithFinalizer(ctx, rclient, &ds, &owner) } + +func getAssetsCache(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) *build.AssetsCache { + cfg := map[build.ResourceKind]*build.ResourceCfg{ + build.SecretConfigResourceKind: { + MountDir: confDir, + SecretName: build.ResourceName(build.SecretConfigResourceKind, cr), + }, + build.TLSAssetsResourceKind: { + MountDir: tlsAssetsDir, + SecretName: build.ResourceName(build.TLSAssetsResourceKind, cr), + }, + } + return build.NewAssetsCache(ctx, rclient, cfg) +} + +// CreateOrUpdateScrapeConfig builds scrape configuration for VMAgent +func CreateOrUpdateScrapeConfig(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent, childObject client.Object) error { + var prevCR *vmv1beta1.VMAgent + if cr.ParsedLastAppliedSpec != nil { + prevCR = cr.DeepCopy() + prevCR.Spec = *cr.ParsedLastAppliedSpec + } + ac := getAssetsCache(ctx, rclient, cr) + if err := createOrUpdateScrapeConfig(ctx, rclient, cr, prevCR, childObject, ac); err != nil { + return err + } + return nil +} + +func createOrUpdateScrapeConfig(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMAgent, childObject client.Object, ac *build.AssetsCache) error { + if ptr.Deref(cr.Spec.IngestOnlyMode, false) { + return nil + } + // HACK: newPodSpec could load content into ac and it must be called + // before secret config reconcile + // + // TODO: @f41gh7 rewrite this section with VLAgent secret assets injection pattern + if _, err := newPodSpec(cr, ac); err != nil { + return err + } + + pos := &vmscrapes.ParsedObjects{ + Namespace: cr.Namespace, + APIServerConfig: cr.Spec.APIServerConfig, + MustUseNodeSelector: cr.Spec.DaemonSetMode, + HasClusterWideAccess: config.IsClusterWideAccessAllowed() || !cr.IsOwnsServiceAccount(), + ExternalLabels: cr.ExternalLabels(), + } + if !pos.HasClusterWideAccess { + logger.WithContext(ctx).Info("Setting discovery for the single namespace only." + + "Since operator launched with set WATCH_NAMESPACE param. " + + "Set custom ServiceAccountName property for VMAgent if needed.") + pos.IgnoreNamespaceSelectors = true + } + sp := &cr.Spec.CommonScrapeParams + if err := pos.Init(ctx, rclient, sp); err != nil { + return err + } + pos.ValidateObjects(sp) + + // Update secret based on the most recent configuration. + generatedConfig, err := pos.GenerateConfig( + ctx, + sp, + ac, + ) + if err != nil { + return fmt.Errorf("generating config for vmagent failed: %w", err) + } + + owner := cr.AsOwner() + for kind, secret := range ac.GetOutput() { + var prevSecretMeta *metav1.ObjectMeta + if prevCR != nil { + prevSecretMeta = ptr.To(build.ResourceMeta(kind, prevCR)) + } + if kind == build.SecretConfigResourceKind { + // Compress config to avoid 1mb secret limit for a while + d, err := build.GzipConfig(generatedConfig) + if err != nil { + return fmt.Errorf("cannot gzip config for vmagent: %w", err) + } + secret.Data[scrapeGzippedFilename] = d + } + secret.ObjectMeta = build.ResourceMeta(kind, cr) + secret.Annotations = map[string]string{ + "generated": "true", + } + if err := reconcile.Secret(ctx, rclient, &secret, prevSecretMeta, &owner); err != nil { + return err + } + } + + parentName := fmt.Sprintf("%s.%s.vmagent", cr.Name, cr.Namespace) + if err := pos.UpdateStatusesForScrapeObjects(ctx, rclient, parentName, childObject); err != nil { + return err + } + + return nil +} diff --git a/internal/controller/operator/factory/vmagent/vmagent_test.go b/internal/controller/operator/factory/vmagent/vmagent_test.go index 14ded09c3..de234d1af 100644 --- a/internal/controller/operator/factory/vmagent/vmagent_test.go +++ b/internal/controller/operator/factory/vmagent/vmagent_test.go @@ -1931,7 +1931,6 @@ func TestCreateOrUpdateRelabelConfigsAssets(t *testing.T) { Action: "DROP", SourceLabels: []string{"pod"}, }, - {}, }, }, }, diff --git a/internal/controller/operator/factory/vmagent/nodescrape.go b/internal/controller/operator/factory/vmscrapes/nodescrape.go similarity index 99% rename from internal/controller/operator/factory/vmagent/nodescrape.go rename to internal/controller/operator/factory/vmscrapes/nodescrape.go index f73444e5b..816c4d60d 100644 --- a/internal/controller/operator/factory/vmagent/nodescrape.go +++ b/internal/controller/operator/factory/vmscrapes/nodescrape.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -13,7 +13,7 @@ import ( func generateNodeScrapeConfig( ctx context.Context, sp *vmv1beta1.CommonScrapeParams, - pos *parsedObjects, + pos *ParsedObjects, sc *vmv1beta1.VMNodeScrape, ac *build.AssetsCache, ) (yaml.MapSlice, error) { diff --git a/internal/controller/operator/factory/vmagent/nodescrape_test.go b/internal/controller/operator/factory/vmscrapes/nodescrape_test.go similarity index 98% rename from internal/controller/operator/factory/vmagent/nodescrape_test.go rename to internal/controller/operator/factory/vmscrapes/nodescrape_test.go index 66db773a6..a9a97a92e 100644 --- a/internal/controller/operator/factory/vmagent/nodescrape_test.go +++ b/internal/controller/operator/factory/vmscrapes/nodescrape_test.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -26,8 +26,8 @@ func Test_generateNodeScrapeConfig(t *testing.T) { t.Helper() ctx := context.Background() fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) - ac := getAssetsCache(ctx, fclient, o.cr) - pos := &parsedObjects{Namespace: o.cr.Namespace} + ac := getAssetsCache(ctx, fclient) + pos := &ParsedObjects{Namespace: o.cr.Namespace} sp := &o.cr.Spec.CommonScrapeParams got, err := generateNodeScrapeConfig(ctx, sp, pos, o.sc, ac) if err != nil { diff --git a/internal/controller/operator/factory/vmagent/objects.go b/internal/controller/operator/factory/vmscrapes/objects.go similarity index 95% rename from internal/controller/operator/factory/vmagent/objects.go rename to internal/controller/operator/factory/vmscrapes/objects.go index 4c0212eba..9ec86ca93 100644 --- a/internal/controller/operator/factory/vmagent/objects.go +++ b/internal/controller/operator/factory/vmscrapes/objects.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -15,7 +15,7 @@ import ( "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/reconcile" ) -type parsedObjects struct { +type ParsedObjects struct { APIServerConfig *vmv1beta1.APIServerConfig Namespace string ExternalLabels map[string]string @@ -30,7 +30,7 @@ type parsedObjects struct { scrapeConfigs *build.ChildObjects[*vmv1beta1.VMScrapeConfig] } -func (pos *parsedObjects) updateMetrics(ctx context.Context) { +func (pos *ParsedObjects) updateMetrics(ctx context.Context) { pos.serviceScrapes.UpdateMetrics(ctx) pos.podScrapes.UpdateMetrics(ctx) pos.staticScrapes.UpdateMetrics(ctx) @@ -39,7 +39,7 @@ func (pos *parsedObjects) updateMetrics(ctx context.Context) { pos.scrapeConfigs.UpdateMetrics(ctx) } -func (pos *parsedObjects) init(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { +func (pos *ParsedObjects) Init(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { if err := pos.selectPodScrapes(ctx, rclient, sp); err != nil { return fmt.Errorf("selecting PodScrapes failed: %w", err) } @@ -61,7 +61,7 @@ func (pos *parsedObjects) init(ctx context.Context, rclient client.Client, sp *v return nil } -func (pos *parsedObjects) selectScrapeConfigs(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { +func (pos *ParsedObjects) selectScrapeConfigs(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { var selectedConfigs []*vmv1beta1.VMScrapeConfig var nsn []string if !build.IsControllerDisabled("VMScrapeConfig") && !pos.MustUseNodeSelector { @@ -88,7 +88,7 @@ func (pos *parsedObjects) selectScrapeConfigs(ctx context.Context, rclient clien return nil } -func (pos *parsedObjects) selectPodScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { +func (pos *ParsedObjects) selectPodScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { var selectedConfigs []*vmv1beta1.VMPodScrape var nsn []string if !build.IsControllerDisabled("VMPodScrape") { @@ -115,7 +115,7 @@ func (pos *parsedObjects) selectPodScrapes(ctx context.Context, rclient client.C return nil } -func (pos *parsedObjects) selectProbes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { +func (pos *ParsedObjects) selectProbes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { var selectedConfigs []*vmv1beta1.VMProbe var nsn []string if !build.IsControllerDisabled("VMProbe") && !pos.MustUseNodeSelector { @@ -142,7 +142,7 @@ func (pos *parsedObjects) selectProbes(ctx context.Context, rclient client.Clien return nil } -func (pos *parsedObjects) selectNodeScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { +func (pos *ParsedObjects) selectNodeScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { var selectedConfigs []*vmv1beta1.VMNodeScrape var nsn []string if !build.IsControllerDisabled("VMNodeScrape") && !pos.MustUseNodeSelector { @@ -175,7 +175,7 @@ func (pos *parsedObjects) selectNodeScrapes(ctx context.Context, rclient client. return nil } -func (pos *parsedObjects) selectStaticScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { +func (pos *ParsedObjects) selectStaticScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { var selectedConfigs []*vmv1beta1.VMStaticScrape var nsn []string if !build.IsControllerDisabled("VMStaticScrape") && !pos.MustUseNodeSelector { @@ -202,7 +202,7 @@ func (pos *parsedObjects) selectStaticScrapes(ctx context.Context, rclient clien return nil } -func (pos *parsedObjects) selectServiceScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { +func (pos *ParsedObjects) selectServiceScrapes(ctx context.Context, rclient client.Client, sp *vmv1beta1.CommonScrapeParams) error { var selectedConfigs []*vmv1beta1.VMServiceScrape var nsn []string if !build.IsControllerDisabled("VMServiceScrape") && !pos.MustUseNodeSelector { @@ -230,7 +230,7 @@ func (pos *parsedObjects) selectServiceScrapes(ctx context.Context, rclient clie return nil } -func (pos *parsedObjects) validateObjects(sp *vmv1beta1.CommonScrapeParams) { +func (pos *ParsedObjects) ValidateObjects(sp *vmv1beta1.CommonScrapeParams) { pos.serviceScrapes.ForEachCollectSkipInvalid(func(sc *vmv1beta1.VMServiceScrape) error { if sp.ArbitraryFSAccessThroughSMs.Deny { for _, ep := range sc.Spec.Endpoints { @@ -324,8 +324,8 @@ func (pos *parsedObjects) validateObjects(sp *vmv1beta1.CommonScrapeParams) { }) } -// updateStatusesForScrapeObjects updates status of either selected childObject or all child objects -func (pos *parsedObjects) updateStatusesForScrapeObjects(ctx context.Context, rclient client.Client, parentName string, childObject client.Object) error { +// UpdateStatusesForScrapeObjects updates status of either selected childObject or all child objects +func (pos *ParsedObjects) UpdateStatusesForScrapeObjects(ctx context.Context, rclient client.Client, parentName string, childObject client.Object) error { pos.updateMetrics(ctx) if childObject != nil && !reflect.ValueOf(childObject).IsNil() { // fast path @@ -377,8 +377,8 @@ func (pos *parsedObjects) updateStatusesForScrapeObjects(ctx context.Context, rc return nil } -// generateConfig generates yaml scrape configuration from collected scrape objects -func (pos *parsedObjects) generateConfig(ctx context.Context, sp *vmv1beta1.CommonScrapeParams, ac *build.AssetsCache) ([]byte, error) { +// GenerateConfig generates yaml scrape configuration from collected scrape objects +func (pos *ParsedObjects) GenerateConfig(ctx context.Context, sp *vmv1beta1.CommonScrapeParams, ac *build.AssetsCache) ([]byte, error) { var additionalScrapeConfigs []byte if sp.AdditionalScrapeConfigs != nil { sc, err := ac.LoadKeyFromSecret(pos.Namespace, sp.AdditionalScrapeConfigs) diff --git a/internal/controller/operator/factory/vmagent/objects_test.go b/internal/controller/operator/factory/vmscrapes/objects_test.go similarity index 98% rename from internal/controller/operator/factory/vmagent/objects_test.go rename to internal/controller/operator/factory/vmscrapes/objects_test.go index 5cea91f43..ca86b2aec 100644 --- a/internal/controller/operator/factory/vmagent/objects_test.go +++ b/internal/controller/operator/factory/vmscrapes/objects_test.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -57,7 +57,7 @@ func TestSelectServiceMonitors(t *testing.T) { t.Helper() fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) sp := &o.cr.Spec.CommonScrapeParams - pos := &parsedObjects{Namespace: o.cr.Namespace} + pos := &ParsedObjects{Namespace: o.cr.Namespace} assert.NoError(t, pos.selectServiceScrapes(context.TODO(), fclient, sp)) gotNames := []string{} for _, monitorName := range pos.serviceScrapes.All() { @@ -287,7 +287,7 @@ func TestSelectPodMonitors(t *testing.T) { f := func(o opts) { fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) sp := &o.cr.Spec.CommonScrapeParams - pos := &parsedObjects{Namespace: o.cr.Namespace} + pos := &ParsedObjects{Namespace: o.cr.Namespace} assert.NoError(t, pos.selectPodScrapes(context.TODO(), fclient, sp)) var gotNames []string @@ -373,7 +373,7 @@ func TestSelectProbes(t *testing.T) { t.Helper() fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) sp := &o.cr.Spec.CommonScrapeParams - pos := &parsedObjects{Namespace: o.cr.Namespace} + pos := &ParsedObjects{Namespace: o.cr.Namespace} assert.NoError(t, pos.selectProbes(context.TODO(), fclient, sp)) var result []string for _, k := range pos.probes.All() { diff --git a/internal/controller/operator/factory/vmagent/podscrape.go b/internal/controller/operator/factory/vmscrapes/podscrape.go similarity index 99% rename from internal/controller/operator/factory/vmagent/podscrape.go rename to internal/controller/operator/factory/vmscrapes/podscrape.go index 83e37ca35..bce9c38df 100644 --- a/internal/controller/operator/factory/vmagent/podscrape.go +++ b/internal/controller/operator/factory/vmscrapes/podscrape.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -13,7 +13,7 @@ import ( func generatePodScrapeConfig( ctx context.Context, sp *vmv1beta1.CommonScrapeParams, - pos *parsedObjects, + pos *ParsedObjects, sc *vmv1beta1.VMPodScrape, ep vmv1beta1.PodMetricsEndpoint, i int, diff --git a/internal/controller/operator/factory/vmagent/podscrape_test.go b/internal/controller/operator/factory/vmscrapes/podscrape_test.go similarity index 98% rename from internal/controller/operator/factory/vmagent/podscrape_test.go rename to internal/controller/operator/factory/vmscrapes/podscrape_test.go index 30131ce16..78cff1c34 100644 --- a/internal/controller/operator/factory/vmagent/podscrape_test.go +++ b/internal/controller/operator/factory/vmscrapes/podscrape_test.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -25,8 +25,8 @@ func Test_generatePodScrapeConfig(t *testing.T) { t.Helper() ctx := context.Background() fclient := k8stools.GetTestClientWithObjects(nil) - ac := getAssetsCache(ctx, fclient, o.cr) - pos := &parsedObjects{Namespace: o.cr.Namespace} + ac := getAssetsCache(ctx, fclient) + pos := &ParsedObjects{Namespace: o.cr.Namespace} sp := &o.cr.Spec.CommonScrapeParams got, err := generatePodScrapeConfig(ctx, sp, pos, o.sc, o.ep, 0, ac) if err != nil { diff --git a/internal/controller/operator/factory/vmagent/probe.go b/internal/controller/operator/factory/vmscrapes/probe.go similarity index 99% rename from internal/controller/operator/factory/vmagent/probe.go rename to internal/controller/operator/factory/vmscrapes/probe.go index 1a7e40720..3ce7597ed 100644 --- a/internal/controller/operator/factory/vmagent/probe.go +++ b/internal/controller/operator/factory/vmscrapes/probe.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -49,7 +49,7 @@ func getRoleRelabelings(role string) []yaml.MapSlice { func generateProbeConfig( ctx context.Context, sp *vmv1beta1.CommonScrapeParams, - pos *parsedObjects, + pos *ParsedObjects, sc *vmv1beta1.VMProbe, ac *build.AssetsCache, ) (yaml.MapSlice, error) { diff --git a/internal/controller/operator/factory/vmagent/probe_test.go b/internal/controller/operator/factory/vmscrapes/probe_test.go similarity index 98% rename from internal/controller/operator/factory/vmagent/probe_test.go rename to internal/controller/operator/factory/vmscrapes/probe_test.go index 8e88e56f3..0120f2e72 100644 --- a/internal/controller/operator/factory/vmagent/probe_test.go +++ b/internal/controller/operator/factory/vmscrapes/probe_test.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -27,8 +27,8 @@ func Test_generateProbeConfig(t *testing.T) { t.Helper() ctx := context.Background() fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) - ac := getAssetsCache(ctx, fclient, o.cr) - pos := &parsedObjects{Namespace: o.cr.Namespace} + ac := getAssetsCache(ctx, fclient) + pos := &ParsedObjects{Namespace: o.cr.Namespace} sp := &o.cr.Spec.CommonScrapeParams got, err := generateProbeConfig(ctx, sp, pos, o.sc, ac) if err != nil { @@ -592,8 +592,8 @@ relabel_configs: replacement: blackbox-monitor:9115 stream_parse: false proxy_tls_config: - ca_file: /etc/vmagent-tls/certs/default_configmap_tls-secret_ca - cert_file: /etc/vmagent-tls/certs/default_tls-secret_cert + ca_file: /tls/default_configmap_tls-secret_ca + cert_file: /tls/default_tls-secret_cert key_file: /tmp/key-1 bearer_token_file: /tmp/some_path basic_auth: diff --git a/internal/controller/operator/factory/vmagent/scrapeconfig.go b/internal/controller/operator/factory/vmscrapes/scrapeconfig.go similarity index 99% rename from internal/controller/operator/factory/vmagent/scrapeconfig.go rename to internal/controller/operator/factory/vmscrapes/scrapeconfig.go index 9dad15334..a98d6f1bb 100644 --- a/internal/controller/operator/factory/vmagent/scrapeconfig.go +++ b/internal/controller/operator/factory/vmscrapes/scrapeconfig.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" diff --git a/internal/controller/operator/factory/vmagent/scrapeconfig_test.go b/internal/controller/operator/factory/vmscrapes/scrapeconfig_test.go similarity index 98% rename from internal/controller/operator/factory/vmagent/scrapeconfig_test.go rename to internal/controller/operator/factory/vmscrapes/scrapeconfig_test.go index 1341ab87b..f6242228c 100644 --- a/internal/controller/operator/factory/vmagent/scrapeconfig_test.go +++ b/internal/controller/operator/factory/vmscrapes/scrapeconfig_test.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -28,7 +28,7 @@ func TestGenerateScrapeConfig(t *testing.T) { t.Helper() ctx := context.Background() fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) - ac := getAssetsCache(ctx, fclient, o.cr) + ac := getAssetsCache(ctx, fclient) sp := &o.cr.Spec.CommonScrapeParams got, err := generateScrapeConfig(ctx, sp, o.sc, ac) if err != nil { @@ -271,8 +271,8 @@ http_sd_configs: credentials: auth-secret type: Bearer tls_config: - ca_file: /etc/vmagent-tls/certs/default_tls-secret_ca - cert_file: /etc/vmagent-tls/certs/default_tls-secret_cert + ca_file: /tls/default_tls-secret_ca + cert_file: /tls/default_tls-secret_cert `, }) diff --git a/internal/controller/operator/factory/vmagent/servicescrape.go b/internal/controller/operator/factory/vmscrapes/servicescrape.go similarity index 99% rename from internal/controller/operator/factory/vmagent/servicescrape.go rename to internal/controller/operator/factory/vmscrapes/servicescrape.go index 52ce8808e..49c9bc6d4 100644 --- a/internal/controller/operator/factory/vmagent/servicescrape.go +++ b/internal/controller/operator/factory/vmscrapes/servicescrape.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -13,7 +13,7 @@ import ( func generateServiceScrapeConfig( ctx context.Context, sp *vmv1beta1.CommonScrapeParams, - pos *parsedObjects, + pos *ParsedObjects, sc *vmv1beta1.VMServiceScrape, ep vmv1beta1.Endpoint, i int, diff --git a/internal/controller/operator/factory/vmagent/servicescrape_test.go b/internal/controller/operator/factory/vmscrapes/servicescrape_test.go similarity index 98% rename from internal/controller/operator/factory/vmagent/servicescrape_test.go rename to internal/controller/operator/factory/vmscrapes/servicescrape_test.go index 931694132..bd7e9aeab 100644 --- a/internal/controller/operator/factory/vmagent/servicescrape_test.go +++ b/internal/controller/operator/factory/vmscrapes/servicescrape_test.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -28,8 +28,8 @@ func Test_generateServiceScrapeConfig(t *testing.T) { t.Helper() ctx := context.Background() fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) - ac := getAssetsCache(ctx, fclient, o.cr) - pos := &parsedObjects{ + ac := getAssetsCache(ctx, fclient) + pos := &ParsedObjects{ Namespace: o.cr.Namespace, APIServerConfig: o.cr.Spec.APIServerConfig, } @@ -152,7 +152,7 @@ relabel_configs: - target_label: endpoint replacement: "8080" tls_config: - ca_file: /etc/vmagent-tls/certs/default_tls-secret_ca + ca_file: /tls/default_tls-secret_ca bearer_token_file: /var/run/token `, }) @@ -257,7 +257,7 @@ relabel_configs: - target_label: endpoint replacement: "8080" tls_config: - ca_file: /etc/vmagent-tls/certs/default_tls-secret_ca + ca_file: /tls/default_tls-secret_ca bearer_token_file: /var/run/token `, }) @@ -362,7 +362,7 @@ relabel_configs: - target_label: endpoint replacement: "8080" tls_config: - ca_file: /etc/vmagent-tls/certs/default_tls-secret_ca + ca_file: /tls/default_tls-secret_ca bearer_token_file: /var/run/token `, }) @@ -459,7 +459,7 @@ relabel_configs: - target_label: endpoint replacement: "8080" tls_config: - ca_file: /etc/vmagent-tls/certs/default_tls-secret_ca + ca_file: /tls/default_tls-secret_ca bearer_token_file: /var/run/token `, }) @@ -542,7 +542,7 @@ relabel_configs: - target_label: endpoint replacement: "8080" tls_config: - ca_file: /etc/vmagent-tls/certs/default_tls-secret_ca + ca_file: /tls/default_tls-secret_ca bearer_token_file: /var/run/token `, }) @@ -854,9 +854,9 @@ oauth2: proxy_url: http://oauth2-access-proxy tls_config: insecure_skip_verify: true - ca_file: /etc/vmagent-tls/certs/default_configmap_tls-cm_ca - cert_file: /etc/vmagent-tls/certs/default_tls_key - key_file: /etc/vmagent-tls/certs/default_tls_cert + ca_file: /tls/default_configmap_tls-cm_ca + cert_file: /tls/default_tls_key + key_file: /tls/default_tls_cert `, }) @@ -966,7 +966,7 @@ relabel_configs: target_label: node regex: .+ tls_config: - ca_file: /etc/vmagent-tls/certs/default_tls-secret_ca + ca_file: /tls/default_tls-secret_ca bearer_token_file: /var/run/token `, }) @@ -991,7 +991,7 @@ bearer_token_file: /var/run/token APIServerConfig: &vmv1beta1.APIServerConfig{ Host: "default-k8s-host", TLSConfig: &vmv1beta1.TLSConfig{ - CAFile: "/etc/vmagent-tls/certs/default_k8s_host_ca", + CAFile: "/tls/default_k8s_host_ca", }, }, }, @@ -1029,7 +1029,7 @@ kubernetes_sd_configs: - default api_server: default-k8s-host tls_config: - ca_file: /etc/vmagent-tls/certs/default_k8s_host_ca + ca_file: /tls/default_k8s_host_ca selectors: - role: endpoints label: dc=prod,env=dev,team=go @@ -1400,7 +1400,7 @@ relabel_configs: action: replace tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt - cert_file: /etc/vmagent-tls/certs/default_tls-secret_cert + cert_file: /tls/default_tls-secret_cert `, }) diff --git a/internal/controller/operator/factory/vmagent/staticscrape.go b/internal/controller/operator/factory/vmscrapes/staticscrape.go similarity index 99% rename from internal/controller/operator/factory/vmagent/staticscrape.go rename to internal/controller/operator/factory/vmscrapes/staticscrape.go index 2f6188e69..98c9d08a9 100644 --- a/internal/controller/operator/factory/vmagent/staticscrape.go +++ b/internal/controller/operator/factory/vmscrapes/staticscrape.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" diff --git a/internal/controller/operator/factory/vmagent/staticscrape_test.go b/internal/controller/operator/factory/vmscrapes/staticscrape_test.go similarity index 98% rename from internal/controller/operator/factory/vmagent/staticscrape_test.go rename to internal/controller/operator/factory/vmscrapes/staticscrape_test.go index 2974318bd..97552f0e8 100644 --- a/internal/controller/operator/factory/vmagent/staticscrape_test.go +++ b/internal/controller/operator/factory/vmscrapes/staticscrape_test.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -27,7 +27,7 @@ func Test_generateStaticScrapeConfig(t *testing.T) { t.Helper() ctx := context.Background() fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) - ac := getAssetsCache(ctx, fclient, o.cr) + ac := getAssetsCache(ctx, fclient) sp := &o.cr.Spec.CommonScrapeParams got, err := generateStaticScrapeConfig(ctx, sp, o.sc, o.sc.Spec.TargetEndpoints[0], 0, ac) if err != nil { @@ -364,9 +364,9 @@ proxy_basic_auth: password: proxy-password tls_config: insecure_skip_verify: true - ca_file: /etc/vmagent-tls/certs/default_tls-cfg_ca + ca_file: /tls/default_tls-cfg_ca cert_file: /tmp/cert-part - key_file: /etc/vmagent-tls/certs/default_tls-cfg_key + key_file: /tls/default_tls-cfg_key bearer_token: token-value basic_auth: username: admin diff --git a/internal/controller/operator/factory/vmagent/vmagent_scrapeconfig.go b/internal/controller/operator/factory/vmscrapes/vmscrapes.go similarity index 86% rename from internal/controller/operator/factory/vmagent/vmagent_scrapeconfig.go rename to internal/controller/operator/factory/vmscrapes/vmscrapes.go index 13bfb712d..4a1898da4 100644 --- a/internal/controller/operator/factory/vmagent/vmagent_scrapeconfig.go +++ b/internal/controller/operator/factory/vmscrapes/vmscrapes.go @@ -1,4 +1,4 @@ -package vmagent +package vmscrapes import ( "context" @@ -12,102 +12,15 @@ import ( "gopkg.in/yaml.v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" - "sigs.k8s.io/controller-runtime/pkg/client" vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" - "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/reconcile" ) -// CreateOrUpdateScrapeConfig builds scrape configuration for VMAgent -func CreateOrUpdateScrapeConfig(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent, childObject client.Object) error { - var prevCR *vmv1beta1.VMAgent - if cr.ParsedLastAppliedSpec != nil { - prevCR = cr.DeepCopy() - prevCR.Spec = *cr.ParsedLastAppliedSpec - } - ac := getAssetsCache(ctx, rclient, cr) - if err := createOrUpdateScrapeConfig(ctx, rclient, cr, prevCR, childObject, ac); err != nil { - return err - } - return nil -} - -func createOrUpdateScrapeConfig(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMAgent, childObject client.Object, ac *build.AssetsCache) error { - if ptr.Deref(cr.Spec.IngestOnlyMode, false) { - return nil - } - // HACK: newPodSpec could load content into ac and it must be called - // before secret config reconcile - // - // TODO: @f41gh7 rewrite this section with VLAgent secret assets injection pattern - if _, err := newPodSpec(cr, ac); err != nil { - return err - } - - pos := &parsedObjects{ - Namespace: cr.Namespace, - APIServerConfig: cr.Spec.APIServerConfig, - MustUseNodeSelector: cr.Spec.DaemonSetMode, - HasClusterWideAccess: config.IsClusterWideAccessAllowed() || !cr.IsOwnsServiceAccount(), - ExternalLabels: cr.ExternalLabels(), - IgnoreNamespaceSelectors: cr.Spec.IgnoreNamespaceSelectors, - } - if !pos.HasClusterWideAccess { - logger.WithContext(ctx).Info("setting discovery for the single namespace only." + - "Since operator launched with set WATCH_NAMESPACE param. " + - "Set custom ServiceAccountName property for VMAgent if needed.") - pos.IgnoreNamespaceSelectors = true - } - sp := &cr.Spec.CommonScrapeParams - if err := pos.init(ctx, rclient, sp); err != nil { - return err - } - - pos.validateObjects(sp) - - // Update secret based on the most recent configuration. - generatedConfig, err := pos.generateConfig( - ctx, - sp, - ac, - ) - if err != nil { - return fmt.Errorf("generating config for vmagent failed: %w", err) - } - - owner := cr.AsOwner() - for kind, secret := range ac.GetOutput() { - var prevSecretMeta *metav1.ObjectMeta - if prevCR != nil { - prevSecretMeta = ptr.To(build.ResourceMeta(kind, prevCR)) - } - if kind == build.SecretConfigResourceKind { - // Compress config to avoid 1mb secret limit for a while - data, err := build.GzipConfig(generatedConfig) - if err != nil { - return fmt.Errorf("cannot gzip config for vmagent: %w", err) - } - secret.Data[scrapeGzippedFilename] = data - } - secret.ObjectMeta = build.ResourceMeta(kind, cr) - secret.Annotations = map[string]string{ - "generated": "true", - } - if err := reconcile.Secret(ctx, rclient, &secret, prevSecretMeta, &owner); err != nil { - return err - } - } - - parentName := fmt.Sprintf("%s.%s.vmagent", cr.Name, cr.Namespace) - if err := pos.updateStatusesForScrapeObjects(ctx, rclient, parentName, childObject); err != nil { - return err - } - - return nil -} +const ( + kubeNodeEnvTemplate = "%{" + vmv1beta1.KubeNodeEnvName + "}" +) // TODO: @f41gh7 validate VMScrapeParams func testForArbitraryFSAccess(e vmv1beta1.EndpointAuth) error { @@ -273,7 +186,8 @@ func addAttachMetadata(dst yaml.MapSlice, am *vmv1beta1.AttachMetadata, role str return dst } -func addRelabelConfigs(dst []yaml.MapSlice, rcs []*vmv1beta1.RelabelConfig) []yaml.MapSlice { +// AddRelabelConfigs adds relabel configuration to yaml +func AddRelabelConfigs(dst []yaml.MapSlice, rcs []*vmv1beta1.RelabelConfig) []yaml.MapSlice { for i := range rcs { rc := rcs[i] if rc.IsEmpty() { @@ -699,20 +613,6 @@ func addEndpointAuthTo(cfg yaml.MapSlice, ea *vmv1beta1.EndpointAuth, namespace return cfg, nil } -func getAssetsCache(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMAgent) *build.AssetsCache { - cfg := map[build.ResourceKind]*build.ResourceCfg{ - build.SecretConfigResourceKind: { - MountDir: vmAgentConfDir, - SecretName: build.ResourceName(build.SecretConfigResourceKind, cr), - }, - build.TLSAssetsResourceKind: { - MountDir: tlsAssetsDir, - SecretName: build.ResourceName(build.TLSAssetsResourceKind, cr), - }, - } - return build.NewAssetsCache(ctx, rclient, cfg) -} - func validateScrapeClassExists(scrapeClassName *string, sp *vmv1beta1.CommonScrapeParams) error { if scrapeClassName == nil { return nil diff --git a/internal/controller/operator/factory/vmscrapes/vmscrapes_test.go b/internal/controller/operator/factory/vmscrapes/vmscrapes_test.go new file mode 100644 index 000000000..0d06515b7 --- /dev/null +++ b/internal/controller/operator/factory/vmscrapes/vmscrapes_test.go @@ -0,0 +1,110 @@ +package vmscrapes + +import ( + "context" + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" +) + +func Test_generateRelabelConfig(t *testing.T) { + f := func(rc *vmv1beta1.RelabelConfig, want string) { + // related fields only filled during json unmarshal + j, err := json.Marshal(rc) + if err != nil { + t.Fatalf("cannot serialize relabelConfig: %s", err) + } + var rlbCfg vmv1beta1.RelabelConfig + if err := json.Unmarshal(j, &rlbCfg); err != nil { + t.Fatalf("cannot parse relabelConfig: %s", err) + } + got := generateRelabelConfig(&rlbCfg) + gotBytes, err := yaml.Marshal(got) + if err != nil { + t.Errorf("cannot marshal generateRelabelConfig to yaml: %e", err) + return + } + assert.Equal(t, want, string(gotBytes)) + } + + // ok base cfg + f(&vmv1beta1.RelabelConfig{ + TargetLabel: "address", + SourceLabels: []string{"__address__"}, + Action: "replace", + }, `source_labels: +- __address__ +target_label: address +action: replace +`) + + // ok base with underscore + f(&vmv1beta1.RelabelConfig{ + UnderScoreTargetLabel: "address", + UnderScoreSourceLabels: []string{"__address__"}, + Action: "replace", + }, `source_labels: +- __address__ +target_label: address +action: replace +`) + + // ok base with graphite match labels + f(&vmv1beta1.RelabelConfig{ + UnderScoreTargetLabel: "address", + UnderScoreSourceLabels: []string{"__address__"}, + Action: "graphite", + Labels: map[string]string{"job": "$1", "instance": "${2}:8080"}, + Match: `foo.*.*.bar`, + }, `source_labels: +- __address__ +target_label: address +action: graphite +match: foo.*.*.bar +labels: + instance: ${2}:8080 + job: $1 +`) + + // with empty replacement and separator + f(&vmv1beta1.RelabelConfig{ + UnderScoreTargetLabel: "address", + UnderScoreSourceLabels: []string{"__address__"}, + Action: "graphite", + Labels: map[string]string{"job": "$1", "instance": "${2}:8080"}, + Match: `foo.*.*.bar`, + Separator: ptr.To(""), + Replacement: ptr.To(""), + }, `source_labels: +- __address__ +separator: "" +target_label: address +replacement: "" +action: graphite +match: foo.*.*.bar +labels: + instance: ${2}:8080 + job: $1 +`) +} + +func getAssetsCache(ctx context.Context, rclient client.Client) *build.AssetsCache { + cfg := map[build.ResourceKind]*build.ResourceCfg{ + build.SecretConfigResourceKind: { + MountDir: "/conf", + SecretName: "conf-secret", + }, + build.TLSAssetsResourceKind: { + MountDir: "/tls", + SecretName: "tls-secret", + }, + } + return build.NewAssetsCache(ctx, rclient, cfg) +} diff --git a/internal/controller/operator/factory/vmsingle/rbac.go b/internal/controller/operator/factory/vmsingle/rbac.go new file mode 100644 index 000000000..70812b402 --- /dev/null +++ b/internal/controller/operator/factory/vmsingle/rbac.go @@ -0,0 +1,276 @@ +package vmsingle + +import ( + "context" + "fmt" + + rbacv1 "k8s.io/api/rbac/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/finalize" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/reconcile" +) + +func getSingleNamespaceRules(cr *vmv1beta1.VMSingle) []rbacv1.PolicyRule { + var rules []rbacv1.PolicyRule + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) || cr.HasAnyRelabellingConfigs() || cr.HasAnyStreamAggrRule() { + rules = append(rules, rbacv1.PolicyRule{ + APIGroups: []string{""}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"configmaps", "secrets"}, + }) + } + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) { + rules = append(rules, []rbacv1.PolicyRule{ + { + APIGroups: []string{"discovery.k8s.io"}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"endpointslices"}, + }, + { + APIGroups: []string{""}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"services", "endpoints", "pods"}, + }, + { + APIGroups: []string{"networking.k8s.io", "extensions"}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"ingresses"}, + }, + }...) + } + return rules +} + +func getClusterWideRules(cr *vmv1beta1.VMSingle) []rbacv1.PolicyRule { + var rules []rbacv1.PolicyRule + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) || cr.HasAnyRelabellingConfigs() || cr.HasAnyStreamAggrRule() { + rules = append(rules, rbacv1.PolicyRule{ + APIGroups: []string{""}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"configmaps", "secrets"}, + }) + } + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) { + rules = append(rules, []rbacv1.PolicyRule{ + { + APIGroups: []string{"discovery.k8s.io"}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"endpointslices"}, + }, + { + APIGroups: []string{""}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"nodes", "nodes/metrics", "services", "endpoints", "pods", "namespaces"}, + }, + { + APIGroups: []string{"networking.k8s.io", "extensions"}, + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"ingresses"}, + }, + { + NonResourceURLs: []string{"/metrics", "/metrics/resources", "/metrics/slis"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"route.openshift.io", "image.openshift.io"}, + Verbs: []string{"get"}, + Resources: []string{"routers/metrics", "registry/metrics"}, + }, + }...) + } + return rules +} + +// createK8sAPIAccess - creates RBAC access rules for vmsingle +func createK8sAPIAccess(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle, clusterWide bool) error { + if err := migrateRBAC(ctx, rclient, cr, clusterWide); err != nil { + return fmt.Errorf("cannot perform RBAC migration: %w", err) + } + if clusterWide { + if err := ensureCRExist(ctx, rclient, cr, prevCR); err != nil { + return fmt.Errorf("cannot ensure state of vmsingle's cluster role: %w", err) + } + if err := ensureCRBExist(ctx, rclient, cr, prevCR); err != nil { + return fmt.Errorf("cannot ensure state of vmsingle's cluster role binding: %w", err) + } + return nil + } + + if err := ensureRoleExist(ctx, rclient, cr, prevCR); err != nil { + return fmt.Errorf("cannot ensure state of vmsingle's role: %w", err) + } + if err := ensureRBExist(ctx, rclient, cr, prevCR); err != nil { + return fmt.Errorf("cannot ensure state of vmsingle's role binding: %w", err) + } + + return nil +} + +func ensureCRExist(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle) error { + var prevClusterRole *rbacv1.ClusterRole + if prevCR != nil { + prevClusterRole = buildCR(prevCR) + } + owner := cr.AsCRDOwner() + return reconcile.ClusterRole(ctx, rclient, buildCR(cr), prevClusterRole, owner) +} + +func ensureCRBExist(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle) error { + var prevCRB *rbacv1.ClusterRoleBinding + if prevCR != nil { + prevCRB = buildCRB(prevCR) + } + owner := cr.AsCRDOwner() + return reconcile.ClusterRoleBinding(ctx, rclient, buildCRB(cr), prevCRB, owner) +} + +// migrateRBAC deletes incorrectly formatted resource names +// see https://github.com/VictoriaMetrics/operator/issues/891 +// and https://github.com/VictoriaMetrics/operator/pull/1176 +func migrateRBAC(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle, clusterWide bool) error { + const prevNamingPrefix = "monitoring:vmsingle-cluster-access-" + prevVersionName := prevNamingPrefix + cr.Name + currentVersionName := cr.GetRBACName() + owner := cr.AsOwner() + + // explicitly set namespace via ObjetMeta for unit tests + toMigrateObjects := []client.Object{ + &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Namespace: cr.Namespace}}, + &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Namespace: cr.Namespace}}, + } + if !clusterWide { + toMigrateObjects = []client.Object{ + &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Namespace: cr.Namespace}}, + &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Namespace: cr.Namespace}}, + } + } + + for _, obj := range toMigrateObjects { + if err := rclient.Get(ctx, types.NamespacedName{Namespace: cr.Namespace, Name: currentVersionName}, obj); err != nil { + if !k8serrors.IsNotFound(err) { + return fmt.Errorf("cannot get object: %w", err) + } + // update name with prev version formatting + obj.SetName(prevVersionName) + if err := finalize.SafeDeleteWithFinalizer(ctx, rclient, obj, &owner); err != nil { + return fmt.Errorf("cannot safe delete obj : %w", err) + } + } + } + + return nil +} + +func buildCRB(cr *vmv1beta1.VMSingle) *rbacv1.ClusterRoleBinding { + r := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.GetRBACName(), + Labels: cr.FinalLabels(), + Annotations: cr.FinalAnnotations(), + Finalizers: []string{vmv1beta1.FinalizerName}, + }, + Subjects: []rbacv1.Subject{ + { + Kind: rbacv1.ServiceAccountKind, + Name: cr.GetServiceAccountName(), + Namespace: cr.GetNamespace(), + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Name: cr.GetRBACName(), + Kind: "ClusterRole", + }, + } + owner := cr.AsCRDOwner() + if owner != nil { + // Kubernetes does not allow namespace-scoped resources to own cluster-scoped resources, + // use crd instead + r.OwnerReferences = []metav1.OwnerReference{*owner} + } + return r +} + +func buildCR(cr *vmv1beta1.VMSingle) *rbacv1.ClusterRole { + r := &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.GetRBACName(), + Labels: cr.FinalLabels(), + Annotations: cr.FinalAnnotations(), + Finalizers: []string{vmv1beta1.FinalizerName}, + }, + Rules: getClusterWideRules(cr), + } + owner := cr.AsCRDOwner() + if owner != nil { + // Kubernetes does not allow namespace-scoped resources to own cluster-scoped resources, + // use crd instead + r.OwnerReferences = []metav1.OwnerReference{*owner} + } + return r +} + +func ensureRoleExist(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle) error { + nr := buildRole(cr) + var prevRole *rbacv1.Role + if prevCR != nil { + prevRole = buildRole(prevCR) + } + owner := cr.AsOwner() + return reconcile.Role(ctx, rclient, nr, prevRole, &owner) +} + +func ensureRBExist(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle) error { + rb := buildRB(cr) + var prevRB *rbacv1.RoleBinding + if prevCR != nil { + prevRB = buildRB(prevCR) + } + owner := cr.AsOwner() + return reconcile.RoleBinding(ctx, rclient, rb, prevRB, &owner) +} + +func buildRole(cr *vmv1beta1.VMSingle) *rbacv1.Role { + return &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.GetRBACName(), + Namespace: cr.GetNamespace(), + Labels: cr.FinalLabels(), + Annotations: cr.FinalAnnotations(), + Finalizers: []string{vmv1beta1.FinalizerName}, + OwnerReferences: []metav1.OwnerReference{cr.AsOwner()}, + }, + Rules: getSingleNamespaceRules(cr), + } +} + +func buildRB(cr *vmv1beta1.VMSingle) *rbacv1.RoleBinding { + return &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.GetRBACName(), + Namespace: cr.GetNamespace(), + Labels: cr.FinalLabels(), + Annotations: cr.FinalAnnotations(), + Finalizers: []string{vmv1beta1.FinalizerName}, + OwnerReferences: []metav1.OwnerReference{cr.AsOwner()}, + }, + Subjects: []rbacv1.Subject{ + { + Kind: rbacv1.ServiceAccountKind, + Name: cr.GetServiceAccountName(), + Namespace: cr.GetNamespace(), + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Name: cr.GetRBACName(), + Kind: "Role", + }, + } +} diff --git a/internal/controller/operator/factory/vmsingle/rbac_test.go b/internal/controller/operator/factory/vmsingle/rbac_test.go new file mode 100644 index 000000000..cb6ed8a13 --- /dev/null +++ b/internal/controller/operator/factory/vmsingle/rbac_test.go @@ -0,0 +1,230 @@ +package vmsingle + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" +) + +func TestCreateVMSingleRBAC(t *testing.T) { + type opts struct { + cr *vmv1beta1.VMSingle + validate func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) + clusterWide bool + predefinedObjects []runtime.Object + } + f := func(o opts) { + t.Helper() + fclient := k8stools.GetTestClientWithObjects(o.predefinedObjects) + ctx := context.TODO() + assert.NoError(t, createK8sAPIAccess(ctx, fclient, o.cr, nil, o.clusterWide)) + if o.validate != nil { + o.validate(ctx, fclient, o.cr) + } + } + + // create default cluster-wide rbac + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "rbac-test", + }, + Spec: vmv1beta1.VMSingleSpec{}, + }, + clusterWide: true, + validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) { + var got rbacv1.ClusterRole + nsn := types.NamespacedName{ + Name: cr.GetRBACName(), + } + assert.NoError(t, rclient.Get(ctx, nsn, &got)) + assert.Len(t, got.Rules, 6) + }, + }) + + // create namespaced rbac + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "rbac-test", + }, + Spec: vmv1beta1.VMSingleSpec{}, + }, + clusterWide: false, + validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) { + var got rbacv1.Role + nsn := types.NamespacedName{ + Name: cr.GetRBACName(), + Namespace: cr.Namespace, + } + assert.NoError(t, rclient.Get(ctx, nsn, &got)) + assert.Len(t, got.Rules, 4) + }, + }) + + // create cluster-wide rbac for relabeling + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "rbac-test", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonRelabelParams: vmv1beta1.CommonRelabelParams{ + InlineRelabelConfig: []*vmv1beta1.RelabelConfig{{ + Action: "drop", + SourceLabels: []string{"environment"}, + }}, + }, + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(true), + }, + }, + }, + clusterWide: true, + validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) { + var got rbacv1.ClusterRole + nsn := types.NamespacedName{ + Name: cr.GetRBACName(), + } + assert.NoError(t, rclient.Get(ctx, nsn, &got)) + assert.Len(t, got.Rules, 1) + }, + }) + + // create namespaced rbac for relabeling + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "rbac-test", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonRelabelParams: vmv1beta1.CommonRelabelParams{ + InlineRelabelConfig: []*vmv1beta1.RelabelConfig{{ + Action: "drop", + SourceLabels: []string{"environment"}, + }}, + }, + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(true), + }, + }, + }, + clusterWide: false, + validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) { + var got rbacv1.Role + nsn := types.NamespacedName{ + Name: cr.GetRBACName(), + Namespace: cr.Namespace, + } + assert.NoError(t, rclient.Get(ctx, nsn, &got)) + assert.Len(t, got.Rules, 1) + }, + }) + + // cluster-wide rbac with no rules + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "rbac-test", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(true), + }, + }, + }, + clusterWide: true, + validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) { + var got rbacv1.ClusterRole + nsn := types.NamespacedName{ + Name: cr.GetRBACName(), + } + assert.NoError(t, rclient.Get(ctx, nsn, &got)) + assert.Empty(t, got.Rules) + }, + }) + + // no namespaced rbac + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "rbac-test", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(true), + }, + }, + }, + clusterWide: false, + validate: func(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) { + var got rbacv1.Role + nsn := types.NamespacedName{ + Name: cr.GetRBACName(), + Namespace: cr.Namespace, + } + assert.NoError(t, rclient.Get(ctx, nsn, &got)) + assert.Empty(t, got.Rules) + }, + }) + + // ok with exist rbac + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default-2", + Name: "rbac-test", + }, + Spec: vmv1beta1.VMSingleSpec{}, + }, + predefinedObjects: []runtime.Object{ + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "monitoring:vmsingle-cluster-access-rbac-test", + Namespace: "default-2", + Labels: map[string]string{ + "app.kubernetes.io/name": "vmsingle", + "app.kubernetes.io/instance": "rbac-test", + "app.kubernetes.io/component": "monitoring", + "managed-by": "vm-operator", + }, + }, + }, + &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "monitoring:vmsingle-cluster-access-rbac-test", + Namespace: "default-2", + Labels: map[string]string{ + "app.kubernetes.io/name": "vmsingle", + "app.kubernetes.io/instance": "rbac-test", + "app.kubernetes.io/component": "monitoring", + "managed-by": "vm-operator", + }, + }, + }, + &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vmsingle-rbac-test", + Namespace: "default-2", + }, + }, + }, + }) +} diff --git a/internal/controller/operator/factory/vmsingle/scrapes_test.go b/internal/controller/operator/factory/vmsingle/scrapes_test.go new file mode 100644 index 000000000..7e8c62b05 --- /dev/null +++ b/internal/controller/operator/factory/vmsingle/scrapes_test.go @@ -0,0 +1,2161 @@ +package vmsingle + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" + "github.com/VictoriaMetrics/operator/internal/config" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" +) + +func TestCreateOrUpdateScrapeConfig(t *testing.T) { + type opts struct { + cr *vmv1beta1.VMSingle + cfgMutator func(c *config.BaseOperatorConf) + predefinedObjects []runtime.Object + wantConfig string + } + + f := func(o opts) { + t.Helper() + ctx := context.TODO() + testClient := k8stools.GetTestClientWithObjects(o.predefinedObjects) + cfg := config.MustGetBaseConfig() + if o.cfgMutator != nil { + defaultCfg := *cfg + o.cfgMutator(cfg) + defer func() { + *config.MustGetBaseConfig() = defaultCfg + }() + } + build.AddDefaults(testClient.Scheme()) + ac := getAssetsCache(ctx, testClient, o.cr) + if err := createOrUpdateScrapeConfig(ctx, testClient, o.cr, nil, nil, ac); err != nil { + t.Errorf("CreateOrUpdateConfigurationSecret() error = %v", err) + } + var expectSecret corev1.Secret + nsn := types.NamespacedName{Namespace: o.cr.Namespace, Name: o.cr.PrefixedName()} + if err := testClient.Get(ctx, nsn, &expectSecret); err != nil { + t.Fatalf("cannot get vmsingle config secret: %s", err) + } + gotCfg := expectSecret.Data[scrapeGzippedFilename] + data, err := build.GunzipConfig(gotCfg) + if err != nil { + t.Fatalf("cannot read cfg: %s", err) + } + assert.Equal(t, o.wantConfig, string(data)) + } + + // complete test + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + ServiceScrapeNamespaceSelector: &metav1.LabelSelector{}, + ServiceScrapeSelector: &metav1.LabelSelector{}, + PodScrapeSelector: &metav1.LabelSelector{}, + PodScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeSelector: &metav1.LabelSelector{}, + StaticScrapeNamespaceSelector: &metav1.LabelSelector{}, + StaticScrapeSelector: &metav1.LabelSelector{}, + ProbeNamespaceSelector: &metav1.LabelSelector{}, + ProbeSelector: &metav1.LabelSelector{}, + }, + }, + }, + predefinedObjects: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-system", + }, + }, + &vmv1beta1.VMServiceScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vms", + }, + Spec: vmv1beta1.VMServiceScrapeSpec{ + Selector: metav1.LabelSelector{}, + JobLabel: "app", + NamespaceSelector: vmv1beta1.NamespaceSelector{}, + Endpoints: []vmv1beta1.Endpoint{ + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics", + }, + Port: "8085", + EndpointAuth: vmv1beta1.EndpointAuth{ + BearerTokenSecret: &corev1.SecretKeySelector{ + Key: "bearer", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + }, + }, + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-2", + }, + Port: "8083", + }, + }, + }, + }, + &vmv1beta1.VMProbe{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "kube-system", + Name: "test-vmp", + }, + Spec: vmv1beta1.VMProbeSpec{ + Targets: vmv1beta1.VMProbeTargets{ + Static: &vmv1beta1.VMProbeTargetStatic{ + Targets: []string{"localhost:8428"}, + }, + }, + VMProberSpec: vmv1beta1.VMProberSpec{URL: "http://blackbox"}, + }, + }, + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vps", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + JobLabel: "app", + NamespaceSelector: vmv1beta1.NamespaceSelector{}, + Selector: metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "app", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"prod"}, + }, + }, + }, + SampleLimit: 10, + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + Port: ptr.To("805"), + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-3", + + VMScrapeParams: &vmv1beta1.VMScrapeParams{ + StreamParse: ptr.To(true), + ProxyClientConfig: &vmv1beta1.ProxyAuth{ + TLSConfig: &vmv1beta1.TLSConfig{ + InsecureSkipVerify: true, + KeySecret: &corev1.SecretKeySelector{ + Key: "key", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + Cert: vmv1beta1.SecretOrConfigMap{Secret: &corev1.SecretKeySelector{ + Key: "cert", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }}, + CA: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "ca", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + }, + }, + }, + }, + }, + }, + { + Port: ptr.To("801"), + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-5", + }, + EndpointAuth: vmv1beta1.EndpointAuth{ + TLSConfig: &vmv1beta1.TLSConfig{ + InsecureSkipVerify: true, + KeySecret: &corev1.SecretKeySelector{ + Key: "key", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + Cert: vmv1beta1.SecretOrConfigMap{Secret: &corev1.SecretKeySelector{ + Key: "cert", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }}, + CA: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "ca", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + }, + }, + }, + }, + }, + }, + }, + &vmv1beta1.VMNodeScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vms", + }, + Spec: vmv1beta1.VMNodeScrapeSpec{ + EndpointAuth: vmv1beta1.EndpointAuth{ + BasicAuth: &vmv1beta1.BasicAuth{ + Username: corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + Password: corev1.SecretKeySelector{ + Key: "password", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + }, + }, + }, + }, + &vmv1beta1.VMStaticScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vmstatic", + }, + Spec: vmv1beta1.VMStaticScrapeSpec{ + TargetEndpoints: []*vmv1beta1.TargetEndpoint{ + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-3", + Scheme: "https", + ProxyURL: ptr.To("https://some-proxy-1"), + }, + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + TokenURL: "https://some-tr", + ClientSecret: &corev1.SecretKeySelector{ + Key: "cs", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + ClientID: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "cid", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + }, + }, + }, + }, + }, + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "access-creds", + Namespace: "default", + }, + Data: map[string][]byte{ + "cid": []byte(`some-client-id`), + "cs": []byte(`some-client-secret`), + "username": []byte(`some-username`), + "password": []byte(`some-password`), + "ca": []byte(`some-ca-cert`), + "cert": []byte(`some-cert`), + "key": []byte(`some-key`), + "bearer": []byte(`some-bearer`), + }, + }, + }, + wantConfig: `global: + scrape_interval: 30s + external_labels: + prometheus: default/test +scrape_configs: +- job_name: serviceScrape/default/test-vms/0 + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics + relabel_configs: + - action: keep + source_labels: + - __meta_kubernetes_endpoint_port_name + regex: "8085" + - source_labels: + - __meta_kubernetes_endpoint_address_target_kind + - __meta_kubernetes_endpoint_address_target_name + separator: ; + regex: Node;(.*) + replacement: ${1} + target_label: node + - source_labels: + - __meta_kubernetes_endpoint_address_target_kind + - __meta_kubernetes_endpoint_address_target_name + separator: ; + regex: Pod;(.*) + replacement: ${1} + target_label: pod + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_service_name + target_label: service + - source_labels: + - __meta_kubernetes_service_name + target_label: job + replacement: ${1} + - source_labels: + - __meta_kubernetes_service_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "8085" + bearer_token: some-bearer +- job_name: serviceScrape/default/test-vms/1 + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics-2 + relabel_configs: + - action: keep + source_labels: + - __meta_kubernetes_endpoint_port_name + regex: "8083" + - source_labels: + - __meta_kubernetes_endpoint_address_target_kind + - __meta_kubernetes_endpoint_address_target_name + separator: ; + regex: Node;(.*) + replacement: ${1} + target_label: node + - source_labels: + - __meta_kubernetes_endpoint_address_target_kind + - __meta_kubernetes_endpoint_address_target_name + separator: ; + regex: Pod;(.*) + replacement: ${1} + target_label: pod + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_service_name + target_label: service + - source_labels: + - __meta_kubernetes_service_name + target_label: job + replacement: ${1} + - source_labels: + - __meta_kubernetes_service_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "8083" +- job_name: podScrape/default/test-vps/0 + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics-3 + sample_limit: 10 + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_label_app + regex: prod + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: "805" + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/test-vps + - source_labels: + - __meta_kubernetes_pod_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "805" + stream_parse: true + proxy_tls_config: + insecure_skip_verify: true + ca_file: /etc/vm-tls/certs/default_access-creds_ca + cert_file: /etc/vm-tls/certs/default_access-creds_cert + key_file: /etc/vm-tls/certs/default_access-creds_key +- job_name: podScrape/default/test-vps/1 + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics-5 + sample_limit: 10 + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_label_app + regex: prod + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: "801" + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/test-vps + - source_labels: + - __meta_kubernetes_pod_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "801" + tls_config: + insecure_skip_verify: true + ca_file: /etc/vm-tls/certs/default_access-creds_ca + cert_file: /etc/vm-tls/certs/default_access-creds_cert + key_file: /etc/vm-tls/certs/default_access-creds_key +- job_name: probe/kube-system/test-vmp + honor_labels: false + metrics_path: /probe + static_configs: + - targets: + - localhost:8428 + relabel_configs: + - source_labels: + - __address__ + target_label: __param_target + - source_labels: + - __param_target + target_label: instance + - target_label: __address__ + replacement: http://blackbox +- job_name: nodeScrape/default/test-vms + kubernetes_sd_configs: + - role: node + honor_labels: false + relabel_configs: + - source_labels: + - __meta_kubernetes_node_name + target_label: node + - target_label: job + replacement: default/test-vms + basic_auth: + username: some-username + password: some-password +- job_name: staticScrape/default/test-vmstatic/0 + static_configs: + - targets: [] + honor_labels: false + metrics_path: /metrics-3 + proxy_url: https://some-proxy-1 + scheme: https + relabel_configs: [] + oauth2: + client_id: some-client-id + client_secret: some-client-secret + token_url: https://some-tr +`, + }) + + // with missing secret references + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + ServiceScrapeNamespaceSelector: &metav1.LabelSelector{}, + ServiceScrapeSelector: &metav1.LabelSelector{}, + PodScrapeSelector: &metav1.LabelSelector{}, + PodScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeSelector: &metav1.LabelSelector{}, + StaticScrapeNamespaceSelector: &metav1.LabelSelector{}, + StaticScrapeSelector: &metav1.LabelSelector{}, + ProbeNamespaceSelector: &metav1.LabelSelector{}, + ProbeSelector: &metav1.LabelSelector{}, + }, + }, + }, + predefinedObjects: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + }, + }, + + &vmv1beta1.VMNodeScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-bad-0", + }, + Spec: vmv1beta1.VMNodeScrapeSpec{ + EndpointAuth: vmv1beta1.EndpointAuth{ + BasicAuth: &vmv1beta1.BasicAuth{ + Username: corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + Password: corev1.SecretKeySelector{ + Key: "password", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + }, + }, + }, + }, + + &vmv1beta1.VMNodeScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-good", + }, + Spec: vmv1beta1.VMNodeScrapeSpec{}, + }, + + &vmv1beta1.VMNodeScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "bad-1", + }, + Spec: vmv1beta1.VMNodeScrapeSpec{ + EndpointAuth: vmv1beta1.EndpointAuth{ + BearerTokenSecret: &corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + }, + }, + }, + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vps-mixed", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + JobLabel: "app", + NamespaceSelector: vmv1beta1.NamespaceSelector{}, + Selector: metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "app", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"prod"}, + }, + }, + }, + SampleLimit: 10, + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + Port: ptr.To("805"), + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-3", + VMScrapeParams: &vmv1beta1.VMScrapeParams{ + StreamParse: ptr.To(true), + ProxyClientConfig: &vmv1beta1.ProxyAuth{ + BearerToken: &corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + }, + }, + }, + }, + { + Port: ptr.To("801"), + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-5", + }, + EndpointAuth: vmv1beta1.EndpointAuth{ + BasicAuth: &vmv1beta1.BasicAuth{ + Username: corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + Password: corev1.SecretKeySelector{ + Key: "password", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + }, + }, + }, + { + Port: ptr.To("801"), + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-5-good", + }, + }, + }, + }, + }, + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vps-good", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + JobLabel: "app", + NamespaceSelector: vmv1beta1.NamespaceSelector{}, + Selector: metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "app", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"prod"}, + }, + }, + }, + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + Port: ptr.To("8011"), + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-1-good", + }, + }, + }, + }, + }, + &vmv1beta1.VMStaticScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vmstatic-bad", + }, + Spec: vmv1beta1.VMStaticScrapeSpec{ + TargetEndpoints: []*vmv1beta1.TargetEndpoint{ + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-3", + Scheme: "https", + ProxyURL: ptr.To("https://some-proxy-1"), + }, + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + TokenURL: "https://some-tr", + ClientSecret: &corev1.SecretKeySelector{ + Key: "cs", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + ClientID: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "cid", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-credentials", + }, + }, + }, + }, + }, + }, + }, + }, + }, + &vmv1beta1.VMStaticScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vmstatic-bad-tls", + }, + Spec: vmv1beta1.VMStaticScrapeSpec{ + TargetEndpoints: []*vmv1beta1.TargetEndpoint{ + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-3", + Scheme: "https", + ProxyURL: ptr.To("https://some-proxy-1"), + }, + EndpointAuth: vmv1beta1.EndpointAuth{ + TLSConfig: &vmv1beta1.TLSConfig{ + Cert: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "cert", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-credentials", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantConfig: `global: + scrape_interval: 30s + external_labels: + prometheus: default/test +scrape_configs: +- job_name: podScrape/default/test-vps-good/0 + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics-1-good + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_label_app + regex: prod + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: "8011" + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/test-vps-good + - source_labels: + - __meta_kubernetes_pod_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "8011" +- job_name: nodeScrape/default/test-good + kubernetes_sd_configs: + - role: node + honor_labels: false + relabel_configs: + - source_labels: + - __meta_kubernetes_node_name + target_label: node + - target_label: job + replacement: default/test-good +`, + }) + + // with changed default config value + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + ServiceScrapeNamespaceSelector: &metav1.LabelSelector{}, + ServiceScrapeSelector: &metav1.LabelSelector{}, + PodScrapeSelector: &metav1.LabelSelector{}, + PodScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeSelector: &metav1.LabelSelector{}, + StaticScrapeNamespaceSelector: &metav1.LabelSelector{}, + StaticScrapeSelector: &metav1.LabelSelector{}, + ProbeNamespaceSelector: &metav1.LabelSelector{}, + ProbeSelector: &metav1.LabelSelector{}, + ScrapeTimeout: "20m", + ScrapeInterval: "30m", + ExternalLabels: map[string]string{ + "externalLabelName": "externalLabelValue", + }, + GlobalScrapeRelabelConfigs: []*vmv1beta1.RelabelConfig{ + { + UnderScoreSourceLabels: []string{"test2"}, + }, + }, + GlobalScrapeMetricRelabelConfigs: []*vmv1beta1.RelabelConfig{ + { + UnderScoreSourceLabels: []string{"test1"}, + }, + }, + }, + }, + }, + cfgMutator: func(c *config.BaseOperatorConf) { + c.VMServiceScrape.EnforceEndpointSlices = true + }, + predefinedObjects: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + }, + }, + &vmv1beta1.VMServiceScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vms", + }, + Spec: vmv1beta1.VMServiceScrapeSpec{ + Selector: metav1.LabelSelector{}, + JobLabel: "app", + NamespaceSelector: vmv1beta1.NamespaceSelector{}, + Endpoints: []vmv1beta1.Endpoint{ + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics", + }, + Port: "8085", + EndpointAuth: vmv1beta1.EndpointAuth{ + BearerTokenSecret: &corev1.SecretKeySelector{ + Key: "bearer", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + }, + }, + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics-2", + }, + Port: "8083", + }, + }, + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "access-creds", + Namespace: "default", + }, + Data: map[string][]byte{ + "cid": []byte(`some-client-id`), + "cs": []byte(`some-client-secret`), + "username": []byte(`some-username`), + "password": []byte(`some-password`), + "ca": []byte(`some-ca-cert`), + "cert": []byte(`some-cert`), + "key": []byte(`some-key`), + "bearer": []byte(`some-bearer`), + }, + }, + }, + wantConfig: `global: + scrape_interval: 30m + external_labels: + externalLabelName: externalLabelValue + prometheus: default/test + scrape_timeout: 20m + metric_relabel_configs: + - source_labels: + - test1 + relabel_configs: + - source_labels: + - test2 +scrape_configs: +- job_name: serviceScrape/default/test-vms/0 + kubernetes_sd_configs: + - role: endpointslice + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics + relabel_configs: + - action: keep + source_labels: + - __meta_kubernetes_endpointslice_port_name + regex: "8085" + - source_labels: + - __meta_kubernetes_endpointslice_address_target_kind + - __meta_kubernetes_endpointslice_address_target_name + separator: ; + regex: Node;(.*) + replacement: ${1} + target_label: node + - source_labels: + - __meta_kubernetes_endpointslice_address_target_kind + - __meta_kubernetes_endpointslice_address_target_name + separator: ; + regex: Pod;(.*) + replacement: ${1} + target_label: pod + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_service_name + target_label: service + - source_labels: + - __meta_kubernetes_service_name + target_label: job + replacement: ${1} + - source_labels: + - __meta_kubernetes_service_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "8085" + bearer_token: some-bearer +- job_name: serviceScrape/default/test-vms/1 + kubernetes_sd_configs: + - role: endpointslice + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics-2 + relabel_configs: + - action: keep + source_labels: + - __meta_kubernetes_endpointslice_port_name + regex: "8083" + - source_labels: + - __meta_kubernetes_endpointslice_address_target_kind + - __meta_kubernetes_endpointslice_address_target_name + separator: ; + regex: Node;(.*) + replacement: ${1} + target_label: node + - source_labels: + - __meta_kubernetes_endpointslice_address_target_kind + - __meta_kubernetes_endpointslice_address_target_name + separator: ; + regex: Pod;(.*) + replacement: ${1} + target_label: pod + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_service_name + target_label: service + - source_labels: + - __meta_kubernetes_service_name + target_label: job + replacement: ${1} + - source_labels: + - __meta_kubernetes_service_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "8083" +`, + }) + + // with oauth2 tls config + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + ServiceScrapeNamespaceSelector: &metav1.LabelSelector{}, + ServiceScrapeSelector: &metav1.LabelSelector{}, + PodScrapeSelector: &metav1.LabelSelector{}, + PodScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeNamespaceSelector: &metav1.LabelSelector{}, + NodeScrapeSelector: &metav1.LabelSelector{}, + StaticScrapeNamespaceSelector: &metav1.LabelSelector{}, + StaticScrapeSelector: &metav1.LabelSelector{}, + ProbeNamespaceSelector: &metav1.LabelSelector{}, + ProbeSelector: &metav1.LabelSelector{}, + }, + }, + }, + predefinedObjects: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + }, + }, + &vmv1beta1.VMServiceScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-vms", + }, + Spec: vmv1beta1.VMServiceScrapeSpec{ + Selector: metav1.LabelSelector{}, + JobLabel: "app", + NamespaceSelector: vmv1beta1.NamespaceSelector{}, + Endpoints: []vmv1beta1.Endpoint{ + { + EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{ + Path: "/metrics", + }, + Port: "8085", + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + ClientID: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CLIENT_ID", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "oauth2-access", + }, + }, + }, + ClientSecret: &corev1.SecretKeySelector{ + Key: "CLIENT_SECRET", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "oauth2-access", + }, + }, + TokenURL: "http://some-url", + TLSConfig: &vmv1beta1.TLSConfig{ + CA: vmv1beta1.SecretOrConfigMap{ + ConfigMap: &corev1.ConfigMapKeySelector{ + Key: "CA", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-default", + }, + }, + }, + Cert: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CERT", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + }, + KeySecret: &corev1.SecretKeySelector{ + Key: "SECRET_KEY", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + InsecureSkipVerify: false, + }, + }, + BearerTokenSecret: &corev1.SecretKeySelector{ + Key: "bearer", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "access-creds", + }, + }, + }, + }, + }, + }, + }, + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "dev-pods", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + Port: ptr.To("8081"), + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + ClientID: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CLIENT_ID", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "oauth2-access", + }, + }, + }, + ClientSecret: &corev1.SecretKeySelector{ + Key: "CLIENT_SECRET", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "oauth2-access", + }, + }, + TokenURL: "http://some-url", + TLSConfig: &vmv1beta1.TLSConfig{ + CA: vmv1beta1.SecretOrConfigMap{ + ConfigMap: &corev1.ConfigMapKeySelector{ + Key: "CA", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-default", + }, + }, + }, + Cert: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CERT", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + }, + KeySecret: &corev1.SecretKeySelector{ + Key: "SECRET_KEY", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + InsecureSkipVerify: false, + }, + }, + }, + }, + }, + }, + }, + &vmv1beta1.VMNodeScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "k8s-nodes", + }, + Spec: vmv1beta1.VMNodeScrapeSpec{ + Port: "9093", + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + ClientID: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CLIENT_ID", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "oauth2-access", + }, + }, + }, + ClientSecret: &corev1.SecretKeySelector{ + Key: "CLIENT_SECRET", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "oauth2-access", + }, + }, + TokenURL: "http://some-url", + TLSConfig: &vmv1beta1.TLSConfig{ + CA: vmv1beta1.SecretOrConfigMap{ + ConfigMap: &corev1.ConfigMapKeySelector{ + Key: "CA", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-default", + }, + }, + }, + Cert: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CERT", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + }, + KeySecret: &corev1.SecretKeySelector{ + Key: "SECRET_KEY", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + InsecureSkipVerify: false, + }, + }, + }, + }, + }, + &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tls-default", + Namespace: "default", + }, + Data: map[string]string{ + "CA": "ca data", + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tls-auth", + Namespace: "default", + }, + Data: map[string][]byte{ + "CERT": []byte(`cert data`), + "SECRET_KEY": []byte(`key data`), + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "oauth2-access", + Namespace: "default", + }, + Data: map[string][]byte{ + "CLIENT_ID": []byte(`data`), + "CLIENT_SECRET": []byte(`data`), + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "access-creds", + Namespace: "default", + }, + Data: map[string][]byte{ + "cid": []byte(`some-client-id`), + "cs": []byte(`some-client-secret`), + "username": []byte(`some-username`), + "password": []byte(`some-password`), + "ca": []byte(`some-ca-cert`), + "cert": []byte(`some-cert`), + "key": []byte(`some-key`), + "bearer": []byte(`some-bearer`), + }, + }, + }, + wantConfig: `global: + scrape_interval: 30s + external_labels: + prometheus: default/test +scrape_configs: +- job_name: serviceScrape/default/test-vms/0 + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + honor_labels: false + metrics_path: /metrics + relabel_configs: + - action: keep + source_labels: + - __meta_kubernetes_endpoint_port_name + regex: "8085" + - source_labels: + - __meta_kubernetes_endpoint_address_target_kind + - __meta_kubernetes_endpoint_address_target_name + separator: ; + regex: Node;(.*) + replacement: ${1} + target_label: node + - source_labels: + - __meta_kubernetes_endpoint_address_target_kind + - __meta_kubernetes_endpoint_address_target_name + separator: ; + regex: Pod;(.*) + replacement: ${1} + target_label: pod + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_service_name + target_label: service + - source_labels: + - __meta_kubernetes_service_name + target_label: job + replacement: ${1} + - source_labels: + - __meta_kubernetes_service_label_app + target_label: job + regex: (.+) + replacement: ${1} + - target_label: endpoint + replacement: "8085" + bearer_token: some-bearer + oauth2: + client_id: data + client_secret: data + token_url: http://some-url + tls_config: + ca_file: /etc/vm-tls/certs/default_configmap_tls-default_CA + cert_file: /etc/vm-tls/certs/default_tls-auth_CERT + key_file: /etc/vm-tls/certs/default_tls-auth_SECRET_KEY +- job_name: podScrape/default/dev-pods/0 + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - default + honor_labels: false + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: "8081" + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/dev-pods + - target_label: endpoint + replacement: "8081" + oauth2: + client_id: data + client_secret: data + token_url: http://some-url + tls_config: + ca_file: /etc/vm-tls/certs/default_configmap_tls-default_CA + cert_file: /etc/vm-tls/certs/default_tls-auth_CERT + key_file: /etc/vm-tls/certs/default_tls-auth_SECRET_KEY +- job_name: nodeScrape/default/k8s-nodes + kubernetes_sd_configs: + - role: node + honor_labels: false + relabel_configs: + - source_labels: + - __meta_kubernetes_node_name + target_label: node + - target_label: job + replacement: default/k8s-nodes + - source_labels: + - __address__ + target_label: __address__ + regex: ^(.*):(.*) + replacement: ${1}:9093 + oauth2: + client_id: data + client_secret: data + token_url: http://some-url + tls_config: + ca_file: /etc/vm-tls/certs/default_configmap_tls-default_CA + cert_file: /etc/vm-tls/certs/default_tls-auth_CERT + key_file: /etc/vm-tls/certs/default_tls-auth_SECRET_KEY +`, + }) + + // with invalid objects syntax + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "select-all", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + SelectAllByDefault: true, + CommonScrapeSecurityEnforcements: vmv1beta1.CommonScrapeSecurityEnforcements{ + ArbitraryFSAccessThroughSMs: vmv1beta1.ArbitraryFSAccessThroughSMsConfig{ + Deny: true, + }, + }, + }, + }, + }, + predefinedObjects: []runtime.Object{ + &vmv1beta1.VMServiceScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "fs-access", + }, + Spec: vmv1beta1.VMServiceScrapeSpec{ + Endpoints: []vmv1beta1.Endpoint{ + { + Port: "8080", + EndpointAuth: vmv1beta1.EndpointAuth{ + TLSConfig: &vmv1beta1.TLSConfig{ + CAFile: "/etc/passwd", + }, + }, + }, + }, + }, + }, + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "bad-syntax", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + Selector: *metav1.SetAsLabelSelector(map[string]string{ + "alb.ingress.kubernetes.io/tags": "Environment=devl", + }), + }, + }, + &vmv1beta1.VMProbe{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "bad-syntax", + }, + Spec: vmv1beta1.VMProbeSpec{ + Targets: vmv1beta1.VMProbeTargets{ + Kubernetes: []*vmv1beta1.VMProbeTargetKubernetes{ + { + Role: "ingress", + Selector: *metav1.SetAsLabelSelector(map[string]string{ + "alb.ingress.kubernetes.io/tags": "Environment=devl", + }), + }, + }, + }, + }, + }, + }, + wantConfig: `global: + scrape_interval: 30s + external_labels: + prometheus: default/select-all +scrape_configs: [] +`, + }) + + // with partial missing refs + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "select-all", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + SelectAllByDefault: true, + }, + }, + }, + predefinedObjects: []runtime.Object{ + &vmv1beta1.VMServiceScrape{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "partially-correct", + }, + Spec: vmv1beta1.VMServiceScrapeSpec{ + Endpoints: []vmv1beta1.Endpoint{ + { + Port: "8080", + EndpointAuth: vmv1beta1.EndpointAuth{ + TLSConfig: &vmv1beta1.TLSConfig{ + CA: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "ca", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + }, + }, + }, + }, + { + Port: "8081", + }, + }, + }, + }, + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Name: "partially-correct", + Namespace: "default", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + Port: ptr.To("8035"), + }, + { + Port: ptr.To("8080"), + EndpointAuth: vmv1beta1.EndpointAuth{ + TLSConfig: &vmv1beta1.TLSConfig{ + CA: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "ca", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "tls-auth", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantConfig: `global: + scrape_interval: 30s + external_labels: + prometheus: default/select-all +scrape_configs: [] +`, + }) + + // with scrape classes + f(opts{ + + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "scrape-classes", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + SelectAllByDefault: true, + ScrapeClasses: []vmv1beta1.ScrapeClass{ + { + Name: "default", + Default: ptr.To(true), + EndpointAuth: vmv1beta1.EndpointAuth{ + TLSConfig: &vmv1beta1.TLSConfig{ + CA: vmv1beta1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{Key: "CA", LocalObjectReference: corev1.LocalObjectReference{Name: "tls-default"}}}, + ServerName: "my-server", + }, + }, + AttachMetadata: &vmv1beta1.AttachMetadata{Node: ptr.To(true)}, + EndpointRelabelings: vmv1beta1.EndpointRelabelings{ + MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{}, + RelabelConfigs: []*vmv1beta1.RelabelConfig{}, + }, + }, + + { + Name: "with-oauth2", + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + TokenURL: "http://some-other", + ClientSecretFile: "/path/to/file", + ClientID: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CLIENT_ID", + LocalObjectReference: corev1.LocalObjectReference{Name: "oauth2-access"}, + }, + }, + }, + }, + }, + { + Name: "with-basic-auth", + EndpointAuth: vmv1beta1.EndpointAuth{ + BasicAuth: &vmv1beta1.BasicAuth{ + Username: corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{Name: "basic-auth"}, + }, + PasswordFile: "/path/to/file", + }, + }, + }, + { + Name: "with-oauth2-tls", + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + TokenURL: "http://some", + ClientSecretFile: "/path/to/file", + ClientID: vmv1beta1.SecretOrConfigMap{ + Secret: &corev1.SecretKeySelector{ + Key: "CLIENT_ID", + LocalObjectReference: corev1.LocalObjectReference{Name: "oauth2-access"}, + }, + }, + TLSConfig: &vmv1beta1.TLSConfig{ + CA: vmv1beta1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{Key: "CA", LocalObjectReference: corev1.LocalObjectReference{Name: "tls-default"}}}, + Cert: vmv1beta1.SecretOrConfigMap{Secret: &corev1.SecretKeySelector{Key: "CERT", LocalObjectReference: corev1.LocalObjectReference{Name: "tls-auth"}}}, + KeySecret: &corev1.SecretKeySelector{Key: "CERT", LocalObjectReference: corev1.LocalObjectReference{Name: "tls-auth"}}, + }, + }, + }, + }, + }, + }, + }, + }, + predefinedObjects: []runtime.Object{ + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Name: "class", + Namespace: "default", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + ScrapeClassName: ptr.To("default"), + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{{Port: ptr.To("some")}}, + }, + }, + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Name: "class-oauth2-tls", + Namespace: "default", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + ScrapeClassName: ptr.To("with-oauth2-tls"), + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{{Port: ptr.To("some-other")}}, + }, + }, + &vmv1beta1.VMNodeScrape{ + ObjectMeta: metav1.ObjectMeta{ + Name: "class-oauth2", + Namespace: "default", + }, + Spec: vmv1beta1.VMNodeScrapeSpec{ + ScrapeClassName: ptr.To("with-basic-auth"), + Port: "8035", + }, + }, + &vmv1beta1.VMStaticScrape{ + ObjectMeta: metav1.ObjectMeta{ + Name: "class-oauth2", + Namespace: "default", + }, + Spec: vmv1beta1.VMStaticScrapeSpec{ + ScrapeClassName: ptr.To("with-oauth2"), + TargetEndpoints: []*vmv1beta1.TargetEndpoint{ + { + Targets: []string{"host-1", "host-2"}, + }, + }, + }, + }, + &vmv1beta1.VMScrapeConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "with-own", + Namespace: "default", + }, + Spec: vmv1beta1.VMScrapeConfigSpec{ + ConsulSDConfigs: []vmv1beta1.ConsulSDConfig{ + { + Server: "some", + TLSConfig: &vmv1beta1.TLSConfig{ + CAFile: "/some/other/path", + CertFile: "/some/other/cert", + KeyFile: "/some/other/key", + ServerName: "my-name", + }, + }, + }, + }, + }, + &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tls-default", + Namespace: "default", + }, + Data: map[string]string{ + "CA": "ca data", + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tls-auth", + Namespace: "default", + }, + Data: map[string][]byte{ + "CERT": []byte(`cert data`), + "SECRET_KEY": []byte(`key data`), + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "oauth2-access", + Namespace: "default", + }, + Data: map[string][]byte{ + "CLIENT_ID": []byte(`data`), + "CLIENT_SECRET": []byte(`data`), + }, + }, + }, + wantConfig: `global: + scrape_interval: 30s + external_labels: + prometheus: default/scrape-classes +scrape_configs: +- job_name: podScrape/default/class/0 + kubernetes_sd_configs: + - role: pod + attach_metadata: + node: true + namespaces: + names: + - default + honor_labels: false + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: some + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/class + - target_label: endpoint + replacement: some + tls_config: + ca_file: /etc/vm-tls/certs/default_configmap_tls-default_CA + server_name: my-server +- job_name: podScrape/default/class-oauth2-tls/0 + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - default + honor_labels: false + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: some-other + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/class-oauth2-tls + - target_label: endpoint + replacement: some-other + oauth2: + client_id: data + client_secret_file: /path/to/file + token_url: http://some + tls_config: + ca_file: /etc/vm-tls/certs/default_configmap_tls-default_CA + cert_file: /etc/vm-tls/certs/default_tls-auth_CERT + key_file: /etc/vm-tls/certs/default_tls-auth_CERT +- job_name: staticScrape/default/class-oauth2/0 + static_configs: + - targets: + - host-1 + - host-2 + honor_labels: false + relabel_configs: [] + oauth2: + client_id: data + client_secret_file: /path/to/file + token_url: http://some-other +- job_name: scrapeConfig/default/with-own + honor_labels: false + relabel_configs: [] + tls_config: + ca_file: /etc/vm-tls/certs/default_configmap_tls-default_CA + server_name: my-server + consul_sd_configs: + - server: some + tls_config: + ca_file: /some/other/path + cert_file: /some/other/cert + key_file: /some/other/key + server_name: my-name +`, + }) + + // oauth2 with partial fields set + f(opts{ + cr: &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "with-oauth2", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + SelectAllByDefault: true, + }, + }, + }, + predefinedObjects: []runtime.Object{ + &vmv1beta1.VMPodScrape{ + ObjectMeta: metav1.ObjectMeta{ + Name: "with-oauth2-simple", + Namespace: "default", + }, + Spec: vmv1beta1.VMPodScrapeSpec{ + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + Port: ptr.To("8085"), + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + TokenURL: "http://some-url", + }, + }, + }, + { + Port: ptr.To("8085"), + EndpointAuth: vmv1beta1.EndpointAuth{ + OAuth2: &vmv1beta1.OAuth2{ + TokenURL: "http://some-other", + ClientSecretFile: "/path/to/file", + }, + }, + }, + }, + }, + }, + }, + wantConfig: `global: + scrape_interval: 30s + external_labels: + prometheus: default/with-oauth2 +scrape_configs: +- job_name: podScrape/default/with-oauth2-simple/0 + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - default + honor_labels: false + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: "8085" + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/with-oauth2-simple + - target_label: endpoint + replacement: "8085" + oauth2: + token_url: http://some-url +- job_name: podScrape/default/with-oauth2-simple/1 + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - default + honor_labels: false + relabel_configs: + - action: drop + source_labels: + - __meta_kubernetes_pod_phase + regex: (Failed|Succeeded) + - action: keep + source_labels: + - __meta_kubernetes_pod_container_port_name + regex: "8085" + - source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - source_labels: + - __meta_kubernetes_pod_container_name + target_label: container + - source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - target_label: job + replacement: default/with-oauth2-simple + - target_label: endpoint + replacement: "8085" + oauth2: + client_secret_file: /path/to/file + token_url: http://some-other +`, + }) +} + +func TestScrapeObjectFailedStatus(t *testing.T) { + + type getStatusMeta interface { + GetStatusMetadata() *vmv1beta1.StatusMetadata + } + f := func(so client.Object) { + t.Helper() + expectedConfig := `global: + scrape_interval: 30s + external_labels: + prometheus: default/vmsingle +scrape_configs: [] +` + ctx := context.TODO() + testClient := k8stools.GetTestClientWithClientObjects([]client.Object{so}) + build.AddDefaults(testClient.Scheme()) + + cr := &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vmsingle", + Namespace: "default", + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + IngestOnlyMode: ptr.To(false), + SelectAllByDefault: true, + }, + }, + } + ac := getAssetsCache(ctx, testClient, cr) + if err := createOrUpdateScrapeConfig(ctx, testClient, cr, nil, nil, ac); err != nil { + t.Errorf("createOrUpdateScrapeConfig() error = %s", err) + } + var configSecret corev1.Secret + if err := testClient.Get(ctx, types.NamespacedName{Namespace: cr.Namespace, Name: cr.PrefixedName()}, &configSecret); err != nil { + t.Fatalf("cannot get vmsingle config secret: %s", err) + } + + gotCfg := configSecret.Data[scrapeGzippedFilename] + data, err := build.GunzipConfig(gotCfg) + if err != nil { + t.Fatalf("cannot read cfg: %s", err) + } + assert.Equal(t, expectedConfig, string(data)) + + if err := testClient.Get(ctx, types.NamespacedName{Name: so.GetName(), Namespace: so.GetNamespace()}, so); err != nil { + t.Fatalf("cannot reload object: %s", err) + } + status := so.(getStatusMeta).GetStatusMetadata() + assert.Equal(t, vmv1beta1.UpdateStatusFailed, status.UpdateStatus) + assert.NotEmpty(t, status.Reason) + assert.Len(t, status.Conditions, 1) + + } + commonMeta := metav1.ObjectMeta{ + Name: "invalid", + Namespace: "default", + } + + // invalid selector + f(&vmv1beta1.VMProbe{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMProbeSpec{ + Targets: vmv1beta1.VMProbeTargets{ + Kubernetes: []*vmv1beta1.VMProbeTargetKubernetes{ + { + Role: "ingress", + Selector: *metav1.SetAsLabelSelector(map[string]string{"alb.ingress.kubernetes.io/tags": "Environment=devl"}), + }, + }, + }, + }, + }, + ) + // missing refs + f(&vmv1beta1.VMScrapeConfig{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMScrapeConfigSpec{ + ConsulSDConfigs: []vmv1beta1.ConsulSDConfig{ + { + Server: "http://consul.example.com", + BasicAuth: &vmv1beta1.BasicAuth{ + Username: corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "auth", + }, + }, + }, + }, + }, + }, + }, + ) + commonEndpointAuthWithMissingRef := vmv1beta1.EndpointAuth{ + BasicAuth: &vmv1beta1.BasicAuth{ + Username: corev1.SecretKeySelector{ + Key: "username", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "auth", + }, + }, + }, + } + f(&vmv1beta1.VMProbe{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMProbeSpec{ + EndpointAuth: commonEndpointAuthWithMissingRef, + }, + }) + + f(&vmv1beta1.VMStaticScrape{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMStaticScrapeSpec{ + TargetEndpoints: []*vmv1beta1.TargetEndpoint{ + { + EndpointAuth: commonEndpointAuthWithMissingRef, + }, + }, + }, + }) + f(&vmv1beta1.VMNodeScrape{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMNodeScrapeSpec{ + EndpointAuth: commonEndpointAuthWithMissingRef, + }, + }) + + f(&vmv1beta1.VMPodScrape{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMPodScrapeSpec{ + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + EndpointAuth: commonEndpointAuthWithMissingRef, + }, + }, + }, + }) + + f(&vmv1beta1.VMServiceScrape{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMServiceScrapeSpec{ + Endpoints: []vmv1beta1.Endpoint{ + { + EndpointAuth: commonEndpointAuthWithMissingRef, + }, + }, + }, + }) + + // missing scrapeClass + f(&vmv1beta1.VMServiceScrape{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMServiceScrapeSpec{ + ScrapeClassName: ptr.To("non-exist"), + Endpoints: []vmv1beta1.Endpoint{ + { + Port: "9090", + }, + }, + }, + }) + + // missing scrapeClass + f(&vmv1beta1.VMPodScrape{ + ObjectMeta: commonMeta, + Spec: vmv1beta1.VMPodScrapeSpec{ + ScrapeClassName: ptr.To("non-exist"), + PodMetricsEndpoints: []vmv1beta1.PodMetricsEndpoint{ + { + Port: ptr.To("9090"), + }, + }, + }, + }, + ) + +} diff --git a/internal/controller/operator/factory/vmsingle/vmsingle.go b/internal/controller/operator/factory/vmsingle/vmsingle.go index 8afcd27c7..adeb48867 100644 --- a/internal/controller/operator/factory/vmsingle/vmsingle.go +++ b/internal/controller/operator/factory/vmsingle/vmsingle.go @@ -9,6 +9,7 @@ import ( "gopkg.in/yaml.v2" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" @@ -20,12 +21,21 @@ import ( "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/finalize" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/reconcile" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmscrapes" ) const ( - dataDataDir = "/victoria-metrics-data" - streamAggrSecretKey = "config.yaml" + confDir = "/etc/vm/config" + confOutDir = "/etc/vm/config_out" + tlsAssetsDir = "/etc/vm-tls/certs" + dataDir = "/victoria-metrics-data" + dataVolumeName = "data" + streamAggrSecretKey = "config.yaml" + relabelingName = "relabeling.yaml" + scrapeGzippedFilename = "scrape.yaml.gz" + configFilename = "scrape.yaml" ) func createStorage(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle) error { @@ -69,10 +79,6 @@ func CreateOrUpdate(ctx context.Context, cr *vmv1beta1.VMSingle, rclient client. return fmt.Errorf("cannot delete objects from prev state: %w", err) } } - ac := getAssetsCache(ctx, rclient) - if err := createOrUpdateStreamAggrConfig(ctx, rclient, cr, prevCR, ac); err != nil { - return fmt.Errorf("cannot update stream aggregation config for vmsingle: %w", err) - } owner := cr.AsOwner() if cr.IsOwnsServiceAccount() { var prevSA *corev1.ServiceAccount @@ -82,6 +88,11 @@ func CreateOrUpdate(ctx context.Context, cr *vmv1beta1.VMSingle, rclient client. if err := reconcile.ServiceAccount(ctx, rclient, build.ServiceAccount(cr), prevSA, &owner); err != nil { return fmt.Errorf("failed create service account: %w", err) } + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) { + if err := createK8sAPIAccess(ctx, rclient, cr, prevCR, config.IsClusterWideAccessAllowed()); err != nil { + return fmt.Errorf("cannot create vmsingle role and binding for it, err: %w", err) + } + } } if cr.Spec.Storage != nil { @@ -93,6 +104,17 @@ func CreateOrUpdate(ctx context.Context, cr *vmv1beta1.VMSingle, rclient client. return err } + ac := getAssetsCache(ctx, rclient, cr) + if err := createOrUpdateScrapeConfig(ctx, rclient, cr, prevCR, nil, ac); err != nil { + return err + } + if err := createOrUpdateRelabelConfigsAssets(ctx, rclient, cr, prevCR, ac); err != nil { + return fmt.Errorf("cannot update relabeling asset for vmsingle: %w", err) + } + if err := createOrUpdateStreamAggrConfig(ctx, rclient, cr, prevCR, ac); err != nil { + return fmt.Errorf("cannot update stream aggregation config for vmsingle: %w", err) + } + var prevDeploy *appsv1.Deployment if prevCR != nil { var err error @@ -111,7 +133,7 @@ func CreateOrUpdate(ctx context.Context, cr *vmv1beta1.VMSingle, rclient client. func newDeploy(ctx context.Context, cr *vmv1beta1.VMSingle) (*appsv1.Deployment, error) { - podSpec, err := makeSpec(ctx, cr) + podSpec, err := newPodSpec(ctx, cr) if err != nil { return nil, err } @@ -140,14 +162,14 @@ func newDeploy(ctx context.Context, cr *vmv1beta1.VMSingle) (*appsv1.Deployment, return depSpec, nil } -func makeSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateSpec, error) { +func newPodSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateSpec, error) { var args []string if cr.Spec.RetentionPeriod != "" { args = append(args, fmt.Sprintf("-retentionPeriod=%s", cr.Spec.RetentionPeriod)) } - storagePath := dataDataDir + storagePath := dataDir if cr.Spec.StorageDataPath != "" { storagePath = cr.Spec.StorageDataPath } @@ -176,6 +198,8 @@ func makeSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateS ports = append(ports, corev1.ContainerPort{Name: "http", Protocol: "TCP", ContainerPort: intstr.Parse(cr.Spec.Port).IntVal}) ports = build.AppendInsertPorts(ports, cr.Spec.InsertPorts) + var crMounts []corev1.VolumeMount + var pvcSrc *corev1.PersistentVolumeClaimVolumeSource if cr.Spec.Storage != nil { pvcSrc = &corev1.PersistentVolumeClaimVolumeSource{ @@ -187,6 +211,56 @@ func makeSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateS if err != nil { return nil, err } + + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) { + args = append(args, fmt.Sprintf("-promscrape.config=%s", path.Join(confOutDir, configFilename))) + + // preserve order of volumes and volumeMounts + // it must prevent vmsingle restarts during operator version change + volumes = append(volumes, corev1.Volume{ + Name: string(build.TLSAssetsResourceKind), + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: build.ResourceName(build.TLSAssetsResourceKind, cr), + }, + }, + }) + + volumes = append(volumes, + corev1.Volume{ + Name: "config-out", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + ) + volumes = append(volumes, corev1.Volume{ + Name: string(build.SecretConfigResourceKind), + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: build.ResourceName(build.SecretConfigResourceKind, cr), + }, + }, + }) + m := corev1.VolumeMount{ + Name: "config-out", + MountPath: confOutDir, + } + crMounts = append(crMounts, m) + m.ReadOnly = true + vmMounts = append(vmMounts, m) + vmMounts = append(vmMounts, corev1.VolumeMount{ + Name: string(build.TLSAssetsResourceKind), + MountPath: tlsAssetsDir, + ReadOnly: true, + }) + vmMounts = append(vmMounts, corev1.VolumeMount{ + Name: string(build.SecretConfigResourceKind), + MountPath: confDir, + ReadOnly: true, + }) + } + commonMounts := vmMounts if cr.Spec.VMBackup != nil && cr.Spec.VMBackup.CredentialsSecret != nil { @@ -227,14 +301,24 @@ func makeSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateS }, }, }) - vmMounts = append(vmMounts, corev1.VolumeMount{ + cvm := corev1.VolumeMount{ Name: k8stools.SanitizeVolumeName("configmap-" + c), ReadOnly: true, MountPath: path.Join(vmv1beta1.ConfigMapsDir, c), - }) + } + vmMounts = append(vmMounts, cvm) + crMounts = append(crMounts, cvm) } + mountsLen := len(vmMounts) volumes, vmMounts = build.StreamAggrVolumeTo(volumes, vmMounts, cr) + volumes, vmMounts = build.RelabelVolumeTo(volumes, vmMounts, cr) + crMounts = append(crMounts, vmMounts[mountsLen:]...) + + relabelKeys := []string{"relabel.yaml"} + relabelConfigs := []*vmv1beta1.CommonRelabelParams{&cr.Spec.CommonRelabelParams} + args = build.RelabelArgsTo(args, "relabelConfig", relabelKeys, relabelConfigs...) + streamAggrKeys := []string{streamAggrSecretKey} streamAggrConfigs := []*vmv1beta1.StreamAggrConfig{cr.Spec.StreamAggrConfig} args = build.StreamAggrArgsTo(args, "streamAggr", streamAggrKeys, streamAggrConfigs...) @@ -263,9 +347,25 @@ func makeSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateS } vmsingleContainer = build.Probe(vmsingleContainer, cr) + useStrictSecurity := ptr.Deref(cr.Spec.UseStrictSecurity, false) + + containers := []corev1.Container{vmsingleContainer} + var ic []corev1.Container - operatorContainers := []corev1.Container{vmsingleContainer} - var initContainers []corev1.Container + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) || cr.HasAnyRelabellingConfigs() || cr.HasAnyStreamAggrRule() { + ss := &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: cr.PrefixedName(), + }, + Key: configFilename, + } + configReloader := build.ConfigReloaderContainer(false, cr, crMounts, ss) + containers = append(containers, configReloader) + if !ptr.Deref(cr.Spec.IngestOnlyMode, false) { + ic = append(ic, build.ConfigReloaderContainer(true, cr, crMounts, ss)) + build.AddStrictSecuritySettingsToContainers(cr.Spec.SecurityContext, ic, useStrictSecurity) + } + } if cr.Spec.VMBackup != nil { vmBackupManagerContainer, err := build.VMBackupManager(ctx, cr.Spec.VMBackup, cr.Spec.Port, storagePath, commonMounts, cr.Spec.ExtraArgs, false, cr.Spec.License) @@ -273,7 +373,7 @@ func makeSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateS return nil, err } if vmBackupManagerContainer != nil { - operatorContainers = append(operatorContainers, *vmBackupManagerContainer) + containers = append(containers, *vmBackupManagerContainer) } if cr.Spec.VMBackup.Restore != nil && cr.Spec.VMBackup.Restore.OnStart != nil && @@ -283,19 +383,19 @@ func makeSpec(ctx context.Context, cr *vmv1beta1.VMSingle) (*corev1.PodTemplateS return nil, err } if vmRestore != nil { - initContainers = append(initContainers, *vmRestore) + ic = append(ic, *vmRestore) } } } - build.AddStrictSecuritySettingsToContainers(cr.Spec.SecurityContext, initContainers, ptr.Deref(cr.Spec.UseStrictSecurity, false)) - ic, err := k8stools.MergePatchContainers(initContainers, cr.Spec.InitContainers) + build.AddStrictSecuritySettingsToContainers(cr.Spec.SecurityContext, ic, useStrictSecurity) + ic, err = k8stools.MergePatchContainers(ic, cr.Spec.InitContainers) if err != nil { return nil, fmt.Errorf("cannot apply initContainer patch: %w", err) } - build.AddStrictSecuritySettingsToContainers(cr.Spec.SecurityContext, operatorContainers, ptr.Deref(cr.Spec.UseStrictSecurity, false)) - containers, err := k8stools.MergePatchContainers(operatorContainers, cr.Spec.Containers) + build.AddStrictSecuritySettingsToContainers(cr.Spec.SecurityContext, containers, useStrictSecurity) + containers, err = k8stools.MergePatchContainers(containers, cr.Spec.Containers) if err != nil { return nil, err } @@ -385,6 +485,53 @@ func createOrUpdateService(ctx context.Context, rclient client.Client, cr, prevC return nil } +// buildRelabelingsAssets combines all possible relabeling config configuration and adding it to the configmap. +func buildRelabelingsAssets(cr *vmv1beta1.VMSingle, ac *build.AssetsCache) (*corev1.ConfigMap, error) { + cm := &corev1.ConfigMap{ + ObjectMeta: build.ResourceMeta(build.RelabelConfigResourceKind, cr), + Data: make(map[string]string), + } + if len(cr.Spec.InlineRelabelConfig) > 0 { + rcs := vmscrapes.AddRelabelConfigs(nil, cr.Spec.InlineRelabelConfig) + data, err := yaml.Marshal(rcs) + if err != nil { + return nil, fmt.Errorf("cannot serialize relabelConfig as yaml: %w", err) + } + if len(data) > 0 { + cm.Data[relabelingName] = string(data) + } + } + if cr.Spec.RelabelConfig != nil { + // need to fetch content from + data, err := ac.LoadKeyFromConfigMap(cr.Namespace, cr.Spec.RelabelConfig) + if err != nil { + return nil, fmt.Errorf("cannot fetch configmap: %s, err: %w", cr.Spec.RelabelConfig.Name, err) + } + if len(data) > 0 { + cm.Data[relabelingName] += data + } + } + return cm, nil +} + +// createOrUpdateRelabelConfigsAssets builds relabeling configs for vmsingle at separate configmap, serialized as yaml +func createOrUpdateRelabelConfigsAssets(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle, ac *build.AssetsCache) error { + if !cr.HasAnyRelabellingConfigs() { + return nil + } + assestsCM, err := buildRelabelingsAssets(cr, ac) + if err != nil { + return err + } + var prevConfigMeta *metav1.ObjectMeta + if prevCR != nil { + prevConfigMeta = ptr.To(build.ResourceMeta(build.RelabelConfigResourceKind, prevCR)) + } + owner := cr.AsOwner() + _, err = reconcile.ConfigMap(ctx, rclient, assestsCM, prevConfigMeta, &owner) + return err +} + // buildStreamAggrConfig build configmap with stream aggregation config for vmsingle. func buildStreamAggrConfig(cr *vmv1beta1.VMSingle, ac *build.AssetsCache) (*corev1.ConfigMap, error) { cfgCM := &corev1.ConfigMap{ @@ -458,11 +605,118 @@ func deleteOrphaned(ctx context.Context, rclient client.Client, cr *vmv1beta1.VM if err := finalize.SafeDeleteWithFinalizer(ctx, rclient, &corev1.ServiceAccount{ObjectMeta: objMeta}, &owner); err != nil { return fmt.Errorf("cannot remove serviceaccount: %w", err) } + + rbacMeta := metav1.ObjectMeta{Name: cr.GetRBACName(), Namespace: cr.Namespace} + var objects []client.Object + if config.IsClusterWideAccessAllowed() { + objects = []client.Object{ + &rbacv1.ClusterRoleBinding{ObjectMeta: rbacMeta}, + &rbacv1.ClusterRole{ObjectMeta: rbacMeta}, + } + } else { + objects = []client.Object{ + &rbacv1.RoleBinding{ObjectMeta: rbacMeta}, + &rbacv1.Role{ObjectMeta: rbacMeta}, + } + } + owner := cr.AsCRDOwner() + for _, o := range objects { + if err := finalize.SafeDeleteWithFinalizer(ctx, rclient, o, owner); err != nil { + return fmt.Errorf("cannot remove %T: %w", o, err) + } + } } return nil } -func getAssetsCache(ctx context.Context, rclient client.Client) *build.AssetsCache { - cfg := map[build.ResourceKind]*build.ResourceCfg{} +func getAssetsCache(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle) *build.AssetsCache { + cfg := map[build.ResourceKind]*build.ResourceCfg{ + build.SecretConfigResourceKind: { + MountDir: confDir, + SecretName: build.ResourceName(build.SecretConfigResourceKind, cr), + }, + build.TLSAssetsResourceKind: { + MountDir: tlsAssetsDir, + SecretName: build.ResourceName(build.TLSAssetsResourceKind, cr), + }, + } return build.NewAssetsCache(ctx, rclient, cfg) } + +// CreateOrUpdateScrapeConfig builds scrape configuration for VMSingle +func CreateOrUpdateScrapeConfig(ctx context.Context, rclient client.Client, cr *vmv1beta1.VMSingle, childObject client.Object) error { + var prevCR *vmv1beta1.VMSingle + if cr.ParsedLastAppliedSpec != nil { + prevCR = cr.DeepCopy() + prevCR.Spec = *cr.ParsedLastAppliedSpec + } + ac := getAssetsCache(ctx, rclient, cr) + if err := createOrUpdateScrapeConfig(ctx, rclient, cr, prevCR, childObject, ac); err != nil { + return err + } + return nil +} + +func createOrUpdateScrapeConfig(ctx context.Context, rclient client.Client, cr, prevCR *vmv1beta1.VMSingle, childObject client.Object, ac *build.AssetsCache) error { + if ptr.Deref(cr.Spec.IngestOnlyMode, false) { + return nil + } + + pos := &vmscrapes.ParsedObjects{ + Namespace: cr.Namespace, + APIServerConfig: cr.Spec.APIServerConfig, + HasClusterWideAccess: config.IsClusterWideAccessAllowed() || !cr.IsOwnsServiceAccount(), + ExternalLabels: cr.ExternalLabels(), + } + if !pos.HasClusterWideAccess { + logger.WithContext(ctx).Info("Setting discovery for the single namespace only." + + "Since operator launched with set WATCH_NAMESPACE param. " + + "Set custom ServiceAccountName property for VMSingle if needed.") + pos.IgnoreNamespaceSelectors = true + } + sp := &cr.Spec.CommonScrapeParams + if err := pos.Init(ctx, rclient, sp); err != nil { + return err + } + pos.ValidateObjects(sp) + + // Update secret based on the most recent configuration. + generatedConfig, err := pos.GenerateConfig( + ctx, + sp, + ac, + ) + if err != nil { + return fmt.Errorf("generating config for vmsingle failed: %w", err) + } + + owner := cr.AsOwner() + for kind, secret := range ac.GetOutput() { + var prevSecretMeta *metav1.ObjectMeta + if prevCR != nil { + prevSecretMeta = ptr.To(build.ResourceMeta(kind, prevCR)) + } + if kind == build.SecretConfigResourceKind { + // Compress config to avoid 1mb secret limit for a while + d, err := build.GzipConfig(generatedConfig) + if err != nil { + return fmt.Errorf("cannot gzip config for vmsingle: %w", err) + } + secret.Data[scrapeGzippedFilename] = d + } + secret.ObjectMeta = build.ResourceMeta(kind, cr) + secret.Annotations = map[string]string{ + "generated": "true", + } + if err := reconcile.Secret(ctx, rclient, &secret, prevSecretMeta, &owner); err != nil { + return err + } + } + + parentName := fmt.Sprintf("%s.%s.vmsingle", cr.Name, cr.Namespace) + if err := pos.UpdateStatusesForScrapeObjects(ctx, rclient, parentName, childObject); err != nil { + return err + } + + return nil +} diff --git a/internal/controller/operator/vmagent_controller.go b/internal/controller/operator/vmagent_controller.go index 29f977061..1aff43864 100644 --- a/internal/controller/operator/vmagent_controller.go +++ b/internal/controller/operator/vmagent_controller.go @@ -18,6 +18,7 @@ package operator import ( "context" + "fmt" "sync" "github.com/go-logr/logr" @@ -29,7 +30,9 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/finalize" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/limiter" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmagent" @@ -141,3 +144,50 @@ func (r *VMAgentReconciler) SetupWithManager(mgr ctrl.Manager) error { WithEventFilter(patchAnnotationPredicate). Complete(r) } + +func collectVMAgentScrapes(l logr.Logger, ctx context.Context, rclient client.Client, watchNamespaces []string, instance client.Object) error { + if build.IsControllerDisabled("VMAgent") && agentReconcileLimit.MustThrottleReconcile() { + return nil + } + agentSync.Lock() + defer agentSync.Unlock() + var objects vmv1beta1.VMAgentList + if err := k8stools.ListObjectsByNamespace(ctx, rclient, watchNamespaces, func(dst *vmv1beta1.VMAgentList) { + objects.Items = append(objects.Items, dst.Items...) + }); err != nil { + return fmt.Errorf("cannot list VMAgents for %T: %w", instance, err) + } + for i := range objects.Items { + item := &objects.Items[i] + if item.IsUnmanaged(instance) { + continue + } + l := l.WithValues("vmagent", item.Name, "parent_namespace", item.Namespace) + ctx := logger.AddToContext(ctx, l) + + // only check selector when deleting object, + // since labels can be changed when updating and we can't tell if it was selected before, and we can't tell if it's creating or updating. + if !instance.GetDeletionTimestamp().IsZero() { + objectSelector, namespaceSelector := item.ScrapeSelectors(instance) + opts := &k8stools.SelectorOpts{ + SelectAll: item.Spec.SelectAllByDefault, + NamespaceSelector: namespaceSelector, + ObjectSelector: objectSelector, + DefaultNamespace: instance.GetNamespace(), + } + match, err := isSelectorsMatchesTargetCRD(ctx, rclient, instance, item, opts) + if err != nil { + l.Error(err, fmt.Sprintf("cannot match VMAgent and %T", instance)) + continue + } + if !match { + continue + } + } + + if err := vmagent.CreateOrUpdateScrapeConfig(ctx, rclient, item, instance); err != nil { + continue + } + } + return nil +} diff --git a/internal/controller/operator/vmnodescrape_controller.go b/internal/controller/operator/vmnodescrape_controller.go index 0c0f2f651..6a90a7c3f 100644 --- a/internal/controller/operator/vmnodescrape_controller.go +++ b/internal/controller/operator/vmnodescrape_controller.go @@ -18,7 +18,6 @@ package operator import ( "context" - "fmt" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" @@ -29,9 +28,7 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmagent" ) // VMNodeScrapeReconciler reconciles a VMNodeScrape object @@ -61,8 +58,8 @@ func (r *VMNodeScrapeReconciler) Scheme() *runtime.Scheme { // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmnodescrapes/finalizers,verbs=* func (r *VMNodeScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { l := r.Log.WithValues("vmnodescrape", req.Name, "namespace", req.Namespace) - if build.IsControllerDisabled("VMAgent") { - l.Info("skipping VMNodeScrape reconcile since VMAgent controller is disabled") + if build.IsControllerDisabled("VMAgent") && build.IsControllerDisabled("VMSingle") { + l.Info("skipping VMNodeScrape reconcile since VMAgent and VMSingle controllers are disabled") return } instance := &vmv1beta1.VMNodeScrape{} @@ -80,49 +77,13 @@ func (r *VMNodeScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Request if instance.Spec.ParsingError != "" { return result, &parsingError{instance.Spec.ParsingError, "vmnodescrape"} } - if agentReconcileLimit.MustThrottleReconcile() { - // fast path, rate limited - return - } - - agentSync.Lock() - defer agentSync.Unlock() - var objects vmv1beta1.VMAgentList - if err := k8stools.ListObjectsByNamespace(ctx, r.Client, r.BaseConf.WatchNamespaces, func(dst *vmv1beta1.VMAgentList) { - objects.Items = append(objects.Items, dst.Items...) - }); err != nil { - return result, fmt.Errorf("cannot list vmagents for vmnodescrape: %w", err) + if err = collectVMAgentScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } - for i := range objects.Items { - item := &objects.Items[i] - if item.IsUnmanaged(instance) { - continue - } - l := l.WithValues("vmagent", item.Name, "parent_namespace", item.Namespace) - ctx := logger.AddToContext(ctx, l) - if !instance.DeletionTimestamp.IsZero() { - objectSelector, namespaceSelector := item.ScrapeSelectors(instance) - opts := &k8stools.SelectorOpts{ - SelectAll: item.Spec.SelectAllByDefault, - NamespaceSelector: namespaceSelector, - ObjectSelector: objectSelector, - DefaultNamespace: instance.Namespace, - } - match, err := isSelectorsMatchesTargetCRD(ctx, r.Client, instance, item, opts) - if err != nil { - l.Error(err, "cannot match vmagent and vmnodescrape") - continue - } - if !match { - continue - } - } - - if err := vmagent.CreateOrUpdateScrapeConfig(ctx, r, item, instance); err != nil { - continue - } + if err = collectVMSingleScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } return diff --git a/internal/controller/operator/vmpodscrape_controller.go b/internal/controller/operator/vmpodscrape_controller.go index ee9e7cdc9..c9ea6ba05 100644 --- a/internal/controller/operator/vmpodscrape_controller.go +++ b/internal/controller/operator/vmpodscrape_controller.go @@ -18,7 +18,6 @@ package operator import ( "context" - "fmt" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" @@ -29,9 +28,7 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmagent" ) // VMPodScrapeReconciler reconciles a VMPodScrape object @@ -60,8 +57,8 @@ func (r *VMPodScrapeReconciler) Scheme() *runtime.Scheme { // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmpodscrapes/status,verbs=get;update;patch func (r *VMPodScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { l := r.Log.WithValues("vmpodscrape", req.Name, "namespace", req.Namespace) - if build.IsControllerDisabled("VMAgent") { - l.Info("skipping VMPodScrape reconcile since VMAgent controller is disabled") + if build.IsControllerDisabled("VMAgent") && build.IsControllerDisabled("VMSingle") { + l.Info("skipping VMPodScrape reconcile since VMAgent and VMSingle controllers are disabled") return } instance := &vmv1beta1.VMPodScrape{} @@ -79,53 +76,12 @@ func (r *VMPodScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Request) if instance.Spec.ParsingError != "" { return result, &parsingError{instance.Spec.ParsingError, "vmpodscrape"} } - if agentReconcileLimit.MustThrottleReconcile() { + if err = collectVMAgentScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { return } - - agentSync.Lock() - defer agentSync.Unlock() - - var objects vmv1beta1.VMAgentList - if err := k8stools.ListObjectsByNamespace(ctx, r.Client, r.BaseConf.WatchNamespaces, func(dst *vmv1beta1.VMAgentList) { - objects.Items = append(objects.Items, dst.Items...) - }); err != nil { - return result, fmt.Errorf("cannot list vmagents for vmpodscrape: %w", err) - } - - for i := range objects.Items { - item := &objects.Items[i] - if item.IsUnmanaged(instance) { - continue - } - l := l.WithValues("vmagent", item.Name, "parent_namespace", item.Namespace) - ctx := logger.AddToContext(ctx, l) - - // only check selector when deleting object, - // since labels can be changed when updating and we can't tell if it was selected before, and we can't tell if it's creating or updating. - if !instance.DeletionTimestamp.IsZero() { - objectSelector, namespaceSelector := item.ScrapeSelectors(instance) - opts := &k8stools.SelectorOpts{ - SelectAll: item.Spec.SelectAllByDefault, - NamespaceSelector: namespaceSelector, - ObjectSelector: objectSelector, - DefaultNamespace: instance.Namespace, - } - match, err := isSelectorsMatchesTargetCRD(ctx, r.Client, instance, item, opts) - if err != nil { - l.Error(err, "cannot match vmagent and vmpodscrape") - continue - } - if !match { - continue - } - } - - if err := vmagent.CreateOrUpdateScrapeConfig(ctx, r, item, instance); err != nil { - continue - } + if err = collectVMSingleScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } - return } diff --git a/internal/controller/operator/vmprobe_controller.go b/internal/controller/operator/vmprobe_controller.go index 26c112d99..234fb1d53 100644 --- a/internal/controller/operator/vmprobe_controller.go +++ b/internal/controller/operator/vmprobe_controller.go @@ -18,7 +18,6 @@ package operator import ( "context" - "fmt" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" @@ -29,9 +28,7 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmagent" ) // VMProbeReconciler reconciles a VMProbe object @@ -60,8 +57,8 @@ func (r *VMProbeReconciler) Scheme() *runtime.Scheme { // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmprobes/status,verbs=get;update;patch func (r *VMProbeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { l := r.Log.WithValues("vmprobe", req.Name, "namespace", req.Namespace) - if build.IsControllerDisabled("VMAgent") { - l.Info("skipping VMProbe reconcile since VMAgent controller is disabled") + if build.IsControllerDisabled("VMAgent") && build.IsControllerDisabled("VMSingle") { + l.Info("skipping VMProbe reconcile since VMAgent and VMSingle controllers are disabled") return } instance := &vmv1beta1.VMProbe{} @@ -79,52 +76,11 @@ func (r *VMProbeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re if instance.Spec.ParsingError != "" { return result, &parsingError{instance.Spec.ParsingError, "vmprobescrape"} } - if agentReconcileLimit.MustThrottleReconcile() { - // fast path, rate limited + if err = collectVMAgentScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { return } - - agentSync.Lock() - defer agentSync.Unlock() - - var objects vmv1beta1.VMAgentList - if err := k8stools.ListObjectsByNamespace(ctx, r.Client, r.BaseConf.WatchNamespaces, func(dst *vmv1beta1.VMAgentList) { - objects.Items = append(objects.Items, dst.Items...) - }); err != nil { - return result, fmt.Errorf("cannot list vmagents for vmprobe: %w", err) - } - - for i := range objects.Items { - item := &objects.Items[i] - if item.IsUnmanaged(instance) { - continue - } - l := l.WithValues("vmagent", item.Name, "parent_namespace", item.Namespace) - ctx := logger.AddToContext(ctx, l) - - // only check selector when deleting object, - // since labels can be changed when updating and we can't tell if it was selected before, and we can't tell if it's creating or updating. - if !instance.DeletionTimestamp.IsZero() { - objectSelector, namespaceSelector := item.ScrapeSelectors(item) - opts := &k8stools.SelectorOpts{ - SelectAll: item.Spec.SelectAllByDefault, - NamespaceSelector: namespaceSelector, - ObjectSelector: objectSelector, - DefaultNamespace: instance.Namespace, - } - match, err := isSelectorsMatchesTargetCRD(ctx, r.Client, instance, item, opts) - if err != nil { - l.Error(err, "cannot match vmagent and vmprobe") - continue - } - if !match { - continue - } - } - - if err := vmagent.CreateOrUpdateScrapeConfig(ctx, r, item, instance); err != nil { - continue - } + if err = collectVMSingleScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } return } diff --git a/internal/controller/operator/vmprometheusconverter_controller.go b/internal/controller/operator/vmprometheusconverter_controller.go index 22dcefffe..fd9309cb5 100644 --- a/internal/controller/operator/vmprometheusconverter_controller.go +++ b/internal/controller/operator/vmprometheusconverter_controller.go @@ -83,7 +83,7 @@ func NewConverterController(ctx context.Context, baseClient *kubernetes.Clientse kindReadyByGroup: map[string]map[string]chan struct{}{}, }, } - + scrapeControllersDisabled := build.IsControllerDisabled("VMAgent") && build.IsControllerDisabled("VMSingle") if !build.IsControllerDisabled("VMRule") || !build.IsControllerDisabled("VMAlert") { c.ruleInf = cache.NewSharedIndexInformer( &cache.ListWatch{ @@ -112,7 +112,7 @@ func NewConverterController(ctx context.Context, baseClient *kubernetes.Clientse } } - if !build.IsControllerDisabled("VMPodScrape") || !build.IsControllerDisabled("VMAgent") { + if !build.IsControllerDisabled("VMPodScrape") || !scrapeControllersDisabled { c.podInf = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { @@ -140,7 +140,7 @@ func NewConverterController(ctx context.Context, baseClient *kubernetes.Clientse } } - if !build.IsControllerDisabled("VMServiceScrape") || !build.IsControllerDisabled("VMAgent") { + if !build.IsControllerDisabled("VMServiceScrape") || !scrapeControllersDisabled { c.serviceInf = cache.NewSharedIndexInformer( &cache.ListWatch{ @@ -198,7 +198,7 @@ func NewConverterController(ctx context.Context, baseClient *kubernetes.Clientse c.amConfigInf = amConfigInf } - if !build.IsControllerDisabled("VMProbe") || !build.IsControllerDisabled("VMAgent") { + if !build.IsControllerDisabled("VMProbe") || !scrapeControllersDisabled { c.probeInf = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { @@ -226,7 +226,7 @@ func NewConverterController(ctx context.Context, baseClient *kubernetes.Clientse } } - if !build.IsControllerDisabled("VMScrapeConfig") || !build.IsControllerDisabled("VMAgent") { + if !build.IsControllerDisabled("VMScrapeConfig") || !scrapeControllersDisabled { c.scrapeConfigInf = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { diff --git a/internal/controller/operator/vmscrapeconfig_controller.go b/internal/controller/operator/vmscrapeconfig_controller.go index 10e65bb7f..5b706d50d 100644 --- a/internal/controller/operator/vmscrapeconfig_controller.go +++ b/internal/controller/operator/vmscrapeconfig_controller.go @@ -18,7 +18,6 @@ package operator import ( "context" - "fmt" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" @@ -29,9 +28,7 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmagent" ) // VMScrapeConfigReconciler reconciles a VMScrapeConfig object @@ -60,8 +57,8 @@ func (r *VMScrapeConfigReconciler) Scheme() *runtime.Scheme { // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmscrapeconfigs/status,verbs=get;update;patch func (r *VMScrapeConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { l := r.Log.WithValues("vmscrapeconfig", req.Name, "namespace", req.Namespace) - if build.IsControllerDisabled("VMAgent") { - l.Info("skipping VMScrapeConfig reconcile since VMAgent controller is disabled") + if build.IsControllerDisabled("VMAgent") && build.IsControllerDisabled("VMSingle") { + l.Info("skipping VMScrapeConfig reconcile since VMAgent and VMSingle controllers are disabled") return } instance := &vmv1beta1.VMScrapeConfig{} @@ -79,50 +76,11 @@ func (r *VMScrapeConfigReconciler) Reconcile(ctx context.Context, req ctrl.Reque if instance.Spec.ParsingError != "" { return result, &parsingError{instance.Spec.ParsingError, "vmscrapeconfig"} } - if agentReconcileLimit.MustThrottleReconcile() { - // fast path, rate limited + if err = collectVMAgentScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { return } - - agentSync.Lock() - defer agentSync.Unlock() - var objects vmv1beta1.VMAgentList - if err := k8stools.ListObjectsByNamespace(ctx, r.Client, r.BaseConf.WatchNamespaces, func(dst *vmv1beta1.VMAgentList) { - objects.Items = append(objects.Items, dst.Items...) - }); err != nil { - return result, fmt.Errorf("cannot list vmagents for vmscrapeconfig: %w", err) - } - - for i := range objects.Items { - item := &objects.Items[i] - if item.IsUnmanaged(instance) { - continue - } - l := l.WithValues("vmagent", item.Name, "parent_namespace", item.Namespace) - ctx := logger.AddToContext(ctx, l) - // only check selector when deleting object, - // since labels can be changed when updating and we can't tell if it was selected before, and we can't tell if it's creating or updating. - if !instance.DeletionTimestamp.IsZero() { - objectSelector, namespaceSelector := item.ScrapeSelectors(instance) - opts := &k8stools.SelectorOpts{ - SelectAll: item.Spec.SelectAllByDefault, - NamespaceSelector: namespaceSelector, - ObjectSelector: objectSelector, - DefaultNamespace: instance.Namespace, - } - match, err := isSelectorsMatchesTargetCRD(ctx, r.Client, instance, item, opts) - if err != nil { - l.Error(err, "cannot match vmagent and vmscrapeconfig") - continue - } - if !match { - continue - } - } - - if err := vmagent.CreateOrUpdateScrapeConfig(ctx, r, item, instance); err != nil { - continue - } + if err = collectVMSingleScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } return } diff --git a/internal/controller/operator/vmservicescrape_controller.go b/internal/controller/operator/vmservicescrape_controller.go index 696ca7b47..e7468193b 100644 --- a/internal/controller/operator/vmservicescrape_controller.go +++ b/internal/controller/operator/vmservicescrape_controller.go @@ -18,7 +18,6 @@ package operator import ( "context" - "fmt" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" @@ -29,9 +28,7 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmagent" ) // VMServiceScrapeReconciler reconciles a VMServiceScrape object @@ -60,8 +57,8 @@ func (r *VMServiceScrapeReconciler) Scheme() *runtime.Scheme { // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmservicescrapes/status,verbs=get;update;patch func (r *VMServiceScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { l := r.Log.WithValues("vmservicescrape", req.Name, "namespace", req.Namespace) - if build.IsControllerDisabled("VMAgent") { - l.Info("skipping VMServiceScrape reconcile since VMAgent controller is disabled") + if build.IsControllerDisabled("VMAgent") && build.IsControllerDisabled("VMSingle") { + l.Info("skipping VMServiceScrape reconcile since VMAgent and VMSingle controllers are disabled") return } instance := &vmv1beta1.VMServiceScrape{} @@ -79,51 +76,11 @@ func (r *VMServiceScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Requ if instance.Spec.ParsingError != "" { return result, &parsingError{instance.Spec.ParsingError, "vmservicescrape"} } - - if agentReconcileLimit.MustThrottleReconcile() { - // fast path, rate limited + if err = collectVMAgentScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { return } - - agentSync.Lock() - defer agentSync.Unlock() - var objects vmv1beta1.VMAgentList - if err := k8stools.ListObjectsByNamespace(ctx, r.Client, r.BaseConf.WatchNamespaces, func(dst *vmv1beta1.VMAgentList) { - objects.Items = append(objects.Items, dst.Items...) - }); err != nil { - return result, fmt.Errorf("cannot list vmagents for vmservicescrape: %w", err) - } - - for i := range objects.Items { - item := &objects.Items[i] - if item.IsUnmanaged(instance) { - continue - } - l := l.WithValues("vmagent", item.Name, "parent_namespace", item.Namespace) - ctx := logger.AddToContext(ctx, l) - // only check selector when deleting object, - // since labels can be changed when updating and we can't tell if it was selected before, and we can't tell if it's creating or updating. - if !instance.DeletionTimestamp.IsZero() { - objectSelector, namespaceSelector := item.ScrapeSelectors(instance) - opts := &k8stools.SelectorOpts{ - SelectAll: item.Spec.SelectAllByDefault, - NamespaceSelector: namespaceSelector, - ObjectSelector: objectSelector, - DefaultNamespace: instance.Namespace, - } - match, err := isSelectorsMatchesTargetCRD(ctx, r.Client, instance, item, opts) - if err != nil { - l.Error(err, "cannot match vmagent and vmservicescrape") - continue - } - if !match { - continue - } - } - - if err := vmagent.CreateOrUpdateScrapeConfig(ctx, r, item, instance); err != nil { - continue - } + if err = collectVMSingleScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } return } diff --git a/internal/controller/operator/vmsingle_controller.go b/internal/controller/operator/vmsingle_controller.go index ff22280a2..86e72f348 100644 --- a/internal/controller/operator/vmsingle_controller.go +++ b/internal/controller/operator/vmsingle_controller.go @@ -19,6 +19,7 @@ package operator import ( "context" "fmt" + "sync" "github.com/go-logr/logr" appsv1 "k8s.io/api/apps/v1" @@ -29,11 +30,19 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/finalize" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" + "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/limiter" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmsingle" ) +var ( + vmsingleSync sync.Mutex + vmsingleReconcileLimit = limiter.NewRateLimiter("vmsingle", 5) +) + // VMSingleReconciler reconciles a VMSingle object type VMSingleReconciler struct { client.Client @@ -57,11 +66,25 @@ func (r *VMSingleReconciler) Scheme() *runtime.Scheme { // Reconcile general reconcile method for controller // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmsingles,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmsingles/status,verbs=get;update;patch // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmsingles/finalizers,verbs=* +// +kubebuilder:rbac:groups="",resources=pods,verbs=* +// +kubebuilder:rbac:groups="",resources=nodes,verbs=get;watch;list +// +kubebuilder:rbac:groups="",resources=nodes/metrics,verbs=get;watch;list +// +kubebuilder:rbac:groups="networking.k8s.io",resources=ingresses,verbs=get;watch;list +// +kubebuilder:rbac:groups="",resources=events,verbs=* +// +kubebuilder:rbac:groups="",resources=endpoints,verbs=* +// +kubebuilder:rbac:groups="",resources=endpointslices,verbs=get;watch;list +// +kubebuilder:rbac:groups="",resources=services,verbs=* +// +kubebuilder:rbac:groups="",resources=services/finalizers,verbs=* +// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=*,verbs=* +// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;watch;list +// +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterrolebindings,verbs=get;create,update;list +// +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterroles,verbs=get;create,update;list +// +kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;create,update;list // +kubebuilder:rbac:groups=apps,resources=deployments,verbs=* // +kubebuilder:rbac:groups=apps,resources=replicasets,verbs=* // +kubebuilder:rbac:groups="",resources=persistentvolumeclaims,verbs=* -// +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmsingles/status,verbs=get;update;patch func (r *VMSingleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { l := r.Log.WithValues("vmsingle", req.Name, "namespace", req.Namespace) ctx = logger.AddToContext(ctx, l) @@ -114,3 +137,51 @@ func (r *VMSingleReconciler) SetupWithManager(mgr ctrl.Manager) error { WithEventFilter(patchAnnotationPredicate). Complete(r) } + +func collectVMSingleScrapes(l logr.Logger, ctx context.Context, rclient client.Client, watchNamespaces []string, instance client.Object) error { + if build.IsControllerDisabled("VMSingle") && vmsingleReconcileLimit.MustThrottleReconcile() { + return nil + } + vmsingleSync.Lock() + defer vmsingleSync.Unlock() + + var objects vmv1beta1.VMSingleList + if err := k8stools.ListObjectsByNamespace(ctx, rclient, watchNamespaces, func(dst *vmv1beta1.VMSingleList) { + objects.Items = append(objects.Items, dst.Items...) + }); err != nil { + return fmt.Errorf("cannot list VMSingles for %T: %w", instance, err) + } + + for i := range objects.Items { + item := &objects.Items[i] + if item.IsUnmanaged(instance) { + continue + } + l := l.WithValues("vmsingle", item.Name, "parent_namespace", item.Namespace) + ctx := logger.AddToContext(ctx, l) + // only check selector when deleting object, + // since labels can be changed when updating and we can't tell if it was selected before, and we can't tell if it's creating or updating. + if !instance.GetDeletionTimestamp().IsZero() { + objectSelector, namespaceSelector := item.ScrapeSelectors(instance) + opts := &k8stools.SelectorOpts{ + SelectAll: item.Spec.SelectAllByDefault, + NamespaceSelector: namespaceSelector, + ObjectSelector: objectSelector, + DefaultNamespace: instance.GetNamespace(), + } + match, err := isSelectorsMatchesTargetCRD(ctx, rclient, instance, item, opts) + if err != nil { + l.Error(err, fmt.Sprintf("cannot match VMSingle and %T", instance)) + continue + } + if !match { + continue + } + } + + if err := vmsingle.CreateOrUpdateScrapeConfig(ctx, rclient, item, instance); err != nil { + continue + } + } + return nil +} diff --git a/internal/controller/operator/vmstaticscrape_controller.go b/internal/controller/operator/vmstaticscrape_controller.go index 528eb8731..c209cd5df 100644 --- a/internal/controller/operator/vmstaticscrape_controller.go +++ b/internal/controller/operator/vmstaticscrape_controller.go @@ -2,7 +2,6 @@ package operator import ( "context" - "fmt" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" @@ -13,9 +12,6 @@ import ( vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/build" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/k8stools" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/vmagent" ) // VMStaticScrapeReconciler reconciles a VMStaticScrape object @@ -44,8 +40,8 @@ func (r *VMStaticScrapeReconciler) Scheme() *runtime.Scheme { // +kubebuilder:rbac:groups=operator.victoriametrics.com,resources=vmstaticscrapes/status,verbs=get;update;patch func (r *VMStaticScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { l := r.Log.WithValues("vmstaticscrape", req.Name, "namespace", req.Namespace) - if build.IsControllerDisabled("VMAgent") { - l.Info("skipping VMStaticScrape reconcile since VMAgent controller is disabled") + if build.IsControllerDisabled("VMAgent") && build.IsControllerDisabled("VMSingle") { + l.Info("skipping VMStaticScrape reconcile since VMAgent and VMSingle controllers are disabled") return } instance := &vmv1beta1.VMStaticScrape{} @@ -59,50 +55,11 @@ func (r *VMStaticScrapeReconciler) Reconcile(ctx context.Context, req ctrl.Reque if instance.Spec.ParsingError != "" { return result, &parsingError{instance.Spec.ParsingError, "vmstaticscrape"} } - if agentReconcileLimit.MustThrottleReconcile() { - // fast path, rate limited - return ctrl.Result{}, nil - } - agentSync.Lock() - defer agentSync.Unlock() - - var objects vmv1beta1.VMAgentList - if err := k8stools.ListObjectsByNamespace(ctx, r.Client, r.BaseConf.WatchNamespaces, func(dst *vmv1beta1.VMAgentList) { - objects.Items = append(objects.Items, dst.Items...) - }); err != nil { - return result, fmt.Errorf("cannot list vmagents for vmstaticscrape: %w", err) + if err = collectVMAgentScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } - - for i := range objects.Items { - item := &objects.Items[i] - if item.IsUnmanaged(instance) { - continue - } - l := l.WithValues("vmagent", item.Name, "parent_namespace", item.Namespace) - ctx := logger.AddToContext(ctx, l) - // only check selector when deleting object, - // since labels can be changed when updating and we can't tell if it was selected before, and we can't tell if it's creating or updating. - if !instance.DeletionTimestamp.IsZero() { - objectSelector, namespaceSelector := item.ScrapeSelectors(instance) - opts := &k8stools.SelectorOpts{ - SelectAll: item.Spec.SelectAllByDefault, - NamespaceSelector: namespaceSelector, - ObjectSelector: objectSelector, - DefaultNamespace: instance.Namespace, - } - match, err := isSelectorsMatchesTargetCRD(ctx, r.Client, instance, item, opts) - if err != nil { - l.Error(err, "cannot match vmagent and vmstaticscrape") - continue - } - if !match { - continue - } - } - - if err := vmagent.CreateOrUpdateScrapeConfig(ctx, r, item, instance); err != nil { - continue - } + if err = collectVMSingleScrapes(l, ctx, r.Client, r.BaseConf.WatchNamespaces, instance); err != nil { + return } return } diff --git a/test/e2e/vmagent_test.go b/test/e2e/vmagent_test.go index ee8525f33..00111730a 100644 --- a/test/e2e/vmagent_test.go +++ b/test/e2e/vmagent_test.go @@ -358,7 +358,7 @@ var _ = Describe("test vmagent Controller", Label("vm", "agent", "vmagent"), fun }, RoleRef: rbacv1.RoleRef{ APIGroup: rbacv1.GroupName, - Name: cr.GetClusterRoleName(), + Name: cr.GetRBACName(), Kind: "ClusterRole", }, }