From c6b7287b02ab7fc20a279e0cd7dcb2edc69938fb Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 22 Jun 2022 09:11:04 -0500 Subject: [PATCH 01/64] Add stack monitoring for Beats Add documentation for Beats stack monitoring --- .../recipes/beats/heartbeat_es_kb_health.yaml | 3 + .../advanced-topics/stack-monitoring.asciidoc | 15 ++- pkg/apis/beat/v1beta1/beat_types.go | 22 ++++ pkg/controller/beat/common/config.go | 109 ++++++++++++++++++ pkg/controller/beat/common/config_test.go | 88 ++++++++++++++ pkg/controller/beat/common/driver.go | 2 + pkg/controller/beat/common/monitoring.go | 31 +++++ pkg/controller/beat/common/pod.go | 12 ++ .../stackmon/validations/validations.go | 1 + 9 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 pkg/controller/beat/common/monitoring.go diff --git a/config/recipes/beats/heartbeat_es_kb_health.yaml b/config/recipes/beats/heartbeat_es_kb_health.yaml index ee5d65c1ee..7779cfc0ed 100644 --- a/config/recipes/beats/heartbeat_es_kb_health.yaml +++ b/config/recipes/beats/heartbeat_es_kb_health.yaml @@ -7,6 +7,9 @@ spec: version: 8.2.0 elasticsearchRef: name: elasticsearch + monitoring: + elasticsearchRefs: + - name: elasticsearch config: heartbeat.monitors: - type: tcp diff --git a/docs/advanced-topics/stack-monitoring.asciidoc b/docs/advanced-topics/stack-monitoring.asciidoc index 8ff0a2f99c..e51cb31990 100644 --- a/docs/advanced-topics/stack-monitoring.asciidoc +++ b/docs/advanced-topics/stack-monitoring.asciidoc @@ -9,7 +9,7 @@ endif::[] = Stack Monitoring You can enable link:https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html[Stack Monitoring] -on Elasticsearch and Kibana to collect and ship their metrics and logs to a dedicated monitoring cluster. +on Elasticsearch, Kibana and Beats to collect and ship their metrics and logs to a dedicated monitoring cluster. To enable stack monitoring, simply reference the monitoring Elasticsearch cluster in the `spec.monitoring` section of their specification. @@ -57,10 +57,23 @@ spec: - name: monitoring namespace: observability <1> count: 1 +--- +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: monitored-sample +spec: + type: filebeat + version: {version} + monitoring: + elasticsearchRefs: + - name: monitoring + namespace: observability <3> ---- <1> The use of `namespace` is optional if the monitoring Elasticsearch cluster and the monitored Elasticsearch cluster are running in the same namespace. <2> The use of `namespace` is optional if the Elasticsearch cluster and the Kibana instance are running in the same namespace. +<3> The use of `namespace` is optional if the Elasticsearch cluster and the Beats instance are running in the same namespace. NOTE: You can configure an Elasticsearch cluster to monitor itself. diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index e46192808e..151976ed31 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -79,6 +79,13 @@ type BeatSpec struct { // Cannot be used along with `daemonSet`. If both are absent a default for the Type is used. // +kubebuilder:validation:Optional Deployment *DeploymentSpec `json:"deployment,omitempty"` + + // Monitoring enables you to collect and ship log and monitoring data of this Beat. + // See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html + // Internal Beat collectors are configured and sends data (metrics and logs) to one + // or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. + // +kubebuilder:validation:Optional + Monitoring Monitoring `json:"monitoring,omitempty"` } type DaemonSetSpec struct { @@ -96,6 +103,21 @@ type DeploymentSpec struct { Strategy appsv1.DeploymentStrategy `json:"strategy,omitempty"` } +type Monitoring struct { + // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. + // Due to existing limitations, only a single Elasticsearch cluster is currently supported. + // +kubebuilder:validation:Required + ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` +} + +// Enabled returns whether the Beat has stack monitoring enabled. +func (m Monitoring) Enabled() bool { + return len(m.ElasticsearchRefs) > 0 +} + +type MetricsMonitoring struct { +} + // BeatStatus defines the observed state of a Beat. type BeatStatus struct { // Version of the stack resource currently running. During version upgrades, multiple versions may run diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 76c73529dd..a06fa8536c 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -7,18 +7,27 @@ package common import ( "hash" "path" + "strings" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/pkg/errors" + beatv1beta1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/association" "github.com/elastic/cloud-on-k8s/pkg/controller/common" "github.com/elastic/cloud-on-k8s/pkg/controller/common/reconciler" "github.com/elastic/cloud-on-k8s/pkg/controller/common/settings" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/stackmon/validations" + esservices "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/services" + esuser "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) +const externalCAPath = "/tmp/external" + // buildOutputConfig will create the output section in Beat config according to the association configuration. func buildOutputConfig(client k8s.Client, associated beatv1beta1.BeatESAssociation) (*settings.CanonicalConfig, error) { esAssocConf, err := associated.AssociationConf() @@ -94,6 +103,17 @@ func buildBeatConfig( return nil, err } + // If monitoring is enabled, render the relevant section + if params.Beat.Spec.Monitoring.Enabled() { + monitoringConfig, err := getMonitoringConfig(params) + if err != nil { + return nil, err + } + if err = cfg.MergeWith(monitoringConfig); err != nil { + return nil, err + } + } + // get user config from `config` or `configRef` userConfig, err := getUserConfig(params) if err != nil { @@ -111,6 +131,95 @@ func buildBeatConfig( return cfg.Render() } +// getMonitoringConfig returns the stack monitoring configuration for a Beats instance. +// TODO: I believe the ssl pieces are remaining. +func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) { + if len(params.Beat.Spec.Monitoring.ElasticsearchRefs) == 0 { + return nil, errors.New("ElasticsearchRef must exist when stack monitoring is enabled") + } + // only the first ElasticsearchRef is currently supported. + esRef := params.Beat.Spec.Monitoring.ElasticsearchRefs[0] + if !esRef.IsDefined() { + return nil, errors.New(validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg) + } + + var username, password, url string + var sslConfig SSLConfig + if esRef.IsExternal() { + info, err := association.GetUnmanagedAssociationConnectionInfoFromSecret(params.Client, esRef) + url = info.URL + if err != nil { + return nil, err + } + username, password = info.Username, info.Password + if info.CaCert != "" { + // save the monitoring connection information so it doesn't have to be retrieved + // again later when buliding the secret which contains the CA. + params.monitoringAssociationConnectionInfo = info + if _, err := reconciler.ReconcileSecret( + params.Context, + params.Client, + corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: getMonitoringCASecretName(params.Beat.Name), + Namespace: params.Beat.Namespace, + }, + Data: map[string][]byte{ + "ca.crt": []byte(info.CaCert), + }, + }, + ¶ms.Beat, + ); err != nil { + return nil, errors.Wrap(err, "while creating external monitoring ca secret") + } + } + sslConfig = SSLConfig{ + // configure the CA cert needed for external monitoring cluster. + // The secret, and volume for the pod will be created during pod templating. + CertificateAuthorities: []string{path.Join(externalCAPath, CAFileName)}, + VerificationMode: "certificate", + } + } else { + associatedEsNsn := esRef.NamespacedName() + if associatedEsNsn.Namespace == "" { + associatedEsNsn.Namespace = params.Beat.Namespace + } + + var es esv1.Elasticsearch + if err := params.Client.Get(params.Context, associatedEsNsn, &es); err != nil { + return nil, errors.Wrap(err, "while retrieving Beat stack monitoring Elasticsearch instance") + } + + var err error + username = esuser.MonitoringUserName + password, err = esuser.GetMonitoringUserPassword(params.Client, associatedEsNsn) + if err != nil { + return nil, err + } + url = esservices.InternalServiceURL(es) + sslConfig = SSLConfig{ + // TODO: Does this work in all ubi/non-ubi containers? + CertificateAuthorities: []string{"/etc/pki/root/tls.crt"}, + VerificationMode: "certificate", + } + } + + config := MonitoringConfig{ + Enabled: true, + Elasticsearch: ElasticsearchConfig{ + Hosts: []string{url}, + Username: username, + Password: password, + }, + } + + if strings.Contains(url, "https") { + config.Elasticsearch.SSL = sslConfig + } + + return settings.NewCanonicalConfigFrom(map[string]interface{}{"monitoring": config}) +} + // getUserConfig extracts the config either from the spec `config` field or from the Secret referenced by spec // `configRef` field. func getUserConfig(params DriverParams) (*settings.CanonicalConfig, error) { diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index c59786ad17..206ada1931 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -16,6 +16,7 @@ import ( beatv1beta1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/pkg/controller/common/watches" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" @@ -47,6 +48,37 @@ func Test_buildBeatConfig(t *testing.T) { }, ) + clientWithMonitoringEnabled := k8s.NewFakeClient( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testes-es-internal-users", + Namespace: "ns", + }, + Data: map[string][]byte{ + "elastic-internal": []byte("asdf"), + "elastic-internal-monitoring": []byte("asdfasdf"), + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "external-es-monitoring", + Namespace: "ns", + }, + Data: map[string][]byte{ + "url": []byte("https://external-es.external.com"), + "username": []byte("monitoring-user"), + "password": []byte("asdfasdf"), + "ca.crt": []byte("my_pem_encoded_cert"), + }, + }, + &esv1.Elasticsearch{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testes", + Namespace: "ns", + }, + }, + ) + managedCfg := settings.MustParseConfig([]byte("setup.kibana: true")) userCfg := &commonv1.Config{Data: map[string]interface{}{"user": "true"}} userCanonicalCfg := settings.MustCanonicalConfig(userCfg.Data) @@ -59,6 +91,30 @@ func Test_buildBeatConfig(t *testing.T) { password: "123" username: elastic `)) + monitoringYaml := settings.MustParseConfig([]byte(`monitoring: + enabled: true + elasticsearch: + hosts: + - "https://testes-es-internal-http.ns.svc:9200" + username: "elastic-internal-monitoring" + password: asdfasdf + ssl: + certificate_authorities: + - "/etc/pki/root/tls.crt" + verification_mode: "certificate +`)) + externalMonitoringYaml := settings.MustParseConfig([]byte(`monitoring: + enabled: true + elasticsearch: + hosts: + - "https://external-es.external.com" + username: "monitoring-user" + password: asdfasdf + ssl: + certificate_authorities: + - "will_fail" + verification_mode: "certificate +`)) withAssoc := beatv1beta1.Beat{ ObjectMeta: metav1.ObjectMeta{ @@ -105,6 +161,38 @@ func Test_buildBeatConfig(t *testing.T) { }}, want: userCanonicalCfg, }, + { + name: "no association, user config, with monitoring enabled", + client: clientWithMonitoringEnabled, + beat: beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + Monitoring: beatv1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "testes", + Namespace: "ns", + }, + }, + }, + }}, + want: merge(userCanonicalCfg, monitoringYaml), + }, + { + name: "no association, user config, with monitoring enabled, external es cluster", + client: clientWithMonitoringEnabled, + beat: beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + Monitoring: beatv1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + SecretName: "external-es-monitoring", + Namespace: "ns", + }, + }, + }, + }}, + want: merge(userCanonicalCfg, externalMonitoringYaml), + }, { name: "no association, managed config", beat: beatv1beta1.Beat{}, diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 1e0534cc30..2ea57ec676 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -40,6 +40,8 @@ type DriverParams struct { Status *beatv1beta1.BeatStatus Beat beatv1beta1.Beat + + monitoringAssociationConnectionInfo *association.UnmanagedAssociationConnectionInfo } func (dp DriverParams) K8sClient() k8s.Client { diff --git a/pkg/controller/beat/common/monitoring.go b/pkg/controller/beat/common/monitoring.go new file mode 100644 index 0000000000..a4b639e893 --- /dev/null +++ b/pkg/controller/beat/common/monitoring.go @@ -0,0 +1,31 @@ +package common + +import "fmt" + +// MonitoringConfig contains the stack monitoring configuration for Beats. +type MonitoringConfig struct { + Enabled bool `json:"enabled,omitempty"` + Elasticsearch ElasticsearchConfig `json:"elasticsearch"` +} + +// ElasticsearchConfig contains the configuration for connecting to Elasticsearch. +type ElasticsearchConfig struct { + // Hosts are the Elasticsearch host urls to use. + Hosts []string `json:"hosts"` + // Username is the Elasticsearch username. + Username string `json:"username"` + // Password is the Elasticsearch password. + Password string `json:"password"` + // SSL is the ssl configuration for communicating with Elasticsearch. + SSL SSLConfig `json:"ssl,omitempty"` +} + +/// SSLConfig contains the SSL configuration for Beat stack monitoring. +type SSLConfig struct { + CertificateAuthorities []string `json:"certificate_authorities,omitempty"` + VerificationMode string `json:"verification_mode,omitempty"` +} + +func getMonitoringCASecretName(beatName string) string { + return fmt.Sprintf("%s-monitoring-ca", beatName) +} diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index ea98eb870a..91a13268e4 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -115,6 +115,18 @@ func buildPodTemplate( vols = append(vols, caVolume) } + // if the monitoring connection information isn't empty + // then we need to create the secret volume for the CA. + if params.monitoringAssociationConnectionInfo != nil { + monitoringCASecretName := getMonitoringCASecretName(params.Beat.Name) + caVolume := volume.NewSecretVolumeWithMountPath( + monitoringCASecretName, + monitoringCASecretName, + externalCAPath, + ) + vols = append(vols, caVolume) + } + volumes := make([]corev1.Volume, 0, len(vols)) volumeMounts := make([]corev1.VolumeMount, 0, len(vols)) var initContainers []corev1.Container diff --git a/pkg/controller/common/stackmon/validations/validations.go b/pkg/controller/common/stackmon/validations/validations.go index 01a9052a51..7a8fc7f1eb 100644 --- a/pkg/controller/common/stackmon/validations/validations.go +++ b/pkg/controller/common/stackmon/validations/validations.go @@ -19,6 +19,7 @@ const ( invalidElasticsearchRefsMsg = "Only one Elasticsearch reference is supported for %s Stack Monitoring" InvalidKibanaElasticsearchRefForStackMonitoringMsg = "Kibana must be associated to an Elasticsearch cluster through elasticsearchRef in order to enable monitoring metrics features" + InvalidBeatsElasticsearchRefForStackMonitoringMsg = "Beats must be associated to an Elasticsearch cluster through elasticsearchRef in order to enable monitoring metrics features" ) var ( From 165decd9970d8c72be5aaec8e105b558afada1da Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 28 Jun 2022 21:01:16 -0500 Subject: [PATCH 02/64] When calling GetAssociations, also add the monitoring objects. --- cmd/manager/main.go | 1 + config/crds/v1/all-crds.yaml | 57 +++++++++++ .../v1/bases/beat.k8s.elastic.co_beats.yaml | 57 +++++++++++ .../recipes/beats/heartbeat_es_kb_health.yaml | 3 - .../eck-operator-crds/templates/all-crds.yaml | 57 +++++++++++ pkg/apis/beat/v1beta1/beat_types.go | 96 ++++++++++++++++++- .../beat/v1beta1/zz_generated.deepcopy.go | 73 +++++++++++++- pkg/apis/common/v1/association.go | 4 + pkg/apis/elasticsearch/v1/status.go | 2 +- .../association/controller/beat_monitoring.go | 56 +++++++++++ pkg/controller/association/reconciler.go | 4 + pkg/controller/beat/common/config.go | 22 +++-- 12 files changed, 419 insertions(+), 13 deletions(-) create mode 100644 pkg/controller/association/controller/beat_monitoring.go diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 5e34ce302c..817f58fea7 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -817,6 +817,7 @@ func registerControllers(mgr manager.Manager, params operator.Parameters, access {name: "EMS-ES", registerFunc: associationctl.AddMapsES}, {name: "ES-MONITORING", registerFunc: associationctl.AddEsMonitoring}, {name: "KB-MONITORING", registerFunc: associationctl.AddKbMonitoring}, + {name: "BEAT-MONITORING", registerFunc: associationctl.AddBeatMonitoring}, } for _, c := range assocControllers { diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 706e63ae5a..407de23e7a 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2347,6 +2347,54 @@ spec: is used. type: string type: object + monitoring: + description: Monitoring enables you to collect and ship log and monitoring + data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html + Internal Beat collectors are configured and sends data (metrics + and logs) to one or two different Elasticsearch monitoring clusters + running in the same Kubernetes cluster. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of monitoring + Elasticsearch clusters running in the same Kubernetes cluster. + Due to existing limitations, only a single Elasticsearch cluster + is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the operator + or a Secret describing an external Elastic resource not managed + by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing Kubernetes + secret that contains connection information for associating + an Elastic resource not managed by the operator. The referenced + secret must contain the following: - `url`: the URL to + reach the Elastic resource - `username`: the username + of the user to be authenticated to the Elastic resource + - `password`: the password of the user to be authenticated + to the Elastic resource - `ca.crt`: the CA certificate + in PEM format (optional). This field cannot be used in + combination with the other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which is used to make requests to the referenced + object. It has to be in the same namespace as the referenced + resource. If left empty, the default HTTP service of the + referenced resource is used. + type: string + type: object + type: array + type: object secureSettings: description: SecureSettings is a list of references to Kubernetes Secrets containing sensitive configuration options for the Beat. @@ -2423,6 +2471,15 @@ spec: kibanaAssociationStatus: description: AssociationStatus is the status of an association resource. type: string + monitoringAssociationStatus: + additionalProperties: + description: AssociationStatus is the status of an association resource. + type: string + description: AssociationStatusMap is the map of association's namespaced + name string to its AssociationStatus. For resources that have a + single Association of a given type (for ex. single ES reference), + this map contains a single entry. + type: object observedGeneration: description: ObservedGeneration represents the .metadata.generation that the status is based upon. It corresponds to the metadata generation, diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index c90caa47e0..7b79246543 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15218,6 +15218,54 @@ spec: is used. type: string type: object + monitoring: + description: Monitoring enables you to collect and ship log and monitoring + data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html + Internal Beat collectors are configured and sends data (metrics + and logs) to one or two different Elasticsearch monitoring clusters + running in the same Kubernetes cluster. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of monitoring + Elasticsearch clusters running in the same Kubernetes cluster. + Due to existing limitations, only a single Elasticsearch cluster + is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the operator + or a Secret describing an external Elastic resource not managed + by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing Kubernetes + secret that contains connection information for associating + an Elastic resource not managed by the operator. The referenced + secret must contain the following: - `url`: the URL to + reach the Elastic resource - `username`: the username + of the user to be authenticated to the Elastic resource + - `password`: the password of the user to be authenticated + to the Elastic resource - `ca.crt`: the CA certificate + in PEM format (optional). This field cannot be used in + combination with the other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which is used to make requests to the referenced + object. It has to be in the same namespace as the referenced + resource. If left empty, the default HTTP service of the + referenced resource is used. + type: string + type: object + type: array + type: object secureSettings: description: SecureSettings is a list of references to Kubernetes Secrets containing sensitive configuration options for the Beat. @@ -15294,6 +15342,15 @@ spec: kibanaAssociationStatus: description: AssociationStatus is the status of an association resource. type: string + monitoringAssociationStatus: + additionalProperties: + description: AssociationStatus is the status of an association resource. + type: string + description: AssociationStatusMap is the map of association's namespaced + name string to its AssociationStatus. For resources that have a + single Association of a given type (for ex. single ES reference), + this map contains a single entry. + type: object observedGeneration: description: ObservedGeneration represents the .metadata.generation that the status is based upon. It corresponds to the metadata generation, diff --git a/config/recipes/beats/heartbeat_es_kb_health.yaml b/config/recipes/beats/heartbeat_es_kb_health.yaml index 7779cfc0ed..ee5d65c1ee 100644 --- a/config/recipes/beats/heartbeat_es_kb_health.yaml +++ b/config/recipes/beats/heartbeat_es_kb_health.yaml @@ -7,9 +7,6 @@ spec: version: 8.2.0 elasticsearchRef: name: elasticsearch - monitoring: - elasticsearchRefs: - - name: elasticsearch config: heartbeat.monitors: - type: tcp diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 09c813a63d..bcd19ece80 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2365,6 +2365,54 @@ spec: is used. type: string type: object + monitoring: + description: Monitoring enables you to collect and ship log and monitoring + data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html + Internal Beat collectors are configured and sends data (metrics + and logs) to one or two different Elasticsearch monitoring clusters + running in the same Kubernetes cluster. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of monitoring + Elasticsearch clusters running in the same Kubernetes cluster. + Due to existing limitations, only a single Elasticsearch cluster + is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the operator + or a Secret describing an external Elastic resource not managed + by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing Kubernetes + secret that contains connection information for associating + an Elastic resource not managed by the operator. The referenced + secret must contain the following: - `url`: the URL to + reach the Elastic resource - `username`: the username + of the user to be authenticated to the Elastic resource + - `password`: the password of the user to be authenticated + to the Elastic resource - `ca.crt`: the CA certificate + in PEM format (optional). This field cannot be used in + combination with the other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which is used to make requests to the referenced + object. It has to be in the same namespace as the referenced + resource. If left empty, the default HTTP service of the + referenced resource is used. + type: string + type: object + type: array + type: object secureSettings: description: SecureSettings is a list of references to Kubernetes Secrets containing sensitive configuration options for the Beat. @@ -2441,6 +2489,15 @@ spec: kibanaAssociationStatus: description: AssociationStatus is the status of an association resource. type: string + monitoringAssociationStatus: + additionalProperties: + description: AssociationStatus is the status of an association resource. + type: string + description: AssociationStatusMap is the map of association's namespaced + name string to its AssociationStatus. For resources that have a + single Association of a given type (for ex. single ES reference), + this map contains a single entry. + type: object observedGeneration: description: ObservedGeneration represents the .metadata.generation that the status is based upon. It corresponds to the metadata generation, diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index 151976ed31..7a1436b549 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -138,6 +138,9 @@ type BeatStatus struct { // +kubebuilder:validation:Optional KibanaAssociationStatus commonv1.AssociationStatus `json:"kibanaAssociationStatus,omitempty"` + // +kubebuilder:validation:Optional + MonitoringAssociationsStatus commonv1.AssociationStatusMap `json:"monitoringAssociationStatus,omitempty"` + // ObservedGeneration represents the .metadata.generation that the status is based upon. // It corresponds to the metadata generation, which is updated on mutation by the API Server. // If the generation observed in status diverges from the generation in metadata, the Beats @@ -183,6 +186,8 @@ type Beat struct { Status BeatStatus `json:"status,omitempty"` esAssocConf *commonv1.AssociationConf `json:"-"` kbAssocConf *commonv1.AssociationConf `json:"-"` + // monitoringAssocConf holds the configuration for the monitoring Elasticsearch clusters association + monitoringAssocConfs map[commonv1.ObjectSelector]commonv1.AssociationConf `json:"-"` } func (b *Beat) AssociationStatusMap(typ commonv1.AssociationType) commonv1.AssociationStatusMap { @@ -195,6 +200,12 @@ func (b *Beat) AssociationStatusMap(typ commonv1.AssociationType) commonv1.Assoc if b.Spec.KibanaRef.IsDefined() { return commonv1.NewSingleAssociationStatusMap(b.Status.KibanaAssociationStatus) } + case commonv1.BeatMonitoringAssociationType: + for _, esRef := range b.Spec.Monitoring.ElasticsearchRefs { + if esRef.IsDefined() { + return b.Status.MonitoringAssociationsStatus + } + } } return commonv1.AssociationStatusMap{} @@ -213,8 +224,11 @@ func (b *Beat) SetAssociationStatusMap(typ commonv1.AssociationType, status comm case commonv1.KibanaAssociationType: b.Status.KibanaAssociationStatus = single return nil + case commonv1.BeatMonitoringAssociationType: + b.Status.MonitoringAssociationsStatus = status + return nil default: - return fmt.Errorf("association type %s not known", typ) + return fmt.Errorf("beat: association type %s not known", typ) } } @@ -237,6 +251,14 @@ func (b *Beat) GetAssociations() []commonv1.Association { Beat: b, }) } + for _, ref := range b.Spec.Monitoring.ElasticsearchRefs { + if ref.IsDefined() { + associations = append(associations, &BeatMonitoringAssociation{ + Beat: b, + ref: ref.WithDefaultNamespace(b.Namespace), + }) + } + } return associations } @@ -357,3 +379,75 @@ type BeatList struct { func init() { SchemeBuilder.Register(&Beat{}, &BeatList{}) } + +// -- association with monitoring Elasticsearch clusters + +// BeatMonitoringAssociation helps to manage the Beats / monitoring Elasticsearch clusters association. +type BeatMonitoringAssociation struct { + // The associated Beat + *Beat + // ref is the object selector of the monitoring Elasticsearch referenced in the Association + ref commonv1.ObjectSelector +} + +var _ commonv1.Association = &BeatMonitoringAssociation{} + +func (beatmon *BeatMonitoringAssociation) ElasticServiceAccount() (commonv1.ServiceAccountName, error) { + return "", nil +} + +func (beatmon *BeatMonitoringAssociation) Associated() commonv1.Associated { + if beatmon == nil { + return nil + } + if beatmon.Beat == nil { + beatmon.Beat = &Beat{} + } + return beatmon.Beat +} + +func (beatmon *BeatMonitoringAssociation) AssociationConfAnnotationName() string { + return commonv1.ElasticsearchConfigAnnotationName(beatmon.ref) +} + +func (beatmon *BeatMonitoringAssociation) AssociationType() commonv1.AssociationType { + return commonv1.BeatMonitoringAssociationType +} + +func (beatmon *BeatMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { + return beatmon.ref +} + +func (beatmon *BeatMonitoringAssociation) AssociationConf() (*commonv1.AssociationConf, error) { + return commonv1.GetAndSetAssociationConfByRef(beatmon, beatmon.ref, beatmon.monitoringAssocConfs) +} + +func (beatmon *BeatMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { + if beatmon.monitoringAssocConfs == nil { + beatmon.monitoringAssocConfs = make(map[commonv1.ObjectSelector]commonv1.AssociationConf) + } + if assocConf != nil { + beatmon.monitoringAssocConfs[beatmon.ref] = *assocConf + } +} + +func (beatmon *BeatMonitoringAssociation) AssociationID() string { + return beatmon.ref.ToID() +} + +// -- HasMonitoring methods + +func (b *Beat) GetMonitoringMetricsRefs() []commonv1.ObjectSelector { + return b.Spec.Monitoring.ElasticsearchRefs +} + +func (b *Beat) GetMonitoringLogsRefs() []commonv1.ObjectSelector { + return b.Spec.Monitoring.ElasticsearchRefs +} + +func (b *Beat) MonitoringAssociation(esRef commonv1.ObjectSelector) commonv1.Association { + return &BeatMonitoringAssociation{ + Beat: b, + ref: esRef.WithDefaultNamespace(b.Namespace), + } +} diff --git a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go index 8a5aee0b3c..45c4e8f12a 100644 --- a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go @@ -20,7 +20,7 @@ func (in *Beat) DeepCopyInto(out *Beat) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) if in.esAssocConf != nil { in, out := &in.esAssocConf, &out.esAssocConf *out = new(v1.AssociationConf) @@ -31,6 +31,13 @@ func (in *Beat) DeepCopyInto(out *Beat) { *out = new(v1.AssociationConf) **out = **in } + if in.monitoringAssocConfs != nil { + in, out := &in.monitoringAssocConfs, &out.monitoringAssocConfs + *out = make(map[v1.ObjectSelector]v1.AssociationConf, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Beat. @@ -123,6 +130,27 @@ func (in *BeatList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BeatMonitoringAssociation) DeepCopyInto(out *BeatMonitoringAssociation) { + *out = *in + if in.Beat != nil { + in, out := &in.Beat, &out.Beat + *out = new(Beat) + (*in).DeepCopyInto(*out) + } + out.ref = in.ref +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BeatMonitoringAssociation. +func (in *BeatMonitoringAssociation) DeepCopy() *BeatMonitoringAssociation { + if in == nil { + return nil + } + out := new(BeatMonitoringAssociation) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BeatSpec) DeepCopyInto(out *BeatSpec) { *out = *in @@ -154,6 +182,7 @@ func (in *BeatSpec) DeepCopyInto(out *BeatSpec) { *out = new(DeploymentSpec) (*in).DeepCopyInto(*out) } + in.Monitoring.DeepCopyInto(&out.Monitoring) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BeatSpec. @@ -169,6 +198,13 @@ func (in *BeatSpec) DeepCopy() *BeatSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BeatStatus) DeepCopyInto(out *BeatStatus) { *out = *in + if in.MonitoringAssociationsStatus != nil { + in, out := &in.MonitoringAssociationsStatus, &out.MonitoringAssociationsStatus + *out = make(v1.AssociationStatusMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BeatStatus. @@ -219,3 +255,38 @@ func (in *DeploymentSpec) DeepCopy() *DeploymentSpec { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricsMonitoring) DeepCopyInto(out *MetricsMonitoring) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoring. +func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { + if in == nil { + return nil + } + out := new(MetricsMonitoring) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Monitoring) DeepCopyInto(out *Monitoring) { + *out = *in + if in.ElasticsearchRefs != nil { + in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs + *out = make([]v1.ObjectSelector, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. +func (in *Monitoring) DeepCopy() *Monitoring { + if in == nil { + return nil + } + out := new(Monitoring) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index 9ac356ff50..877da0fa2a 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -106,6 +106,10 @@ const ( FleetServerConfigAnnotationNameBase = "association.k8s.elastic.co/fs-conf" FleetServerAssociationType = "fleetserver" + BeatConfigAnnotationNameBase = "association.k8s.elastic.co/beat-conf" + BeatAssociationType = "beat" + BeatMonitoringAssociationType = "beat-monitoring" + AssociationUnknown AssociationStatus = "" AssociationPending AssociationStatus = "Pending" AssociationEstablished AssociationStatus = "Established" diff --git a/pkg/apis/elasticsearch/v1/status.go b/pkg/apis/elasticsearch/v1/status.go index ff6805d287..effe95d35a 100644 --- a/pkg/apis/elasticsearch/v1/status.go +++ b/pkg/apis/elasticsearch/v1/status.go @@ -98,7 +98,7 @@ func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) comm func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, status commonv1.AssociationStatusMap) error { if typ != commonv1.EsMonitoringAssociationType { - return fmt.Errorf("association type %s not known", typ) + return fmt.Errorf("Elasticsearch: association type %s not known", typ) } es.Status.MonitoringAssociationsStatus = status diff --git a/pkg/controller/association/controller/beat_monitoring.go b/pkg/controller/association/controller/beat_monitoring.go new file mode 100644 index 0000000000..830d3e4fbd --- /dev/null +++ b/pkg/controller/association/controller/beat_monitoring.go @@ -0,0 +1,56 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + +package controller + +import ( + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + + beatv1b1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + "github.com/elastic/cloud-on-k8s/pkg/controller/association" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/operator" + eslabel "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" + "github.com/elastic/cloud-on-k8s/pkg/utils/rbac" +) + +// AddBeatMonitoring reconciles an association between Beat and Elasticsearch clusters for Stack Monitoring. +// Beat is configured to use internal collectors to send its monitoring data to the Elasticsearch referenced in the association. +func AddBeatMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { + return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ + AssociatedObjTemplate: func() commonv1.Associated { return &beatv1b1.Beat{} }, + ReferencedObjTemplate: func() client.Object { return &esv1.Elasticsearch{} }, + ReferencedResourceVersion: referencedElasticsearchStatusVersion, + ExternalServiceURL: getElasticsearchExternalURL, + AssociationType: commonv1.BeatMonitoringAssociationType, + ReferencedResourceNamer: esv1.ESNamer, + AssociationName: "beat-monitoring", + AssociatedShortName: "beat-mon", + Labels: func(associated types.NamespacedName) map[string]string { + return map[string]string{ + BeatAssociationLabelName: associated.Name, + BeatAssociationLabelNamespace: associated.Namespace, + BeatAssociationLabelType: commonv1.BeatMonitoringAssociationType, + } + }, + AssociationConfAnnotationNameBase: commonv1.ElasticsearchConfigAnnotationNameBase, + AssociationResourceNameLabelName: eslabel.ClusterNameLabelName, + AssociationResourceNamespaceLabelName: eslabel.ClusterNamespaceLabelName, + + ElasticsearchUserCreation: &association.ElasticsearchUserCreation{ + ElasticsearchRef: func(c k8s.Client, association commonv1.Association) (bool, commonv1.ObjectSelector, error) { + return true, association.AssociationRef(), nil + }, + UserSecretSuffix: "beat-es-mon-user", + ESUserRole: func(associated commonv1.Associated) (string, error) { + return user.StackMonitoringUserRole, nil + }, + }, + }) +} diff --git a/pkg/controller/association/reconciler.go b/pkg/controller/association/reconciler.go index 0a9395b0f4..bbc714bb98 100644 --- a/pkg/controller/association/reconciler.go +++ b/pkg/controller/association/reconciler.go @@ -463,13 +463,16 @@ func (r *Reconciler) updateStatus(ctx context.Context, associated commonv1.Assoc // To correctly compare statuses without making the reconciler aware of singleton vs multiple associations status // differences we: set new status, get it from associated and only then compare with the oldStatus. Setting the // same status is harmless, setting a different status is fine as we have a copy of oldStatus above. + r.logger.Info("calling setAssociationStatusMap") if err := associated.SetAssociationStatusMap(r.AssociationType, newStatus); err != nil { return err } + r.logger.Info("generating new status") newStatus = associated.AssociationStatusMap(r.AssociationType) // shortcut if the two maps are nil or empty if len(oldStatus) == 0 && len(newStatus) == 0 { + r.logger.Info("old and new status are empty") return nil } if !reflect.DeepEqual(oldStatus, newStatus) { @@ -487,6 +490,7 @@ func (r *Reconciler) updateStatus(ctx context.Context, associated commonv1.Assoc events.EventAssociationStatusChange, "Association status changed from [%s] to [%s]", oldStatus, newStatus) } + r.logger.Info("old and new status were equal", "old", oldStatus.String(), "new", newStatus.String()) return nil } diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index a06fa8536c..6dbc83ecc5 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -20,9 +20,9 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/common" "github.com/elastic/cloud-on-k8s/pkg/controller/common/reconciler" "github.com/elastic/cloud-on-k8s/pkg/controller/common/settings" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/pkg/controller/common/stackmon/validations" esservices "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/services" - esuser "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) @@ -180,6 +180,20 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) VerificationMode: "certificate", } } else { + associations := monitoring.GetMetricsAssociation(¶ms.Beat) + if len(associations) != 1 { + // should never happen because of the pre-creation validation + return nil, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") + } + assoc := associations[0] + + credentials, err := association.ElasticsearchAuthSettings(params.Client, assoc) + if err != nil { + return nil, err + } + + username, password = credentials.Username, credentials.Password + associatedEsNsn := esRef.NamespacedName() if associatedEsNsn.Namespace == "" { associatedEsNsn.Namespace = params.Beat.Namespace @@ -190,12 +204,6 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) return nil, errors.Wrap(err, "while retrieving Beat stack monitoring Elasticsearch instance") } - var err error - username = esuser.MonitoringUserName - password, err = esuser.GetMonitoringUserPassword(params.Client, associatedEsNsn) - if err != nil { - return nil, err - } url = esservices.InternalServiceURL(es) sslConfig = SSLConfig{ // TODO: Does this work in all ubi/non-ubi containers? From c31c29d02b15c0987a8b4e7047c586011afa82b1 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 30 Jun 2022 08:04:51 -0500 Subject: [PATCH 03/64] Only access info after chedcking error --- pkg/apis/beat/v1beta1/beat_types.go | 3 --- pkg/apis/beat/v1beta1/zz_generated.deepcopy.go | 15 --------------- pkg/controller/beat/common/config.go | 3 ++- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index 7a1436b549..40271614f7 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -115,9 +115,6 @@ func (m Monitoring) Enabled() bool { return len(m.ElasticsearchRefs) > 0 } -type MetricsMonitoring struct { -} - // BeatStatus defines the observed state of a Beat. type BeatStatus struct { // Version of the stack resource currently running. During version upgrades, multiple versions may run diff --git a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go index 45c4e8f12a..a5883fe43d 100644 --- a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go @@ -256,21 +256,6 @@ func (in *DeploymentSpec) DeepCopy() *DeploymentSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MetricsMonitoring) DeepCopyInto(out *MetricsMonitoring) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoring. -func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { - if in == nil { - return nil - } - out := new(MetricsMonitoring) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Monitoring) DeepCopyInto(out *Monitoring) { *out = *in diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 6dbc83ecc5..cebceb9301 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -137,6 +137,7 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) if len(params.Beat.Spec.Monitoring.ElasticsearchRefs) == 0 { return nil, errors.New("ElasticsearchRef must exist when stack monitoring is enabled") } + // only the first ElasticsearchRef is currently supported. esRef := params.Beat.Spec.Monitoring.ElasticsearchRefs[0] if !esRef.IsDefined() { @@ -147,10 +148,10 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) var sslConfig SSLConfig if esRef.IsExternal() { info, err := association.GetUnmanagedAssociationConnectionInfoFromSecret(params.Client, esRef) - url = info.URL if err != nil { return nil, err } + url = info.URL username, password = info.Username, info.Password if info.CaCert != "" { // save the monitoring connection information so it doesn't have to be retrieved From de1cddcc4dbbe99c0c9f774901a2607301a4d504 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 30 Jun 2022 08:28:23 -0500 Subject: [PATCH 04/64] Add debugging --- pkg/controller/beat/common/config.go | 18 ++- pkg/controller/beat/common/config_test.go | 144 ++++++++++++------ pkg/controller/beat/common/driver.go | 8 + pkg/controller/beat/common/monitoring.go | 6 +- .../common/settings/canonical_config_test.go | 17 +++ test/e2e/beat/config_test.go | 6 +- test/e2e/test/beat/builder.go | 22 +++ test/e2e/test/beat/checks.go | 37 +++++ test/e2e/test/beat/steps.go | 40 ++++- 9 files changed, 238 insertions(+), 60 deletions(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index cebceb9301..240134bba1 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -9,10 +9,10 @@ import ( "path" "strings" + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/pkg/errors" + logf "sigs.k8s.io/controller-runtime/pkg/log" beatv1beta1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" @@ -105,20 +105,24 @@ func buildBeatConfig( // If monitoring is enabled, render the relevant section if params.Beat.Spec.Monitoring.Enabled() { + logf.Log.WithName("beat_config").Info("about to getMonitoringConfig") monitoringConfig, err := getMonitoringConfig(params) if err != nil { return nil, err } + logf.Log.WithName("beat_config").Info("end about to getMonitoringConfig") if err = cfg.MergeWith(monitoringConfig); err != nil { return nil, err } } // get user config from `config` or `configRef` + logf.Log.WithName("beat_config").Info("about to getUserConfig") userConfig, err := getUserConfig(params) if err != nil { return nil, err } + logf.Log.WithName("beat_config").Info("end about to getUserConfig") if userConfig == nil { return cfg.Render() @@ -147,16 +151,18 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) var username, password, url string var sslConfig SSLConfig if esRef.IsExternal() { - info, err := association.GetUnmanagedAssociationConnectionInfoFromSecret(params.Client, esRef) + info, err := association.GetUnmanagedAssociationConnectionInfoFromSecret(params.Client, esRef.WithDefaultNamespace(params.Beat.Namespace)) if err != nil { return nil, err } + url = info.URL username, password = info.Username, info.Password if info.CaCert != "" { // save the monitoring connection information so it doesn't have to be retrieved // again later when buliding the secret which contains the CA. params.monitoringAssociationConnectionInfo = info + logf.Log.WithName("beat_config").Info("about to reconcile monitoring CA secret") if _, err := reconciler.ReconcileSecret( params.Context, params.Client, @@ -173,6 +179,7 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) ); err != nil { return nil, errors.Wrap(err, "while creating external monitoring ca secret") } + logf.Log.WithName("beat_config").Info("end about to reconcile monitoring CA secret") } sslConfig = SSLConfig{ // configure the CA cert needed for external monitoring cluster. @@ -207,7 +214,6 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) url = esservices.InternalServiceURL(es) sslConfig = SSLConfig{ - // TODO: Does this work in all ubi/non-ubi containers? CertificateAuthorities: []string{"/etc/pki/root/tls.crt"}, VerificationMode: "certificate", } @@ -243,10 +249,12 @@ func reconcileConfig( managedConfig *settings.CanonicalConfig, configHash hash.Hash, ) error { + logf.Log.WithName("beat_config").Info("building beat configuration") cfgBytes, err := buildBeatConfig(params, managedConfig) if err != nil { return err } + logf.Log.WithName("beat_config").Info("end building beat configuration") expected := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -259,9 +267,11 @@ func reconcileConfig( }, } + logf.Log.WithName("beat_config").Info("reconciling beat creentials secret") if _, err = reconciler.ReconcileSecret(params.Context, params.Client, expected, ¶ms.Beat); err != nil { return err } + logf.Log.WithName("beat_config").Info("end reconciling beat creentials secret") _, _ = configHash.Write(cfgBytes) diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 206ada1931..62fadca6cf 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/go-logr/logr" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -51,12 +52,18 @@ func Test_buildBeatConfig(t *testing.T) { clientWithMonitoringEnabled := k8s.NewFakeClient( &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "testes-es-internal-users", + Name: "secret", + Namespace: "ns", + }, + Data: map[string][]byte{"elastic": []byte("123")}, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "external-user-secret", Namespace: "ns", }, Data: map[string][]byte{ - "elastic-internal": []byte("asdf"), - "elastic-internal-monitoring": []byte("asdfasdf"), + "elastic-external": []byte("asdf"), }, }, &corev1.Secret{ @@ -82,7 +89,7 @@ func Test_buildBeatConfig(t *testing.T) { managedCfg := settings.MustParseConfig([]byte("setup.kibana: true")) userCfg := &commonv1.Config{Data: map[string]interface{}{"user": "true"}} userCanonicalCfg := settings.MustCanonicalConfig(userCfg.Data) - outputCAYaml := settings.MustParseConfig([]byte(`output.elasticsearch.ssl.certificate_authorities: + outputCAYaml := settings.MustParseConfig([]byte(`output.elasticsearch.ssl.certificate_authorities: - /mnt/elastic-internal/elasticsearch-certs/ca.crt`)) outputYaml := settings.MustParseConfig([]byte(`output: elasticsearch: @@ -96,12 +103,12 @@ func Test_buildBeatConfig(t *testing.T) { elasticsearch: hosts: - "https://testes-es-internal-http.ns.svc:9200" - username: "elastic-internal-monitoring" - password: asdfasdf + username: elastic + password: "123" ssl: certificate_authorities: - - "/etc/pki/root/tls.crt" - verification_mode: "certificate + - "/etc/pki/root/tls.crt" + verification_mode: "certificate" `)) externalMonitoringYaml := settings.MustParseConfig([]byte(`monitoring: enabled: true @@ -112,8 +119,8 @@ func Test_buildBeatConfig(t *testing.T) { password: asdfasdf ssl: certificate_authorities: - - "will_fail" - verification_mode: "certificate + - /tmp/external/ca.crt + verification_mode: "certificate" `)) withAssoc := beatv1beta1.Beat{ @@ -145,117 +152,147 @@ func Test_buildBeatConfig(t *testing.T) { for _, tt := range []struct { name string client k8s.Client - beat beatv1beta1.Beat + beat func() beatv1beta1.Beat managedConfig *settings.CanonicalConfig want *settings.CanonicalConfig wantErr bool }{ { name: "no association, no configs", - beat: beatv1beta1.Beat{}, + beat: func() beatv1beta1.Beat { return beatv1beta1.Beat{} }, }, { name: "no association, user config", - beat: beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - }}, + beat: func() beatv1beta1.Beat { + return beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + }} + }, want: userCanonicalCfg, }, { name: "no association, user config, with monitoring enabled", client: clientWithMonitoringEnabled, - beat: beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - Monitoring: beatv1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "testes", - Namespace: "ns", - }, + beat: func() beatv1beta1.Beat { + b := beatv1beta1.Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat", + Namespace: "ns", }, - }, - }}, + Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + Monitoring: beatv1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "testes", + Namespace: "ns", + }, + }, + }, + }} + b.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ + AuthSecretName: "secret", + AuthSecretKey: "elastic", + URL: "https://testes-es-internal-http.ns.svc:9200", + }) + return b + }, want: merge(userCanonicalCfg, monitoringYaml), }, { name: "no association, user config, with monitoring enabled, external es cluster", client: clientWithMonitoringEnabled, - beat: beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - Monitoring: beatv1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - SecretName: "external-es-monitoring", - Namespace: "ns", - }, + beat: func() beatv1beta1.Beat { + b := beatv1beta1.Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat", + Namespace: "ns", }, - }, - }}, + Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + Monitoring: beatv1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + SecretName: "external-es-monitoring", + Namespace: "ns", + }, + }, + }, + }} + b.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ + URL: "https://testes-es-internal-http.ns.svc:9200", + }) + return b + }, want: merge(userCanonicalCfg, externalMonitoringYaml), }, { name: "no association, managed config", - beat: beatv1beta1.Beat{}, + beat: func() beatv1beta1.Beat { return beatv1beta1.Beat{} }, managedConfig: managedCfg, want: managedCfg, }, { name: "no association, managed and user configs", - beat: beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - }}, + beat: func() beatv1beta1.Beat { + return beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + }, + } + }, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg), }, { name: "association without ca, no configs", client: clientWithSecret, - beat: withAssoc, + beat: func() beatv1beta1.Beat { return withAssoc }, want: outputYaml, }, { name: "association without ca, user config", client: clientWithSecret, - beat: withAssocWithConfig, + beat: func() beatv1beta1.Beat { return withAssocWithConfig }, want: merge(userCanonicalCfg, outputYaml), }, { name: "association without ca, managed config", client: clientWithSecret, - beat: withAssoc, + beat: func() beatv1beta1.Beat { return withAssoc }, managedConfig: managedCfg, want: merge(managedCfg, outputYaml), }, { name: "association without ca, user and managed configs", client: clientWithSecret, - beat: withAssocWithConfig, + beat: func() beatv1beta1.Beat { return withAssocWithConfig }, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg, outputYaml), }, { name: "association with ca, no configs", client: clientWithSecret, - beat: withAssocWithCA, + beat: func() beatv1beta1.Beat { return withAssocWithCA }, want: merge(outputYaml, outputCAYaml), }, { name: "association with ca, user config", client: clientWithSecret, - beat: withAssocWithCAWithonfig, + beat: func() beatv1beta1.Beat { return withAssocWithCAWithonfig }, want: merge(userCanonicalCfg, outputYaml, outputCAYaml), }, { name: "association with ca, managed config", client: clientWithSecret, - beat: withAssocWithCA, + beat: func() beatv1beta1.Beat { return withAssocWithCA }, managedConfig: managedCfg, want: merge(managedCfg, outputYaml, outputCAYaml), }, { name: "association with ca, user and managed configs", client: clientWithSecret, - beat: withAssocWithCAWithonfig, + beat: func() beatv1beta1.Beat { return withAssocWithCAWithonfig }, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg, outputYaml, outputCAYaml), }, @@ -267,12 +304,15 @@ func Test_buildBeatConfig(t *testing.T) { Logger: logr.Discard(), Watches: watches.NewDynamicWatches(), EventRecorder: nil, - Beat: tt.beat, + Beat: tt.beat(), }, tt.managedConfig) diff := tt.want.Diff(settings.MustParseConfig(gotYaml), nil) - require.Empty(t, diff) + if len(diff) != 0 { + wantBytes, _ := tt.want.Render() + t.Errorf("BuildKibanaConfig() got unexpected differences: %s", cmp.Diff(string(wantBytes), string(gotYaml))) + } require.Equal(t, gotErr != nil, tt.wantErr) }) } @@ -377,7 +417,11 @@ setup.kibana: return } diff := tt.want.Diff(got, nil) - require.Empty(t, diff) + if len(diff) != 0 { + wantBytes, _ := tt.want.Render() + gotBytes, _ := got.Render() + t.Errorf("BuildKibanaConfig() got unexpected differences: %s", cmp.Diff(string(wantBytes), string(gotBytes))) + } }) } } diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 2ea57ec676..226947ea9f 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -91,21 +91,29 @@ func Reconcile( } configHash := fnv.New32a() + params.Logger.Info("about to reconcileConfig") if err := reconcileConfig(params, managedConfig, configHash); err != nil { return results.WithError(err), params.Status } + params.Logger.Info("end about to reconcileConfig") + params.Logger.Info("about to WriteAssocsToConfigHash") // we need to deref the secret here (if any) to include it in the configHash otherwise Beat will not be rolled on content changes if err := commonassociation.WriteAssocsToConfigHash(params.Client, params.Beat.GetAssociations(), configHash); err != nil { return results.WithError(err), params.Status } + params.Logger.Info("end about to WriteAssocsToConfigHash") + params.Logger.Info("about to buildPodTemplate") podTemplate, err := buildPodTemplate(params, defaultImage, configHash) if err != nil { return results.WithError(err), params.Status } + params.Logger.Info("end about to buildPodTemplate") var reconcileResults *reconciler.Results + params.Logger.Info("about to reconcilePodVehicle") reconcileResults, params.Status = reconcilePodVehicle(podTemplate, params) + params.Logger.Info("end about to reconcilePodVehicle") results.WithResults(reconcileResults) return results, params.Status } diff --git a/pkg/controller/beat/common/monitoring.go b/pkg/controller/beat/common/monitoring.go index a4b639e893..690acd1e05 100644 --- a/pkg/controller/beat/common/monitoring.go +++ b/pkg/controller/beat/common/monitoring.go @@ -22,8 +22,10 @@ type ElasticsearchConfig struct { /// SSLConfig contains the SSL configuration for Beat stack monitoring. type SSLConfig struct { - CertificateAuthorities []string `json:"certificate_authorities,omitempty"` - VerificationMode string `json:"verification_mode,omitempty"` + // CertificateAuthorities contains a slice of filenames that contain PEM formatted certificate authorities. + CertificateAuthorities []string `config:"certificate_authorities" yaml:"certificate_authorities"` + // VerificationMode contains the verification mode for server certificates. Valid options: [full, strict, certificate, none] + VerificationMode string `config:"verification_mode" yaml:"verification_mode"` } func getMonitoringCASecretName(beatName string) string { diff --git a/pkg/controller/common/settings/canonical_config_test.go b/pkg/controller/common/settings/canonical_config_test.go index ba590dcba2..06ff33dd71 100644 --- a/pkg/controller/common/settings/canonical_config_test.go +++ b/pkg/controller/common/settings/canonical_config_test.go @@ -417,6 +417,10 @@ func TestNewCanonicalConfigFrom(t *testing.T) { type args struct { data untypedDict } + type sslConfig struct { + CertificateAuthorities []string `config:"certificate_authorities" json:"certificate_authorities" yaml:"certificate_authorities"` + VerificationMode string `config:"verification_mode" json:"verification_mode" yaml:"verification_mode"` + } tests := []struct { name string args args @@ -437,6 +441,19 @@ func TestNewCanonicalConfigFrom(t *testing.T) { }), wantErr: false, }, + { + name: "config tags should be supported to allow underscores", + args: args{ + data: map[string]interface{}{ + "monitoring": float64(1), // after json round trip or deep copy typically a float + }, + }, + want: MustCanonicalConfig(map[string]interface{}{ + "a": 1, + "b": 1.2, + }), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/test/e2e/beat/config_test.go b/test/e2e/beat/config_test.go index 1ee45c5c7f..d676662c9f 100644 --- a/test/e2e/beat/config_test.go +++ b/test/e2e/beat/config_test.go @@ -10,10 +10,11 @@ import ( "fmt" "testing" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" + v1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/beat/auditbeat" "github.com/elastic/cloud-on-k8s/pkg/controller/beat/filebeat" @@ -49,7 +50,7 @@ func TestFilebeatDefaultConfig(t *testing.T) { test.Sequence(nil, test.EmptySteps, esBuilder, fbBuilder, testPodBuilder).RunSequential(t) } -func TestMetricbeatDefaultConfig(t *testing.T) { +func TestMetricbeatDefaultConfigWithStackMonitoring(t *testing.T) { name := "test-mb-default-cfg" esBuilder := elasticsearch.NewBuilder(name). @@ -61,6 +62,7 @@ func TestMetricbeatDefaultConfig(t *testing.T) { WithType(metricbeat.Type). WithRoles(beat.MetricbeatClusterRoleName, beat.PSPClusterRoleName, beat.AutodiscoverClusterRoleName). WithElasticsearchRef(esBuilder.Ref()). + WithMonitoring(esBuilder.Ref()). WithESValidations( beat.HasEventFromBeat(metricbeat.Type), beat.HasEvent("event.dataset:system.cpu"), diff --git a/test/e2e/test/beat/builder.go b/test/e2e/test/beat/builder.go index cafe701cbf..e9aaeada56 100644 --- a/test/e2e/test/beat/builder.go +++ b/test/e2e/test/beat/builder.go @@ -17,6 +17,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/rand" k8sclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -335,3 +336,24 @@ func ApplyYamls(t *testing.T, b Builder, configYaml, podTemplateYaml string) Bui return b } + +func (b Builder) WithMonitoring(esRef commonv1.ObjectSelector) Builder { + b.Beat.Spec.Monitoring.ElasticsearchRefs = []commonv1.ObjectSelector{esRef} + return b +} + +func (b Builder) GetMetricsIndexPattern() string { + v := version.MustParse(test.Ctx().ElasticStackVersion) + if v.GTE(version.MinFor(8, 0, 0)) { + return fmt.Sprintf("metricbeat-%d.%d.%d*", v.Major, v.Minor, v.Patch) + } + return ".monitoring-beat-*" +} + +func (b Builder) GetMetricsCluster() *types.NamespacedName { + if len(b.Beat.Spec.Monitoring.ElasticsearchRefs) == 0 { + return nil + } + metricsCluster := b.Beat.Spec.Monitoring.ElasticsearchRefs[0].NamespacedName() + return &metricsCluster +} diff --git a/test/e2e/test/beat/checks.go b/test/e2e/test/beat/checks.go index 8e6d944223..7b00d1c204 100644 --- a/test/e2e/test/beat/checks.go +++ b/test/e2e/test/beat/checks.go @@ -10,9 +10,11 @@ import ( "fmt" "io/ioutil" "net/http" + "strconv" beatcommon "github.com/elastic/cloud-on-k8s/pkg/controller/beat/common" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/client" + "github.com/elastic/cloud-on-k8s/test/e2e/test/checks" ) func HasEventFromBeat(name beatcommon.Type) ValidationFunc { @@ -87,3 +89,38 @@ func checkEvent(url string, check func(int) error) ValidationFunc { return check(len(results.Hits.Hits)) } } + +func containsDocuments(esClient client.Client, indexPattern string) error { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/_cat/indices/%s?format=json", indexPattern), nil) //nolint:noctx + if err != nil { + return err + } + resp, err := esClient.Request(context.Background(), req) + if err != nil { + return err + } + defer resp.Body.Close() + resultBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + var indices []checks.Index + err = json.Unmarshal(resultBytes, &indices) + if err != nil { + return err + } + + // 1 index must exist + if len(indices) != 1 { + return fmt.Errorf("expected [%d] index [%s], found [%d]", 1, indexPattern, len(indices)) + } + docsCount, err := strconv.Atoi(indices[0].DocsCount) + if err != nil { + return err + } + // with at least 1 doc + if docsCount <= 0 { + return fmt.Errorf("index [%s] empty", indexPattern) + } + return nil +} diff --git a/test/e2e/test/beat/steps.go b/test/e2e/test/beat/steps.go index 7bf8762620..a9cefca2d2 100644 --- a/test/e2e/test/beat/steps.go +++ b/test/e2e/test/beat/steps.go @@ -8,6 +8,7 @@ import ( "context" "fmt" + "github.com/google/go-cmp/cmp" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -132,9 +133,15 @@ func (b Builder) CheckK8sTestSteps(k *test.K8sClient) test.StepList { beat.Status.ExpectedNodes = 0 beat.Status.AvailableNodes = 0 } - if beat.Status != expected { - return fmt.Errorf("expected status %+v but got %+v", expected, beat.Status) + if !cmp.Equal(beat.Status, expected) { + return fmt.Errorf("expected status health %+v, got diff: %s", expected, cmp.Diff(beat.Status, expected)) } + // if beat.Status.Health != expected.Health { + // return fmt.Errorf("expected status health %+v but got %+v", expected.Health, beat.Status.Health) + // } + // if beat.Status.Version != expected.Version { + // return fmt.Errorf("expected status version %+v but got %+v", expected.Version, beat.Status.Version) + // } return nil }), }, @@ -182,6 +189,7 @@ func (b Builder) CheckStackTestSteps(k *test.K8sClient) test.StepList { return nil }), }, + b.CheckMonitoringMetricsIndex(k), } } @@ -250,3 +258,31 @@ func (b Builder) MutationTestSteps(k *test.K8sClient) test.StepList { WithSteps(b.CheckStackTestSteps(k)). WithStep(generation.CompareObjectGenerationsStep(&b.Beat, k, isMutated, beatGenerationBeforeMutation, beatObservedGenerationBeforeMutation)) } + +func (b Builder) CheckMonitoringMetricsIndex(k *test.K8sClient) test.Step { + indexPattern := b.GetMetricsIndexPattern() + return test.Step{ + Name: fmt.Sprintf("Check that documents are indexed in index %s", indexPattern), + Test: test.Eventually(func() error { + if b.GetMetricsCluster() == nil { + return nil + } + esMetricsRef := *b.GetMetricsCluster() + // Get Elasticsearch + esMetrics := esv1.Elasticsearch{} + if err := k.Client.Get(context.Background(), esMetricsRef, &esMetrics); err != nil { + return err + } + // Create a new Elasticsearch client + client, err := elasticsearch.NewElasticsearchClient(esMetrics, k) + if err != nil { + return err + } + // Check that there is at least one document + err = containsDocuments(client, indexPattern) + if err != nil { + return err + } + return nil + })} +} From e14849d929a29b41aedf16e2e147e558de7b1531 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 11 Jul 2022 15:34:27 -0400 Subject: [PATCH 05/64] Removing debugging logging statements --- pkg/controller/association/reconciler.go | 4 ---- pkg/controller/beat/common/config.go | 11 ----------- pkg/controller/beat/common/driver.go | 8 -------- 3 files changed, 23 deletions(-) diff --git a/pkg/controller/association/reconciler.go b/pkg/controller/association/reconciler.go index bbc714bb98..0a9395b0f4 100644 --- a/pkg/controller/association/reconciler.go +++ b/pkg/controller/association/reconciler.go @@ -463,16 +463,13 @@ func (r *Reconciler) updateStatus(ctx context.Context, associated commonv1.Assoc // To correctly compare statuses without making the reconciler aware of singleton vs multiple associations status // differences we: set new status, get it from associated and only then compare with the oldStatus. Setting the // same status is harmless, setting a different status is fine as we have a copy of oldStatus above. - r.logger.Info("calling setAssociationStatusMap") if err := associated.SetAssociationStatusMap(r.AssociationType, newStatus); err != nil { return err } - r.logger.Info("generating new status") newStatus = associated.AssociationStatusMap(r.AssociationType) // shortcut if the two maps are nil or empty if len(oldStatus) == 0 && len(newStatus) == 0 { - r.logger.Info("old and new status are empty") return nil } if !reflect.DeepEqual(oldStatus, newStatus) { @@ -490,7 +487,6 @@ func (r *Reconciler) updateStatus(ctx context.Context, associated commonv1.Assoc events.EventAssociationStatusChange, "Association status changed from [%s] to [%s]", oldStatus, newStatus) } - r.logger.Info("old and new status were equal", "old", oldStatus.String(), "new", newStatus.String()) return nil } diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 240134bba1..d358259a88 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -12,7 +12,6 @@ import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - logf "sigs.k8s.io/controller-runtime/pkg/log" beatv1beta1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" @@ -105,24 +104,20 @@ func buildBeatConfig( // If monitoring is enabled, render the relevant section if params.Beat.Spec.Monitoring.Enabled() { - logf.Log.WithName("beat_config").Info("about to getMonitoringConfig") monitoringConfig, err := getMonitoringConfig(params) if err != nil { return nil, err } - logf.Log.WithName("beat_config").Info("end about to getMonitoringConfig") if err = cfg.MergeWith(monitoringConfig); err != nil { return nil, err } } // get user config from `config` or `configRef` - logf.Log.WithName("beat_config").Info("about to getUserConfig") userConfig, err := getUserConfig(params) if err != nil { return nil, err } - logf.Log.WithName("beat_config").Info("end about to getUserConfig") if userConfig == nil { return cfg.Render() @@ -162,7 +157,6 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) // save the monitoring connection information so it doesn't have to be retrieved // again later when buliding the secret which contains the CA. params.monitoringAssociationConnectionInfo = info - logf.Log.WithName("beat_config").Info("about to reconcile monitoring CA secret") if _, err := reconciler.ReconcileSecret( params.Context, params.Client, @@ -179,7 +173,6 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) ); err != nil { return nil, errors.Wrap(err, "while creating external monitoring ca secret") } - logf.Log.WithName("beat_config").Info("end about to reconcile monitoring CA secret") } sslConfig = SSLConfig{ // configure the CA cert needed for external monitoring cluster. @@ -249,12 +242,10 @@ func reconcileConfig( managedConfig *settings.CanonicalConfig, configHash hash.Hash, ) error { - logf.Log.WithName("beat_config").Info("building beat configuration") cfgBytes, err := buildBeatConfig(params, managedConfig) if err != nil { return err } - logf.Log.WithName("beat_config").Info("end building beat configuration") expected := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -267,11 +258,9 @@ func reconcileConfig( }, } - logf.Log.WithName("beat_config").Info("reconciling beat creentials secret") if _, err = reconciler.ReconcileSecret(params.Context, params.Client, expected, ¶ms.Beat); err != nil { return err } - logf.Log.WithName("beat_config").Info("end reconciling beat creentials secret") _, _ = configHash.Write(cfgBytes) diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 226947ea9f..2ea57ec676 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -91,29 +91,21 @@ func Reconcile( } configHash := fnv.New32a() - params.Logger.Info("about to reconcileConfig") if err := reconcileConfig(params, managedConfig, configHash); err != nil { return results.WithError(err), params.Status } - params.Logger.Info("end about to reconcileConfig") - params.Logger.Info("about to WriteAssocsToConfigHash") // we need to deref the secret here (if any) to include it in the configHash otherwise Beat will not be rolled on content changes if err := commonassociation.WriteAssocsToConfigHash(params.Client, params.Beat.GetAssociations(), configHash); err != nil { return results.WithError(err), params.Status } - params.Logger.Info("end about to WriteAssocsToConfigHash") - params.Logger.Info("about to buildPodTemplate") podTemplate, err := buildPodTemplate(params, defaultImage, configHash) if err != nil { return results.WithError(err), params.Status } - params.Logger.Info("end about to buildPodTemplate") var reconcileResults *reconciler.Results - params.Logger.Info("about to reconcilePodVehicle") reconcileResults, params.Status = reconcilePodVehicle(podTemplate, params) - params.Logger.Info("end about to reconcilePodVehicle") results.WithResults(reconcileResults) return results, params.Status } From 23de080b14d61d1732980070e994956c50593164 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 11 Jul 2022 22:20:53 -0400 Subject: [PATCH 06/64] Handling external, and internal monitoring refs the same. Add additional unit testing. --- pkg/controller/beat/common/config.go | 91 +++++------------ pkg/controller/beat/common/config_test.go | 26 ++++- pkg/controller/beat/common/pod.go | 12 --- pkg/controller/beat/common/pod_test.go | 116 +++++++++++++++++++++- 4 files changed, 164 insertions(+), 81 deletions(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index d358259a88..bf7c19d3a1 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -7,6 +7,7 @@ package common import ( "hash" "path" + "path/filepath" "strings" "github.com/pkg/errors" @@ -14,19 +15,17 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" beatv1beta1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" - esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + v1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/association" "github.com/elastic/cloud-on-k8s/pkg/controller/common" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/certificates" "github.com/elastic/cloud-on-k8s/pkg/controller/common/reconciler" "github.com/elastic/cloud-on-k8s/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/pkg/controller/common/stackmon/validations" - esservices "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/services" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) -const externalCAPath = "/tmp/external" - // buildOutputConfig will create the output section in Beat config according to the association configuration. func buildOutputConfig(client k8s.Client, associated beatv1beta1.BeatESAssociation) (*settings.CanonicalConfig, error) { esAssocConf, err := associated.AssociationConf() @@ -104,7 +103,7 @@ func buildBeatConfig( // If monitoring is enabled, render the relevant section if params.Beat.Spec.Monitoring.Enabled() { - monitoringConfig, err := getMonitoringConfig(params) + monitoringConfig, err := buildMonitoringConfig(params) if err != nil { return nil, err } @@ -130,9 +129,8 @@ func buildBeatConfig( return cfg.Render() } -// getMonitoringConfig returns the stack monitoring configuration for a Beats instance. -// TODO: I believe the ssl pieces are remaining. -func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) { +// buildMonitoringConfig builds the stack monitoring configuration for a Beats instance. +func buildMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) { if len(params.Beat.Spec.Monitoring.ElasticsearchRefs) == 0 { return nil, errors.New("ElasticsearchRef must exist when stack monitoring is enabled") } @@ -145,69 +143,34 @@ func getMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) var username, password, url string var sslConfig SSLConfig - if esRef.IsExternal() { - info, err := association.GetUnmanagedAssociationConnectionInfoFromSecret(params.Client, esRef.WithDefaultNamespace(params.Beat.Namespace)) - if err != nil { - return nil, err - } + associations := monitoring.GetMetricsAssociation(¶ms.Beat) + if len(associations) != 1 { + // should never happen because of the pre-creation validation + return nil, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") + } + assoc := associations[0] - url = info.URL - username, password = info.Username, info.Password - if info.CaCert != "" { - // save the monitoring connection information so it doesn't have to be retrieved - // again later when buliding the secret which contains the CA. - params.monitoringAssociationConnectionInfo = info - if _, err := reconciler.ReconcileSecret( - params.Context, - params.Client, - corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: getMonitoringCASecretName(params.Beat.Name), - Namespace: params.Beat.Namespace, - }, - Data: map[string][]byte{ - "ca.crt": []byte(info.CaCert), - }, - }, - ¶ms.Beat, - ); err != nil { - return nil, errors.Wrap(err, "while creating external monitoring ca secret") - } - } - sslConfig = SSLConfig{ - // configure the CA cert needed for external monitoring cluster. - // The secret, and volume for the pod will be created during pod templating. - CertificateAuthorities: []string{path.Join(externalCAPath, CAFileName)}, - VerificationMode: "certificate", - } - } else { - associations := monitoring.GetMetricsAssociation(¶ms.Beat) - if len(associations) != 1 { - // should never happen because of the pre-creation validation - return nil, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") - } - assoc := associations[0] + credentials, err := association.ElasticsearchAuthSettings(params.Client, assoc) + if err != nil { + return nil, err + } - credentials, err := association.ElasticsearchAuthSettings(params.Client, assoc) - if err != nil { - return nil, err - } + username, password = credentials.Username, credentials.Password - username, password = credentials.Username, credentials.Password + var assocConf *v1.AssociationConf + assocConf, err = assoc.AssociationConf() + if err != nil { + return nil, err + } - associatedEsNsn := esRef.NamespacedName() - if associatedEsNsn.Namespace == "" { - associatedEsNsn.Namespace = params.Beat.Namespace - } + url = assocConf.GetURL() - var es esv1.Elasticsearch - if err := params.Client.Get(params.Context, associatedEsNsn, &es); err != nil { - return nil, errors.Wrap(err, "while retrieving Beat stack monitoring Elasticsearch instance") - } + caDirPath := certificatesDir(assoc) - url = esservices.InternalServiceURL(es) + if assocConf.GetCACertProvided() { + sslCAPath := filepath.Join(caDirPath, certificates.CAFileName) sslConfig = SSLConfig{ - CertificateAuthorities: []string{"/etc/pki/root/tls.crt"}, + CertificateAuthorities: []string{sslCAPath}, VerificationMode: "certificate", } } diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 62fadca6cf..389ffc0968 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -78,6 +78,15 @@ func Test_buildBeatConfig(t *testing.T) { "ca.crt": []byte("my_pem_encoded_cert"), }, }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat-es-testes-ns-monitoring-ca", + Namespace: "ns", + }, + Data: map[string][]byte{ + "ca.crt": []byte("my_pem_encoded_cert"), + }, + }, &esv1.Elasticsearch{ ObjectMeta: metav1.ObjectMeta{ Name: "testes", @@ -107,7 +116,7 @@ func Test_buildBeatConfig(t *testing.T) { password: "123" ssl: certificate_authorities: - - "/etc/pki/root/tls.crt" + - "/mnt/elastic-internal/beat-monitoring-certs/ca.crt" verification_mode: "certificate" `)) externalMonitoringYaml := settings.MustParseConfig([]byte(`monitoring: @@ -139,6 +148,13 @@ func Test_buildBeatConfig(t *testing.T) { withAssocWithCA := *withAssoc.DeepCopy() esAssocWithCA := beatv1beta1.BeatESAssociation{Beat: &withAssocWithCA} + esAssocWithCA.SetAssociationConf(&commonv1.AssociationConf{ + AuthSecretName: "secret", + AuthSecretKey: "elastic", + CACertProvided: true, + CASecretName: "secret2", + URL: "url", + }) assocConf, err := esAssocWithCA.AssociationConf() require.NoError(t, err) assocConf.CACertProvided = true @@ -193,6 +209,8 @@ func Test_buildBeatConfig(t *testing.T) { b.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ AuthSecretName: "secret", AuthSecretKey: "elastic", + CACertProvided: true, + CASecretName: "testbeat-es-testes-ns-monitoring-ca", URL: "https://testes-es-internal-http.ns.svc:9200", }) return b @@ -220,7 +238,11 @@ func Test_buildBeatConfig(t *testing.T) { }, }} b.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ - URL: "https://testes-es-internal-http.ns.svc:9200", + AuthSecretName: "secret", + AuthSecretKey: "elastic", + CASecretName: "testbeat-es-testes-ns-monitoring-ca", + CACertProvided: true, + URL: "https://testes-es-internal-http.ns.svc:9200", }) return b }, diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index 91a13268e4..ea98eb870a 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -115,18 +115,6 @@ func buildPodTemplate( vols = append(vols, caVolume) } - // if the monitoring connection information isn't empty - // then we need to create the secret volume for the CA. - if params.monitoringAssociationConnectionInfo != nil { - monitoringCASecretName := getMonitoringCASecretName(params.Beat.Name) - caVolume := volume.NewSecretVolumeWithMountPath( - monitoringCASecretName, - monitoringCASecretName, - externalCAPath, - ) - vols = append(vols, caVolume) - } - volumes := make([]corev1.Volume, 0, len(vols)) volumeMounts := make([]corev1.VolumeMount, 0, len(vols)) var initContainers []corev1.Container diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index afaa67ed3f..fd66ea8f5f 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -12,17 +12,79 @@ import ( "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/container" "github.com/elastic/cloud-on-k8s/pkg/controller/common/watches" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) func Test_buildPodTemplate(t *testing.T) { + clientWithMonitoringEnabled := k8s.NewFakeClient( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secret", + Namespace: "ns", + }, + Data: map[string][]byte{"elastic": []byte("123")}, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "external-user-secret", + Namespace: "ns", + }, + Data: map[string][]byte{ + "elastic-external": []byte("asdf"), + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "external-es-monitoring", + Namespace: "ns", + }, + Data: map[string][]byte{ + "url": []byte("https://external-es.external.com"), + "username": []byte("monitoring-user"), + "password": []byte("asdfasdf"), + "ca.crt": []byte("my_pem_encoded_cert"), + }, + }, + &esv1.Elasticsearch{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testes", + Namespace: "ns", + }, + }, + ) + userCfg := &commonv1.Config{Data: map[string]interface{}{"user": "true"}} + beatWithMonitoring := v1beta1.Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beat-name", + Namespace: "ns", + }, + Spec: v1beta1.BeatSpec{ + Version: "7.15.0", + Config: userCfg, + Monitoring: v1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "testes", + Namespace: "ns", + }, + }, + }, + }} + beatWithMonitoring.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ + AuthSecretName: "secret", + AuthSecretKey: "elastic", + CASecretName: "testbeat-es-testes-ns-monitoring-ca", + URL: "https://testes-es-internal-http.ns.svc:9200", + }) type args struct { params DriverParams initialHash hash.Hash32 @@ -39,6 +101,30 @@ func Test_buildPodTemplate(t *testing.T) { args args want want }{ + { + name: "deployment with monitoring enabled should have CA volume", + args: args{ + initialHash: newHash("foobar"), // SHA224 for foobar is de76c3e567fca9d246f5f8d3b2e704a38c3c5e258988ab525f941db8 + params: DriverParams{ + Watches: watches.NewDynamicWatches(), + Client: clientWithMonitoringEnabled, + Beat: beatWithMonitoring, + }, + defaultImage: "beats/filebeat", + }, + want: want{ + initContainers: 0, + labels: map[string]string{ + "beat.k8s.elastic.co/name": "beat-name", + "beat.k8s.elastic.co/version": "7.15.0", + "common.k8s.elastic.co/type": "beat", + }, + annotations: map[string]string{ + // SHA224 should be the same as the initial one. + "beat.k8s.elastic.co/config-hash": "3214735720", + }, + }, + }, { name: "daemonset user-provided init containers should inherit from the default main container image", args: args{ @@ -170,6 +256,9 @@ func Test_buildPodTemplate(t *testing.T) { t.Errorf("Annotations do not match: %s", cmp.Diff(tt.want.annotations, podTemplateSpec.Annotations)) return } + if tt.args.params.Beat.Spec.Monitoring.Enabled() { + assertMonitoring(t, podTemplateSpec.Spec.Volumes) + } }) } } @@ -180,7 +269,12 @@ var expectedConfigVolumeMode int32 = 292 func assertInitContainers(t *testing.T, pod corev1.PodTemplateSpec, wantInitContainers int) { t.Helper() // Validate that init container is in the PodTemplate - assert.Len(t, pod.Spec.InitContainers, wantInitContainers) + require.Len(t, pod.Spec.InitContainers, wantInitContainers) + if wantInitContainers == 0 { + return + } + // Validate that the containers contains a container before referencing the first + require.NotEmpty(t, pod.Spec.Containers, "pod.Spec.Containers should not be empty") // Image used by the init container and by the "main" container must be the same assert.Equal(t, pod.Spec.Containers[0].Image, pod.Spec.InitContainers[0].Image) } @@ -195,12 +289,28 @@ func assertConfiguration(t *testing.T, pod corev1.PodTemplateSpec) { break } } - assert.NotNil(t, configVolume) + require.NotNil(t, configVolume) // Validate the mode - assert.NotNil(t, configVolume.DefaultMode, "default volume mode for beat configuration should not be nil") + require.NotNil(t, configVolume.DefaultMode, "default volume mode for beat configuration should not be nil") assert.Equal(t, expectedConfigVolumeMode, *configVolume.DefaultMode) } +func assertMonitoring(t *testing.T, volumes []corev1.Volume) { + t.Helper() + var monitoringVolume *corev1.Volume + // Validate that the Pod's volumes contain a Secret as a monitoring CA volume. + for _, vol := range volumes { + if vol.Name == "beat-monitoring-certs" { + foundVol := vol + monitoringVolume = &foundVol + break + } + } + require.NotNil(t, monitoringVolume) + require.NotNil(t, monitoringVolume.Secret) + assert.Equal(t, monitoringVolume.Secret.SecretName, "testbeat-es-testes-ns-monitoring-ca") +} + // newHash creates a hash with some initial data. func newHash(initialData string) hash.Hash32 { dataHash := fnv.New32a() From ec13b90e7d9e17cfd28805a30a23e55931c4afa5 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Fri, 15 Jul 2022 11:23:07 -0500 Subject: [PATCH 07/64] Fix unit test. Fix e2e tests. --- pkg/controller/beat/common/config_test.go | 10 +++++----- test/e2e/test/beat/steps.go | 13 +++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 389ffc0968..7d3c3c8edc 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -128,7 +128,7 @@ func Test_buildBeatConfig(t *testing.T) { password: asdfasdf ssl: certificate_authorities: - - /tmp/external/ca.crt + - "/mnt/elastic-internal/beat-monitoring-certs/ca.crt" verification_mode: "certificate" `)) @@ -237,12 +237,12 @@ func Test_buildBeatConfig(t *testing.T) { }, }, }} - b.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ - AuthSecretName: "secret", - AuthSecretKey: "elastic", + b.MonitoringAssociation(commonv1.ObjectSelector{SecretName: "external-es-monitoring", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ + AuthSecretName: "external-es-monitoring", + AuthSecretKey: "password", CASecretName: "testbeat-es-testes-ns-monitoring-ca", CACertProvided: true, - URL: "https://testes-es-internal-http.ns.svc:9200", + URL: "https://external-es.external.com", }) return b }, diff --git a/test/e2e/test/beat/steps.go b/test/e2e/test/beat/steps.go index a9cefca2d2..407654fd50 100644 --- a/test/e2e/test/beat/steps.go +++ b/test/e2e/test/beat/steps.go @@ -118,6 +118,7 @@ func (b Builder) CheckK8sTestSteps(k *test.K8sClient) test.StepList { // don't check association statuses that may vary across tests beat.Status.ElasticsearchAssociationStatus = "" beat.Status.KibanaAssociationStatus = "" + beat.Status.MonitoringAssociationsStatus = nil beat.Status.ObservedGeneration = 0 expected := beatv1beta1.BeatStatus{ @@ -136,12 +137,12 @@ func (b Builder) CheckK8sTestSteps(k *test.K8sClient) test.StepList { if !cmp.Equal(beat.Status, expected) { return fmt.Errorf("expected status health %+v, got diff: %s", expected, cmp.Diff(beat.Status, expected)) } - // if beat.Status.Health != expected.Health { - // return fmt.Errorf("expected status health %+v but got %+v", expected.Health, beat.Status.Health) - // } - // if beat.Status.Version != expected.Version { - // return fmt.Errorf("expected status version %+v but got %+v", expected.Version, beat.Status.Version) - // } + if beat.Status.Health != expected.Health { + return fmt.Errorf("expected status health %+v but got %+v", expected.Health, beat.Status.Health) + } + if beat.Status.Version != expected.Version { + return fmt.Errorf("expected status version %+v but got %+v", expected.Version, beat.Status.Version) + } return nil }), }, From a21aa92d9f784d83bb2219b493d168244705ada6 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Fri, 15 Jul 2022 11:32:21 -0500 Subject: [PATCH 08/64] Fix some issues with errorf formatting remove some unecessary tests that were added remove unused func --- pkg/apis/elasticsearch/v1/status.go | 2 +- pkg/controller/beat/common/config_test.go | 2 +- pkg/controller/beat/common/monitoring.go | 6 ------ .../common/settings/canonical_config_test.go | 17 ----------------- test/e2e/beat/config_test.go | 3 +-- 5 files changed, 3 insertions(+), 27 deletions(-) diff --git a/pkg/apis/elasticsearch/v1/status.go b/pkg/apis/elasticsearch/v1/status.go index effe95d35a..2effe58c53 100644 --- a/pkg/apis/elasticsearch/v1/status.go +++ b/pkg/apis/elasticsearch/v1/status.go @@ -98,7 +98,7 @@ func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) comm func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, status commonv1.AssociationStatusMap) error { if typ != commonv1.EsMonitoringAssociationType { - return fmt.Errorf("Elasticsearch: association type %s not known", typ) + return fmt.Errorf("elasticsearch: association type %s not known", typ) } es.Status.MonitoringAssociationsStatus = status diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 7d3c3c8edc..af3a8040c8 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -333,7 +333,7 @@ func Test_buildBeatConfig(t *testing.T) { if len(diff) != 0 { wantBytes, _ := tt.want.Render() - t.Errorf("BuildKibanaConfig() got unexpected differences: %s", cmp.Diff(string(wantBytes), string(gotYaml))) + t.Errorf("buildBeatConfig() got unexpected differences: %s", cmp.Diff(string(wantBytes), string(gotYaml))) } require.Equal(t, gotErr != nil, tt.wantErr) }) diff --git a/pkg/controller/beat/common/monitoring.go b/pkg/controller/beat/common/monitoring.go index 690acd1e05..80b15c6c38 100644 --- a/pkg/controller/beat/common/monitoring.go +++ b/pkg/controller/beat/common/monitoring.go @@ -1,7 +1,5 @@ package common -import "fmt" - // MonitoringConfig contains the stack monitoring configuration for Beats. type MonitoringConfig struct { Enabled bool `json:"enabled,omitempty"` @@ -27,7 +25,3 @@ type SSLConfig struct { // VerificationMode contains the verification mode for server certificates. Valid options: [full, strict, certificate, none] VerificationMode string `config:"verification_mode" yaml:"verification_mode"` } - -func getMonitoringCASecretName(beatName string) string { - return fmt.Sprintf("%s-monitoring-ca", beatName) -} diff --git a/pkg/controller/common/settings/canonical_config_test.go b/pkg/controller/common/settings/canonical_config_test.go index 06ff33dd71..ba590dcba2 100644 --- a/pkg/controller/common/settings/canonical_config_test.go +++ b/pkg/controller/common/settings/canonical_config_test.go @@ -417,10 +417,6 @@ func TestNewCanonicalConfigFrom(t *testing.T) { type args struct { data untypedDict } - type sslConfig struct { - CertificateAuthorities []string `config:"certificate_authorities" json:"certificate_authorities" yaml:"certificate_authorities"` - VerificationMode string `config:"verification_mode" json:"verification_mode" yaml:"verification_mode"` - } tests := []struct { name string args args @@ -441,19 +437,6 @@ func TestNewCanonicalConfigFrom(t *testing.T) { }), wantErr: false, }, - { - name: "config tags should be supported to allow underscores", - args: args{ - data: map[string]interface{}{ - "monitoring": float64(1), // after json round trip or deep copy typically a float - }, - }, - want: MustCanonicalConfig(map[string]interface{}{ - "a": 1, - "b": 1.2, - }), - wantErr: false, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/test/e2e/beat/config_test.go b/test/e2e/beat/config_test.go index d676662c9f..1873dc612b 100644 --- a/test/e2e/beat/config_test.go +++ b/test/e2e/beat/config_test.go @@ -13,8 +13,6 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" - v1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/beat/auditbeat" "github.com/elastic/cloud-on-k8s/pkg/controller/beat/filebeat" @@ -22,6 +20,7 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/beat/journalbeat" "github.com/elastic/cloud-on-k8s/pkg/controller/beat/metricbeat" "github.com/elastic/cloud-on-k8s/pkg/controller/beat/packetbeat" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/test/e2e/test" "github.com/elastic/cloud-on-k8s/test/e2e/test/beat" "github.com/elastic/cloud-on-k8s/test/e2e/test/elasticsearch" From 89914126e39c66e1d5cbfd2cc8d7bbc3463d6bc7 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 18 Jul 2022 13:04:45 -0500 Subject: [PATCH 09/64] Add missing '/v2' to association package. Add unit test for buildMonitoringConfig Fix duplicative import in test/e2e/beat/config_test.go --- pkg/apis/beat/v1beta1/beat_types.go | 8 +- pkg/apis/elasticsearch/v1/status.go | 2 +- .../association/controller/beat_monitoring.go | 18 +- pkg/controller/beat/common/config.go | 5 +- pkg/controller/beat/common/config_test.go | 155 +++++++++++++++++- test/e2e/beat/config_test.go | 1 - 6 files changed, 172 insertions(+), 17 deletions(-) diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index fb43a618ee..c72b95f0b5 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -80,10 +80,10 @@ type BeatSpec struct { // +kubebuilder:validation:Optional Deployment *DeploymentSpec `json:"deployment,omitempty"` - // Monitoring enables you to collect and ship log and monitoring data of this Beat. + // Monitoring enables you to collect and ship monitoring data of this Beat. // See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - // Internal Beat collectors are configured and sends data (metrics and logs) to one - // or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. + // Internal Beat collectors are configured and send metrics data to one + // Elasticsearch monitoring cluster running in the same Kubernetes cluster. // +kubebuilder:validation:Optional Monitoring Monitoring `json:"monitoring,omitempty"` @@ -228,7 +228,7 @@ func (b *Beat) SetAssociationStatusMap(typ commonv1.AssociationType, status comm b.Status.MonitoringAssociationsStatus = status return nil default: - return fmt.Errorf("beat: association type %s not known", typ) + return fmt.Errorf("association type %s not known", typ) } } diff --git a/pkg/apis/elasticsearch/v1/status.go b/pkg/apis/elasticsearch/v1/status.go index fc1925d396..af8ca91c47 100644 --- a/pkg/apis/elasticsearch/v1/status.go +++ b/pkg/apis/elasticsearch/v1/status.go @@ -98,7 +98,7 @@ func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) comm func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, status commonv1.AssociationStatusMap) error { if typ != commonv1.EsMonitoringAssociationType { - return fmt.Errorf("elasticsearch: association type %s not known", typ) + return fmt.Errorf("association type %s not known", typ) } es.Status.MonitoringAssociationsStatus = status diff --git a/pkg/controller/association/controller/beat_monitoring.go b/pkg/controller/association/controller/beat_monitoring.go index 830d3e4fbd..26fb9f7da1 100644 --- a/pkg/controller/association/controller/beat_monitoring.go +++ b/pkg/controller/association/controller/beat_monitoring.go @@ -9,15 +9,15 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - beatv1b1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" - commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" - esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" - "github.com/elastic/cloud-on-k8s/pkg/controller/association" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/operator" - eslabel "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" - "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" - "github.com/elastic/cloud-on-k8s/pkg/utils/rbac" + beatv1b1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" + commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/operator" + eslabel "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/label" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/user" + "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" + "github.com/elastic/cloud-on-k8s/v2/pkg/utils/rbac" ) // AddBeatMonitoring reconciles an association between Beat and Elasticsearch clusters for Stack Monitoring. diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 54c60fe167..baf404b357 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -15,12 +15,15 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" - v1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + v1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/certificates" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/labels" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/reconciler" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/validations" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" ) diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 9732f402e7..29e927f2e2 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -6,6 +6,7 @@ package common import ( "context" + "reflect" "testing" "github.com/go-logr/logr" @@ -17,7 +18,7 @@ import ( beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" - esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" + esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/watches" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" @@ -542,3 +543,155 @@ func Test_getUserConfig(t *testing.T) { }) } } + +func Test_buildMonitoringConfig(t *testing.T) { + k8sClient := k8s.NewFakeClient() + k8sClientWithValidMonitoring := k8s.NewFakeClient( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beat-secret", + Namespace: "test", + }, + Data: map[string][]byte{"elastic": []byte("123")}, + }, + ) + monitoringYaml := settings.MustParseConfig([]byte(`monitoring: + enabled: true + elasticsearch: + hosts: + - "https://testes-es-internal-http.ns.svc:9200" + username: elastic + password: "123" + ssl: + certificate_authorities: + - "/mnt/elastic-internal/beat-monitoring-certs/ca.crt" + verification_mode: "certificate" +`)) + tests := []struct { + name string + params func() DriverParams + want *settings.CanonicalConfig + wantErr bool + expectedErrString string + }{ + { + name: "beat without monitoring.ElasticsearchRefs returns error", + params: func() DriverParams { + return DriverParams{ + Beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Monitoring: beatv1beta1.Monitoring{}, + }, + }, + } + }, + want: nil, + wantErr: true, + expectedErrString: "ElasticsearchRef must exist when stack monitoring is enabled", + }, + { + name: "beat with monitoring.ElasticsearchRef that isn't properly defined returns error", + params: func() DriverParams { + return DriverParams{ + Beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Monitoring: beatv1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "", + SecretName: "", + }, + }, + }, + }, + }, + } + }, + want: nil, + wantErr: true, + expectedErrString: "Beats must be associated to an Elasticsearch cluster through elasticsearchRef in order to enable monitoring metrics features", + }, + { + name: "beat with monitoring.ElasticsearchRef with invalid association config (secret not found) returns error", + params: func() DriverParams { + beat := beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Monitoring: beatv1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "fake", + SecretName: "fake", + }, + }, + }, + }, + } + beat.MonitoringAssociation(commonv1.ObjectSelector{Name: "fake", SecretName: "fake"}).SetAssociationConf(&commonv1.AssociationConf{ + AuthSecretName: "does-not-exist", + AuthSecretKey: "invalid", + }) + return DriverParams{ + Beat: beat, + Client: k8sClient, + } + }, + want: nil, + wantErr: true, + expectedErrString: `secrets "does-not-exist" not found`, + }, + { + name: "beat with valid monitoring association configuration succeeds", + params: func() DriverParams { + beat := beatv1beta1.Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beat", + Namespace: "test", + }, + Spec: beatv1beta1.BeatSpec{ + Monitoring: beatv1beta1.Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "fake", + SecretName: "fake", + }, + }, + }, + }, + } + beat.MonitoringAssociation(commonv1.ObjectSelector{Name: "fake", SecretName: "fake"}).SetAssociationConf(&commonv1.AssociationConf{ + AuthSecretName: "beat-secret", + AuthSecretKey: "elastic", + CACertProvided: true, + URL: "https://testes-es-internal-http.ns.svc:9200", + }) + return DriverParams{ + Beat: beat, + Client: k8sClientWithValidMonitoring, + } + }, + want: monitoringYaml, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := buildMonitoringConfig(tt.params()) + if (err != nil) != tt.wantErr { + t.Errorf("buildMonitoringConfig() error = %v, wantErr %v", err, tt.wantErr) + return + } + if tt.wantErr && (tt.expectedErrString != err.Error()) { + t.Errorf("buildMonitoringConfig() = %v, want %v", err.Error(), tt.expectedErrString) + return + } + if len(tt.want.Diff(got, nil)) != 0 { + wantBytes, _ := tt.want.Render() + gotBytes, _ := got.Render() + t.Errorf("buildMonitoringConfig() got unexpected differences: %s", cmp.Diff(string(wantBytes), string(gotBytes))) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("buildMonitoringConfig() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/test/e2e/beat/config_test.go b/test/e2e/beat/config_test.go index e66aa02d00..e52b9cbd4b 100644 --- a/test/e2e/beat/config_test.go +++ b/test/e2e/beat/config_test.go @@ -13,7 +13,6 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/version" v1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/beat/auditbeat" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/beat/filebeat" From 02b04892675d6d115714f73ff9fc094874bc58ef Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 18 Jul 2022 13:07:41 -0500 Subject: [PATCH 10/64] Optimize ssl/ca bits when creating monitoring configuration --- pkg/controller/beat/common/config.go | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index baf404b357..f5577db9c7 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -8,7 +8,6 @@ import ( "hash" "path" "path/filepath" - "strings" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" @@ -143,7 +142,6 @@ func buildMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, erro } var username, password, url string - var sslConfig SSLConfig associations := monitoring.GetMetricsAssociation(¶ms.Beat) if len(associations) != 1 { // should never happen because of the pre-creation validation @@ -168,14 +166,6 @@ func buildMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, erro caDirPath := certificatesDir(assoc) - if assocConf.GetCACertProvided() { - sslCAPath := filepath.Join(caDirPath, certificates.CAFileName) - sslConfig = SSLConfig{ - CertificateAuthorities: []string{sslCAPath}, - VerificationMode: "certificate", - } - } - config := MonitoringConfig{ Enabled: true, Elasticsearch: ElasticsearchConfig{ @@ -185,8 +175,12 @@ func buildMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, erro }, } - if strings.Contains(url, "https") { - config.Elasticsearch.SSL = sslConfig + if assocConf.GetCACertProvided() { + sslCAPath := filepath.Join(caDirPath, certificates.CAFileName) + config.Elasticsearch.SSL = SSLConfig{ + CertificateAuthorities: []string{sslCAPath}, + VerificationMode: "certificate", + } } return settings.NewCanonicalConfigFrom(map[string]interface{}{"monitoring": config}) From e5177334d5f49f531ca1b6752d2ee8eb35c0b5d2 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 18 Jul 2022 13:10:01 -0500 Subject: [PATCH 11/64] Add copyright to beat/common/monitoring.go --- pkg/controller/beat/common/monitoring.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/controller/beat/common/monitoring.go b/pkg/controller/beat/common/monitoring.go index 80b15c6c38..8691cf958b 100644 --- a/pkg/controller/beat/common/monitoring.go +++ b/pkg/controller/beat/common/monitoring.go @@ -1,3 +1,7 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + package common // MonitoringConfig contains the stack monitoring configuration for Beats. From 42829d92c705273ce5f5494dc0e314acad5751ce Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 18 Jul 2022 13:12:36 -0500 Subject: [PATCH 12/64] remove duplicative checks in beat e2e test --- test/e2e/test/beat/steps.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/e2e/test/beat/steps.go b/test/e2e/test/beat/steps.go index 1fca017c8c..2007fef3ba 100644 --- a/test/e2e/test/beat/steps.go +++ b/test/e2e/test/beat/steps.go @@ -137,12 +137,6 @@ func (b Builder) CheckK8sTestSteps(k *test.K8sClient) test.StepList { if !cmp.Equal(beat.Status, expected) { return fmt.Errorf("expected status health %+v, got diff: %s", expected, cmp.Diff(beat.Status, expected)) } - if beat.Status.Health != expected.Health { - return fmt.Errorf("expected status health %+v but got %+v", expected.Health, beat.Status.Health) - } - if beat.Status.Version != expected.Version { - return fmt.Errorf("expected status version %+v but got %+v", expected.Version, beat.Status.Version) - } return nil }), }, From 94ebcf3b509d446f54d83567f3e831fc10c9e271 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 18 Jul 2022 13:29:10 -0500 Subject: [PATCH 13/64] remove unused monitoringAssociationConnectionInfo --- pkg/controller/beat/common/driver.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 28dd7ea966..56f77a830e 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -40,8 +40,6 @@ type DriverParams struct { Status *beatv1beta1.BeatStatus Beat beatv1beta1.Beat - - monitoringAssociationConnectionInfo *association.UnmanagedAssociationConnectionInfo } func (dp DriverParams) K8sClient() k8s.Client { From 77a205ed9dafb07cf1ab6841a534aef2b64588ed Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 18 Jul 2022 14:23:36 -0500 Subject: [PATCH 14/64] re-running generation, since wording changed in crds --- config/crds/v1/all-crds.yaml | 8 ++++---- .../v1/bases/beat.k8s.elastic.co_beats.yaml | 8 ++++---- .../eck-operator-crds/templates/all-crds.yaml | 8 ++++---- docs/reference/api-docs.asciidoc | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index ee891c4712..2ad5c6d65b 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2352,11 +2352,11 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship log and monitoring + description: Monitoring enables you to collect and ship monitoring data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - Internal Beat collectors are configured and sends data (metrics - and logs) to one or two different Elasticsearch monitoring clusters - running in the same Kubernetes cluster. + Internal Beat collectors are configured and send metrics data to + one Elasticsearch monitoring cluster running in the same Kubernetes + cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index 36c5fca96a..f099671199 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15341,11 +15341,11 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship log and monitoring + description: Monitoring enables you to collect and ship monitoring data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - Internal Beat collectors are configured and sends data (metrics - and logs) to one or two different Elasticsearch monitoring clusters - running in the same Kubernetes cluster. + Internal Beat collectors are configured and send metrics data to + one Elasticsearch monitoring cluster running in the same Kubernetes + cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 676fba4a8b..32243a7e7e 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2370,11 +2370,11 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship log and monitoring + description: Monitoring enables you to collect and ship monitoring data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - Internal Beat collectors are configured and sends data (metrics - and logs) to one or two different Elasticsearch monitoring clusters - running in the same Kubernetes cluster. + Internal Beat collectors are configured and send metrics data to + one Elasticsearch monitoring cluster running in the same Kubernetes + cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 151b9e961d..9ab6f8dd6d 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -315,6 +315,7 @@ BeatSpec defines the desired state of a Beat. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`daemonSet`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-daemonsetspec[$$DaemonSetSpec$$]__ | DaemonSet specifies the Beat should be deployed as a DaemonSet, and allows providing its spec. Cannot be used along with `deployment`. If both are absent a default for the Type is used. | *`deployment`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-deploymentspec[$$DeploymentSpec$$]__ | Deployment specifies the Beat should be deployed as a Deployment, and allows providing its spec. Cannot be used along with `daemonSet`. If both are absent a default for the Type is used. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship monitoring data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html Internal Beat collectors are configured and send metrics data to one Elasticsearch monitoring cluster running in the same Kubernetes cluster. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying DaemonSet or Deployment. |=== @@ -356,6 +357,23 @@ BeatSpec defines the desired state of a Beat. |=== +[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring"] +=== Monitoring + + + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-beatspec[$$BeatSpec$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +|=== + + [id="{anchor_prefix}-common-k8s-elastic-co-v1"] == common.k8s.elastic.co/v1 @@ -488,6 +506,7 @@ ObjectSelector defines a reference to a Kubernetes object which can be an Elasti - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-maps-v1alpha1-mapsspec[$$MapsSpec$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-metricsmonitoring[$$MetricsMonitoring$$] +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-agent-v1alpha1-output[$$Output$$] **** From 0ea5dfd0080b7c03d45511326f7c0a5c314b36c8 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 26 Jul 2022 12:32:52 -0500 Subject: [PATCH 15/64] Avoid extra var in range in pkg/controller/beat/common/pod_test.go Co-authored-by: Peter Brachwitz --- pkg/controller/beat/common/pod_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 37932b231e..588505116b 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -299,10 +299,9 @@ func assertMonitoring(t *testing.T, volumes []corev1.Volume) { t.Helper() var monitoringVolume *corev1.Volume // Validate that the Pod's volumes contain a Secret as a monitoring CA volume. - for _, vol := range volumes { - if vol.Name == "beat-monitoring-certs" { - foundVol := vol - monitoringVolume = &foundVol + for i := range volumes { + if volumes[i].Name == "beat-monitoring-certs" { + monitoringVolume = &volumes[i] break } } From 9831c382550eec7e69e6b94d44e36e4c4a057c74 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 26 Jul 2022 12:52:38 -0500 Subject: [PATCH 16/64] Use new func in existing checks package to return beats monitoring step to avoid duplicating code. Remove duplicated code. --- test/e2e/test/beat/builder.go | 15 ++++++++++++ test/e2e/test/beat/checks.go | 37 ------------------------------ test/e2e/test/beat/steps.go | 31 ++----------------------- test/e2e/test/checks/monitoring.go | 11 +++++++++ 4 files changed, 28 insertions(+), 66 deletions(-) diff --git a/test/e2e/test/beat/builder.go b/test/e2e/test/beat/builder.go index 6c7be568aa..1ed0742a68 100644 --- a/test/e2e/test/beat/builder.go +++ b/test/e2e/test/beat/builder.go @@ -350,6 +350,14 @@ func (b Builder) GetMetricsIndexPattern() string { return ".monitoring-beat-*" } +func (b Builder) Name() string { + return b.Beat.Name +} + +func (b Builder) Namespace() string { + return b.Beat.Namespace +} + func (b Builder) GetMetricsCluster() *types.NamespacedName { if len(b.Beat.Spec.Monitoring.ElasticsearchRefs) == 0 { return nil @@ -357,3 +365,10 @@ func (b Builder) GetMetricsCluster() *types.NamespacedName { metricsCluster := b.Beat.Spec.Monitoring.ElasticsearchRefs[0].NamespacedName() return &metricsCluster } + +// GetLogsCluster does not return a logs cluster, as Beats stack monitoring is slightly +// different that both Elasticsearch, and Kibana stack monitoring, as it uses internal +// beat collectors to send only metrics data, not logs data. +func (b Builder) GetLogsCluster() *types.NamespacedName { + return nil +} diff --git a/test/e2e/test/beat/checks.go b/test/e2e/test/beat/checks.go index bcbb08aab4..41f871cbf4 100644 --- a/test/e2e/test/beat/checks.go +++ b/test/e2e/test/beat/checks.go @@ -10,11 +10,9 @@ import ( "fmt" "io/ioutil" "net/http" - "strconv" beatcommon "github.com/elastic/cloud-on-k8s/v2/pkg/controller/beat/common" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/client" - "github.com/elastic/cloud-on-k8s/v2/test/e2e/test/checks" ) func HasEventFromBeat(name beatcommon.Type) ValidationFunc { @@ -89,38 +87,3 @@ func checkEvent(url string, check func(int) error) ValidationFunc { return check(len(results.Hits.Hits)) } } - -func containsDocuments(esClient client.Client, indexPattern string) error { - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/_cat/indices/%s?format=json", indexPattern), nil) //nolint:noctx - if err != nil { - return err - } - resp, err := esClient.Request(context.Background(), req) - if err != nil { - return err - } - defer resp.Body.Close() - resultBytes, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - var indices []checks.Index - err = json.Unmarshal(resultBytes, &indices) - if err != nil { - return err - } - - // 1 index must exist - if len(indices) != 1 { - return fmt.Errorf("expected [%d] index [%s], found [%d]", 1, indexPattern, len(indices)) - } - docsCount, err := strconv.Atoi(indices[0].DocsCount) - if err != nil { - return err - } - // with at least 1 doc - if docsCount <= 0 { - return fmt.Errorf("index [%s] empty", indexPattern) - } - return nil -} diff --git a/test/e2e/test/beat/steps.go b/test/e2e/test/beat/steps.go index 2007fef3ba..19e20e132a 100644 --- a/test/e2e/test/beat/steps.go +++ b/test/e2e/test/beat/steps.go @@ -19,6 +19,7 @@ import ( "github.com/elastic/cloud-on-k8s/v2/pkg/utils/pointer" "github.com/elastic/cloud-on-k8s/v2/test/e2e/cmd/run" "github.com/elastic/cloud-on-k8s/v2/test/e2e/test" + "github.com/elastic/cloud-on-k8s/v2/test/e2e/test/checks" "github.com/elastic/cloud-on-k8s/v2/test/e2e/test/elasticsearch" "github.com/elastic/cloud-on-k8s/v2/test/e2e/test/generation" ) @@ -184,7 +185,7 @@ func (b Builder) CheckStackTestSteps(k *test.K8sClient) test.StepList { return nil }), }, - b.CheckMonitoringMetricsIndex(k), + checks.BeatsMonitoredStep(&b, k), } } @@ -253,31 +254,3 @@ func (b Builder) MutationTestSteps(k *test.K8sClient) test.StepList { WithSteps(b.CheckStackTestSteps(k)). WithStep(generation.CompareObjectGenerationsStep(&b.Beat, k, isMutated, beatGenerationBeforeMutation, beatObservedGenerationBeforeMutation)) } - -func (b Builder) CheckMonitoringMetricsIndex(k *test.K8sClient) test.Step { - indexPattern := b.GetMetricsIndexPattern() - return test.Step{ - Name: fmt.Sprintf("Check that documents are indexed in index %s", indexPattern), - Test: test.Eventually(func() error { - if b.GetMetricsCluster() == nil { - return nil - } - esMetricsRef := *b.GetMetricsCluster() - // Get Elasticsearch - esMetrics := esv1.Elasticsearch{} - if err := k.Client.Get(context.Background(), esMetricsRef, &esMetrics); err != nil { - return err - } - // Create a new Elasticsearch client - client, err := elasticsearch.NewElasticsearchClient(esMetrics, k) - if err != nil { - return err - } - // Check that there is at least one document - err = containsDocuments(client, indexPattern) - if err != nil { - return err - } - return nil - })} -} diff --git a/test/e2e/test/checks/monitoring.go b/test/e2e/test/checks/monitoring.go index 970c9b67d0..aad6e4b89c 100644 --- a/test/e2e/test/checks/monitoring.go +++ b/test/e2e/test/checks/monitoring.go @@ -36,6 +36,13 @@ func MonitoredSteps(monitored Monitored, k8sClient *test.K8sClient) test.StepLis }.Steps() } +func BeatsMonitoredStep(monitored Monitored, k8sClient *test.K8sClient) test.Step { + return stackMonitoringChecks{ + monitored: monitored, + k8sClient: k8sClient, + }.BeatsStep() +} + // stackMonitoringChecks tests that the monitored resource pods have 3 containers ready and that there are documents indexed in the beat indexes // of the monitoring Elasticsearch clusters. type stackMonitoringChecks struct { @@ -51,6 +58,10 @@ func (c stackMonitoringChecks) Steps() test.StepList { } } +func (c stackMonitoringChecks) BeatsStep() test.Step { + return c.CheckMonitoringMetricsIndex() +} + func (c stackMonitoringChecks) CheckBeatSidecars() test.Step { return test.Step{ Name: "Check that beat sidecars are running", From b155d9d4c41d1458b560a7e72c2714f90da66a1b Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 26 Jul 2022 20:36:59 -0500 Subject: [PATCH 17/64] Enabling webhook validation for beats stack monitoring. --- pkg/apis/beat/v1beta1/validations.go | 36 +++++++++++++++++++ .../stackmon/validations/validations.go | 4 +-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/pkg/apis/beat/v1beta1/validations.go b/pkg/apis/beat/v1beta1/validations.go index c5af436a01..23f9ad9306 100644 --- a/pkg/apis/beat/v1beta1/validations.go +++ b/pkg/apis/beat/v1beta1/validations.go @@ -5,11 +5,15 @@ package v1beta1 import ( + "fmt" "regexp" + "github.com/blang/semver/v4" "k8s.io/apimachinery/pkg/util/validation/field" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/validations" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/version" ) @@ -24,6 +28,7 @@ var ( checkSingleConfigSource, checkSpec, checkAssociations, + checkMonitoring, } updateChecks = []func(old, curr *Beat) field.ErrorList{ @@ -31,6 +36,8 @@ var ( } typeRegex = regexp.MustCompile("^[a-zA-Z0-9-]+$") + // minStackVersion is the minimum Stack version to enable Stack Monitoring on an Elastic Beats. + minStackVersion = version.MustParse("7.2.0-SNAPSHOT") ) func checkNoUnknownFields(b *Beat) field.ErrorList { @@ -114,3 +121,32 @@ func checkAssociations(b *Beat) field.ErrorList { err2 := commonv1.CheckAssociationRefs(field.NewPath("spec").Child("kibanaRef"), b.Spec.KibanaRef) return append(err1, err2...) } + +func checkMonitoring(b *Beat) field.ErrorList { + var errs field.ErrorList + if !b.Spec.Monitoring.Enabled() { + return nil + } + if err := isStackSupportedVersion(b.Spec.Version); err != nil { + finalMinStackVersion, _ := semver.FinalizeVersion(minStackVersion.String()) // discards prerelease suffix + errs = append(errs, field.Invalid(field.NewPath("spec").Child("version"), b.Spec.Version, + fmt.Sprintf(validations.UnsupportedVersionMsg, finalMinStackVersion))) + } + refs := b.GetMonitoringMetricsRefs() + if monitoring.AreEsRefsDefined(refs) && len(refs) != 1 { + errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), + refs, validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg)) + } + return errs +} + +func isStackSupportedVersion(v string) error { + ver, err := version.Parse(v) + if err != nil { + return err + } + if ver.LT(minStackVersion) { + return fmt.Errorf("unsupported version for Stack Monitoring: required >= %s", minStackVersion) + } + return nil +} diff --git a/pkg/controller/common/stackmon/validations/validations.go b/pkg/controller/common/stackmon/validations/validations.go index 873719a7e4..88cdeaa75a 100644 --- a/pkg/controller/common/stackmon/validations/validations.go +++ b/pkg/controller/common/stackmon/validations/validations.go @@ -15,7 +15,7 @@ import ( ) const ( - unsupportedVersionMsg = "Unsupported version for Stack Monitoring. Required >= %s." + UnsupportedVersionMsg = "Unsupported version for Stack Monitoring. Required >= %s." invalidElasticsearchRefsMsg = "Only one Elasticsearch reference is supported for %s Stack Monitoring" InvalidKibanaElasticsearchRefForStackMonitoringMsg = "Kibana must be associated to an Elasticsearch cluster through elasticsearchRef in order to enable monitoring metrics features" @@ -38,7 +38,7 @@ func Validate(resource monitoring.HasMonitoring, version string) field.ErrorList if err != nil { finalMinStackVersion, _ := semver.FinalizeVersion(MinStackVersion.String()) // discards prerelease suffix errs = append(errs, field.Invalid(field.NewPath("spec").Child("version"), version, - fmt.Sprintf(unsupportedVersionMsg, finalMinStackVersion))) + fmt.Sprintf(UnsupportedVersionMsg, finalMinStackVersion))) } } refs := resource.GetMonitoringMetricsRefs() From 25702b7852a6704ad184619490872e4231dbbafa Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 27 Jul 2022 09:47:09 -0500 Subject: [PATCH 18/64] Add unit tests for beat validation. --- pkg/apis/beat/v1beta1/validations.go | 13 +- pkg/apis/beat/v1beta1/validations_test.go | 119 ++++++++++++++++++ .../stackmon/validations/validations.go | 6 +- 3 files changed, 130 insertions(+), 8 deletions(-) diff --git a/pkg/apis/beat/v1beta1/validations.go b/pkg/apis/beat/v1beta1/validations.go index 23f9ad9306..8e96371165 100644 --- a/pkg/apis/beat/v1beta1/validations.go +++ b/pkg/apis/beat/v1beta1/validations.go @@ -128,15 +128,17 @@ func checkMonitoring(b *Beat) field.ErrorList { return nil } if err := isStackSupportedVersion(b.Spec.Version); err != nil { - finalMinStackVersion, _ := semver.FinalizeVersion(minStackVersion.String()) // discards prerelease suffix - errs = append(errs, field.Invalid(field.NewPath("spec").Child("version"), b.Spec.Version, - fmt.Sprintf(validations.UnsupportedVersionMsg, finalMinStackVersion))) + errs = append(errs, field.Invalid(field.NewPath("spec").Child("version"), b.Spec.Version, err.Error())) } refs := b.GetMonitoringMetricsRefs() - if monitoring.AreEsRefsDefined(refs) && len(refs) != 1 { + if !monitoring.AreEsRefsDefined(refs) { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), refs, validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg)) } + if len(refs) != 1 { + errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), + refs, validations.InvalidElasticsearchRefsMsg)) + } return errs } @@ -146,7 +148,8 @@ func isStackSupportedVersion(v string) error { return err } if ver.LT(minStackVersion) { - return fmt.Errorf("unsupported version for Stack Monitoring: required >= %s", minStackVersion) + finalMinStackVersion, _ := semver.FinalizeVersion(minStackVersion.String()) // discards prerelease suffix + return fmt.Errorf(validations.UnsupportedVersionMsg, finalMinStackVersion) } return nil } diff --git a/pkg/apis/beat/v1beta1/validations_test.go b/pkg/apis/beat/v1beta1/validations_test.go index 45adfbfb18..dc22839945 100644 --- a/pkg/apis/beat/v1beta1/validations_test.go +++ b/pkg/apis/beat/v1beta1/validations_test.go @@ -7,12 +7,14 @@ package v1beta1 import ( "testing" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/validation/field" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/validations" ) func Test_checkBeatType(t *testing.T) { @@ -207,3 +209,120 @@ func Test_checkNoDowngrade(t *testing.T) { }) } } + +func Test_checkMonitoring(t *testing.T) { + tests := []struct { + name string + beat *Beat + want field.ErrorList + }{ + { + name: "stack monitoring not enabled returns nil", + beat: &Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat", + Namespace: "test", + }, + Spec: BeatSpec{ + Type: "filebeat", + Version: "8.2.3", + DaemonSet: &DaemonSetSpec{}, + }, + }, + want: nil, + }, + { + name: "too old version with stack monitoring enabled returns unsupported version error", + beat: &Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat", + Namespace: "test", + }, + Spec: BeatSpec{ + Type: "filebeat", + Version: "7.1.0", + DaemonSet: &DaemonSetSpec{}, + Monitoring: Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "elasticsearch", + Namespace: "test", + }, + }, + }, + }, + }, + want: field.ErrorList{&field.Error{Type: field.ErrorTypeInvalid, Field: "spec.version", BadValue: "7.1.0", Detail: "Unsupported version for Stack Monitoring. Required >= 7.2.0."}}, + }, + { + name: "valid version with stack monitoring enabled but invalid ref returns error", + beat: &Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat", + Namespace: "test", + }, + Spec: BeatSpec{ + Type: "filebeat", + Version: "8.2.3", + DaemonSet: &DaemonSetSpec{}, + Monitoring: Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + // missing name + Namespace: "test", + }, + }, + }, + }, + }, + want: field.ErrorList{&field.Error{ + Type: field.ErrorTypeInvalid, + Field: "spec.monitoring.metrics.elasticsearchRefs", + BadValue: []commonv1.ObjectSelector{{Namespace: "test", Name: "", ServiceName: "", SecretName: ""}}, + Detail: validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg, + }}, + }, + { + name: "valid version with stack monitoring enabled but 2 elasticsearch refs", + beat: &Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat", + Namespace: "test", + }, + Spec: BeatSpec{ + Type: "filebeat", + Version: "8.2.3", + DaemonSet: &DaemonSetSpec{}, + Monitoring: Monitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "es1", + Namespace: "test", + }, + { + Name: "es2", + Namespace: "test", + }, + }, + }, + }, + }, + want: field.ErrorList{&field.Error{ + Type: field.ErrorTypeInvalid, + Field: "spec.monitoring.metrics.elasticsearchRefs", + BadValue: []commonv1.ObjectSelector{ + {Namespace: "test", Name: "es1", ServiceName: "", SecretName: ""}, + {Namespace: "test", Name: "es2", ServiceName: "", SecretName: ""}, + }, + Detail: validations.InvalidElasticsearchRefsMsg, + }}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := checkMonitoring(tt.beat); !cmp.Equal(got, tt.want) { + t.Errorf("checkMonitoring() = diff: %s", cmp.Diff(got, tt.want)) + } + }) + } +} diff --git a/pkg/controller/common/stackmon/validations/validations.go b/pkg/controller/common/stackmon/validations/validations.go index 88cdeaa75a..45a435ebe8 100644 --- a/pkg/controller/common/stackmon/validations/validations.go +++ b/pkg/controller/common/stackmon/validations/validations.go @@ -16,7 +16,7 @@ import ( const ( UnsupportedVersionMsg = "Unsupported version for Stack Monitoring. Required >= %s." - invalidElasticsearchRefsMsg = "Only one Elasticsearch reference is supported for %s Stack Monitoring" + InvalidElasticsearchRefsMsg = "Only one Elasticsearch reference is supported for %s Stack Monitoring" InvalidKibanaElasticsearchRefForStackMonitoringMsg = "Kibana must be associated to an Elasticsearch cluster through elasticsearchRef in order to enable monitoring metrics features" InvalidBeatsElasticsearchRefForStackMonitoringMsg = "Beats must be associated to an Elasticsearch cluster through elasticsearchRef in order to enable monitoring metrics features" @@ -44,12 +44,12 @@ func Validate(resource monitoring.HasMonitoring, version string) field.ErrorList refs := resource.GetMonitoringMetricsRefs() if monitoring.AreEsRefsDefined(refs) && len(refs) != 1 { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), - refs, fmt.Sprintf(invalidElasticsearchRefsMsg, "Metrics"))) + refs, fmt.Sprintf(InvalidElasticsearchRefsMsg, "Metrics"))) } refs = resource.GetMonitoringLogsRefs() if monitoring.AreEsRefsDefined(refs) && len(refs) != 1 { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), - refs, fmt.Sprintf(invalidElasticsearchRefsMsg, "Logs"))) + refs, fmt.Sprintf(InvalidElasticsearchRefsMsg, "Logs"))) } return errs } From 2779620e48a2acaa3fa6dadea9298eee7f06bedd Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 27 Jul 2022 09:59:56 -0500 Subject: [PATCH 19/64] Minor change in pod_test.go. --- pkg/controller/beat/common/pod_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 588505116b..4a63115868 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -299,7 +299,7 @@ func assertMonitoring(t *testing.T, volumes []corev1.Volume) { t.Helper() var monitoringVolume *corev1.Volume // Validate that the Pod's volumes contain a Secret as a monitoring CA volume. - for i := range volumes { + for i := range volumes { if volumes[i].Name == "beat-monitoring-certs" { monitoringVolume = &volumes[i] break From 2994d5f630229fdad9791ec50535e542a48f7547 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Fri, 29 Jul 2022 09:13:44 -0500 Subject: [PATCH 20/64] Removing unneeded BeatsStep function. Removing snapshot from minimal beats stack version. Adding some documentation around why 7.2 is the minimum version. --- pkg/apis/beat/v1beta1/validations.go | 8 ++++---- test/e2e/test/checks/monitoring.go | 6 +----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/pkg/apis/beat/v1beta1/validations.go b/pkg/apis/beat/v1beta1/validations.go index 8e96371165..517b22c64b 100644 --- a/pkg/apis/beat/v1beta1/validations.go +++ b/pkg/apis/beat/v1beta1/validations.go @@ -8,7 +8,6 @@ import ( "fmt" "regexp" - "github.com/blang/semver/v4" "k8s.io/apimachinery/pkg/util/validation/field" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" @@ -37,7 +36,9 @@ var ( typeRegex = regexp.MustCompile("^[a-zA-Z0-9-]+$") // minStackVersion is the minimum Stack version to enable Stack Monitoring on an Elastic Beats. - minStackVersion = version.MustParse("7.2.0-SNAPSHOT") + // Technically, Beats internal monitoring existed prior to 7.2.0, but it's configuration format + // was slightly different. + minStackVersion = version.MustParse("7.2.0") ) func checkNoUnknownFields(b *Beat) field.ErrorList { @@ -148,8 +149,7 @@ func isStackSupportedVersion(v string) error { return err } if ver.LT(minStackVersion) { - finalMinStackVersion, _ := semver.FinalizeVersion(minStackVersion.String()) // discards prerelease suffix - return fmt.Errorf(validations.UnsupportedVersionMsg, finalMinStackVersion) + return fmt.Errorf(validations.UnsupportedVersionMsg, minStackVersion) } return nil } diff --git a/test/e2e/test/checks/monitoring.go b/test/e2e/test/checks/monitoring.go index aad6e4b89c..a3b7b01409 100644 --- a/test/e2e/test/checks/monitoring.go +++ b/test/e2e/test/checks/monitoring.go @@ -40,7 +40,7 @@ func BeatsMonitoredStep(monitored Monitored, k8sClient *test.K8sClient) test.Ste return stackMonitoringChecks{ monitored: monitored, k8sClient: k8sClient, - }.BeatsStep() + }.CheckMonitoringMetricsIndex() } // stackMonitoringChecks tests that the monitored resource pods have 3 containers ready and that there are documents indexed in the beat indexes @@ -58,10 +58,6 @@ func (c stackMonitoringChecks) Steps() test.StepList { } } -func (c stackMonitoringChecks) BeatsStep() test.Step { - return c.CheckMonitoringMetricsIndex() -} - func (c stackMonitoringChecks) CheckBeatSidecars() test.Step { return test.Step{ Name: "Check that beat sidecars are running", From 2c19f81178e54f75ba17e7185e4ebb61b8572da7 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 2 Aug 2022 10:36:47 -0500 Subject: [PATCH 21/64] Moving to utilizing sidecars for beat monitoring instead of internal collectors. --- config/crds/v1/all-crds.yaml | 134 +++++--- .../v1/bases/beat.k8s.elastic.co_beats.yaml | 134 +++++--- .../recipes/beats/filebeat_autodiscover.yaml | 64 ++-- .../eck-operator-crds/templates/all-crds.yaml | 134 +++++--- pkg/apis/beat/v1beta1/beat_types.go | 43 ++- pkg/apis/beat/v1beta1/validations.go | 11 +- .../beat/v1beta1/zz_generated.deepcopy.go | 39 ++- pkg/controller/beat/common/config.go | 76 +---- pkg/controller/beat/common/config_test.go | 287 ------------------ pkg/controller/beat/common/monitoring.go | 31 -- pkg/controller/beat/common/pod.go | 37 ++- pkg/controller/beat/common/pod_test.go | 13 +- .../beat/common/stackmon/filebeat.yml | 8 + .../beat/common/stackmon/metricbeat.yml | 9 + .../beat/common/stackmon/stackmon.go | 67 ++++ 15 files changed, 532 insertions(+), 555 deletions(-) delete mode 100644 pkg/controller/beat/common/monitoring.go create mode 100644 pkg/controller/beat/common/stackmon/filebeat.yml create mode 100644 pkg/controller/beat/common/stackmon/metricbeat.yml create mode 100644 pkg/controller/beat/common/stackmon/stackmon.go diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 2ad5c6d65b..5839ba5fb6 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2358,46 +2358,100 @@ spec: one Elasticsearch monitoring cluster running in the same Kubernetes cluster. properties: - elasticsearchRefs: - description: ElasticsearchRefs is a reference to a list of monitoring - Elasticsearch clusters running in the same Kubernetes cluster. - Due to existing limitations, only a single Elasticsearch cluster - is currently supported. - items: - description: ObjectSelector defines a reference to a Kubernetes - object which can be an Elastic resource managed by the operator - or a Secret describing an external Elastic resource not managed - by the operator. - properties: - name: - description: Name of an existing Kubernetes object corresponding - to an Elastic resource managed by ECK. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - secretName: - description: 'SecretName is the name of an existing Kubernetes - secret that contains connection information for associating - an Elastic resource not managed by the operator. The referenced - secret must contain the following: - `url`: the URL to - reach the Elastic resource - `username`: the username - of the user to be authenticated to the Elastic resource - - `password`: the password of the user to be authenticated - to the Elastic resource - `ca.crt`: the CA certificate - in PEM format (optional). This field cannot be used in - combination with the other fields name, namespace or serviceName.' - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which is used to make requests to the referenced - object. It has to be in the same namespace as the referenced - resource. If left empty, the default HTTP service of the - referenced resource is used. - type: string - type: object - type: array + logs: + description: Logs holds references to Elasticsearch clusters which + receive log data from this Beats resource. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the + operator or a Secret describing an external Elastic resource + not managed by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing + Kubernetes secret that contains connection information + for associating an Elastic resource not managed by + the operator. The referenced secret must contain the + following: - `url`: the URL to reach the Elastic resource + - `username`: the username of the user to be authenticated + to the Elastic resource - `password`: the password + of the user to be authenticated to the Elastic resource + - `ca.crt`: the CA certificate in PEM format (optional). + This field cannot be used in combination with the + other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which is used to make requests + to the referenced object. It has to be in the same + namespace as the referenced resource. If left empty, + the default HTTP service of the referenced resource + is used. + type: string + type: object + type: array + type: object + metrics: + description: Metrics holds references to Elasticsearch clusters + which receive monitoring data from this Beats resource. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the + operator or a Secret describing an external Elastic resource + not managed by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing + Kubernetes secret that contains connection information + for associating an Elastic resource not managed by + the operator. The referenced secret must contain the + following: - `url`: the URL to reach the Elastic resource + - `username`: the username of the user to be authenticated + to the Elastic resource - `password`: the password + of the user to be authenticated to the Elastic resource + - `ca.crt`: the CA certificate in PEM format (optional). + This field cannot be used in combination with the + other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which is used to make requests + to the referenced object. It has to be in the same + namespace as the referenced resource. If left empty, + the default HTTP service of the referenced resource + is used. + type: string + type: object + type: array + type: object type: object revisionHistoryLimit: description: RevisionHistoryLimit is the number of revisions to retain diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index f099671199..f46eb12f68 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15347,46 +15347,100 @@ spec: one Elasticsearch monitoring cluster running in the same Kubernetes cluster. properties: - elasticsearchRefs: - description: ElasticsearchRefs is a reference to a list of monitoring - Elasticsearch clusters running in the same Kubernetes cluster. - Due to existing limitations, only a single Elasticsearch cluster - is currently supported. - items: - description: ObjectSelector defines a reference to a Kubernetes - object which can be an Elastic resource managed by the operator - or a Secret describing an external Elastic resource not managed - by the operator. - properties: - name: - description: Name of an existing Kubernetes object corresponding - to an Elastic resource managed by ECK. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - secretName: - description: 'SecretName is the name of an existing Kubernetes - secret that contains connection information for associating - an Elastic resource not managed by the operator. The referenced - secret must contain the following: - `url`: the URL to - reach the Elastic resource - `username`: the username - of the user to be authenticated to the Elastic resource - - `password`: the password of the user to be authenticated - to the Elastic resource - `ca.crt`: the CA certificate - in PEM format (optional). This field cannot be used in - combination with the other fields name, namespace or serviceName.' - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which is used to make requests to the referenced - object. It has to be in the same namespace as the referenced - resource. If left empty, the default HTTP service of the - referenced resource is used. - type: string - type: object - type: array + logs: + description: Logs holds references to Elasticsearch clusters which + receive log data from this Beats resource. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the + operator or a Secret describing an external Elastic resource + not managed by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing + Kubernetes secret that contains connection information + for associating an Elastic resource not managed by + the operator. The referenced secret must contain the + following: - `url`: the URL to reach the Elastic resource + - `username`: the username of the user to be authenticated + to the Elastic resource - `password`: the password + of the user to be authenticated to the Elastic resource + - `ca.crt`: the CA certificate in PEM format (optional). + This field cannot be used in combination with the + other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which is used to make requests + to the referenced object. It has to be in the same + namespace as the referenced resource. If left empty, + the default HTTP service of the referenced resource + is used. + type: string + type: object + type: array + type: object + metrics: + description: Metrics holds references to Elasticsearch clusters + which receive monitoring data from this Beats resource. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the + operator or a Secret describing an external Elastic resource + not managed by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing + Kubernetes secret that contains connection information + for associating an Elastic resource not managed by + the operator. The referenced secret must contain the + following: - `url`: the URL to reach the Elastic resource + - `username`: the username of the user to be authenticated + to the Elastic resource - `password`: the password + of the user to be authenticated to the Elastic resource + - `ca.crt`: the CA certificate in PEM format (optional). + This field cannot be used in combination with the + other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which is used to make requests + to the referenced object. It has to be in the same + namespace as the referenced resource. If left empty, + the default HTTP service of the referenced resource + is used. + type: string + type: object + type: array + type: object type: object revisionHistoryLimit: description: RevisionHistoryLimit is the number of revisions to retain diff --git a/config/recipes/beats/filebeat_autodiscover.yaml b/config/recipes/beats/filebeat_autodiscover.yaml index 234f671ab5..64257bb2d8 100644 --- a/config/recipes/beats/filebeat_autodiscover.yaml +++ b/config/recipes/beats/filebeat_autodiscover.yaml @@ -6,9 +6,16 @@ spec: type: filebeat version: 8.3.1 elasticsearchRef: - name: elasticsearch + name: source kibanaRef: - name: kibana + name: source-kibana + monitoring: + logs: + elasticsearchRefs: + - name: source + metrics: + elasticsearchRefs: + - name: source config: filebeat: autodiscover: @@ -34,6 +41,13 @@ spec: hostNetwork: true # Allows to provide richer host metadata containers: - name: filebeat + resources: + limits: + cpu: 500m + memory: 500Mi + requests: + cpu: 500m + memory: 200M securityContext: runAsUser: 0 # If using Red Hat OpenShift uncomment this: @@ -94,26 +108,26 @@ roleRef: kind: ClusterRole name: filebeat apiGroup: rbac.authorization.k8s.io ---- -apiVersion: elasticsearch.k8s.elastic.co/v1 -kind: Elasticsearch -metadata: - name: elasticsearch -spec: - version: 8.3.1 - nodeSets: - - name: default - count: 3 - config: - node.store.allow_mmap: false ---- -apiVersion: kibana.k8s.elastic.co/v1 -kind: Kibana -metadata: - name: kibana -spec: - version: 8.3.1 - count: 1 - elasticsearchRef: - name: elasticsearch -... +# --- +# apiVersion: elasticsearch.k8s.elastic.co/v1 +# kind: Elasticsearch +# metadata: +# name: elasticsearch +# spec: +# version: 8.3.1 +# nodeSets: +# - name: default +# count: 3 +# config: +# node.store.allow_mmap: false +# --- +# apiVersion: kibana.k8s.elastic.co/v1 +# kind: Kibana +# metadata: +# name: kibana +# spec: +# version: 8.3.1 +# count: 1 +# elasticsearchRef: +# name: elasticsearch +# ... diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 32243a7e7e..77bdc7bda6 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2376,46 +2376,100 @@ spec: one Elasticsearch monitoring cluster running in the same Kubernetes cluster. properties: - elasticsearchRefs: - description: ElasticsearchRefs is a reference to a list of monitoring - Elasticsearch clusters running in the same Kubernetes cluster. - Due to existing limitations, only a single Elasticsearch cluster - is currently supported. - items: - description: ObjectSelector defines a reference to a Kubernetes - object which can be an Elastic resource managed by the operator - or a Secret describing an external Elastic resource not managed - by the operator. - properties: - name: - description: Name of an existing Kubernetes object corresponding - to an Elastic resource managed by ECK. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - secretName: - description: 'SecretName is the name of an existing Kubernetes - secret that contains connection information for associating - an Elastic resource not managed by the operator. The referenced - secret must contain the following: - `url`: the URL to - reach the Elastic resource - `username`: the username - of the user to be authenticated to the Elastic resource - - `password`: the password of the user to be authenticated - to the Elastic resource - `ca.crt`: the CA certificate - in PEM format (optional). This field cannot be used in - combination with the other fields name, namespace or serviceName.' - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which is used to make requests to the referenced - object. It has to be in the same namespace as the referenced - resource. If left empty, the default HTTP service of the - referenced resource is used. - type: string - type: object - type: array + logs: + description: Logs holds references to Elasticsearch clusters which + receive log data from this Beats resource. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the + operator or a Secret describing an external Elastic resource + not managed by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing + Kubernetes secret that contains connection information + for associating an Elastic resource not managed by + the operator. The referenced secret must contain the + following: - `url`: the URL to reach the Elastic resource + - `username`: the username of the user to be authenticated + to the Elastic resource - `password`: the password + of the user to be authenticated to the Elastic resource + - `ca.crt`: the CA certificate in PEM format (optional). + This field cannot be used in combination with the + other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which is used to make requests + to the referenced object. It has to be in the same + namespace as the referenced resource. If left empty, + the default HTTP service of the referenced resource + is used. + type: string + type: object + type: array + type: object + metrics: + description: Metrics holds references to Elasticsearch clusters + which receive monitoring data from this Beats resource. + properties: + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object which can be an Elastic resource managed by the + operator or a Secret describing an external Elastic resource + not managed by the operator. + properties: + name: + description: Name of an existing Kubernetes object corresponding + to an Elastic resource managed by ECK. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + secretName: + description: 'SecretName is the name of an existing + Kubernetes secret that contains connection information + for associating an Elastic resource not managed by + the operator. The referenced secret must contain the + following: - `url`: the URL to reach the Elastic resource + - `username`: the username of the user to be authenticated + to the Elastic resource - `password`: the password + of the user to be authenticated to the Elastic resource + - `ca.crt`: the CA certificate in PEM format (optional). + This field cannot be used in combination with the + other fields name, namespace or serviceName.' + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which is used to make requests + to the referenced object. It has to be in the same + namespace as the referenced resource. If left empty, + the default HTTP service of the referenced resource + is used. + type: string + type: object + type: array + type: object type: object revisionHistoryLimit: description: RevisionHistoryLimit is the number of revisions to retain diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index c72b95f0b5..fee457dfe3 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" ) const ( @@ -80,9 +81,8 @@ type BeatSpec struct { // +kubebuilder:validation:Optional Deployment *DeploymentSpec `json:"deployment,omitempty"` - // Monitoring enables you to collect and ship monitoring data of this Beat. - // See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - // Internal Beat collectors are configured and send metrics data to one + // Monitoring enables you to collect and ship monitoring, and logs data of this Beat. + // Metricbeat and/or Filebeat sidecars are configured and send metrics data to one // Elasticsearch monitoring cluster running in the same Kubernetes cluster. // +kubebuilder:validation:Optional Monitoring Monitoring `json:"monitoring,omitempty"` @@ -107,15 +107,26 @@ type DeploymentSpec struct { } type Monitoring struct { + // Metrics holds references to Elasticsearch clusters which receive monitoring data from this Beats resource. + // +kubebuilder:validation:Optional + Metrics MetricsMonitoring `json:"metrics,omitempty"` + // Logs holds references to Elasticsearch clusters which receive log data from this Beats resource. + // +kubebuilder:validation:Optional + Logs LogsMonitoring `json:"logs,omitempty"` +} + +type MetricsMonitoring struct { // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. // Due to existing limitations, only a single Elasticsearch cluster is currently supported. // +kubebuilder:validation:Required ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` } -// Enabled returns whether the Beat has stack monitoring enabled. -func (m Monitoring) Enabled() bool { - return len(m.ElasticsearchRefs) > 0 +type LogsMonitoring struct { + // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. + // Due to existing limitations, only a single Elasticsearch cluster is currently supported. + // +kubebuilder:validation:Required + ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` } // BeatStatus defines the observed state of a Beat. @@ -201,10 +212,8 @@ func (b *Beat) AssociationStatusMap(typ commonv1.AssociationType) commonv1.Assoc return commonv1.NewSingleAssociationStatusMap(b.Status.KibanaAssociationStatus) } case commonv1.BeatMonitoringAssociationType: - for _, esRef := range b.Spec.Monitoring.ElasticsearchRefs { - if esRef.IsDefined() { - return b.Status.MonitoringAssociationsStatus - } + if monitoring.IsDefined(b) { + return b.Status.MonitoringAssociationsStatus } } @@ -251,7 +260,15 @@ func (b *Beat) GetAssociations() []commonv1.Association { Beat: b, }) } - for _, ref := range b.Spec.Monitoring.ElasticsearchRefs { + for _, ref := range b.Spec.Monitoring.Metrics.ElasticsearchRefs { + if ref.IsDefined() { + associations = append(associations, &BeatMonitoringAssociation{ + Beat: b, + ref: ref.WithDefaultNamespace(b.Namespace), + }) + } + } + for _, ref := range b.Spec.Monitoring.Logs.ElasticsearchRefs { if ref.IsDefined() { associations = append(associations, &BeatMonitoringAssociation{ Beat: b, @@ -438,11 +455,11 @@ func (beatmon *BeatMonitoringAssociation) AssociationID() string { // -- HasMonitoring methods func (b *Beat) GetMonitoringMetricsRefs() []commonv1.ObjectSelector { - return b.Spec.Monitoring.ElasticsearchRefs + return b.Spec.Monitoring.Metrics.ElasticsearchRefs } func (b *Beat) GetMonitoringLogsRefs() []commonv1.ObjectSelector { - return b.Spec.Monitoring.ElasticsearchRefs + return b.Spec.Monitoring.Logs.ElasticsearchRefs } func (b *Beat) MonitoringAssociation(esRef commonv1.ObjectSelector) commonv1.Association { diff --git a/pkg/apis/beat/v1beta1/validations.go b/pkg/apis/beat/v1beta1/validations.go index 517b22c64b..0264a8bec9 100644 --- a/pkg/apis/beat/v1beta1/validations.go +++ b/pkg/apis/beat/v1beta1/validations.go @@ -125,7 +125,7 @@ func checkAssociations(b *Beat) field.ErrorList { func checkMonitoring(b *Beat) field.ErrorList { var errs field.ErrorList - if !b.Spec.Monitoring.Enabled() { + if !monitoring.IsDefined(b) { return nil } if err := isStackSupportedVersion(b.Spec.Version); err != nil { @@ -140,6 +140,15 @@ func checkMonitoring(b *Beat) field.ErrorList { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), refs, validations.InvalidElasticsearchRefsMsg)) } + refs = b.GetMonitoringLogsRefs() + if !monitoring.AreEsRefsDefined(refs) { + errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), + refs, validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg)) + } + if len(refs) != 1 { + errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), + refs, validations.InvalidElasticsearchRefsMsg)) + } return errs } diff --git a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go index 6eaa455b20..2f8d5757a3 100644 --- a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go @@ -262,7 +262,7 @@ func (in *DeploymentSpec) DeepCopy() *DeploymentSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Monitoring) DeepCopyInto(out *Monitoring) { +func (in *LogsMonitoring) DeepCopyInto(out *LogsMonitoring) { *out = *in if in.ElasticsearchRefs != nil { in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs @@ -271,6 +271,43 @@ func (in *Monitoring) DeepCopyInto(out *Monitoring) { } } +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoring. +func (in *LogsMonitoring) DeepCopy() *LogsMonitoring { + if in == nil { + return nil + } + out := new(LogsMonitoring) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricsMonitoring) DeepCopyInto(out *MetricsMonitoring) { + *out = *in + if in.ElasticsearchRefs != nil { + in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs + *out = make([]v1.ObjectSelector, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoring. +func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { + if in == nil { + return nil + } + out := new(MetricsMonitoring) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Monitoring) DeepCopyInto(out *Monitoring) { + *out = *in + in.Metrics.DeepCopyInto(&out.Metrics) + in.Logs.DeepCopyInto(&out.Logs) +} + // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. func (in *Monitoring) DeepCopy() *Monitoring { if in == nil { diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index f5577db9c7..54013e024a 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -7,22 +7,17 @@ package common import ( "hash" "path" - "path/filepath" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" - v1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/certificates" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/labels" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/reconciler" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/validations" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" ) @@ -101,17 +96,6 @@ func buildBeatConfig( return nil, err } - // If monitoring is enabled, render the relevant section - if params.Beat.Spec.Monitoring.Enabled() { - monitoringConfig, err := buildMonitoringConfig(params) - if err != nil { - return nil, err - } - if err = cfg.MergeWith(monitoringConfig); err != nil { - return nil, err - } - } - // get user config from `config` or `configRef` userConfig, err := getUserConfig(params) if err != nil { @@ -126,64 +110,14 @@ func buildBeatConfig( return nil, err } - return cfg.Render() -} - -// buildMonitoringConfig builds the stack monitoring configuration for a Beats instance. -func buildMonitoringConfig(params DriverParams) (*settings.CanonicalConfig, error) { - if len(params.Beat.Spec.Monitoring.ElasticsearchRefs) == 0 { - return nil, errors.New("ElasticsearchRef must exist when stack monitoring is enabled") - } - - // only the first ElasticsearchRef is currently supported. - esRef := params.Beat.Spec.Monitoring.ElasticsearchRefs[0] - if !esRef.IsDefined() { - return nil, errors.New(validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg) - } - - var username, password, url string - associations := monitoring.GetMetricsAssociation(¶ms.Beat) - if len(associations) != 1 { - // should never happen because of the pre-creation validation - return nil, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") - } - assoc := associations[0] - - credentials, err := association.ElasticsearchAuthSettings(params.Client, assoc) - if err != nil { - return nil, err - } - - username, password = credentials.Username, credentials.Password - - var assocConf *v1.AssociationConf - assocConf, err = assoc.AssociationConf() - if err != nil { - return nil, err - } - - url = assocConf.GetURL() - - caDirPath := certificatesDir(assoc) - - config := MonitoringConfig{ - Enabled: true, - Elasticsearch: ElasticsearchConfig{ - Hosts: []string{url}, - Username: username, - Password: password, - }, - } - - if assocConf.GetCACertProvided() { - sslCAPath := filepath.Join(caDirPath, certificates.CAFileName) - config.Elasticsearch.SSL = SSLConfig{ - CertificateAuthorities: []string{sslCAPath}, - VerificationMode: "certificate", + // if metrics monitoring is enabled, then enable the metrics http endpoint for metricsbeat sidecar. + if monitoring.IsMetricsDefined(¶ms.Beat) { + if err = cfg.MergeWith(settings.MustCanonicalConfig(map[string]bool{"http.enabled": true})); err != nil { + return nil, err } } - return settings.NewCanonicalConfigFrom(map[string]interface{}{"monitoring": config}) + return cfg.Render() } // getUserConfig extracts the config either from the spec `config` field or from the Secret referenced by spec diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 29e927f2e2..49be97712b 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -6,7 +6,6 @@ package common import ( "context" - "reflect" "testing" "github.com/go-logr/logr" @@ -18,7 +17,6 @@ import ( beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" - esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/watches" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" @@ -50,52 +48,6 @@ func Test_buildBeatConfig(t *testing.T) { }, ) - clientWithMonitoringEnabled := k8s.NewFakeClient( - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "ns", - }, - Data: map[string][]byte{"elastic": []byte("123")}, - }, - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "external-user-secret", - Namespace: "ns", - }, - Data: map[string][]byte{ - "elastic-external": []byte("asdf"), - }, - }, - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "external-es-monitoring", - Namespace: "ns", - }, - Data: map[string][]byte{ - "url": []byte("https://external-es.external.com"), - "username": []byte("monitoring-user"), - "password": []byte("asdfasdf"), - "ca.crt": []byte("my_pem_encoded_cert"), - }, - }, - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testbeat-es-testes-ns-monitoring-ca", - Namespace: "ns", - }, - Data: map[string][]byte{ - "ca.crt": []byte("my_pem_encoded_cert"), - }, - }, - &esv1.Elasticsearch{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testes", - Namespace: "ns", - }, - }, - ) - managedCfg := settings.MustParseConfig([]byte("setup.kibana: true")) userCfg := &commonv1.Config{Data: map[string]interface{}{"user": "true"}} userCanonicalCfg := settings.MustCanonicalConfig(userCfg.Data) @@ -108,31 +60,6 @@ func Test_buildBeatConfig(t *testing.T) { password: "123" username: elastic `)) - monitoringYaml := settings.MustParseConfig([]byte(`monitoring: - enabled: true - elasticsearch: - hosts: - - "https://testes-es-internal-http.ns.svc:9200" - username: elastic - password: "123" - ssl: - certificate_authorities: - - "/mnt/elastic-internal/beat-monitoring-certs/ca.crt" - verification_mode: "certificate" -`)) - externalMonitoringYaml := settings.MustParseConfig([]byte(`monitoring: - enabled: true - elasticsearch: - hosts: - - "https://external-es.external.com" - username: "monitoring-user" - password: asdfasdf - ssl: - certificate_authorities: - - "/mnt/elastic-internal/beat-monitoring-certs/ca.crt" - verification_mode: "certificate" -`)) - withAssoc := beatv1beta1.Beat{ ObjectMeta: metav1.ObjectMeta{ Namespace: "ns", @@ -187,68 +114,6 @@ func Test_buildBeatConfig(t *testing.T) { }, want: userCanonicalCfg, }, - { - name: "no association, user config, with monitoring enabled", - client: clientWithMonitoringEnabled, - beat: func() beatv1beta1.Beat { - b := beatv1beta1.Beat{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testbeat", - Namespace: "ns", - }, - Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - Monitoring: beatv1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "testes", - Namespace: "ns", - }, - }, - }, - }} - b.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ - AuthSecretName: "secret", - AuthSecretKey: "elastic", - CACertProvided: true, - CASecretName: "testbeat-es-testes-ns-monitoring-ca", - URL: "https://testes-es-internal-http.ns.svc:9200", - }) - return b - }, - want: merge(userCanonicalCfg, monitoringYaml), - }, - { - name: "no association, user config, with monitoring enabled, external es cluster", - client: clientWithMonitoringEnabled, - beat: func() beatv1beta1.Beat { - b := beatv1beta1.Beat{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testbeat", - Namespace: "ns", - }, - Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - Monitoring: beatv1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - SecretName: "external-es-monitoring", - Namespace: "ns", - }, - }, - }, - }} - b.MonitoringAssociation(commonv1.ObjectSelector{SecretName: "external-es-monitoring", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ - AuthSecretName: "external-es-monitoring", - AuthSecretKey: "password", - CASecretName: "testbeat-es-testes-ns-monitoring-ca", - CACertProvided: true, - URL: "https://external-es.external.com", - }) - return b - }, - want: merge(userCanonicalCfg, externalMonitoringYaml), - }, { name: "no association, managed config", beat: func() beatv1beta1.Beat { return beatv1beta1.Beat{} }, @@ -543,155 +408,3 @@ func Test_getUserConfig(t *testing.T) { }) } } - -func Test_buildMonitoringConfig(t *testing.T) { - k8sClient := k8s.NewFakeClient() - k8sClientWithValidMonitoring := k8s.NewFakeClient( - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "beat-secret", - Namespace: "test", - }, - Data: map[string][]byte{"elastic": []byte("123")}, - }, - ) - monitoringYaml := settings.MustParseConfig([]byte(`monitoring: - enabled: true - elasticsearch: - hosts: - - "https://testes-es-internal-http.ns.svc:9200" - username: elastic - password: "123" - ssl: - certificate_authorities: - - "/mnt/elastic-internal/beat-monitoring-certs/ca.crt" - verification_mode: "certificate" -`)) - tests := []struct { - name string - params func() DriverParams - want *settings.CanonicalConfig - wantErr bool - expectedErrString string - }{ - { - name: "beat without monitoring.ElasticsearchRefs returns error", - params: func() DriverParams { - return DriverParams{ - Beat: beatv1beta1.Beat{ - Spec: beatv1beta1.BeatSpec{ - Monitoring: beatv1beta1.Monitoring{}, - }, - }, - } - }, - want: nil, - wantErr: true, - expectedErrString: "ElasticsearchRef must exist when stack monitoring is enabled", - }, - { - name: "beat with monitoring.ElasticsearchRef that isn't properly defined returns error", - params: func() DriverParams { - return DriverParams{ - Beat: beatv1beta1.Beat{ - Spec: beatv1beta1.BeatSpec{ - Monitoring: beatv1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "", - SecretName: "", - }, - }, - }, - }, - }, - } - }, - want: nil, - wantErr: true, - expectedErrString: "Beats must be associated to an Elasticsearch cluster through elasticsearchRef in order to enable monitoring metrics features", - }, - { - name: "beat with monitoring.ElasticsearchRef with invalid association config (secret not found) returns error", - params: func() DriverParams { - beat := beatv1beta1.Beat{ - Spec: beatv1beta1.BeatSpec{ - Monitoring: beatv1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "fake", - SecretName: "fake", - }, - }, - }, - }, - } - beat.MonitoringAssociation(commonv1.ObjectSelector{Name: "fake", SecretName: "fake"}).SetAssociationConf(&commonv1.AssociationConf{ - AuthSecretName: "does-not-exist", - AuthSecretKey: "invalid", - }) - return DriverParams{ - Beat: beat, - Client: k8sClient, - } - }, - want: nil, - wantErr: true, - expectedErrString: `secrets "does-not-exist" not found`, - }, - { - name: "beat with valid monitoring association configuration succeeds", - params: func() DriverParams { - beat := beatv1beta1.Beat{ - ObjectMeta: metav1.ObjectMeta{ - Name: "beat", - Namespace: "test", - }, - Spec: beatv1beta1.BeatSpec{ - Monitoring: beatv1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "fake", - SecretName: "fake", - }, - }, - }, - }, - } - beat.MonitoringAssociation(commonv1.ObjectSelector{Name: "fake", SecretName: "fake"}).SetAssociationConf(&commonv1.AssociationConf{ - AuthSecretName: "beat-secret", - AuthSecretKey: "elastic", - CACertProvided: true, - URL: "https://testes-es-internal-http.ns.svc:9200", - }) - return DriverParams{ - Beat: beat, - Client: k8sClientWithValidMonitoring, - } - }, - want: monitoringYaml, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := buildMonitoringConfig(tt.params()) - if (err != nil) != tt.wantErr { - t.Errorf("buildMonitoringConfig() error = %v, wantErr %v", err, tt.wantErr) - return - } - if tt.wantErr && (tt.expectedErrString != err.Error()) { - t.Errorf("buildMonitoringConfig() = %v, want %v", err.Error(), tt.expectedErrString) - return - } - if len(tt.want.Diff(got, nil)) != 0 { - wantBytes, _ := tt.want.Render() - gotBytes, _ := got.Render() - t.Errorf("buildMonitoringConfig() got unexpected differences: %s", cmp.Diff(string(wantBytes), string(gotBytes))) - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("buildMonitoringConfig() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/controller/beat/common/monitoring.go b/pkg/controller/beat/common/monitoring.go deleted file mode 100644 index 8691cf958b..0000000000 --- a/pkg/controller/beat/common/monitoring.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -// or more contributor license agreements. Licensed under the Elastic License 2.0; -// you may not use this file except in compliance with the Elastic License 2.0. - -package common - -// MonitoringConfig contains the stack monitoring configuration for Beats. -type MonitoringConfig struct { - Enabled bool `json:"enabled,omitempty"` - Elasticsearch ElasticsearchConfig `json:"elasticsearch"` -} - -// ElasticsearchConfig contains the configuration for connecting to Elasticsearch. -type ElasticsearchConfig struct { - // Hosts are the Elasticsearch host urls to use. - Hosts []string `json:"hosts"` - // Username is the Elasticsearch username. - Username string `json:"username"` - // Password is the Elasticsearch password. - Password string `json:"password"` - // SSL is the ssl configuration for communicating with Elasticsearch. - SSL SSLConfig `json:"ssl,omitempty"` -} - -/// SSLConfig contains the SSL configuration for Beat stack monitoring. -type SSLConfig struct { - // CertificateAuthorities contains a slice of filenames that contain PEM formatted certificate authorities. - CertificateAuthorities []string `config:"certificate_authorities" yaml:"certificate_authorities"` - // VerificationMode contains the verification mode for server certificates. Valid options: [full, strict, certificate, none] - VerificationMode string `config:"verification_mode" yaml:"verification_mode"` -} diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index 5badaba01f..be8688a11f 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -12,9 +12,12 @@ import ( "k8s.io/apimachinery/pkg/api/resource" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + beat_stackmon "github.com/elastic/cloud-on-k8s/v2/pkg/controller/beat/common/stackmon" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/container" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/defaults" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/keystore" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/reconciler" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/volume" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/maps" ) @@ -118,6 +121,7 @@ func buildPodTemplate( volumes := make([]corev1.Volume, 0, len(vols)) volumeMounts := make([]corev1.VolumeMount, 0, len(vols)) var initContainers []corev1.Container + var sideCars []corev1.Container for _, v := range vols { volumes = append(volumes, v.Volume()) @@ -130,6 +134,36 @@ func buildPodTemplate( initContainers = append(initContainers, keystoreResources.InitContainer) } + if monitoring.IsLogsDefined(¶ms.Beat) { + sideCar, err := beat_stackmon.Filebeat(params.Client, ¶ms.Beat, params.Beat.Spec.Version) + if err != nil { + return podTemplate, err + } + // name of container must be adjusted from default, or it will not be added to + // pod template builder because of duplicative names. + sideCar.Container.Name = "logs-monitoring-sidecar" + if _, err := reconciler.ReconcileSecret(params.Context, params.Client, sideCar.ConfigSecret, ¶ms.Beat); err != nil { + return podTemplate, err + } + volumes = append(volumes, sideCar.Volumes...) + sideCars = append(sideCars, sideCar.Container) + } + + if monitoring.IsMetricsDefined(¶ms.Beat) { + sideCar, err := beat_stackmon.MetricBeat(params.Client, ¶ms.Beat, params.Beat.Spec.Version) + if err != nil { + return podTemplate, err + } + // name of container must be adjusted from default, or it will not be added to + // pod template builder because of duplicative names. + sideCar.Container.Name = "metrics-monitoring-sidecar" + if _, err := reconciler.ReconcileSecret(params.Context, params.Client, sideCar.ConfigSecret, ¶ms.Beat); err != nil { + return podTemplate, err + } + volumes = append(volumes, sideCar.Volumes...) + sideCars = append(sideCars, sideCar.Container) + } + labels := maps.Merge(NewLabels(params.Beat), map[string]string{ VersionLabelName: spec.Version}) @@ -146,7 +180,8 @@ func buildPodTemplate( WithVolumes(volumes...). WithVolumeMounts(volumeMounts...). WithInitContainers(initContainers...). - WithInitContainerDefaults() + WithInitContainerDefaults(). + WithContainers(sideCars...) return builder.PodTemplate, nil } diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 4a63115868..7b8557c364 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -20,6 +20,7 @@ import ( commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/container" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/watches" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" ) @@ -71,10 +72,12 @@ func Test_buildPodTemplate(t *testing.T) { Version: "7.15.0", Config: userCfg, Monitoring: v1beta1.Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "testes", - Namespace: "ns", + Metrics: v1beta1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "testes", + Namespace: "ns", + }, }, }, }, @@ -256,7 +259,7 @@ func Test_buildPodTemplate(t *testing.T) { t.Errorf("Annotations do not match: %s", cmp.Diff(tt.want.annotations, podTemplateSpec.Annotations)) return } - if tt.args.params.Beat.Spec.Monitoring.Enabled() { + if monitoring.IsDefined(&tt.args.params.Beat) { assertMonitoring(t, podTemplateSpec.Spec.Volumes) } }) diff --git a/pkg/controller/beat/common/stackmon/filebeat.yml b/pkg/controller/beat/common/stackmon/filebeat.yml new file mode 100644 index 0000000000..bab23be96f --- /dev/null +++ b/pkg/controller/beat/common/stackmon/filebeat.yml @@ -0,0 +1,8 @@ +filebeat.inputs: +- type: filestream + id: filebeatlogs + paths: + - /var/log/*.log + - /usr/share/filebeat/data/registry/filebeat/*.json + +# Elasticsearch output configuration is generated and added here \ No newline at end of file diff --git a/pkg/controller/beat/common/stackmon/metricbeat.yml b/pkg/controller/beat/common/stackmon/metricbeat.yml new file mode 100644 index 0000000000..d0d0bd5fd5 --- /dev/null +++ b/pkg/controller/beat/common/stackmon/metricbeat.yml @@ -0,0 +1,9 @@ +metricbeat.modules: +- module: beat + metricsets: + - stats + - state + period: 10s + hosts: ["http://localhost:5066"] + +# Elasticsearch output configuration is generated and added here \ No newline at end of file diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go new file mode 100644 index 0000000000..9c7f3ea7ea --- /dev/null +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -0,0 +1,67 @@ +package stackmon + +import ( + _ "embed" // for the beats config files + "errors" + + commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" + common_name "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/name" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" + "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" +) + +var ( + // filebeatConfig is a static configuration for Filebeat to collect Beats logs + //go:embed filebeat.yml + filebeatConfig string + + // metricbeatConfigTemplate is a configuration template for Metricbeat to collect monitoring data from Beats resources + //go:embed metricbeat.yml + metricbeatConfigTemplate string +) + +func Filebeat(client k8s.Client, resource monitoring.HasMonitoring, version string) (stackmon.BeatSidecar, error) { + filebeat, err := stackmon.NewFileBeatSidecar(client, resource, version, filebeatConfig, nil) + if err != nil { + return stackmon.BeatSidecar{}, err + } + + return filebeat, nil +} + +func MetricBeat(client k8s.Client, mon monitoring.HasMonitoring, version string) (stackmon.BeatSidecar, error) { + var username, password string + var sideCar stackmon.BeatSidecar + var err error + associations := monitoring.GetMetricsAssociation(mon) + if len(associations) != 1 { + // should never happen because of the pre-creation validation + return sideCar, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") + } + assoc := associations[0] + + credentials, err := association.ElasticsearchAuthSettings(client, assoc) + if err != nil { + return sideCar, err + } + + username, password = credentials.Username, credentials.Password + sideCar, err = stackmon.NewMetricBeatSidecar( + client, + commonv1.BeatMonitoringAssociationType, + mon, + version, + metricbeatConfigTemplate, + common_name.NewNamer("beat"), + "http://localhost:5066", + username, + password, + false, + ) + if err != nil { + return sideCar, err + } + return sideCar, nil +} From 4ae5d27c99e51a8c699238d1da9e83f0e393cc20 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 2 Aug 2022 16:04:03 -0500 Subject: [PATCH 22/64] revert config/recipes changes --- .../recipes/beats/filebeat_autodiscover.yaml | 64 ++++++++----------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/config/recipes/beats/filebeat_autodiscover.yaml b/config/recipes/beats/filebeat_autodiscover.yaml index 64257bb2d8..234f671ab5 100644 --- a/config/recipes/beats/filebeat_autodiscover.yaml +++ b/config/recipes/beats/filebeat_autodiscover.yaml @@ -6,16 +6,9 @@ spec: type: filebeat version: 8.3.1 elasticsearchRef: - name: source + name: elasticsearch kibanaRef: - name: source-kibana - monitoring: - logs: - elasticsearchRefs: - - name: source - metrics: - elasticsearchRefs: - - name: source + name: kibana config: filebeat: autodiscover: @@ -41,13 +34,6 @@ spec: hostNetwork: true # Allows to provide richer host metadata containers: - name: filebeat - resources: - limits: - cpu: 500m - memory: 500Mi - requests: - cpu: 500m - memory: 200M securityContext: runAsUser: 0 # If using Red Hat OpenShift uncomment this: @@ -108,26 +94,26 @@ roleRef: kind: ClusterRole name: filebeat apiGroup: rbac.authorization.k8s.io -# --- -# apiVersion: elasticsearch.k8s.elastic.co/v1 -# kind: Elasticsearch -# metadata: -# name: elasticsearch -# spec: -# version: 8.3.1 -# nodeSets: -# - name: default -# count: 3 -# config: -# node.store.allow_mmap: false -# --- -# apiVersion: kibana.k8s.elastic.co/v1 -# kind: Kibana -# metadata: -# name: kibana -# spec: -# version: 8.3.1 -# count: 1 -# elasticsearchRef: -# name: elasticsearch -# ... +--- +apiVersion: elasticsearch.k8s.elastic.co/v1 +kind: Elasticsearch +metadata: + name: elasticsearch +spec: + version: 8.3.1 + nodeSets: + - name: default + count: 3 + config: + node.store.allow_mmap: false +--- +apiVersion: kibana.k8s.elastic.co/v1 +kind: Kibana +metadata: + name: kibana +spec: + version: 8.3.1 + count: 1 + elasticsearchRef: + name: elasticsearch +... From 06a3396aa427a9b92d292eb42633d7572e3c1a5a Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 3 Aug 2022 10:00:18 -0500 Subject: [PATCH 23/64] Fix early return in beats validation so that invalid monitoring refs return errors. Fix naming issue in config_test.go. Add test to ensure http.enabled is turned on when metrics monitoring is enabled. Add tests for monitoring sidecars in pod_test.go. --- pkg/apis/beat/v1beta1/validations.go | 12 ++++--- pkg/apis/beat/v1beta1/validations_test.go | 38 +++++++++++++---------- pkg/controller/beat/common/config_test.go | 29 ++++++++++++++--- pkg/controller/beat/common/pod_test.go | 36 +++++++++++++++++---- test/e2e/test/beat/builder.go | 12 ++++--- 5 files changed, 92 insertions(+), 35 deletions(-) diff --git a/pkg/apis/beat/v1beta1/validations.go b/pkg/apis/beat/v1beta1/validations.go index 0264a8bec9..d2f4a1b82a 100644 --- a/pkg/apis/beat/v1beta1/validations.go +++ b/pkg/apis/beat/v1beta1/validations.go @@ -125,27 +125,29 @@ func checkAssociations(b *Beat) field.ErrorList { func checkMonitoring(b *Beat) field.ErrorList { var errs field.ErrorList - if !monitoring.IsDefined(b) { + if len(b.GetMonitoringMetricsRefs()) == 0 && len(b.GetMonitoringLogsRefs()) == 0 { return nil } if err := isStackSupportedVersion(b.Spec.Version); err != nil { errs = append(errs, field.Invalid(field.NewPath("spec").Child("version"), b.Spec.Version, err.Error())) } refs := b.GetMonitoringMetricsRefs() - if !monitoring.AreEsRefsDefined(refs) { + refsDefined := monitoring.AreEsRefsDefined(refs) + if len(refs) > 0 && !refsDefined { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), refs, validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg)) } - if len(refs) != 1 { + if refsDefined && len(refs) != 1 { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), refs, validations.InvalidElasticsearchRefsMsg)) } refs = b.GetMonitoringLogsRefs() - if !monitoring.AreEsRefsDefined(refs) { + refsDefined = monitoring.AreEsRefsDefined(refs) + if len(refs) > 0 && !refsDefined { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), refs, validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg)) } - if len(refs) != 1 { + if refsDefined && len(refs) != 1 { errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), refs, validations.InvalidElasticsearchRefsMsg)) } diff --git a/pkg/apis/beat/v1beta1/validations_test.go b/pkg/apis/beat/v1beta1/validations_test.go index dc22839945..bca0f1d31b 100644 --- a/pkg/apis/beat/v1beta1/validations_test.go +++ b/pkg/apis/beat/v1beta1/validations_test.go @@ -243,10 +243,12 @@ func Test_checkMonitoring(t *testing.T) { Version: "7.1.0", DaemonSet: &DaemonSetSpec{}, Monitoring: Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "elasticsearch", - Namespace: "test", + Metrics: MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "elasticsearch", + Namespace: "test", + }, }, }, }, @@ -266,10 +268,12 @@ func Test_checkMonitoring(t *testing.T) { Version: "8.2.3", DaemonSet: &DaemonSetSpec{}, Monitoring: Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - // missing name - Namespace: "test", + Metrics: MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + // missing name + Namespace: "test", + }, }, }, }, @@ -294,14 +298,16 @@ func Test_checkMonitoring(t *testing.T) { Version: "8.2.3", DaemonSet: &DaemonSetSpec{}, Monitoring: Monitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "es1", - Namespace: "test", - }, - { - Name: "es2", - Namespace: "test", + Metrics: MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "es1", + Namespace: "test", + }, + { + Name: "es2", + Namespace: "test", + }, }, }, }, diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 49be97712b..e416b14cde 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -87,8 +87,8 @@ func Test_buildBeatConfig(t *testing.T) { require.NoError(t, err) assocConf.CACertProvided = true - withAssocWithCAWithonfig := *withAssocWithCA.DeepCopy() - withAssocWithCAWithonfig.Spec.Config = userCfg + withAssocWithCAWithconfig := *withAssocWithCA.DeepCopy() + withAssocWithCAWithconfig.Spec.Config = userCfg withAssocWithConfig := *withAssoc.DeepCopy() withAssocWithConfig.Spec.Config = userCfg @@ -167,7 +167,7 @@ func Test_buildBeatConfig(t *testing.T) { { name: "association with ca, user config", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCAWithonfig }, + beat: func() beatv1beta1.Beat { return withAssocWithCAWithconfig }, want: merge(userCanonicalCfg, outputYaml, outputCAYaml), }, { @@ -180,10 +180,31 @@ func Test_buildBeatConfig(t *testing.T) { { name: "association with ca, user and managed configs", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCAWithonfig }, + beat: func() beatv1beta1.Beat { return withAssocWithCAWithconfig }, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg, outputYaml, outputCAYaml), }, + { + name: "no association, user config, with metrics monitoring enabled", + beat: func() beatv1beta1.Beat { + return beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + Monitoring: beatv1beta1.Monitoring{ + Metrics: beatv1beta1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "testesref", + Namespace: "test", + }, + }, + }, + }, + }, + } + }, + want: merge(userCanonicalCfg, settings.MustCanonicalConfig(map[string]bool{"http.enabled": true})), + }, } { t.Run(tt.name, func(t *testing.T) { gotYaml, gotErr := buildBeatConfig(DriverParams{ diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 7b8557c364..c4aa6d9a72 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -80,6 +80,14 @@ func Test_buildPodTemplate(t *testing.T) { }, }, }, + Logs: v1beta1.LogsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "testes", + Namespace: "ns", + }, + }, + }, }, }} beatWithMonitoring.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ @@ -105,7 +113,7 @@ func Test_buildPodTemplate(t *testing.T) { want want }{ { - name: "deployment with monitoring enabled should have CA volume", + name: "deployment with monitoring enabled should have CA volume, and sidecars", args: args{ initialHash: newHash("foobar"), // SHA224 for foobar is de76c3e567fca9d246f5f8d3b2e704a38c3c5e258988ab525f941db8 params: DriverParams{ @@ -260,7 +268,7 @@ func Test_buildPodTemplate(t *testing.T) { return } if monitoring.IsDefined(&tt.args.params.Beat) { - assertMonitoring(t, podTemplateSpec.Spec.Volumes) + assertMonitoring(t, tt.args.params.Beat, podTemplateSpec) } }) } @@ -298,19 +306,35 @@ func assertConfiguration(t *testing.T, pod corev1.PodTemplateSpec) { assert.Equal(t, expectedConfigVolumeMode, *configVolume.DefaultMode) } -func assertMonitoring(t *testing.T, volumes []corev1.Volume) { +func assertMonitoring(t *testing.T, beat v1beta1.Beat, pod corev1.PodTemplateSpec) { t.Helper() var monitoringVolume *corev1.Volume // Validate that the Pod's volumes contain a Secret as a monitoring CA volume. - for i := range volumes { - if volumes[i].Name == "beat-monitoring-certs" { - monitoringVolume = &volumes[i] + for _, volume := range pod.Spec.Volumes { + if volume.Name == "beat-monitoring-certs" { + monitoringVolume = &volume break } } require.NotNil(t, monitoringVolume) require.NotNil(t, monitoringVolume.Secret) assert.Equal(t, monitoringVolume.Secret.SecretName, "testbeat-es-testes-ns-monitoring-ca") + + if monitoring.IsMetricsDefined(&beat) { + assert.True(t, containersContains(pod.Spec.Containers, "metrics-monitoring-sidecar")) + } + if monitoring.IsLogsDefined(&beat) { + assert.True(t, containersContains(pod.Spec.Containers, "logs-monitoring-sidecar")) + } +} + +func containersContains(containers []corev1.Container, name string) bool { + for _, container := range containers { + if container.Name == name { + return true + } + } + return false } // newHash creates a hash with some initial data. diff --git a/test/e2e/test/beat/builder.go b/test/e2e/test/beat/builder.go index 1ed0742a68..f4405187c7 100644 --- a/test/e2e/test/beat/builder.go +++ b/test/e2e/test/beat/builder.go @@ -338,7 +338,7 @@ func ApplyYamls(t *testing.T, b Builder, configYaml, podTemplateYaml string) Bui } func (b Builder) WithMonitoring(esRef commonv1.ObjectSelector) Builder { - b.Beat.Spec.Monitoring.ElasticsearchRefs = []commonv1.ObjectSelector{esRef} + b.Beat.Spec.Monitoring.Metrics.ElasticsearchRefs = []commonv1.ObjectSelector{esRef} return b } @@ -359,10 +359,10 @@ func (b Builder) Namespace() string { } func (b Builder) GetMetricsCluster() *types.NamespacedName { - if len(b.Beat.Spec.Monitoring.ElasticsearchRefs) == 0 { + if len(b.Beat.Spec.Monitoring.Metrics.ElasticsearchRefs) == 0 { return nil } - metricsCluster := b.Beat.Spec.Monitoring.ElasticsearchRefs[0].NamespacedName() + metricsCluster := b.Beat.Spec.Monitoring.Metrics.ElasticsearchRefs[0].NamespacedName() return &metricsCluster } @@ -370,5 +370,9 @@ func (b Builder) GetMetricsCluster() *types.NamespacedName { // different that both Elasticsearch, and Kibana stack monitoring, as it uses internal // beat collectors to send only metrics data, not logs data. func (b Builder) GetLogsCluster() *types.NamespacedName { - return nil + if len(b.Beat.Spec.Monitoring.Metrics.ElasticsearchRefs) == 0 { + return nil + } + metricsCluster := b.Beat.Spec.Monitoring.Logs.ElasticsearchRefs[0].NamespacedName() + return &metricsCluster } From a175029d315b2e53e21cdbfa3328de654db544cf Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 3 Aug 2022 11:08:44 -0500 Subject: [PATCH 24/64] Ensure that beats http.port setting finds it's way all the way to the metricsbeat sidecar, if set. --- pkg/controller/beat/common/pod_test.go | 42 +++++++++++++++++-- .../beat/common/stackmon/metricbeat.yml | 9 ---- .../beat/common/stackmon/stackmon.go | 39 ++++++++++++++--- 3 files changed, 72 insertions(+), 18 deletions(-) delete mode 100644 pkg/controller/beat/common/stackmon/metricbeat.yml diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index c4aa6d9a72..df648fcd54 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -5,16 +5,21 @@ package common import ( + "context" + "fmt" "hash" "hash/fnv" + "net/url" "reflect" "testing" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" @@ -62,7 +67,7 @@ func Test_buildPodTemplate(t *testing.T) { }, }, ) - userCfg := &commonv1.Config{Data: map[string]interface{}{"user": "true"}} + httpPortCfg := &commonv1.Config{Data: map[string]interface{}{"http.port": 3033}} beatWithMonitoring := v1beta1.Beat{ ObjectMeta: metav1.ObjectMeta{ Name: "beat-name", @@ -70,7 +75,7 @@ func Test_buildPodTemplate(t *testing.T) { }, Spec: v1beta1.BeatSpec{ Version: "7.15.0", - Config: userCfg, + Config: httpPortCfg, Monitoring: v1beta1.Monitoring{ Metrics: v1beta1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ @@ -268,7 +273,7 @@ func Test_buildPodTemplate(t *testing.T) { return } if monitoring.IsDefined(&tt.args.params.Beat) { - assertMonitoring(t, tt.args.params.Beat, podTemplateSpec) + assertMonitoring(t, tt.args.params.Client, tt.args.params.Beat, podTemplateSpec) } }) } @@ -306,7 +311,7 @@ func assertConfiguration(t *testing.T, pod corev1.PodTemplateSpec) { assert.Equal(t, expectedConfigVolumeMode, *configVolume.DefaultMode) } -func assertMonitoring(t *testing.T, beat v1beta1.Beat, pod corev1.PodTemplateSpec) { +func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod corev1.PodTemplateSpec) { t.Helper() var monitoringVolume *corev1.Volume // Validate that the Pod's volumes contain a Secret as a monitoring CA volume. @@ -321,13 +326,42 @@ func assertMonitoring(t *testing.T, beat v1beta1.Beat, pod corev1.PodTemplateSpe assert.Equal(t, monitoringVolume.Secret.SecretName, "testbeat-es-testes-ns-monitoring-ca") if monitoring.IsMetricsDefined(&beat) { + // ensure the metricsbeat sidecar exists assert.True(t, containersContains(pod.Spec.Containers, "metrics-monitoring-sidecar")) + + // ensure that the beat's metrics port can be set, and used in the sidecar + var secret corev1.Secret + assert.NoError(t, client.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("%s-beat-monitoring-metricbeat-config", beat.Name), Namespace: beat.Namespace}, &secret)) + data, ok := secret.Data["metricbeat.yml"] + assert.True(t, ok) + + var cfg metricsbeatConfig + assert.NoError(t, yaml.Unmarshal(data, &cfg)) + u, err := url.Parse(cfg.MetricBeat.Modules[0].Hosts[0]) + require.NoError(t, err) + assert.Equal(t, "3033", u.Port()) } if monitoring.IsLogsDefined(&beat) { assert.True(t, containersContains(pod.Spec.Containers, "logs-monitoring-sidecar")) } } +// metricsbeatConfig represents the metricsbeat configuration for testing purposes. +// +// example: +// +// metricbeat: +// modules: +// - hosts: +// - http://example.com:3033 +type metricsbeatConfig struct { + MetricBeat struct { + Modules []struct { + Hosts []string + } + } +} + func containersContains(containers []corev1.Container, name string) bool { for _, container := range containers { if container.Name == name { diff --git a/pkg/controller/beat/common/stackmon/metricbeat.yml b/pkg/controller/beat/common/stackmon/metricbeat.yml deleted file mode 100644 index d0d0bd5fd5..0000000000 --- a/pkg/controller/beat/common/stackmon/metricbeat.yml +++ /dev/null @@ -1,9 +0,0 @@ -metricbeat.modules: -- module: beat - metricsets: - - stats - - state - period: 10s - hosts: ["http://localhost:5066"] - -# Elasticsearch output configuration is generated and added here \ No newline at end of file diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index 9c7f3ea7ea..4fb8be9bbb 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -3,10 +3,13 @@ package stackmon import ( _ "embed" // for the beats config files "errors" + "fmt" + "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" common_name "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/name" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" @@ -18,7 +21,7 @@ var ( filebeatConfig string // metricbeatConfigTemplate is a configuration template for Metricbeat to collect monitoring data from Beats resources - //go:embed metricbeat.yml + //go:embed metricbeat.tpl.yml metricbeatConfigTemplate string ) @@ -31,11 +34,11 @@ func Filebeat(client k8s.Client, resource monitoring.HasMonitoring, version stri return filebeat, nil } -func MetricBeat(client k8s.Client, mon monitoring.HasMonitoring, version string) (stackmon.BeatSidecar, error) { +func MetricBeat(client k8s.Client, beat *v1beta1.Beat, version string) (stackmon.BeatSidecar, error) { var username, password string var sideCar stackmon.BeatSidecar var err error - associations := monitoring.GetMetricsAssociation(mon) + associations := monitoring.GetMetricsAssociation(beat) if len(associations) != 1 { // should never happen because of the pre-creation validation return sideCar, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") @@ -48,14 +51,36 @@ func MetricBeat(client k8s.Client, mon monitoring.HasMonitoring, version string) } username, password = credentials.Username, credentials.Password + + config, err := settings.NewCanonicalConfigFrom(beat.Spec.Config.Data) + if err != nil { + return sideCar, err + } + + // Default metricbeat monitoring port + var httpPort uint64 = 5066 + var p httpPortSetting + if err := config.Unpack(&p); err != nil { + return sideCar, err + } + + // if http.port is set in beats configuration, then use the port. + if p.PortData != nil { + portData, ok := p.PortData.(uint64) + if !ok { + return sideCar, fmt.Errorf("http.port must be an int") + } + httpPort = portData + } + sideCar, err = stackmon.NewMetricBeatSidecar( client, commonv1.BeatMonitoringAssociationType, - mon, + beat, version, metricbeatConfigTemplate, common_name.NewNamer("beat"), - "http://localhost:5066", + fmt.Sprintf("http://localhost:%d", httpPort), username, password, false, @@ -65,3 +90,7 @@ func MetricBeat(client k8s.Client, mon monitoring.HasMonitoring, version string) } return sideCar, nil } + +type httpPortSetting struct { + PortData interface{} `config:"http.port"` +} From ccf1323553ad47498ce5138709319aca67d76d45 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 3 Aug 2022 12:32:56 -0500 Subject: [PATCH 25/64] Add missing metricbeat template yaml file. --- pkg/controller/beat/common/stackmon/metricbeat.tpl.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 pkg/controller/beat/common/stackmon/metricbeat.tpl.yml diff --git a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml new file mode 100644 index 0000000000..a02d8fd8f9 --- /dev/null +++ b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml @@ -0,0 +1,9 @@ +metricbeat.modules: +- module: beat + metricsets: + - stats + - state + period: 10s + hosts: ["{{ .URL }}"] + +# Elasticsearch output configuration is generated and added here \ No newline at end of file From b9a0c6ae74ea5e4928244d4c9179b0c78be8e8e4 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 3 Aug 2022 13:35:47 -0500 Subject: [PATCH 26/64] Adding missing header to new file. Avoid implicit memory aliasing in test loop --- pkg/controller/beat/common/pod_test.go | 6 +++--- pkg/controller/beat/common/stackmon/stackmon.go | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index df648fcd54..ba9920baa1 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -315,9 +315,9 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co t.Helper() var monitoringVolume *corev1.Volume // Validate that the Pod's volumes contain a Secret as a monitoring CA volume. - for _, volume := range pod.Spec.Volumes { - if volume.Name == "beat-monitoring-certs" { - monitoringVolume = &volume + for i := range pod.Spec.Volumes { + if pod.Spec.Volumes[i].Name == "beat-monitoring-certs" { + monitoringVolume = &pod.Spec.Volumes[i] break } } diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index 4fb8be9bbb..8dc9eec810 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -1,3 +1,7 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + package stackmon import ( From f21ff9c4e5d6dcd0fc342c067a199879aecb36ec Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 3 Aug 2022 21:07:22 -0500 Subject: [PATCH 27/64] running make generate crds --- config/crds/v1/all-crds.yaml | 9 ++++----- config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml | 9 ++++----- .../charts/eck-operator-crds/templates/all-crds.yaml | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 5839ba5fb6..bb4e2c55ab 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2352,11 +2352,10 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship monitoring - data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - Internal Beat collectors are configured and send metrics data to - one Elasticsearch monitoring cluster running in the same Kubernetes - cluster. + description: Monitoring enables you to collect and ship monitoring, + and logs data of this Beat. Metricbeat and/or Filebeat sidecars + are configured and send metrics data to one Elasticsearch monitoring + cluster running in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index f46eb12f68..22b5a45429 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15341,11 +15341,10 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship monitoring - data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - Internal Beat collectors are configured and send metrics data to - one Elasticsearch monitoring cluster running in the same Kubernetes - cluster. + description: Monitoring enables you to collect and ship monitoring, + and logs data of this Beat. Metricbeat and/or Filebeat sidecars + are configured and send metrics data to one Elasticsearch monitoring + cluster running in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 77bdc7bda6..9b03affeaf 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2370,11 +2370,10 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship monitoring - data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html - Internal Beat collectors are configured and send metrics data to - one Elasticsearch monitoring cluster running in the same Kubernetes - cluster. + description: Monitoring enables you to collect and ship monitoring, + and logs data of this Beat. Metricbeat and/or Filebeat sidecars + are configured and send metrics data to one Elasticsearch monitoring + cluster running in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which From 7dc4bc9ed33eacdd69171d0849d52979a0a1ec77 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 3 Aug 2022 21:26:46 -0500 Subject: [PATCH 28/64] Updating api docs --- docs/reference/api-docs.asciidoc | 42 +++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 9ab6f8dd6d..c0ebdc1f86 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -315,7 +315,7 @@ BeatSpec defines the desired state of a Beat. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`daemonSet`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-daemonsetspec[$$DaemonSetSpec$$]__ | DaemonSet specifies the Beat should be deployed as a DaemonSet, and allows providing its spec. Cannot be used along with `deployment`. If both are absent a default for the Type is used. | *`deployment`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-deploymentspec[$$DeploymentSpec$$]__ | Deployment specifies the Beat should be deployed as a Deployment, and allows providing its spec. Cannot be used along with `daemonSet`. If both are absent a default for the Type is used. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship monitoring data of this Beat. See https://www.elastic.co/guide/en/beats/filebeat/current/monitoring.html Internal Beat collectors are configured and send metrics data to one Elasticsearch monitoring cluster running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship monitoring, and logs data of this Beat. Metricbeat and/or Filebeat sidecars are configured and send metrics data to one Elasticsearch monitoring cluster running in the same Kubernetes cluster. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying DaemonSet or Deployment. |=== @@ -357,6 +357,40 @@ BeatSpec defines the desired state of a Beat. |=== +[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-logsmonitoring"] +=== LogsMonitoring + + + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +|=== + + +[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-metricsmonitoring"] +=== MetricsMonitoring + + + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +|=== + + [id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring"] === Monitoring @@ -370,7 +404,8 @@ BeatSpec defines the desired state of a Beat. [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which receive monitoring data from this Beats resource. +| *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which receive log data from this Beats resource. |=== @@ -501,12 +536,13 @@ ObjectSelector defines a reference to a Kubernetes object which can be an Elasti - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-enterprisesearch-v1-enterprisesearchspec[$$EnterpriseSearchSpec$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-enterprisesearch-v1beta1-enterprisesearchspec[$$EnterpriseSearchSpec$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-kibanaspec[$$KibanaSpec$$] +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-logsmonitoring[$$LogsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-logsmonitoring[$$LogsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-maps-v1alpha1-mapsspec[$$MapsSpec$$] +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-metricsmonitoring[$$MetricsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-metricsmonitoring[$$MetricsMonitoring$$] -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-agent-v1alpha1-output[$$Output$$] **** From d14893a439ef2c255d363d119206e59315f9555d Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Fri, 12 Aug 2022 08:34:13 -0500 Subject: [PATCH 29/64] Update CRD documentation remove invalid version validation, as it's no longer valid when using sidecars. remove authentication information for beats stack monitoring, as it's not required. add 'xpack' setting to beats stack monitoring, as it's required to enable data in 'stack monitoring' kibana page/proper indices. --- config/crds/v1/all-crds.yaml | 8 ++--- .../v1/bases/beat.k8s.elastic.co_beats.yaml | 8 ++--- .../eck-operator-crds/templates/all-crds.yaml | 8 ++--- pkg/apis/beat/v1beta1/beat_types.go | 6 ++-- pkg/apis/beat/v1beta1/validations.go | 19 ---------- pkg/apis/beat/v1beta1/validations_test.go | 29 ++------------- pkg/controller/beat/common/config.go | 11 ++++-- .../beat/common/stackmon/metricbeat.tpl.yml | 1 + .../beat/common/stackmon/stackmon.go | 35 +++++-------------- test/e2e/test/beat/steps.go | 2 +- 10 files changed, 36 insertions(+), 91 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index bb4e2c55ab..d844b19f40 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2352,10 +2352,10 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship monitoring, - and logs data of this Beat. Metricbeat and/or Filebeat sidecars - are configured and send metrics data to one Elasticsearch monitoring - cluster running in the same Kubernetes cluster. + description: Monitoring enables you to collect and ship logs and metrics + for this Beat. Metricbeat and/or Filebeat sidecars are configured + and send montioring data to a Elasticsearch monitoring cluster running + in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index 22b5a45429..5adcaf1e3d 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15341,10 +15341,10 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship monitoring, - and logs data of this Beat. Metricbeat and/or Filebeat sidecars - are configured and send metrics data to one Elasticsearch monitoring - cluster running in the same Kubernetes cluster. + description: Monitoring enables you to collect and ship logs and metrics + for this Beat. Metricbeat and/or Filebeat sidecars are configured + and send montioring data to a Elasticsearch monitoring cluster running + in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 9b03affeaf..1354e5fabf 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2370,10 +2370,10 @@ spec: type: string type: object monitoring: - description: Monitoring enables you to collect and ship monitoring, - and logs data of this Beat. Metricbeat and/or Filebeat sidecars - are configured and send metrics data to one Elasticsearch monitoring - cluster running in the same Kubernetes cluster. + description: Monitoring enables you to collect and ship logs and metrics + for this Beat. Metricbeat and/or Filebeat sidecars are configured + and send montioring data to a Elasticsearch monitoring cluster running + in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index fee457dfe3..cdcfc0fa8d 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -81,8 +81,8 @@ type BeatSpec struct { // +kubebuilder:validation:Optional Deployment *DeploymentSpec `json:"deployment,omitempty"` - // Monitoring enables you to collect and ship monitoring, and logs data of this Beat. - // Metricbeat and/or Filebeat sidecars are configured and send metrics data to one + // Monitoring enables you to collect and ship logs and metrics for this Beat. + // Metricbeat and/or Filebeat sidecars are configured and send montioring data to a // Elasticsearch monitoring cluster running in the same Kubernetes cluster. // +kubebuilder:validation:Optional Monitoring Monitoring `json:"monitoring,omitempty"` @@ -403,7 +403,7 @@ func init() { type BeatMonitoringAssociation struct { // The associated Beat *Beat - // ref is the object selector of the monitoring Elasticsearch referenced in the Association + // ref is the object selector of the monitoring Elasticsearch referenced in the association ref commonv1.ObjectSelector } diff --git a/pkg/apis/beat/v1beta1/validations.go b/pkg/apis/beat/v1beta1/validations.go index d2f4a1b82a..ec4b3ba4b3 100644 --- a/pkg/apis/beat/v1beta1/validations.go +++ b/pkg/apis/beat/v1beta1/validations.go @@ -5,7 +5,6 @@ package v1beta1 import ( - "fmt" "regexp" "k8s.io/apimachinery/pkg/util/validation/field" @@ -35,10 +34,6 @@ var ( } typeRegex = regexp.MustCompile("^[a-zA-Z0-9-]+$") - // minStackVersion is the minimum Stack version to enable Stack Monitoring on an Elastic Beats. - // Technically, Beats internal monitoring existed prior to 7.2.0, but it's configuration format - // was slightly different. - minStackVersion = version.MustParse("7.2.0") ) func checkNoUnknownFields(b *Beat) field.ErrorList { @@ -128,9 +123,6 @@ func checkMonitoring(b *Beat) field.ErrorList { if len(b.GetMonitoringMetricsRefs()) == 0 && len(b.GetMonitoringLogsRefs()) == 0 { return nil } - if err := isStackSupportedVersion(b.Spec.Version); err != nil { - errs = append(errs, field.Invalid(field.NewPath("spec").Child("version"), b.Spec.Version, err.Error())) - } refs := b.GetMonitoringMetricsRefs() refsDefined := monitoring.AreEsRefsDefined(refs) if len(refs) > 0 && !refsDefined { @@ -153,14 +145,3 @@ func checkMonitoring(b *Beat) field.ErrorList { } return errs } - -func isStackSupportedVersion(v string) error { - ver, err := version.Parse(v) - if err != nil { - return err - } - if ver.LT(minStackVersion) { - return fmt.Errorf(validations.UnsupportedVersionMsg, minStackVersion) - } - return nil -} diff --git a/pkg/apis/beat/v1beta1/validations_test.go b/pkg/apis/beat/v1beta1/validations_test.go index bca0f1d31b..9aec42636e 100644 --- a/pkg/apis/beat/v1beta1/validations_test.go +++ b/pkg/apis/beat/v1beta1/validations_test.go @@ -232,32 +232,7 @@ func Test_checkMonitoring(t *testing.T) { want: nil, }, { - name: "too old version with stack monitoring enabled returns unsupported version error", - beat: &Beat{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testbeat", - Namespace: "test", - }, - Spec: BeatSpec{ - Type: "filebeat", - Version: "7.1.0", - DaemonSet: &DaemonSetSpec{}, - Monitoring: Monitoring{ - Metrics: MetricsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "elasticsearch", - Namespace: "test", - }, - }, - }, - }, - }, - }, - want: field.ErrorList{&field.Error{Type: field.ErrorTypeInvalid, Field: "spec.version", BadValue: "7.1.0", Detail: "Unsupported version for Stack Monitoring. Required >= 7.2.0."}}, - }, - { - name: "valid version with stack monitoring enabled but invalid ref returns error", + name: "stack monitoring enabled but invalid ref returns error", beat: &Beat{ ObjectMeta: metav1.ObjectMeta{ Name: "testbeat", @@ -287,7 +262,7 @@ func Test_checkMonitoring(t *testing.T) { }}, }, { - name: "valid version with stack monitoring enabled but 2 elasticsearch refs", + name: "stack monitoring enabled but 2 elasticsearch refs", beat: &Beat{ ObjectMeta: metav1.ObjectMeta{ Name: "testbeat", diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 54013e024a..42a630c42b 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -110,9 +110,16 @@ func buildBeatConfig( return nil, err } - // if metrics monitoring is enabled, then enable the metrics http endpoint for metricsbeat sidecar. + // if metrics monitoring is enabled, then + // 1. enable the metrics http endpoint for the metricsbeat sidecar to consume + // 2. disable internal metrics monitoring endpoint if monitoring.IsMetricsDefined(¶ms.Beat) { - if err = cfg.MergeWith(settings.MustCanonicalConfig(map[string]bool{"http.enabled": true})); err != nil { + if err = cfg.MergeWith(settings.MustCanonicalConfig( + map[string]interface{}{ + "http.enabled": true, + "monitoring.enabled": false, + }, + )); err != nil { return nil, err } } diff --git a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml index a02d8fd8f9..85b08364c0 100644 --- a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml +++ b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml @@ -5,5 +5,6 @@ metricbeat.modules: - state period: 10s hosts: ["{{ .URL }}"] + xpack.enabled: true # Elasticsearch output configuration is generated and added here \ No newline at end of file diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index 8dc9eec810..f474efdc39 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -6,12 +6,10 @@ package stackmon import ( _ "embed" // for the beats config files - "errors" "fmt" "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" common_name "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/name" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon" @@ -39,45 +37,28 @@ func Filebeat(client k8s.Client, resource monitoring.HasMonitoring, version stri } func MetricBeat(client k8s.Client, beat *v1beta1.Beat, version string) (stackmon.BeatSidecar, error) { - var username, password string - var sideCar stackmon.BeatSidecar - var err error - associations := monitoring.GetMetricsAssociation(beat) - if len(associations) != 1 { - // should never happen because of the pre-creation validation - return sideCar, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") - } - assoc := associations[0] - - credentials, err := association.ElasticsearchAuthSettings(client, assoc) - if err != nil { - return sideCar, err - } - - username, password = credentials.Username, credentials.Password - config, err := settings.NewCanonicalConfigFrom(beat.Spec.Config.Data) if err != nil { - return sideCar, err + return stackmon.BeatSidecar{}, err } // Default metricbeat monitoring port var httpPort uint64 = 5066 var p httpPortSetting if err := config.Unpack(&p); err != nil { - return sideCar, err + return stackmon.BeatSidecar{}, err } // if http.port is set in beats configuration, then use the port. if p.PortData != nil { portData, ok := p.PortData.(uint64) if !ok { - return sideCar, fmt.Errorf("http.port must be an int") + return stackmon.BeatSidecar{}, fmt.Errorf("while configuring beats stack monitoring: 'http.port' must be an int") } httpPort = portData } - sideCar, err = stackmon.NewMetricBeatSidecar( + sidecar, err := stackmon.NewMetricBeatSidecar( client, commonv1.BeatMonitoringAssociationType, beat, @@ -85,14 +66,14 @@ func MetricBeat(client k8s.Client, beat *v1beta1.Beat, version string) (stackmon metricbeatConfigTemplate, common_name.NewNamer("beat"), fmt.Sprintf("http://localhost:%d", httpPort), - username, - password, + "", + "", false, ) if err != nil { - return sideCar, err + return sidecar, err } - return sideCar, nil + return sidecar, nil } type httpPortSetting struct { diff --git a/test/e2e/test/beat/steps.go b/test/e2e/test/beat/steps.go index 19e20e132a..1c931b9e2a 100644 --- a/test/e2e/test/beat/steps.go +++ b/test/e2e/test/beat/steps.go @@ -136,7 +136,7 @@ func (b Builder) CheckK8sTestSteps(k *test.K8sClient) test.StepList { beat.Status.AvailableNodes = 0 } if !cmp.Equal(beat.Status, expected) { - return fmt.Errorf("expected status health %+v, got diff: %s", expected, cmp.Diff(beat.Status, expected)) + return fmt.Errorf("expected status %+v, got diff: %s", expected, cmp.Diff(beat.Status, expected)) } return nil }), From d9012287bbaa21f65606c16732f9e525d80fea66 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 15 Aug 2022 13:16:56 -0500 Subject: [PATCH 30/64] Correcting spelling --- pkg/controller/beat/common/config_test.go | 8 ++++---- pkg/controller/beat/common/pod_test.go | 6 +++--- pkg/controller/beat/common/stackmon/filebeat.yml | 13 +++++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index e416b14cde..adfb47bcb5 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -87,8 +87,8 @@ func Test_buildBeatConfig(t *testing.T) { require.NoError(t, err) assocConf.CACertProvided = true - withAssocWithCAWithconfig := *withAssocWithCA.DeepCopy() - withAssocWithCAWithconfig.Spec.Config = userCfg + withAssocWithCAWithConfig := *withAssocWithCA.DeepCopy() + withAssocWithCAWithConfig.Spec.Config = userCfg withAssocWithConfig := *withAssoc.DeepCopy() withAssocWithConfig.Spec.Config = userCfg @@ -167,7 +167,7 @@ func Test_buildBeatConfig(t *testing.T) { { name: "association with ca, user config", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCAWithconfig }, + beat: func() beatv1beta1.Beat { return withAssocWithCAWithConfig }, want: merge(userCanonicalCfg, outputYaml, outputCAYaml), }, { @@ -180,7 +180,7 @@ func Test_buildBeatConfig(t *testing.T) { { name: "association with ca, user and managed configs", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCAWithconfig }, + beat: func() beatv1beta1.Beat { return withAssocWithCAWithConfig }, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg, outputYaml, outputCAYaml), }, diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index ba9920baa1..22c2287af1 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -335,7 +335,7 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co data, ok := secret.Data["metricbeat.yml"] assert.True(t, ok) - var cfg metricsbeatConfig + var cfg metricbeatConfig assert.NoError(t, yaml.Unmarshal(data, &cfg)) u, err := url.Parse(cfg.MetricBeat.Modules[0].Hosts[0]) require.NoError(t, err) @@ -346,7 +346,7 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co } } -// metricsbeatConfig represents the metricsbeat configuration for testing purposes. +// metricbeatConfig represents the MetricBeat configuration for testing purposes. // // example: // @@ -354,7 +354,7 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co // modules: // - hosts: // - http://example.com:3033 -type metricsbeatConfig struct { +type metricbeatConfig struct { MetricBeat struct { Modules []struct { Hosts []string diff --git a/pkg/controller/beat/common/stackmon/filebeat.yml b/pkg/controller/beat/common/stackmon/filebeat.yml index bab23be96f..c279e6a190 100644 --- a/pkg/controller/beat/common/stackmon/filebeat.yml +++ b/pkg/controller/beat/common/stackmon/filebeat.yml @@ -1,8 +1,9 @@ -filebeat.inputs: -- type: filestream - id: filebeatlogs - paths: - - /var/log/*.log - - /usr/share/filebeat/data/registry/filebeat/*.json +filebeat: + inputs: + - type: filestream + id: filebeatlogs + paths: + - /var/log/*.log + - /usr/share/filebeat/data/registry/filebeat/*.json # Elasticsearch output configuration is generated and added here \ No newline at end of file From 3ae14e4fd8d4c42da44aedfb09ed959dc9160101 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 15 Aug 2022 13:27:17 -0500 Subject: [PATCH 31/64] Add UUID to stack monitoring *beat configuration. --- pkg/controller/beat/common/config.go | 20 ++++++++++++++++++-- pkg/controller/beat/common/driver.go | 6 ++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 42a630c42b..44c296a6ed 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -5,6 +5,7 @@ package common import ( + "errors" "hash" "path" @@ -12,15 +13,19 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" + esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/labels" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/reconciler" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/bootstrap" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" ) +var ElasticsearchMonitoringClusterUUIDUnavailable = errors.New("beats metrics monitoring cluster uuid is unavailable") + // buildOutputConfig will create the output section in Beat config according to the association configuration. func buildOutputConfig(client k8s.Client, associated beatv1beta1.BeatESAssociation) (*settings.CanonicalConfig, error) { esAssocConf, err := associated.AssociationConf() @@ -114,10 +119,21 @@ func buildBeatConfig( // 1. enable the metrics http endpoint for the metricsbeat sidecar to consume // 2. disable internal metrics monitoring endpoint if monitoring.IsMetricsDefined(¶ms.Beat) { + var es esv1.Elasticsearch + params.Beat.ElasticsearchRef() + if err := params.Client.Get(params.Context, params.Beat.ElasticsearchRef().NamespacedName(), &es); err != nil { + return nil, err + } + uuid, ok := es.Annotations[bootstrap.ClusterUUIDAnnotationName] + if !ok { + // returning specific error here to retry this operation. + return nil, ElasticsearchMonitoringClusterUUIDUnavailable + } if err = cfg.MergeWith(settings.MustCanonicalConfig( map[string]interface{}{ - "http.enabled": true, - "monitoring.enabled": false, + "http.enabled": true, + "monitoring.enabled": false, + "monitoring.cluster_uuid": uuid, }, )); err != nil { return nil, err diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 56f77a830e..adc6a43a10 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -6,11 +6,14 @@ package common import ( "context" + "errors" "hash/fnv" + "time" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/reconcile" beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" @@ -90,6 +93,9 @@ func Reconcile( configHash := fnv.New32a() if err := reconcileConfig(params, managedConfig, configHash); err != nil { + if errors.Is(err, ElasticsearchMonitoringClusterUUIDUnavailable) { + results.WithReconciliationState(reconciler.Requeue.WithReason("ElasticsearchRef UUID unavailable while configuring beats stack monitoring")).WithResult(reconcile.Result{Requeue: true, RequeueAfter: 10 * time.Second}) + } return results.WithError(err), params.Status } From 268944b078ad0626a0d8763eb7acb4680b0ffed0 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 10:53:41 -0500 Subject: [PATCH 32/64] Ensure metricbeat sidecar for beat has cluster_uuid. Tests ensuring behavior. --- pkg/controller/beat/common/config.go | 26 ++-------- pkg/controller/beat/common/config_test.go | 2 +- pkg/controller/beat/common/driver.go | 7 +-- pkg/controller/beat/common/pod.go | 2 +- pkg/controller/beat/common/pod_test.go | 11 +++-- .../beat/common/stackmon/metricbeat.tpl.yml | 4 +- .../beat/common/stackmon/stackmon.go | 49 ++++++++++++++++--- 7 files changed, 62 insertions(+), 39 deletions(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 44c296a6ed..bf2e9b0f09 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -5,7 +5,6 @@ package common import ( - "errors" "hash" "path" @@ -13,19 +12,15 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" - esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/labels" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/reconciler" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/bootstrap" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" ) -var ElasticsearchMonitoringClusterUUIDUnavailable = errors.New("beats metrics monitoring cluster uuid is unavailable") - // buildOutputConfig will create the output section in Beat config according to the association configuration. func buildOutputConfig(client k8s.Client, associated beatv1beta1.BeatESAssociation) (*settings.CanonicalConfig, error) { esAssocConf, err := associated.AssociationConf() @@ -119,23 +114,10 @@ func buildBeatConfig( // 1. enable the metrics http endpoint for the metricsbeat sidecar to consume // 2. disable internal metrics monitoring endpoint if monitoring.IsMetricsDefined(¶ms.Beat) { - var es esv1.Elasticsearch - params.Beat.ElasticsearchRef() - if err := params.Client.Get(params.Context, params.Beat.ElasticsearchRef().NamespacedName(), &es); err != nil { - return nil, err - } - uuid, ok := es.Annotations[bootstrap.ClusterUUIDAnnotationName] - if !ok { - // returning specific error here to retry this operation. - return nil, ElasticsearchMonitoringClusterUUIDUnavailable - } - if err = cfg.MergeWith(settings.MustCanonicalConfig( - map[string]interface{}{ - "http.enabled": true, - "monitoring.enabled": false, - "monitoring.cluster_uuid": uuid, - }, - )); err != nil { + if err = cfg.MergeWith(settings.MustCanonicalConfig(map[string]interface{}{ + "http.enabled": true, + "monitoring.enabled": false, + })); err != nil { return nil, err } } diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index adfb47bcb5..333cb25b30 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -203,7 +203,7 @@ func Test_buildBeatConfig(t *testing.T) { }, } }, - want: merge(userCanonicalCfg, settings.MustCanonicalConfig(map[string]bool{"http.enabled": true})), + want: merge(userCanonicalCfg, settings.MustCanonicalConfig(map[string]bool{"http.enabled": true, "monitoring.enabled": false})), }, } { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index adc6a43a10..e81be1bf29 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -17,6 +17,7 @@ import ( beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" + beat_stackmon "github.com/elastic/cloud-on-k8s/v2/pkg/controller/beat/common/stackmon" commonassociation "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/association" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/container" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/driver" @@ -93,9 +94,6 @@ func Reconcile( configHash := fnv.New32a() if err := reconcileConfig(params, managedConfig, configHash); err != nil { - if errors.Is(err, ElasticsearchMonitoringClusterUUIDUnavailable) { - results.WithReconciliationState(reconciler.Requeue.WithReason("ElasticsearchRef UUID unavailable while configuring beats stack monitoring")).WithResult(reconcile.Result{Requeue: true, RequeueAfter: 10 * time.Second}) - } return results.WithError(err), params.Status } @@ -106,6 +104,9 @@ func Reconcile( podTemplate, err := buildPodTemplate(params, defaultImage, configHash) if err != nil { + if errors.Is(err, beat_stackmon.MonitoringClusterUUIDUnavailable) { + results.WithReconciliationState(reconciler.Requeue.WithReason("ElasticsearchRef UUID unavailable while configuring beats stack monitoring")).WithResult(reconcile.Result{Requeue: true, RequeueAfter: 10 * time.Second}) + } return results.WithError(err), params.Status } var reconcileResults *reconciler.Results diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index be8688a11f..be271e4787 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -150,7 +150,7 @@ func buildPodTemplate( } if monitoring.IsMetricsDefined(¶ms.Beat) { - sideCar, err := beat_stackmon.MetricBeat(params.Client, ¶ms.Beat, params.Beat.Spec.Version) + sideCar, err := beat_stackmon.MetricBeat(params.Context, params.Client, ¶ms.Beat, params.Beat.Spec.Version) if err != nil { return podTemplate, err } diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 22c2287af1..bf689af598 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -27,6 +27,7 @@ import ( "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/container" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/watches" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/bootstrap" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" ) @@ -62,8 +63,9 @@ func Test_buildPodTemplate(t *testing.T) { }, &esv1.Elasticsearch{ ObjectMeta: metav1.ObjectMeta{ - Name: "testes", - Namespace: "ns", + Name: "testes", + Namespace: "ns", + Annotations: map[string]string{bootstrap.ClusterUUIDAnnotationName: "abcd1234"}, }, }, ) @@ -74,8 +76,9 @@ func Test_buildPodTemplate(t *testing.T) { Namespace: "ns", }, Spec: v1beta1.BeatSpec{ - Version: "7.15.0", - Config: httpPortCfg, + Version: "7.15.0", + Config: httpPortCfg, + ElasticsearchRef: commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}, Monitoring: v1beta1.Monitoring{ Metrics: v1beta1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ diff --git a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml index 85b08364c0..6b2d14a84e 100644 --- a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml +++ b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml @@ -6,5 +6,7 @@ metricbeat.modules: period: 10s hosts: ["{{ .URL }}"] xpack.enabled: true - +{{if .ClusterUUID }} +monitoring.cluster_uuid: "{{ .ClusterUUID }}" +{{end}} # Elasticsearch output configuration is generated and added here \ No newline at end of file diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index f474efdc39..b0d3230fae 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -5,15 +5,21 @@ package stackmon import ( + "bytes" + "context" _ "embed" // for the beats config files + "errors" "fmt" + "text/template" "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" common_name "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/name" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/bootstrap" "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" ) @@ -25,6 +31,10 @@ var ( // metricbeatConfigTemplate is a configuration template for Metricbeat to collect monitoring data from Beats resources //go:embed metricbeat.tpl.yml metricbeatConfigTemplate string + + // MonitoringClusterUUIDUnavailable will be returned when the UUID for the Beat ElasticsearchRef cluster + // has not yet been assigned a UUID. This could happen on a newly created Elasticsearch cluster. + MonitoringClusterUUIDUnavailable = errors.New("beats stack monitoring cluster uuid is unavailable") ) func Filebeat(client k8s.Client, resource monitoring.HasMonitoring, version string) (stackmon.BeatSidecar, error) { @@ -36,7 +46,8 @@ func Filebeat(client k8s.Client, resource monitoring.HasMonitoring, version stri return filebeat, nil } -func MetricBeat(client k8s.Client, beat *v1beta1.Beat, version string) (stackmon.BeatSidecar, error) { +func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, version string) (stackmon.BeatSidecar, error) { + finalTemplate := metricbeatConfigTemplate config, err := settings.NewCanonicalConfigFrom(beat.Spec.Config.Data) if err != nil { return stackmon.BeatSidecar{}, err @@ -58,22 +69,46 @@ func MetricBeat(client k8s.Client, beat *v1beta1.Beat, version string) (stackmon httpPort = portData } - sidecar, err := stackmon.NewMetricBeatSidecar( + if err := beat.ElasticsearchRef().IsValid(); err == nil { + var es esv1.Elasticsearch + if err := client.Get(ctx, beat.ElasticsearchRef().WithDefaultNamespace(beat.Namespace).NamespacedName(), &es); err != nil { + return stackmon.BeatSidecar{}, err + } + uuid, ok := es.Annotations[bootstrap.ClusterUUIDAnnotationName] + if !ok { + // returning specific error here so this operation can be retried. + return stackmon.BeatSidecar{}, MonitoringClusterUUIDUnavailable + } + var tmpl *template.Template + if tmpl, err = template.New("beat_stack_monitoring").Parse(metricbeatConfigTemplate); err != nil { + return stackmon.BeatSidecar{}, fmt.Errorf("while parsing template for beats stack monitoring configuration: %s", err) + } + var tpl bytes.Buffer + data := struct { + ClusterUUID string + URL string + }{ + ClusterUUID: uuid, + URL: fmt.Sprintf("http://localhost:%d", httpPort), + } + if err := tmpl.Execute(&tpl, data); err != nil { + return stackmon.BeatSidecar{}, fmt.Errorf("while templating beats stack monitoring configuration: %s", err) + } + finalTemplate = tpl.String() + } + + return stackmon.NewMetricBeatSidecar( client, commonv1.BeatMonitoringAssociationType, beat, version, - metricbeatConfigTemplate, + finalTemplate, common_name.NewNamer("beat"), fmt.Sprintf("http://localhost:%d", httpPort), "", "", false, ) - if err != nil { - return sidecar, err - } - return sidecar, nil } type httpPortSetting struct { From d5bb9b8e5d8e7ac3a6e283882c080bb182e9a653 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 10:55:18 -0500 Subject: [PATCH 33/64] Add beats stackmon tests --- .../beat/common/stackmon/stackmon_test.go | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 pkg/controller/beat/common/stackmon/stackmon_test.go diff --git a/pkg/controller/beat/common/stackmon/stackmon_test.go b/pkg/controller/beat/common/stackmon/stackmon_test.go new file mode 100644 index 0000000000..2ae291909a --- /dev/null +++ b/pkg/controller/beat/common/stackmon/stackmon_test.go @@ -0,0 +1,221 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + +package stackmon + +import ( + "context" + _ "embed" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + + "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" + commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + v1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/bootstrap" + "github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s" +) + +func TestMetricBeat(t *testing.T) { + containerFixture := corev1.Container{ + Name: "metricbeat", + Image: "docker.elastic.co/beats/metricbeat:8.2.3", + Args: []string{"-c", "/etc/metricbeat-config/metricbeat.yml", "-e"}, + Env: []corev1.EnvVar{ + { + Name: "POD_IP", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "status.podIP", + }, + }, + }, + { + Name: "POD_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }, + }, + }, + { + Name: "NODE_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "spec.nodeName", + }, + }, + }, + { + Name: "NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.namespace", + }, + }, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "beat-metricbeat-config", + ReadOnly: true, + MountPath: "/etc/metricbeat-config", + }, + }, + } + beatYml := `metricbeat: + modules: + - hosts: + - http://localhost:5066 + metricsets: + - stats + - state + module: beat + period: 10s + xpack: + enabled: true +monitoring: + cluster_uuid: abcd1234 +output: + elasticsearch: + hosts: + - es-metrics-monitoring-url + password: es-password + username: es-user +` + beatSidecarFixture := stackmon.BeatSidecar{ + Container: containerFixture, + ConfigSecret: corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beat-beat-monitoring-metricbeat-config", + Namespace: "test", + Labels: map[string]string{ + "common.k8s.elastic.co/type": "elasticsearch", + "elasticsearch.k8s.elastic.co/cluster-name": "beat", + }, + }, + Data: map[string][]byte{ + "metricbeat.yml": []byte(beatYml), + }, + }, + Volumes: []corev1.Volume{ + { + Name: "beat-metricbeat-config", + VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "beat-beat-monitoring-metricbeat-config", Optional: pointer.BoolPtr(false)}}, + }, + }, + } + esFixture := esv1.Elasticsearch{ + ObjectMeta: metav1.ObjectMeta{ + Name: "es", + Namespace: "test", + Annotations: map[string]string{bootstrap.ClusterUUIDAnnotationName: "abcd1234"}, + }, + Spec: esv1.ElasticsearchSpec{ + Version: "8.2.3", + }, + } + monitoringEsFixture := esv1.Elasticsearch{ + ObjectMeta: metav1.ObjectMeta{ + Name: "esmonitoring", + Namespace: "test", + Annotations: map[string]string{bootstrap.ClusterUUIDAnnotationName: "abcd4321"}, + }, + Spec: esv1.ElasticsearchSpec{ + Version: "8.2.3", + }, + } + beatFixture := v1beta1.Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beat", + Namespace: "test", + }, + Spec: v1beta1.BeatSpec{ + Type: "metricbeat", + Version: "8.2.3", + ElasticsearchRef: v1.ObjectSelector{Name: "es", Namespace: "test"}, + Deployment: &v1beta1.DeploymentSpec{}, + Config: &v1.Config{ + Data: map[string]interface{}{}, + }, + Monitoring: v1beta1.Monitoring{ + Metrics: v1beta1.MetricsMonitoring{ + ElasticsearchRefs: []v1.ObjectSelector{{Name: "esmonitoring"}}, + }, + Logs: v1beta1.LogsMonitoring{ + ElasticsearchRefs: []v1.ObjectSelector{{Name: "esmonitoring"}}, + }, + }, + }, + } + beatFixture.GetAssociations()[2].SetAssociationConf(&commonv1.AssociationConf{ + AuthSecretName: "es-secret-name", + AuthSecretKey: "es-user", + URL: "es-metrics-monitoring-url", + }) + type args struct { + client k8s.Client + beat func() *v1beta1.Beat + version string + } + tests := []struct { + name string + args args + want stackmon.BeatSidecar + wantErr bool + }{ + { + name: "beat with stack monitoring enabled and valid elasticsearchRef returns properly configured sidecar", + args: args{ + client: k8s.NewFakeClient(&beatFixture, &esFixture, &monitoringEsFixture, &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "es-secret-name", Namespace: "test"}, + Data: map[string][]byte{"es-user": []byte("es-password")}, + }), + beat: func() *v1beta1.Beat { + return &beatFixture + }, + version: "8.2.3", + }, + want: beatSidecarFixture, + wantErr: false, + }, + { + name: "beat with invalid http.port configuration data returns error", + args: args{ + client: k8s.NewFakeClient(), + beat: func() *v1beta1.Beat { + beat := beatFixture.DeepCopy() + beat.Spec.Config.Data = map[string]interface{}{"http.port": "invalid"} + return beat + }, + version: "8.2.3", + }, + want: stackmon.BeatSidecar{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := MetricBeat(context.Background(), tt.args.client, tt.args.beat(), tt.args.version) + if (err != nil) != tt.wantErr { + t.Errorf("MetricBeat() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !cmp.Equal(got, tt.want, cmpopts.IgnoreFields(stackmon.BeatSidecar{}, "ConfigHash")) { + t.Errorf("MetricBeat() = diff: %s", cmp.Diff(got, tt.want, cmpopts.IgnoreFields(stackmon.BeatSidecar{}, "ConfigHash"))) + } + }) + } +} From b57902efb6a6a3ab021c4ca8b39681e951d272f9 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 10:58:19 -0500 Subject: [PATCH 34/64] Add newlines to yaml files --- pkg/controller/beat/common/stackmon/filebeat.yml | 2 +- pkg/controller/beat/common/stackmon/metricbeat.tpl.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/beat/common/stackmon/filebeat.yml b/pkg/controller/beat/common/stackmon/filebeat.yml index c279e6a190..c5983f3ca6 100644 --- a/pkg/controller/beat/common/stackmon/filebeat.yml +++ b/pkg/controller/beat/common/stackmon/filebeat.yml @@ -6,4 +6,4 @@ filebeat: - /var/log/*.log - /usr/share/filebeat/data/registry/filebeat/*.json -# Elasticsearch output configuration is generated and added here \ No newline at end of file +# Elasticsearch output configuration is generated and added here diff --git a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml index 6b2d14a84e..96d48288ba 100644 --- a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml +++ b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml @@ -9,4 +9,4 @@ metricbeat.modules: {{if .ClusterUUID }} monitoring.cluster_uuid: "{{ .ClusterUUID }}" {{end}} -# Elasticsearch output configuration is generated and added here \ No newline at end of file +# Elasticsearch output configuration is generated and added here From c86c85e9442325def3f95dcabf0a6093f0c57392 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 11:19:36 -0500 Subject: [PATCH 35/64] Update beats stackmon validation to use same common validation --- pkg/apis/beat/v1beta1/validations.go | 32 ++------ pkg/apis/beat/v1beta1/validations_test.go | 89 +++++++++++++++++------ 2 files changed, 72 insertions(+), 49 deletions(-) diff --git a/pkg/apis/beat/v1beta1/validations.go b/pkg/apis/beat/v1beta1/validations.go index ec4b3ba4b3..7f147ee7db 100644 --- a/pkg/apis/beat/v1beta1/validations.go +++ b/pkg/apis/beat/v1beta1/validations.go @@ -10,7 +10,6 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/validations" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/version" ) @@ -113,35 +112,14 @@ func checkSpec(b *Beat) field.ErrorList { } func checkAssociations(b *Beat) field.ErrorList { + monitoringPath := field.NewPath("spec").Child("monitoring") err1 := commonv1.CheckAssociationRefs(field.NewPath("spec").Child("elasticsearchRef"), b.Spec.ElasticsearchRef) err2 := commonv1.CheckAssociationRefs(field.NewPath("spec").Child("kibanaRef"), b.Spec.KibanaRef) - return append(err1, err2...) + err3 := commonv1.CheckAssociationRefs(monitoringPath.Child("metrics"), b.GetMonitoringMetricsRefs()...) + err4 := commonv1.CheckAssociationRefs(monitoringPath.Child("logs"), b.GetMonitoringLogsRefs()...) + return append(err1, append(err2, append(err3, err4...)...)...) } func checkMonitoring(b *Beat) field.ErrorList { - var errs field.ErrorList - if len(b.GetMonitoringMetricsRefs()) == 0 && len(b.GetMonitoringLogsRefs()) == 0 { - return nil - } - refs := b.GetMonitoringMetricsRefs() - refsDefined := monitoring.AreEsRefsDefined(refs) - if len(refs) > 0 && !refsDefined { - errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), - refs, validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg)) - } - if refsDefined && len(refs) != 1 { - errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), - refs, validations.InvalidElasticsearchRefsMsg)) - } - refs = b.GetMonitoringLogsRefs() - refsDefined = monitoring.AreEsRefsDefined(refs) - if len(refs) > 0 && !refsDefined { - errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), - refs, validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg)) - } - if refsDefined && len(refs) != 1 { - errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), - refs, validations.InvalidElasticsearchRefsMsg)) - } - return errs + return validations.Validate(b, b.Spec.Version) } diff --git a/pkg/apis/beat/v1beta1/validations_test.go b/pkg/apis/beat/v1beta1/validations_test.go index 9aec42636e..7827c30eea 100644 --- a/pkg/apis/beat/v1beta1/validations_test.go +++ b/pkg/apis/beat/v1beta1/validations_test.go @@ -14,7 +14,6 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/validations" ) func Test_checkBeatType(t *testing.T) { @@ -155,6 +154,36 @@ func Test_checkAssociations(t *testing.T) { }, wantErr: true, }, + { + name: "invalid metrics stackmon ref with name and secretname: NOK", + args: args{ + b: &Beat{ + Spec: BeatSpec{ + Monitoring: Monitoring{ + Metrics: MetricsMonitoring{ + []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, + }, + }, + }, + }, + }, + wantErr: true, + }, + { + name: "invalid logs stackmon ref with name and secretname: NOK", + args: args{ + b: &Beat{ + Spec: BeatSpec{ + Monitoring: Monitoring{ + Logs: LogsMonitoring{ + []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, + }, + }, + }, + }, + }, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -232,7 +261,7 @@ func Test_checkMonitoring(t *testing.T) { want: nil, }, { - name: "stack monitoring enabled but invalid ref returns error", + name: "stack monitoring enabled with only metrics ref is valid", beat: &Beat{ ObjectMeta: metav1.ObjectMeta{ Name: "testbeat", @@ -246,7 +275,7 @@ func Test_checkMonitoring(t *testing.T) { Metrics: MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { - // missing name + Name: "es", Namespace: "test", }, }, @@ -254,15 +283,10 @@ func Test_checkMonitoring(t *testing.T) { }, }, }, - want: field.ErrorList{&field.Error{ - Type: field.ErrorTypeInvalid, - Field: "spec.monitoring.metrics.elasticsearchRefs", - BadValue: []commonv1.ObjectSelector{{Namespace: "test", Name: "", ServiceName: "", SecretName: ""}}, - Detail: validations.InvalidBeatsElasticsearchRefForStackMonitoringMsg, - }}, + want: nil, }, { - name: "stack monitoring enabled but 2 elasticsearch refs", + name: "stack monitoring enabled with only logs ref is valid", beat: &Beat{ ObjectMeta: metav1.ObjectMeta{ Name: "testbeat", @@ -273,14 +297,43 @@ func Test_checkMonitoring(t *testing.T) { Version: "8.2.3", DaemonSet: &DaemonSetSpec{}, Monitoring: Monitoring{ - Metrics: MetricsMonitoring{ + Logs: LogsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "es", + Namespace: "test", + }, + }, + }, + }, + }, + }, + want: nil, + }, + { + name: "stack monitoring enabled with both logs and metrics ref is valid", + beat: &Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testbeat", + Namespace: "test", + }, + Spec: BeatSpec{ + Type: "filebeat", + Version: "8.2.3", + DaemonSet: &DaemonSetSpec{}, + Monitoring: Monitoring{ + Logs: LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { - Name: "es1", + Name: "es", Namespace: "test", }, + }, + }, + Metrics: MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ { - Name: "es2", + Name: "es", Namespace: "test", }, }, @@ -288,15 +341,7 @@ func Test_checkMonitoring(t *testing.T) { }, }, }, - want: field.ErrorList{&field.Error{ - Type: field.ErrorTypeInvalid, - Field: "spec.monitoring.metrics.elasticsearchRefs", - BadValue: []commonv1.ObjectSelector{ - {Namespace: "test", Name: "es1", ServiceName: "", SecretName: ""}, - {Namespace: "test", Name: "es2", ServiceName: "", SecretName: ""}, - }, - Detail: validations.InvalidElasticsearchRefsMsg, - }}, + want: nil, }, } for _, tt := range tests { From 025a30f0027824b0d9b15914c382dce49f131794 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 11:24:49 -0500 Subject: [PATCH 36/64] Update public docs. remove invalid documentation in e2e tests beat builder --- docs/advanced-topics/stack-monitoring.asciidoc | 11 ++++++++--- test/e2e/test/beat/builder.go | 3 --- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/advanced-topics/stack-monitoring.asciidoc b/docs/advanced-topics/stack-monitoring.asciidoc index e51cb31990..67a0d3bc70 100644 --- a/docs/advanced-topics/stack-monitoring.asciidoc +++ b/docs/advanced-topics/stack-monitoring.asciidoc @@ -66,9 +66,14 @@ spec: type: filebeat version: {version} monitoring: - elasticsearchRefs: - - name: monitoring - namespace: observability <3> + metrics: + elasticsearchRefs: + - name: monitoring + namespace: observability <3> + logs: + elasticsearchRefs: + - name: monitoring + namespace: observability <3> ---- <1> The use of `namespace` is optional if the monitoring Elasticsearch cluster and the monitored Elasticsearch cluster are running in the same namespace. diff --git a/test/e2e/test/beat/builder.go b/test/e2e/test/beat/builder.go index f4405187c7..e5d0f49fb9 100644 --- a/test/e2e/test/beat/builder.go +++ b/test/e2e/test/beat/builder.go @@ -366,9 +366,6 @@ func (b Builder) GetMetricsCluster() *types.NamespacedName { return &metricsCluster } -// GetLogsCluster does not return a logs cluster, as Beats stack monitoring is slightly -// different that both Elasticsearch, and Kibana stack monitoring, as it uses internal -// beat collectors to send only metrics data, not logs data. func (b Builder) GetLogsCluster() *types.NamespacedName { if len(b.Beat.Spec.Monitoring.Metrics.ElasticsearchRefs) == 0 { return nil From 97125e5e4246975f73ccf751f805b2808331ecb4 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 12:30:51 -0500 Subject: [PATCH 37/64] Update api docs --- docs/reference/api-docs.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index c0ebdc1f86..d056e03fc3 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -315,7 +315,7 @@ BeatSpec defines the desired state of a Beat. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`daemonSet`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-daemonsetspec[$$DaemonSetSpec$$]__ | DaemonSet specifies the Beat should be deployed as a DaemonSet, and allows providing its spec. Cannot be used along with `deployment`. If both are absent a default for the Type is used. | *`deployment`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-deploymentspec[$$DeploymentSpec$$]__ | Deployment specifies the Beat should be deployed as a Deployment, and allows providing its spec. Cannot be used along with `daemonSet`. If both are absent a default for the Type is used. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship monitoring, and logs data of this Beat. Metricbeat and/or Filebeat sidecars are configured and send metrics data to one Elasticsearch monitoring cluster running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured and send montioring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying DaemonSet or Deployment. |=== From 9bf98fe0c6fa4d3e7354a3f713eba8ba9f9ec973 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 12:43:26 -0500 Subject: [PATCH 38/64] Fix naming of static error. Fix wrapping of errors. --- pkg/controller/beat/common/driver.go | 2 +- pkg/controller/beat/common/stackmon/stackmon.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index e81be1bf29..cb163a5c5f 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -104,7 +104,7 @@ func Reconcile( podTemplate, err := buildPodTemplate(params, defaultImage, configHash) if err != nil { - if errors.Is(err, beat_stackmon.MonitoringClusterUUIDUnavailable) { + if errors.Is(err, beat_stackmon.ErrMonitoringClusterUUIDUnavailable) { results.WithReconciliationState(reconciler.Requeue.WithReason("ElasticsearchRef UUID unavailable while configuring beats stack monitoring")).WithResult(reconcile.Result{Requeue: true, RequeueAfter: 10 * time.Second}) } return results.WithError(err), params.Status diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index b0d3230fae..e9bfd57372 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -32,9 +32,9 @@ var ( //go:embed metricbeat.tpl.yml metricbeatConfigTemplate string - // MonitoringClusterUUIDUnavailable will be returned when the UUID for the Beat ElasticsearchRef cluster + // ErrMonitoringClusterUUIDUnavailable will be returned when the UUID for the Beat ElasticsearchRef cluster // has not yet been assigned a UUID. This could happen on a newly created Elasticsearch cluster. - MonitoringClusterUUIDUnavailable = errors.New("beats stack monitoring cluster uuid is unavailable") + ErrMonitoringClusterUUIDUnavailable = errors.New("beats stack monitoring cluster uuid is unavailable") ) func Filebeat(client k8s.Client, resource monitoring.HasMonitoring, version string) (stackmon.BeatSidecar, error) { @@ -77,11 +77,11 @@ func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, vers uuid, ok := es.Annotations[bootstrap.ClusterUUIDAnnotationName] if !ok { // returning specific error here so this operation can be retried. - return stackmon.BeatSidecar{}, MonitoringClusterUUIDUnavailable + return stackmon.BeatSidecar{}, ErrMonitoringClusterUUIDUnavailable } var tmpl *template.Template if tmpl, err = template.New("beat_stack_monitoring").Parse(metricbeatConfigTemplate); err != nil { - return stackmon.BeatSidecar{}, fmt.Errorf("while parsing template for beats stack monitoring configuration: %s", err) + return stackmon.BeatSidecar{}, fmt.Errorf("while parsing template for beats stack monitoring configuration: %w", err) } var tpl bytes.Buffer data := struct { @@ -92,7 +92,7 @@ func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, vers URL: fmt.Sprintf("http://localhost:%d", httpPort), } if err := tmpl.Execute(&tpl, data); err != nil { - return stackmon.BeatSidecar{}, fmt.Errorf("while templating beats stack monitoring configuration: %s", err) + return stackmon.BeatSidecar{}, fmt.Errorf("while templating beats stack monitoring configuration: %w", err) } finalTemplate = tpl.String() } From 710575d34b996dd4852c902ce45795882f8e3a16 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 13:26:08 -0500 Subject: [PATCH 39/64] fixing ghost changes causing ci failures --- pkg/apis/beat/v1beta1/beat_types.go | 2 +- pkg/controller/beat/common/pod_test.go | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index cdcfc0fa8d..3bacc070ae 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -82,7 +82,7 @@ type BeatSpec struct { Deployment *DeploymentSpec `json:"deployment,omitempty"` // Monitoring enables you to collect and ship logs and metrics for this Beat. - // Metricbeat and/or Filebeat sidecars are configured and send montioring data to a + // Metricbeat and/or Filebeat sidecars are configured and send monitoring data to a // Elasticsearch monitoring cluster running in the same Kubernetes cluster. // +kubebuilder:validation:Optional Monitoring Monitoring `json:"monitoring,omitempty"` diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index bf689af598..7f7029a440 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -354,9 +354,10 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co // example: // // metricbeat: -// modules: -// - hosts: -// - http://example.com:3033 +// +// modules: +// - hosts: +// - http://example.com:3033 type metricbeatConfig struct { MetricBeat struct { Modules []struct { From 6840e41d6590f82aa26f959e23a562dc33ae4b83 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 14:55:51 -0500 Subject: [PATCH 40/64] Add changed yaml files vi automation thatss breaking ci --- config/crds/v1/all-crds.yaml | 2 +- config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml | 2 +- docs/reference/api-docs.asciidoc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index d844b19f40..2602067024 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2354,7 +2354,7 @@ spec: monitoring: description: Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured - and send montioring data to a Elasticsearch monitoring cluster running + and send monitoring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. properties: logs: diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index 5adcaf1e3d..ff5e0983dc 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15343,7 +15343,7 @@ spec: monitoring: description: Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured - and send montioring data to a Elasticsearch monitoring cluster running + and send monitoring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. properties: logs: diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index d056e03fc3..ea6f1c79b0 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -315,7 +315,7 @@ BeatSpec defines the desired state of a Beat. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`daemonSet`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-daemonsetspec[$$DaemonSetSpec$$]__ | DaemonSet specifies the Beat should be deployed as a DaemonSet, and allows providing its spec. Cannot be used along with `deployment`. If both are absent a default for the Type is used. | *`deployment`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-deploymentspec[$$DeploymentSpec$$]__ | Deployment specifies the Beat should be deployed as a Deployment, and allows providing its spec. Cannot be used along with `daemonSet`. If both are absent a default for the Type is used. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured and send montioring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured and send monitoring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying DaemonSet or Deployment. |=== From 734130de0dc9aac4f36b363f493134b92c83bf6b Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 16 Aug 2022 15:20:33 -0500 Subject: [PATCH 41/64] adjust all-crds in opeartor chart --- .../charts/eck-operator-crds/templates/all-crds.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 1354e5fabf..bfdfd210b7 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2372,7 +2372,7 @@ spec: monitoring: description: Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured - and send montioring data to a Elasticsearch monitoring cluster running + and send monitoring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. properties: logs: From 0b5581f033e11bfde0e0f02f9a9dfa8c5d326720 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 17 Aug 2022 08:04:59 -0500 Subject: [PATCH 42/64] Apply https://github.com/elastic/cloud-on-k8s/pull/5955 to try and get e2e to run properly. Fix missing context from main merge. --- hack/deployer/runner/gke.go | 18 +++++++++++------- pkg/controller/beat/common/config_test.go | 1 + pkg/controller/beat/common/pod.go | 2 +- pkg/controller/beat/common/pod_test.go | 1 + .../beat/common/stackmon/stackmon.go | 5 +++-- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/hack/deployer/runner/gke.go b/hack/deployer/runner/gke.go index 3512bf5757..2c2047d2cb 100644 --- a/hack/deployer/runner/gke.go +++ b/hack/deployer/runner/gke.go @@ -8,9 +8,12 @@ import ( "fmt" "log" "strings" + "time" "github.com/ghodss/yaml" storagev1 "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/retry" "github.com/elastic/cloud-on-k8s/v2/hack/deployer/exec" ) @@ -179,18 +182,19 @@ func (d *GKEDriver) setupLabelsForGCEProvider() error { storageClass.Parameters = make(map[string]string) } storageClass.Parameters["labels"] = labels - // Delete the storage class as it is not allowed to patch parameters. - if err := exec.NewCommand(fmt.Sprintf("kubectl delete sc %s", storageClass.Name)).Run(); err != nil { - return err - } - // Apply the new one storageClassYaml, err := yaml.Marshal(storageClass) if err != nil { return err } - if err := exec.NewCommand(fmt.Sprintf(`cat < Date: Wed, 17 Aug 2022 08:29:07 -0500 Subject: [PATCH 43/64] Add missing context to beat buildPodTemplate test. --- pkg/controller/beat/common/pod_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 2f732dd784..ed4c8c3c2f 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -262,6 +262,7 @@ func Test_buildPodTemplate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + tt.args.params.Context = context.Background() podTemplateSpec, err := buildPodTemplate(tt.args.params, tt.args.defaultImage, tt.args.initialHash) if (err != nil) != tt.want.err { t.Errorf("buildPodTemplate() error = %v, wantErr %v", err, tt.want.err) From c710cd55c04adc99f3df62c0f23eec048636aca3 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 17 Aug 2022 11:02:29 -0500 Subject: [PATCH 44/64] Revert change to deployer/runner/gke.go as it was merged. --- hack/deployer/runner/gke.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/hack/deployer/runner/gke.go b/hack/deployer/runner/gke.go index 2c2047d2cb..3512bf5757 100644 --- a/hack/deployer/runner/gke.go +++ b/hack/deployer/runner/gke.go @@ -8,12 +8,9 @@ import ( "fmt" "log" "strings" - "time" "github.com/ghodss/yaml" storagev1 "k8s.io/api/storage/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/util/retry" "github.com/elastic/cloud-on-k8s/v2/hack/deployer/exec" ) @@ -182,19 +179,18 @@ func (d *GKEDriver) setupLabelsForGCEProvider() error { storageClass.Parameters = make(map[string]string) } storageClass.Parameters["labels"] = labels + // Delete the storage class as it is not allowed to patch parameters. + if err := exec.NewCommand(fmt.Sprintf("kubectl delete sc %s", storageClass.Name)).Run(); err != nil { + return err + } + // Apply the new one storageClassYaml, err := yaml.Marshal(storageClass) if err != nil { return err } - if err := retry.OnError( - wait.Backoff{Duration: 10 * time.Millisecond, Steps: 5}, - func(err error) bool { return true }, - func() error { - return exec.NewCommand(fmt.Sprintf(`cat < Date: Mon, 22 Aug 2022 17:01:02 -0500 Subject: [PATCH 45/64] Move Monitoring objects to commonv1. Adjust Beats, Kibana, and Elasticsearch to use common Monitoring resources. Add Note about beat stack monitoring not having ES cluster monitored. Adjust beat test to not return a func to retrieve Beat. Adjust reconcile statement for when ElasticsearchRef UUID is not available. Adjust beat/common/stackmon/metricbeat.tpl.yml to remove IF statement. Remove unnecessary block when calling common NewFileBeatSidecar --- config/crds/v1/all-crds.yaml | 12 ++-- .../v1/bases/beat.k8s.elastic.co_beats.yaml | 4 +- ...search.k8s.elastic.co_elasticsearches.yaml | 4 +- .../bases/kibana.k8s.elastic.co_kibanas.yaml | 4 +- .../eck-operator-crds/templates/all-crds.yaml | 12 ++-- .../advanced-topics/stack-monitoring.asciidoc | 2 + pkg/apis/beat/v1beta1/beat_types.go | 25 +------ pkg/apis/beat/v1beta1/validations_test.go | 22 +++---- .../beat/v1beta1/zz_generated.deepcopy.go | 57 ---------------- pkg/apis/common/v1/monitoring.go | 34 ++++++++++ pkg/apis/common/v1/zz_generated.deepcopy.go | 57 ++++++++++++++++ .../elasticsearch/v1/elasticsearch_types.go | 25 +------ .../v1/elasticsearch_types_test.go | 6 +- .../elasticsearch/v1/zz_generated.deepcopy.go | 57 ---------------- pkg/apis/kibana/v1/kibana_types.go | 25 +------ pkg/apis/kibana/v1/webhook_test.go | 22 +++---- pkg/apis/kibana/v1/zz_generated.deepcopy.go | 57 ---------------- pkg/controller/beat/common/config_test.go | 63 +++++++++--------- pkg/controller/beat/common/driver.go | 3 +- pkg/controller/beat/common/pod_test.go | 8 +-- .../beat/common/stackmon/metricbeat.tpl.yml | 3 +- .../beat/common/stackmon/stackmon.go | 65 +++++++++---------- .../beat/common/stackmon/stackmon_test.go | 9 ++- .../stackmon/monitoring/monitoring_test.go | 44 ++++++------- pkg/controller/common/stackmon/name_test.go | 6 +- .../stackmon/validations/validations_test.go | 18 ++--- .../elasticsearch/stackmon/sidecar.go | 7 +- .../validation/validations_test.go | 50 +++++++------- pkg/controller/kibana/stackmon/sidecar.go | 7 +- pkg/telemetry/telemetry_test.go | 18 ++--- test/e2e/es/stack_monitoring_test.go | 6 +- 31 files changed, 282 insertions(+), 450 deletions(-) create mode 100644 pkg/apis/common/v1/monitoring.go diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index e110f47a4d..fb5e163455 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2364,7 +2364,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - receive log data from this Beats resource. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -2411,7 +2411,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from this Beats resource. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -3670,7 +3670,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - receive log data from this Elasticsearch cluster. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -3717,7 +3717,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -7673,7 +7673,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Kibana. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -7720,7 +7720,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Kibana. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index 8c61cd8225..7c82fb01c3 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15324,7 +15324,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - receive log data from this Beats resource. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -15371,7 +15371,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from this Beats resource. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index 082a8f45fd..cbc6700b17 100644 --- a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -509,7 +509,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - receive log data from this Elasticsearch cluster. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -556,7 +556,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml b/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml index 454da39f5a..396fdd36c7 100644 --- a/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml +++ b/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml @@ -550,7 +550,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Kibana. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -597,7 +597,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Kibana. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 159d46aeb8..15708717c6 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2382,7 +2382,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - receive log data from this Beats resource. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -2429,7 +2429,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from this Beats resource. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -3700,7 +3700,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - receive log data from this Elasticsearch cluster. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -3747,7 +3747,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -7715,7 +7715,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Kibana. + receive log data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -7762,7 +7762,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Kibana. + which receive monitoring data from an associated resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/docs/advanced-topics/stack-monitoring.asciidoc b/docs/advanced-topics/stack-monitoring.asciidoc index 67a0d3bc70..10972fc273 100644 --- a/docs/advanced-topics/stack-monitoring.asciidoc +++ b/docs/advanced-topics/stack-monitoring.asciidoc @@ -82,6 +82,8 @@ spec: NOTE: You can configure an Elasticsearch cluster to monitor itself. +NOTE: If stack monitoring is configured for a Beat, but the cooresponding Elasticsearch cluster is not monitored, the Kibana Stack Monitoring page will not show the Beats data. + IMPORTANT: The monitoring cluster must be managed by ECK in the same Kubernetes cluster as the monitored one. You can send metrics and logs to two different Elasticsearch monitoring clusters. diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index 3bacc070ae..6ac63ce6f4 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -85,7 +85,7 @@ type BeatSpec struct { // Metricbeat and/or Filebeat sidecars are configured and send monitoring data to a // Elasticsearch monitoring cluster running in the same Kubernetes cluster. // +kubebuilder:validation:Optional - Monitoring Monitoring `json:"monitoring,omitempty"` + Monitoring commonv1.Monitoring `json:"monitoring,omitempty"` // RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying DaemonSet or Deployment. RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"` @@ -106,29 +106,6 @@ type DeploymentSpec struct { Strategy appsv1.DeploymentStrategy `json:"strategy,omitempty"` } -type Monitoring struct { - // Metrics holds references to Elasticsearch clusters which receive monitoring data from this Beats resource. - // +kubebuilder:validation:Optional - Metrics MetricsMonitoring `json:"metrics,omitempty"` - // Logs holds references to Elasticsearch clusters which receive log data from this Beats resource. - // +kubebuilder:validation:Optional - Logs LogsMonitoring `json:"logs,omitempty"` -} - -type MetricsMonitoring struct { - // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. - // Due to existing limitations, only a single Elasticsearch cluster is currently supported. - // +kubebuilder:validation:Required - ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` -} - -type LogsMonitoring struct { - // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. - // Due to existing limitations, only a single Elasticsearch cluster is currently supported. - // +kubebuilder:validation:Required - ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` -} - // BeatStatus defines the observed state of a Beat. type BeatStatus struct { // Version of the stack resource currently running. During version upgrades, multiple versions may run diff --git a/pkg/apis/beat/v1beta1/validations_test.go b/pkg/apis/beat/v1beta1/validations_test.go index 7827c30eea..4e823a42d9 100644 --- a/pkg/apis/beat/v1beta1/validations_test.go +++ b/pkg/apis/beat/v1beta1/validations_test.go @@ -159,8 +159,8 @@ func Test_checkAssociations(t *testing.T) { args: args{ b: &Beat{ Spec: BeatSpec{ - Monitoring: Monitoring{ - Metrics: MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, }, }, @@ -174,8 +174,8 @@ func Test_checkAssociations(t *testing.T) { args: args{ b: &Beat{ Spec: BeatSpec{ - Monitoring: Monitoring{ - Logs: LogsMonitoring{ + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, }, }, @@ -271,8 +271,8 @@ func Test_checkMonitoring(t *testing.T) { Type: "filebeat", Version: "8.2.3", DaemonSet: &DaemonSetSpec{}, - Monitoring: Monitoring{ - Metrics: MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { Name: "es", @@ -296,8 +296,8 @@ func Test_checkMonitoring(t *testing.T) { Type: "filebeat", Version: "8.2.3", DaemonSet: &DaemonSetSpec{}, - Monitoring: Monitoring{ - Logs: LogsMonitoring{ + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { Name: "es", @@ -321,8 +321,8 @@ func Test_checkMonitoring(t *testing.T) { Type: "filebeat", Version: "8.2.3", DaemonSet: &DaemonSetSpec{}, - Monitoring: Monitoring{ - Logs: LogsMonitoring{ + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { Name: "es", @@ -330,7 +330,7 @@ func Test_checkMonitoring(t *testing.T) { }, }, }, - Metrics: MetricsMonitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { Name: "es", diff --git a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go index 2f8d5757a3..b9c660d479 100644 --- a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go @@ -260,60 +260,3 @@ func (in *DeploymentSpec) DeepCopy() *DeploymentSpec { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LogsMonitoring) DeepCopyInto(out *LogsMonitoring) { - *out = *in - if in.ElasticsearchRefs != nil { - in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs - *out = make([]v1.ObjectSelector, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoring. -func (in *LogsMonitoring) DeepCopy() *LogsMonitoring { - if in == nil { - return nil - } - out := new(LogsMonitoring) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MetricsMonitoring) DeepCopyInto(out *MetricsMonitoring) { - *out = *in - if in.ElasticsearchRefs != nil { - in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs - *out = make([]v1.ObjectSelector, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoring. -func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { - if in == nil { - return nil - } - out := new(MetricsMonitoring) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Monitoring) DeepCopyInto(out *Monitoring) { - *out = *in - in.Metrics.DeepCopyInto(&out.Metrics) - in.Logs.DeepCopyInto(&out.Logs) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. -func (in *Monitoring) DeepCopy() *Monitoring { - if in == nil { - return nil - } - out := new(Monitoring) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/apis/common/v1/monitoring.go b/pkg/apis/common/v1/monitoring.go new file mode 100644 index 0000000000..3c1aa00029 --- /dev/null +++ b/pkg/apis/common/v1/monitoring.go @@ -0,0 +1,34 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + +package v1 + +// Monitoring holds references to both the metrics, and logs Elasticsearch clusters for +// configuring stack monitoring. +type Monitoring struct { + // Metrics holds references to Elasticsearch clusters which receive monitoring data from an associated resource. + // +kubebuilder:validation:Optional + Metrics MetricsMonitoring `json:"metrics,omitempty"` + // Logs holds references to Elasticsearch clusters which receive log data from an associated resource. + // +kubebuilder:validation:Optional + Logs LogsMonitoring `json:"logs,omitempty"` +} + +// MetricsMonitoring holds a list of Elasticsearch clusters which receive monitoring data from +// associated resources. +type MetricsMonitoring struct { + // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. + // Due to existing limitations, only a single Elasticsearch cluster is currently supported. + // +kubebuilder:validation:Required + ElasticsearchRefs []ObjectSelector `json:"elasticsearchRefs,omitempty"` +} + +// LogsMonitoring holds a list of Elasticsearch clusters which receive logs data from +// associated resources. +type LogsMonitoring struct { + // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. + // Due to existing limitations, only a single Elasticsearch cluster is currently supported. + // +kubebuilder:validation:Required + ElasticsearchRefs []ObjectSelector `json:"elasticsearchRefs,omitempty"` +} diff --git a/pkg/apis/common/v1/zz_generated.deepcopy.go b/pkg/apis/common/v1/zz_generated.deepcopy.go index e9d746265f..605865e4f5 100644 --- a/pkg/apis/common/v1/zz_generated.deepcopy.go +++ b/pkg/apis/common/v1/zz_generated.deepcopy.go @@ -135,6 +135,63 @@ func (in *LocalObjectSelector) DeepCopy() *LocalObjectSelector { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LogsMonitoring) DeepCopyInto(out *LogsMonitoring) { + *out = *in + if in.ElasticsearchRefs != nil { + in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs + *out = make([]ObjectSelector, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoring. +func (in *LogsMonitoring) DeepCopy() *LogsMonitoring { + if in == nil { + return nil + } + out := new(LogsMonitoring) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricsMonitoring) DeepCopyInto(out *MetricsMonitoring) { + *out = *in + if in.ElasticsearchRefs != nil { + in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs + *out = make([]ObjectSelector, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoring. +func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { + if in == nil { + return nil + } + out := new(MetricsMonitoring) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Monitoring) DeepCopyInto(out *Monitoring) { + *out = *in + in.Metrics.DeepCopyInto(&out.Metrics) + in.Logs.DeepCopyInto(&out.Logs) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. +func (in *Monitoring) DeepCopy() *Monitoring { + if in == nil { + return nil + } + out := new(Monitoring) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ObjectSelector) DeepCopyInto(out *ObjectSelector) { *out = *in diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index fc1c35c860..61ae67a73f 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -126,35 +126,12 @@ type ElasticsearchSpec struct { // Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different // Elasticsearch monitoring clusters running in the same Kubernetes cluster. // +kubebuilder:validation:Optional - Monitoring Monitoring `json:"monitoring,omitempty"` + Monitoring commonv1.Monitoring `json:"monitoring,omitempty"` // RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying StatefulSets. RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"` } -type Monitoring struct { - // Metrics holds references to Elasticsearch clusters which receive monitoring data from this Elasticsearch cluster. - // +kubebuilder:validation:Optional - Metrics MetricsMonitoring `json:"metrics,omitempty"` - // Logs holds references to Elasticsearch clusters which receive log data from this Elasticsearch cluster. - // +kubebuilder:validation:Optional - Logs LogsMonitoring `json:"logs,omitempty"` -} - -type MetricsMonitoring struct { - // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. - // Due to existing limitations, only a single Elasticsearch cluster is currently supported. - // +kubebuilder:validation:Required - ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` -} - -type LogsMonitoring struct { - // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. - // Due to existing limitations, only a single Elasticsearch cluster is currently supported. - // +kubebuilder:validation:Required - ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` -} - // VolumeClaimDeletePolicy describes the delete policy for handling PersistentVolumeClaims that hold Elasticsearch data. // Inspired by https://github.com/kubernetes/enhancements/pull/2440 type VolumeClaimDeletePolicy string diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types_test.go b/pkg/apis/elasticsearch/v1/elasticsearch_types_test.go index 6b5349b17e..11373a314a 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types_test.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types_test.go @@ -344,11 +344,11 @@ func Test_AssociationConfs(t *testing.T) { }, }, Spec: ElasticsearchSpec{ - Monitoring: Monitoring{ - Metrics: MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{metricsEsRef}, }, - Logs: LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{ Name: "logs", Namespace: "default"}, diff --git a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go index ae1b4c3ab5..fedf1cfd11 100644 --- a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go +++ b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go @@ -391,63 +391,6 @@ func (in *InProgressOperations) DeepCopy() *InProgressOperations { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LogsMonitoring) DeepCopyInto(out *LogsMonitoring) { - *out = *in - if in.ElasticsearchRefs != nil { - in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs - *out = make([]commonv1.ObjectSelector, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoring. -func (in *LogsMonitoring) DeepCopy() *LogsMonitoring { - if in == nil { - return nil - } - out := new(LogsMonitoring) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MetricsMonitoring) DeepCopyInto(out *MetricsMonitoring) { - *out = *in - if in.ElasticsearchRefs != nil { - in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs - *out = make([]commonv1.ObjectSelector, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoring. -func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { - if in == nil { - return nil - } - out := new(MetricsMonitoring) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Monitoring) DeepCopyInto(out *Monitoring) { - *out = *in - in.Metrics.DeepCopyInto(&out.Metrics) - in.Logs.DeepCopyInto(&out.Logs) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. -func (in *Monitoring) DeepCopy() *Monitoring { - if in == nil { - return nil - } - out := new(Monitoring) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NewNode) DeepCopyInto(out *NewNode) { *out = *in diff --git a/pkg/apis/kibana/v1/kibana_types.go b/pkg/apis/kibana/v1/kibana_types.go index 61b5dddb78..ccbf6ca491 100644 --- a/pkg/apis/kibana/v1/kibana_types.go +++ b/pkg/apis/kibana/v1/kibana_types.go @@ -108,30 +108,7 @@ type KibanaSpec struct { // Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different // Elasticsearch monitoring clusters running in the same Kubernetes cluster. // +kubebuilder:validation:Optional - Monitoring Monitoring `json:"monitoring,omitempty"` -} - -type Monitoring struct { - // Metrics holds references to Elasticsearch clusters which will receive monitoring data from this Kibana. - // +kubebuilder:validation:Optional - Metrics MetricsMonitoring `json:"metrics,omitempty"` - // Logs holds references to Elasticsearch clusters which will receive log data from this Kibana. - // +kubebuilder:validation:Optional - Logs LogsMonitoring `json:"logs,omitempty"` -} - -type MetricsMonitoring struct { - // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. - // Due to existing limitations, only a single Elasticsearch cluster is currently supported. - // +kubebuilder:validation:Required - ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` -} - -type LogsMonitoring struct { - // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. - // Due to existing limitations, only a single Elasticsearch cluster is currently supported. - // +kubebuilder:validation:Required - ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` + Monitoring commonv1.Monitoring `json:"monitoring,omitempty"` } // KibanaStatus defines the observed state of Kibana diff --git a/pkg/apis/kibana/v1/webhook_test.go b/pkg/apis/kibana/v1/webhook_test.go index c42670f412..3190add183 100644 --- a/pkg/apis/kibana/v1/webhook_test.go +++ b/pkg/apis/kibana/v1/webhook_test.go @@ -245,7 +245,7 @@ func TestWebhook(t *testing.T) { t.Helper() ent := mkKibana(uid) ent.Spec.Version = "7.14.0" - ent.Spec.Monitoring = kbv1.Monitoring{Metrics: kbv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns"}}}} + ent.Spec.Monitoring = commonv1.Monitoring{Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns"}}}} ent.Spec.ElasticsearchRef = commonv1.ObjectSelector{Name: "esname", Namespace: "esns"} return serialize(t, ent) }, @@ -258,9 +258,9 @@ func TestWebhook(t *testing.T) { t.Helper() ent := mkKibana(uid) ent.Spec.Version = "7.14.0" - ent.Spec.Monitoring = kbv1.Monitoring{ - Metrics: kbv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname"}}}, - Logs: kbv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, + ent.Spec.Monitoring = commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname"}}}, + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, } ent.Spec.ElasticsearchRef = commonv1.ObjectSelector{Name: "esname", Namespace: "esns"} return serialize(t, ent) @@ -274,7 +274,7 @@ func TestWebhook(t *testing.T) { t.Helper() ent := mkKibana(uid) ent.Spec.Version = "7.13.0" - ent.Spec.Monitoring = kbv1.Monitoring{Metrics: kbv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns"}}}} + ent.Spec.Monitoring = commonv1.Monitoring{Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns"}}}} ent.Spec.ElasticsearchRef = commonv1.ObjectSelector{Name: "esname", Namespace: "esns"} return serialize(t, ent) }, @@ -289,9 +289,9 @@ func TestWebhook(t *testing.T) { t.Helper() ent := mkKibana(uid) ent.Spec.Version = "7.14.0" - ent.Spec.Monitoring = kbv1.Monitoring{ - Metrics: kbv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname", Name: "xx"}}}, - Logs: kbv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, + ent.Spec.Monitoring = commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname", Name: "xx"}}}, + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, } ent.Spec.ElasticsearchRef = commonv1.ObjectSelector{Name: "esname", Namespace: "esns"} return serialize(t, ent) @@ -307,9 +307,9 @@ func TestWebhook(t *testing.T) { t.Helper() ent := mkKibana(uid) ent.Spec.Version = "7.14.0" - ent.Spec.Monitoring = kbv1.Monitoring{ - Metrics: kbv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname"}}}, - Logs: kbv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname", ServiceName: "xx"}}}, + ent.Spec.Monitoring = commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname"}}}, + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname", ServiceName: "xx"}}}, } ent.Spec.ElasticsearchRef = commonv1.ObjectSelector{Name: "esname", Namespace: "esns"} return serialize(t, ent) diff --git a/pkg/apis/kibana/v1/zz_generated.deepcopy.go b/pkg/apis/kibana/v1/zz_generated.deepcopy.go index ac9d550149..18c52d6a58 100644 --- a/pkg/apis/kibana/v1/zz_generated.deepcopy.go +++ b/pkg/apis/kibana/v1/zz_generated.deepcopy.go @@ -209,60 +209,3 @@ func (in *KibanaStatus) DeepCopy() *KibanaStatus { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LogsMonitoring) DeepCopyInto(out *LogsMonitoring) { - *out = *in - if in.ElasticsearchRefs != nil { - in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs - *out = make([]commonv1.ObjectSelector, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoring. -func (in *LogsMonitoring) DeepCopy() *LogsMonitoring { - if in == nil { - return nil - } - out := new(LogsMonitoring) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MetricsMonitoring) DeepCopyInto(out *MetricsMonitoring) { - *out = *in - if in.ElasticsearchRefs != nil { - in, out := &in.ElasticsearchRefs, &out.ElasticsearchRefs - *out = make([]commonv1.ObjectSelector, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoring. -func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { - if in == nil { - return nil - } - out := new(MetricsMonitoring) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Monitoring) DeepCopyInto(out *Monitoring) { - *out = *in - in.Metrics.DeepCopyInto(&out.Metrics) - in.Logs.DeepCopyInto(&out.Logs) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. -func (in *Monitoring) DeepCopy() *Monitoring { - if in == nil { - return nil - } - out := new(Monitoring) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index a91cc7c9bf..24b62b93a1 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -95,38 +95,35 @@ func Test_buildBeatConfig(t *testing.T) { for _, tt := range []struct { name string client k8s.Client - beat func() beatv1beta1.Beat + beat beatv1beta1.Beat managedConfig *settings.CanonicalConfig want *settings.CanonicalConfig wantErr bool }{ { name: "no association, no configs", - beat: func() beatv1beta1.Beat { return beatv1beta1.Beat{} }, + beat: beatv1beta1.Beat{}, }, { name: "no association, user config", - beat: func() beatv1beta1.Beat { - return beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - }} + beat: beatv1beta1.Beat{Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + }, }, want: userCanonicalCfg, }, { name: "no association, managed config", - beat: func() beatv1beta1.Beat { return beatv1beta1.Beat{} }, + beat: beatv1beta1.Beat{}, managedConfig: managedCfg, want: managedCfg, }, { name: "no association, managed and user configs", - beat: func() beatv1beta1.Beat { - return beatv1beta1.Beat{ - Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - }, - } + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + }, }, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg), @@ -134,73 +131,71 @@ func Test_buildBeatConfig(t *testing.T) { { name: "association without ca, no configs", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssoc }, + beat: withAssoc, want: outputYaml, }, { name: "association without ca, user config", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithConfig }, + beat: withAssocWithConfig, want: merge(userCanonicalCfg, outputYaml), }, { name: "association without ca, managed config", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssoc }, + beat: withAssoc, managedConfig: managedCfg, want: merge(managedCfg, outputYaml), }, { name: "association without ca, user and managed configs", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithConfig }, + beat: withAssocWithConfig, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg, outputYaml), }, { name: "association with ca, no configs", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCA }, + beat: withAssocWithCA, want: merge(outputYaml, outputCAYaml), }, { name: "association with ca, user config", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCAWithConfig }, + beat: withAssocWithCAWithConfig, want: merge(userCanonicalCfg, outputYaml, outputCAYaml), }, { name: "association with ca, managed config", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCA }, + beat: withAssocWithCA, managedConfig: managedCfg, want: merge(managedCfg, outputYaml, outputCAYaml), }, { name: "association with ca, user and managed configs", client: clientWithSecret, - beat: func() beatv1beta1.Beat { return withAssocWithCAWithConfig }, + beat: withAssocWithCAWithConfig, managedConfig: managedCfg, want: merge(userCanonicalCfg, managedCfg, outputYaml, outputCAYaml), }, { name: "no association, user config, with metrics monitoring enabled", - beat: func() beatv1beta1.Beat { - return beatv1beta1.Beat{ - Spec: beatv1beta1.BeatSpec{ - Config: userCfg, - Monitoring: beatv1beta1.Monitoring{ - Metrics: beatv1beta1.MetricsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{ - { - Name: "testesref", - Namespace: "test", - }, + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Config: userCfg, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + { + Name: "testesref", + Namespace: "test", }, }, }, }, - } + }, }, want: merge(userCanonicalCfg, settings.MustCanonicalConfig(map[string]bool{"http.enabled": true, "monitoring.enabled": false})), }, @@ -211,7 +206,7 @@ func Test_buildBeatConfig(t *testing.T) { Context: nil, Watches: watches.NewDynamicWatches(), EventRecorder: nil, - Beat: tt.beat(), + Beat: tt.beat, }, tt.managedConfig) diff := tt.want.Diff(settings.MustParseConfig(gotYaml), nil) diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 335df7d003..026a0e98ad 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -12,7 +12,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/reconcile" beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" @@ -104,7 +103,7 @@ func Reconcile( podTemplate, err := buildPodTemplate(params, defaultImage, configHash) if err != nil { if errors.Is(err, beat_stackmon.ErrMonitoringClusterUUIDUnavailable) { - results.WithReconciliationState(reconciler.Requeue.WithReason("ElasticsearchRef UUID unavailable while configuring beats stack monitoring")).WithResult(reconcile.Result{Requeue: true, RequeueAfter: 10 * time.Second}) + results.WithReconciliationState(reconciler.RequeueAfter(10 * time.Second).WithReason("ElasticsearchRef UUID unavailable while configuring Beats stack monitoring")) } return results.WithError(err), params.Status } diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index ed4c8c3c2f..92be33e29d 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -79,8 +79,8 @@ func Test_buildPodTemplate(t *testing.T) { Version: "7.15.0", Config: httpPortCfg, ElasticsearchRef: commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}, - Monitoring: v1beta1.Monitoring{ - Metrics: v1beta1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { Name: "testes", @@ -88,7 +88,7 @@ func Test_buildPodTemplate(t *testing.T) { }, }, }, - Logs: v1beta1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ { Name: "testes", @@ -149,7 +149,6 @@ func Test_buildPodTemplate(t *testing.T) { args: args{ initialHash: newHash("foobar"), // SHA224 for foobar is de76c3e567fca9d246f5f8d3b2e704a38c3c5e258988ab525f941db8 params: DriverParams{ - Context: context.Background(), Watches: watches.NewDynamicWatches(), Client: k8s.NewFakeClient(), Beat: v1beta1.Beat{ @@ -196,7 +195,6 @@ func Test_buildPodTemplate(t *testing.T) { args: args{ initialHash: newHash("foobar"), params: DriverParams{ - Context: context.Background(), Watches: watches.NewDynamicWatches(), Client: k8s.NewFakeClient( // Secret maintained by the operator diff --git a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml index 96d48288ba..cd554438db 100644 --- a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml +++ b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml @@ -6,7 +6,6 @@ metricbeat.modules: period: 10s hosts: ["{{ .URL }}"] xpack.enabled: true -{{if .ClusterUUID }} monitoring.cluster_uuid: "{{ .ClusterUUID }}" -{{end}} + # Elasticsearch output configuration is generated and added here diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index 8a29e6928f..9ed3154810 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -34,20 +34,14 @@ var ( // ErrMonitoringClusterUUIDUnavailable will be returned when the UUID for the Beat ElasticsearchRef cluster // has not yet been assigned a UUID. This could happen on a newly created Elasticsearch cluster. - ErrMonitoringClusterUUIDUnavailable = errors.New("beats stack monitoring cluster uuid is unavailable") + ErrMonitoringClusterUUIDUnavailable = errors.New("cluster UUID for Beats stack monitoring is unavailable") ) func Filebeat(ctx context.Context, client k8s.Client, resource monitoring.HasMonitoring, version string) (stackmon.BeatSidecar, error) { - filebeat, err := stackmon.NewFileBeatSidecar(ctx, client, resource, version, filebeatConfig, nil) - if err != nil { - return stackmon.BeatSidecar{}, err - } - - return filebeat, nil + return stackmon.NewFileBeatSidecar(ctx, client, resource, version, filebeatConfig, nil) } func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, version string) (stackmon.BeatSidecar, error) { - finalTemplate := metricbeatConfigTemplate config, err := settings.NewCanonicalConfigFrom(beat.Spec.Config.Data) if err != nil { return stackmon.BeatSidecar{}, err @@ -69,32 +63,33 @@ func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, vers httpPort = portData } - if err := beat.ElasticsearchRef().IsValid(); err == nil { - var es esv1.Elasticsearch - if err := client.Get(ctx, beat.ElasticsearchRef().WithDefaultNamespace(beat.Namespace).NamespacedName(), &es); err != nil { - return stackmon.BeatSidecar{}, err - } - uuid, ok := es.Annotations[bootstrap.ClusterUUIDAnnotationName] - if !ok { - // returning specific error here so this operation can be retried. - return stackmon.BeatSidecar{}, ErrMonitoringClusterUUIDUnavailable - } - var tmpl *template.Template - if tmpl, err = template.New("beat_stack_monitoring").Parse(metricbeatConfigTemplate); err != nil { - return stackmon.BeatSidecar{}, fmt.Errorf("while parsing template for beats stack monitoring configuration: %w", err) - } - var tpl bytes.Buffer - data := struct { - ClusterUUID string - URL string - }{ - ClusterUUID: uuid, - URL: fmt.Sprintf("http://localhost:%d", httpPort), - } - if err := tmpl.Execute(&tpl, data); err != nil { - return stackmon.BeatSidecar{}, fmt.Errorf("while templating beats stack monitoring configuration: %w", err) - } - finalTemplate = tpl.String() + if err := beat.ElasticsearchRef().IsValid(); err != nil { + return stackmon.BeatSidecar{}, err + } + + var es esv1.Elasticsearch + if err := client.Get(ctx, beat.ElasticsearchRef().WithDefaultNamespace(beat.Namespace).NamespacedName(), &es); err != nil { + return stackmon.BeatSidecar{}, err + } + uuid, ok := es.Annotations[bootstrap.ClusterUUIDAnnotationName] + if !ok { + // returning specific error here so this operation can be retried. + return stackmon.BeatSidecar{}, ErrMonitoringClusterUUIDUnavailable + } + var beatTemplate *template.Template + if beatTemplate, err = template.New("beat_stack_monitoring").Parse(metricbeatConfigTemplate); err != nil { + return stackmon.BeatSidecar{}, fmt.Errorf("while parsing template for beats stack monitoring configuration: %w", err) + } + var byteBuffer bytes.Buffer + data := struct { + ClusterUUID string + URL string + }{ + ClusterUUID: uuid, + URL: fmt.Sprintf("http://localhost:%d", httpPort), + } + if err := beatTemplate.Execute(&byteBuffer, data); err != nil { + return stackmon.BeatSidecar{}, fmt.Errorf("while templating beats stack monitoring configuration: %w", err) } return stackmon.NewMetricBeatSidecar( @@ -103,7 +98,7 @@ func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, vers commonv1.BeatMonitoringAssociationType, beat, version, - finalTemplate, + byteBuffer.String(), common_name.NewNamer("beat"), fmt.Sprintf("http://localhost:%d", httpPort), "", diff --git a/pkg/controller/beat/common/stackmon/stackmon_test.go b/pkg/controller/beat/common/stackmon/stackmon_test.go index 2ae291909a..0bcb2f7082 100644 --- a/pkg/controller/beat/common/stackmon/stackmon_test.go +++ b/pkg/controller/beat/common/stackmon/stackmon_test.go @@ -101,6 +101,9 @@ output: ObjectMeta: metav1.ObjectMeta{ Name: "beat-beat-monitoring-metricbeat-config", Namespace: "test", + // *note* the following is a bug in the common/stackmon/NewMetricBeatSidecar func + // and this type should be the underlying CRD type, not hard-coded to Elasticsearch. + // https://github.com/elastic/cloud-on-k8s/issues/5967 Labels: map[string]string{ "common.k8s.elastic.co/type": "elasticsearch", "elasticsearch.k8s.elastic.co/cluster-name": "beat", @@ -150,11 +153,11 @@ output: Config: &v1.Config{ Data: map[string]interface{}{}, }, - Monitoring: v1beta1.Monitoring{ - Metrics: v1beta1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []v1.ObjectSelector{{Name: "esmonitoring"}}, }, - Logs: v1beta1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []v1.ObjectSelector{{Name: "esmonitoring"}}, }, }, diff --git a/pkg/controller/common/stackmon/monitoring/monitoring_test.go b/pkg/controller/common/stackmon/monitoring/monitoring_test.go index b7f2e17fcc..92b8f56122 100644 --- a/pkg/controller/common/stackmon/monitoring/monitoring_test.go +++ b/pkg/controller/common/stackmon/monitoring/monitoring_test.go @@ -18,8 +18,8 @@ var ( monitoringEsRef = commonv1.ObjectSelector{Name: "monitoring", Namespace: "observability"} sampleMonitoredEs = esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{monitoringEsRef}, }, }, @@ -46,8 +46,8 @@ func TestIsReconcilable(t *testing.T) { name: "with metrics monitoring defined but not configured", es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, }, @@ -59,8 +59,8 @@ func TestIsReconcilable(t *testing.T) { name: "with metrics monitoring defined and configured", es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, }, @@ -75,8 +75,8 @@ func TestIsReconcilable(t *testing.T) { name: "with logs monitoring defined and configured", es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Logs: esv1.LogsMonitoring{ + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, }, @@ -91,11 +91,11 @@ func TestIsReconcilable(t *testing.T) { name: "with metrics and logs monitoring defined and partially configured", es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, - Logs: esv1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m2", Namespace: "b"}}, }, }, @@ -110,11 +110,11 @@ func TestIsReconcilable(t *testing.T) { name: "with metrics and logs monitoring defined and partially configured", es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, - Logs: esv1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m2", Namespace: "b"}}, }, }, @@ -129,11 +129,11 @@ func TestIsReconcilable(t *testing.T) { name: "with logs and metrics monitoring defined and configured", es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, - Logs: esv1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, }, @@ -148,18 +148,18 @@ func TestIsReconcilable(t *testing.T) { name: "with distinct logs and metrics monitoring defined and configured", es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, - Logs: esv1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m2", Namespace: "b"}}, }, }, }, AssocConfs: map[commonv1.ObjectSelector]commonv1.AssociationConf{ - commonv1.ObjectSelector{Name: "m1", Namespace: "b"}: {URL: "https://m1.xyz", AuthSecretName: "-"}, - commonv1.ObjectSelector{Name: "m2", Namespace: "b"}: {URL: "https://m2.xyz", AuthSecretName: "-"}, + {Name: "m1", Namespace: "b"}: {URL: "https://m1.xyz", AuthSecretName: "-"}, + {Name: "m2", Namespace: "b"}: {URL: "https://m2.xyz", AuthSecretName: "-"}, }, }, want: true, diff --git a/pkg/controller/common/stackmon/name_test.go b/pkg/controller/common/stackmon/name_test.go index 845e9fd25b..ef3a051165 100644 --- a/pkg/controller/common/stackmon/name_test.go +++ b/pkg/controller/common/stackmon/name_test.go @@ -32,13 +32,13 @@ func TestCAVolumeName(t *testing.T) { }, Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{ Name: "extremely-long-and-unwieldy-name-that-exceeds-the-limit", Namespace: "extremely-long-and-unwieldy-namespace-that-exceeds-the-limit"}}, }, - Logs: esv1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{ Name: "extremely-long-and-unwieldy-name-that-exceeds-the-limit", Namespace: "extremely-long-and-unwieldy-namespace-that-exceeds-the-limit"}}, diff --git a/pkg/controller/common/stackmon/validations/validations_test.go b/pkg/controller/common/stackmon/validations/validations_test.go index b3142c7c2d..0679d08b0c 100644 --- a/pkg/controller/common/stackmon/validations/validations_test.go +++ b/pkg/controller/common/stackmon/validations/validations_test.go @@ -33,11 +33,11 @@ func TestValidate(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, - Logs: esv1.LogsMonitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, }, @@ -50,8 +50,8 @@ func TestValidate(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.13.1", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, }, }, @@ -64,8 +64,8 @@ func TestValidate(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ {Name: "m1", Namespace: "b"}, {Name: "m2", Namespace: "c"}, @@ -81,8 +81,8 @@ func TestValidate(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Logs: esv1.LogsMonitoring{ + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ ElasticsearchRefs: []commonv1.ObjectSelector{ {Name: "m1", Namespace: "b"}, {Name: "m2", Namespace: "c"}, diff --git a/pkg/controller/elasticsearch/stackmon/sidecar.go b/pkg/controller/elasticsearch/stackmon/sidecar.go index d374a1bfb8..65abe350f1 100644 --- a/pkg/controller/elasticsearch/stackmon/sidecar.go +++ b/pkg/controller/elasticsearch/stackmon/sidecar.go @@ -53,12 +53,7 @@ func Metricbeat(ctx context.Context, client k8s.Client, es esv1.Elasticsearch) ( } func Filebeat(ctx context.Context, client k8s.Client, es esv1.Elasticsearch) (stackmon.BeatSidecar, error) { - filebeat, err := stackmon.NewFileBeatSidecar(ctx, client, &es, es.Spec.Version, filebeatConfig, nil) - if err != nil { - return stackmon.BeatSidecar{}, err - } - - return filebeat, nil + return stackmon.NewFileBeatSidecar(ctx, client, &es, es.Spec.Version, filebeatConfig, nil) } // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers diff --git a/pkg/controller/elasticsearch/validation/validations_test.go b/pkg/controller/elasticsearch/validation/validations_test.go index 9a97c9fe74..8418e39a66 100644 --- a/pkg/controller/elasticsearch/validation/validations_test.go +++ b/pkg/controller/elasticsearch/validation/validations_test.go @@ -571,7 +571,7 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname"}}}}, + Monitoring: commonv1.Monitoring{Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname"}}}}, }, }, expectErrors: false, @@ -581,7 +581,7 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns"}}}}, + Monitoring: commonv1.Monitoring{Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns"}}}}, }, }, expectErrors: false, @@ -591,7 +591,7 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", ServiceName: "esmonsvc"}}}}, + Monitoring: commonv1.Monitoring{Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", ServiceName: "esmonsvc"}}}}, }, }, expectErrors: false, @@ -601,7 +601,7 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns", ServiceName: "esmonsvc"}}}}, + Monitoring: commonv1.Monitoring{Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "esmonname", Namespace: "esmonns", ServiceName: "esmonsvc"}}}}, }, }, expectErrors: false, @@ -611,7 +611,7 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "esmonname"}}}}, + Monitoring: commonv1.Monitoring{Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "esmonname"}}}}, }, }, expectErrors: false, @@ -621,7 +621,7 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "esmonns"}}}}, + Monitoring: commonv1.Monitoring{Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "esmonns"}}}}, }, }, expectErrors: false, @@ -631,9 +631,9 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "es1monname", Namespace: "esmonns1"}}}, - Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "es2monname", Namespace: "esmonns2"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "es1monname", Namespace: "esmonns1"}}}, + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "es2monname", Namespace: "esmonns2"}}}, }, }, }, @@ -644,9 +644,9 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname"}}}, - Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es1monname"}}}, + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, }, }, }, @@ -657,9 +657,9 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "es1monname", Namespace: "esmonns"}}}, - Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "es1monname", Namespace: "esmonns"}}}, + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname"}}}, }, }, }, @@ -670,8 +670,8 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Namespace: "esmonns"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Namespace: "esmonns"}}}, }, }, }, @@ -682,8 +682,8 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{ServiceName: "esmonsvc"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{ServiceName: "esmonsvc"}}}, }, }, }, @@ -694,8 +694,8 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "xx", Name: "es1monname"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "xx", Name: "es1monname"}}}, }, }, }, @@ -706,8 +706,8 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname", Namespace: "esmonns"}}}, + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname", Namespace: "esmonns"}}}, }, }, }, @@ -718,8 +718,8 @@ func Test_validAssociations(t *testing.T) { es: esv1.Elasticsearch{ Spec: esv1.ElasticsearchSpec{ Version: "7.14.0", - Monitoring: esv1.Monitoring{ - Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname", ServiceName: "xx"}}}, + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "es2monname", ServiceName: "xx"}}}, }, }, }, diff --git a/pkg/controller/kibana/stackmon/sidecar.go b/pkg/controller/kibana/stackmon/sidecar.go index fb9cf71643..197076c309 100644 --- a/pkg/controller/kibana/stackmon/sidecar.go +++ b/pkg/controller/kibana/stackmon/sidecar.go @@ -79,12 +79,7 @@ func Metricbeat(ctx context.Context, client k8s.Client, kb kbv1.Kibana) (stackmo } func Filebeat(ctx context.Context, client k8s.Client, kb kbv1.Kibana) (stackmon.BeatSidecar, error) { - filebeat, err := stackmon.NewFileBeatSidecar(ctx, client, &kb, kb.Spec.Version, filebeatConfig, nil) - if err != nil { - return stackmon.BeatSidecar{}, err - } - - return filebeat, nil + return stackmon.NewFileBeatSidecar(ctx, client, &kb, kb.Spec.Version, filebeatConfig, nil) } // WithMonitoring updates the Kibana Pod template builder to deploy Metricbeat and Filebeat in sidecar containers diff --git a/pkg/telemetry/telemetry_test.go b/pkg/telemetry/telemetry_test.go index 158c2698fd..d6630dd209 100644 --- a/pkg/telemetry/telemetry_test.go +++ b/pkg/telemetry/telemetry_test.go @@ -183,9 +183,9 @@ func TestNewReporter(t *testing.T) { Name: "monitored", }, Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, }, }, Status: esv1.ElasticsearchStatus{ @@ -434,8 +434,8 @@ func TestReporter_report(t *testing.T) { Name: "monitored", }, Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, }, }, Status: esv1.ElasticsearchStatus{ @@ -448,8 +448,8 @@ func TestReporter_report(t *testing.T) { Name: "monitored2", }, Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, }, }, Status: esv1.ElasticsearchStatus{ @@ -485,8 +485,8 @@ func TestReporter_report(t *testing.T) { Name: "monitored", }, Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Logs: esv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, + Monitoring: commonv1.Monitoring{ + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, }, }, Status: esv1.ElasticsearchStatus{ diff --git a/test/e2e/es/stack_monitoring_test.go b/test/e2e/es/stack_monitoring_test.go index 3d59204fad..7c83fddc1a 100644 --- a/test/e2e/es/stack_monitoring_test.go +++ b/test/e2e/es/stack_monitoring_test.go @@ -188,9 +188,9 @@ func TestExternalESStackMonitoring(t *testing.T) { } monitoringEsRef := []commonv1.ObjectSelector{{SecretName: extRefSecretName}} - es.Spec.Monitoring = esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: monitoringEsRef}, - Logs: esv1.LogsMonitoring{ElasticsearchRefs: monitoringEsRef}, + es.Spec.Monitoring = commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: monitoringEsRef}, + Logs: commonv1.LogsMonitoring{ElasticsearchRefs: monitoringEsRef}, } return k.Client.Update(context.Background(), &es) From 23ae156110a356cedde29520b043497726bb0f04 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 23 Aug 2022 09:36:13 -0500 Subject: [PATCH 46/64] Add Keyed field to struct to pass linter. --- pkg/apis/beat/v1beta1/validations_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/beat/v1beta1/validations_test.go b/pkg/apis/beat/v1beta1/validations_test.go index 4e823a42d9..34c25a2aa2 100644 --- a/pkg/apis/beat/v1beta1/validations_test.go +++ b/pkg/apis/beat/v1beta1/validations_test.go @@ -161,7 +161,7 @@ func Test_checkAssociations(t *testing.T) { Spec: BeatSpec{ Monitoring: commonv1.Monitoring{ Metrics: commonv1.MetricsMonitoring{ - []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, + ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, }, }, }, @@ -176,7 +176,7 @@ func Test_checkAssociations(t *testing.T) { Spec: BeatSpec{ Monitoring: commonv1.Monitoring{ Logs: commonv1.LogsMonitoring{ - []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, + ElasticsearchRefs: []commonv1.ObjectSelector{{SecretName: "bli", Namespace: "blub"}}, }, }, }, From 2975684e42da421455704ae59bfedf3faf6460a5 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 23 Aug 2022 10:04:27 -0500 Subject: [PATCH 47/64] Fix moved struct from esv1 -> commonv1 in stackmon tests --- pkg/controller/common/stackmon/config_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/common/stackmon/config_test.go b/pkg/controller/common/stackmon/config_test.go index ab32da7475..cda29bb15c 100644 --- a/pkg/controller/common/stackmon/config_test.go +++ b/pkg/controller/common/stackmon/config_test.go @@ -72,8 +72,8 @@ param2: value2 }, }, Spec: esv1.ElasticsearchSpec{ - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, + Monitoring: commonv1.Monitoring{ + Metrics: commonv1.MetricsMonitoring{ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "monitoring"}}}, }, }, }, From 2182d4022e84ae9098d1e211316031ac1eeb0057 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 23 Aug 2022 11:20:37 -0500 Subject: [PATCH 48/64] Update api docs --- docs/reference/api-docs.asciidoc | 224 ++++++++----------------------- 1 file changed, 59 insertions(+), 165 deletions(-) diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 27f1923289..c045c0014d 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -316,7 +316,7 @@ BeatSpec defines the desired state of a Beat. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`daemonSet`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-daemonsetspec[$$DaemonSetSpec$$]__ | DaemonSet specifies the Beat should be deployed as a DaemonSet, and allows providing its spec. Cannot be used along with `deployment`. If both are absent a default for the Type is used. | *`deployment`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-deploymentspec[$$DeploymentSpec$$]__ | Deployment specifies the Beat should be deployed as a Deployment, and allows providing its spec. Cannot be used along with `daemonSet`. If both are absent a default for the Type is used. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured and send monitoring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured and send monitoring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying DaemonSet or Deployment. |=== @@ -358,58 +358,6 @@ BeatSpec defines the desired state of a Beat. |=== -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-logsmonitoring"] -=== LogsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-metricsmonitoring"] -=== MetricsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-monitoring"] -=== Monitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-beatspec[$$BeatSpec$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which receive monitoring data from this Beats resource. -| *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which receive log data from this Beats resource. -|=== - - [id="{anchor_prefix}-common-k8s-elastic-co-v1"] == common.k8s.elastic.co/v1 @@ -524,6 +472,60 @@ LocalObjectSelector defines a reference to a Kubernetes object corresponding to |=== +[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-logsmonitoring"] +=== LogsMonitoring + +LogsMonitoring holds a list of Elasticsearch clusters which receive logs data from associated resources. + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +|=== + + +[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-metricsmonitoring"] +=== MetricsMonitoring + +MetricsMonitoring holds a list of Elasticsearch clusters which receive monitoring data from associated resources. + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +|=== + + +[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring"] +=== Monitoring + +Monitoring holds references to both the metrics, and logs Elasticsearch clusters for configuring stack monitoring. + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-beatspec[$$BeatSpec$$] +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-elasticsearchspec[$$ElasticsearchSpec$$] +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-kibanaspec[$$KibanaSpec$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which receive monitoring data from an associated resource. +| *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which receive log data from an associated resource. +|=== + + [id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector"] === ObjectSelector @@ -537,13 +539,9 @@ ObjectSelector defines a reference to a Kubernetes object which can be an Elasti - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-enterprisesearch-v1-enterprisesearchspec[$$EnterpriseSearchSpec$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-enterprisesearch-v1beta1-enterprisesearchspec[$$EnterpriseSearchSpec$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-kibanaspec[$$KibanaSpec$$] -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-logsmonitoring[$$LogsMonitoring$$] -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$] -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-logsmonitoring[$$LogsMonitoring$$] +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-logsmonitoring[$$LogsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-maps-v1alpha1-mapsspec[$$MapsSpec$$] -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-metricsmonitoring[$$MetricsMonitoring$$] -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$] -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-metricsmonitoring[$$MetricsMonitoring$$] +- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-metricsmonitoring[$$MetricsMonitoring$$] - xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-agent-v1alpha1-output[$$Output$$] **** @@ -1101,7 +1099,7 @@ ElasticsearchSpec holds the specification of an Elasticsearch cluster. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (for ex. a remote Elasticsearch cluster) in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`remoteClusters`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-remotecluster[$$RemoteCluster$$] array__ | RemoteClusters enables you to establish uni-directional connections to a remote Elasticsearch cluster. | *`volumeClaimDeletePolicy`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-volumeclaimdeletepolicy[$$VolumeClaimDeletePolicy$$]__ | VolumeClaimDeletePolicy sets the policy for handling deletion of PersistentVolumeClaims for all NodeSets. Possible values are DeleteOnScaledownOnly and DeleteOnScaledownAndClusterDeletion. Defaults to DeleteOnScaledownAndClusterDeletion. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship log and monitoring data of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship log and monitoring data of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying StatefulSets. |=== @@ -1166,58 +1164,6 @@ InProgressOperations provides details about in progress changes applied by the o |=== -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-logsmonitoring"] -=== LogsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-metricsmonitoring"] -=== MetricsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-monitoring"] -=== Monitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-elasticsearchspec[$$ElasticsearchSpec$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which receive monitoring data from this Elasticsearch cluster. -| *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which receive log data from this Elasticsearch cluster. -|=== - - [id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-newnode"] === NewNode @@ -1728,59 +1674,7 @@ KibanaSpec holds the specification of a Kibana instance. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying Deployment. | *`secureSettings`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-secretsource[$$SecretSource$$]__ | SecureSettings is a list of references to Kubernetes secrets containing sensitive configuration options for Kibana. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (for ex. Elasticsearch) in a different namespace. Can only be used if ECK is enforcing RBAC on references. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship log and monitoring data of this Kibana. See https://www.elastic.co/guide/en/kibana/current/xpack-monitoring.html. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-logsmonitoring"] -=== LogsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-metricsmonitoring"] -=== MetricsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring"] -=== Monitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-kibanaspec[$$KibanaSpec$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which will receive monitoring data from this Kibana. -| *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which will receive log data from this Kibana. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship log and monitoring data of this Kibana. See https://www.elastic.co/guide/en/kibana/current/xpack-monitoring.html. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. |=== From ca26311b46d1666209bebde556e88047d75e6824 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 23 Aug 2022 12:59:45 -0500 Subject: [PATCH 49/64] Update test for new ssl verification mode for beats --- pkg/controller/beat/common/stackmon/stackmon_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/controller/beat/common/stackmon/stackmon_test.go b/pkg/controller/beat/common/stackmon/stackmon_test.go index 0bcb2f7082..330145eae0 100644 --- a/pkg/controller/beat/common/stackmon/stackmon_test.go +++ b/pkg/controller/beat/common/stackmon/stackmon_test.go @@ -93,6 +93,8 @@ output: hosts: - es-metrics-monitoring-url password: es-password + ssl: + verification_mode: certificate username: es-user ` beatSidecarFixture := stackmon.BeatSidecar{ From 0e37cbb38eb3379458b9915af4498e0e9762f02c Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Sat, 27 Aug 2022 10:38:28 -0500 Subject: [PATCH 50/64] wip --- pkg/controller/beat/common/config.go | 6 ++++++ pkg/controller/beat/common/stackmon/filebeat.yml | 8 ++++++++ pkg/controller/beat/common/stackmon/metricbeat.tpl.yml | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 5dcd199b72..77e5702fdf 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -114,10 +114,16 @@ func buildBeatConfig( // if metrics monitoring is enabled, then // 1. enable the metrics http endpoint for the metricsbeat sidecar to consume // 2. disable internal metrics monitoring endpoint + // 3. disable stderr, and syslog monitoring + // 4. enable files monitoring, and configure path if monitoring.IsMetricsDefined(¶ms.Beat) { if err = cfg.MergeWith(settings.MustCanonicalConfig(map[string]interface{}{ "http.enabled": true, "monitoring.enabled": false, + "logging.to_stderr": false, + "logging.to_syslog": false, + "logging.to_files": true, + "logging.files.path": "/var/log/beat", })); err != nil { return nil, err } diff --git a/pkg/controller/beat/common/stackmon/filebeat.yml b/pkg/controller/beat/common/stackmon/filebeat.yml index c5983f3ca6..d1ce4630ea 100644 --- a/pkg/controller/beat/common/stackmon/filebeat.yml +++ b/pkg/controller/beat/common/stackmon/filebeat.yml @@ -4,6 +4,14 @@ filebeat: id: filebeatlogs paths: - /var/log/*.log + - /var/log/beat/* - /usr/share/filebeat/data/registry/filebeat/*.json +path.home: /usr/share/filebeat-sidecar +path.config: /usr/share/filebeat-sidecar/config +path.data: /usr/share/filebeat-sidecar/data +path.logs: /usr/share/filebeat-sidecar/logs +http.enabled: false +monitoring.enabled: false + # Elasticsearch output configuration is generated and added here diff --git a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml index cd554438db..8ca402a615 100644 --- a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml +++ b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml @@ -6,6 +6,7 @@ metricbeat.modules: period: 10s hosts: ["{{ .URL }}"] xpack.enabled: true -monitoring.cluster_uuid: "{{ .ClusterUUID }}" +http.enabled: false +monitoring.enabled: false # Elasticsearch output configuration is generated and added here From fe83cee656f900f1d6f27e121e4786d7c57b92f2 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 1 Sep 2022 15:26:18 -0500 Subject: [PATCH 51/64] Use unix sockets for beat metrics gather when stack monitoring is enabled. Add back cluster_uuid in metricbeat sidecar config. Add shared volume between beats when metrics stack monitoring is enabled to shared unix socket. Update tests to account for unix sockets, and new shared volume --- pkg/controller/beat/common/config.go | 11 +++- pkg/controller/beat/common/config_test.go | 22 ++++++- pkg/controller/beat/common/pod.go | 6 ++ pkg/controller/beat/common/pod_test.go | 6 +- .../beat/common/stackmon/metricbeat.tpl.yml | 1 + .../beat/common/stackmon/stackmon.go | 66 +++++++++++-------- .../beat/common/stackmon/stackmon_test.go | 16 ++++- 7 files changed, 89 insertions(+), 39 deletions(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 77e5702fdf..6f6501cc7f 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -14,6 +14,7 @@ import ( beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/association" + "github.com/elastic/cloud-on-k8s/v2/pkg/controller/beat/common/stackmon" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/labels" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/reconciler" @@ -113,12 +114,16 @@ func buildBeatConfig( // if metrics monitoring is enabled, then // 1. enable the metrics http endpoint for the metricsbeat sidecar to consume - // 2. disable internal metrics monitoring endpoint - // 3. disable stderr, and syslog monitoring - // 4. enable files monitoring, and configure path + // 2. set http.host to a unix socket + // 3. disable http.port, as unix sockets are used to communicate + // 4. disable internal metrics monitoring endpoint + // 5. disable stderr, and syslog monitoring + // 6. enable files monitoring, and configure path if monitoring.IsMetricsDefined(¶ms.Beat) { if err = cfg.MergeWith(settings.MustCanonicalConfig(map[string]interface{}{ "http.enabled": true, + "http.host": stackmon.GetStackMonitoringSocketURL(¶ms.Beat), + "http.port": nil, "monitoring.enabled": false, "logging.to_stderr": false, "logging.to_syslog": false, diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 24b62b93a1..4013c6b22f 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -183,7 +183,12 @@ func Test_buildBeatConfig(t *testing.T) { { name: "no association, user config, with metrics monitoring enabled", beat: beatv1beta1.Beat{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beat", + Namespace: "test", + }, Spec: beatv1beta1.BeatSpec{ + Type: "filebeat", Config: userCfg, Monitoring: commonv1.Monitoring{ Metrics: commonv1.MetricsMonitoring{ @@ -197,7 +202,22 @@ func Test_buildBeatConfig(t *testing.T) { }, }, }, - want: merge(userCanonicalCfg, settings.MustCanonicalConfig(map[string]bool{"http.enabled": true, "monitoring.enabled": false})), + want: merge(userCanonicalCfg, settings.MustCanonicalConfig(map[string]interface{}{ + "http": map[string]interface{}{ + "enabled": true, + "host": "unix:///var/shared/filebeat-test-beat.sock", + "port": nil, + }, + "monitoring.enabled": false, + "logging": map[string]interface{}{ + "files": map[string]string{ + "path": "/var/log/beat", + }, + "to_files": true, + "to_stderr": false, + "to_syslog": false, + }, + })), }, } { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index e6c4f6197b..c8891a5eac 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -160,6 +160,12 @@ func buildPodTemplate( if _, err := reconciler.ReconcileSecret(params.Context, params.Client, sideCar.ConfigSecret, ¶ms.Beat); err != nil { return podTemplate, err } + // Add shared volume for Unix socket between containers. + volumeMounts = append(volumeMounts, corev1.VolumeMount{ + Name: "shared-data", + ReadOnly: false, + MountPath: "/var/shared", + }) volumes = append(volumes, sideCar.Volumes...) sideCars = append(sideCars, sideCar.Container) } diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 92be33e29d..3b8d464349 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -9,7 +9,6 @@ import ( "fmt" "hash" "hash/fnv" - "net/url" "reflect" "testing" @@ -78,6 +77,7 @@ func Test_buildPodTemplate(t *testing.T) { Spec: v1beta1.BeatSpec{ Version: "7.15.0", Config: httpPortCfg, + Type: "filebeat", ElasticsearchRef: commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}, Monitoring: commonv1.Monitoring{ Metrics: commonv1.MetricsMonitoring{ @@ -341,9 +341,7 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co var cfg metricbeatConfig assert.NoError(t, yaml.Unmarshal(data, &cfg)) - u, err := url.Parse(cfg.MetricBeat.Modules[0].Hosts[0]) - require.NoError(t, err) - assert.Equal(t, "3033", u.Port()) + assert.Equal(t, fmt.Sprintf("http+unix:///var/shared/%s-%s-%s.sock", beat.Spec.Type, beat.Namespace, beat.Name), cfg.MetricBeat.Modules[0].Hosts[0]) } if monitoring.IsLogsDefined(&beat) { assert.True(t, containersContains(pod.Spec.Containers, "logs-monitoring-sidecar")) diff --git a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml index 8ca402a615..62d61b4f28 100644 --- a/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml +++ b/pkg/controller/beat/common/stackmon/metricbeat.tpl.yml @@ -8,5 +8,6 @@ metricbeat.modules: xpack.enabled: true http.enabled: false monitoring.enabled: false +monitoring.cluster_uuid: "{{ .ClusterUUID }}" # Elasticsearch output configuration is generated and added here diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index 9ed3154810..4b5739f081 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -12,11 +12,12 @@ import ( "fmt" "text/template" + corev1 "k8s.io/api/core/v1" + "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" common_name "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/name" - "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/settings" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/stackmon/monitoring" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/elasticsearch/bootstrap" @@ -42,27 +43,6 @@ func Filebeat(ctx context.Context, client k8s.Client, resource monitoring.HasMon } func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, version string) (stackmon.BeatSidecar, error) { - config, err := settings.NewCanonicalConfigFrom(beat.Spec.Config.Data) - if err != nil { - return stackmon.BeatSidecar{}, err - } - - // Default metricbeat monitoring port - var httpPort uint64 = 5066 - var p httpPortSetting - if err := config.Unpack(&p); err != nil { - return stackmon.BeatSidecar{}, err - } - - // if http.port is set in beats configuration, then use the port. - if p.PortData != nil { - portData, ok := p.PortData.(uint64) - if !ok { - return stackmon.BeatSidecar{}, fmt.Errorf("while configuring beats stack monitoring: 'http.port' must be an int") - } - httpPort = portData - } - if err := beat.ElasticsearchRef().IsValid(); err != nil { return stackmon.BeatSidecar{}, err } @@ -76,8 +56,8 @@ func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, vers // returning specific error here so this operation can be retried. return stackmon.BeatSidecar{}, ErrMonitoringClusterUUIDUnavailable } - var beatTemplate *template.Template - if beatTemplate, err = template.New("beat_stack_monitoring").Parse(metricbeatConfigTemplate); err != nil { + beatTemplate, err := template.New("beat_stack_monitoring").Parse(metricbeatConfigTemplate) + if err != nil { return stackmon.BeatSidecar{}, fmt.Errorf("while parsing template for beats stack monitoring configuration: %w", err) } var byteBuffer bytes.Buffer @@ -86,13 +66,15 @@ func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, vers URL string }{ ClusterUUID: uuid, - URL: fmt.Sprintf("http://localhost:%d", httpPort), + // https://www.elastic.co/guide/en/beats/metricbeat/current/configuration-metricbeat.html#module-http-config-options + // Beat module http options require "http+" to be appended to unix sockets. + URL: fmt.Sprintf("http+%s", GetStackMonitoringSocketURL(beat)), } if err := beatTemplate.Execute(&byteBuffer, data); err != nil { return stackmon.BeatSidecar{}, fmt.Errorf("while templating beats stack monitoring configuration: %w", err) } - return stackmon.NewMetricBeatSidecar( + sidecar, err := stackmon.NewMetricBeatSidecar( ctx, client, commonv1.BeatMonitoringAssociationType, @@ -100,13 +82,39 @@ func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, vers version, byteBuffer.String(), common_name.NewNamer("beat"), - fmt.Sprintf("http://localhost:%d", httpPort), + GetStackMonitoringSocketURL(beat), "", "", false, ) + if err != nil { + return stackmon.BeatSidecar{}, err + } + + // Add shared volume for Unix socket between containers. + sidecar.Container.VolumeMounts = append(sidecar.Container.VolumeMounts, corev1.VolumeMount{ + Name: "shared-data", + MountPath: "/var/shared", + ReadOnly: false, + }) + sidecar.Volumes = append(sidecar.Volumes, corev1.Volume{ + Name: "shared-data", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }) + + return sidecar, nil } -type httpPortSetting struct { - PortData interface{} `config:"http.port"` +// GetStackMonitoringSocketURL will return a path to a Unix socket that will be used to expose and query metrics. +// Unix sockets are used instead of network ports to avoid situations where "hostNetwork: true" is enabled on multiple +// Beat daemonsets, along with stack monitoring, which will cause 2 pods to try and bind to the same port on the +// Node's host network, which will cause bind errors. (bind: address already in use) +func GetStackMonitoringSocketURL(beat *v1beta1.Beat) string { + // TODO: Enable when Beats as containers in Windows is supported: https://github.com/elastic/beats/issues/16814 + // if runtime.GOOS == "windows" { + // return fmt.Sprintf("npipe:///%s-%s-%s.sock", beat.Spec.Type, beat.GetNamespace(), beat.GetName()) + // } + return fmt.Sprintf("unix:///var/shared/%s-%s-%s.sock", beat.Spec.Type, beat.GetNamespace(), beat.GetName()) } diff --git a/pkg/controller/beat/common/stackmon/stackmon_test.go b/pkg/controller/beat/common/stackmon/stackmon_test.go index 330145eae0..4f7ca2a885 100644 --- a/pkg/controller/beat/common/stackmon/stackmon_test.go +++ b/pkg/controller/beat/common/stackmon/stackmon_test.go @@ -73,12 +73,19 @@ func TestMetricBeat(t *testing.T) { ReadOnly: true, MountPath: "/etc/metricbeat-config", }, + { + Name: "shared-data", + ReadOnly: false, + MountPath: "/var/shared", + }, }, } - beatYml := `metricbeat: + beatYml := `http: + enabled: false +metricbeat: modules: - hosts: - - http://localhost:5066 + - http+unix:///var/shared/metricbeat-test-beat.sock metricsets: - stats - state @@ -88,6 +95,7 @@ func TestMetricBeat(t *testing.T) { enabled: true monitoring: cluster_uuid: abcd1234 + enabled: false output: elasticsearch: hosts: @@ -120,6 +128,10 @@ output: Name: "beat-metricbeat-config", VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "beat-beat-monitoring-metricbeat-config", Optional: pointer.BoolPtr(false)}}, }, + { + Name: "shared-data", + VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}, + }, }, } esFixture := esv1.Elasticsearch{ From 44a3d1e43523a3ab5e5d7ef8eb13d51bcbc91aeb Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 1 Sep 2022 15:31:00 -0500 Subject: [PATCH 52/64] Regenerate api docs --- docs/reference/api-docs.asciidoc | 110 +------------------------------ 1 file changed, 3 insertions(+), 107 deletions(-) diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 28cd2f79db..c5f6a30834 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -485,7 +485,7 @@ LogsMonitoring holds a list of Elasticsearch clusters which receive logs data fr [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$] array__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. |=== @@ -502,7 +502,7 @@ MetricsMonitoring holds a list of Elasticsearch clusters which receive monitorin [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$] array__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. |=== @@ -1164,58 +1164,6 @@ InProgressOperations provides details about in progress changes applied by the o |=== -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-logsmonitoring"] -=== LogsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$] array__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-metricsmonitoring"] -=== MetricsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$] array__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-monitoring"] -=== Monitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-elasticsearchspec[$$ElasticsearchSpec$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which receive monitoring data from this Elasticsearch cluster. -| *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which receive log data from this Elasticsearch cluster. -|=== - - [id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-elasticsearch-v1-newnode"] === NewNode @@ -1726,59 +1674,7 @@ KibanaSpec holds the specification of a Kibana instance. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying Deployment. | *`secureSettings`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-secretsource[$$SecretSource$$] array__ | SecureSettings is a list of references to Kubernetes secrets containing sensitive configuration options for Kibana. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (for ex. Elasticsearch) in a different namespace. Can only be used if ECK is enforcing RBAC on references. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship log and monitoring data of this Kibana. See https://www.elastic.co/guide/en/kibana/current/xpack-monitoring.html. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-logsmonitoring"] -=== LogsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$] array__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-metricsmonitoring"] -=== MetricsMonitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring[$$Monitoring$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-objectselector[$$ObjectSelector$$] array__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster. Due to existing limitations, only a single Elasticsearch cluster is currently supported. -|=== - - -[id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-monitoring"] -=== Monitoring - - - -.Appears In: -**** -- xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-kibanaspec[$$KibanaSpec$$] -**** - -[cols="25a,75a", options="header"] -|=== -| Field | Description -| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which will receive monitoring data from this Kibana. -| *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-kibana-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which will receive log data from this Kibana. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship log and monitoring data of this Kibana. See https://www.elastic.co/guide/en/kibana/current/xpack-monitoring.html. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. |=== From 8864c1ccd0df5bde6089987a7307d563b4c224e1 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Tue, 6 Sep 2022 09:14:00 -0500 Subject: [PATCH 53/64] Docs and CRD wording updates --- config/crds/v1/all-crds.yaml | 6 +++--- config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml | 2 +- .../bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml | 2 +- config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml | 2 +- .../charts/eck-operator-crds/templates/all-crds.yaml | 6 +++--- docs/advanced-topics/stack-monitoring.asciidoc | 2 +- docs/reference/api-docs.asciidoc | 2 +- pkg/apis/common/v1/monitoring.go | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index fb5e163455..311aeeae50 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2411,7 +2411,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -3717,7 +3717,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -7720,7 +7720,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index 7c82fb01c3..d797f16ef3 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15371,7 +15371,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index cbc6700b17..7e04c63f35 100644 --- a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -556,7 +556,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml b/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml index 396fdd36c7..cdfafa0caa 100644 --- a/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml +++ b/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml @@ -597,7 +597,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 15708717c6..10ea83c1a5 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2429,7 +2429,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -3747,7 +3747,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -7762,7 +7762,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which receive monitoring data from an associated resource. + which receive monitoring data from this resource. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of diff --git a/docs/advanced-topics/stack-monitoring.asciidoc b/docs/advanced-topics/stack-monitoring.asciidoc index 10972fc273..12ad45459b 100644 --- a/docs/advanced-topics/stack-monitoring.asciidoc +++ b/docs/advanced-topics/stack-monitoring.asciidoc @@ -82,7 +82,7 @@ spec: NOTE: You can configure an Elasticsearch cluster to monitor itself. -NOTE: If stack monitoring is configured for a Beat, but the cooresponding Elasticsearch cluster is not monitored, the Kibana Stack Monitoring page will not show the Beats data. +NOTE: If stack monitoring is configured for a Beat, but the corresponding Elasticsearch cluster is not monitored, the Kibana Stack Monitoring page will not show the Beats data. IMPORTANT: The monitoring cluster must be managed by ECK in the same Kubernetes cluster as the monitored one. diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index c5f6a30834..54c2e73026 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -521,7 +521,7 @@ Monitoring holds references to both the metrics, and logs Elasticsearch clusters [cols="25a,75a", options="header"] |=== | Field | Description -| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which receive monitoring data from an associated resource. +| *`metrics`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which receive monitoring data from this resource. | *`logs`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which receive log data from an associated resource. |=== diff --git a/pkg/apis/common/v1/monitoring.go b/pkg/apis/common/v1/monitoring.go index 3c1aa00029..a243afac36 100644 --- a/pkg/apis/common/v1/monitoring.go +++ b/pkg/apis/common/v1/monitoring.go @@ -7,7 +7,7 @@ package v1 // Monitoring holds references to both the metrics, and logs Elasticsearch clusters for // configuring stack monitoring. type Monitoring struct { - // Metrics holds references to Elasticsearch clusters which receive monitoring data from an associated resource. + // Metrics holds references to Elasticsearch clusters which receive monitoring data from this resource. // +kubebuilder:validation:Optional Metrics MetricsMonitoring `json:"metrics,omitempty"` // Logs holds references to Elasticsearch clusters which receive log data from an associated resource. From 42535c03e0161e345caa67c8f8f608a7da8f9161 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 12 Sep 2022 09:57:57 -0500 Subject: [PATCH 54/64] Attempt remove specific path in filebeat. --- pkg/controller/beat/common/stackmon/filebeat.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/controller/beat/common/stackmon/filebeat.yml b/pkg/controller/beat/common/stackmon/filebeat.yml index d1ce4630ea..639ead2cbc 100644 --- a/pkg/controller/beat/common/stackmon/filebeat.yml +++ b/pkg/controller/beat/common/stackmon/filebeat.yml @@ -7,10 +7,6 @@ filebeat: - /var/log/beat/* - /usr/share/filebeat/data/registry/filebeat/*.json -path.home: /usr/share/filebeat-sidecar -path.config: /usr/share/filebeat-sidecar/config -path.data: /usr/share/filebeat-sidecar/data -path.logs: /usr/share/filebeat-sidecar/logs http.enabled: false monitoring.enabled: false From 53e7dd16ec32e2f19e75820d3b7defcf4ade7fa8 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 12 Sep 2022 10:17:22 -0500 Subject: [PATCH 55/64] Always uppercase stack monitoring in docs. comment changes per review. remove newlines per review. --- docs/advanced-topics/stack-monitoring.asciidoc | 4 ++-- .../managing-compute-resources.asciidoc | 2 +- docs/reference/api-docs.asciidoc | 2 +- pkg/apis/beat/v1beta1/beat_types.go | 2 +- pkg/controller/association/controller/beat_monitoring.go | 2 +- pkg/controller/beat/common/pod_test.go | 4 +--- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/advanced-topics/stack-monitoring.asciidoc b/docs/advanced-topics/stack-monitoring.asciidoc index 12ad45459b..339dc9beec 100644 --- a/docs/advanced-topics/stack-monitoring.asciidoc +++ b/docs/advanced-topics/stack-monitoring.asciidoc @@ -11,7 +11,7 @@ endif::[] You can enable link:https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html[Stack Monitoring] on Elasticsearch, Kibana and Beats to collect and ship their metrics and logs to a dedicated monitoring cluster. -To enable stack monitoring, simply reference the monitoring Elasticsearch cluster in the `spec.monitoring` section of their specification. +To enable Stack Monitoring, simply reference the monitoring Elasticsearch cluster in the `spec.monitoring` section of their specification. [source,yaml,subs="attributes,callouts"] ---- @@ -82,7 +82,7 @@ spec: NOTE: You can configure an Elasticsearch cluster to monitor itself. -NOTE: If stack monitoring is configured for a Beat, but the corresponding Elasticsearch cluster is not monitored, the Kibana Stack Monitoring page will not show the Beats data. +NOTE: If Stack Monitoring is configured for a Beat, but the corresponding Elasticsearch cluster is not monitored, the Kibana Stack Monitoring page will not show the Beats data. IMPORTANT: The monitoring cluster must be managed by ECK in the same Kubernetes cluster as the monitored one. diff --git a/docs/orchestrating-elastic-stack-applications/managing-compute-resources.asciidoc b/docs/orchestrating-elastic-stack-applications/managing-compute-resources.asciidoc index 3f49ea46cb..8358842e54 100644 --- a/docs/orchestrating-elastic-stack-applications/managing-compute-resources.asciidoc +++ b/docs/orchestrating-elastic-stack-applications/managing-compute-resources.asciidoc @@ -328,7 +328,7 @@ image::images/metrics-explorer-cpu.png[cgroup CPU perforamce chart] [id="{p}-monitor-compute-resources-stack-monitoring"] ==== Monitoring Elasticsearch CPU using Stack Monitoring -If link:{p}-stack-monitoring.html[stack monitoring] is enabled, the pressure applied by the CPU cgroup controller to an Elasticsearch node can be evaluated from the *Stack Monitoring* page in Kibana. +If link:{p}-stack-monitoring.html[Stack Monitoring] is enabled, the pressure applied by the CPU cgroup controller to an Elasticsearch node can be evaluated from the *Stack Monitoring* page in Kibana. . On the *Stack Monitoring* page select the Elasticsearch node you want to monitor. . Select the *Advanced* tab. diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 54c2e73026..f012afad61 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -509,7 +509,7 @@ MetricsMonitoring holds a list of Elasticsearch clusters which receive monitorin [id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring"] === Monitoring -Monitoring holds references to both the metrics, and logs Elasticsearch clusters for configuring stack monitoring. +Monitoring holds references to both the metrics, and logs Elasticsearch clusters for configuring Stack Monitoring. .Appears In: **** diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index 6ac63ce6f4..6214df83d0 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -82,7 +82,7 @@ type BeatSpec struct { Deployment *DeploymentSpec `json:"deployment,omitempty"` // Monitoring enables you to collect and ship logs and metrics for this Beat. - // Metricbeat and/or Filebeat sidecars are configured and send monitoring data to a + // Metricbeat and/or Filebeat sidecars are configured and send monitoring data to an // Elasticsearch monitoring cluster running in the same Kubernetes cluster. // +kubebuilder:validation:Optional Monitoring commonv1.Monitoring `json:"monitoring,omitempty"` diff --git a/pkg/controller/association/controller/beat_monitoring.go b/pkg/controller/association/controller/beat_monitoring.go index 26fb9f7da1..35697bbb03 100644 --- a/pkg/controller/association/controller/beat_monitoring.go +++ b/pkg/controller/association/controller/beat_monitoring.go @@ -21,7 +21,7 @@ import ( ) // AddBeatMonitoring reconciles an association between Beat and Elasticsearch clusters for Stack Monitoring. -// Beat is configured to use internal collectors to send its monitoring data to the Elasticsearch referenced in the association. +// Beat is configured with sidecars to send its monitoring data to the Elasticsearch referenced in the association. func AddBeatMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ AssociatedObjTemplate: func() commonv1.Associated { return &beatv1b1.Beat{} }, diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 3b8d464349..118552da90 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -350,10 +350,8 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co // metricbeatConfig represents the MetricBeat configuration for testing purposes. // -// example: -// +// Example: // metricbeat: -// // modules: // - hosts: // - http://example.com:3033 From a14eb20b0e9716f3610c4a5e19dc691f5dc99146 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 12 Sep 2022 15:09:52 -0500 Subject: [PATCH 56/64] running make docs, and go vet --- config/crds/v1/all-crds.yaml | 4 ++-- config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml | 4 ++-- .../charts/eck-operator-crds/templates/all-crds.yaml | 4 ++-- docs/reference/api-docs.asciidoc | 4 ++-- pkg/controller/beat/common/pod_test.go | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 311aeeae50..c4eac51ea4 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2359,8 +2359,8 @@ spec: monitoring: description: Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured - and send monitoring data to a Elasticsearch monitoring cluster running - in the same Kubernetes cluster. + and send monitoring data to an Elasticsearch monitoring cluster + running in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml index d797f16ef3..7c435bfd9e 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -15319,8 +15319,8 @@ spec: monitoring: description: Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured - and send monitoring data to a Elasticsearch monitoring cluster running - in the same Kubernetes cluster. + and send monitoring data to an Elasticsearch monitoring cluster + running in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml index 10ea83c1a5..df22cf880f 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds.yaml @@ -2377,8 +2377,8 @@ spec: monitoring: description: Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured - and send monitoring data to a Elasticsearch monitoring cluster running - in the same Kubernetes cluster. + and send monitoring data to an Elasticsearch monitoring cluster + running in the same Kubernetes cluster. properties: logs: description: Logs holds references to Elasticsearch clusters which diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index f012afad61..27168f115f 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -316,7 +316,7 @@ BeatSpec defines the desired state of a Beat. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`daemonSet`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-daemonsetspec[$$DaemonSetSpec$$]__ | DaemonSet specifies the Beat should be deployed as a DaemonSet, and allows providing its spec. Cannot be used along with `deployment`. If both are absent a default for the Type is used. | *`deployment`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-beat-v1beta1-deploymentspec[$$DeploymentSpec$$]__ | Deployment specifies the Beat should be deployed as a Deployment, and allows providing its spec. Cannot be used along with `daemonSet`. If both are absent a default for the Type is used. -| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured and send monitoring data to a Elasticsearch monitoring cluster running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to collect and ship logs and metrics for this Beat. Metricbeat and/or Filebeat sidecars are configured and send monitoring data to an Elasticsearch monitoring cluster running in the same Kubernetes cluster. | *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying DaemonSet or Deployment. |=== @@ -509,7 +509,7 @@ MetricsMonitoring holds a list of Elasticsearch clusters which receive monitorin [id="{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-monitoring"] === Monitoring -Monitoring holds references to both the metrics, and logs Elasticsearch clusters for configuring Stack Monitoring. +Monitoring holds references to both the metrics, and logs Elasticsearch clusters for configuring stack monitoring. .Appears In: **** diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 118552da90..7059797017 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -352,6 +352,7 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co // // Example: // metricbeat: +// // modules: // - hosts: // - http://example.com:3033 From e3f965d7a615bbfde1cb7fd79d9ffd0528b9e97a Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 14 Sep 2022 10:26:41 -0500 Subject: [PATCH 57/64] Do not log when ES cluster UUID isn't yet available, just emit event. When primary beat is running as root, also run sidecars as root to be able to read socket. Tests around sidecars running as root. --- pkg/controller/beat/common/driver.go | 2 +- pkg/controller/beat/common/pod.go | 34 +++++ pkg/controller/beat/common/pod_test.go | 177 ++++++++++++++++++++++++- 3 files changed, 211 insertions(+), 2 deletions(-) diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 026a0e98ad..c338fc2f85 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -105,7 +105,7 @@ func Reconcile( if errors.Is(err, beat_stackmon.ErrMonitoringClusterUUIDUnavailable) { results.WithReconciliationState(reconciler.RequeueAfter(10 * time.Second).WithReason("ElasticsearchRef UUID unavailable while configuring Beats stack monitoring")) } - return results.WithError(err), params.Status + return results, params.Status } var reconcileResults *reconciler.Results reconcileResults, params.Status = reconcilePodVehicle(podTemplate, params) diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index c8891a5eac..8d23ed9e00 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -10,7 +10,9 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/utils/pointer" + beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" beat_stackmon "github.com/elastic/cloud-on-k8s/v2/pkg/controller/beat/common/stackmon" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/container" @@ -146,6 +148,11 @@ func buildPodTemplate( return podTemplate, err } volumes = append(volumes, sideCar.Volumes...) + if runningAsRoot(params.Beat) { + sideCar.Container.SecurityContext = &corev1.SecurityContext{ + RunAsUser: pointer.Int64(0), + } + } sideCars = append(sideCars, sideCar.Container) } @@ -167,6 +174,11 @@ func buildPodTemplate( MountPath: "/var/shared", }) volumes = append(volumes, sideCar.Volumes...) + if runningAsRoot(params.Beat) { + sideCar.Container.SecurityContext = &corev1.SecurityContext{ + RunAsUser: pointer.Int64(0), + } + } sideCars = append(sideCars, sideCar.Container) } @@ -192,6 +204,28 @@ func buildPodTemplate( return builder.PodTemplate, nil } +func runningAsRoot(beat beatv1beta1.Beat) bool { + if beat.Spec.DaemonSet != nil { + for _, container := range beat.Spec.DaemonSet.PodTemplate.Spec.Containers { + if container.SecurityContext != nil && container.SecurityContext.RunAsUser != nil { + if *container.SecurityContext.RunAsUser == 0 { + return true + } + } + } + } + if beat.Spec.Deployment != nil { + for _, container := range beat.Spec.Deployment.PodTemplate.Spec.Containers { + if container.SecurityContext != nil && container.SecurityContext.RunAsUser != nil { + if *container.SecurityContext.RunAsUser == 0 { + return true + } + } + } + } + return false +} + func createDataVolume(dp DriverParams) volume.VolumeLike { dataMountPath := fmt.Sprintf(DataPathTemplate, dp.Beat.Spec.Type) hostDataPath := fmt.Sprintf(DataMountPathTemplate, dp.Beat.Namespace, dp.Beat.Name, dp.Beat.Spec.Type) diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 7059797017..62b08d5362 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -19,8 +19,10 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/pointer" "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" + beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" commonv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v2/pkg/controller/common/container" @@ -97,6 +99,20 @@ func Test_buildPodTemplate(t *testing.T) { }, }, }, + DaemonSet: &beatv1beta1.DaemonSetSpec{ + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "filebeat", + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointer.Int64(0), + }, + }, + }, + }, + }, + }, }} beatWithMonitoring.MonitoringAssociation(commonv1.ObjectSelector{Name: "testes", Namespace: "ns"}).SetAssociationConf(&commonv1.AssociationConf{ AuthSecretName: "secret", @@ -333,7 +349,6 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co // ensure the metricsbeat sidecar exists assert.True(t, containersContains(pod.Spec.Containers, "metrics-monitoring-sidecar")) - // ensure that the beat's metrics port can be set, and used in the sidecar var secret corev1.Secret assert.NoError(t, client.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("%s-beat-monitoring-metricbeat-config", beat.Name), Namespace: beat.Namespace}, &secret)) data, ok := secret.Data["metricbeat.yml"] @@ -342,9 +357,25 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co var cfg metricbeatConfig assert.NoError(t, yaml.Unmarshal(data, &cfg)) assert.Equal(t, fmt.Sprintf("http+unix:///var/shared/%s-%s-%s.sock", beat.Spec.Type, beat.Namespace, beat.Name), cfg.MetricBeat.Modules[0].Hosts[0]) + if runningAsRoot(beat) { + for _, container := range pod.Spec.Containers { + if container.Name == "metrics-monitoring-sidecar" { + require.NotNil(t, container.SecurityContext) + assert.Equal(t, int64(0), *container.SecurityContext.RunAsUser) + } + } + } } if monitoring.IsLogsDefined(&beat) { assert.True(t, containersContains(pod.Spec.Containers, "logs-monitoring-sidecar")) + if runningAsRoot(beat) { + for _, container := range pod.Spec.Containers { + if container.Name == "logs-monitoring-sidecar" { + require.NotNil(t, container.SecurityContext) + assert.Equal(t, int64(0), *container.SecurityContext.RunAsUser) + } + } + } } } @@ -379,3 +410,147 @@ func newHash(initialData string) hash.Hash32 { _, _ = dataHash.Write([]byte(initialData)) return dataHash } + +func Test_runningAsRoot(t *testing.T) { + tests := []struct { + name string + beat beatv1beta1.Beat + want bool + }{ + { + name: "beat deployment running as root should return true", + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Deployment: &beatv1beta1.DeploymentSpec{ + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "filebeat", + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointer.Int64(0), + }, + }, + }, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "beat daemonset running as root should return true", + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + DaemonSet: &beatv1beta1.DaemonSetSpec{ + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "filebeat", + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointer.Int64(0), + }, + }, + }, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "beat deployment running as non-root should return false", + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Deployment: &beatv1beta1.DeploymentSpec{ + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "filebeat", + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointer.Int64(1), + }, + }, + }, + }, + }, + }, + }, + }, + want: false, + }, + { + name: "beat daemonset running as non-root should return false", + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + DaemonSet: &beatv1beta1.DaemonSetSpec{ + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "filebeat", + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointer.Int64(1), + }, + }, + }, + }, + }, + }, + }, + }, + want: false, + }, + { + name: "beat deployment with no security context should return false", + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + Deployment: &beatv1beta1.DeploymentSpec{ + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "filebeat", + SecurityContext: nil, + }, + }, + }, + }, + }, + }, + }, + want: false, + }, + { + name: "beat daemonset with no security context should return false", + beat: beatv1beta1.Beat{ + Spec: beatv1beta1.BeatSpec{ + DaemonSet: &beatv1beta1.DaemonSetSpec{ + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "filebeat", + SecurityContext: nil, + }, + }, + }, + }, + }, + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := runningAsRoot(tt.beat); got != tt.want { + t.Errorf("runningAsRoot() = %v, want %v", got, tt.want) + } + }) + } +} From ed042317e0c7843699929993859630a4774eda99 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 15 Sep 2022 08:29:09 -0500 Subject: [PATCH 58/64] add shared volume for filebeat logs consumption --- pkg/controller/beat/common/config.go | 2 +- pkg/controller/beat/common/pod.go | 6 ++++++ .../beat/common/stackmon/filebeat.yml | 2 +- .../beat/common/stackmon/stackmon.go | 19 ++++++++++++++++++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 6f6501cc7f..743e0b0580 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -128,7 +128,7 @@ func buildBeatConfig( "logging.to_stderr": false, "logging.to_syslog": false, "logging.to_files": true, - "logging.files.path": "/var/log/beat", + "logging.files.path": "/usr/share/filebeat/logs", })); err != nil { return nil, err } diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index 8d23ed9e00..a8f56b4fa5 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -147,6 +147,12 @@ func buildPodTemplate( if _, err := reconciler.ReconcileSecret(params.Context, params.Client, sideCar.ConfigSecret, ¶ms.Beat); err != nil { return podTemplate, err } + // Add shared volume for logs consumption. + volumeMounts = append(volumeMounts, corev1.VolumeMount{ + Name: "filebeat-logs", + ReadOnly: false, + MountPath: "/usr/share/filebeat/logs", + }) volumes = append(volumes, sideCar.Volumes...) if runningAsRoot(params.Beat) { sideCar.Container.SecurityContext = &corev1.SecurityContext{ diff --git a/pkg/controller/beat/common/stackmon/filebeat.yml b/pkg/controller/beat/common/stackmon/filebeat.yml index 639ead2cbc..0dae3b55ae 100644 --- a/pkg/controller/beat/common/stackmon/filebeat.yml +++ b/pkg/controller/beat/common/stackmon/filebeat.yml @@ -4,7 +4,7 @@ filebeat: id: filebeatlogs paths: - /var/log/*.log - - /var/log/beat/* + - /usr/share/filebeat/logs/* - /usr/share/filebeat/data/registry/filebeat/*.json http.enabled: false diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index 4b5739f081..934b3edc2c 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -39,7 +39,24 @@ var ( ) func Filebeat(ctx context.Context, client k8s.Client, resource monitoring.HasMonitoring, version string) (stackmon.BeatSidecar, error) { - return stackmon.NewFileBeatSidecar(ctx, client, resource, version, filebeatConfig, nil) + sidecar, err := stackmon.NewFileBeatSidecar(ctx, client, resource, version, filebeatConfig, nil) + if err != nil { + return stackmon.BeatSidecar{}, err + } + + // Add shared volume for logs consumption. + sidecar.Container.VolumeMounts = append(sidecar.Container.VolumeMounts, corev1.VolumeMount{ + Name: "filebeat-logs", + MountPath: "/usr/share/filbeat/logs", + ReadOnly: false, + }) + sidecar.Volumes = append(sidecar.Volumes, corev1.Volume{ + Name: "filebeat-logs", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }) + return sidecar, nil } func MetricBeat(ctx context.Context, client k8s.Client, beat *v1beta1.Beat, version string) (stackmon.BeatSidecar, error) { From 0f99ccb25eb9be0a28e679ae43a41e6b14431b4e Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 15 Sep 2022 12:08:52 -0500 Subject: [PATCH 59/64] correct spelling in beat/*/stackmon.go Co-authored-by: Thibault Richard --- pkg/controller/beat/common/stackmon/stackmon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/beat/common/stackmon/stackmon.go b/pkg/controller/beat/common/stackmon/stackmon.go index 934b3edc2c..0a671806b0 100644 --- a/pkg/controller/beat/common/stackmon/stackmon.go +++ b/pkg/controller/beat/common/stackmon/stackmon.go @@ -47,7 +47,7 @@ func Filebeat(ctx context.Context, client k8s.Client, resource monitoring.HasMon // Add shared volume for logs consumption. sidecar.Container.VolumeMounts = append(sidecar.Container.VolumeMounts, corev1.VolumeMount{ Name: "filebeat-logs", - MountPath: "/usr/share/filbeat/logs", + MountPath: "/usr/share/filebeat/logs", ReadOnly: false, }) sidecar.Volumes = append(sidecar.Volumes, corev1.Volume{ From f3bf6afa40a8b6c7fd921d30f31ac67994220e30 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 15 Sep 2022 12:53:24 -0500 Subject: [PATCH 60/64] Ensure Beat doesn't contain '-e' startup option when log stack monitoring is enabled. --- pkg/controller/beat/common/pod.go | 10 ++++++++-- pkg/controller/beat/common/pod_test.go | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index a8f56b4fa5..4ad7941d61 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -200,14 +200,20 @@ func buildPodTemplate( WithAnnotations(annotations). WithResources(defaultResources). WithDockerImage(spec.Image, container.ImageRepository(defaultImage, spec.Version)). - WithArgs("-e", "-c", ConfigMountPath). WithVolumes(volumes...). WithVolumeMounts(volumeMounts...). WithInitContainers(initContainers...). WithInitContainerDefaults(). WithContainers(sideCars...) - return builder.PodTemplate, nil + // If logs monitoring is enabled, do not include the "-e" startup option for the Beat + // so that it does not log only to stderr, and writes log file for filebeat to consume. + if monitoring.IsLogsDefined(¶ms.Beat) { + builder = builder.WithArgs("-c", ConfigMountPath) + return builder.PodTemplate, nil + } + + return builder.WithArgs("-e", "-c", ConfigMountPath).PodTemplate, nil } func runningAsRoot(beat beatv1beta1.Beat) bool { diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 62b08d5362..9d91fb728e 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -20,6 +20,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/utils/pointer" + "k8s.io/utils/strings/slices" "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" beatv1beta1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/beat/v1beta1" @@ -376,6 +377,11 @@ func assertMonitoring(t *testing.T, client k8s.Client, beat v1beta1.Beat, pod co } } } + assert.False( + t, + slices.Contains(pod.Spec.Containers[0].Args, "-e"), + "container args %v should not contain '-e' when logs stack monitoring is enabled", pod.Spec.Containers[0].Args, + ) } } From bebdf6ec6fa3d67251d40d4cf5f0746e462b3e09 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Mon, 19 Sep 2022 09:09:15 -0500 Subject: [PATCH 61/64] Fix beat configuration test for stackmon being enabled. --- pkg/controller/beat/common/config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/beat/common/config_test.go b/pkg/controller/beat/common/config_test.go index 4013c6b22f..12ddd961ca 100644 --- a/pkg/controller/beat/common/config_test.go +++ b/pkg/controller/beat/common/config_test.go @@ -211,7 +211,7 @@ func Test_buildBeatConfig(t *testing.T) { "monitoring.enabled": false, "logging": map[string]interface{}{ "files": map[string]string{ - "path": "/var/log/beat", + "path": "/usr/share/filebeat/logs", }, "to_files": true, "to_stderr": false, From 52cd829cc6259cc1bdbd81158f845318bcd384f6 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 21 Sep 2022 11:09:55 -0500 Subject: [PATCH 62/64] Ensure "-e" argument to *beat is removed if provided in podtemplate container args when stack monitoring is enabled. Update test to ensure that it's removed. --- pkg/controller/beat/common/pod.go | 16 ++++++++++++++-- pkg/controller/beat/common/pod_test.go | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index 4ad7941d61..49b8a9f884 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -206,9 +206,13 @@ func buildPodTemplate( WithInitContainerDefaults(). WithContainers(sideCars...) - // If logs monitoring is enabled, do not include the "-e" startup option for the Beat - // so that it does not log only to stderr, and writes log file for filebeat to consume. + // If logs monitoring is enabled, remove the "-e" argument from the main container + // if it exists, and do not include the "-e" startup option for the Beat so that + // it does not log only to stderr, and writes log file for filebeat to consume. if monitoring.IsLogsDefined(¶ms.Beat) { + if main := builder.MainContainer(); main != nil { + removeLogToStderrOption(main) + } builder = builder.WithArgs("-c", ConfigMountPath) return builder.PodTemplate, nil } @@ -216,6 +220,14 @@ func buildPodTemplate( return builder.WithArgs("-e", "-c", ConfigMountPath).PodTemplate, nil } +func removeLogToStderrOption(container *corev1.Container) { + for i, arg := range container.Args { + if arg == "-e" { + container.Args = append(container.Args[:i], container.Args[i+1:]...) + } + } +} + func runningAsRoot(beat beatv1beta1.Beat) bool { if beat.Spec.DaemonSet != nil { for _, container := range beat.Spec.DaemonSet.PodTemplate.Spec.Containers { diff --git a/pkg/controller/beat/common/pod_test.go b/pkg/controller/beat/common/pod_test.go index 9d91fb728e..d8d64d481c 100644 --- a/pkg/controller/beat/common/pod_test.go +++ b/pkg/controller/beat/common/pod_test.go @@ -109,6 +109,8 @@ func Test_buildPodTemplate(t *testing.T) { SecurityContext: &corev1.SecurityContext{ RunAsUser: pointer.Int64(0), }, + // The "-e" in these arguments should be removed + Args: []string{"-e", "-c", "/etc/beat.yml", "-system.hostfs=/hostfs"}, }, }, }, From 0cd89e263070815065d7b56682ec4539d783b9bd Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Wed, 21 Sep 2022 14:04:12 -0500 Subject: [PATCH 63/64] Add documentation for the '-e' filebeat option being automatically removed when logs stack monitoring is enabled. --- docs/advanced-topics/stack-monitoring.asciidoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/advanced-topics/stack-monitoring.asciidoc b/docs/advanced-topics/stack-monitoring.asciidoc index 339dc9beec..5736e40dfb 100644 --- a/docs/advanced-topics/stack-monitoring.asciidoc +++ b/docs/advanced-topics/stack-monitoring.asciidoc @@ -84,6 +84,8 @@ NOTE: You can configure an Elasticsearch cluster to monitor itself. NOTE: If Stack Monitoring is configured for a Beat, but the corresponding Elasticsearch cluster is not monitored, the Kibana Stack Monitoring page will not show the Beats data. +NOTE: If Logs Stack Monitoring is configured for a Beat, and custom container arguments (`podTemplate.spec.containers[].args`) include `-e`, which enables logging to stderr and disables log file output, this argument will be removed from the Pod to allow the filebeat sidecar to consume the Beat's log files. + IMPORTANT: The monitoring cluster must be managed by ECK in the same Kubernetes cluster as the monitored one. You can send metrics and logs to two different Elasticsearch monitoring clusters. From 0658e37bc8bcd2bf3f9a75328edcb6e24accc017 Mon Sep 17 00:00:00 2001 From: Michael Montgomery Date: Thu, 22 Sep 2022 10:29:10 -0500 Subject: [PATCH 64/64] uppercase Filebeat Co-authored-by: Thibault Richard --- docs/advanced-topics/stack-monitoring.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-topics/stack-monitoring.asciidoc b/docs/advanced-topics/stack-monitoring.asciidoc index 5736e40dfb..cded98a268 100644 --- a/docs/advanced-topics/stack-monitoring.asciidoc +++ b/docs/advanced-topics/stack-monitoring.asciidoc @@ -84,7 +84,7 @@ NOTE: You can configure an Elasticsearch cluster to monitor itself. NOTE: If Stack Monitoring is configured for a Beat, but the corresponding Elasticsearch cluster is not monitored, the Kibana Stack Monitoring page will not show the Beats data. -NOTE: If Logs Stack Monitoring is configured for a Beat, and custom container arguments (`podTemplate.spec.containers[].args`) include `-e`, which enables logging to stderr and disables log file output, this argument will be removed from the Pod to allow the filebeat sidecar to consume the Beat's log files. +NOTE: If Logs Stack Monitoring is configured for a Beat, and custom container arguments (`podTemplate.spec.containers[].args`) include `-e`, which enables logging to stderr and disables log file output, this argument will be removed from the Pod to allow the Filebeat sidecar to consume the Beat's log files. IMPORTANT: The monitoring cluster must be managed by ECK in the same Kubernetes cluster as the monitored one.