From 2c1619a9dfaa81276aca635bfe454916e0054754 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 27 May 2021 23:56:01 +0200 Subject: [PATCH 01/83] Stack monitoring for Elasticsearch --- cmd/manager/main.go | 2 + pkg/apis/common/v1/association.go | 4 + .../elasticsearch/v1/elasticsearch_types.go | 269 +++++++++++++++++- pkg/apis/elasticsearch/v1/fields.go | 3 + .../elasticsearch/v1/zz_generated.deepcopy.go | 100 +++++++ .../association/controller/filebeat_es.go | 59 ++++ .../association/controller/metricbeat_es.go | 59 ++++ pkg/controller/association/reconciler.go | 6 +- pkg/controller/association/service.go | 2 +- pkg/controller/common/volume/configmap.go | 17 +- .../elasticsearch/configmap/configmap.go | 29 ++ pkg/controller/elasticsearch/driver/driver.go | 13 + .../elasticsearch/elasticsearch_controller.go | 12 +- .../elasticsearch/nodespec/podspec.go | 12 + .../elasticsearch/nodespec/podspec_test.go | 4 +- .../elasticsearch/nodespec/resources.go | 4 +- .../elasticsearch/settings/merged_config.go | 16 ++ .../settings/merged_config_test.go | 1 + .../elasticsearch/stackmon/config.go | 119 ++++++++ .../elasticsearch/stackmon/container.go | 155 ++++++++++ .../elasticsearch/stackmon/volume.go | 99 +++++++ 21 files changed, 974 insertions(+), 11 deletions(-) create mode 100644 pkg/controller/association/controller/filebeat_es.go create mode 100644 pkg/controller/association/controller/metricbeat_es.go create mode 100644 pkg/controller/elasticsearch/stackmon/config.go create mode 100644 pkg/controller/elasticsearch/stackmon/container.go create mode 100644 pkg/controller/elasticsearch/stackmon/volume.go diff --git a/cmd/manager/main.go b/cmd/manager/main.go index e8caadffcc..e7154c0ebb 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -677,6 +677,8 @@ func registerControllers(mgr manager.Manager, params operator.Parameters, access {name: "BEAT-KB", registerFunc: associationctl.AddBeatKibana}, {name: "AGENT-ES", registerFunc: associationctl.AddAgentES}, {name: "EMS-ES", registerFunc: associationctl.AddMapsES}, + {name: "METRICBEAT-ES", registerFunc: associationctl.AddMetricbeatES}, + {name: "FILEBEAT-ES", registerFunc: associationctl.AddFilebeatES}, } for _, c := range assocControllers { diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index 46a8b39e6b..47430d1174 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -92,6 +92,10 @@ func (asm AssociationStatusMap) AllEstablished() bool { const ( ElasticsearchConfigAnnotationNameBase = "association.k8s.elastic.co/es-conf" ElasticsearchAssociationType = "elasticsearch" + MetricbeatConfigAnnotationNameBase = "association.k8s.elastic.co/mb-conf" + MetricbeatAssociationType = "metricbeat" + FilebeatConfigAnnotationNameBase = "association.k8s.elastic.co/fb-conf" + FilebeatAssociationType = "filebeat" KibanaConfigAnnotationNameBase = "association.k8s.elastic.co/kb-conf" KibanaAssociationType = "kibana" diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 30c55c554a..c2e8029feb 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -5,8 +5,13 @@ package v1 import ( + "crypto/sha256" + "encoding/base32" + "fmt" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/hash" @@ -72,8 +77,264 @@ type ElasticsearchSpec struct { // +kubebuilder:validation:Optional // +kubebuilder:validation:Enum=DeleteOnScaledownOnly;DeleteOnScaledownAndClusterDeletion VolumeClaimDeletePolicy VolumeClaimDeletePolicy `json:"volumeClaimDeletePolicy,omitempty"` + + // Monitoring enables you to extract log and stack monitoring metrics of this Elasticsearch cluster. + // Metricbeat and Filebeat are deployed in the same pod as sidecar and each one send data to one or two different + // monitoring Elasticsearch clusters running in the same Kubernetes cluster. + // +kubebuilder:validation:Optional + Monitoring Monitoring `json:"monitoring,omitempty"` +} + +// Monitoring holds Elasticsearch references to send logs and metrics of this Elasticsearch cluster. +type Monitoring struct { + Metrics MetricsMonitoring `json:"metrics,omitempty"` + Logs LogsMonitoring `json:"logs,omitempty"` +} + +type MetricsMonitoring struct { + // ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster + // dedicated to receiving stack monitoring metrics. + ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` +} + +type LogsMonitoring struct { + // ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster + // dedicated to receiving Elasticsearch logs. + ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` +} + +// MetricsMonitoringAssociation helps to manage the (Elasticsearch+Metricbeat)/Elasticsearch association +type MetricsMonitoringAssociation struct { + *Elasticsearch + ref types.NamespacedName +} + +var _ commonv1.Association = &MetricsMonitoringAssociation{} + +func (mma *MetricsMonitoringAssociation) Associated() commonv1.Associated { + if mma == nil { + return nil + } + if mma.Elasticsearch == nil { + mma.Elasticsearch = &Elasticsearch{} + } + return mma.Elasticsearch +} + +func (mma *MetricsMonitoringAssociation) AssociationConfAnnotationName() string { + // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, + // based on ElasticsearchRefs + + nsNameHash := sha256.New224() + // concat with dot to avoid collisions, as namespace can't contain dots + _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", mma.ref.Namespace, mma.ref.Name))) + // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to + // give too long output + // no padding to avoid illegal '=' character in the annotation name + hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) + + return commonv1.FormatNameWithID( + commonv1.MetricbeatConfigAnnotationNameBase+"%s", + hash, + ) +} + +func (mma *MetricsMonitoringAssociation) AssociationType() commonv1.AssociationType { + return commonv1.MetricbeatAssociationType +} + +func (mma *MetricsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { + return commonv1.ObjectSelector{ + Name: mma.ref.Name, + Namespace: mma.ref.Namespace, + } +} + +func (mma *MetricsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf { + if mma.assocConfs == nil { + return nil + } + assocConf, found := mma.assocConfs[mma.ref] + if !found { + return nil + } + + return &assocConf +} + +func (mma *MetricsMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { + if mma.assocConfs == nil { + mma.assocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) + } + if assocConf != nil { + mma.assocConfs[mma.ref] = *assocConf + } +} + +func (mma *MetricsMonitoringAssociation) AssociationID() string { + return fmt.Sprintf("%s-%s", mma.ref.Namespace, mma.ref.Name) +} + +// LogsMonitoringAssociation helps to manage the (Elasticsearch+Filebeat)/Elasticsearch association +type LogsMonitoringAssociation struct { + *Elasticsearch + ref types.NamespacedName +} + +var _ commonv1.Association = &LogsMonitoringAssociation{} + +func (lma *LogsMonitoringAssociation) Associated() commonv1.Associated { + if lma == nil { + return nil + } + if lma.Elasticsearch == nil { + lma.Elasticsearch = &Elasticsearch{} + } + return lma.Elasticsearch +} + +func (lma *LogsMonitoringAssociation) AssociationConfAnnotationName() string { + // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, + // based on ElasticsearchRefs + + nsNameHash := sha256.New224() + // concat with dot to avoid collisions, as namespace can't contain dots + _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", lma.ref.Namespace, lma.ref.Name))) + // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to + // give too long output + // no padding to avoid illegal '=' character in the annotation name + hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) + + return commonv1.FormatNameWithID( + commonv1.FilebeatConfigAnnotationNameBase+"%s", + hash, + ) } +func (lma *LogsMonitoringAssociation) AssociationType() commonv1.AssociationType { + return commonv1.FilebeatAssociationType +} + +func (lma *LogsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { + return commonv1.ObjectSelector{ + Name: lma.ref.Name, + Namespace: lma.ref.Namespace, + } +} + +func (lma *LogsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf { + if lma.assocConfs == nil { + return nil + } + assocConf, found := lma.assocConfs[lma.ref] + if !found { + return nil + } + + return &assocConf +} + +func (lma *LogsMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { + if lma.assocConfs == nil { + lma.assocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) + } + if assocConf != nil { + lma.assocConfs[lma.ref] = *assocConf + } +} + +func (lma *LogsMonitoringAssociation) AssociationID() string { + return fmt.Sprintf("%s-%s", lma.ref.Namespace, lma.ref.Name) +} + +// RequiresAssociation returns true if the spec specifies an Elasticsearch reference. +/*func (es *Elasticsearch) RequiresAssociation() bool { + return es.Spec.Monitoring.Metrics.ElasticsearchRef.Name != "" || es.Spec.Monitoring.Logs.ElasticsearchRef.Name != "" +}*/ + +// Associated methods + +var _ commonv1.Associated = &Elasticsearch{} + +func (es *Elasticsearch) ServiceAccountName() string { + return es.Spec.ServiceAccountName +} + +func (es *Elasticsearch) GetAssociations() []commonv1.Association { + associations := make([]commonv1.Association, 0) + ref := es.Spec.Monitoring.Metrics.ElasticsearchRef + if ref.IsDefined() { + associations = append(associations, &MetricsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + }) + } + + ref = es.Spec.Monitoring.Logs.ElasticsearchRef + if ref.IsDefined() { + associations = append(associations, &LogsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + }) + } + return associations +} + +func (es *Elasticsearch) GetMonitoringMetricsAssociation() commonv1.Association { + ref := es.Spec.Monitoring.Metrics.ElasticsearchRef + if ref.IsDefined() { + return &MetricsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + } + } + return &MetricsMonitoringAssociation{} +} + +func (es *Elasticsearch) GetMonitoringLogsAssociation() commonv1.Association { + ref := es.Spec.Monitoring.Logs.ElasticsearchRef + if ref.IsDefined() { + return &LogsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + } + } + return &LogsMonitoringAssociation{} +} + +func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) commonv1.AssociationStatusMap { + switch typ { + case commonv1.MetricbeatAssociationType: + return commonv1.NewSingleAssociationStatusMap(es.Status.MonitoringMetricsAssociationStatus) + case commonv1.FilebeatAssociationType: + return commonv1.NewSingleAssociationStatusMap(es.Status.MonitoringLogsAssociationStatus) + } + + return commonv1.AssociationStatusMap{} +} + +func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, status commonv1.AssociationStatusMap) error { + single, err := status.Single() + if err != nil { + return err + } + + switch typ { + case commonv1.MetricbeatAssociationType: + es.Status.MonitoringMetricsAssociationStatus = single + return nil + case commonv1.FilebeatAssociationType: + es.Status.MonitoringLogsAssociationStatus = single + return nil + default: + return fmt.Errorf("association type %s not known", typ) + } +} + +/*func (es *Elasticsearch) AssociationID() string { + return commonv1.SingletonAssociationID +}*/ + // VolumeClaimDeletePolicy describes the delete policy for handling PersistentVolumeClaims that hold Elasticsearch data. // Inspired by https://github.com/kubernetes/enhancements/pull/2440 type VolumeClaimDeletePolicy string @@ -364,6 +625,9 @@ type ElasticsearchStatus struct { Version string `json:"version,omitempty"` Health ElasticsearchHealth `json:"health,omitempty"` Phase ElasticsearchOrchestrationPhase `json:"phase,omitempty"` + + MonitoringMetricsAssociationStatus commonv1.AssociationStatus `json:"monitoringMetricsAssociationStatus,omitempty"` + MonitoringLogsAssociationStatus commonv1.AssociationStatus `json:"monitoringLogsAssociationStatus,omitempty"` } type ZenDiscoveryStatus struct { @@ -390,8 +654,9 @@ type Elasticsearch struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec ElasticsearchSpec `json:"spec,omitempty"` - Status ElasticsearchStatus `json:"status,omitempty"` + Spec ElasticsearchSpec `json:"spec,omitempty"` + Status ElasticsearchStatus `json:"status,omitempty"` + assocConfs map[types.NamespacedName]commonv1.AssociationConf `json:"-"` } // IsMarkedForDeletion returns true if the Elasticsearch is going to be deleted diff --git a/pkg/apis/elasticsearch/v1/fields.go b/pkg/apis/elasticsearch/v1/fields.go index dca78eed88..84e4748d4b 100644 --- a/pkg/apis/elasticsearch/v1/fields.go +++ b/pkg/apis/elasticsearch/v1/fields.go @@ -45,6 +45,9 @@ const ( XPackSecurityTransportSslVerificationMode = "xpack.security.transport.ssl.verification_mode" XPackLicenseUploadTypes = "xpack.license.upload.types" // supported >= 7.6.0 used as of 7.8.1 + + XPackMonitoringCollectionEnabled = "xpack.monitoring.collection.enabled" + XPackMonitoringElasticsearchCollectionEnabled = "xpack.monitoring.elasticsearch.collection.enabled" ) var UnsupportedSettings = []string{ diff --git a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go index 6f30645b2b..cfb7d00920 100644 --- a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go +++ b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go @@ -12,6 +12,7 @@ import ( commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" corev1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -91,6 +92,13 @@ func (in *Elasticsearch) DeepCopyInto(out *Elasticsearch) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status + if in.assocConfs != nil { + in, out := &in.assocConfs, &out.assocConfs + *out = make(map[types.NamespacedName]commonv1.AssociationConf, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Elasticsearch. @@ -195,6 +203,7 @@ func (in *ElasticsearchSpec) DeepCopyInto(out *ElasticsearchSpec) { *out = make([]RemoteCluster, len(*in)) copy(*out, *in) } + out.Monitoring = in.Monitoring } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ElasticsearchSpec. @@ -238,6 +247,97 @@ func (in *FileRealmSource) DeepCopy() *FileRealmSource { 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 + out.ElasticsearchRef = in.ElasticsearchRef +} + +// 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 *LogsMonitoringAssociation) DeepCopyInto(out *LogsMonitoringAssociation) { + *out = *in + if in.Elasticsearch != nil { + in, out := &in.Elasticsearch, &out.Elasticsearch + *out = new(Elasticsearch) + (*in).DeepCopyInto(*out) + } + out.ref = in.ref +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoringAssociation. +func (in *LogsMonitoringAssociation) DeepCopy() *LogsMonitoringAssociation { + if in == nil { + return nil + } + out := new(LogsMonitoringAssociation) + 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 + out.ElasticsearchRef = in.ElasticsearchRef +} + +// 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 *MetricsMonitoringAssociation) DeepCopyInto(out *MetricsMonitoringAssociation) { + *out = *in + if in.Elasticsearch != nil { + in, out := &in.Elasticsearch, &out.Elasticsearch + *out = new(Elasticsearch) + (*in).DeepCopyInto(*out) + } + out.ref = in.ref +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoringAssociation. +func (in *MetricsMonitoringAssociation) DeepCopy() *MetricsMonitoringAssociation { + if in == nil { + return nil + } + out := new(MetricsMonitoringAssociation) + 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 + out.Metrics = in.Metrics + out.Logs = in.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 *Node) DeepCopyInto(out *Node) { *out = *in diff --git a/pkg/controller/association/controller/filebeat_es.go b/pkg/controller/association/controller/filebeat_es.go new file mode 100644 index 0000000000..87e22ba6f7 --- /dev/null +++ b/pkg/controller/association/controller/filebeat_es.go @@ -0,0 +1,59 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package controller + +import ( + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/manager" + + 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/utils/k8s" + "github.com/elastic/cloud-on-k8s/pkg/utils/rbac" +) + +const ( + // FilebeatESAssociationLabelName marks resources created by this controller for easier retrieval. + FilebeatESAssociationLabelName = "filebeatassociation.k8s.elastic.co/name" + // FilebeatESAssociationLabelNamespace marks resources created by this controller for easier retrieval. + FilebeatESAssociationLabelNamespace = "filebeatassociation.k8s.elastic.co/namespace" + // FilebeatESAssociationLabelType marks the type of association. + FilebeatESAssociationLabelType = "filebeatassociation.k8s.elastic.co/type" + + // FilebeatBuiltinRole is the name of the built-in role for the Filebeat system user. + FilebeatBuiltinRole = "superuser" // FIXME: create a dedicated role? +) + +func AddFilebeatES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { + return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ + AssociatedObjTemplate: func() commonv1.Associated { return &esv1.Elasticsearch{} }, + ElasticsearchRef: func(c k8s.Client, association commonv1.Association) (bool, commonv1.ObjectSelector, error) { + return true, association.AssociationRef(), nil + }, + ReferencedResourceVersion: referencedElasticsearchStatusVersion, + ExternalServiceURL: getElasticsearchExternalURL, + AssociationType: commonv1.FilebeatAssociationType, + AssociatedNamer: esv1.ESNamer, + AssociationName: "filebeat-es", + AssociatedShortName: "filebeat", + Labels: func(associated types.NamespacedName) map[string]string { + return map[string]string{ + FilebeatESAssociationLabelName: associated.Name, + FilebeatESAssociationLabelNamespace: associated.Namespace, + FilebeatESAssociationLabelType: commonv1.FilebeatAssociationType, + } + }, + AssociationConfAnnotationNameBase: commonv1.FilebeatConfigAnnotationNameBase, + UserSecretSuffix: "filebeat-user", + ESUserRole: func(associated commonv1.Associated) (string, error) { + return FilebeatBuiltinRole, nil + }, + AssociationResourceNameLabelName: eslabel.ClusterNameLabelName, + AssociationResourceNamespaceLabelName: eslabel.ClusterNamespaceLabelName, + }) +} diff --git a/pkg/controller/association/controller/metricbeat_es.go b/pkg/controller/association/controller/metricbeat_es.go new file mode 100644 index 0000000000..e8a9d8c627 --- /dev/null +++ b/pkg/controller/association/controller/metricbeat_es.go @@ -0,0 +1,59 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package controller + +import ( + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/manager" + + 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/utils/k8s" + "github.com/elastic/cloud-on-k8s/pkg/utils/rbac" +) + +const ( + // MetricbeatESAssociationLabelName marks resources created by this controller for easier retrieval. + MetricbeatESAssociationLabelName = "metricbeatassociation.k8s.elastic.co/name" + // MetricbeatESAssociationLabelNamespace marks resources created by this controller for easier retrieval. + MetricbeatESAssociationLabelNamespace = "metricbeatassociation.k8s.elastic.co/namespace" + // MetricbeatESAssociationLabelType marks the type of association. + MetricbeatESAssociationLabelType = "metricbeatassociation.k8s.elastic.co/type" + + // MetricbeatBuiltinRole is the name of the built-in role for the Metricbeat system user. + MetricbeatBuiltinRole = "superuser" // FIXME: create a dedicated role? +) + +func AddMetricbeatES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { + return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ + AssociatedObjTemplate: func() commonv1.Associated { return &esv1.Elasticsearch{} }, + ElasticsearchRef: func(c k8s.Client, association commonv1.Association) (bool, commonv1.ObjectSelector, error) { + return true, association.AssociationRef(), nil + }, + ReferencedResourceVersion: referencedElasticsearchStatusVersion, + ExternalServiceURL: getElasticsearchExternalURL, + AssociationType: commonv1.MetricbeatAssociationType, + AssociatedNamer: esv1.ESNamer, + AssociationName: "metricbeat-es", + AssociatedShortName: "metricbeat", + Labels: func(associated types.NamespacedName) map[string]string { + return map[string]string{ + MetricbeatESAssociationLabelName: associated.Name, + MetricbeatESAssociationLabelNamespace: associated.Namespace, + MetricbeatESAssociationLabelType: commonv1.MetricbeatAssociationType, + } + }, + AssociationConfAnnotationNameBase: commonv1.MetricbeatConfigAnnotationNameBase, + UserSecretSuffix: "metricbeat-user", + ESUserRole: func(associated commonv1.Associated) (string, error) { + return MetricbeatBuiltinRole, nil + }, + AssociationResourceNameLabelName: eslabel.ClusterNameLabelName, + AssociationResourceNamespaceLabelName: eslabel.ClusterNamespaceLabelName, + }) +} diff --git a/pkg/controller/association/reconciler.go b/pkg/controller/association/reconciler.go index 2d2d826f05..a264fa7365 100644 --- a/pkg/controller/association/reconciler.go +++ b/pkg/controller/association/reconciler.go @@ -377,7 +377,11 @@ func (r *Reconciler) updateStatus(ctx context.Context, associated commonv1.Assoc span, _ := apm.StartSpan(ctx, "update_association_status", tracing.SpanTypeApp) defer span.End() - oldStatus := associated.AssociationStatusMap(r.AssociationType) + oldStatus := commonv1.AssociationStatusMap{} + // Copy from the original map to the target map + for key, value := range associated.AssociationStatusMap(r.AssociationType) { + oldStatus[key] = value + } // 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 diff --git a/pkg/controller/association/service.go b/pkg/controller/association/service.go index 2ac1d0de02..f11aab1536 100644 --- a/pkg/controller/association/service.go +++ b/pkg/controller/association/service.go @@ -18,7 +18,7 @@ import ( func ServiceURL(c k8s.Client, serviceNSN types.NamespacedName, protocol string) (string, error) { var svc corev1.Service if err := c.Get(context.Background(), serviceNSN, &svc); err != nil { - return "", fmt.Errorf("while fetching refernced service: %w", err) + return "", fmt.Errorf("while fetching referenced service: %w", err) } port, err := findPortFor(protocol, svc) if err != nil { diff --git a/pkg/controller/common/volume/configmap.go b/pkg/controller/common/volume/configmap.go index 6631fb6c62..e371d49221 100644 --- a/pkg/controller/common/volume/configmap.go +++ b/pkg/controller/common/volume/configmap.go @@ -23,6 +23,16 @@ func NewConfigMapVolumeWithMode(configMapName, name, mountPath string, defaultMo } } +func NewConfigMapVolumeWithSubPath(configMapName, name, mountPath string, subPath string) ConfigMapVolume { + return ConfigMapVolume{ + configMapName: configMapName, + name: name, + mountPath: mountPath, + defaultMode: corev1.ConfigMapVolumeSourceDefaultMode, + subPath: subPath, + } +} + // ConfigMapVolume defines a volume to expose a configmap type ConfigMapVolume struct { configMapName string @@ -30,15 +40,20 @@ type ConfigMapVolume struct { mountPath string items []corev1.KeyToPath defaultMode int32 + subPath string } // VolumeMount returns the k8s volume mount. func (cm ConfigMapVolume) VolumeMount() corev1.VolumeMount { - return corev1.VolumeMount{ + vm := corev1.VolumeMount{ Name: cm.name, MountPath: cm.mountPath, ReadOnly: true, } + if cm.subPath != "" { + vm.SubPath = cm.subPath + } + return vm } // Volume returns the k8s volume. diff --git a/pkg/controller/elasticsearch/configmap/configmap.go b/pkg/controller/elasticsearch/configmap/configmap.go index ea00fb5696..f2c612c4d0 100644 --- a/pkg/controller/elasticsearch/configmap/configmap.go +++ b/pkg/controller/elasticsearch/configmap/configmap.go @@ -8,6 +8,7 @@ import ( "context" "github.com/elastic/cloud-on-k8s/pkg/controller/common/tracing" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" "go.elastic.co/apm" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -54,3 +55,31 @@ func ReconcileScriptsConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasti return ReconcileConfigMap(c, es, scriptsConfigMap) } + +func ReconcileMetricbeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasticsearch) error { + span, _ := apm.StartSpan(ctx, "reconcile_metricbeat_config", tracing.SpanTypeApp) + defer span.End() + + configMap := NewConfigMapWithData( + types.NamespacedName{Namespace: es.Namespace, Name: stackmon.MetricbeatConfigMapName(es)}, + map[string]string{ + stackmon.MetricbeatConfigKey: stackmon.MetricbeatConfig, + }, + ) + + return ReconcileConfigMap(c, es, configMap) +} + +func ReconcileFilebeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasticsearch) error { + span, _ := apm.StartSpan(ctx, "reconcile_filebeat_config", tracing.SpanTypeApp) + defer span.End() + + configMap := NewConfigMapWithData( + types.NamespacedName{Namespace: es.Namespace, Name: stackmon.FilebeatConfigMapName(es)}, + map[string]string{ + stackmon.FilebeatConfigKey: stackmon.FilebeatConfig, + }, + ) + + return ReconcileConfigMap(c, es, configMap) +} diff --git a/pkg/controller/elasticsearch/driver/driver.go b/pkg/controller/elasticsearch/driver/driver.go index 4b89a56525..cf23a14d50 100644 --- a/pkg/controller/elasticsearch/driver/driver.go +++ b/pkg/controller/elasticsearch/driver/driver.go @@ -10,6 +10,7 @@ import ( "fmt" "time" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/record" controller "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -244,6 +245,18 @@ func (d *defaultDriver) Reconcile(ctx context.Context) *reconciler.Results { results = results.WithResult(defaultRequeue) } + // reconcile monitoring configurations + if stackmon.IsMonitoringMetricsDefined(d.ES) { + if err := configmap.ReconcileMetricbeatConfigMap(ctx, d.Client, d.ES); err != nil { + return results.WithError(err) + } + } + if stackmon.IsMonitoringLogDefined(d.ES) { + if err := configmap.ReconcileFilebeatConfigMap(ctx, d.Client, d.ES); err != nil { + return results.WithError(err) + } + } + // reconcile StatefulSets and nodes configuration res = d.reconcileNodeSpecs(ctx, esReachable, esClient, d.ReconcileState, observedState, *resourcesState, keystoreResources) results = results.WithResults(res) diff --git a/pkg/controller/elasticsearch/elasticsearch_controller.go b/pkg/controller/elasticsearch/elasticsearch_controller.go index b0b8614e51..b8dc37de34 100644 --- a/pkg/controller/elasticsearch/elasticsearch_controller.go +++ b/pkg/controller/elasticsearch/elasticsearch_controller.go @@ -9,6 +9,7 @@ import ( "sync/atomic" 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/annotation" "github.com/elastic/cloud-on-k8s/pkg/controller/common/certificates" @@ -159,7 +160,7 @@ func (r *ReconcileElasticsearch) Reconcile(ctx context.Context, request reconcil // Fetch the Elasticsearch instance var es esv1.Elasticsearch - requeue, err := r.fetchElasticsearch(ctx, request, &es) + requeue, err := r.fetchElasticsearchWithAssociations(ctx, request, &es) if err != nil || requeue { return reconcile.Result{}, tracing.CaptureError(ctx, err) } @@ -191,6 +192,11 @@ func (r *ReconcileElasticsearch) Reconcile(ctx context.Context, request reconcil return reconcile.Result{}, tracing.CaptureError(ctx, err) } + // Requeue if associations are configured but not yet defined + if !association.AreConfiguredIfSet(es.GetAssociations(), r.recorder) { + return reconcile.Result{}, nil + } + state := esreconcile.NewState(es) results := r.internalReconcile(ctx, es, state) err = r.updateStatus(ctx, es, state) @@ -204,11 +210,11 @@ func (r *ReconcileElasticsearch) Reconcile(ctx context.Context, request reconcil return results.WithError(err).Aggregate() } -func (r *ReconcileElasticsearch) fetchElasticsearch(ctx context.Context, request reconcile.Request, es *esv1.Elasticsearch) (bool, error) { +func (r *ReconcileElasticsearch) fetchElasticsearchWithAssociations(ctx context.Context, request reconcile.Request, es *esv1.Elasticsearch) (bool, error) { span, _ := apm.StartSpan(ctx, "fetch_elasticsearch", tracing.SpanTypeApp) defer span.End() - err := r.Get(context.Background(), request.NamespacedName, es) + err := association.FetchWithAssociations(ctx, r.Client, request, es) if err != nil { if apierrors.IsNotFound(err) { // Object not found, cleanup in-memory state. Children resources are garbage-collected either by diff --git a/pkg/controller/elasticsearch/nodespec/podspec.go b/pkg/controller/elasticsearch/nodespec/podspec.go index 9b1c477f25..d99b6e5ca7 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec.go +++ b/pkg/controller/elasticsearch/nodespec/podspec.go @@ -8,6 +8,7 @@ import ( "crypto/sha256" "fmt" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" corev1 "k8s.io/api/core/v1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" @@ -73,6 +74,10 @@ func BuildPodTemplateSpec( }) } + if stackmon.IsMonitoringLogDefined(es) { + builder = stackmon.EnableStackLoggingEnvVar(builder) + } + headlessServiceName := HeadlessServiceName(esv1.StatefulSet(es.Name, nodeSet.Name)) builder = builder. WithLabels(labels). @@ -90,6 +95,13 @@ func BuildPodTemplateSpec( WithInitContainerDefaults(corev1.EnvVar{Name: settings.HeadlessServiceName, Value: headlessServiceName}). WithPreStopHook(*NewPreStopHook()) + if stackmon.IsMonitoringDefined(es) { + builder, err = stackmon.WithMonitoring(builder, es) + if err != nil { + return corev1.PodTemplateSpec{}, err + } + } + return builder.PodTemplate, nil } diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index 5858b8cce4..91c5215bb5 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -164,7 +164,7 @@ func TestBuildPodTemplateSpecWithDefaultSecurityContext(t *testing.T) { es.Spec.Version = tt.version.String() es.Spec.NodeSets[0].PodTemplate.Spec.SecurityContext = tt.userSecurityContext - cfg, err := settings.NewMergedESConfig(es.Name, tt.version, corev1.IPv4Protocol, es.Spec.HTTP, *es.Spec.NodeSets[0].Config) + cfg, err := settings.NewMergedESConfig(es.Name, tt.version, corev1.IPv4Protocol, es.Spec.HTTP, *es.Spec.NodeSets[0].Config, false) require.NoError(t, err) actual, err := BuildPodTemplateSpec(es, es.Spec.NodeSets[0], cfg, nil, tt.setDefaultFSGroup) @@ -178,7 +178,7 @@ func TestBuildPodTemplateSpec(t *testing.T) { nodeSet := sampleES.Spec.NodeSets[0] ver, err := version.Parse(sampleES.Spec.Version) require.NoError(t, err) - cfg, err := settings.NewMergedESConfig(sampleES.Name, ver, corev1.IPv4Protocol, sampleES.Spec.HTTP, *nodeSet.Config) + cfg, err := settings.NewMergedESConfig(sampleES.Name, ver, corev1.IPv4Protocol, sampleES.Spec.HTTP, *nodeSet.Config, false) require.NoError(t, err) actual, err := BuildPodTemplateSpec(sampleES, sampleES.Spec.NodeSets[0], cfg, nil, false) diff --git a/pkg/controller/elasticsearch/nodespec/resources.go b/pkg/controller/elasticsearch/nodespec/resources.go index 99673cb7e4..f88b93c4c3 100644 --- a/pkg/controller/elasticsearch/nodespec/resources.go +++ b/pkg/controller/elasticsearch/nodespec/resources.go @@ -5,6 +5,7 @@ package nodespec import ( + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -54,7 +55,8 @@ func BuildExpectedResources( if nodeSpec.Config != nil { userCfg = *nodeSpec.Config } - cfg, err := settings.NewMergedESConfig(es.Name, ver, ipFamily, es.Spec.HTTP, userCfg) + isMonitoring := stackmon.IsMonitoringDefined(es) + cfg, err := settings.NewMergedESConfig(es.Name, ver, ipFamily, es.Spec.HTTP, userCfg, isMonitoring) if err != nil { return nil, err } diff --git a/pkg/controller/elasticsearch/settings/merged_config.go b/pkg/controller/elasticsearch/settings/merged_config.go index ed4c374720..4df5523f57 100644 --- a/pkg/controller/elasticsearch/settings/merged_config.go +++ b/pkg/controller/elasticsearch/settings/merged_config.go @@ -32,6 +32,7 @@ func NewMergedESConfig( ipFamily corev1.IPFamily, httpConfig commonv1.HTTPConfig, userConfig commonv1.Config, + isMonitoring bool, ) (CanonicalConfig, error) { userCfg, err := common.NewCanonicalConfigFrom(userConfig.Data) if err != nil { @@ -45,6 +46,12 @@ func NewMergedESConfig( if err != nil { return CanonicalConfig{}, err } + if isMonitoring { + err = config.MergeWith(monitoringConfig().CanonicalConfig) + } + if err != nil { + return CanonicalConfig{}, err + } return CanonicalConfig{config}, nil } @@ -133,3 +140,12 @@ func xpackConfig(ver version.Version, httpCfg commonv1.HTTPConfig) *CanonicalCon return &CanonicalConfig{common.MustCanonicalConfig(cfg)} } + +// monitoringConfig returns the configuration bit related to XPack monitoring +func monitoringConfig() *CanonicalConfig { + cfg := map[string]interface{}{ + esv1.XPackMonitoringCollectionEnabled: true, + esv1.XPackMonitoringElasticsearchCollectionEnabled: false, + } + return &CanonicalConfig{common.MustCanonicalConfig(cfg)} +} diff --git a/pkg/controller/elasticsearch/settings/merged_config_test.go b/pkg/controller/elasticsearch/settings/merged_config_test.go index ad99b0d80d..bcb29abf12 100644 --- a/pkg/controller/elasticsearch/settings/merged_config_test.go +++ b/pkg/controller/elasticsearch/settings/merged_config_test.go @@ -219,6 +219,7 @@ func TestNewMergedESConfig(t *testing.T) { tt.ipFamily, commonv1.HTTPConfig{}, commonv1.Config{Data: tt.cfgData}, + false, ) require.NoError(t, err) tt.assert(cfg) diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go new file mode 100644 index 0000000000..cc6850a78e --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -0,0 +1,119 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + +const ( + MetricbeatConfigKey = "metricbeat.yml" + MetricbeatConfigMapSuffix = "metricbeat-config" + + FilebeatConfigKey = "filebeat.yml" + FilebeatConfigMapSuffix = "filebeat-config" +) + +var ( + EsSourceURLEnvVarKey = "ES_SOURCE_URL" + EsSourceURLEnvVarValue = "https://localhost:9200" + EsSourceUsernameEnvVarKey = "ES_SOURCE_USERNAME" + EsSourcePasswordEnvVarKey = "ES_SOURCE_PASSWORD" //nolint:gosec + EsTargetURLEnvVarKey = "ES_TARGET_URL" + EsTargetUsernameEnvVarKey = "ES_TARGET_USERNAME" + EsTargetPasswordEnvVarKey = "ES_TARGET_PASSWORD" //nolint:gosec + + // MetricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch + MetricbeatConfig = `metricbeat.modules: +- module: elasticsearch + metricsets: + - ccr + - cluster_stats + - enrich + - index + - index_recovery + - index_summary + - ml_job + - node_stats + - shard + period: 10s + xpack.enabled: true + hosts: ["${ES_SOURCE_URL}"] + username: ${ES_SOURCE_USERNAME} + password: ${ES_SOURCE_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/source/ca.crt"] + ssl.verification_mode: "certificate" + +processors: + - add_cloud_metadata: {} + - add_host_metadata: {} + +output.elasticsearch: + hosts: ['${ES_TARGET_URL}'] + username: ${ES_TARGET_USERNAME} + password: ${ES_TARGET_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/target/ca.crt"]` + + // FilebeatConfig is a static configuration for Filebeat to collect Elasticsearch logs + FilebeatConfig = `filebeat.modules: +# https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-elasticsearch.html +- module: elasticsearch + server: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_server.json + close_timeout: 2h + fields_under_root: true + gc: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/gc.log.[0-9]* + - /usr/share/elasticsearch/logs/gc.log + - /usr/share/elasticsearch/logs/gc.output.[0-9]* + - /usr/share/elasticsearch/logs/gc.output + close_timeout: 2h + fields_under_root: true + audit: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_audit.json + close_timeout: 2h + fields_under_root: true + slowlog: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_index_search_slowlog.json + - /usr/share/elasticsearch/logs/*_index_indexing_slowlog.json + close_timeout: 2h + fields_under_root: true + deprecation: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_deprecation.json + close_timeout: 2h + fields_under_root: true + +processors: + - add_cloud_metadata: {} + - add_host_metadata: {} + +#setup.dashboards.enabled: true +#setup.kibana: + #host: '${ES_TARGET_URL}' + #username: ${ES_TARGET_USERNAME} + #password: ${ES_TARGET_PASSWORD} + +output.elasticsearch: + hosts: ['${ES_TARGET_URL}'] + username: ${ES_TARGET_USERNAME} + password: ${ES_TARGET_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/monitoring/logs/target/ca.crt"]` +) + +func MetricbeatConfigMapName(es esv1.Elasticsearch) string { + return esv1.ESNamer.Suffix(es.Name, MetricbeatConfigMapSuffix) +} + +func FilebeatConfigMapName(es esv1.Elasticsearch) string { + return esv1.ESNamer.Suffix(es.Name, FilebeatConfigMapSuffix) +} diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go new file mode 100644 index 0000000000..5a18fa48eb --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -0,0 +1,155 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "strings" + + v1 "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/defaults" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" + esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" +) + +var ( + EsLogStyleEnvVarKey = "ES_LOG_STYLE" + EsLogStyleEnvVarValue = "file" +) + +func IsMonitoringDefined(es esv1.Elasticsearch) bool { + return IsMonitoringMetricsDefined(es) || IsMonitoringLogDefined(es) +} + +func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { + return es.Spec.Monitoring.Metrics.ElasticsearchRef.IsDefined() +} + +func IsMonitoringLogDefined(es esv1.Elasticsearch) bool { + return es.Spec.Monitoring.Logs.ElasticsearchRef.IsDefined() +} + +func EnableStackLoggingEnvVar(builder *defaults.PodTemplateBuilder) *defaults.PodTemplateBuilder { + return builder.WithEnv(corev1.EnvVar{Name: EsLogStyleEnvVarKey, Value: EsLogStyleEnvVarValue}) +} + +// WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers +// in the pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. +func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { + isMonitoringMetricsDefined := IsMonitoringMetricsDefined(es) + isMonitoringLogsDefined := IsMonitoringLogDefined(es) + + // Inject volumes + builder = builder.WithVolumes(monitoringVolumes(es, isMonitoringMetricsDefined, isMonitoringLogsDefined)...) + + if isMonitoringMetricsDefined { + // Inject Metricbeat sidecar container + metricBeat, err := metricbeatContainer(es) + if err != nil { + return nil, err + } + builder.PodTemplate.Spec.Containers = append(builder.PodTemplate.Spec.Containers, metricBeat) + } + + if isMonitoringLogsDefined { + // Inject Filebeat sidecar container + filebeat, err := filebeatContainer(es) + if err != nil { + return nil, err + } + builder.PodTemplate.Spec.Containers = append(builder.PodTemplate.Spec.Containers, filebeat) + } + + return builder, nil +} + +func metricbeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { + image, err := containerImage(es, container.MetricbeatImage) + if err != nil { + return corev1.Container{}, err + } + + assocConf := es.GetMonitoringMetricsAssociation().AssociationConf() + envVars := append(monitoringSourceEnvVars(es), monitoringTargetEnvVars(assocConf)...) + + return corev1.Container{ + Name: MetricbeatContainerName, + Image: image, + Args: []string{"-c", MetricbeatConfigMountPath, "-e"}, + Env: append(envVars, defaults.PodDownwardEnvVars()...), + VolumeMounts: []corev1.VolumeMount{ + metricbeatConfigMapVolume(es).VolumeMount(), + monitoringMetricsSourceCaCertSecretVolume(es).VolumeMount(), + monitoringMetricsTargetCaCertSecretVolume(es).VolumeMount(), + }, + }, nil +} + +func filebeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { + image, err := containerImage(es, container.FilebeatImage) + if err != nil { + return corev1.Container{}, err + } + + assocConf := es.GetMonitoringLogsAssociation().AssociationConf() + envVars := monitoringTargetEnvVars(assocConf) + + return corev1.Container{ + Name: FilebeatContainerName, + Image: image, + Args: []string{"-c", FilebeatConfigMountPath, "-e"}, + Env: append(envVars, defaults.PodDownwardEnvVars()...), + VolumeMounts: []corev1.VolumeMount{ + esvolume.DefaultLogsVolumeMount, + filebeatConfigMapVolume(es).VolumeMount(), + monitoringLogsTargetCaCertSecretVolume(es).VolumeMount(), + }, + }, nil +} + +func containerImage(es esv1.Elasticsearch, defaultImage container.Image) (string, error) { + customImage := es.Spec.Image + if customImage != "" { + esImage := string(container.ElasticsearchImage) + if strings.Contains(customImage, esImage) { + // Derive the image from the custom image by replacing the ES image by the default beat image. + return strings.ReplaceAll(es.Spec.Image, esImage, string(defaultImage)), nil + } + return "", errors.New("Stack monitoring not supported with custom image") + } + return container.ImageRepository(defaultImage, es.Spec.Version), nil +} + +func monitoringSourceEnvVars(es esv1.Elasticsearch) []corev1.EnvVar { + return []corev1.EnvVar{ + {Name: EsSourceURLEnvVarKey, Value: EsSourceURLEnvVarValue}, + {Name: EsSourceUsernameEnvVarKey, Value: user.ElasticUserName}, + {Name: EsSourcePasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: esv1.ElasticUserSecret(es.Name)}, + Key: user.ElasticUserName, + }, + }}, + } +} + +func monitoringTargetEnvVars(assocConf *v1.AssociationConf) []corev1.EnvVar { + return []corev1.EnvVar{ + {Name: EsTargetURLEnvVarKey, Value: assocConf.GetURL()}, + {Name: EsTargetUsernameEnvVarKey, Value: assocConf.GetAuthSecretKey()}, + {Name: EsTargetPasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: assocConf.GetAuthSecretName(), + }, + Key: assocConf.GetAuthSecretKey(), + }, + }}, + } +} diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go new file mode 100644 index 0000000000..643dc0d97a --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -0,0 +1,99 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/certificates" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" + corev1 "k8s.io/api/core/v1" +) + +const ( + MetricbeatContainerName = "metricbeat" + MetricbeatConfigVolumeName = "metricbeat-config" + MetricbeatConfigMountPath = "/etc/metricbeat.yml" + + FilebeatContainerName = "filebeat" + FilebeatConfigVolumeName = "filebeat-config" + FilebeatConfigMountPath = "/etc/filebeat.yml" + + MonitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" + MonitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" + + MonitoringMetricsTargetEsCaCertVolumeName = "es-monitoring-metrics-target-certs" + MonitoringMetricsTargetEsCaCertMountPath = "/mnt/es/monitoring/metrics/target" + + MonitoringLogsTargetEsCaCertVolumeName = "es-monitoring-logs-certs" + MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/monitoring/logs/target" +) + +// monitoringVolumes returns the volumes to add to the Elasticsearch pod for the Metricbeat and Filebeat sidecar containers. +// Metricbeat mounts its configuration and the CA certificate of the source and the target Elasticsearch cluster. +// Filebeat mounts its configuration and the CA certificate of the target Elasticsearch cluster. +func monitoringVolumes(es esv1.Elasticsearch, isMonitoringMetricsDefined bool, isMonitoringLogsDefined bool) []corev1.Volume { + var volumes []corev1.Volume + if isMonitoringMetricsDefined { + volumes = append(volumes, + metricbeatConfigMapVolume(es).Volume(), + monitoringMetricsSourceCaCertSecretVolume(es).Volume(), + monitoringMetricsTargetCaCertSecretVolume(es).Volume(), + ) + } + if isMonitoringLogsDefined { + volumes = append(volumes, + filebeatConfigMapVolume(es).Volume(), + monitoringLogsTargetCaCertSecretVolume(es).Volume(), + ) + } + return volumes +} + +func metricbeatConfigMapVolume(es esv1.Elasticsearch) volume.ConfigMapVolume { + return volume.NewConfigMapVolumeWithSubPath( + MetricbeatConfigMapName(es), + MetricbeatConfigVolumeName, + MetricbeatConfigMountPath, + MetricbeatConfigKey, + ) +} + +func filebeatConfigMapVolume(es esv1.Elasticsearch) volume.ConfigMapVolume { + return volume.NewConfigMapVolumeWithSubPath( + FilebeatConfigMapName(es), + FilebeatConfigVolumeName, + FilebeatConfigMountPath, + FilebeatConfigKey, + ) +} + +func monitoringMetricsSourceCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { + return volume.NewSecretVolumeWithMountPath( + certificates.PublicCertsSecretName( + esv1.ESNamer, + es.Name, + ), + MonitoringMetricsSourceEsCaCertVolumeName, + MonitoringMetricsSourceEsCaCertMountPath, + ) +} + +func monitoringMetricsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { + assocConf := es.GetMonitoringMetricsAssociation().AssociationConf() + return volume.NewSecretVolumeWithMountPath( + assocConf.CASecretName, + MonitoringMetricsTargetEsCaCertVolumeName, + MonitoringMetricsTargetEsCaCertMountPath, + ) +} + +func monitoringLogsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { + assocConf := es.GetMonitoringMetricsAssociation().AssociationConf() + return volume.NewSecretVolumeWithMountPath( + assocConf.CASecretName, + MonitoringLogsTargetEsCaCertVolumeName, + MonitoringLogsTargetEsCaCertMountPath, + ) +} From e621963822935c849bbf59ce445f5567f4280aca Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Fri, 28 May 2021 00:25:39 +0200 Subject: [PATCH 02/83] Regenerate --- config/crds/all-crds.yaml | 64 +++++++++++++++++++ ...search.k8s.elastic.co_elasticsearches.yaml | 46 +++++++++++++ .../eck-operator-crds/templates/all-crds.yaml | 64 +++++++++++++++++++ docs/reference/api-docs.asciidoc | 55 ++++++++++++++++ 4 files changed, 229 insertions(+) diff --git a/config/crds/all-crds.yaml b/config/crds/all-crds.yaml index 6ee84debe9..8a3d4666a4 100644 --- a/config/crds/all-crds.yaml +++ b/config/crds/all-crds.yaml @@ -2166,6 +2166,64 @@ spec: image: description: Image is the Elasticsearch Docker image to deploy. type: string + monitoring: + description: Monitoring enables you to extract log and stack monitoring + metrics of this Elasticsearch cluster. Metricbeat and Filebeat are + deployed in the same pod as sidecar and each one send data to one + or two different monitoring Elasticsearch clusters running in the + same Kubernetes cluster. + properties: + logs: + properties: + elasticsearchRef: + description: ElasticsearchRef is a reference to a monitoring + Elasticsearch cluster running in the same Kubernetes cluster + dedicated to receiving Elasticsearch logs. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: object + metrics: + properties: + elasticsearchRef: + description: ElasticsearchRef is a reference to a monitoring + Elasticsearch cluster running in the same Kubernetes cluster + dedicated to receiving stack monitoring metrics. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: object + type: object nodeSets: description: NodeSets allow specifying groups of Elasticsearch nodes sharing the same configuration and Pod templates. @@ -2972,6 +3030,12 @@ spec: description: ElasticsearchHealth is the health of the cluster as returned by the health API. type: string + monitoringLogsAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string + monitoringMetricsAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index e896c1c0cc..ea71600ea7 100644 --- a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -242,6 +242,46 @@ spec: image: description: Image is the Elasticsearch Docker image to deploy. type: string + monitoring: + description: Monitoring enables you to extract log and stack monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same pod as sidecar and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. + properties: + logs: + properties: + elasticsearchRef: + description: ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving Elasticsearch logs. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes service which will be 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 will be used. + type: string + required: + - name + type: object + type: object + metrics: + properties: + elasticsearchRef: + description: ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving stack monitoring metrics. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes service which will be 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 will be used. + type: string + required: + - name + type: object + type: object + type: object nodeSets: description: NodeSets allow specifying groups of Elasticsearch nodes sharing the same configuration and Pod templates. items: @@ -4441,6 +4481,12 @@ spec: health: description: ElasticsearchHealth is the health of the cluster as returned by the health API. type: string + monitoringLogsAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string + monitoringMetricsAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. type: string 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 00715cc45b..8caf9e90c6 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 @@ -2196,6 +2196,64 @@ spec: image: description: Image is the Elasticsearch Docker image to deploy. type: string + monitoring: + description: Monitoring enables you to extract log and stack monitoring + metrics of this Elasticsearch cluster. Metricbeat and Filebeat are + deployed in the same pod as sidecar and each one send data to one + or two different monitoring Elasticsearch clusters running in the + same Kubernetes cluster. + properties: + logs: + properties: + elasticsearchRef: + description: ElasticsearchRef is a reference to a monitoring + Elasticsearch cluster running in the same Kubernetes cluster + dedicated to receiving Elasticsearch logs. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: object + metrics: + properties: + elasticsearchRef: + description: ElasticsearchRef is a reference to a monitoring + Elasticsearch cluster running in the same Kubernetes cluster + dedicated to receiving stack monitoring metrics. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: object + type: object nodeSets: description: NodeSets allow specifying groups of Elasticsearch nodes sharing the same configuration and Pod templates. @@ -3002,6 +3060,12 @@ spec: description: ElasticsearchHealth is the health of the cluster as returned by the health API. type: string + monitoringLogsAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string + monitoringMetricsAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 9d1835de2d..dba4de7017 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -442,7 +442,9 @@ ObjectSelector defines a reference to a Kubernetes object. - xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-enterprisesearch-v1-enterprisesearchspec[$$EnterpriseSearchSpec$$] - xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-enterprisesearch-v1beta1-enterprisesearchspec[$$EnterpriseSearchSpec$$] - xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-kibana-v1-kibanaspec[$$KibanaSpec$$] +- xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$] - xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-maps-v1alpha1-mapsspec[$$MapsSpec$$] +- xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$] - xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-agent-v1alpha1-output[$$Output$$] - xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-remotecluster[$$RemoteCluster$$] **** @@ -902,6 +904,7 @@ ElasticsearchSpec holds the specification of an Elasticsearch cluster. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (eg. a remote Elasticsearch cluster) in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`remoteClusters`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract log and stack monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same pod as sidecar and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. |=== @@ -923,6 +926,58 @@ FileRealmSource references users to create in the Elasticsearch cluster. |=== +[id="{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-logsmonitoring"] +=== LogsMonitoring + + + +.Appears In: +**** +- xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`elasticsearchRef`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving Elasticsearch logs. +|=== + + +[id="{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-metricsmonitoring"] +=== MetricsMonitoring + + + +.Appears In: +**** +- xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`elasticsearchRef`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving stack monitoring metrics. +|=== + + +[id="{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring"] +=== Monitoring + +Monitoring holds Elasticsearch references to send logs and metrics of this Elasticsearch cluster. + +.Appears In: +**** +- xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-elasticsearchspec[$$ElasticsearchSpec$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`metrics`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | +| *`logs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$]__ | +|=== + + [id="{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-nodeset"] From 18396143756b76cc57a5161e01851e92e0052205 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 31 May 2021 18:36:17 +0200 Subject: [PATCH 03/83] Model with only one associationi es->es --- cmd/manager/main.go | 3 +- pkg/apis/common/v1/association.go | 4 - .../elasticsearch/v1/elasticsearch_types.go | 188 ++++-------------- .../controller/{filebeat_es.go => es_es.go} | 36 ++-- .../association/controller/metricbeat_es.go | 59 ------ .../elasticsearch/stackmon/config.go | 10 + .../elasticsearch/stackmon/container.go | 11 +- .../elasticsearch/stackmon/volume.go | 17 +- 8 files changed, 80 insertions(+), 248 deletions(-) rename pkg/controller/association/controller/{filebeat_es.go => es_es.go} (56%) delete mode 100644 pkg/controller/association/controller/metricbeat_es.go diff --git a/cmd/manager/main.go b/cmd/manager/main.go index e7154c0ebb..03f17ff383 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -677,8 +677,7 @@ func registerControllers(mgr manager.Manager, params operator.Parameters, access {name: "BEAT-KB", registerFunc: associationctl.AddBeatKibana}, {name: "AGENT-ES", registerFunc: associationctl.AddAgentES}, {name: "EMS-ES", registerFunc: associationctl.AddMapsES}, - {name: "METRICBEAT-ES", registerFunc: associationctl.AddMetricbeatES}, - {name: "FILEBEAT-ES", registerFunc: associationctl.AddFilebeatES}, + {name: "ES-ES", registerFunc: associationctl.AddEsEs}, } for _, c := range assocControllers { diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index 47430d1174..46a8b39e6b 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -92,10 +92,6 @@ func (asm AssociationStatusMap) AllEstablished() bool { const ( ElasticsearchConfigAnnotationNameBase = "association.k8s.elastic.co/es-conf" ElasticsearchAssociationType = "elasticsearch" - MetricbeatConfigAnnotationNameBase = "association.k8s.elastic.co/mb-conf" - MetricbeatAssociationType = "metricbeat" - FilebeatConfigAnnotationNameBase = "association.k8s.elastic.co/fb-conf" - FilebeatAssociationType = "filebeat" KibanaConfigAnnotationNameBase = "association.k8s.elastic.co/kb-conf" KibanaAssociationType = "kibana" diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index c2e8029feb..95f31d69f4 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -5,8 +5,6 @@ package v1 import ( - "crypto/sha256" - "encoding/base32" "fmt" corev1 "k8s.io/api/core/v1" @@ -103,58 +101,45 @@ type LogsMonitoring struct { ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` } -// MetricsMonitoringAssociation helps to manage the (Elasticsearch+Metricbeat)/Elasticsearch association -type MetricsMonitoringAssociation struct { +// EsEsAssociation helps to manage the Elasticsearch+Metricbeat+Filebeat <-> Elasticsearch(es) association +type EsEsAssociation struct { *Elasticsearch + // ref is the namespaced name of the Elasticsearch used in Association ref types.NamespacedName } -var _ commonv1.Association = &MetricsMonitoringAssociation{} +var _ commonv1.Association = &EsEsAssociation{} -func (mma *MetricsMonitoringAssociation) Associated() commonv1.Associated { - if mma == nil { +func (eea *EsEsAssociation) Associated() commonv1.Associated { + if eea == nil { return nil } - if mma.Elasticsearch == nil { - mma.Elasticsearch = &Elasticsearch{} + if eea.Elasticsearch == nil { + eea.Elasticsearch = &Elasticsearch{} } - return mma.Elasticsearch + return eea.Elasticsearch } -func (mma *MetricsMonitoringAssociation) AssociationConfAnnotationName() string { - // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, - // based on ElasticsearchRefs - - nsNameHash := sha256.New224() - // concat with dot to avoid collisions, as namespace can't contain dots - _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", mma.ref.Namespace, mma.ref.Name))) - // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to - // give too long output - // no padding to avoid illegal '=' character in the annotation name - hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) - - return commonv1.FormatNameWithID( - commonv1.MetricbeatConfigAnnotationNameBase+"%s", - hash, - ) +func (eea *EsEsAssociation) AssociationConfAnnotationName() string { + return commonv1.ElasticsearchConfigAnnotationNameBase } -func (mma *MetricsMonitoringAssociation) AssociationType() commonv1.AssociationType { - return commonv1.MetricbeatAssociationType +func (eea *EsEsAssociation) AssociationType() commonv1.AssociationType { + return commonv1.ElasticsearchAssociationType } -func (mma *MetricsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { +func (eea *EsEsAssociation) AssociationRef() commonv1.ObjectSelector { return commonv1.ObjectSelector{ - Name: mma.ref.Name, - Namespace: mma.ref.Namespace, + Name: eea.ref.Name, + Namespace: eea.ref.Namespace, } } -func (mma *MetricsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf { - if mma.assocConfs == nil { +func (eea *EsEsAssociation) AssociationConf() *commonv1.AssociationConf { + if eea.AssocConfs == nil { return nil } - assocConf, found := mma.assocConfs[mma.ref] + assocConf, found := eea.AssocConfs[eea.ref] if !found { return nil } @@ -162,96 +147,19 @@ func (mma *MetricsMonitoringAssociation) AssociationConf() *commonv1.Association return &assocConf } -func (mma *MetricsMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { - if mma.assocConfs == nil { - mma.assocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) +func (eea *EsEsAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { + if eea.AssocConfs == nil { + eea.AssocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) } if assocConf != nil { - mma.assocConfs[mma.ref] = *assocConf - } -} - -func (mma *MetricsMonitoringAssociation) AssociationID() string { - return fmt.Sprintf("%s-%s", mma.ref.Namespace, mma.ref.Name) -} - -// LogsMonitoringAssociation helps to manage the (Elasticsearch+Filebeat)/Elasticsearch association -type LogsMonitoringAssociation struct { - *Elasticsearch - ref types.NamespacedName -} - -var _ commonv1.Association = &LogsMonitoringAssociation{} - -func (lma *LogsMonitoringAssociation) Associated() commonv1.Associated { - if lma == nil { - return nil - } - if lma.Elasticsearch == nil { - lma.Elasticsearch = &Elasticsearch{} + eea.AssocConfs[eea.ref] = *assocConf } - return lma.Elasticsearch -} - -func (lma *LogsMonitoringAssociation) AssociationConfAnnotationName() string { - // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, - // based on ElasticsearchRefs - - nsNameHash := sha256.New224() - // concat with dot to avoid collisions, as namespace can't contain dots - _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", lma.ref.Namespace, lma.ref.Name))) - // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to - // give too long output - // no padding to avoid illegal '=' character in the annotation name - hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) - - return commonv1.FormatNameWithID( - commonv1.FilebeatConfigAnnotationNameBase+"%s", - hash, - ) } -func (lma *LogsMonitoringAssociation) AssociationType() commonv1.AssociationType { - return commonv1.FilebeatAssociationType +func (eea *EsEsAssociation) AssociationID() string { + return fmt.Sprintf("%s-%s", eea.ref.Namespace, eea.ref.Name) } -func (lma *LogsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { - return commonv1.ObjectSelector{ - Name: lma.ref.Name, - Namespace: lma.ref.Namespace, - } -} - -func (lma *LogsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf { - if lma.assocConfs == nil { - return nil - } - assocConf, found := lma.assocConfs[lma.ref] - if !found { - return nil - } - - return &assocConf -} - -func (lma *LogsMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { - if lma.assocConfs == nil { - lma.assocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) - } - if assocConf != nil { - lma.assocConfs[lma.ref] = *assocConf - } -} - -func (lma *LogsMonitoringAssociation) AssociationID() string { - return fmt.Sprintf("%s-%s", lma.ref.Namespace, lma.ref.Name) -} - -// RequiresAssociation returns true if the spec specifies an Elasticsearch reference. -/*func (es *Elasticsearch) RequiresAssociation() bool { - return es.Spec.Monitoring.Metrics.ElasticsearchRef.Name != "" || es.Spec.Monitoring.Logs.ElasticsearchRef.Name != "" -}*/ - // Associated methods var _ commonv1.Associated = &Elasticsearch{} @@ -264,15 +172,14 @@ func (es *Elasticsearch) GetAssociations() []commonv1.Association { associations := make([]commonv1.Association, 0) ref := es.Spec.Monitoring.Metrics.ElasticsearchRef if ref.IsDefined() { - associations = append(associations, &MetricsMonitoringAssociation{ + associations = append(associations, &EsEsAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), }) } - ref = es.Spec.Monitoring.Logs.ElasticsearchRef if ref.IsDefined() { - associations = append(associations, &LogsMonitoringAssociation{ + associations = append(associations, &EsEsAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), }) @@ -283,52 +190,40 @@ func (es *Elasticsearch) GetAssociations() []commonv1.Association { func (es *Elasticsearch) GetMonitoringMetricsAssociation() commonv1.Association { ref := es.Spec.Monitoring.Metrics.ElasticsearchRef if ref.IsDefined() { - return &MetricsMonitoringAssociation{ + return &EsEsAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), } } - return &MetricsMonitoringAssociation{} + return &EsEsAssociation{} } func (es *Elasticsearch) GetMonitoringLogsAssociation() commonv1.Association { ref := es.Spec.Monitoring.Logs.ElasticsearchRef if ref.IsDefined() { - return &LogsMonitoringAssociation{ + return &EsEsAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), } } - return &LogsMonitoringAssociation{} + return &EsEsAssociation{} } func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) commonv1.AssociationStatusMap { - switch typ { - case commonv1.MetricbeatAssociationType: - return commonv1.NewSingleAssociationStatusMap(es.Status.MonitoringMetricsAssociationStatus) - case commonv1.FilebeatAssociationType: - return commonv1.NewSingleAssociationStatusMap(es.Status.MonitoringLogsAssociationStatus) + if typ != commonv1.ElasticsearchAssociationType { + return commonv1.AssociationStatusMap{} } - return commonv1.AssociationStatusMap{} + return es.Status.ElasticsearchAssociationsStatus } func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, status commonv1.AssociationStatusMap) error { - single, err := status.Single() - if err != nil { - return err - } - - switch typ { - case commonv1.MetricbeatAssociationType: - es.Status.MonitoringMetricsAssociationStatus = single - return nil - case commonv1.FilebeatAssociationType: - es.Status.MonitoringLogsAssociationStatus = single - return nil - default: + if typ != commonv1.ElasticsearchAssociationType { return fmt.Errorf("association type %s not known", typ) } + + es.Status.ElasticsearchAssociationsStatus = status + return nil } /*func (es *Elasticsearch) AssociationID() string { @@ -626,12 +521,11 @@ type ElasticsearchStatus struct { Health ElasticsearchHealth `json:"health,omitempty"` Phase ElasticsearchOrchestrationPhase `json:"phase,omitempty"` - MonitoringMetricsAssociationStatus commonv1.AssociationStatus `json:"monitoringMetricsAssociationStatus,omitempty"` - MonitoringLogsAssociationStatus commonv1.AssociationStatus `json:"monitoringLogsAssociationStatus,omitempty"` + ElasticsearchAssociationsStatus commonv1.AssociationStatusMap `json:"esAssociationStatus,omitempty"` } type ZenDiscoveryStatus struct { - MinimumMasterNodes int `json:"minimumMasterNodes,omitempty"` + MinimueeasterNodes int `json:"minimueeasterNodes,omitempty"` } // IsDegraded returns true if the current status is worse than the previous. @@ -656,7 +550,7 @@ type Elasticsearch struct { Spec ElasticsearchSpec `json:"spec,omitempty"` Status ElasticsearchStatus `json:"status,omitempty"` - assocConfs map[types.NamespacedName]commonv1.AssociationConf `json:"-"` + AssocConfs map[types.NamespacedName]commonv1.AssociationConf `json:"-"` } // IsMarkedForDeletion returns true if the Elasticsearch is going to be deleted diff --git a/pkg/controller/association/controller/filebeat_es.go b/pkg/controller/association/controller/es_es.go similarity index 56% rename from pkg/controller/association/controller/filebeat_es.go rename to pkg/controller/association/controller/es_es.go index 87e22ba6f7..f45289c379 100644 --- a/pkg/controller/association/controller/filebeat_es.go +++ b/pkg/controller/association/controller/es_es.go @@ -18,18 +18,18 @@ import ( ) const ( - // FilebeatESAssociationLabelName marks resources created by this controller for easier retrieval. - FilebeatESAssociationLabelName = "filebeatassociation.k8s.elastic.co/name" - // FilebeatESAssociationLabelNamespace marks resources created by this controller for easier retrieval. - FilebeatESAssociationLabelNamespace = "filebeatassociation.k8s.elastic.co/namespace" - // FilebeatESAssociationLabelType marks the type of association. - FilebeatESAssociationLabelType = "filebeatassociation.k8s.elastic.co/type" + // EsEsAssociationLabelName marks resources created by this controller for easier retrieval. + EsEsAssociationLabelName = "esesassociation.k8s.elastic.co/name" + // EsEsAssociationLabelNamespace marks resources created by this controller for easier retrieval. + EsEsAssociationLabelNamespace = "esesassociation.k8s.elastic.co/namespace" + // EsEsAssociationLabelType marks the type of association. + EsEsAssociationLabelType = "esesassociation.k8s.elastic.co/type" - // FilebeatBuiltinRole is the name of the built-in role for the Filebeat system user. - FilebeatBuiltinRole = "superuser" // FIXME: create a dedicated role? + // BeatBuiltinRole is the name of the built-in role for the Metricbeat/Filebeat system user. + BeatBuiltinRole = "superuser" // FIXME: create a dedicated role? ) -func AddFilebeatES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { +func AddEsEs(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ AssociatedObjTemplate: func() commonv1.Associated { return &esv1.Elasticsearch{} }, ElasticsearchRef: func(c k8s.Client, association commonv1.Association) (bool, commonv1.ObjectSelector, error) { @@ -37,21 +37,21 @@ func AddFilebeatES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, para }, ReferencedResourceVersion: referencedElasticsearchStatusVersion, ExternalServiceURL: getElasticsearchExternalURL, - AssociationType: commonv1.FilebeatAssociationType, + AssociationType: commonv1.ElasticsearchAssociationType, AssociatedNamer: esv1.ESNamer, - AssociationName: "filebeat-es", - AssociatedShortName: "filebeat", + AssociationName: "es-es", + AssociatedShortName: "es", Labels: func(associated types.NamespacedName) map[string]string { return map[string]string{ - FilebeatESAssociationLabelName: associated.Name, - FilebeatESAssociationLabelNamespace: associated.Namespace, - FilebeatESAssociationLabelType: commonv1.FilebeatAssociationType, + EsEsAssociationLabelName: associated.Name, + EsEsAssociationLabelNamespace: associated.Namespace, + EsEsAssociationLabelType: commonv1.ElasticsearchAssociationType, } }, - AssociationConfAnnotationNameBase: commonv1.FilebeatConfigAnnotationNameBase, - UserSecretSuffix: "filebeat-user", + AssociationConfAnnotationNameBase: commonv1.ElasticsearchConfigAnnotationNameBase, + UserSecretSuffix: "beat-user", ESUserRole: func(associated commonv1.Associated) (string, error) { - return FilebeatBuiltinRole, nil + return BeatBuiltinRole, nil }, AssociationResourceNameLabelName: eslabel.ClusterNameLabelName, AssociationResourceNamespaceLabelName: eslabel.ClusterNamespaceLabelName, diff --git a/pkg/controller/association/controller/metricbeat_es.go b/pkg/controller/association/controller/metricbeat_es.go deleted file mode 100644 index e8a9d8c627..0000000000 --- a/pkg/controller/association/controller/metricbeat_es.go +++ /dev/null @@ -1,59 +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; -// you may not use this file except in compliance with the Elastic License. - -package controller - -import ( - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/manager" - - 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/utils/k8s" - "github.com/elastic/cloud-on-k8s/pkg/utils/rbac" -) - -const ( - // MetricbeatESAssociationLabelName marks resources created by this controller for easier retrieval. - MetricbeatESAssociationLabelName = "metricbeatassociation.k8s.elastic.co/name" - // MetricbeatESAssociationLabelNamespace marks resources created by this controller for easier retrieval. - MetricbeatESAssociationLabelNamespace = "metricbeatassociation.k8s.elastic.co/namespace" - // MetricbeatESAssociationLabelType marks the type of association. - MetricbeatESAssociationLabelType = "metricbeatassociation.k8s.elastic.co/type" - - // MetricbeatBuiltinRole is the name of the built-in role for the Metricbeat system user. - MetricbeatBuiltinRole = "superuser" // FIXME: create a dedicated role? -) - -func AddMetricbeatES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { - return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ - AssociatedObjTemplate: func() commonv1.Associated { return &esv1.Elasticsearch{} }, - ElasticsearchRef: func(c k8s.Client, association commonv1.Association) (bool, commonv1.ObjectSelector, error) { - return true, association.AssociationRef(), nil - }, - ReferencedResourceVersion: referencedElasticsearchStatusVersion, - ExternalServiceURL: getElasticsearchExternalURL, - AssociationType: commonv1.MetricbeatAssociationType, - AssociatedNamer: esv1.ESNamer, - AssociationName: "metricbeat-es", - AssociatedShortName: "metricbeat", - Labels: func(associated types.NamespacedName) map[string]string { - return map[string]string{ - MetricbeatESAssociationLabelName: associated.Name, - MetricbeatESAssociationLabelNamespace: associated.Namespace, - MetricbeatESAssociationLabelType: commonv1.MetricbeatAssociationType, - } - }, - AssociationConfAnnotationNameBase: commonv1.MetricbeatConfigAnnotationNameBase, - UserSecretSuffix: "metricbeat-user", - ESUserRole: func(associated commonv1.Associated) (string, error) { - return MetricbeatBuiltinRole, nil - }, - AssociationResourceNameLabelName: eslabel.ClusterNameLabelName, - AssociationResourceNamespaceLabelName: eslabel.ClusterNamespaceLabelName, - }) -} diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index cc6850a78e..d1ad4ec1c1 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -15,6 +15,8 @@ const ( ) var ( + // Environments variables used in the beats configuration to describe how to connect to Elasticsearch. + // Warning: they are hard-coded in the two configs below. EsSourceURLEnvVarKey = "ES_SOURCE_URL" EsSourceURLEnvVarValue = "https://localhost:9200" EsSourceUsernameEnvVarKey = "ES_SOURCE_USERNAME" @@ -23,7 +25,13 @@ var ( EsTargetUsernameEnvVarKey = "ES_TARGET_USERNAME" EsTargetPasswordEnvVarKey = "ES_TARGET_PASSWORD" //nolint:gosec + // Paths to the Elasticsearch CA certificates used by the beats to send data + MonitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" + MonitoringMetricsTargetEsCaCertMountPath = "/mnt/es/monitoring/metrics/target" + MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/monitoring/logs/target" + // MetricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch + // Warning: environment variables and CA cert paths are hard-coded for simplicity. MetricbeatConfig = `metricbeat.modules: - module: elasticsearch metricsets: @@ -55,6 +63,7 @@ output.elasticsearch: ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/target/ca.crt"]` // FilebeatConfig is a static configuration for Filebeat to collect Elasticsearch logs + // Warning: environment variables and CA cert paths are hard-coded for simplicity. FilebeatConfig = `filebeat.modules: # https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-elasticsearch.html - module: elasticsearch @@ -97,6 +106,7 @@ processors: - add_cloud_metadata: {} - add_host_metadata: {} +# TODO: finish #setup.dashboards.enabled: true #setup.kibana: #host: '${ES_TARGET_URL}' diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 5a18fa48eb..ca5d3f8c7e 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -39,15 +39,12 @@ func EnableStackLoggingEnvVar(builder *defaults.PodTemplateBuilder) *defaults.Po } // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers -// in the pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. +// in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { - isMonitoringMetricsDefined := IsMonitoringMetricsDefined(es) - isMonitoringLogsDefined := IsMonitoringLogDefined(es) - // Inject volumes - builder = builder.WithVolumes(monitoringVolumes(es, isMonitoringMetricsDefined, isMonitoringLogsDefined)...) + builder = builder.WithVolumes(monitoringVolumes(es)...) - if isMonitoringMetricsDefined { + if IsMonitoringMetricsDefined(es) { // Inject Metricbeat sidecar container metricBeat, err := metricbeatContainer(es) if err != nil { @@ -56,7 +53,7 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) builder.PodTemplate.Spec.Containers = append(builder.PodTemplate.Spec.Containers, metricBeat) } - if isMonitoringLogsDefined { + if IsMonitoringLogDefined(es) { // Inject Filebeat sidecar container filebeat, err := filebeatContainer(es) if err != nil { diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go index 643dc0d97a..8fb507f01d 100644 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -21,28 +21,23 @@ const ( FilebeatConfigMountPath = "/etc/filebeat.yml" MonitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" - MonitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" - MonitoringMetricsTargetEsCaCertVolumeName = "es-monitoring-metrics-target-certs" - MonitoringMetricsTargetEsCaCertMountPath = "/mnt/es/monitoring/metrics/target" - - MonitoringLogsTargetEsCaCertVolumeName = "es-monitoring-logs-certs" - MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/monitoring/logs/target" + MonitoringLogsTargetEsCaCertVolumeName = "es-monitoring-logs-certs" ) // monitoringVolumes returns the volumes to add to the Elasticsearch pod for the Metricbeat and Filebeat sidecar containers. -// Metricbeat mounts its configuration and the CA certificate of the source and the target Elasticsearch cluster. +// Metricbeat mounts its configuration and the CA certificates of the source and the target Elasticsearch cluster. // Filebeat mounts its configuration and the CA certificate of the target Elasticsearch cluster. -func monitoringVolumes(es esv1.Elasticsearch, isMonitoringMetricsDefined bool, isMonitoringLogsDefined bool) []corev1.Volume { +func monitoringVolumes(es esv1.Elasticsearch) []corev1.Volume { var volumes []corev1.Volume - if isMonitoringMetricsDefined { + if IsMonitoringMetricsDefined(es) { volumes = append(volumes, metricbeatConfigMapVolume(es).Volume(), monitoringMetricsSourceCaCertSecretVolume(es).Volume(), monitoringMetricsTargetCaCertSecretVolume(es).Volume(), ) } - if isMonitoringLogsDefined { + if IsMonitoringLogDefined(es) { volumes = append(volumes, filebeatConfigMapVolume(es).Volume(), monitoringLogsTargetCaCertSecretVolume(es).Volume(), @@ -90,7 +85,7 @@ func monitoringMetricsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.Sec } func monitoringLogsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { - assocConf := es.GetMonitoringMetricsAssociation().AssociationConf() + assocConf := es.GetMonitoringLogsAssociation().AssociationConf() return volume.NewSecretVolumeWithMountPath( assocConf.CASecretName, MonitoringLogsTargetEsCaCertVolumeName, From cd1e21ef3f0dca8823d225daa23e356d35f31c22 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 31 May 2021 18:44:01 +0200 Subject: [PATCH 04/83] Regenerate --- config/crds/all-crds.yaml | 15 ++-- ...search.k8s.elastic.co_elasticsearches.yaml | 12 +-- .../eck-operator-crds/templates/all-crds.yaml | 15 ++-- .../elasticsearch/v1/zz_generated.deepcopy.go | 74 ++++++++----------- 4 files changed, 54 insertions(+), 62 deletions(-) diff --git a/config/crds/all-crds.yaml b/config/crds/all-crds.yaml index 8a3d4666a4..efe3a02f0e 100644 --- a/config/crds/all-crds.yaml +++ b/config/crds/all-crds.yaml @@ -3026,16 +3026,19 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer + esAssociationStatus: + 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 (eg. single ES reference), this map will + contain a single entry. + type: object health: description: ElasticsearchHealth is the health of the cluster as returned by the health API. type: string - monitoringLogsAssociationStatus: - description: AssociationStatus is the status of an association resource. - type: string - monitoringMetricsAssociationStatus: - description: AssociationStatus is the status of an association resource. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index ea71600ea7..6f42855d7c 100644 --- a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -4478,15 +4478,15 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer + esAssociationStatus: + 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 (eg. single ES reference), this map will contain a single entry. + type: object health: description: ElasticsearchHealth is the health of the cluster as returned by the health API. type: string - monitoringLogsAssociationStatus: - description: AssociationStatus is the status of an association resource. - type: string - monitoringMetricsAssociationStatus: - description: AssociationStatus is the status of an association resource. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. type: string 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 8caf9e90c6..2712a29118 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 @@ -3056,16 +3056,19 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer + esAssociationStatus: + 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 (eg. single ES reference), this map will + contain a single entry. + type: object health: description: ElasticsearchHealth is the health of the cluster as returned by the health API. type: string - monitoringLogsAssociationStatus: - description: AssociationStatus is the status of an association resource. - type: string - monitoringMetricsAssociationStatus: - description: AssociationStatus is the status of an association resource. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go index cfb7d00920..713a6cbdda 100644 --- a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go +++ b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go @@ -91,9 +91,9 @@ func (in *Elasticsearch) DeepCopyInto(out *Elasticsearch) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status - if in.assocConfs != nil { - in, out := &in.assocConfs, &out.assocConfs + in.Status.DeepCopyInto(&out.Status) + if in.AssocConfs != nil { + in, out := &in.AssocConfs, &out.AssocConfs *out = make(map[types.NamespacedName]commonv1.AssociationConf, len(*in)) for key, val := range *in { (*out)[key] = val @@ -219,6 +219,13 @@ func (in *ElasticsearchSpec) DeepCopy() *ElasticsearchSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ElasticsearchStatus) DeepCopyInto(out *ElasticsearchStatus) { *out = *in + if in.ElasticsearchAssociationsStatus != nil { + in, out := &in.ElasticsearchAssociationsStatus, &out.ElasticsearchAssociationsStatus + *out = make(commonv1.AssociationStatusMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ElasticsearchStatus. @@ -232,54 +239,54 @@ func (in *ElasticsearchStatus) DeepCopy() *ElasticsearchStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FileRealmSource) DeepCopyInto(out *FileRealmSource) { +func (in *EsEsAssociation) DeepCopyInto(out *EsEsAssociation) { *out = *in - out.SecretRef = in.SecretRef + if in.Elasticsearch != nil { + in, out := &in.Elasticsearch, &out.Elasticsearch + *out = new(Elasticsearch) + (*in).DeepCopyInto(*out) + } + out.ref = in.ref } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileRealmSource. -func (in *FileRealmSource) DeepCopy() *FileRealmSource { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EsEsAssociation. +func (in *EsEsAssociation) DeepCopy() *EsEsAssociation { if in == nil { return nil } - out := new(FileRealmSource) + out := new(EsEsAssociation) 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) { +func (in *FileRealmSource) DeepCopyInto(out *FileRealmSource) { *out = *in - out.ElasticsearchRef = in.ElasticsearchRef + out.SecretRef = in.SecretRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoring. -func (in *LogsMonitoring) DeepCopy() *LogsMonitoring { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileRealmSource. +func (in *FileRealmSource) DeepCopy() *FileRealmSource { if in == nil { return nil } - out := new(LogsMonitoring) + out := new(FileRealmSource) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LogsMonitoringAssociation) DeepCopyInto(out *LogsMonitoringAssociation) { +func (in *LogsMonitoring) DeepCopyInto(out *LogsMonitoring) { *out = *in - if in.Elasticsearch != nil { - in, out := &in.Elasticsearch, &out.Elasticsearch - *out = new(Elasticsearch) - (*in).DeepCopyInto(*out) - } - out.ref = in.ref + out.ElasticsearchRef = in.ElasticsearchRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogsMonitoringAssociation. -func (in *LogsMonitoringAssociation) DeepCopy() *LogsMonitoringAssociation { +// 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(LogsMonitoringAssociation) + out := new(LogsMonitoring) in.DeepCopyInto(out) return out } @@ -300,27 +307,6 @@ func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MetricsMonitoringAssociation) DeepCopyInto(out *MetricsMonitoringAssociation) { - *out = *in - if in.Elasticsearch != nil { - in, out := &in.Elasticsearch, &out.Elasticsearch - *out = new(Elasticsearch) - (*in).DeepCopyInto(*out) - } - out.ref = in.ref -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsMonitoringAssociation. -func (in *MetricsMonitoringAssociation) DeepCopy() *MetricsMonitoringAssociation { - if in == nil { - return nil - } - out := new(MetricsMonitoringAssociation) - 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 From cc931cd5dbd3ae81ce3a09a2877cac3f1e57936a Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 1 Jun 2021 15:21:08 +0200 Subject: [PATCH 05/83] Restore hash-based annotation name --- .../elasticsearch/v1/elasticsearch_types.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 95f31d69f4..dd3a9db7c9 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -5,6 +5,8 @@ package v1 import ( + "crypto/sha256" + "encoding/base32" "fmt" corev1 "k8s.io/api/core/v1" @@ -121,7 +123,21 @@ func (eea *EsEsAssociation) Associated() commonv1.Associated { } func (eea *EsEsAssociation) AssociationConfAnnotationName() string { - return commonv1.ElasticsearchConfigAnnotationNameBase + // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, + // based on ElasticsearchRefs + + nsNameHash := sha256.New224() + // concat with dot to avoid collisions, as namespace can't contain dots + _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", eea.ref.Namespace, eea.ref.Name))) + // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to + // give too long output + // no padding to avoid illegal '=' character in the annotation name + hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) + + return commonv1.FormatNameWithID( + commonv1.ElasticsearchConfigAnnotationNameBase+"%s", + hash, + ) } func (eea *EsEsAssociation) AssociationType() commonv1.AssociationType { From e018707badfa2f631ba1c236476657cc0b46a63d Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 3 Jun 2021 13:07:19 +0200 Subject: [PATCH 06/83] Simple stack monitoring E2E test --- test/e2e/es/stack_monitoring_test.go | 122 +++++++++++++++++++++++++ test/e2e/test/elasticsearch/builder.go | 6 ++ 2 files changed, 128 insertions(+) create mode 100644 test/e2e/es/stack_monitoring_test.go diff --git a/test/e2e/es/stack_monitoring_test.go b/test/e2e/es/stack_monitoring_test.go new file mode 100644 index 0000000000..e8950c2ffa --- /dev/null +++ b/test/e2e/es/stack_monitoring_test.go @@ -0,0 +1,122 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package es + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "testing" + + esClient "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/client" + "github.com/elastic/cloud-on-k8s/test/e2e/test" + "github.com/elastic/cloud-on-k8s/test/e2e/test/elasticsearch" +) + +// TestStackMonitoring +func TestStackMonitoring(t *testing.T) { + // Create 1 monitored and 2 monitoring clusters to collect separately metrics and logs + metrics := elasticsearch.NewBuilder("test-es-mon-metrics"). + WithESMasterDataNodes(2, elasticsearch.DefaultResources) + logs := elasticsearch.NewBuilder("test-es-mon-logs"). + WithESMasterDataNodes(2, elasticsearch.DefaultResources) + monitored := elasticsearch.NewBuilder("test-es-mon-a"). + WithESMasterDataNodes(1, elasticsearch.DefaultResources). + WithMonitoring(metrics.Ref(), logs.Ref()) + + // Checks that the beats have sent data in the monitoring clusters + steps := func(k *test.K8sClient) test.StepList { + checks := stackMonitoringChecks{metrics, logs, k} + return test.StepList{ + checks.CheckMetricbeatIndex(), + checks.CheckFilebeatIndex(), + } + } + + test.Sequence(nil, steps, metrics, logs, monitored).RunSequential(t) +} + +type stackMonitoringChecks struct { + metrics elasticsearch.Builder + logs elasticsearch.Builder + k *test.K8sClient +} + +func (c *stackMonitoringChecks) CheckMetricbeatIndex() test.Step { + return test.Step{ + Name: "Check that documents are indexed in one metricbeat-* index", + Test: test.Eventually(func() error { + client, err := elasticsearch.NewElasticsearchClient(c.metrics.Elasticsearch, c.k) + if err != nil { + return err + } + err = AreIndexedDocs(client, "metricbeat-*") + if err != nil { + return err + } + return nil + })} +} + +func (c *stackMonitoringChecks) CheckFilebeatIndex() test.Step { + return test.Step{ + Name: "Check that documents are indexed in one filebeat-* index", + Test: test.Eventually(func() error { + client, err := elasticsearch.NewElasticsearchClient(c.logs.Elasticsearch, c.k) + if err != nil { + return err + } + err = AreIndexedDocs(client, "filebeat*") + if err != nil { + return err + } + return nil + })} +} + +// Index partially models Elasticsearch cluster index returned by /_cat/indices +type Index struct { + Index string `json:"index"` + DocsCount string `json:"docs.count"` +} + +func AreIndexedDocs(esClient esClient.Client, indexPattern string) error { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/_cat/indices/%s?health=green&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 []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]", len(indices), indexPattern, 1) + } + 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/elasticsearch/builder.go b/test/e2e/test/elasticsearch/builder.go index 6dfc0e8c6c..4b4eabd90b 100644 --- a/test/e2e/test/elasticsearch/builder.go +++ b/test/e2e/test/elasticsearch/builder.go @@ -448,6 +448,12 @@ func (b Builder) WithPodLabel(key, value string) Builder { return b } +func (b Builder) WithMonitoring(metricsESRef commonv1.ObjectSelector, logsESRef commonv1.ObjectSelector) Builder { + b.Elasticsearch.Spec.Monitoring.Metrics.ElasticsearchRef = metricsESRef + b.Elasticsearch.Spec.Monitoring.Logs.ElasticsearchRef = logsESRef + return b +} + // -- Helper functions func (b Builder) RuntimeObjects() []client.Object { From a27f910859943c6b24838f56e4e1c90257c6d8df Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 3 Jun 2021 13:08:23 +0200 Subject: [PATCH 07/83] Move beats config in embedded files --- .../elasticsearch/stackmon/config.go | 96 ++----------------- .../elasticsearch/stackmon/filebeat.yml | 54 +++++++++++ .../elasticsearch/stackmon/metricbeat.yml | 29 ++++++ 3 files changed, 93 insertions(+), 86 deletions(-) create mode 100644 pkg/controller/elasticsearch/stackmon/filebeat.yml create mode 100644 pkg/controller/elasticsearch/stackmon/metricbeat.yml diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index d1ad4ec1c1..da67625504 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -4,7 +4,10 @@ package stackmon -import esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" +import ( + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + _ "embed" // for the beats config files +) const ( MetricbeatConfigKey = "metricbeat.yml" @@ -31,93 +34,14 @@ var ( MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/monitoring/logs/target" // MetricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch - // Warning: environment variables and CA cert paths are hard-coded for simplicity. - MetricbeatConfig = `metricbeat.modules: -- module: elasticsearch - metricsets: - - ccr - - cluster_stats - - enrich - - index - - index_recovery - - index_summary - - ml_job - - node_stats - - shard - period: 10s - xpack.enabled: true - hosts: ["${ES_SOURCE_URL}"] - username: ${ES_SOURCE_USERNAME} - password: ${ES_SOURCE_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/source/ca.crt"] - ssl.verification_mode: "certificate" - -processors: - - add_cloud_metadata: {} - - add_host_metadata: {} - -output.elasticsearch: - hosts: ['${ES_TARGET_URL}'] - username: ${ES_TARGET_USERNAME} - password: ${ES_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/target/ca.crt"]` + // Warning: environment variables and CA cert paths defined below are hard-coded for simplicity. + //go:embed metricbeat.yml + MetricbeatConfig string // FilebeatConfig is a static configuration for Filebeat to collect Elasticsearch logs - // Warning: environment variables and CA cert paths are hard-coded for simplicity. - FilebeatConfig = `filebeat.modules: -# https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-elasticsearch.html -- module: elasticsearch - server: - enabled: true - var.paths: - - /usr/share/elasticsearch/logs/*_server.json - close_timeout: 2h - fields_under_root: true - gc: - enabled: true - var.paths: - - /usr/share/elasticsearch/logs/gc.log.[0-9]* - - /usr/share/elasticsearch/logs/gc.log - - /usr/share/elasticsearch/logs/gc.output.[0-9]* - - /usr/share/elasticsearch/logs/gc.output - close_timeout: 2h - fields_under_root: true - audit: - enabled: true - var.paths: - - /usr/share/elasticsearch/logs/*_audit.json - close_timeout: 2h - fields_under_root: true - slowlog: - enabled: true - var.paths: - - /usr/share/elasticsearch/logs/*_index_search_slowlog.json - - /usr/share/elasticsearch/logs/*_index_indexing_slowlog.json - close_timeout: 2h - fields_under_root: true - deprecation: - enabled: true - var.paths: - - /usr/share/elasticsearch/logs/*_deprecation.json - close_timeout: 2h - fields_under_root: true - -processors: - - add_cloud_metadata: {} - - add_host_metadata: {} - -# TODO: finish -#setup.dashboards.enabled: true -#setup.kibana: - #host: '${ES_TARGET_URL}' - #username: ${ES_TARGET_USERNAME} - #password: ${ES_TARGET_PASSWORD} - -output.elasticsearch: - hosts: ['${ES_TARGET_URL}'] - username: ${ES_TARGET_USERNAME} - password: ${ES_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/logs/target/ca.crt"]` + // Warning: environment variables and CA cert paths defined below are hard-coded for simplicity. + //go:embed filebeat.yml + FilebeatConfig string ) func MetricbeatConfigMapName(es esv1.Elasticsearch) string { diff --git a/pkg/controller/elasticsearch/stackmon/filebeat.yml b/pkg/controller/elasticsearch/stackmon/filebeat.yml new file mode 100644 index 0000000000..c17c6f24f0 --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/filebeat.yml @@ -0,0 +1,54 @@ +filebeat.modules: + # https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-elasticsearch.html + - module: elasticsearch + server: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_server.json + close_timeout: 2h + fields_under_root: true + gc: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/gc.log.[0-9]* + - /usr/share/elasticsearch/logs/gc.log + - /usr/share/elasticsearch/logs/gc.output.[0-9]* + - /usr/share/elasticsearch/logs/gc.output + close_timeout: 2h + fields_under_root: true + audit: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_audit.json + close_timeout: 2h + fields_under_root: true + slowlog: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_index_search_slowlog.json + - /usr/share/elasticsearch/logs/*_index_indexing_slowlog.json + close_timeout: 2h + fields_under_root: true + deprecation: + enabled: true + var.paths: + - /usr/share/elasticsearch/logs/*_deprecation.json + close_timeout: 2h + fields_under_root: true + +processors: + - add_cloud_metadata: {} + - add_host_metadata: {} + + # TODO: finish + #setup.dashboards.enabled: true + #setup.kibana: + #host: '${ES_TARGET_URL}' + #username: ${ES_TARGET_USERNAME} + #password: ${ES_TARGET_PASSWORD} + +output.elasticsearch: + hosts: ['${ES_TARGET_URL}'] + username: ${ES_TARGET_USERNAME} + password: ${ES_TARGET_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/monitoring/logs/target/ca.crt"] \ No newline at end of file diff --git a/pkg/controller/elasticsearch/stackmon/metricbeat.yml b/pkg/controller/elasticsearch/stackmon/metricbeat.yml new file mode 100644 index 0000000000..40343d6843 --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/metricbeat.yml @@ -0,0 +1,29 @@ +metricbeat.modules: + - module: elasticsearch + metricsets: + - ccr + - cluster_stats + - enrich + - index + - index_recovery + - index_summary + - ml_job + - node_stats + - shard + period: 10s + xpack.enabled: true + hosts: ["${ES_SOURCE_URL}"] + username: ${ES_SOURCE_USERNAME} + password: ${ES_SOURCE_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/source/ca.crt"] + ssl.verification_mode: "certificate" + +processors: + - add_cloud_metadata: {} + - add_host_metadata: {} + +output.elasticsearch: + hosts: ['${ES_TARGET_URL}'] + username: ${ES_TARGET_USERNAME} + password: ${ES_TARGET_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/target/ca.crt"] \ No newline at end of file From b298efc4426bf83ebb0d12f4f1f30dc4be446828 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 3 Jun 2021 15:00:56 +0200 Subject: [PATCH 08/83] Renaming --- cmd/manager/main.go | 2 +- .../elasticsearch/v1/elasticsearch_types.go | 34 +++++++++---------- .../elasticsearch/v1/zz_generated.deepcopy.go | 8 ++--- .../controller/{es_es.go => es_monitoring.go} | 27 ++++++++------- 4 files changed, 37 insertions(+), 34 deletions(-) rename pkg/controller/association/controller/{es_es.go => es_monitoring.go} (62%) diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 03f17ff383..758e73f667 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -677,7 +677,7 @@ func registerControllers(mgr manager.Manager, params operator.Parameters, access {name: "BEAT-KB", registerFunc: associationctl.AddBeatKibana}, {name: "AGENT-ES", registerFunc: associationctl.AddAgentES}, {name: "EMS-ES", registerFunc: associationctl.AddMapsES}, - {name: "ES-ES", registerFunc: associationctl.AddEsEs}, + {name: "ES-MONITORING", registerFunc: associationctl.AddEsMonitoring}, } for _, c := range assocControllers { diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index dd3a9db7c9..e24b0e01e6 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -103,16 +103,16 @@ type LogsMonitoring struct { ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` } -// EsEsAssociation helps to manage the Elasticsearch+Metricbeat+Filebeat <-> Elasticsearch(es) association -type EsEsAssociation struct { +// EsMonitoringAssociation helps to manage Elasticsearch+Metricbeat+Filebeat <-> Elasticsearch(es) associations +type EsMonitoringAssociation struct { *Elasticsearch - // ref is the namespaced name of the Elasticsearch used in Association + // ref is the namespaced name of the Elasticsearch referenced in the Association ref types.NamespacedName } -var _ commonv1.Association = &EsEsAssociation{} +var _ commonv1.Association = &EsMonitoringAssociation{} -func (eea *EsEsAssociation) Associated() commonv1.Associated { +func (eea *EsMonitoringAssociation) Associated() commonv1.Associated { if eea == nil { return nil } @@ -122,7 +122,7 @@ func (eea *EsEsAssociation) Associated() commonv1.Associated { return eea.Elasticsearch } -func (eea *EsEsAssociation) AssociationConfAnnotationName() string { +func (eea *EsMonitoringAssociation) AssociationConfAnnotationName() string { // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, // based on ElasticsearchRefs @@ -140,18 +140,18 @@ func (eea *EsEsAssociation) AssociationConfAnnotationName() string { ) } -func (eea *EsEsAssociation) AssociationType() commonv1.AssociationType { +func (eea *EsMonitoringAssociation) AssociationType() commonv1.AssociationType { return commonv1.ElasticsearchAssociationType } -func (eea *EsEsAssociation) AssociationRef() commonv1.ObjectSelector { +func (eea *EsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { return commonv1.ObjectSelector{ Name: eea.ref.Name, Namespace: eea.ref.Namespace, } } -func (eea *EsEsAssociation) AssociationConf() *commonv1.AssociationConf { +func (eea *EsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf { if eea.AssocConfs == nil { return nil } @@ -163,7 +163,7 @@ func (eea *EsEsAssociation) AssociationConf() *commonv1.AssociationConf { return &assocConf } -func (eea *EsEsAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { +func (eea *EsMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { if eea.AssocConfs == nil { eea.AssocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) } @@ -172,7 +172,7 @@ func (eea *EsEsAssociation) SetAssociationConf(assocConf *commonv1.AssociationCo } } -func (eea *EsEsAssociation) AssociationID() string { +func (eea *EsMonitoringAssociation) AssociationID() string { return fmt.Sprintf("%s-%s", eea.ref.Namespace, eea.ref.Name) } @@ -188,14 +188,14 @@ func (es *Elasticsearch) GetAssociations() []commonv1.Association { associations := make([]commonv1.Association, 0) ref := es.Spec.Monitoring.Metrics.ElasticsearchRef if ref.IsDefined() { - associations = append(associations, &EsEsAssociation{ + associations = append(associations, &EsMonitoringAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), }) } ref = es.Spec.Monitoring.Logs.ElasticsearchRef if ref.IsDefined() { - associations = append(associations, &EsEsAssociation{ + associations = append(associations, &EsMonitoringAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), }) @@ -206,23 +206,23 @@ func (es *Elasticsearch) GetAssociations() []commonv1.Association { func (es *Elasticsearch) GetMonitoringMetricsAssociation() commonv1.Association { ref := es.Spec.Monitoring.Metrics.ElasticsearchRef if ref.IsDefined() { - return &EsEsAssociation{ + return &EsMonitoringAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), } } - return &EsEsAssociation{} + return &EsMonitoringAssociation{} } func (es *Elasticsearch) GetMonitoringLogsAssociation() commonv1.Association { ref := es.Spec.Monitoring.Logs.ElasticsearchRef if ref.IsDefined() { - return &EsEsAssociation{ + return &EsMonitoringAssociation{ Elasticsearch: es, ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), } } - return &EsEsAssociation{} + return &EsMonitoringAssociation{} } func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) commonv1.AssociationStatusMap { diff --git a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go index 713a6cbdda..5b35b67437 100644 --- a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go +++ b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go @@ -239,7 +239,7 @@ func (in *ElasticsearchStatus) DeepCopy() *ElasticsearchStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EsEsAssociation) DeepCopyInto(out *EsEsAssociation) { +func (in *EsMonitoringAssociation) DeepCopyInto(out *EsMonitoringAssociation) { *out = *in if in.Elasticsearch != nil { in, out := &in.Elasticsearch, &out.Elasticsearch @@ -249,12 +249,12 @@ func (in *EsEsAssociation) DeepCopyInto(out *EsEsAssociation) { out.ref = in.ref } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EsEsAssociation. -func (in *EsEsAssociation) DeepCopy() *EsEsAssociation { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EsMonitoringAssociation. +func (in *EsMonitoringAssociation) DeepCopy() *EsMonitoringAssociation { if in == nil { return nil } - out := new(EsEsAssociation) + out := new(EsMonitoringAssociation) in.DeepCopyInto(out) return out } diff --git a/pkg/controller/association/controller/es_es.go b/pkg/controller/association/controller/es_monitoring.go similarity index 62% rename from pkg/controller/association/controller/es_es.go rename to pkg/controller/association/controller/es_monitoring.go index f45289c379..a1bb5ceaf5 100644 --- a/pkg/controller/association/controller/es_es.go +++ b/pkg/controller/association/controller/es_monitoring.go @@ -18,18 +18,21 @@ import ( ) const ( - // EsEsAssociationLabelName marks resources created by this controller for easier retrieval. - EsEsAssociationLabelName = "esesassociation.k8s.elastic.co/name" - // EsEsAssociationLabelNamespace marks resources created by this controller for easier retrieval. - EsEsAssociationLabelNamespace = "esesassociation.k8s.elastic.co/namespace" - // EsEsAssociationLabelType marks the type of association. - EsEsAssociationLabelType = "esesassociation.k8s.elastic.co/type" + // EsMonitoringAssociationLabelName marks resources created by this controller for easier retrieval. + EsMonitoringAssociationLabelName = "esmonitoringassociation.k8s.elastic.co/name" + // EsMonitoringAssociationLabelNamespace marks resources created by this controller for easier retrieval. + EsMonitoringAssociationLabelNamespace = "esmonitoringassociation.k8s.elastic.co/namespace" + // EsMonitoringAssociationLabelType marks the type of association. + EsMonitoringAssociationLabelType = "esmonitoringassociation.k8s.elastic.co/type" // BeatBuiltinRole is the name of the built-in role for the Metricbeat/Filebeat system user. BeatBuiltinRole = "superuser" // FIXME: create a dedicated role? ) -func AddEsEs(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { +// AddEsMonitoring reconciles an association between two Elasticsearch clusters for Stack monitoring. +// Beats are configured to collect monitoring metrics and logs data of the associated Elasticsearch and send +// them to the Elasticsearch referenced in the association. +func AddEsMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ AssociatedObjTemplate: func() commonv1.Associated { return &esv1.Elasticsearch{} }, ElasticsearchRef: func(c k8s.Client, association commonv1.Association) (bool, commonv1.ObjectSelector, error) { @@ -39,17 +42,17 @@ func AddEsEs(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params ope ExternalServiceURL: getElasticsearchExternalURL, AssociationType: commonv1.ElasticsearchAssociationType, AssociatedNamer: esv1.ESNamer, - AssociationName: "es-es", + AssociationName: "es-mon", AssociatedShortName: "es", Labels: func(associated types.NamespacedName) map[string]string { return map[string]string{ - EsEsAssociationLabelName: associated.Name, - EsEsAssociationLabelNamespace: associated.Namespace, - EsEsAssociationLabelType: commonv1.ElasticsearchAssociationType, + EsMonitoringAssociationLabelName: associated.Name, + EsMonitoringAssociationLabelNamespace: associated.Namespace, + EsMonitoringAssociationLabelType: commonv1.ElasticsearchAssociationType, } }, AssociationConfAnnotationNameBase: commonv1.ElasticsearchConfigAnnotationNameBase, - UserSecretSuffix: "beat-user", + UserSecretSuffix: "beat-mon-user", ESUserRole: func(associated commonv1.Associated) (string, error) { return BeatBuiltinRole, nil }, From 29e3cd91d055e9e635d773ba98ae798457ecbcd5 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 3 Jun 2021 15:01:09 +0200 Subject: [PATCH 09/83] Typo --- pkg/apis/common/v1/association.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index 46a8b39e6b..dc70a8bd71 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -79,7 +79,7 @@ func (asm AssociationStatusMap) Single() (AssociationStatus, error) { return result, nil } -// AllEstablished returns true iff all Associations have AssociationEstablished status, false otherwise. +// AllEstablished returns true if all Associations have AssociationEstablished status, false otherwise. func (asm AssociationStatusMap) AllEstablished() bool { for _, status := range asm { if status != AssociationEstablished { From 964bedd18876bd66f0b2f040092d8db4fe51edf7 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 3 Jun 2021 15:01:27 +0200 Subject: [PATCH 10/83] Revert bad replace all --- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index e24b0e01e6..99092f4ae3 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -541,7 +541,7 @@ type ElasticsearchStatus struct { } type ZenDiscoveryStatus struct { - MinimueeasterNodes int `json:"minimueeasterNodes,omitempty"` + MinimumMasterNodes int `json:"minimumMasterNodes,omitempty"` } // IsDegraded returns true if the current status is worse than the previous. From 9a2a5e3112389cdaccb4625ad45b45438a5a4b0e Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 3 Jun 2021 15:52:28 +0200 Subject: [PATCH 11/83] Avoid to use configmap subpath --- pkg/controller/common/volume/configmap.go | 10 ------- .../elasticsearch/configmap/configmap.go | 18 ++----------- pkg/controller/elasticsearch/driver/driver.go | 2 +- .../elasticsearch/stackmon/config.go | 22 ++++++++++++--- .../elasticsearch/stackmon/volume.go | 27 +++++++++++-------- 5 files changed, 37 insertions(+), 42 deletions(-) diff --git a/pkg/controller/common/volume/configmap.go b/pkg/controller/common/volume/configmap.go index e371d49221..316c2fb7d4 100644 --- a/pkg/controller/common/volume/configmap.go +++ b/pkg/controller/common/volume/configmap.go @@ -23,16 +23,6 @@ func NewConfigMapVolumeWithMode(configMapName, name, mountPath string, defaultMo } } -func NewConfigMapVolumeWithSubPath(configMapName, name, mountPath string, subPath string) ConfigMapVolume { - return ConfigMapVolume{ - configMapName: configMapName, - name: name, - mountPath: mountPath, - defaultMode: corev1.ConfigMapVolumeSourceDefaultMode, - subPath: subPath, - } -} - // ConfigMapVolume defines a volume to expose a configmap type ConfigMapVolume struct { configMapName string diff --git a/pkg/controller/elasticsearch/configmap/configmap.go b/pkg/controller/elasticsearch/configmap/configmap.go index f2c612c4d0..eeaf607d66 100644 --- a/pkg/controller/elasticsearch/configmap/configmap.go +++ b/pkg/controller/elasticsearch/configmap/configmap.go @@ -60,26 +60,12 @@ func ReconcileMetricbeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Ela span, _ := apm.StartSpan(ctx, "reconcile_metricbeat_config", tracing.SpanTypeApp) defer span.End() - configMap := NewConfigMapWithData( - types.NamespacedName{Namespace: es.Namespace, Name: stackmon.MetricbeatConfigMapName(es)}, - map[string]string{ - stackmon.MetricbeatConfigKey: stackmon.MetricbeatConfig, - }, - ) - - return ReconcileConfigMap(c, es, configMap) + return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.MetricbeatConfigMapParams(es))) } func ReconcileFilebeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasticsearch) error { span, _ := apm.StartSpan(ctx, "reconcile_filebeat_config", tracing.SpanTypeApp) defer span.End() - configMap := NewConfigMapWithData( - types.NamespacedName{Namespace: es.Namespace, Name: stackmon.FilebeatConfigMapName(es)}, - map[string]string{ - stackmon.FilebeatConfigKey: stackmon.FilebeatConfig, - }, - ) - - return ReconcileConfigMap(c, es, configMap) + return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.FilebeatConfigMapParams(es))) } diff --git a/pkg/controller/elasticsearch/driver/driver.go b/pkg/controller/elasticsearch/driver/driver.go index cf23a14d50..53ba104b3a 100644 --- a/pkg/controller/elasticsearch/driver/driver.go +++ b/pkg/controller/elasticsearch/driver/driver.go @@ -245,7 +245,7 @@ func (d *defaultDriver) Reconcile(ctx context.Context) *reconciler.Results { results = results.WithResult(defaultRequeue) } - // reconcile monitoring configurations + // reconcile Beat configurations when monitoring is enabled if stackmon.IsMonitoringMetricsDefined(d.ES) { if err := configmap.ReconcileMetricbeatConfigMap(ctx, d.Client, d.ES); err != nil { return results.WithError(err) diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index da67625504..3b4b840cba 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -5,16 +5,18 @@ package stackmon import ( - esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" _ "embed" // for the beats config files + + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + "k8s.io/apimachinery/pkg/types" ) const ( MetricbeatConfigKey = "metricbeat.yml" MetricbeatConfigMapSuffix = "metricbeat-config" - FilebeatConfigKey = "filebeat.yml" FilebeatConfigMapSuffix = "filebeat-config" + FilebeatConfigKey = "filebeat.yml" ) var ( @@ -44,10 +46,22 @@ var ( FilebeatConfig string ) -func MetricbeatConfigMapName(es esv1.Elasticsearch) string { +func metricbeatConfigMapName(es esv1.Elasticsearch) string { return esv1.ESNamer.Suffix(es.Name, MetricbeatConfigMapSuffix) } -func FilebeatConfigMapName(es esv1.Elasticsearch) string { +func filebeatConfigMapName(es esv1.Elasticsearch) string { return esv1.ESNamer.Suffix(es.Name, FilebeatConfigMapSuffix) } + +func MetricbeatConfigMapParams(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { + nsn := types.NamespacedName{Namespace: es.Namespace, Name: metricbeatConfigMapName(es)} + data := map[string]string{MetricbeatConfigKey: MetricbeatConfig} + return nsn, data +} + +func FilebeatConfigMapParams(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { + nsn := types.NamespacedName{Namespace: es.Namespace, Name: filebeatConfigMapName(es)} + data := map[string]string{FilebeatConfigKey: FilebeatConfig} + return nsn, data +} \ No newline at end of file diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go index 8fb507f01d..2ce2fa679d 100644 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -5,6 +5,8 @@ package stackmon import ( + "path/filepath" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/certificates" "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" @@ -14,15 +16,20 @@ import ( const ( MetricbeatContainerName = "metricbeat" MetricbeatConfigVolumeName = "metricbeat-config" - MetricbeatConfigMountPath = "/etc/metricbeat.yml" + MetricbeatConfigDirMountPath = "/etc/metricbeat-config" FilebeatContainerName = "filebeat" FilebeatConfigVolumeName = "filebeat-config" - FilebeatConfigMountPath = "/etc/filebeat.yml" + FilebeatConfigDirMountPath = "/etc/filebeat-config" MonitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" MonitoringMetricsTargetEsCaCertVolumeName = "es-monitoring-metrics-target-certs" - MonitoringLogsTargetEsCaCertVolumeName = "es-monitoring-logs-certs" + MonitoringLogsTargetEsCaCertVolumeName = "es-monitoring-logs-target-certs" +) + +var ( + MetricbeatConfigMountPath = filepath.Join(MetricbeatConfigDirMountPath, MetricbeatConfigKey) + FilebeatConfigMountPath = filepath.Join(FilebeatConfigDirMountPath, FilebeatConfigKey) ) // monitoringVolumes returns the volumes to add to the Elasticsearch pod for the Metricbeat and Filebeat sidecar containers. @@ -47,20 +54,18 @@ func monitoringVolumes(es esv1.Elasticsearch) []corev1.Volume { } func metricbeatConfigMapVolume(es esv1.Elasticsearch) volume.ConfigMapVolume { - return volume.NewConfigMapVolumeWithSubPath( - MetricbeatConfigMapName(es), + return volume.NewConfigMapVolume( + metricbeatConfigMapName(es), MetricbeatConfigVolumeName, - MetricbeatConfigMountPath, - MetricbeatConfigKey, + MetricbeatConfigDirMountPath, ) } func filebeatConfigMapVolume(es esv1.Elasticsearch) volume.ConfigMapVolume { - return volume.NewConfigMapVolumeWithSubPath( - FilebeatConfigMapName(es), + return volume.NewConfigMapVolume( + filebeatConfigMapName(es), FilebeatConfigVolumeName, - FilebeatConfigMountPath, - FilebeatConfigKey, + FilebeatConfigDirMountPath, ) } From 3f5d8ee7ff1f03b178465bf8b08ba575eae2908c Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 3 Jun 2021 15:52:40 +0200 Subject: [PATCH 12/83] containerImage func godoc --- .../elasticsearch/stackmon/container.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index ca5d3f8c7e..361cb249c1 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -109,15 +109,20 @@ func filebeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { }, nil } +// containerImage returns the full Beat container image with the image registry. +// If the Elasticsearch specification is configured with a custom image, we do best effort by trying to derive the Beat +// image from the Elasticsearch custom image with an image name replacement +// (/elasticsearch/elasticsearch: becomes /beats/:) func containerImage(es esv1.Elasticsearch, defaultImage container.Image) (string, error) { - customImage := es.Spec.Image - if customImage != "" { + fullCustomImage := es.Spec.Image + if fullCustomImage != "" { esImage := string(container.ElasticsearchImage) - if strings.Contains(customImage, esImage) { - // Derive the image from the custom image by replacing the ES image by the default beat image. - return strings.ReplaceAll(es.Spec.Image, esImage, string(defaultImage)), nil + // Check if Elasticsearch image follows official Elastic naming + if strings.Contains(fullCustomImage, esImage) { + // Derive the Beat image from the ES custom image, there is no guarantee that the resulted image exists + return strings.ReplaceAll(fullCustomImage, esImage, string(defaultImage)), nil } - return "", errors.New("Stack monitoring not supported with custom image") + return "", errors.New("stack monitoring not supported with custom image") } return container.ImageRepository(defaultImage, es.Spec.Version), nil } From 064fd501cdbecddcf93acac069d9670c2c83fe6c Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 7 Jun 2021 22:07:26 +0200 Subject: [PATCH 13/83] Introduce WithContainers to avoid weirdness with container defaulter --- .../common/defaults/pod_template.go | 35 +++++++--- pkg/controller/elasticsearch/driver/driver.go | 2 +- .../elasticsearch/nodespec/podspec.go | 12 +--- .../elasticsearch/nodespec/resources.go | 4 +- .../elasticsearch/settings/merged_config.go | 4 +- .../elasticsearch/stackmon/config.go | 2 +- .../elasticsearch/stackmon/container.go | 70 +++++++++++-------- .../elasticsearch/stackmon/volume.go | 19 ++--- 8 files changed, 78 insertions(+), 70 deletions(-) diff --git a/pkg/controller/common/defaults/pod_template.go b/pkg/controller/common/defaults/pod_template.go index 37ca183871..3274cae534 100644 --- a/pkg/controller/common/defaults/pod_template.go +++ b/pkg/controller/common/defaults/pod_template.go @@ -55,23 +55,27 @@ func NewPodTemplateBuilder(base corev1.PodTemplateSpec, containerName string) *P return builder.setDefaults() } +// getContainer retrieves the existing Container from the pod template +func (b *PodTemplateBuilder) getContainer() *corev1.Container { + for i, c := range b.PodTemplate.Spec.Containers { + if c.Name == b.containerName { + return &b.PodTemplate.Spec.Containers[i] + } + } + return nil +} +func (b *PodTemplateBuilder) setContainerDefaulter() { + b.containerDefaulter = container.NewDefaulter(b.getContainer()) +} + // setDefaults sets up a default Container in the pod template, // and disables service account token auto mount. func (b *PodTemplateBuilder) setDefaults() *PodTemplateBuilder { - // retrieve the existing Container from the pod template - getContainer := func() *corev1.Container { - for i, c := range b.PodTemplate.Spec.Containers { - if c.Name == b.containerName { - return &b.PodTemplate.Spec.Containers[i] - } - } - return nil - } - userContainer := getContainer() + userContainer := b.getContainer() if userContainer == nil { // create the default Container if not provided by the user b.PodTemplate.Spec.Containers = append(b.PodTemplate.Spec.Containers, corev1.Container{Name: b.containerName}) - b.containerDefaulter = container.NewDefaulter(getContainer()) + b.setContainerDefaulter() } else { b.containerDefaulter = container.NewDefaulter(userContainer) } @@ -179,6 +183,15 @@ func (b *PodTemplateBuilder) WithTerminationGracePeriod(period int64) *PodTempla return b } +// WithContainer appends the given containers to the list of containers belonging to the pod. +// It also ensures that the base container defaulter still points to the container in the list because append() +// create a new slice. +func (b *PodTemplateBuilder) WithContainers(containers ...corev1.Container) *PodTemplateBuilder { + b.PodTemplate.Spec.Containers = append(b.PodTemplate.Spec.Containers, containers...) + b.setContainerDefaulter() + return b +} + // WithInitContainerDefaults sets default values for the current init containers. // // Defaults: diff --git a/pkg/controller/elasticsearch/driver/driver.go b/pkg/controller/elasticsearch/driver/driver.go index 53ba104b3a..f8b8042f62 100644 --- a/pkg/controller/elasticsearch/driver/driver.go +++ b/pkg/controller/elasticsearch/driver/driver.go @@ -245,7 +245,7 @@ func (d *defaultDriver) Reconcile(ctx context.Context) *reconciler.Results { results = results.WithResult(defaultRequeue) } - // reconcile Beat configurations when monitoring is enabled + // reconcile Beats configs on demand if stackmon.IsMonitoringMetricsDefined(d.ES) { if err := configmap.ReconcileMetricbeatConfigMap(ctx, d.Client, d.ES); err != nil { return results.WithError(err) diff --git a/pkg/controller/elasticsearch/nodespec/podspec.go b/pkg/controller/elasticsearch/nodespec/podspec.go index d99b6e5ca7..7d4dea8bb4 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec.go +++ b/pkg/controller/elasticsearch/nodespec/podspec.go @@ -74,10 +74,6 @@ func BuildPodTemplateSpec( }) } - if stackmon.IsMonitoringLogDefined(es) { - builder = stackmon.EnableStackLoggingEnvVar(builder) - } - headlessServiceName := HeadlessServiceName(esv1.StatefulSet(es.Name, nodeSet.Name)) builder = builder. WithLabels(labels). @@ -95,11 +91,9 @@ func BuildPodTemplateSpec( WithInitContainerDefaults(corev1.EnvVar{Name: settings.HeadlessServiceName, Value: headlessServiceName}). WithPreStopHook(*NewPreStopHook()) - if stackmon.IsMonitoringDefined(es) { - builder, err = stackmon.WithMonitoring(builder, es) - if err != nil { - return corev1.PodTemplateSpec{}, err - } + builder, err = stackmon.WithMonitoring(builder, es) + if err != nil { + return corev1.PodTemplateSpec{}, err } return builder.PodTemplate, nil diff --git a/pkg/controller/elasticsearch/nodespec/resources.go b/pkg/controller/elasticsearch/nodespec/resources.go index f88b93c4c3..8694699195 100644 --- a/pkg/controller/elasticsearch/nodespec/resources.go +++ b/pkg/controller/elasticsearch/nodespec/resources.go @@ -55,8 +55,8 @@ func BuildExpectedResources( if nodeSpec.Config != nil { userCfg = *nodeSpec.Config } - isMonitoring := stackmon.IsMonitoringDefined(es) - cfg, err := settings.NewMergedESConfig(es.Name, ver, ipFamily, es.Spec.HTTP, userCfg, isMonitoring) + isMonitoringMetrics := stackmon.IsMonitoringMetricsDefined(es) + cfg, err := settings.NewMergedESConfig(es.Name, ver, ipFamily, es.Spec.HTTP, userCfg, isMonitoringMetrics) if err != nil { return nil, err } diff --git a/pkg/controller/elasticsearch/settings/merged_config.go b/pkg/controller/elasticsearch/settings/merged_config.go index 4df5523f57..b59524ab90 100644 --- a/pkg/controller/elasticsearch/settings/merged_config.go +++ b/pkg/controller/elasticsearch/settings/merged_config.go @@ -32,7 +32,7 @@ func NewMergedESConfig( ipFamily corev1.IPFamily, httpConfig commonv1.HTTPConfig, userConfig commonv1.Config, - isMonitoring bool, + isMonitoringMetrics bool, ) (CanonicalConfig, error) { userCfg, err := common.NewCanonicalConfigFrom(userConfig.Data) if err != nil { @@ -46,7 +46,7 @@ func NewMergedESConfig( if err != nil { return CanonicalConfig{}, err } - if isMonitoring { + if isMonitoringMetrics { err = config.MergeWith(monitoringConfig().CanonicalConfig) } if err != nil { diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index 3b4b840cba..02df8d1d4b 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -64,4 +64,4 @@ func FilebeatConfigMapParams(es esv1.Elasticsearch) (types.NamespacedName, map[s nsn := types.NamespacedName{Namespace: es.Namespace, Name: filebeatConfigMapName(es)} data := map[string]string{FilebeatConfigKey: FilebeatConfig} return nsn, data -} \ No newline at end of file +} diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 361cb249c1..d39b6c322c 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -5,6 +5,7 @@ package stackmon import ( + "path/filepath" "strings" v1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" @@ -18,55 +19,62 @@ import ( ) var ( - EsLogStyleEnvVarKey = "ES_LOG_STYLE" - EsLogStyleEnvVarValue = "file" -) - -func IsMonitoringDefined(es esv1.Elasticsearch) bool { - return IsMonitoringMetricsDefined(es) || IsMonitoringLogDefined(es) -} - -func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { - return es.Spec.Monitoring.Metrics.ElasticsearchRef.IsDefined() -} + metricbeatConfigMountPath = filepath.Join(MetricbeatConfigDirMountPath, MetricbeatConfigKey) + filebeatConfigMountPath = filepath.Join(FilebeatConfigDirMountPath, FilebeatConfigKey) -func IsMonitoringLogDefined(es esv1.Elasticsearch) bool { - return es.Spec.Monitoring.Logs.ElasticsearchRef.IsDefined() -} - -func EnableStackLoggingEnvVar(builder *defaults.PodTemplateBuilder) *defaults.PodTemplateBuilder { - return builder.WithEnv(corev1.EnvVar{Name: EsLogStyleEnvVarKey, Value: EsLogStyleEnvVarValue}) -} + esLogStyleEnvVarKey = "ES_LOG_STYLE" + esLogStyleEnvVarValue = "file" +) // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers // in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { - // Inject volumes - builder = builder.WithVolumes(monitoringVolumes(es)...) + isMonitoringMetrics := IsMonitoringMetricsDefined(es) + isMonitoringLog := IsMonitoringLogDefined(es) - if IsMonitoringMetricsDefined(es) { + if isMonitoringMetrics || isMonitoringLog { + // Inject volumes + builder.WithVolumes(monitoringVolumes(es)...) + } + + if isMonitoringMetrics { // Inject Metricbeat sidecar container - metricBeat, err := metricbeatContainer(es) + metricbeat, err := metricbeatContainer(es) if err != nil { return nil, err } - builder.PodTemplate.Spec.Containers = append(builder.PodTemplate.Spec.Containers, metricBeat) + builder.WithContainers(metricbeat) } - if IsMonitoringLogDefined(es) { + if isMonitoringLog { + // Enable stack logging in files + builder.WithEnv(stackLoggingEnvVar()) + // Inject Filebeat sidecar container filebeat, err := filebeatContainer(es) if err != nil { return nil, err } - builder.PodTemplate.Spec.Containers = append(builder.PodTemplate.Spec.Containers, filebeat) + builder.WithContainers(filebeat) } return builder, nil } +func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { + return es.Spec.Monitoring.Metrics.ElasticsearchRef.IsDefined() +} + +func IsMonitoringLogDefined(es esv1.Elasticsearch) bool { + return es.Spec.Monitoring.Logs.ElasticsearchRef.IsDefined() +} + +func stackLoggingEnvVar() corev1.EnvVar { + return corev1.EnvVar{Name: esLogStyleEnvVarKey, Value: esLogStyleEnvVarValue} +} + func metricbeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { - image, err := containerImage(es, container.MetricbeatImage) + image, err := fullContainerImage(es, container.MetricbeatImage) if err != nil { return corev1.Container{}, err } @@ -77,7 +85,7 @@ func metricbeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { return corev1.Container{ Name: MetricbeatContainerName, Image: image, - Args: []string{"-c", MetricbeatConfigMountPath, "-e"}, + Args: []string{"-c", metricbeatConfigMountPath, "-e"}, Env: append(envVars, defaults.PodDownwardEnvVars()...), VolumeMounts: []corev1.VolumeMount{ metricbeatConfigMapVolume(es).VolumeMount(), @@ -88,7 +96,7 @@ func metricbeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { } func filebeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { - image, err := containerImage(es, container.FilebeatImage) + image, err := fullContainerImage(es, container.FilebeatImage) if err != nil { return corev1.Container{}, err } @@ -99,7 +107,7 @@ func filebeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { return corev1.Container{ Name: FilebeatContainerName, Image: image, - Args: []string{"-c", FilebeatConfigMountPath, "-e"}, + Args: []string{"-c", filebeatConfigMountPath, "-e"}, Env: append(envVars, defaults.PodDownwardEnvVars()...), VolumeMounts: []corev1.VolumeMount{ esvolume.DefaultLogsVolumeMount, @@ -109,11 +117,11 @@ func filebeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { }, nil } -// containerImage returns the full Beat container image with the image registry. +// fullContainerImage returns the full Beat container image with the image registry. // If the Elasticsearch specification is configured with a custom image, we do best effort by trying to derive the Beat // image from the Elasticsearch custom image with an image name replacement // (/elasticsearch/elasticsearch: becomes /beats/:) -func containerImage(es esv1.Elasticsearch, defaultImage container.Image) (string, error) { +func fullContainerImage(es esv1.Elasticsearch, defaultImage container.Image) (string, error) { fullCustomImage := es.Spec.Image if fullCustomImage != "" { esImage := string(container.ElasticsearchImage) diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go index 2ce2fa679d..6fdf3ab589 100644 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -5,8 +5,6 @@ package stackmon import ( - "path/filepath" - esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/certificates" "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" @@ -14,24 +12,19 @@ import ( ) const ( - MetricbeatContainerName = "metricbeat" - MetricbeatConfigVolumeName = "metricbeat-config" - MetricbeatConfigDirMountPath = "/etc/metricbeat-config" + MetricbeatContainerName = "metricbeat" + MetricbeatConfigVolumeName = "metricbeat-config" + MetricbeatConfigDirMountPath = "/etc/metricbeat-config" - FilebeatContainerName = "filebeat" - FilebeatConfigVolumeName = "filebeat-config" - FilebeatConfigDirMountPath = "/etc/filebeat-config" + FilebeatContainerName = "filebeat" + FilebeatConfigVolumeName = "filebeat-config" + FilebeatConfigDirMountPath = "/etc/filebeat-config" MonitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" MonitoringMetricsTargetEsCaCertVolumeName = "es-monitoring-metrics-target-certs" MonitoringLogsTargetEsCaCertVolumeName = "es-monitoring-logs-target-certs" ) -var ( - MetricbeatConfigMountPath = filepath.Join(MetricbeatConfigDirMountPath, MetricbeatConfigKey) - FilebeatConfigMountPath = filepath.Join(FilebeatConfigDirMountPath, FilebeatConfigKey) -) - // monitoringVolumes returns the volumes to add to the Elasticsearch pod for the Metricbeat and Filebeat sidecar containers. // Metricbeat mounts its configuration and the CA certificates of the source and the target Elasticsearch cluster. // Filebeat mounts its configuration and the CA certificate of the target Elasticsearch cluster. From 76f4f27ad7edb99298ab345000ab732779d0968a Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 7 Jun 2021 22:17:52 +0200 Subject: [PATCH 14/83] Wording --- config/crds/all-crds.yaml | 6 +++--- .../bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml | 4 ++-- .../charts/eck-operator-crds/templates/all-crds.yaml | 6 +++--- docs/reference/api-docs.asciidoc | 4 ++-- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 6 +++--- pkg/controller/association/controller/es_monitoring.go | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/config/crds/all-crds.yaml b/config/crds/all-crds.yaml index efe3a02f0e..3f2cc48cf9 100644 --- a/config/crds/all-crds.yaml +++ b/config/crds/all-crds.yaml @@ -2167,9 +2167,9 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract log and stack monitoring + description: Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are - deployed in the same pod as sidecar and each one send data to one + deployed in the same Pod as sidecars and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. properties: @@ -2203,7 +2203,7 @@ spec: elasticsearchRef: description: ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving stack monitoring metrics. + dedicated to receiving Stack Monitoring metrics. properties: name: description: Name of the Kubernetes object. diff --git a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index 6f42855d7c..cc35b004a5 100644 --- a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -243,7 +243,7 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract log and stack monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same pod as sidecar and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. + description: Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. properties: logs: properties: @@ -266,7 +266,7 @@ spec: metrics: properties: elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving stack monitoring metrics. + description: ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving Stack Monitoring metrics. properties: name: description: Name of the Kubernetes object. 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 2712a29118..2f793a9b1b 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 @@ -2197,9 +2197,9 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract log and stack monitoring + description: Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are - deployed in the same pod as sidecar and each one send data to one + deployed in the same Pod as sidecars and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. properties: @@ -2233,7 +2233,7 @@ spec: elasticsearchRef: description: ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving stack monitoring metrics. + dedicated to receiving Stack Monitoring metrics. properties: name: description: Name of the Kubernetes object. diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index dba4de7017..3cf11187ae 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -904,7 +904,7 @@ ElasticsearchSpec holds the specification of an Elasticsearch cluster. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (eg. a remote Elasticsearch cluster) in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`remoteClusters`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract log and stack monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same pod as sidecar and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. |=== @@ -956,7 +956,7 @@ FileRealmSource references users to create in the Elasticsearch cluster. [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRef`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving stack monitoring metrics. +| *`elasticsearchRef`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving Stack Monitoring metrics. |=== diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 99092f4ae3..4d57f442f6 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -78,8 +78,8 @@ type ElasticsearchSpec struct { // +kubebuilder:validation:Enum=DeleteOnScaledownOnly;DeleteOnScaledownAndClusterDeletion VolumeClaimDeletePolicy VolumeClaimDeletePolicy `json:"volumeClaimDeletePolicy,omitempty"` - // Monitoring enables you to extract log and stack monitoring metrics of this Elasticsearch cluster. - // Metricbeat and Filebeat are deployed in the same pod as sidecar and each one send data to one or two different + // Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. + // Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one send data to one or two different // monitoring Elasticsearch clusters running in the same Kubernetes cluster. // +kubebuilder:validation:Optional Monitoring Monitoring `json:"monitoring,omitempty"` @@ -93,7 +93,7 @@ type Monitoring struct { type MetricsMonitoring struct { // ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster - // dedicated to receiving stack monitoring metrics. + // dedicated to receiving Stack Monitoring metrics. ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` } diff --git a/pkg/controller/association/controller/es_monitoring.go b/pkg/controller/association/controller/es_monitoring.go index a1bb5ceaf5..f62e6ff2b1 100644 --- a/pkg/controller/association/controller/es_monitoring.go +++ b/pkg/controller/association/controller/es_monitoring.go @@ -29,7 +29,7 @@ const ( BeatBuiltinRole = "superuser" // FIXME: create a dedicated role? ) -// AddEsMonitoring reconciles an association between two Elasticsearch clusters for Stack monitoring. +// AddEsMonitoring reconciles an association between two Elasticsearch clusters for Stack Monitoring. // Beats are configured to collect monitoring metrics and logs data of the associated Elasticsearch and send // them to the Elasticsearch referenced in the association. func AddEsMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { From 9f163624ee91d632484b81dc5ffe6c476e44fdf1 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 7 Jun 2021 22:19:49 +0200 Subject: [PATCH 15/83] Remove unused code --- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 4d57f442f6..ea88921fae 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -242,10 +242,6 @@ func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, s return nil } -/*func (es *Elasticsearch) AssociationID() string { - return commonv1.SingletonAssociationID -}*/ - // VolumeClaimDeletePolicy describes the delete policy for handling PersistentVolumeClaims that hold Elasticsearch data. // Inspired by https://github.com/kubernetes/enhancements/pull/2440 type VolumeClaimDeletePolicy string From 27ab36e73342fecf60dff0cdb85a81bd18b156a7 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 7 Jun 2021 22:19:58 +0200 Subject: [PATCH 16/83] Sort imports --- pkg/controller/elasticsearch/driver/driver.go | 2 +- pkg/controller/elasticsearch/nodespec/podspec.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/elasticsearch/driver/driver.go b/pkg/controller/elasticsearch/driver/driver.go index f8b8042f62..ebe1fccfe4 100644 --- a/pkg/controller/elasticsearch/driver/driver.go +++ b/pkg/controller/elasticsearch/driver/driver.go @@ -10,7 +10,6 @@ import ( "fmt" "time" - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/record" controller "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -39,6 +38,7 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/remotecluster" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/services" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/settings" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) diff --git a/pkg/controller/elasticsearch/nodespec/podspec.go b/pkg/controller/elasticsearch/nodespec/podspec.go index 7d4dea8bb4..17917bd93b 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec.go +++ b/pkg/controller/elasticsearch/nodespec/podspec.go @@ -8,7 +8,6 @@ import ( "crypto/sha256" "fmt" - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" corev1 "k8s.io/api/core/v1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" @@ -22,6 +21,7 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/network" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/settings" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" "github.com/elastic/cloud-on-k8s/pkg/utils/pointer" From 02400fda260c63f3aed4914956d231af517fb315 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 8 Jun 2021 11:15:28 +0200 Subject: [PATCH 17/83] Reject unsupported version --- .../elasticsearch/stackmon/container.go | 37 +++++++++++++++++-- .../elasticsearch/validation/validations.go | 14 +++++++ test/e2e/es/stack_monitoring_test.go | 7 ++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index d39b6c322c..e697f5fb79 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -5,6 +5,7 @@ package stackmon import ( + "fmt" "path/filepath" "strings" @@ -12,6 +13,7 @@ import ( 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/defaults" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" "github.com/pkg/errors" @@ -24,6 +26,11 @@ var ( esLogStyleEnvVarKey = "ES_LOG_STYLE" esLogStyleEnvVarValue = "file" + + // Minimum Stack version to enable Stack Monitoring. + // This requirement comes from the fact that we configure Elasticsearch to write logs to disk for Filebeat + // via the env var ES_LOG_STYLE available from this version. + MinStackVersion = version.MustParse("7.14.0") ) // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers @@ -32,11 +39,20 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) isMonitoringMetrics := IsMonitoringMetricsDefined(es) isMonitoringLog := IsMonitoringLogDefined(es) - if isMonitoringMetrics || isMonitoringLog { - // Inject volumes - builder.WithVolumes(monitoringVolumes(es)...) + // No monitoring defined + if !isMonitoringMetrics && !isMonitoringLog { + return builder, nil + } + + // Reject unsupported version + err := IsSupportedVersion(es.Spec.Version) + if err != nil { + return nil, err } + // Inject volumes + builder.WithVolumes(monitoringVolumes(es)...) + if isMonitoringMetrics { // Inject Metricbeat sidecar container metricbeat, err := metricbeatContainer(es) @@ -61,6 +77,10 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) return builder, nil } +func IsStackMonitoringDefined(es esv1.Elasticsearch) bool { + return IsMonitoringMetricsDefined(es) || IsMonitoringLogDefined(es) +} + func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { return es.Spec.Monitoring.Metrics.ElasticsearchRef.IsDefined() } @@ -69,6 +89,17 @@ func IsMonitoringLogDefined(es esv1.Elasticsearch) bool { return es.Spec.Monitoring.Logs.ElasticsearchRef.IsDefined() } +func IsSupportedVersion(esVersion string) error { + ver, err := version.Parse(esVersion) + if err != nil { + return err + } + if ver.LT(MinStackVersion) { + return fmt.Errorf("unsupported version for Stack Monitoring: required >= %s", MinStackVersion) + } + return nil +} + func stackLoggingEnvVar() corev1.EnvVar { return corev1.EnvVar{Name: esLogStyleEnvVarKey, Value: esLogStyleEnvVarValue} } diff --git a/pkg/controller/elasticsearch/validation/validations.go b/pkg/controller/elasticsearch/validation/validations.go index 2cb8578be3..d322e1c8eb 100644 --- a/pkg/controller/elasticsearch/validation/validations.go +++ b/pkg/controller/elasticsearch/validation/validations.go @@ -12,6 +12,7 @@ import ( 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/version" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" esversion "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/version" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ulog "github.com/elastic/cloud-on-k8s/pkg/utils/log" @@ -37,6 +38,7 @@ const ( unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported" unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths." unsupportedVersionMsg = "Unsupported version" + unsupportedVersionForStackMonitoringMsg = "Unsupported version for Stack Monitoring. Required >= %s." ) type validation func(esv1.Elasticsearch) field.ErrorList @@ -49,6 +51,7 @@ var validations = []validation{ supportedVersion, validSanIP, validAutoscalingConfiguration, + supportedVersionForStackMonitoring, } type updateValidation func(esv1.Elasticsearch, esv1.Elasticsearch) field.ErrorList @@ -101,6 +104,17 @@ func supportedVersion(es esv1.Elasticsearch) field.ErrorList { return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, unsupportedVersionMsg)} } +func supportedVersionForStackMonitoring(es esv1.Elasticsearch) field.ErrorList { + if stackmon.IsStackMonitoringDefined(es) { + err := stackmon.IsSupportedVersion(es.Spec.Version) + if err != nil { + return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, + fmt.Sprintf(unsupportedVersionForStackMonitoringMsg, stackmon.MinStackVersion.String()))} + } + } + return field.ErrorList{} +} + // hasCorrectNodeRoles checks whether Elasticsearch node roles are correctly configured. // The rules are: // There must be at least one master node. diff --git a/test/e2e/es/stack_monitoring_test.go b/test/e2e/es/stack_monitoring_test.go index e8950c2ffa..f8c45be9e6 100644 --- a/test/e2e/es/stack_monitoring_test.go +++ b/test/e2e/es/stack_monitoring_test.go @@ -14,12 +14,19 @@ import ( "testing" esClient "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/client" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" "github.com/elastic/cloud-on-k8s/test/e2e/test" "github.com/elastic/cloud-on-k8s/test/e2e/test/elasticsearch" ) // TestStackMonitoring func TestStackMonitoring(t *testing.T) { + // only execute this test on supported version + err := stackmon.IsSupportedVersion(test.Ctx().ElasticStackVersion) + if err != nil { + t.SkipNow() + } + // Create 1 monitored and 2 monitoring clusters to collect separately metrics and logs metrics := elasticsearch.NewBuilder("test-es-mon-metrics"). WithESMasterDataNodes(2, elasticsearch.DefaultResources) From fc4c78213c6fd6baac1c01845acbaa6bbcc9238a Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 8 Jun 2021 11:35:39 +0200 Subject: [PATCH 18/83] Naming --- pkg/controller/elasticsearch/driver/driver.go | 2 +- pkg/controller/elasticsearch/stackmon/container.go | 12 ++++++------ pkg/controller/elasticsearch/stackmon/volume.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/controller/elasticsearch/driver/driver.go b/pkg/controller/elasticsearch/driver/driver.go index ebe1fccfe4..44a62a2983 100644 --- a/pkg/controller/elasticsearch/driver/driver.go +++ b/pkg/controller/elasticsearch/driver/driver.go @@ -251,7 +251,7 @@ func (d *defaultDriver) Reconcile(ctx context.Context) *reconciler.Results { return results.WithError(err) } } - if stackmon.IsMonitoringLogDefined(d.ES) { + if stackmon.IsMonitoringLogsDefined(d.ES) { if err := configmap.ReconcileFilebeatConfigMap(ctx, d.Client, d.ES); err != nil { return results.WithError(err) } diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index e697f5fb79..9e631dfc23 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -37,10 +37,10 @@ var ( // in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { isMonitoringMetrics := IsMonitoringMetricsDefined(es) - isMonitoringLog := IsMonitoringLogDefined(es) + isMonitoringLogs := IsMonitoringLogsDefined(es) // No monitoring defined - if !isMonitoringMetrics && !isMonitoringLog { + if !isMonitoringMetrics && !isMonitoringLogs { return builder, nil } @@ -62,8 +62,8 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) builder.WithContainers(metricbeat) } - if isMonitoringLog { - // Enable stack logging in files + if isMonitoringLogs { + // Enable Stack logging to write Elasticsearch logs to disk builder.WithEnv(stackLoggingEnvVar()) // Inject Filebeat sidecar container @@ -78,14 +78,14 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) } func IsStackMonitoringDefined(es esv1.Elasticsearch) bool { - return IsMonitoringMetricsDefined(es) || IsMonitoringLogDefined(es) + return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) } func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { return es.Spec.Monitoring.Metrics.ElasticsearchRef.IsDefined() } -func IsMonitoringLogDefined(es esv1.Elasticsearch) bool { +func IsMonitoringLogsDefined(es esv1.Elasticsearch) bool { return es.Spec.Monitoring.Logs.ElasticsearchRef.IsDefined() } diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go index 6fdf3ab589..f8c0c26e2f 100644 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -37,7 +37,7 @@ func monitoringVolumes(es esv1.Elasticsearch) []corev1.Volume { monitoringMetricsTargetCaCertSecretVolume(es).Volume(), ) } - if IsMonitoringLogDefined(es) { + if IsMonitoringLogsDefined(es) { volumes = append(volumes, filebeatConfigMapVolume(es).Volume(), monitoringLogsTargetCaCertSecretVolume(es).Volume(), From d3d97abaad9562b369da2c1192c6b360c636f0f2 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 8 Jun 2021 11:36:06 +0200 Subject: [PATCH 19/83] Add stack mon doc link in es spec doc --- config/crds/all-crds.yaml | 10 +++++----- .../elasticsearch.k8s.elastic.co_elasticsearches.yaml | 2 +- .../charts/eck-operator-crds/templates/all-crds.yaml | 10 +++++----- docs/reference/api-docs.asciidoc | 2 +- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 3 ++- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/config/crds/all-crds.yaml b/config/crds/all-crds.yaml index 3f2cc48cf9..4c03df2091 100644 --- a/config/crds/all-crds.yaml +++ b/config/crds/all-crds.yaml @@ -2167,11 +2167,11 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract log and Stack Monitoring - metrics of this Elasticsearch cluster. Metricbeat and Filebeat are - deployed in the same Pod as sidecars and each one send data to one - or two different monitoring Elasticsearch clusters running in the - same Kubernetes cluster. + description: Monitoring enables you to extract logs and Stack Monitoring + metrics 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 send data to one or two different monitoring Elasticsearch + clusters running in the same Kubernetes cluster. properties: logs: properties: diff --git a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index cc35b004a5..1723d0fb8a 100644 --- a/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -243,7 +243,7 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. + description: Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. properties: logs: properties: 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 2f793a9b1b..cb25c8ec16 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 @@ -2197,11 +2197,11 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract log and Stack Monitoring - metrics of this Elasticsearch cluster. Metricbeat and Filebeat are - deployed in the same Pod as sidecars and each one send data to one - or two different monitoring Elasticsearch clusters running in the - same Kubernetes cluster. + description: Monitoring enables you to extract logs and Stack Monitoring + metrics 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 send data to one or two different monitoring Elasticsearch + clusters running in the same Kubernetes cluster. properties: logs: properties: diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 3cf11187ae..b83a341517 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -904,7 +904,7 @@ ElasticsearchSpec holds the specification of an Elasticsearch cluster. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (eg. a remote Elasticsearch cluster) in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`remoteClusters`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. Metricbeat and Filebeat are deployed in the same Pod as sidecars and each one send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. |=== diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index ea88921fae..844415d28c 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -78,7 +78,8 @@ type ElasticsearchSpec struct { // +kubebuilder:validation:Enum=DeleteOnScaledownOnly;DeleteOnScaledownAndClusterDeletion VolumeClaimDeletePolicy VolumeClaimDeletePolicy `json:"volumeClaimDeletePolicy,omitempty"` - // Monitoring enables you to extract log and Stack Monitoring metrics of this Elasticsearch cluster. + // Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different // monitoring Elasticsearch clusters running in the same Kubernetes cluster. // +kubebuilder:validation:Optional From 0a7528d66807754e9d6f716156b9b2ac281c8005 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 8 Jun 2021 12:14:42 +0200 Subject: [PATCH 20/83] Typo --- pkg/controller/common/defaults/pod_template.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/common/defaults/pod_template.go b/pkg/controller/common/defaults/pod_template.go index 3274cae534..7f98a965eb 100644 --- a/pkg/controller/common/defaults/pod_template.go +++ b/pkg/controller/common/defaults/pod_template.go @@ -183,9 +183,9 @@ func (b *PodTemplateBuilder) WithTerminationGracePeriod(period int64) *PodTempla return b } -// WithContainer appends the given containers to the list of containers belonging to the pod. +// WithContainers appends the given containers to the list of containers belonging to the pod. // It also ensures that the base container defaulter still points to the container in the list because append() -// create a new slice. +// creates a new slice. func (b *PodTemplateBuilder) WithContainers(containers ...corev1.Container) *PodTemplateBuilder { b.PodTemplate.Spec.Containers = append(b.PodTemplate.Spec.Containers, containers...) b.setContainerDefaulter() From 75fcde379d7cf405369f7420d3493a4a8221abf9 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 8 Jun 2021 12:27:20 +0200 Subject: [PATCH 21/83] go fmt --- .../elasticsearch/validation/validations.go | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/controller/elasticsearch/validation/validations.go b/pkg/controller/elasticsearch/validation/validations.go index b28bc140f9..69b932cca0 100644 --- a/pkg/controller/elasticsearch/validation/validations.go +++ b/pkg/controller/elasticsearch/validation/validations.go @@ -23,23 +23,23 @@ import ( var log = ulog.Log.WithName("es-validation") const ( - autoscalingVersionMsg = "autoscaling is not available in this version of Elasticsearch" - cfgInvalidMsg = "Configuration invalid" - duplicateNodeSets = "NodeSet names must be unique" - invalidNamesErrMsg = "Elasticsearch configuration would generate resources with invalid names" - invalidSanIPErrMsg = "Invalid SAN IP address. Must be a valid IPv4 address" - masterRequiredMsg = "Elasticsearch needs to have at least one master node" - mixedRoleConfigMsg = "Detected a combination of node.roles and %s. Use only node.roles" - noDowngradesMsg = "Downgrades are not supported" - nodeRolesInOldVersionMsg = "node.roles setting is not available in this version of Elasticsearch" - parseStoredVersionErrMsg = "Cannot parse current Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" - parseVersionErrMsg = "Cannot parse Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" - pvcImmutableErrMsg = "volume claim templates can only have their storage requests increased, if the storage class allows volume expansion. Any other change is forbidden" - pvcNotMountedErrMsg = "volume claim declared but volume not mounted in any container. Note that the Elasticsearch data volume should be named 'elasticsearch-data'" - unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported" - unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths." - unsupportedVersionMsg = "Unsupported version" - unsupportedVersionForStackMonitoringMsg = "Unsupported version for Stack Monitoring. Required >= %s." + autoscalingVersionMsg = "autoscaling is not available in this version of Elasticsearch" + cfgInvalidMsg = "Configuration invalid" + duplicateNodeSets = "NodeSet names must be unique" + invalidNamesErrMsg = "Elasticsearch configuration would generate resources with invalid names" + invalidSanIPErrMsg = "Invalid SAN IP address. Must be a valid IPv4 address" + masterRequiredMsg = "Elasticsearch needs to have at least one master node" + mixedRoleConfigMsg = "Detected a combination of node.roles and %s. Use only node.roles" + noDowngradesMsg = "Downgrades are not supported" + nodeRolesInOldVersionMsg = "node.roles setting is not available in this version of Elasticsearch" + parseStoredVersionErrMsg = "Cannot parse current Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" + parseVersionErrMsg = "Cannot parse Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" + pvcImmutableErrMsg = "volume claim templates can only have their storage requests increased, if the storage class allows volume expansion. Any other change is forbidden" + pvcNotMountedErrMsg = "volume claim declared but volume not mounted in any container. Note that the Elasticsearch data volume should be named 'elasticsearch-data'" + unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported" + unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths." + unsupportedVersionMsg = "Unsupported version" + unsupportedVersionForStackMonitoringMsg = "Unsupported version for Stack Monitoring. Required >= %s." ) type validation func(esv1.Elasticsearch) field.ErrorList From dfe83f5f12b97246af669e0cce8a4e7d284cce10 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 8 Jun 2021 12:36:15 +0200 Subject: [PATCH 22/83] doc --- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 844415d28c..b2d7ca3814 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -106,8 +106,9 @@ type LogsMonitoring struct { // EsMonitoringAssociation helps to manage Elasticsearch+Metricbeat+Filebeat <-> Elasticsearch(es) associations type EsMonitoringAssociation struct { + // The monitored Elasticsearch cluster from where are collected logs and monitoring metrics *Elasticsearch - // ref is the namespaced name of the Elasticsearch referenced in the Association + // ref is the namespaced name of the Elasticsearch referenced in the Association used to send and store monitoring data ref types.NamespacedName } From ac6d4f9ffde526571e5ce803ebdbb5a69795fee0 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 8 Jun 2021 12:49:08 +0200 Subject: [PATCH 23/83] Dedicated role --- .../association/controller/es_monitoring.go | 6 ++-- pkg/controller/elasticsearch/user/roles.go | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/pkg/controller/association/controller/es_monitoring.go b/pkg/controller/association/controller/es_monitoring.go index f62e6ff2b1..92ecb71f76 100644 --- a/pkg/controller/association/controller/es_monitoring.go +++ b/pkg/controller/association/controller/es_monitoring.go @@ -13,6 +13,7 @@ import ( "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" ) @@ -24,9 +25,6 @@ const ( EsMonitoringAssociationLabelNamespace = "esmonitoringassociation.k8s.elastic.co/namespace" // EsMonitoringAssociationLabelType marks the type of association. EsMonitoringAssociationLabelType = "esmonitoringassociation.k8s.elastic.co/type" - - // BeatBuiltinRole is the name of the built-in role for the Metricbeat/Filebeat system user. - BeatBuiltinRole = "superuser" // FIXME: create a dedicated role? ) // AddEsMonitoring reconciles an association between two Elasticsearch clusters for Stack Monitoring. @@ -54,7 +52,7 @@ func AddEsMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, pa AssociationConfAnnotationNameBase: commonv1.ElasticsearchConfigAnnotationNameBase, UserSecretSuffix: "beat-mon-user", ESUserRole: func(associated commonv1.Associated) (string, error) { - return BeatBuiltinRole, nil + return user.StackMonitoringUserRole, nil }, AssociationResourceNameLabelName: eslabel.ClusterNameLabelName, AssociationResourceNamespaceLabelName: eslabel.ClusterNamespaceLabelName, diff --git a/pkg/controller/elasticsearch/user/roles.go b/pkg/controller/elasticsearch/user/roles.go index 1cd07293fc..cc8cb3ecc1 100644 --- a/pkg/controller/elasticsearch/user/roles.go +++ b/pkg/controller/elasticsearch/user/roles.go @@ -32,6 +32,10 @@ const ( // ApmAgentUserRole is the name of the role used by APMServer instances to connect to Kibana ApmAgentUserRole = "eck_apm_agent_user_role" + // StackMonitoringMetricsUserRole is the name of the role used by Metricbeat and Filebeat to send metrics and log + // data to the monitoring Elasticsearch cluster when Stack Monitoring is enabled + StackMonitoringUserRole = "eck_stack_mon_user_role" + // V70 indicates version 7.0 V70 = "v70" @@ -87,6 +91,33 @@ var ( }, }, }, + // StackMonitoringUserRole is a dedicated role for Stack Monitoring with Metricbeat and Filebeat. + // See: https://www.elastic.co/guide/en/beats/filebeat/7.13/privileges-to-publish-monitoring.html. + StackMonitoringUserRole: esclient.Role{ + Cluster: []string{ + "monitor", + "manage_index_templates", + "manage_ingest_pipelines", + "manage_ilm", + "read_ilm", + "cluster:admin/xpack/watcher/watch/put", + "cluster:admin/xpack/watcher/watch/delete", + }, + Indices: []esclient.IndexRole{ + { + Names: []string{".monitoring-*"}, + Privileges: []string{"all"}, + }, + { + Names: []string{"metricbeat-*"}, + Privileges: []string{"create_index", "view_index_metadata", "index", "indices:admin/aliases"}, + }, + { + Names: []string{"filebeat-*"}, + Privileges: []string{"create_index", "view_index_metadata", "create_doc", "indices:admin/aliases"}, + }, + }, + }, } ) From ff98c869ce97cf59b0d169141b884c29e55be4c8 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 10 Jun 2021 20:48:10 +0200 Subject: [PATCH 24/83] Update Test_aggregateRoles --- pkg/controller/elasticsearch/user/reconcile_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/elasticsearch/user/reconcile_test.go b/pkg/controller/elasticsearch/user/reconcile_test.go index 61e485d5ee..88fbbe41b2 100644 --- a/pkg/controller/elasticsearch/user/reconcile_test.go +++ b/pkg/controller/elasticsearch/user/reconcile_test.go @@ -75,6 +75,6 @@ func Test_aggregateRoles(t *testing.T) { c := k8s.NewFakeClient(sampleUserProvidedRolesSecret...) roles, err := aggregateRoles(c, sampleEsWithAuth, initDynamicWatches(), record.NewFakeRecorder(10)) require.NoError(t, err) - require.Len(t, roles, 49) + require.Len(t, roles, 50) require.Contains(t, roles, ProbeUserRole, "role1", "role2") } From 450492cf1b2fbf1e929821e3c302e36ab80e6a44 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 16 Jun 2021 16:58:04 +0200 Subject: [PATCH 25/83] Renaming --- pkg/controller/elasticsearch/configmap/configmap.go | 4 ++-- pkg/controller/elasticsearch/stackmon/config.go | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/controller/elasticsearch/configmap/configmap.go b/pkg/controller/elasticsearch/configmap/configmap.go index eeaf607d66..695653f5f9 100644 --- a/pkg/controller/elasticsearch/configmap/configmap.go +++ b/pkg/controller/elasticsearch/configmap/configmap.go @@ -60,12 +60,12 @@ func ReconcileMetricbeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Ela span, _ := apm.StartSpan(ctx, "reconcile_metricbeat_config", tracing.SpanTypeApp) defer span.End() - return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.MetricbeatConfigMapParams(es))) + return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.MetricbeatConfigMapData(es))) } func ReconcileFilebeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasticsearch) error { span, _ := apm.StartSpan(ctx, "reconcile_filebeat_config", tracing.SpanTypeApp) defer span.End() - return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.FilebeatConfigMapParams(es))) + return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.FilebeatConfigMapData(es))) } diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index 02df8d1d4b..ac10cb91f6 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -54,13 +54,15 @@ func filebeatConfigMapName(es esv1.Elasticsearch) string { return esv1.ESNamer.Suffix(es.Name, FilebeatConfigMapSuffix) } -func MetricbeatConfigMapParams(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { +// MetricbeatConfigMapData returns the data for the ConfigMap holding the Metricbeat configuration +func MetricbeatConfigMapData(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { nsn := types.NamespacedName{Namespace: es.Namespace, Name: metricbeatConfigMapName(es)} data := map[string]string{MetricbeatConfigKey: MetricbeatConfig} return nsn, data } -func FilebeatConfigMapParams(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { +// FilebeatConfigMapData returns the data for the ConfigMap holding the Filebeat configuration +func FilebeatConfigMapData(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { nsn := types.NamespacedName{Namespace: es.Namespace, Name: filebeatConfigMapName(es)} data := map[string]string{FilebeatConfigKey: FilebeatConfig} return nsn, data From e01836d712bb748666f37d442fe2849437bcaeeb Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 16 Jun 2021 16:19:43 +0200 Subject: [PATCH 26/83] End of revert about configmap subpath --- pkg/controller/common/volume/configmap.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pkg/controller/common/volume/configmap.go b/pkg/controller/common/volume/configmap.go index 316c2fb7d4..6631fb6c62 100644 --- a/pkg/controller/common/volume/configmap.go +++ b/pkg/controller/common/volume/configmap.go @@ -30,20 +30,15 @@ type ConfigMapVolume struct { mountPath string items []corev1.KeyToPath defaultMode int32 - subPath string } // VolumeMount returns the k8s volume mount. func (cm ConfigMapVolume) VolumeMount() corev1.VolumeMount { - vm := corev1.VolumeMount{ + return corev1.VolumeMount{ Name: cm.name, MountPath: cm.mountPath, ReadOnly: true, } - if cm.subPath != "" { - vm.SubPath = cm.subPath - } - return vm } // Volume returns the k8s volume. From 46ff83aa74db0464fb4f13672bacb0fac5536927 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 16 Jun 2021 16:58:58 +0200 Subject: [PATCH 27/83] Move ES monitoring config in stackmon package --- .../elasticsearch/nodespec/podspec_test.go | 4 ++-- .../elasticsearch/nodespec/resources.go | 3 +-- .../elasticsearch/settings/merged_config.go | 20 ++++++++----------- .../settings/merged_config_test.go | 2 +- .../elasticsearch/stackmon/config.go | 12 +++++++++++ 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index 91c5215bb5..0311e99065 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -164,7 +164,7 @@ func TestBuildPodTemplateSpecWithDefaultSecurityContext(t *testing.T) { es.Spec.Version = tt.version.String() es.Spec.NodeSets[0].PodTemplate.Spec.SecurityContext = tt.userSecurityContext - cfg, err := settings.NewMergedESConfig(es.Name, tt.version, corev1.IPv4Protocol, es.Spec.HTTP, *es.Spec.NodeSets[0].Config, false) + cfg, err := settings.NewMergedESConfig(es.Name, tt.version, corev1.IPv4Protocol, es.Spec.HTTP, *es.Spec.NodeSets[0].Config, commonv1.Config{}) require.NoError(t, err) actual, err := BuildPodTemplateSpec(es, es.Spec.NodeSets[0], cfg, nil, tt.setDefaultFSGroup) @@ -178,7 +178,7 @@ func TestBuildPodTemplateSpec(t *testing.T) { nodeSet := sampleES.Spec.NodeSets[0] ver, err := version.Parse(sampleES.Spec.Version) require.NoError(t, err) - cfg, err := settings.NewMergedESConfig(sampleES.Name, ver, corev1.IPv4Protocol, sampleES.Spec.HTTP, *nodeSet.Config, false) + cfg, err := settings.NewMergedESConfig(sampleES.Name, ver, corev1.IPv4Protocol, sampleES.Spec.HTTP, *nodeSet.Config, commonv1.Config{}) require.NoError(t, err) actual, err := BuildPodTemplateSpec(sampleES, sampleES.Spec.NodeSets[0], cfg, nil, false) diff --git a/pkg/controller/elasticsearch/nodespec/resources.go b/pkg/controller/elasticsearch/nodespec/resources.go index 8694699195..56727984d3 100644 --- a/pkg/controller/elasticsearch/nodespec/resources.go +++ b/pkg/controller/elasticsearch/nodespec/resources.go @@ -55,8 +55,7 @@ func BuildExpectedResources( if nodeSpec.Config != nil { userCfg = *nodeSpec.Config } - isMonitoringMetrics := stackmon.IsMonitoringMetricsDefined(es) - cfg, err := settings.NewMergedESConfig(es.Name, ver, ipFamily, es.Spec.HTTP, userCfg, isMonitoringMetrics) + cfg, err := settings.NewMergedESConfig(es.Name, ver, ipFamily, es.Spec.HTTP, userCfg, stackmon.MonitoringConfig(es)) if err != nil { return nil, err } diff --git a/pkg/controller/elasticsearch/settings/merged_config.go b/pkg/controller/elasticsearch/settings/merged_config.go index b59524ab90..1e6a00ccb7 100644 --- a/pkg/controller/elasticsearch/settings/merged_config.go +++ b/pkg/controller/elasticsearch/settings/merged_config.go @@ -32,7 +32,7 @@ func NewMergedESConfig( ipFamily corev1.IPFamily, httpConfig commonv1.HTTPConfig, userConfig commonv1.Config, - isMonitoringMetrics bool, + monitoringConfig commonv1.Config, ) (CanonicalConfig, error) { userCfg, err := common.NewCanonicalConfigFrom(userConfig.Data) if err != nil { @@ -46,9 +46,14 @@ func NewMergedESConfig( if err != nil { return CanonicalConfig{}, err } - if isMonitoringMetrics { - err = config.MergeWith(monitoringConfig().CanonicalConfig) + monitoringCfg, err := common.NewCanonicalConfigFrom(monitoringConfig.Data) + if err != nil { + return CanonicalConfig{}, err } + err = config.MergeWith( + xpackConfig(ver, httpConfig).CanonicalConfig, + monitoringCfg, + ) if err != nil { return CanonicalConfig{}, err } @@ -140,12 +145,3 @@ func xpackConfig(ver version.Version, httpCfg commonv1.HTTPConfig) *CanonicalCon return &CanonicalConfig{common.MustCanonicalConfig(cfg)} } - -// monitoringConfig returns the configuration bit related to XPack monitoring -func monitoringConfig() *CanonicalConfig { - cfg := map[string]interface{}{ - esv1.XPackMonitoringCollectionEnabled: true, - esv1.XPackMonitoringElasticsearchCollectionEnabled: false, - } - return &CanonicalConfig{common.MustCanonicalConfig(cfg)} -} diff --git a/pkg/controller/elasticsearch/settings/merged_config_test.go b/pkg/controller/elasticsearch/settings/merged_config_test.go index bcb29abf12..9101ac4bcd 100644 --- a/pkg/controller/elasticsearch/settings/merged_config_test.go +++ b/pkg/controller/elasticsearch/settings/merged_config_test.go @@ -219,7 +219,7 @@ func TestNewMergedESConfig(t *testing.T) { tt.ipFamily, commonv1.HTTPConfig{}, commonv1.Config{Data: tt.cfgData}, - false, + commonv1.Config{}, ) require.NoError(t, err) tt.assert(cfg) diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index ac10cb91f6..ca950754a7 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -7,6 +7,7 @@ package stackmon import ( _ "embed" // for the beats config files + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "k8s.io/apimachinery/pkg/types" ) @@ -46,6 +47,17 @@ var ( FilebeatConfig string ) +// MonitoringConfig returns the Elasticsearch settings required to enable the collection of monitoring data +func MonitoringConfig(es esv1.Elasticsearch) commonv1.Config { + if !IsMonitoringMetricsDefined(es) { + return commonv1.Config{} + } + return commonv1.Config{Data: map[string]interface{}{ + esv1.XPackMonitoringCollectionEnabled: true, + esv1.XPackMonitoringElasticsearchCollectionEnabled: false, + }} +} + func metricbeatConfigMapName(es esv1.Elasticsearch) string { return esv1.ESNamer.Suffix(es.Name, MetricbeatConfigMapSuffix) } From b3fcdc6fc530488d98cacf3a531da3f580353a9b Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 16 Jun 2021 17:08:53 +0200 Subject: [PATCH 28/83] Review's input --- pkg/apis/common/v1/association.go | 2 +- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index dc70a8bd71..46a8b39e6b 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -79,7 +79,7 @@ func (asm AssociationStatusMap) Single() (AssociationStatus, error) { return result, nil } -// AllEstablished returns true if all Associations have AssociationEstablished status, false otherwise. +// AllEstablished returns true iff all Associations have AssociationEstablished status, false otherwise. func (asm AssociationStatusMap) AllEstablished() bool { for _, status := range asm { if status != AssociationEstablished { diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 8b22d0de2a..c59c8ec30e 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -80,13 +80,13 @@ type ElasticsearchSpec struct { // Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different - // monitoring Elasticsearch clusters running in the same Kubernetes cluster. + // 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 holds Elasticsearch references to send logs and metrics of this Elasticsearch cluster. +// Monitoring holds references to Elasticsearch clusters which will receive logs and metrics from this Elasticsearch cluster. type Monitoring struct { Metrics MetricsMonitoring `json:"metrics,omitempty"` Logs LogsMonitoring `json:"logs,omitempty"` @@ -232,7 +232,7 @@ func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) comm return commonv1.AssociationStatusMap{} } - return es.Status.ElasticsearchAssociationsStatus + return es.Status.MonitoringAssociationsStatus } func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, status commonv1.AssociationStatusMap) error { @@ -240,7 +240,7 @@ func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, s return fmt.Errorf("association type %s not known", typ) } - es.Status.ElasticsearchAssociationsStatus = status + es.Status.MonitoringAssociationsStatus = status return nil } @@ -538,7 +538,7 @@ type ElasticsearchStatus struct { Health ElasticsearchHealth `json:"health,omitempty"` Phase ElasticsearchOrchestrationPhase `json:"phase,omitempty"` - ElasticsearchAssociationsStatus commonv1.AssociationStatusMap `json:"esAssociationStatus,omitempty"` + MonitoringAssociationsStatus commonv1.AssociationStatusMap `json:"monitoringAssociationStatus,omitempty"` } type ZenDiscoveryStatus struct { From 337e96e319736ff989e8dfef1dd137802c4119b9 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 16 Jun 2021 17:14:03 +0200 Subject: [PATCH 29/83] Generate --- config/crds/v1/all-crds.yaml | 12 ++++++------ ...elasticsearch.k8s.elastic.co_elasticsearches.yaml | 12 ++++++------ config/crds/v1beta1/all-crds.yaml | 12 ++++++------ ...elasticsearch.k8s.elastic.co_elasticsearches.yaml | 12 ++++++------ .../eck-operator-crds/templates/all-crds-legacy.yaml | 12 ++++++------ .../charts/eck-operator-crds/templates/all-crds.yaml | 12 ++++++------ docs/reference/api-docs.asciidoc | 4 ++-- pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go | 4 ++-- 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 4871f7ee3b..27de28ffdf 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2837,7 +2837,7 @@ spec: description: Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch + and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. properties: logs: @@ -3778,7 +3778,11 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer - esAssociationStatus: + health: + description: ElasticsearchHealth is the health of the cluster as returned + by the health API. + type: string + monitoringAssociationStatus: additionalProperties: description: AssociationStatus is the status of an association resource. type: string @@ -3787,10 +3791,6 @@ spec: single Association of a given type (eg. single ES reference), this map will contain a single entry. type: object - health: - description: ElasticsearchHealth is the health of the cluster as returned - by the health API. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. 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 c509e6129f..1d30c2d438 100644 --- a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -498,7 +498,7 @@ spec: description: Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch + and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. properties: logs: @@ -8155,7 +8155,11 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer - esAssociationStatus: + health: + description: ElasticsearchHealth is the health of the cluster as returned + by the health API. + type: string + monitoringAssociationStatus: additionalProperties: description: AssociationStatus is the status of an association resource. type: string @@ -8164,10 +8168,6 @@ spec: single Association of a given type (eg. single ES reference), this map will contain a single entry. type: object - health: - description: ElasticsearchHealth is the health of the cluster as returned - by the health API. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/config/crds/v1beta1/all-crds.yaml b/config/crds/v1beta1/all-crds.yaml index 3f1a45bc4c..65dc556a26 100644 --- a/config/crds/v1beta1/all-crds.yaml +++ b/config/crds/v1beta1/all-crds.yaml @@ -2170,7 +2170,7 @@ spec: description: Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch + each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. properties: logs: @@ -3026,7 +3026,11 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer - esAssociationStatus: + health: + description: ElasticsearchHealth is the health of the cluster as returned + by the health API. + type: string + monitoringAssociationStatus: additionalProperties: description: AssociationStatus is the status of an association resource. type: string @@ -3035,10 +3039,6 @@ spec: Association of a given type (eg. single ES reference), this map will contain a single entry. type: object - health: - description: ElasticsearchHealth is the health of the cluster as returned - by the health API. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index 108aacd6c2..cfc0e76225 100644 --- a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -483,7 +483,7 @@ spec: description: Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch + and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. properties: logs: @@ -8051,7 +8051,11 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer - esAssociationStatus: + health: + description: ElasticsearchHealth is the health of the cluster as returned + by the health API. + type: string + monitoringAssociationStatus: additionalProperties: description: AssociationStatus is the status of an association resource. type: string @@ -8060,10 +8064,6 @@ spec: single Association of a given type (eg. single ES reference), this map will contain a single entry. type: object - health: - description: ElasticsearchHealth is the health of the cluster as returned - by the health API. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml index e600a6a086..26972ebd44 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml @@ -2203,7 +2203,7 @@ spec: description: Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch + each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. properties: logs: @@ -3059,7 +3059,11 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer - esAssociationStatus: + health: + description: ElasticsearchHealth is the health of the cluster as returned + by the health API. + type: string + monitoringAssociationStatus: additionalProperties: description: AssociationStatus is the status of an association resource. type: string @@ -3068,10 +3072,6 @@ spec: Association of a given type (eg. single ES reference), this map will contain a single entry. type: object - health: - description: ElasticsearchHealth is the health of the cluster as returned - by the health API. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. 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 0e2da317d0..1e5f7ad4a0 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 @@ -2870,7 +2870,7 @@ spec: description: Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch + and each one sends data to one or two different Elasticsearch monitoring clusters running in the same Kubernetes cluster. properties: logs: @@ -3811,7 +3811,11 @@ spec: description: AvailableNodes is the number of available instances. format: int32 type: integer - esAssociationStatus: + health: + description: ElasticsearchHealth is the health of the cluster as returned + by the health API. + type: string + monitoringAssociationStatus: additionalProperties: description: AssociationStatus is the status of an association resource. type: string @@ -3820,10 +3824,6 @@ spec: single Association of a given type (eg. single ES reference), this map will contain a single entry. type: object - health: - description: ElasticsearchHealth is the health of the cluster as returned - by the health API. - type: string phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch is in from the controller point of view. diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index b83a341517..23119ad89b 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -904,7 +904,7 @@ ElasticsearchSpec holds the specification of an Elasticsearch cluster. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (eg. a remote Elasticsearch cluster) in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`remoteClusters`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract logs and Stack Monitoring metrics 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 send data to one or two different monitoring Elasticsearch clusters running in the same Kubernetes cluster. +| *`monitoring`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract logs and Stack Monitoring metrics 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. |=== @@ -963,7 +963,7 @@ FileRealmSource references users to create in the Elasticsearch cluster. [id="{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring"] === Monitoring -Monitoring holds Elasticsearch references to send logs and metrics of this Elasticsearch cluster. +Monitoring holds references to Elasticsearch clusters which will receive logs and metrics from this Elasticsearch cluster. .Appears In: **** diff --git a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go index 5b35b67437..7636ac67bc 100644 --- a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go +++ b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go @@ -219,8 +219,8 @@ func (in *ElasticsearchSpec) DeepCopy() *ElasticsearchSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ElasticsearchStatus) DeepCopyInto(out *ElasticsearchStatus) { *out = *in - if in.ElasticsearchAssociationsStatus != nil { - in, out := &in.ElasticsearchAssociationsStatus, &out.ElasticsearchAssociationsStatus + if in.MonitoringAssociationsStatus != nil { + in, out := &in.MonitoringAssociationsStatus, &out.MonitoringAssociationsStatus *out = make(commonv1.AssociationStatusMap, len(*in)) for key, val := range *in { (*out)[key] = val From 4abcc0ca01d5fa33cc3cb520da2144f4b0be1fff Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 16 Jun 2021 17:20:24 +0200 Subject: [PATCH 30/83] Revert --- pkg/controller/association/reconciler.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/controller/association/reconciler.go b/pkg/controller/association/reconciler.go index a264fa7365..2d2d826f05 100644 --- a/pkg/controller/association/reconciler.go +++ b/pkg/controller/association/reconciler.go @@ -377,11 +377,7 @@ func (r *Reconciler) updateStatus(ctx context.Context, associated commonv1.Assoc span, _ := apm.StartSpan(ctx, "update_association_status", tracing.SpanTypeApp) defer span.End() - oldStatus := commonv1.AssociationStatusMap{} - // Copy from the original map to the target map - for key, value := range associated.AssociationStatusMap(r.AssociationType) { - oldStatus[key] = value - } + oldStatus := associated.AssociationStatusMap(r.AssociationType) // 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 From cc48fd1275db7f8fdf257afb25abe43204839642 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 17 Jun 2021 10:22:30 +0200 Subject: [PATCH 31/83] Fix monitoring config --- pkg/controller/elasticsearch/settings/merged_config.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pkg/controller/elasticsearch/settings/merged_config.go b/pkg/controller/elasticsearch/settings/merged_config.go index 1e6a00ccb7..4ad81b260d 100644 --- a/pkg/controller/elasticsearch/settings/merged_config.go +++ b/pkg/controller/elasticsearch/settings/merged_config.go @@ -39,19 +39,13 @@ func NewMergedESConfig( return CanonicalConfig{}, err } config := baseConfig(clusterName, ver, ipFamily).CanonicalConfig - err = config.MergeWith( - xpackConfig(ver, httpConfig).CanonicalConfig, - userCfg, - ) - if err != nil { - return CanonicalConfig{}, err - } monitoringCfg, err := common.NewCanonicalConfigFrom(monitoringConfig.Data) if err != nil { return CanonicalConfig{}, err } err = config.MergeWith( xpackConfig(ver, httpConfig).CanonicalConfig, + userCfg, monitoringCfg, ) if err != nil { From 074d760b0216b052d502f870ae92b8341db7565d Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 17 Jun 2021 11:23:28 +0200 Subject: [PATCH 32/83] Add unit tests --- .../elasticsearch/nodespec/podspec_test.go | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index 0311e99065..f3c4e70eba 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -5,6 +5,7 @@ package nodespec import ( + "errors" "sort" "testing" @@ -14,6 +15,7 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/initcontainer" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/settings" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" "github.com/elastic/cloud-on-k8s/pkg/utils/pointer" "github.com/go-test/deep" "github.com/stretchr/testify/assert" @@ -318,3 +320,111 @@ func Test_getDefaultContainerPorts(t *testing.T) { }) } } + +func TestWithMonitoring(t *testing.T) { + monitoringRef := commonv1.ObjectSelector{ + Name: "m1", + Namespace: "c", + } + fakeAssocConf := commonv1.AssociationConf{ + AuthSecretName: "name-c-m1-beat-mon-user", + AuthSecretKey: "default-name-c-m1-beat-mon-user", + CACertProvided: true, + CASecretName: "name-es-mon-c-m1-ca", + URL: "https://m1-es-http.c.svc:9200", + Version: "7.14.0", + } + tt := []struct { + name string + es func() esv1.Elasticsearch + expectedXPackMonitoringConfigKeys int + expectedContainerLen int + expectedErr error + }{ + { + name: "without monitoring", + es: func() esv1.Elasticsearch { + return sampleES + }, + expectedXPackMonitoringConfigKeys: 0, + expectedContainerLen: 2, + }, + { + name: "with unsupported version", + es: func() esv1.Elasticsearch { + es := sampleES + es.Spec.Monitoring.Logs.ElasticsearchRef = monitoringRef + return es + }, + expectedXPackMonitoringConfigKeys: 0, + expectedErr: errors.New("unsupported version for Stack Monitoring: required >= 7.14.0"), + }, + { + name: "with logs monitoring", + es: func() esv1.Elasticsearch { + es := sampleES + es.Spec.Version = "7.14.0" + es.Spec.Monitoring.Logs.ElasticsearchRef = monitoringRef + return es + }, + expectedXPackMonitoringConfigKeys: 0, + expectedContainerLen: 3, + }, + { + name: "with metrics monitoring", + es: func() esv1.Elasticsearch { + es := sampleES + es.Spec.Version = "7.14.0" + es.Spec.Monitoring.Metrics.ElasticsearchRef = monitoringRef + return es + }, + expectedXPackMonitoringConfigKeys: 2, + expectedContainerLen: 3, + }, + { + name: "with logs and metrics monitoring", + es: func() esv1.Elasticsearch { + es := sampleES + es.Spec.Version = "7.14.0" + es.Spec.Monitoring.Metrics.ElasticsearchRef = monitoringRef + es.Spec.Monitoring.Logs.ElasticsearchRef = monitoringRef + return es + }, + expectedXPackMonitoringConfigKeys: 2, + expectedContainerLen: 4, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + es := tc.es() + nodeSet := es.Spec.NodeSets[0] + ver, err := version.Parse(es.Spec.Version) + require.NoError(t, err) + + // Check that the Elasticsearch config contains Xpack monitoring settings only when metrics monitoring config is defined + cfg, err := settings.NewMergedESConfig(es.Name, ver, corev1.IPv4Protocol, es.Spec.HTTP, *nodeSet.Config, stackmon.MonitoringConfig(es)) + require.NoError(t, err) + require.Len(t, cfg.HasKeys([]string{esv1.XPackMonitoringCollectionEnabled, esv1.XPackMonitoringElasticsearchCollectionEnabled}), tc.expectedXPackMonitoringConfigKeys) + + // Fake association conf + if stackmon.IsMonitoringMetricsDefined(es) { + es.GetMonitoringMetricsAssociation().SetAssociationConf(&fakeAssocConf) + } + if stackmon.IsMonitoringLogsDefined(es) { + es.GetMonitoringLogsAssociation().SetAssociationConf(&fakeAssocConf) + } + + actual, err := BuildPodTemplateSpec(es, es.Spec.NodeSets[0], cfg, nil, false) + if tc.expectedErr != nil { + require.Error(t, err) + require.Equal(t, tc.expectedErr, err) + } else { + require.NoError(t, err) + // Check that the beat sidecar containers are present + require.Len(t, actual.Spec.Containers, tc.expectedContainerLen) + } + + }) + } +} From 9346b4ab3b98ab4314bbc3a375108538b140f0fb Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 17 Jun 2021 12:21:54 +0200 Subject: [PATCH 33/83] Use GetCASecretName() --- pkg/controller/elasticsearch/stackmon/volume.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go index f8c0c26e2f..a641116c75 100644 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -76,7 +76,7 @@ func monitoringMetricsSourceCaCertSecretVolume(es esv1.Elasticsearch) volume.Sec func monitoringMetricsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { assocConf := es.GetMonitoringMetricsAssociation().AssociationConf() return volume.NewSecretVolumeWithMountPath( - assocConf.CASecretName, + assocConf.GetCASecretName(), MonitoringMetricsTargetEsCaCertVolumeName, MonitoringMetricsTargetEsCaCertMountPath, ) @@ -85,7 +85,7 @@ func monitoringMetricsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.Sec func monitoringLogsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { assocConf := es.GetMonitoringLogsAssociation().AssociationConf() return volume.NewSecretVolumeWithMountPath( - assocConf.CASecretName, + assocConf.GetCASecretName(), MonitoringLogsTargetEsCaCertVolumeName, MonitoringLogsTargetEsCaCertMountPath, ) From 6c96979e24c1699e458a03ce5e1d353b65088c26 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 17 Jun 2021 13:40:46 +0200 Subject: [PATCH 34/83] lint --- pkg/controller/elasticsearch/nodespec/podspec_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index f3c4e70eba..2abbc4cea6 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -424,7 +424,6 @@ func TestWithMonitoring(t *testing.T) { // Check that the beat sidecar containers are present require.Len(t, actual.Spec.Containers, tc.expectedContainerLen) } - }) } } From 4d62d07c7df9a487043167fecb1805b864dd27b1 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Fri, 18 Jun 2021 17:16:18 +0200 Subject: [PATCH 35/83] Move warning comment --- pkg/controller/elasticsearch/stackmon/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index ca950754a7..7ed89974ba 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -20,6 +20,7 @@ const ( FilebeatConfigKey = "filebeat.yml" ) +// Warning: environment variables and CA cert paths defined below are also used in the embedded files. var ( // Environments variables used in the beats configuration to describe how to connect to Elasticsearch. // Warning: they are hard-coded in the two configs below. @@ -37,7 +38,6 @@ var ( MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/monitoring/logs/target" // MetricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch - // Warning: environment variables and CA cert paths defined below are hard-coded for simplicity. //go:embed metricbeat.yml MetricbeatConfig string From b2cfbce64c88ae5372073487c76daabfca7fd555 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Fri, 18 Jun 2021 17:16:59 +0200 Subject: [PATCH 36/83] Unit tests for fullContainerImage --- .../elasticsearch/stackmon/container.go | 2 +- .../elasticsearch/stackmon/container_test.go | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 pkg/controller/elasticsearch/stackmon/container_test.go diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 9e631dfc23..9a44ca0870 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -5,6 +5,7 @@ package stackmon import ( + "errors" "fmt" "path/filepath" "strings" @@ -16,7 +17,6 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" ) diff --git a/pkg/controller/elasticsearch/stackmon/container_test.go b/pkg/controller/elasticsearch/stackmon/container_test.go new file mode 100644 index 0000000000..28aaff66ca --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/container_test.go @@ -0,0 +1,68 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "errors" + "testing" + + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/container" + "github.com/stretchr/testify/require" +) + +func TestFullContainerImage(t *testing.T) { + tests := []struct { + name string + es esv1.Elasticsearch + defaultImage container.Image + fullImage string + err error + }{ + { + name: "with default Elasticsearch image", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.1", + }, + }, + defaultImage: "beats/filebeat", + fullImage: "docker.elastic.co/beats/filebeat:7.14.1", + }, + { + name: "with custom Elasticsearch image", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Image: "my.registry.space/elasticsearch/elasticsearch:7.15.0", + }, + }, + defaultImage: "beats/metricbeat", + fullImage: "my.registry.space/beats/metricbeat:7.15.0", + }, + { + name: "with custom Elasticsearch image that doesn't follow the Elastic scheme", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Image: "my.registry.space/es/es:7.14.0", + }, + }, + defaultImage: "beats/filebeat", + err: errors.New("stack monitoring not supported with custom image"), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + image, err := fullContainerImage(tc.es, tc.defaultImage) + + if err != nil { + require.Error(t, tc.err) + require.Equal(t, tc.err, err) + } else { + require.Equal(t, tc.fullImage, image) + } + }) + } +} From ce855c04eedc88769353e31f0ed1a434f9cc2813 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 21 Jun 2021 13:29:06 +0200 Subject: [PATCH 37/83] Future proof elasticsearchRefs for Elastic Agent --- config/crds/v1/all-crds.yaml | 100 ++++++----- ...search.k8s.elastic.co_elasticsearches.yaml | 100 ++++++----- config/crds/v1beta1/all-crds.yaml | 98 ++++++----- ...search.k8s.elastic.co_elasticsearches.yaml | 100 ++++++----- .../templates/all-crds-legacy.yaml | 98 ++++++----- .../eck-operator-crds/templates/all-crds.yaml | 100 ++++++----- docs/reference/api-docs.asciidoc | 4 +- .../elasticsearch/v1/elasticsearch_types.go | 70 ++++---- .../elasticsearch/v1/zz_generated.deepcopy.go | 18 +- .../elasticsearch/elasticsearch_controller.go | 2 +- .../elasticsearch/nodespec/podspec_test.go | 14 +- .../elasticsearch/stackmon/config.go | 38 +++- .../elasticsearch/stackmon/container.go | 165 ++++++++++-------- .../elasticsearch/stackmon/filebeat.yml | 12 +- .../elasticsearch/stackmon/metricbeat.yml | 8 +- .../elasticsearch/stackmon/volume.go | 64 +++---- .../elasticsearch/validation/validations.go | 51 ++++-- test/e2e/test/elasticsearch/builder.go | 4 +- 18 files changed, 589 insertions(+), 457 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 27de28ffdf..ab860c23e7 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2842,53 +2842,65 @@ spec: properties: logs: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Elasticsearch logs. Only + one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object metrics: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Stack Monitoring metrics. + Only one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object type: object nodeSets: 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 1d30c2d438..c20c55c567 100644 --- a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -503,53 +503,65 @@ spec: properties: logs: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Elasticsearch logs. Only + one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object metrics: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Stack Monitoring metrics. + Only one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object type: object nodeSets: diff --git a/config/crds/v1beta1/all-crds.yaml b/config/crds/v1beta1/all-crds.yaml index 65dc556a26..afe08d414c 100644 --- a/config/crds/v1beta1/all-crds.yaml +++ b/config/crds/v1beta1/all-crds.yaml @@ -2175,53 +2175,63 @@ spec: properties: logs: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of monitoring + Elasticsearch clusters running in the same Kubernetes cluster + dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef + is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: array type: object metrics: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of monitoring + Elasticsearch clusters running in the same Kubernetes cluster + dedicated to receiving Stack Monitoring metrics. Only one + ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: array type: object type: object nodeSets: diff --git a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index cfc0e76225..e4d4caf428 100644 --- a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -488,53 +488,65 @@ spec: properties: logs: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Elasticsearch logs. Only + one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object metrics: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Stack Monitoring metrics. + Only one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object type: object nodeSets: diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml index 26972ebd44..e8c4e6ef74 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml @@ -2208,53 +2208,63 @@ spec: properties: logs: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of monitoring + Elasticsearch clusters running in the same Kubernetes cluster + dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef + is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: array type: object metrics: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of monitoring + Elasticsearch clusters running in the same Kubernetes cluster + dedicated to receiving Stack Monitoring metrics. Only one + ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If empty, + defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing Kubernetes + service which will be 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 will be used. + type: string + required: + - name + type: object + type: array type: object type: object nodeSets: 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 1e5f7ad4a0..1d89068f50 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 @@ -2875,53 +2875,65 @@ spec: properties: logs: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Elasticsearch logs. Only + one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object metrics: properties: - elasticsearchRef: - description: ElasticsearchRef is a reference to a monitoring - Elasticsearch cluster running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. - properties: - name: - description: Name of the Kubernetes object. - type: string - namespace: - description: Namespace of the Kubernetes object. If empty, - defaults to the current namespace. - type: string - serviceName: - description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. - type: string - required: - - name - type: object + elasticsearchRefs: + description: ElasticsearchRefs is a reference to a list of + monitoring Elasticsearch clusters running in the same Kubernetes + cluster dedicated to receiving Stack Monitoring metrics. + Only one ElasticsearchRef is supported. + items: + description: ObjectSelector defines a reference to a Kubernetes + object. + properties: + name: + description: Name of the Kubernetes object. + type: string + namespace: + description: Namespace of the Kubernetes object. If + empty, defaults to the current namespace. + type: string + serviceName: + description: ServiceName is the name of an existing + Kubernetes service which will be 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 + will be used. + type: string + required: + - name + type: object + type: array type: object type: object nodeSets: diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 23119ad89b..359caa403f 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -939,7 +939,7 @@ FileRealmSource references users to create in the Elasticsearch cluster. [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRef`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving Elasticsearch logs. +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef is supported. |=== @@ -956,7 +956,7 @@ FileRealmSource references users to create in the Elasticsearch cluster. [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRef`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster dedicated to receiving Stack Monitoring metrics. +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster dedicated to receiving Stack Monitoring metrics. Only one ElasticsearchRef is supported. |=== diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index c59c8ec30e..d8def9651a 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -93,15 +93,15 @@ type Monitoring struct { } type MetricsMonitoring struct { - // ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster - // dedicated to receiving Stack Monitoring metrics. - ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` + // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster + // dedicated to receiving Stack Monitoring metrics. Only one ElasticsearchRef is supported. + ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` } type LogsMonitoring struct { - // ElasticsearchRef is a reference to a monitoring Elasticsearch cluster running in the same Kubernetes cluster - // dedicated to receiving Elasticsearch logs. - ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` + // ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster + // dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef is supported. + ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` } // EsMonitoringAssociation helps to manage Elasticsearch+Metricbeat+Filebeat <-> Elasticsearch(es) associations @@ -188,43 +188,49 @@ func (es *Elasticsearch) ServiceAccountName() string { func (es *Elasticsearch) GetAssociations() []commonv1.Association { associations := make([]commonv1.Association, 0) - ref := es.Spec.Monitoring.Metrics.ElasticsearchRef - if ref.IsDefined() { - associations = append(associations, &EsMonitoringAssociation{ - Elasticsearch: es, - ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), - }) + for _, ref := range es.Spec.Monitoring.Metrics.ElasticsearchRefs { + if ref.IsDefined() { + associations = append(associations, &EsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + }) + } } - ref = es.Spec.Monitoring.Logs.ElasticsearchRef - if ref.IsDefined() { - associations = append(associations, &EsMonitoringAssociation{ - Elasticsearch: es, - ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), - }) + for _, ref := range es.Spec.Monitoring.Logs.ElasticsearchRefs { + if ref.IsDefined() { + associations = append(associations, &EsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + }) + } } return associations } -func (es *Elasticsearch) GetMonitoringMetricsAssociation() commonv1.Association { - ref := es.Spec.Monitoring.Metrics.ElasticsearchRef - if ref.IsDefined() { - return &EsMonitoringAssociation{ - Elasticsearch: es, - ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), +func (es *Elasticsearch) GetMonitoringMetricsAssociation() []commonv1.Association { + associations := make([]commonv1.Association, 0) + for _, ref := range es.Spec.Monitoring.Metrics.ElasticsearchRefs { + if ref.IsDefined() { + associations = append(associations, &EsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + }) } } - return &EsMonitoringAssociation{} + return associations } -func (es *Elasticsearch) GetMonitoringLogsAssociation() commonv1.Association { - ref := es.Spec.Monitoring.Logs.ElasticsearchRef - if ref.IsDefined() { - return &EsMonitoringAssociation{ - Elasticsearch: es, - ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), +func (es *Elasticsearch) GetMonitoringLogsAssociation() []commonv1.Association { + associations := make([]commonv1.Association, 0) + for _, ref := range es.Spec.Monitoring.Logs.ElasticsearchRefs { + if ref.IsDefined() { + associations = append(associations, &EsMonitoringAssociation{ + Elasticsearch: es, + ref: ref.WithDefaultNamespace(es.Namespace).NamespacedName(), + }) } } - return &EsMonitoringAssociation{} + return associations } func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) commonv1.AssociationStatusMap { diff --git a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go index 7636ac67bc..c1c4c82735 100644 --- a/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go +++ b/pkg/apis/elasticsearch/v1/zz_generated.deepcopy.go @@ -203,7 +203,7 @@ func (in *ElasticsearchSpec) DeepCopyInto(out *ElasticsearchSpec) { *out = make([]RemoteCluster, len(*in)) copy(*out, *in) } - out.Monitoring = in.Monitoring + in.Monitoring.DeepCopyInto(&out.Monitoring) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ElasticsearchSpec. @@ -278,7 +278,11 @@ func (in *FileRealmSource) DeepCopy() *FileRealmSource { // 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 - out.ElasticsearchRef = in.ElasticsearchRef + 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. @@ -294,7 +298,11 @@ func (in *LogsMonitoring) DeepCopy() *LogsMonitoring { // 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 - out.ElasticsearchRef = in.ElasticsearchRef + 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. @@ -310,8 +318,8 @@ func (in *MetricsMonitoring) DeepCopy() *MetricsMonitoring { // 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 - out.Metrics = in.Metrics - out.Logs = in.Logs + in.Metrics.DeepCopyInto(&out.Metrics) + in.Logs.DeepCopyInto(&out.Logs) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. diff --git a/pkg/controller/elasticsearch/elasticsearch_controller.go b/pkg/controller/elasticsearch/elasticsearch_controller.go index b8dc37de34..bf6bf53521 100644 --- a/pkg/controller/elasticsearch/elasticsearch_controller.go +++ b/pkg/controller/elasticsearch/elasticsearch_controller.go @@ -192,7 +192,7 @@ func (r *ReconcileElasticsearch) Reconcile(ctx context.Context, request reconcil return reconcile.Result{}, tracing.CaptureError(ctx, err) } - // Requeue if associations are configured but not yet defined + // Requeue if associations are defined but not yet configured if !association.AreConfiguredIfSet(es.GetAssociations(), r.recorder) { return reconcile.Result{}, nil } diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index 2abbc4cea6..dec6c0029d 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -353,7 +353,7 @@ func TestWithMonitoring(t *testing.T) { name: "with unsupported version", es: func() esv1.Elasticsearch { es := sampleES - es.Spec.Monitoring.Logs.ElasticsearchRef = monitoringRef + es.Spec.Monitoring.Logs.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} return es }, expectedXPackMonitoringConfigKeys: 0, @@ -364,7 +364,7 @@ func TestWithMonitoring(t *testing.T) { es: func() esv1.Elasticsearch { es := sampleES es.Spec.Version = "7.14.0" - es.Spec.Monitoring.Logs.ElasticsearchRef = monitoringRef + es.Spec.Monitoring.Logs.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} return es }, expectedXPackMonitoringConfigKeys: 0, @@ -375,7 +375,7 @@ func TestWithMonitoring(t *testing.T) { es: func() esv1.Elasticsearch { es := sampleES es.Spec.Version = "7.14.0" - es.Spec.Monitoring.Metrics.ElasticsearchRef = monitoringRef + es.Spec.Monitoring.Metrics.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} return es }, expectedXPackMonitoringConfigKeys: 2, @@ -386,8 +386,8 @@ func TestWithMonitoring(t *testing.T) { es: func() esv1.Elasticsearch { es := sampleES es.Spec.Version = "7.14.0" - es.Spec.Monitoring.Metrics.ElasticsearchRef = monitoringRef - es.Spec.Monitoring.Logs.ElasticsearchRef = monitoringRef + es.Spec.Monitoring.Metrics.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} + es.Spec.Monitoring.Logs.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} return es }, expectedXPackMonitoringConfigKeys: 2, @@ -409,10 +409,10 @@ func TestWithMonitoring(t *testing.T) { // Fake association conf if stackmon.IsMonitoringMetricsDefined(es) { - es.GetMonitoringMetricsAssociation().SetAssociationConf(&fakeAssocConf) + es.GetMonitoringMetricsAssociation()[0].SetAssociationConf(&fakeAssocConf) } if stackmon.IsMonitoringLogsDefined(es) { - es.GetMonitoringLogsAssociation().SetAssociationConf(&fakeAssocConf) + es.GetMonitoringLogsAssociation()[0].SetAssociationConf(&fakeAssocConf) } actual, err := BuildPodTemplateSpec(es, es.Spec.NodeSets[0], cfg, nil, false) diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index 7ed89974ba..c0a31d6a56 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -6,9 +6,11 @@ package stackmon import ( _ "embed" // for the beats config files + "fmt" commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" ) @@ -20,22 +22,22 @@ const ( FilebeatConfigKey = "filebeat.yml" ) +// Environments variables and paths to the Elasticsearch CA certificates used in the beats configuration to describe +// how to connect to Elasticsearch. // Warning: environment variables and CA cert paths defined below are also used in the embedded files. var ( - // Environments variables used in the beats configuration to describe how to connect to Elasticsearch. - // Warning: they are hard-coded in the two configs below. EsSourceURLEnvVarKey = "ES_SOURCE_URL" EsSourceURLEnvVarValue = "https://localhost:9200" EsSourceUsernameEnvVarKey = "ES_SOURCE_USERNAME" EsSourcePasswordEnvVarKey = "ES_SOURCE_PASSWORD" //nolint:gosec - EsTargetURLEnvVarKey = "ES_TARGET_URL" - EsTargetUsernameEnvVarKey = "ES_TARGET_USERNAME" - EsTargetPasswordEnvVarKey = "ES_TARGET_PASSWORD" //nolint:gosec - // Paths to the Elasticsearch CA certificates used by the beats to send data + EsTargetURLEnvVarKeyFormat = "ES_%d_TARGET_URL" + EsTargetUsernameEnvVarKeyFormat = "ES_%d_TARGET_USERNAME" + EsTargetPasswordEnvVarKeyFormat = "ES_%d_TARGET_PASSWORD" //nolint:gosec + MonitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" - MonitoringMetricsTargetEsCaCertMountPath = "/mnt/es/monitoring/metrics/target" - MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/monitoring/logs/target" + MonitoringMetricsTargetEsCaCertMountPath = "/mnt/es/%d/monitoring/metrics/target" + MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/%d/monitoring/logs/target" // MetricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch //go:embed metricbeat.yml @@ -79,3 +81,23 @@ func FilebeatConfigMapData(es esv1.Elasticsearch) (types.NamespacedName, map[str data := map[string]string{FilebeatConfigKey: FilebeatConfig} return nsn, data } + +func monitoringTargetEnvVars(assocs []commonv1.Association) []corev1.EnvVar { + vars := make([]corev1.EnvVar, 0) + for i, assoc := range assocs { + assocConf := assoc.AssociationConf() + vars = append(vars, []corev1.EnvVar{ + {Name: fmt.Sprintf(EsTargetURLEnvVarKeyFormat, i), Value: assocConf.GetURL()}, + {Name: fmt.Sprintf(EsTargetUsernameEnvVarKeyFormat, i), Value: assocConf.GetAuthSecretKey()}, + {Name: fmt.Sprintf(EsTargetPasswordEnvVarKeyFormat, i), ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: assocConf.GetAuthSecretName(), + }, + Key: assocConf.GetAuthSecretKey(), + }, + }}}..., + ) + } + return vars +} diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 9a44ca0870..6a593bc949 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -10,11 +10,11 @@ import ( "path/filepath" "strings" - v1 "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/defaults" "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" corev1 "k8s.io/api/core/v1" @@ -33,6 +33,53 @@ var ( MinStackVersion = version.MustParse("7.14.0") ) +func ValidMonitoringMetricsElasticsearchRefs(es esv1.Elasticsearch) bool { + if IsMonitoringMetricsDefined(es) { + return len(es.Spec.Monitoring.Metrics.ElasticsearchRefs) == 1 + } + return true +} + +func ValidMonitoringLogsElasticsearchRefs(es esv1.Elasticsearch) bool { + if IsMonitoringLogsDefined(es) { + return len(es.Spec.Monitoring.Logs.ElasticsearchRefs) == 1 + } + return true +} + +func IsStackMonitoringDefined(es esv1.Elasticsearch) bool { + return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) +} + +func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { + for _, ref := range es.Spec.Monitoring.Metrics.ElasticsearchRefs { + if !ref.IsDefined() { + return false + } + } + return len(es.Spec.Monitoring.Metrics.ElasticsearchRefs) > 0 +} + +func IsMonitoringLogsDefined(es esv1.Elasticsearch) bool { + for _, ref := range es.Spec.Monitoring.Logs.ElasticsearchRefs { + if !ref.IsDefined() { + return false + } + } + return len(es.Spec.Monitoring.Logs.ElasticsearchRefs) > 0 +} + +func IsSupportedVersion(esVersion string) error { + ver, err := version.Parse(esVersion) + if err != nil { + return err + } + if ver.LT(MinStackVersion) { + return fmt.Errorf("unsupported version for Stack Monitoring: required >= %s", MinStackVersion) + } + return nil +} + // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers // in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { @@ -50,12 +97,17 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) return nil, err } - // Inject volumes - builder.WithVolumes(monitoringVolumes(es)...) - + volumeLikes := make([]volume.VolumeLike, 0) if isMonitoringMetrics { + metricbeatVolumes := append( + monitoringMetricsTargetCaCertSecretVolumes(es), + metricbeatConfigMapVolume(es), + monitoringMetricsSourceCaCertSecretVolume(es), + ) + volumeLikes = append(volumeLikes, metricbeatVolumes...) + // Inject Metricbeat sidecar container - metricbeat, err := metricbeatContainer(es) + metricbeat, err := metricbeatContainer(es, metricbeatVolumes) if err != nil { return nil, err } @@ -66,85 +118,77 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) // Enable Stack logging to write Elasticsearch logs to disk builder.WithEnv(stackLoggingEnvVar()) + filebeatVolumes := append( + monitoringLogsTargetCaCertSecretVolumes(es), + filebeatConfigMapVolume(es), + ) + volumeLikes = append(volumeLikes, filebeatVolumes...) + // Inject Filebeat sidecar container - filebeat, err := filebeatContainer(es) + filebeat, err := filebeatContainer(es, filebeatVolumes) if err != nil { return nil, err } builder.WithContainers(filebeat) } - return builder, nil -} - -func IsStackMonitoringDefined(es esv1.Elasticsearch) bool { - return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) -} - -func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { - return es.Spec.Monitoring.Metrics.ElasticsearchRef.IsDefined() -} - -func IsMonitoringLogsDefined(es esv1.Elasticsearch) bool { - return es.Spec.Monitoring.Logs.ElasticsearchRef.IsDefined() -} - -func IsSupportedVersion(esVersion string) error { - ver, err := version.Parse(esVersion) - if err != nil { - return err - } - if ver.LT(MinStackVersion) { - return fmt.Errorf("unsupported version for Stack Monitoring: required >= %s", MinStackVersion) + // Inject volumes + volumes := make([]corev1.Volume, 0) + for _, v := range volumeLikes { + volumes = append(volumes, v.Volume()) } - return nil + builder.WithVolumes(volumes...) + + return builder, nil } func stackLoggingEnvVar() corev1.EnvVar { return corev1.EnvVar{Name: esLogStyleEnvVarKey, Value: esLogStyleEnvVarValue} } -func metricbeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { +func metricbeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (corev1.Container, error) { image, err := fullContainerImage(es, container.MetricbeatImage) if err != nil { return corev1.Container{}, err } - assocConf := es.GetMonitoringMetricsAssociation().AssociationConf() - envVars := append(monitoringSourceEnvVars(es), monitoringTargetEnvVars(assocConf)...) + volumeMounts := make([]corev1.VolumeMount, 0) + for _, v := range volumes { + volumeMounts = append(volumeMounts, v.VolumeMount()) + } + + envVars := append(monitoringSourceEnvVars(es), monitoringTargetEnvVars(es.GetMonitoringMetricsAssociation())...) return corev1.Container{ - Name: MetricbeatContainerName, - Image: image, - Args: []string{"-c", metricbeatConfigMountPath, "-e"}, - Env: append(envVars, defaults.PodDownwardEnvVars()...), - VolumeMounts: []corev1.VolumeMount{ - metricbeatConfigMapVolume(es).VolumeMount(), - monitoringMetricsSourceCaCertSecretVolume(es).VolumeMount(), - monitoringMetricsTargetCaCertSecretVolume(es).VolumeMount(), - }, + Name: MetricbeatContainerName, + Image: image, + Args: []string{"-c", metricbeatConfigMountPath, "-e"}, + Env: append(envVars, defaults.PodDownwardEnvVars()...), + VolumeMounts: volumeMounts, }, nil } -func filebeatContainer(es esv1.Elasticsearch) (corev1.Container, error) { +func filebeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (corev1.Container, error) { image, err := fullContainerImage(es, container.FilebeatImage) if err != nil { return corev1.Container{}, err } - assocConf := es.GetMonitoringLogsAssociation().AssociationConf() - envVars := monitoringTargetEnvVars(assocConf) + volumeMounts := []corev1.VolumeMount{ + esvolume.DefaultLogsVolumeMount, // mount Elasticsearch logs volume into the Filebeat container + } + for _, v := range volumes { + volumeMounts = append(volumeMounts, v.VolumeMount()) + } + + envVars := monitoringTargetEnvVars(es.GetMonitoringLogsAssociation()) return corev1.Container{ - Name: FilebeatContainerName, - Image: image, - Args: []string{"-c", filebeatConfigMountPath, "-e"}, - Env: append(envVars, defaults.PodDownwardEnvVars()...), - VolumeMounts: []corev1.VolumeMount{ - esvolume.DefaultLogsVolumeMount, - filebeatConfigMapVolume(es).VolumeMount(), - monitoringLogsTargetCaCertSecretVolume(es).VolumeMount(), - }, + Name: FilebeatContainerName, + Image: image, + Args: []string{"-c", filebeatConfigMountPath, "-e"}, + Env: append(envVars, defaults.PodDownwardEnvVars()...), + VolumeMounts: volumeMounts, }, nil } @@ -179,18 +223,3 @@ func monitoringSourceEnvVars(es esv1.Elasticsearch) []corev1.EnvVar { }}, } } - -func monitoringTargetEnvVars(assocConf *v1.AssociationConf) []corev1.EnvVar { - return []corev1.EnvVar{ - {Name: EsTargetURLEnvVarKey, Value: assocConf.GetURL()}, - {Name: EsTargetUsernameEnvVarKey, Value: assocConf.GetAuthSecretKey()}, - {Name: EsTargetPasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: assocConf.GetAuthSecretName(), - }, - Key: assocConf.GetAuthSecretKey(), - }, - }}, - } -} diff --git a/pkg/controller/elasticsearch/stackmon/filebeat.yml b/pkg/controller/elasticsearch/stackmon/filebeat.yml index c17c6f24f0..05f9c68df7 100644 --- a/pkg/controller/elasticsearch/stackmon/filebeat.yml +++ b/pkg/controller/elasticsearch/stackmon/filebeat.yml @@ -42,13 +42,9 @@ processors: # TODO: finish #setup.dashboards.enabled: true - #setup.kibana: - #host: '${ES_TARGET_URL}' - #username: ${ES_TARGET_USERNAME} - #password: ${ES_TARGET_PASSWORD} output.elasticsearch: - hosts: ['${ES_TARGET_URL}'] - username: ${ES_TARGET_USERNAME} - password: ${ES_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/logs/target/ca.crt"] \ No newline at end of file + hosts: ['${ES_0_TARGET_URL}'] + username: ${ES_0_TARGET_USERNAME} + password: ${ES_0_TARGET_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/0/monitoring/logs/target/ca.crt"] \ No newline at end of file diff --git a/pkg/controller/elasticsearch/stackmon/metricbeat.yml b/pkg/controller/elasticsearch/stackmon/metricbeat.yml index 40343d6843..a1f935876e 100644 --- a/pkg/controller/elasticsearch/stackmon/metricbeat.yml +++ b/pkg/controller/elasticsearch/stackmon/metricbeat.yml @@ -23,7 +23,7 @@ processors: - add_host_metadata: {} output.elasticsearch: - hosts: ['${ES_TARGET_URL}'] - username: ${ES_TARGET_USERNAME} - password: ${ES_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/target/ca.crt"] \ No newline at end of file + hosts: ['${ES_0_TARGET_URL}'] + username: ${ES_0_TARGET_USERNAME} + password: ${ES_0_TARGET_PASSWORD} + ssl.certificate_authorities: ["/mnt/es/0/monitoring/metrics/target/ca.crt"] \ No newline at end of file diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go index a641116c75..cccd359178 100644 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -5,10 +5,11 @@ package stackmon import ( + "fmt" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/certificates" "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" - corev1 "k8s.io/api/core/v1" ) const ( @@ -20,32 +21,11 @@ const ( FilebeatConfigVolumeName = "filebeat-config" FilebeatConfigDirMountPath = "/etc/filebeat-config" - MonitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" - MonitoringMetricsTargetEsCaCertVolumeName = "es-monitoring-metrics-target-certs" - MonitoringLogsTargetEsCaCertVolumeName = "es-monitoring-logs-target-certs" + MonitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" + MonitoringMetricsTargetEsCaCertVolumeNameFormat = "es-monitoring-metrics-target-certs-%d" + MonitoringLogsTargetEsCaCertVolumeNameFormat = "es-monitoring-logs-target-certs-%d" ) -// monitoringVolumes returns the volumes to add to the Elasticsearch pod for the Metricbeat and Filebeat sidecar containers. -// Metricbeat mounts its configuration and the CA certificates of the source and the target Elasticsearch cluster. -// Filebeat mounts its configuration and the CA certificate of the target Elasticsearch cluster. -func monitoringVolumes(es esv1.Elasticsearch) []corev1.Volume { - var volumes []corev1.Volume - if IsMonitoringMetricsDefined(es) { - volumes = append(volumes, - metricbeatConfigMapVolume(es).Volume(), - monitoringMetricsSourceCaCertSecretVolume(es).Volume(), - monitoringMetricsTargetCaCertSecretVolume(es).Volume(), - ) - } - if IsMonitoringLogsDefined(es) { - volumes = append(volumes, - filebeatConfigMapVolume(es).Volume(), - monitoringLogsTargetCaCertSecretVolume(es).Volume(), - ) - } - return volumes -} - func metricbeatConfigMapVolume(es esv1.Elasticsearch) volume.ConfigMapVolume { return volume.NewConfigMapVolume( metricbeatConfigMapName(es), @@ -73,20 +53,26 @@ func monitoringMetricsSourceCaCertSecretVolume(es esv1.Elasticsearch) volume.Sec ) } -func monitoringMetricsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { - assocConf := es.GetMonitoringMetricsAssociation().AssociationConf() - return volume.NewSecretVolumeWithMountPath( - assocConf.GetCASecretName(), - MonitoringMetricsTargetEsCaCertVolumeName, - MonitoringMetricsTargetEsCaCertMountPath, - ) +func monitoringMetricsTargetCaCertSecretVolumes(es esv1.Elasticsearch) []volume.VolumeLike { + volumes := make([]volume.VolumeLike, 0) + for i, assoc := range es.GetMonitoringMetricsAssociation() { + volumes = append(volumes, volume.NewSecretVolumeWithMountPath( + assoc.AssociationConf().GetCASecretName(), + fmt.Sprintf(MonitoringMetricsTargetEsCaCertVolumeNameFormat, i), + fmt.Sprintf(MonitoringMetricsTargetEsCaCertMountPath, i), + )) + } + return volumes } -func monitoringLogsTargetCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { - assocConf := es.GetMonitoringLogsAssociation().AssociationConf() - return volume.NewSecretVolumeWithMountPath( - assocConf.GetCASecretName(), - MonitoringLogsTargetEsCaCertVolumeName, - MonitoringLogsTargetEsCaCertMountPath, - ) +func monitoringLogsTargetCaCertSecretVolumes(es esv1.Elasticsearch) []volume.VolumeLike { + volumes := make([]volume.VolumeLike, 0) + for i, assoc := range es.GetMonitoringLogsAssociation() { + volumes = append(volumes, volume.NewSecretVolumeWithMountPath( + assoc.AssociationConf().GetCASecretName(), + fmt.Sprintf(MonitoringLogsTargetEsCaCertVolumeNameFormat, i), + fmt.Sprintf(MonitoringLogsTargetEsCaCertMountPath, i), + )) + } + return volumes } diff --git a/pkg/controller/elasticsearch/validation/validations.go b/pkg/controller/elasticsearch/validation/validations.go index 69b932cca0..51bd78b91b 100644 --- a/pkg/controller/elasticsearch/validation/validations.go +++ b/pkg/controller/elasticsearch/validation/validations.go @@ -23,23 +23,24 @@ import ( var log = ulog.Log.WithName("es-validation") const ( - autoscalingVersionMsg = "autoscaling is not available in this version of Elasticsearch" - cfgInvalidMsg = "Configuration invalid" - duplicateNodeSets = "NodeSet names must be unique" - invalidNamesErrMsg = "Elasticsearch configuration would generate resources with invalid names" - invalidSanIPErrMsg = "Invalid SAN IP address. Must be a valid IPv4 address" - masterRequiredMsg = "Elasticsearch needs to have at least one master node" - mixedRoleConfigMsg = "Detected a combination of node.roles and %s. Use only node.roles" - noDowngradesMsg = "Downgrades are not supported" - nodeRolesInOldVersionMsg = "node.roles setting is not available in this version of Elasticsearch" - parseStoredVersionErrMsg = "Cannot parse current Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" - parseVersionErrMsg = "Cannot parse Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" - pvcImmutableErrMsg = "volume claim templates can only have their storage requests increased, if the storage class allows volume expansion. Any other change is forbidden" - pvcNotMountedErrMsg = "volume claim declared but volume not mounted in any container. Note that the Elasticsearch data volume should be named 'elasticsearch-data'" - unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported" - unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths." - unsupportedVersionMsg = "Unsupported version" - unsupportedVersionForStackMonitoringMsg = "Unsupported version for Stack Monitoring. Required >= %s." + autoscalingVersionMsg = "autoscaling is not available in this version of Elasticsearch" + cfgInvalidMsg = "Configuration invalid" + duplicateNodeSets = "NodeSet names must be unique" + invalidNamesErrMsg = "Elasticsearch configuration would generate resources with invalid names" + invalidSanIPErrMsg = "Invalid SAN IP address. Must be a valid IPv4 address" + masterRequiredMsg = "Elasticsearch needs to have at least one master node" + mixedRoleConfigMsg = "Detected a combination of node.roles and %s. Use only node.roles" + noDowngradesMsg = "Downgrades are not supported" + nodeRolesInOldVersionMsg = "node.roles setting is not available in this version of Elasticsearch" + parseStoredVersionErrMsg = "Cannot parse current Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" + parseVersionErrMsg = "Cannot parse Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" + pvcImmutableErrMsg = "volume claim templates can only have their storage requests increased, if the storage class allows volume expansion. Any other change is forbidden" + pvcNotMountedErrMsg = "volume claim declared but volume not mounted in any container. Note that the Elasticsearch data volume should be named 'elasticsearch-data'" + unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported" + unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths." + unsupportedVersionMsg = "Unsupported version" + unsupportedVersionForStackMonitoringMsg = "Unsupported version for Stack Monitoring. Required >= %s." + invalidStackMonitoringElasticsearchRefsMsg = "Only one Elasticsearch reference is supported for %s Stack Monitoring" ) type validation func(esv1.Elasticsearch) field.ErrorList @@ -54,6 +55,7 @@ var validations = []validation{ validAutoscalingConfiguration, validPVCNaming, supportedVersionForStackMonitoring, + validStackMonitoringElasticsearchRefs, } type updateValidation func(esv1.Elasticsearch, esv1.Elasticsearch) field.ErrorList @@ -117,6 +119,21 @@ func supportedVersionForStackMonitoring(es esv1.Elasticsearch) field.ErrorList { return field.ErrorList{} } +func validStackMonitoringElasticsearchRefs(es esv1.Elasticsearch) field.ErrorList { + if !stackmon.ValidMonitoringMetricsElasticsearchRefs(es) { + return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), + es.Spec.Monitoring.Metrics.ElasticsearchRefs, + fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Metrics"))} + } + if !stackmon.ValidMonitoringLogsElasticsearchRefs(es) { + return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), + es.Spec.Monitoring.Logs.ElasticsearchRefs, + fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Logs"))} + } + + return field.ErrorList{} +} + // hasCorrectNodeRoles checks whether Elasticsearch node roles are correctly configured. // The rules are: // There must be at least one master node. diff --git a/test/e2e/test/elasticsearch/builder.go b/test/e2e/test/elasticsearch/builder.go index 4b4eabd90b..0fd8a18cba 100644 --- a/test/e2e/test/elasticsearch/builder.go +++ b/test/e2e/test/elasticsearch/builder.go @@ -449,8 +449,8 @@ func (b Builder) WithPodLabel(key, value string) Builder { } func (b Builder) WithMonitoring(metricsESRef commonv1.ObjectSelector, logsESRef commonv1.ObjectSelector) Builder { - b.Elasticsearch.Spec.Monitoring.Metrics.ElasticsearchRef = metricsESRef - b.Elasticsearch.Spec.Monitoring.Logs.ElasticsearchRef = logsESRef + b.Elasticsearch.Spec.Monitoring.Metrics.ElasticsearchRefs = []commonv1.ObjectSelector{metricsESRef} + b.Elasticsearch.Spec.Monitoring.Logs.ElasticsearchRefs = []commonv1.ObjectSelector{logsESRef} return b } From 86e9fbd434b9457e3e89b044d147058390300387 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 22 Jun 2021 15:54:13 +0200 Subject: [PATCH 38/83] Add kubebuilder annotations --- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index d8def9651a..8fec41aa28 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -88,19 +88,23 @@ type ElasticsearchSpec struct { // Monitoring holds references to Elasticsearch clusters which will receive logs and metrics from this Elasticsearch cluster. type Monitoring struct { + // +kubebuilder:validation:Optional Metrics MetricsMonitoring `json:"metrics,omitempty"` - Logs LogsMonitoring `json:"logs,omitempty"` + // +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 // dedicated to receiving Stack Monitoring metrics. Only one ElasticsearchRef is 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 // dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef is supported. + // +kubebuilder:validation:Required ElasticsearchRefs []commonv1.ObjectSelector `json:"elasticsearchRefs,omitempty"` } From 9a81c1cfec5325bd45525d6ded89ac8938d64182 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 22 Jun 2021 15:54:39 +0200 Subject: [PATCH 39/83] Adjust association name --- pkg/controller/association/controller/es_monitoring.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/controller/association/controller/es_monitoring.go b/pkg/controller/association/controller/es_monitoring.go index 92ecb71f76..46e1e9a353 100644 --- a/pkg/controller/association/controller/es_monitoring.go +++ b/pkg/controller/association/controller/es_monitoring.go @@ -40,8 +40,8 @@ func AddEsMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, pa ExternalServiceURL: getElasticsearchExternalURL, AssociationType: commonv1.ElasticsearchAssociationType, AssociatedNamer: esv1.ESNamer, - AssociationName: "es-mon", - AssociatedShortName: "es", + AssociationName: "es-monitoring", + AssociatedShortName: "es-mon", Labels: func(associated types.NamespacedName) map[string]string { return map[string]string{ EsMonitoringAssociationLabelName: associated.Name, @@ -50,7 +50,7 @@ func AddEsMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, pa } }, AssociationConfAnnotationNameBase: commonv1.ElasticsearchConfigAnnotationNameBase, - UserSecretSuffix: "beat-mon-user", + UserSecretSuffix: "beat-es-mon-user", ESUserRole: func(associated commonv1.Associated) (string, error) { return user.StackMonitoringUserRole, nil }, From 3fb22c42542031e361566145e2baa020e2c9bfef Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 22 Jun 2021 16:01:00 +0200 Subject: [PATCH 40/83] Refactoring validation --- .../elasticsearch/nodespec/podspec_test.go | 25 ++------ .../elasticsearch/stackmon/container.go | 17 ----- .../elasticsearch/stackmon/validations.go | 61 ++++++++++++++++++ .../elasticsearch/validation/validations.go | 63 +++++-------------- 4 files changed, 82 insertions(+), 84 deletions(-) create mode 100644 pkg/controller/elasticsearch/stackmon/validations.go diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index dec6c0029d..e760c03ce9 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -5,7 +5,6 @@ package nodespec import ( - "errors" "sort" "testing" @@ -339,7 +338,6 @@ func TestWithMonitoring(t *testing.T) { es func() esv1.Elasticsearch expectedXPackMonitoringConfigKeys int expectedContainerLen int - expectedErr error }{ { name: "without monitoring", @@ -349,16 +347,6 @@ func TestWithMonitoring(t *testing.T) { expectedXPackMonitoringConfigKeys: 0, expectedContainerLen: 2, }, - { - name: "with unsupported version", - es: func() esv1.Elasticsearch { - es := sampleES - es.Spec.Monitoring.Logs.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} - return es - }, - expectedXPackMonitoringConfigKeys: 0, - expectedErr: errors.New("unsupported version for Stack Monitoring: required >= 7.14.0"), - }, { name: "with logs monitoring", es: func() esv1.Elasticsearch { @@ -402,7 +390,7 @@ func TestWithMonitoring(t *testing.T) { ver, err := version.Parse(es.Spec.Version) require.NoError(t, err) - // Check that the Elasticsearch config contains Xpack monitoring settings only when metrics monitoring config is defined + // Check that the Elasticsearch config contains XPack monitoring settings only when metrics monitoring config is defined cfg, err := settings.NewMergedESConfig(es.Name, ver, corev1.IPv4Protocol, es.Spec.HTTP, *nodeSet.Config, stackmon.MonitoringConfig(es)) require.NoError(t, err) require.Len(t, cfg.HasKeys([]string{esv1.XPackMonitoringCollectionEnabled, esv1.XPackMonitoringElasticsearchCollectionEnabled}), tc.expectedXPackMonitoringConfigKeys) @@ -416,14 +404,9 @@ func TestWithMonitoring(t *testing.T) { } actual, err := BuildPodTemplateSpec(es, es.Spec.NodeSets[0], cfg, nil, false) - if tc.expectedErr != nil { - require.Error(t, err) - require.Equal(t, tc.expectedErr, err) - } else { - require.NoError(t, err) - // Check that the beat sidecar containers are present - require.Len(t, actual.Spec.Containers, tc.expectedContainerLen) - } + require.NoError(t, err) + // Check that the beat sidecar containers are present + require.Len(t, actual.Spec.Containers, tc.expectedContainerLen) }) } } diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 6a593bc949..7dc01f87de 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -69,17 +69,6 @@ func IsMonitoringLogsDefined(es esv1.Elasticsearch) bool { return len(es.Spec.Monitoring.Logs.ElasticsearchRefs) > 0 } -func IsSupportedVersion(esVersion string) error { - ver, err := version.Parse(esVersion) - if err != nil { - return err - } - if ver.LT(MinStackVersion) { - return fmt.Errorf("unsupported version for Stack Monitoring: required >= %s", MinStackVersion) - } - return nil -} - // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers // in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { @@ -91,12 +80,6 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) return builder, nil } - // Reject unsupported version - err := IsSupportedVersion(es.Spec.Version) - if err != nil { - return nil, err - } - volumeLikes := make([]volume.VolumeLike, 0) if isMonitoringMetrics { metricbeatVolumes := append( diff --git a/pkg/controller/elasticsearch/stackmon/validations.go b/pkg/controller/elasticsearch/stackmon/validations.go new file mode 100644 index 0000000000..c6c080d3d6 --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/validations.go @@ -0,0 +1,61 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "fmt" + + "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" + "k8s.io/apimachinery/pkg/util/validation/field" + + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" +) + +const ( + unsupportedVersionForStackMonitoringMsg = "Unsupported version for Stack Monitoring. Required >= %s." + invalidStackMonitoringElasticsearchRefsMsg = "Only one Elasticsearch reference is supported for %s Stack Monitoring" +) + +var ( + // Minimum Stack version to enable Stack Monitoring. + // This requirement comes from the fact that we configure Elasticsearch to write logs to disk for Filebeat + // via the env var ES_LOG_STYLE available from this version. + MinStackVersion = version.MustParse("7.14.0") +) + +// Validate validates that the Elasticsearch version is supported for Stack Monitoring and that there is exactly one +// Elasticsearch reference defined when Stack Monitoring is defined +func Validate(es esv1.Elasticsearch) field.ErrorList { + if IsStackMonitoringDefined(es) { + err := IsSupportedVersion(es.Spec.Version) + if err != nil { + return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, + fmt.Sprintf(unsupportedVersionForStackMonitoringMsg, MinStackVersion))} + } + } + if IsMonitoringMetricsDefined(es) && len(es.Spec.Monitoring.Metrics.ElasticsearchRefs) != 1 { + return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), + es.Spec.Monitoring.Metrics.ElasticsearchRefs, + fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Metrics"))} + } + if IsMonitoringLogsDefined(es) && len(es.Spec.Monitoring.Logs.ElasticsearchRefs) != 1 { + return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), + es.Spec.Monitoring.Logs.ElasticsearchRefs, + fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Logs"))} + } + return field.ErrorList{} +} + +// IsSupportedVersion returns true if the Elasticsearch version is supported for Stack Monitoring, else returns false +func IsSupportedVersion(esVersion string) error { + ver, err := version.Parse(esVersion) + 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/elasticsearch/validation/validations.go b/pkg/controller/elasticsearch/validation/validations.go index 51bd78b91b..a782eecb7f 100644 --- a/pkg/controller/elasticsearch/validation/validations.go +++ b/pkg/controller/elasticsearch/validation/validations.go @@ -23,24 +23,22 @@ import ( var log = ulog.Log.WithName("es-validation") const ( - autoscalingVersionMsg = "autoscaling is not available in this version of Elasticsearch" - cfgInvalidMsg = "Configuration invalid" - duplicateNodeSets = "NodeSet names must be unique" - invalidNamesErrMsg = "Elasticsearch configuration would generate resources with invalid names" - invalidSanIPErrMsg = "Invalid SAN IP address. Must be a valid IPv4 address" - masterRequiredMsg = "Elasticsearch needs to have at least one master node" - mixedRoleConfigMsg = "Detected a combination of node.roles and %s. Use only node.roles" - noDowngradesMsg = "Downgrades are not supported" - nodeRolesInOldVersionMsg = "node.roles setting is not available in this version of Elasticsearch" - parseStoredVersionErrMsg = "Cannot parse current Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" - parseVersionErrMsg = "Cannot parse Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" - pvcImmutableErrMsg = "volume claim templates can only have their storage requests increased, if the storage class allows volume expansion. Any other change is forbidden" - pvcNotMountedErrMsg = "volume claim declared but volume not mounted in any container. Note that the Elasticsearch data volume should be named 'elasticsearch-data'" - unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported" - unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths." - unsupportedVersionMsg = "Unsupported version" - unsupportedVersionForStackMonitoringMsg = "Unsupported version for Stack Monitoring. Required >= %s." - invalidStackMonitoringElasticsearchRefsMsg = "Only one Elasticsearch reference is supported for %s Stack Monitoring" + autoscalingVersionMsg = "autoscaling is not available in this version of Elasticsearch" + cfgInvalidMsg = "Configuration invalid" + duplicateNodeSets = "NodeSet names must be unique" + invalidNamesErrMsg = "Elasticsearch configuration would generate resources with invalid names" + invalidSanIPErrMsg = "Invalid SAN IP address. Must be a valid IPv4 address" + masterRequiredMsg = "Elasticsearch needs to have at least one master node" + mixedRoleConfigMsg = "Detected a combination of node.roles and %s. Use only node.roles" + noDowngradesMsg = "Downgrades are not supported" + nodeRolesInOldVersionMsg = "node.roles setting is not available in this version of Elasticsearch" + parseStoredVersionErrMsg = "Cannot parse current Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" + parseVersionErrMsg = "Cannot parse Elasticsearch version. String format must be {major}.{minor}.{patch}[-{label}]" + pvcImmutableErrMsg = "volume claim templates can only have their storage requests increased, if the storage class allows volume expansion. Any other change is forbidden" + pvcNotMountedErrMsg = "volume claim declared but volume not mounted in any container. Note that the Elasticsearch data volume should be named 'elasticsearch-data'" + unsupportedConfigErrMsg = "Configuration setting is reserved for internal use. User-configured use is unsupported" + unsupportedUpgradeMsg = "Unsupported version upgrade path. Check the Elasticsearch documentation for supported upgrade paths." + unsupportedVersionMsg = "Unsupported version" ) type validation func(esv1.Elasticsearch) field.ErrorList @@ -54,8 +52,7 @@ var validations = []validation{ validSanIP, validAutoscalingConfiguration, validPVCNaming, - supportedVersionForStackMonitoring, - validStackMonitoringElasticsearchRefs, + stackmon.Validate, } type updateValidation func(esv1.Elasticsearch, esv1.Elasticsearch) field.ErrorList @@ -108,32 +105,6 @@ func supportedVersion(es esv1.Elasticsearch) field.ErrorList { return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, unsupportedVersionMsg)} } -func supportedVersionForStackMonitoring(es esv1.Elasticsearch) field.ErrorList { - if stackmon.IsStackMonitoringDefined(es) { - err := stackmon.IsSupportedVersion(es.Spec.Version) - if err != nil { - return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, - fmt.Sprintf(unsupportedVersionForStackMonitoringMsg, stackmon.MinStackVersion.String()))} - } - } - return field.ErrorList{} -} - -func validStackMonitoringElasticsearchRefs(es esv1.Elasticsearch) field.ErrorList { - if !stackmon.ValidMonitoringMetricsElasticsearchRefs(es) { - return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), - es.Spec.Monitoring.Metrics.ElasticsearchRefs, - fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Metrics"))} - } - if !stackmon.ValidMonitoringLogsElasticsearchRefs(es) { - return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), - es.Spec.Monitoring.Logs.ElasticsearchRefs, - fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Logs"))} - } - - return field.ErrorList{} -} - // hasCorrectNodeRoles checks whether Elasticsearch node roles are correctly configured. // The rules are: // There must be at least one master node. From 6b9c2d303ef410c314eed317768a16ac58d5fc05 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 22 Jun 2021 16:15:14 +0200 Subject: [PATCH 41/83] Cleaning beat yaml config --- pkg/controller/elasticsearch/stackmon/filebeat.yml | 5 +---- pkg/controller/elasticsearch/stackmon/metricbeat.yml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/filebeat.yml b/pkg/controller/elasticsearch/stackmon/filebeat.yml index 05f9c68df7..5182c0c8b9 100644 --- a/pkg/controller/elasticsearch/stackmon/filebeat.yml +++ b/pkg/controller/elasticsearch/stackmon/filebeat.yml @@ -40,11 +40,8 @@ processors: - add_cloud_metadata: {} - add_host_metadata: {} - # TODO: finish - #setup.dashboards.enabled: true - output.elasticsearch: hosts: ['${ES_0_TARGET_URL}'] username: ${ES_0_TARGET_USERNAME} password: ${ES_0_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/0/monitoring/logs/target/ca.crt"] \ No newline at end of file + ssl.certificate_authorities: ["/mnt/es/0/monitoring/logs/target/ca.crt"] diff --git a/pkg/controller/elasticsearch/stackmon/metricbeat.yml b/pkg/controller/elasticsearch/stackmon/metricbeat.yml index a1f935876e..626b0d1dfb 100644 --- a/pkg/controller/elasticsearch/stackmon/metricbeat.yml +++ b/pkg/controller/elasticsearch/stackmon/metricbeat.yml @@ -26,4 +26,4 @@ output.elasticsearch: hosts: ['${ES_0_TARGET_URL}'] username: ${ES_0_TARGET_USERNAME} password: ${ES_0_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/0/monitoring/metrics/target/ca.crt"] \ No newline at end of file + ssl.certificate_authorities: ["/mnt/es/0/monitoring/metrics/target/ca.crt"] From 482784a6950444060b6824499e6d0731e521da03 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 22 Jun 2021 16:03:07 +0200 Subject: [PATCH 42/83] Refactoring beat config in secrets --- .../elasticsearch/configmap/configmap.go | 15 --- pkg/controller/elasticsearch/driver/driver.go | 14 +-- .../elasticsearch/nodespec/resources.go | 2 +- .../elasticsearch/stackmon/config.go | 95 +++++++++++-------- .../elasticsearch/stackmon/container.go | 51 ++++------ .../elasticsearch/stackmon/volume.go | 61 ++++++------ 6 files changed, 107 insertions(+), 131 deletions(-) diff --git a/pkg/controller/elasticsearch/configmap/configmap.go b/pkg/controller/elasticsearch/configmap/configmap.go index 695653f5f9..ea00fb5696 100644 --- a/pkg/controller/elasticsearch/configmap/configmap.go +++ b/pkg/controller/elasticsearch/configmap/configmap.go @@ -8,7 +8,6 @@ import ( "context" "github.com/elastic/cloud-on-k8s/pkg/controller/common/tracing" - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" "go.elastic.co/apm" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -55,17 +54,3 @@ func ReconcileScriptsConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasti return ReconcileConfigMap(c, es, scriptsConfigMap) } - -func ReconcileMetricbeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasticsearch) error { - span, _ := apm.StartSpan(ctx, "reconcile_metricbeat_config", tracing.SpanTypeApp) - defer span.End() - - return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.MetricbeatConfigMapData(es))) -} - -func ReconcileFilebeatConfigMap(ctx context.Context, c k8s.Client, es esv1.Elasticsearch) error { - span, _ := apm.StartSpan(ctx, "reconcile_filebeat_config", tracing.SpanTypeApp) - defer span.End() - - return ReconcileConfigMap(c, es, NewConfigMapWithData(stackmon.FilebeatConfigMapData(es))) -} diff --git a/pkg/controller/elasticsearch/driver/driver.go b/pkg/controller/elasticsearch/driver/driver.go index 44a62a2983..ddba1da6ea 100644 --- a/pkg/controller/elasticsearch/driver/driver.go +++ b/pkg/controller/elasticsearch/driver/driver.go @@ -245,16 +245,10 @@ func (d *defaultDriver) Reconcile(ctx context.Context) *reconciler.Results { results = results.WithResult(defaultRequeue) } - // reconcile Beats configs on demand - if stackmon.IsMonitoringMetricsDefined(d.ES) { - if err := configmap.ReconcileMetricbeatConfigMap(ctx, d.Client, d.ES); err != nil { - return results.WithError(err) - } - } - if stackmon.IsMonitoringLogsDefined(d.ES) { - if err := configmap.ReconcileFilebeatConfigMap(ctx, d.Client, d.ES); err != nil { - return results.WithError(err) - } + // reconcile beats config secrets if Stack Monitoring is defined + err = stackmon.ReconcileConfigSecrets(d.Client, d.ES) + if err != nil { + return results.WithError(err) } // reconcile StatefulSets and nodes configuration diff --git a/pkg/controller/elasticsearch/nodespec/resources.go b/pkg/controller/elasticsearch/nodespec/resources.go index 56727984d3..2cfc54f095 100644 --- a/pkg/controller/elasticsearch/nodespec/resources.go +++ b/pkg/controller/elasticsearch/nodespec/resources.go @@ -5,7 +5,6 @@ package nodespec import ( - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -16,6 +15,7 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/settings" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/sset" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" ) // Resources contain per-NodeSet resources to be created. diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index c0a31d6a56..7b93a4cb02 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -10,43 +10,37 @@ import ( 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/reconciler" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" -) - -const ( - MetricbeatConfigKey = "metricbeat.yml" - MetricbeatConfigMapSuffix = "metricbeat-config" - - FilebeatConfigMapSuffix = "filebeat-config" - FilebeatConfigKey = "filebeat.yml" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // Environments variables and paths to the Elasticsearch CA certificates used in the beats configuration to describe // how to connect to Elasticsearch. // Warning: environment variables and CA cert paths defined below are also used in the embedded files. var ( - EsSourceURLEnvVarKey = "ES_SOURCE_URL" - EsSourceURLEnvVarValue = "https://localhost:9200" - EsSourceUsernameEnvVarKey = "ES_SOURCE_USERNAME" - EsSourcePasswordEnvVarKey = "ES_SOURCE_PASSWORD" //nolint:gosec + esSourceURLEnvVarKey = "ES_SOURCE_URL" + esSourceURLEnvVarValue = "https://localhost:9200" + esSourceUsernameEnvVarKey = "ES_SOURCE_USERNAME" + esSourcePasswordEnvVarKey = "ES_SOURCE_PASSWORD" //nolint:gosec - EsTargetURLEnvVarKeyFormat = "ES_%d_TARGET_URL" - EsTargetUsernameEnvVarKeyFormat = "ES_%d_TARGET_USERNAME" - EsTargetPasswordEnvVarKeyFormat = "ES_%d_TARGET_PASSWORD" //nolint:gosec + esTargetURLEnvVarKeyFormat = "ES_%d_TARGET_URL" + esTargetUsernameEnvVarKeyFormat = "ES_%d_TARGET_USERNAME" + esTargetPasswordEnvVarKeyFormat = "ES_%d_TARGET_PASSWORD" //nolint:gosec - MonitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" - MonitoringMetricsTargetEsCaCertMountPath = "/mnt/es/%d/monitoring/metrics/target" - MonitoringLogsTargetEsCaCertMountPath = "/mnt/es/%d/monitoring/logs/target" + monitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" + monitoringMetricsTargetEsCaCertMountPathFormat = "/mnt/es/%d/monitoring/metrics/target" + monitoringLogsTargetEsCaCertMountPathFormat = "/mnt/es/%d/monitoring/logs/target" // MetricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch //go:embed metricbeat.yml - MetricbeatConfig string + metricbeatConfig string // FilebeatConfig is a static configuration for Filebeat to collect Elasticsearch logs - // Warning: environment variables and CA cert paths defined below are hard-coded for simplicity. //go:embed filebeat.yml - FilebeatConfig string + filebeatConfig string ) // MonitoringConfig returns the Elasticsearch settings required to enable the collection of monitoring data @@ -60,36 +54,53 @@ func MonitoringConfig(es esv1.Elasticsearch) commonv1.Config { }} } -func metricbeatConfigMapName(es esv1.Elasticsearch) string { - return esv1.ESNamer.Suffix(es.Name, MetricbeatConfigMapSuffix) -} - -func filebeatConfigMapName(es esv1.Elasticsearch) string { - return esv1.ESNamer.Suffix(es.Name, FilebeatConfigMapSuffix) -} +// ReconcileConfigSecrets reconciles the secrets holding the beats configuration +func ReconcileConfigSecrets(client k8s.Client, es esv1.Elasticsearch) error { + if IsMonitoringMetricsDefined(es) { + secret := beatConfigSecret(es, metricbeatConfigSecretName, metricbeatConfigKey, metricbeatConfig) + if _, err := reconciler.ReconcileSecret(client, secret, &es); err != nil { + return err + } + } -// MetricbeatConfigMapData returns the data for the ConfigMap holding the Metricbeat configuration -func MetricbeatConfigMapData(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { - nsn := types.NamespacedName{Namespace: es.Namespace, Name: metricbeatConfigMapName(es)} - data := map[string]string{MetricbeatConfigKey: MetricbeatConfig} - return nsn, data + if IsMonitoringLogsDefined(es) { + secret := beatConfigSecret(es, filebeatConfigSecretName, filebeatConfigKey, filebeatConfig) + if _, err := reconciler.ReconcileSecret(client, secret, &es); err != nil { + return err + } + } + return nil } -// FilebeatConfigMapData returns the data for the ConfigMap holding the Filebeat configuration -func FilebeatConfigMapData(es esv1.Elasticsearch) (types.NamespacedName, map[string]string) { - nsn := types.NamespacedName{Namespace: es.Namespace, Name: filebeatConfigMapName(es)} - data := map[string]string{FilebeatConfigKey: FilebeatConfig} - return nsn, data +// beatConfigSecret returns the data for a Secret holding a beat configuration +func beatConfigSecret( + es esv1.Elasticsearch, + secretNamer func(es esv1.Elasticsearch) string, + beatConfigKey string, + beatConfig string, +) corev1.Secret { + return corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretNamer(es), + Namespace: es.GetNamespace(), + Labels: label.NewLabels(k8s.ExtractNamespacedName(&es)), + }, + Data: map[string][]byte{ + beatConfigKey: []byte(beatConfig), + }, + } } +// monitoringTargetEnvVars returns the environment variables describing how to connect to Elasticsearch clusters +// referenced in given associations func monitoringTargetEnvVars(assocs []commonv1.Association) []corev1.EnvVar { vars := make([]corev1.EnvVar, 0) for i, assoc := range assocs { assocConf := assoc.AssociationConf() vars = append(vars, []corev1.EnvVar{ - {Name: fmt.Sprintf(EsTargetURLEnvVarKeyFormat, i), Value: assocConf.GetURL()}, - {Name: fmt.Sprintf(EsTargetUsernameEnvVarKeyFormat, i), Value: assocConf.GetAuthSecretKey()}, - {Name: fmt.Sprintf(EsTargetPasswordEnvVarKeyFormat, i), ValueFrom: &corev1.EnvVarSource{ + {Name: fmt.Sprintf(esTargetURLEnvVarKeyFormat, i), Value: assocConf.GetURL()}, + {Name: fmt.Sprintf(esTargetUsernameEnvVarKeyFormat, i), Value: assocConf.GetAuthSecretKey()}, + {Name: fmt.Sprintf(esTargetPasswordEnvVarKeyFormat, i), ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ Name: assocConf.GetAuthSecretName(), diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 7dc01f87de..72f33027b7 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -6,46 +6,28 @@ package stackmon import ( "errors" - "fmt" "path/filepath" "strings" 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/defaults" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" corev1 "k8s.io/api/core/v1" ) -var ( - metricbeatConfigMountPath = filepath.Join(MetricbeatConfigDirMountPath, MetricbeatConfigKey) - filebeatConfigMountPath = filepath.Join(FilebeatConfigDirMountPath, FilebeatConfigKey) - +const ( esLogStyleEnvVarKey = "ES_LOG_STYLE" esLogStyleEnvVarValue = "file" - // Minimum Stack version to enable Stack Monitoring. - // This requirement comes from the fact that we configure Elasticsearch to write logs to disk for Filebeat - // via the env var ES_LOG_STYLE available from this version. - MinStackVersion = version.MustParse("7.14.0") -) - -func ValidMonitoringMetricsElasticsearchRefs(es esv1.Elasticsearch) bool { - if IsMonitoringMetricsDefined(es) { - return len(es.Spec.Monitoring.Metrics.ElasticsearchRefs) == 1 - } - return true -} + metricbeatContainerName = "metricbeat" + filebeatContainerName = "filebeat" -func ValidMonitoringLogsElasticsearchRefs(es esv1.Elasticsearch) bool { - if IsMonitoringLogsDefined(es) { - return len(es.Spec.Monitoring.Logs.ElasticsearchRefs) == 1 - } - return true -} + metricbeatConfigKey = "metricbeat.yml" + filebeatConfigKey = "filebeat.yml" +) func IsStackMonitoringDefined(es esv1.Elasticsearch) bool { return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) @@ -75,16 +57,17 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) isMonitoringMetrics := IsMonitoringMetricsDefined(es) isMonitoringLogs := IsMonitoringLogsDefined(es) - // No monitoring defined + // No monitoring defined, skip if !isMonitoringMetrics && !isMonitoringLogs { return builder, nil } volumeLikes := make([]volume.VolumeLike, 0) + if isMonitoringMetrics { metricbeatVolumes := append( monitoringMetricsTargetCaCertSecretVolumes(es), - metricbeatConfigMapVolume(es), + metricbeatConfigSecretVolume(es), monitoringMetricsSourceCaCertSecretVolume(es), ) volumeLikes = append(volumeLikes, metricbeatVolumes...) @@ -103,7 +86,7 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) filebeatVolumes := append( monitoringLogsTargetCaCertSecretVolumes(es), - filebeatConfigMapVolume(es), + filebeatConfigSecretVolume(es), ) volumeLikes = append(volumeLikes, filebeatVolumes...) @@ -143,9 +126,9 @@ func metricbeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (co envVars := append(monitoringSourceEnvVars(es), monitoringTargetEnvVars(es.GetMonitoringMetricsAssociation())...) return corev1.Container{ - Name: MetricbeatContainerName, + Name: metricbeatContainerName, Image: image, - Args: []string{"-c", metricbeatConfigMountPath, "-e"}, + Args: []string{"-c", filepath.Join(metricbeatConfigDirMountPath, metricbeatConfigKey), "-e"}, Env: append(envVars, defaults.PodDownwardEnvVars()...), VolumeMounts: volumeMounts, }, nil @@ -167,9 +150,9 @@ func filebeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (core envVars := monitoringTargetEnvVars(es.GetMonitoringLogsAssociation()) return corev1.Container{ - Name: FilebeatContainerName, + Name: filebeatContainerName, Image: image, - Args: []string{"-c", filebeatConfigMountPath, "-e"}, + Args: []string{"-c", filepath.Join(filebeatConfigDirMountPath, filebeatConfigKey), "-e"}, Env: append(envVars, defaults.PodDownwardEnvVars()...), VolumeMounts: volumeMounts, }, nil @@ -195,9 +178,9 @@ func fullContainerImage(es esv1.Elasticsearch, defaultImage container.Image) (st func monitoringSourceEnvVars(es esv1.Elasticsearch) []corev1.EnvVar { return []corev1.EnvVar{ - {Name: EsSourceURLEnvVarKey, Value: EsSourceURLEnvVarValue}, - {Name: EsSourceUsernameEnvVarKey, Value: user.ElasticUserName}, - {Name: EsSourcePasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ + {Name: esSourceURLEnvVarKey, Value: esSourceURLEnvVarValue}, + {Name: esSourceUsernameEnvVarKey, Value: user.ElasticUserName}, + {Name: esSourcePasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ Name: esv1.ElasticUserSecret(es.Name)}, diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go index cccd359178..2b45344b57 100644 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ b/pkg/controller/elasticsearch/stackmon/volume.go @@ -13,43 +13,46 @@ import ( ) const ( - MetricbeatContainerName = "metricbeat" - MetricbeatConfigVolumeName = "metricbeat-config" - MetricbeatConfigDirMountPath = "/etc/metricbeat-config" + metricbeatConfigVolumeName = "metricbeat-config" + metricbeatConfigDirMountPath = "/etc/metricbeat-config" - FilebeatContainerName = "filebeat" - FilebeatConfigVolumeName = "filebeat-config" - FilebeatConfigDirMountPath = "/etc/filebeat-config" + filebeatConfigVolumeName = "filebeat-config" + filebeatConfigDirMountPath = "/etc/filebeat-config" - MonitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" - MonitoringMetricsTargetEsCaCertVolumeNameFormat = "es-monitoring-metrics-target-certs-%d" - MonitoringLogsTargetEsCaCertVolumeNameFormat = "es-monitoring-logs-target-certs-%d" + monitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" + monitoringMetricsTargetEsCaCertVolumeNameFormat = "es-monitoring-metrics-target-certs-%d" + monitoringLogsTargetEsCaCertVolumeNameFormat = "es-monitoring-logs-target-certs-%d" ) -func metricbeatConfigMapVolume(es esv1.Elasticsearch) volume.ConfigMapVolume { - return volume.NewConfigMapVolume( - metricbeatConfigMapName(es), - MetricbeatConfigVolumeName, - MetricbeatConfigDirMountPath, +func metricbeatConfigSecretName(es esv1.Elasticsearch) string { + return esv1.ESNamer.Suffix(es.Name, metricbeatConfigVolumeName) +} + +func metricbeatConfigSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { + return volume.NewSecretVolumeWithMountPath( + metricbeatConfigSecretName(es), + metricbeatConfigVolumeName, + metricbeatConfigDirMountPath, ) } -func filebeatConfigMapVolume(es esv1.Elasticsearch) volume.ConfigMapVolume { - return volume.NewConfigMapVolume( - filebeatConfigMapName(es), - FilebeatConfigVolumeName, - FilebeatConfigDirMountPath, +func filebeatConfigSecretName(es esv1.Elasticsearch) string { + return esv1.ESNamer.Suffix(es.Name, filebeatConfigVolumeName) +} + +func filebeatConfigSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { + return volume.NewSecretVolumeWithMountPath( + filebeatConfigSecretName(es), + filebeatConfigVolumeName, + filebeatConfigDirMountPath, ) } func monitoringMetricsSourceCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { return volume.NewSecretVolumeWithMountPath( - certificates.PublicCertsSecretName( - esv1.ESNamer, - es.Name, - ), - MonitoringMetricsSourceEsCaCertVolumeName, - MonitoringMetricsSourceEsCaCertMountPath, + certificates.PublicCertsSecretName(esv1.ESNamer, es.Name), + monitoringMetricsSourceEsCaCertVolumeName, + monitoringMetricsSourceEsCaCertMountPath, ) } @@ -58,8 +61,8 @@ func monitoringMetricsTargetCaCertSecretVolumes(es esv1.Elasticsearch) []volume. for i, assoc := range es.GetMonitoringMetricsAssociation() { volumes = append(volumes, volume.NewSecretVolumeWithMountPath( assoc.AssociationConf().GetCASecretName(), - fmt.Sprintf(MonitoringMetricsTargetEsCaCertVolumeNameFormat, i), - fmt.Sprintf(MonitoringMetricsTargetEsCaCertMountPath, i), + fmt.Sprintf(monitoringMetricsTargetEsCaCertVolumeNameFormat, i), + fmt.Sprintf(monitoringMetricsTargetEsCaCertMountPathFormat, i), )) } return volumes @@ -70,8 +73,8 @@ func monitoringLogsTargetCaCertSecretVolumes(es esv1.Elasticsearch) []volume.Vol for i, assoc := range es.GetMonitoringLogsAssociation() { volumes = append(volumes, volume.NewSecretVolumeWithMountPath( assoc.AssociationConf().GetCASecretName(), - fmt.Sprintf(MonitoringLogsTargetEsCaCertVolumeNameFormat, i), - fmt.Sprintf(MonitoringLogsTargetEsCaCertMountPath, i), + fmt.Sprintf(monitoringLogsTargetEsCaCertVolumeNameFormat, i), + fmt.Sprintf(monitoringLogsTargetEsCaCertMountPathFormat, i), )) } return volumes From 2d1c67e29adb5502bc6df3d23f00bd53e29fe213 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 23 Jun 2021 11:46:29 +0200 Subject: [PATCH 43/83] godoc --- pkg/controller/elasticsearch/stackmon/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index 7b93a4cb02..debead5b05 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -34,11 +34,11 @@ var ( monitoringMetricsTargetEsCaCertMountPathFormat = "/mnt/es/%d/monitoring/metrics/target" monitoringLogsTargetEsCaCertMountPathFormat = "/mnt/es/%d/monitoring/logs/target" - // MetricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch + // metricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch //go:embed metricbeat.yml metricbeatConfig string - // FilebeatConfig is a static configuration for Filebeat to collect Elasticsearch logs + // filebeatConfig is a static configuration for Filebeat to collect Elasticsearch logs //go:embed filebeat.yml filebeatConfig string ) From a2fd5d26dc42a57295992075759a150285fbf6b8 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 23 Jun 2021 14:39:26 +0200 Subject: [PATCH 44/83] Put monitoringXxxEnvVars funcs side by side --- .../elasticsearch/stackmon/config.go | 18 +++++++++++++++++- .../elasticsearch/stackmon/container.go | 15 --------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/config.go index debead5b05..83003982c0 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/config.go @@ -12,6 +12,7 @@ import ( esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/reconciler" "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" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -91,8 +92,23 @@ func beatConfigSecret( } } +// monitoringSourceEnvVars returns the environment variables describing how to connect to the monitored Elasticsearch cluster +func monitoringSourceEnvVars(es esv1.Elasticsearch) []corev1.EnvVar { + return []corev1.EnvVar{ + {Name: esSourceURLEnvVarKey, Value: esSourceURLEnvVarValue}, + {Name: esSourceUsernameEnvVarKey, Value: user.ElasticUserName}, + {Name: esSourcePasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: esv1.ElasticUserSecret(es.Name)}, + Key: user.ElasticUserName, + }, + }}, + } +} + // monitoringTargetEnvVars returns the environment variables describing how to connect to Elasticsearch clusters -// referenced in given associations +// referenced in the given associations func monitoringTargetEnvVars(assocs []commonv1.Association) []corev1.EnvVar { vars := make([]corev1.EnvVar, 0) for i, assoc := range assocs { diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 72f33027b7..32d4da6a0c 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -13,7 +13,6 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/common/container" "github.com/elastic/cloud-on-k8s/pkg/controller/common/defaults" "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" corev1 "k8s.io/api/core/v1" ) @@ -175,17 +174,3 @@ func fullContainerImage(es esv1.Elasticsearch, defaultImage container.Image) (st } return container.ImageRepository(defaultImage, es.Spec.Version), nil } - -func monitoringSourceEnvVars(es esv1.Elasticsearch) []corev1.EnvVar { - return []corev1.EnvVar{ - {Name: esSourceURLEnvVarKey, Value: esSourceURLEnvVarValue}, - {Name: esSourceUsernameEnvVarKey, Value: user.ElasticUserName}, - {Name: esSourcePasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: esv1.ElasticUserSecret(es.Name)}, - Key: user.ElasticUserName, - }, - }}, - } -} From 048f8e4722ef83ecf91dd3aab27560a0596264ce Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 23 Jun 2021 14:49:48 +0200 Subject: [PATCH 45/83] Update descriptions for API doc --- config/crds/v1/all-crds.yaml | 16 +++++++++------ ...search.k8s.elastic.co_elasticsearches.yaml | 16 +++++++++------ config/crds/v1beta1/all-crds.yaml | 20 +++++++++++-------- ...search.k8s.elastic.co_elasticsearches.yaml | 16 +++++++++------ .../templates/all-crds-legacy.yaml | 20 +++++++++++-------- .../eck-operator-crds/templates/all-crds.yaml | 16 +++++++++------ docs/reference/api-docs.asciidoc | 12 +++++------ .../elasticsearch/v1/elasticsearch_types.go | 13 ++++++------ 8 files changed, 77 insertions(+), 52 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index ab860c23e7..5eee7aef8c 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -2834,19 +2834,21 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract logs and Stack Monitoring - metrics of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. + description: 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. properties: logs: + description: Logs holds references to Elasticsearch clusters which + will receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Elasticsearch logs. Only - one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. @@ -2872,12 +2874,14 @@ spec: type: array type: object metrics: + description: Metrics holds references to Elasticsearch clusters + which will receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Stack Monitoring metrics. - Only one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. 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 c20c55c567..5d71df1906 100644 --- a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -495,19 +495,21 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract logs and Stack Monitoring - metrics of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. + description: 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. properties: logs: + description: Logs holds references to Elasticsearch clusters which + will receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Elasticsearch logs. Only - one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. @@ -533,12 +535,14 @@ spec: type: array type: object metrics: + description: Metrics holds references to Elasticsearch clusters + which will receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Stack Monitoring metrics. - Only one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. diff --git a/config/crds/v1beta1/all-crds.yaml b/config/crds/v1beta1/all-crds.yaml index afe08d414c..4207e47b6f 100644 --- a/config/crds/v1beta1/all-crds.yaml +++ b/config/crds/v1beta1/all-crds.yaml @@ -2167,19 +2167,21 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract logs and Stack Monitoring - metrics of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. + description: 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. properties: logs: + description: Logs holds references to Elasticsearch clusters which + will receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring - Elasticsearch clusters running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef - is supported. + 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. @@ -2204,12 +2206,14 @@ spec: type: array type: object metrics: + description: Metrics holds references to Elasticsearch clusters + which will receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring - Elasticsearch clusters running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. Only one - ElasticsearchRef is supported. + 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. diff --git a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index e4d4caf428..f408a149ef 100644 --- a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -480,19 +480,21 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract logs and Stack Monitoring - metrics of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. + description: 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. properties: logs: + description: Logs holds references to Elasticsearch clusters which + will receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Elasticsearch logs. Only - one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. @@ -518,12 +520,14 @@ spec: type: array type: object metrics: + description: Metrics holds references to Elasticsearch clusters + which will receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Stack Monitoring metrics. - Only one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml index e8c4e6ef74..cbae89e440 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml @@ -2200,19 +2200,21 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract logs and Stack Monitoring - metrics of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. + description: 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. properties: logs: + description: Logs holds references to Elasticsearch clusters which + will receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring - Elasticsearch clusters running in the same Kubernetes cluster - dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef - is supported. + 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. @@ -2237,12 +2239,14 @@ spec: type: array type: object metrics: + description: Metrics holds references to Elasticsearch clusters + which will receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring - Elasticsearch clusters running in the same Kubernetes cluster - dedicated to receiving Stack Monitoring metrics. Only one - ElasticsearchRef is supported. + 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. 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 1d89068f50..48fa134928 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 @@ -2867,19 +2867,21 @@ spec: description: Image is the Elasticsearch Docker image to deploy. type: string monitoring: - description: Monitoring enables you to extract logs and Stack Monitoring - metrics of this Elasticsearch cluster. See https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html. + description: 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. properties: logs: + description: Logs holds references to Elasticsearch clusters which + will receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Elasticsearch logs. Only - one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. @@ -2905,12 +2907,14 @@ spec: type: array type: object metrics: + description: Metrics holds references to Elasticsearch clusters + which will receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes - cluster dedicated to receiving Stack Monitoring metrics. - Only one ElasticsearchRef is supported. + cluster. Due to existing limitations, only a single Elasticsearch + cluster is currently supported. items: description: ObjectSelector defines a reference to a Kubernetes object. diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 359caa403f..4e2206033b 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -904,7 +904,7 @@ ElasticsearchSpec holds the specification of an Elasticsearch cluster. | *`serviceAccountName`* __string__ | ServiceAccountName is used to check access from the current resource to a resource (eg. a remote Elasticsearch cluster) in a different namespace. Can only be used if ECK is enforcing RBAC on references. | *`remoteClusters`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring[$$Monitoring$$]__ | Monitoring enables you to extract logs and Stack Monitoring metrics 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.aaakk.us.kg-elastic-cloud-on-k8s-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. |=== @@ -939,7 +939,7 @@ FileRealmSource references users to create in the Elasticsearch cluster. [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef is supported. +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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. |=== @@ -956,14 +956,14 @@ FileRealmSource references users to create in the Elasticsearch cluster. [cols="25a,75a", options="header"] |=== | Field | Description -| *`elasticsearchRefs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-common-v1-objectselector[$$ObjectSelector$$]__ | ElasticsearchRefs is a reference to a list of monitoring Elasticsearch clusters running in the same Kubernetes cluster dedicated to receiving Stack Monitoring metrics. Only one ElasticsearchRef is supported. +| *`elasticsearchRefs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-monitoring"] === Monitoring -Monitoring holds references to Elasticsearch clusters which will receive logs and metrics from this Elasticsearch cluster. + .Appears In: **** @@ -973,8 +973,8 @@ Monitoring holds references to Elasticsearch clusters which will receive logs an [cols="25a,75a", options="header"] |=== | Field | Description -| *`metrics`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | -| *`logs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$]__ | +| *`metrics`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which will receive monitoring data from this Elasticsearch cluster. +| *`logs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which will receive log data from this Elasticsearch cluster. |=== diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 8fec41aa28..bcefb01185 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -78,7 +78,7 @@ type ElasticsearchSpec struct { // +kubebuilder:validation:Enum=DeleteOnScaledownOnly;DeleteOnScaledownAndClusterDeletion VolumeClaimDeletePolicy VolumeClaimDeletePolicy `json:"volumeClaimDeletePolicy,omitempty"` - // Monitoring enables you to extract logs and Stack Monitoring metrics of this Elasticsearch cluster. + // 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. @@ -86,24 +86,25 @@ type ElasticsearchSpec struct { Monitoring Monitoring `json:"monitoring,omitempty"` } -// Monitoring holds references to Elasticsearch clusters which will receive logs and metrics from this Elasticsearch cluster. type Monitoring struct { + // Metrics holds references to Elasticsearch clusters which will receive monitoring data from this Elasticsearch cluster. // +kubebuilder:validation:Optional Metrics MetricsMonitoring `json:"metrics,omitempty"` + // Logs holds references to Elasticsearch clusters which will 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 - // dedicated to receiving Stack Monitoring metrics. Only one ElasticsearchRef is supported. + // 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 - // dedicated to receiving Elasticsearch logs. Only one ElasticsearchRef is supported. + // 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"` } From 7b249bd4b84396547ce16b1b4b88f368975337bf Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 23 Jun 2021 16:20:30 +0200 Subject: [PATCH 46/83] Apply review's input for API doc --- pkg/apis/common/v1/association.go | 2 +- pkg/apis/common/v1/common.go | 6 +++--- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index 46a8b39e6b..d0e4296f19 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -24,7 +24,7 @@ type AssociationType string type AssociationStatus string // AssociationStatusMap is the map of association's namespaced name string to its AssociationStatus. For resources that -// have a single Association of a given type (eg. single ES reference), this map will contain a single entry. +// have a single Association of a given type (for ex. single ES reference), this map contains a single entry. type AssociationStatusMap map[string]AssociationStatus // NewSingleAssociationStatusMap creates an AssociationStatusMap that expects only a single Association. Using a diff --git a/pkg/apis/common/v1/common.go b/pkg/apis/common/v1/common.go index a0fa67db8d..a2337689da 100644 --- a/pkg/apis/common/v1/common.go +++ b/pkg/apis/common/v1/common.go @@ -49,9 +49,9 @@ type ObjectSelector struct { Name string `json:"name"` // Namespace of the Kubernetes object. If empty, defaults to the current namespace. Namespace string `json:"namespace,omitempty"` - // ServiceName is the name of an existing Kubernetes service which will be 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 will be used. + // 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. ServiceName string `json:"serviceName,omitempty"` } diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index bcefb01185..2fee799af8 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -87,10 +87,10 @@ type ElasticsearchSpec struct { } type Monitoring struct { - // Metrics holds references to Elasticsearch clusters which will receive monitoring data from this Elasticsearch cluster. + // 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 will receive log data from this Elasticsearch cluster. + // Logs holds references to Elasticsearch clusters which receive log data from this Elasticsearch cluster. // +kubebuilder:validation:Optional Logs LogsMonitoring `json:"logs,omitempty"` } From eb9de170ca0a59a5e2426230a52f849de03e9ce1 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Wed, 23 Jun 2021 16:20:41 +0200 Subject: [PATCH 47/83] Run generate --- config/crds/v1/all-crds.yaml | 102 +++++++++--------- .../v1/bases/agent.k8s.elastic.co_agents.yaml | 12 +-- .../bases/apm.k8s.elastic.co_apmservers.yaml | 16 +-- .../v1/bases/beat.k8s.elastic.co_beats.yaml | 16 +-- ...search.k8s.elastic.co_elasticsearches.yaml | 26 ++--- ...rch.k8s.elastic.co_enterprisesearches.yaml | 16 +-- .../bases/kibana.k8s.elastic.co_kibanas.yaml | 8 +- ...aps.k8s.elastic.co_elasticmapsservers.yaml | 8 +- config/crds/v1beta1/all-crds.yaml | 94 ++++++++-------- .../bases/agent.k8s.elastic.co_agents.yaml | 12 +-- .../bases/apm.k8s.elastic.co_apmservers.yaml | 16 +-- .../bases/beat.k8s.elastic.co_beats.yaml | 16 +-- ...search.k8s.elastic.co_elasticsearches.yaml | 26 ++--- ...rch.k8s.elastic.co_enterprisesearches.yaml | 8 +- .../bases/kibana.k8s.elastic.co_kibanas.yaml | 8 +- ...aps.k8s.elastic.co_elasticmapsservers.yaml | 8 +- .../templates/all-crds-legacy.yaml | 94 ++++++++-------- .../eck-operator-crds/templates/all-crds.yaml | 102 +++++++++--------- docs/reference/api-docs.asciidoc | 6 +- 19 files changed, 297 insertions(+), 297 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 5eee7aef8c..3f8776e601 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -202,10 +202,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -276,8 +276,8 @@ spec: 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 (eg. single ES reference), this - map will contain a single entry. + single Association of a given type (for ex. single ES reference), + this map contains a single entry. type: object expectedNodes: format: int32 @@ -378,10 +378,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -808,10 +808,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -1657,10 +1657,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -1683,10 +1683,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -1874,10 +1874,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -2842,7 +2842,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Elasticsearch cluster. + receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -2862,11 +2862,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -2875,7 +2875,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -2895,11 +2895,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -3304,10 +3304,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of the + referenced resource is used. type: string required: - name @@ -3804,8 +3804,8 @@ spec: 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 (eg. single ES reference), this - map will contain a single entry. + single Association of a given type (for ex. single ES reference), + this map contains a single entry. type: object phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch @@ -4826,10 +4826,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -5355,10 +5355,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -5899,10 +5899,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/config/crds/v1/bases/agent.k8s.elastic.co_agents.yaml b/config/crds/v1/bases/agent.k8s.elastic.co_agents.yaml index f02879027f..5cc163a6bd 100644 --- a/config/crds/v1/bases/agent.k8s.elastic.co_agents.yaml +++ b/config/crds/v1/bases/agent.k8s.elastic.co_agents.yaml @@ -13380,10 +13380,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -13454,8 +13454,8 @@ spec: 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 (eg. single ES reference), this - map will contain a single entry. + single Association of a given type (for ex. single ES reference), + this map contains a single entry. type: object expectedNodes: format: int32 diff --git a/config/crds/v1/bases/apm.k8s.elastic.co_apmservers.yaml b/config/crds/v1/bases/apm.k8s.elastic.co_apmservers.yaml index 3dcc7d1fca..70da858762 100644 --- a/config/crds/v1/bases/apm.k8s.elastic.co_apmservers.yaml +++ b/config/crds/v1/bases/apm.k8s.elastic.co_apmservers.yaml @@ -76,10 +76,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -506,10 +506,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name 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 fa84684123..cc2e2fd70e 100644 --- a/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1/bases/beat.k8s.elastic.co_beats.yaml @@ -13380,10 +13380,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -13406,10 +13406,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name 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 5d71df1906..0d5a841807 100644 --- a/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -503,7 +503,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Elasticsearch cluster. + receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -523,11 +523,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -536,7 +536,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -556,11 +556,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -7681,10 +7681,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of the + referenced resource is used. type: string required: - name @@ -8181,8 +8181,8 @@ spec: 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 (eg. single ES reference), this - map will contain a single entry. + single Association of a given type (for ex. single ES reference), + this map contains a single entry. type: object phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch diff --git a/config/crds/v1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml b/config/crds/v1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml index 93754921f6..ea671c05b3 100644 --- a/config/crds/v1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml +++ b/config/crds/v1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml @@ -88,10 +88,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -6890,10 +6890,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name 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 f68bfe8188..6f18d6a28d 100644 --- a/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml +++ b/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml @@ -76,10 +76,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/config/crds/v1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml b/config/crds/v1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml index c406a862e6..9c2b015395 100644 --- a/config/crds/v1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml +++ b/config/crds/v1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml @@ -89,10 +89,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/config/crds/v1beta1/all-crds.yaml b/config/crds/v1beta1/all-crds.yaml index 4207e47b6f..2ee58066f6 100644 --- a/config/crds/v1beta1/all-crds.yaml +++ b/config/crds/v1beta1/all-crds.yaml @@ -185,10 +185,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -259,8 +259,8 @@ spec: 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 (eg. single ES reference), this map will - contain a single entry. + Association of a given type (for ex. single ES reference), this map + contains a single entry. type: object expectedNodes: format: int32 @@ -360,10 +360,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -758,10 +758,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -1056,10 +1056,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -1082,10 +1082,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -1272,10 +1272,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -2175,7 +2175,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Elasticsearch cluster. + receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring @@ -2195,10 +2195,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of + the referenced resource is used. type: string required: - name @@ -2207,7 +2207,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring @@ -2227,10 +2227,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of + the referenced resource is used. type: string required: - name @@ -2585,10 +2585,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of the + referenced resource is used. type: string required: - name @@ -3050,8 +3050,8 @@ spec: 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 (eg. single ES reference), this map will - contain a single entry. + Association of a given type (for ex. single ES reference), this map + contains a single entry. type: object phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch @@ -3167,10 +3167,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -3680,10 +3680,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name diff --git a/config/crds/v1beta1/bases/agent.k8s.elastic.co_agents.yaml b/config/crds/v1beta1/bases/agent.k8s.elastic.co_agents.yaml index ac59c3a857..87edf39a22 100644 --- a/config/crds/v1beta1/bases/agent.k8s.elastic.co_agents.yaml +++ b/config/crds/v1beta1/bases/agent.k8s.elastic.co_agents.yaml @@ -12955,10 +12955,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -13029,8 +13029,8 @@ spec: 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 (eg. single ES reference), this map will - contain a single entry. + Association of a given type (for ex. single ES reference), this map + contains a single entry. type: object expectedNodes: format: int32 diff --git a/config/crds/v1beta1/bases/apm.k8s.elastic.co_apmservers.yaml b/config/crds/v1beta1/bases/apm.k8s.elastic.co_apmservers.yaml index 99b6d361d5..c4cd2ce981 100644 --- a/config/crds/v1beta1/bases/apm.k8s.elastic.co_apmservers.yaml +++ b/config/crds/v1beta1/bases/apm.k8s.elastic.co_apmservers.yaml @@ -79,10 +79,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -491,10 +491,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/config/crds/v1beta1/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/v1beta1/bases/beat.k8s.elastic.co_beats.yaml index 3454216c7a..696e4bf2d5 100644 --- a/config/crds/v1beta1/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/v1beta1/bases/beat.k8s.elastic.co_beats.yaml @@ -12956,10 +12956,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -12982,10 +12982,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name diff --git a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml index f408a149ef..6ef97d187f 100644 --- a/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml +++ b/config/crds/v1beta1/bases/elasticsearch.k8s.elastic.co_elasticsearches.yaml @@ -488,7 +488,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Elasticsearch cluster. + receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -508,11 +508,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -521,7 +521,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -541,11 +541,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -7595,10 +7595,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of the + referenced resource is used. type: string required: - name @@ -8077,8 +8077,8 @@ spec: 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 (eg. single ES reference), this - map will contain a single entry. + single Association of a given type (for ex. single ES reference), + this map contains a single entry. type: object phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch diff --git a/config/crds/v1beta1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml b/config/crds/v1beta1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml index 84c468593e..8896ec49da 100644 --- a/config/crds/v1beta1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml +++ b/config/crds/v1beta1/bases/enterprisesearch.k8s.elastic.co_enterprisesearches.yaml @@ -87,10 +87,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name diff --git a/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml b/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml index c6ab1c3c02..83d1823a50 100644 --- a/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml +++ b/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml @@ -79,10 +79,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/config/crds/v1beta1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml b/config/crds/v1beta1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml index 425f444c53..d604b0959d 100644 --- a/config/crds/v1beta1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml +++ b/config/crds/v1beta1/bases/maps.k8s.elastic.co_elasticmapsservers.yaml @@ -89,10 +89,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml index cbae89e440..93a054df7f 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml @@ -194,10 +194,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -268,8 +268,8 @@ spec: 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 (eg. single ES reference), this map will - contain a single entry. + Association of a given type (for ex. single ES reference), this map + contains a single entry. type: object expectedNodes: format: int32 @@ -375,10 +375,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -773,10 +773,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -1077,10 +1077,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -1103,10 +1103,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -1299,10 +1299,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -2208,7 +2208,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Elasticsearch cluster. + receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring @@ -2228,10 +2228,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of + the referenced resource is used. type: string required: - name @@ -2240,7 +2240,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of monitoring @@ -2260,10 +2260,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of + the referenced resource is used. type: string required: - name @@ -2618,10 +2618,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of the + referenced resource is used. type: string required: - name @@ -3083,8 +3083,8 @@ spec: 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 (eg. single ES reference), this map will - contain a single entry. + Association of a given type (for ex. single ES reference), this map + contains a single entry. type: object phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch @@ -3206,10 +3206,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name @@ -3725,10 +3725,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name 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 48fa134928..a658eef00a 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 @@ -211,10 +211,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -285,8 +285,8 @@ spec: 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 (eg. single ES reference), this - map will contain a single entry. + single Association of a given type (for ex. single ES reference), + this map contains a single entry. type: object expectedNodes: format: int32 @@ -393,10 +393,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -823,10 +823,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -1678,10 +1678,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -1704,10 +1704,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -1901,10 +1901,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -2875,7 +2875,7 @@ spec: properties: logs: description: Logs holds references to Elasticsearch clusters which - will receive log data from this Elasticsearch cluster. + receive log data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -2895,11 +2895,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -2908,7 +2908,7 @@ spec: type: object metrics: description: Metrics holds references to Elasticsearch clusters - which will receive monitoring data from this Elasticsearch cluster. + which receive monitoring data from this Elasticsearch cluster. properties: elasticsearchRefs: description: ElasticsearchRefs is a reference to a list of @@ -2928,11 +2928,11 @@ spec: type: string serviceName: description: ServiceName is the name of an existing - Kubernetes service which will be used to make requests + 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 + namespace as the referenced resource. If left empty, the default HTTP service of the referenced resource - will be used. + is used. type: string required: - name @@ -3337,10 +3337,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be used to make requests to the referenced + 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 will be used. + resource. If left empty, the default HTTP service of the + referenced resource is used. type: string required: - name @@ -3837,8 +3837,8 @@ spec: 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 (eg. single ES reference), this - map will contain a single entry. + single Association of a given type (for ex. single ES reference), + this map contains a single entry. type: object phase: description: ElasticsearchOrchestrationPhase is the phase Elasticsearch @@ -4865,10 +4865,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -5394,10 +5394,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name @@ -5944,10 +5944,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/docs/reference/api-docs.asciidoc b/docs/reference/api-docs.asciidoc index 4e2206033b..8e1287726c 100644 --- a/docs/reference/api-docs.asciidoc +++ b/docs/reference/api-docs.asciidoc @@ -454,7 +454,7 @@ ObjectSelector defines a reference to a Kubernetes object. | Field | Description | *`name`* __string__ | Name of the Kubernetes object. | *`namespace`* __string__ | Namespace of the Kubernetes object. If empty, defaults to the current namespace. -| *`serviceName`* __string__ | ServiceName is the name of an existing Kubernetes service which will be 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 will be used. +| *`serviceName`* __string__ | 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. |=== @@ -973,8 +973,8 @@ FileRealmSource references users to create in the Elasticsearch cluster. [cols="25a,75a", options="header"] |=== | Field | Description -| *`metrics`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-metricsmonitoring[$$MetricsMonitoring$$]__ | Metrics holds references to Elasticsearch clusters which will receive monitoring data from this Elasticsearch cluster. -| *`logs`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which will receive log data from this Elasticsearch cluster. +| *`metrics`* __xref:{anchor_prefix}-github.aaakk.us.kg-elastic-cloud-on-k8s-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.aaakk.us.kg-elastic-cloud-on-k8s-pkg-apis-elasticsearch-v1-logsmonitoring[$$LogsMonitoring$$]__ | Logs holds references to Elasticsearch clusters which receive log data from this Elasticsearch cluster. |=== From 541ab647ba56ce1ad0e785d42e6893453d299412 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 12:07:49 +0200 Subject: [PATCH 48/83] Fix receiver name --- .../elasticsearch/v1/elasticsearch_types.go | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 2fee799af8..8bcd7ae34e 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -119,23 +119,23 @@ type EsMonitoringAssociation struct { var _ commonv1.Association = &EsMonitoringAssociation{} -func (eea *EsMonitoringAssociation) Associated() commonv1.Associated { - if eea == nil { +func (ema *EsMonitoringAssociation) Associated() commonv1.Associated { + if ema == nil { return nil } - if eea.Elasticsearch == nil { - eea.Elasticsearch = &Elasticsearch{} + if ema.Elasticsearch == nil { + ema.Elasticsearch = &Elasticsearch{} } - return eea.Elasticsearch + return ema.Elasticsearch } -func (eea *EsMonitoringAssociation) AssociationConfAnnotationName() string { +func (ema *EsMonitoringAssociation) AssociationConfAnnotationName() string { // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, // based on ElasticsearchRefs nsNameHash := sha256.New224() // concat with dot to avoid collisions, as namespace can't contain dots - _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", eea.ref.Namespace, eea.ref.Name))) + _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", ema.ref.Namespace, ema.ref.Name))) // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to // give too long output // no padding to avoid illegal '=' character in the annotation name @@ -147,22 +147,22 @@ func (eea *EsMonitoringAssociation) AssociationConfAnnotationName() string { ) } -func (eea *EsMonitoringAssociation) AssociationType() commonv1.AssociationType { +func (ema *EsMonitoringAssociation) AssociationType() commonv1.AssociationType { return commonv1.ElasticsearchAssociationType } -func (eea *EsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { +func (ema *EsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { return commonv1.ObjectSelector{ - Name: eea.ref.Name, - Namespace: eea.ref.Namespace, + Name: ema.ref.Name, + Namespace: ema.ref.Namespace, } } -func (eea *EsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf { - if eea.AssocConfs == nil { +func (ema *EsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf { + if ema.AssocConfs == nil { return nil } - assocConf, found := eea.AssocConfs[eea.ref] + assocConf, found := ema.AssocConfs[ema.ref] if !found { return nil } @@ -170,17 +170,17 @@ func (eea *EsMonitoringAssociation) AssociationConf() *commonv1.AssociationConf return &assocConf } -func (eea *EsMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { - if eea.AssocConfs == nil { - eea.AssocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) +func (ema *EsMonitoringAssociation) SetAssociationConf(assocConf *commonv1.AssociationConf) { + if ema.AssocConfs == nil { + ema.AssocConfs = make(map[types.NamespacedName]commonv1.AssociationConf) } if assocConf != nil { - eea.AssocConfs[eea.ref] = *assocConf + ema.AssocConfs[ema.ref] = *assocConf } } -func (eea *EsMonitoringAssociation) AssociationID() string { - return fmt.Sprintf("%s-%s", eea.ref.Namespace, eea.ref.Name) +func (ema *EsMonitoringAssociation) AssociationID() string { + return fmt.Sprintf("%s-%s", ema.ref.Namespace, ema.ref.Name) } // Associated methods From 175bcf365aca84a9dc6994d8690782af638208f3 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 12:09:19 +0200 Subject: [PATCH 49/83] Factorize ElasticsearchConfigAnnotationName shared with agent --- pkg/apis/agent/v1alpha1/agent_types.go | 18 +--------------- pkg/apis/common/v1/association.go | 21 +++++++++++++++++++ .../elasticsearch/v1/elasticsearch_types.go | 18 +--------------- 3 files changed, 23 insertions(+), 34 deletions(-) diff --git a/pkg/apis/agent/v1alpha1/agent_types.go b/pkg/apis/agent/v1alpha1/agent_types.go index 259df6b07d..27e9374c97 100644 --- a/pkg/apis/agent/v1alpha1/agent_types.go +++ b/pkg/apis/agent/v1alpha1/agent_types.go @@ -5,8 +5,6 @@ package v1alpha1 import ( - "crypto/sha256" - "encoding/base32" "fmt" appsv1 "k8s.io/api/apps/v1" @@ -228,21 +226,7 @@ func (aea *AgentESAssociation) AssociationRef() commonv1.ObjectSelector { } func (aea *AgentESAssociation) AssociationConfAnnotationName() string { - // annotation key should be stable to allow Agent Controller only pick up the ones it expects, - // based on ElasticsearchRefs - - nsNameHash := sha256.New224() - // concat with dot to avoid collisions, as namespace can't contain dots - _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", aea.ref.Namespace, aea.ref.Name))) - // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to - // give too long output - // no padding to avoid illegal '=' character in the annotation name - hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) - - return commonv1.FormatNameWithID( - commonv1.ElasticsearchConfigAnnotationNameBase+"%s", - hash, - ) + return commonv1.ElasticsearchConfigAnnotationName(aea.ref) } func (aea *AgentESAssociation) AssociationConf() *commonv1.AssociationConf { diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index d0e4296f19..9b6bbbdb83 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -5,12 +5,15 @@ package v1 import ( + "crypto/sha256" + "encoding/base32" "fmt" "sort" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ) const ( @@ -258,3 +261,21 @@ func (ac *AssociationConf) GetVersion() string { } return ac.Version } + +func ElasticsearchConfigAnnotationName(esNsn types.NamespacedName) string { + // annotation key should be stable to allow the Elasticsearch Controller to only pick up the ones it expects, + // based on ElasticsearchRefs + + nsNameHash := sha256.New224() + // concat with dot to avoid collisions, as namespace can't contain dots + _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", esNsn.Namespace, esNsn.Name))) + // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to + // give too long output + // no padding to avoid illegal '=' character in the annotation name + hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) + + return FormatNameWithID( + ElasticsearchConfigAnnotationNameBase+"%s", + hash, + ) +} \ No newline at end of file diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 8bcd7ae34e..c0046d7ec9 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -5,8 +5,6 @@ package v1 import ( - "crypto/sha256" - "encoding/base32" "fmt" corev1 "k8s.io/api/core/v1" @@ -130,21 +128,7 @@ func (ema *EsMonitoringAssociation) Associated() commonv1.Associated { } func (ema *EsMonitoringAssociation) AssociationConfAnnotationName() string { - // annotation key should be stable to allow Elasticsearch Controller only pick up the ones it expects, - // based on ElasticsearchRefs - - nsNameHash := sha256.New224() - // concat with dot to avoid collisions, as namespace can't contain dots - _, _ = nsNameHash.Write([]byte(fmt.Sprintf("%s.%s", ema.ref.Namespace, ema.ref.Name))) - // base32 to encode and limit the length, as using Sprintf with "%x" encodes with base16 which happens to - // give too long output - // no padding to avoid illegal '=' character in the annotation name - hash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nsNameHash.Sum(nil)) - - return commonv1.FormatNameWithID( - commonv1.ElasticsearchConfigAnnotationNameBase+"%s", - hash, - ) + return commonv1.ElasticsearchConfigAnnotationName(ema.ref) } func (ema *EsMonitoringAssociation) AssociationType() commonv1.AssociationType { From ac8cbb2132f476e44768193b6ed9c3d7a5811f9c Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:05:30 +0200 Subject: [PATCH 50/83] Adjust association type and labels --- pkg/apis/common/v1/association.go | 3 ++- .../elasticsearch/v1/elasticsearch_types.go | 6 ++--- .../association/controller/es_monitoring.go | 22 ++++++++++--------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index 9b6bbbdb83..9285d6fde0 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -95,6 +95,7 @@ func (asm AssociationStatusMap) AllEstablished() bool { const ( ElasticsearchConfigAnnotationNameBase = "association.k8s.elastic.co/es-conf" ElasticsearchAssociationType = "elasticsearch" + EsMonitoringAssociationType = "es-monitoring" KibanaConfigAnnotationNameBase = "association.k8s.elastic.co/kb-conf" KibanaAssociationType = "kibana" @@ -278,4 +279,4 @@ func ElasticsearchConfigAnnotationName(esNsn types.NamespacedName) string { ElasticsearchConfigAnnotationNameBase+"%s", hash, ) -} \ No newline at end of file +} diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index c0046d7ec9..61a8129ded 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -132,7 +132,7 @@ func (ema *EsMonitoringAssociation) AssociationConfAnnotationName() string { } func (ema *EsMonitoringAssociation) AssociationType() commonv1.AssociationType { - return commonv1.ElasticsearchAssociationType + return commonv1.EsMonitoringAssociationType } func (ema *EsMonitoringAssociation) AssociationRef() commonv1.ObjectSelector { @@ -223,7 +223,7 @@ func (es *Elasticsearch) GetMonitoringLogsAssociation() []commonv1.Association { } func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) commonv1.AssociationStatusMap { - if typ != commonv1.ElasticsearchAssociationType { + if typ != commonv1.EsMonitoringAssociationType { return commonv1.AssociationStatusMap{} } @@ -231,7 +231,7 @@ func (es *Elasticsearch) AssociationStatusMap(typ commonv1.AssociationType) comm } func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, status commonv1.AssociationStatusMap) error { - if typ != commonv1.ElasticsearchAssociationType { + if typ != commonv1.EsMonitoringAssociationType { return fmt.Errorf("association type %s not known", typ) } diff --git a/pkg/controller/association/controller/es_monitoring.go b/pkg/controller/association/controller/es_monitoring.go index 46e1e9a353..17da71699c 100644 --- a/pkg/controller/association/controller/es_monitoring.go +++ b/pkg/controller/association/controller/es_monitoring.go @@ -19,12 +19,14 @@ import ( ) const ( - // EsMonitoringAssociationLabelName marks resources created by this controller for easier retrieval. - EsMonitoringAssociationLabelName = "esmonitoringassociation.k8s.elastic.co/name" - // EsMonitoringAssociationLabelNamespace marks resources created by this controller for easier retrieval. - EsMonitoringAssociationLabelNamespace = "esmonitoringassociation.k8s.elastic.co/namespace" - // EsMonitoringAssociationLabelType marks the type of association. - EsMonitoringAssociationLabelType = "esmonitoringassociation.k8s.elastic.co/type" + // EsAssociationLabelName marks resources created by this controller for easier retrieval. + EsAssociationLabelName = "esassociation.k8s.elastic.co/name" + // EsAssociationLabelNamespace marks resources created by this controller for easier retrieval. + EsAssociationLabelNamespace = "esassociation.k8s.elastic.co/namespace" + // EsAssociationLabelType marks the type of association. + EsAssociationLabelType = "esassociation.k8s.elastic.co/type" + + EsMonitoringAssociationType = "es-monitoring" ) // AddEsMonitoring reconciles an association between two Elasticsearch clusters for Stack Monitoring. @@ -38,15 +40,15 @@ func AddEsMonitoring(mgr manager.Manager, accessReviewer rbac.AccessReviewer, pa }, ReferencedResourceVersion: referencedElasticsearchStatusVersion, ExternalServiceURL: getElasticsearchExternalURL, - AssociationType: commonv1.ElasticsearchAssociationType, + AssociationType: commonv1.EsMonitoringAssociationType, AssociatedNamer: esv1.ESNamer, AssociationName: "es-monitoring", AssociatedShortName: "es-mon", Labels: func(associated types.NamespacedName) map[string]string { return map[string]string{ - EsMonitoringAssociationLabelName: associated.Name, - EsMonitoringAssociationLabelNamespace: associated.Namespace, - EsMonitoringAssociationLabelType: commonv1.ElasticsearchAssociationType, + EsAssociationLabelName: associated.Name, + EsAssociationLabelNamespace: associated.Namespace, + EsAssociationLabelType: EsMonitoringAssociationType, } }, AssociationConfAnnotationNameBase: commonv1.ElasticsearchConfigAnnotationNameBase, From a52d1f19a2b1c4d13827a468f09acce5aebcee0c Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:05:51 +0200 Subject: [PATCH 51/83] Typo and new line --- pkg/controller/common/defaults/pod_template.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/controller/common/defaults/pod_template.go b/pkg/controller/common/defaults/pod_template.go index 7f98a965eb..5771b310ce 100644 --- a/pkg/controller/common/defaults/pod_template.go +++ b/pkg/controller/common/defaults/pod_template.go @@ -55,7 +55,7 @@ func NewPodTemplateBuilder(base corev1.PodTemplateSpec, containerName string) *P return builder.setDefaults() } -// getContainer retrieves the existing Container from the pod template +// getContainer retrieves the main Container from the pod template func (b *PodTemplateBuilder) getContainer() *corev1.Container { for i, c := range b.PodTemplate.Spec.Containers { if c.Name == b.containerName { @@ -64,6 +64,7 @@ func (b *PodTemplateBuilder) getContainer() *corev1.Container { } return nil } + func (b *PodTemplateBuilder) setContainerDefaulter() { b.containerDefaulter = container.NewDefaulter(b.getContainer()) } From e52d785b89d1660cbf3d573df36e46c6ee23be81 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:09:21 +0200 Subject: [PATCH 52/83] Decouple beat_config.go and es_config.go --- .../stackmon/{config.go => beat_config.go} | 16 +++----------- .../elasticsearch/stackmon/es_config.go | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 13 deletions(-) rename pkg/controller/elasticsearch/stackmon/{config.go => beat_config.go} (91%) create mode 100644 pkg/controller/elasticsearch/stackmon/es_config.go diff --git a/pkg/controller/elasticsearch/stackmon/config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go similarity index 91% rename from pkg/controller/elasticsearch/stackmon/config.go rename to pkg/controller/elasticsearch/stackmon/beat_config.go index 83003982c0..dfb8d47f3a 100644 --- a/pkg/controller/elasticsearch/stackmon/config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -8,14 +8,15 @@ import ( _ "embed" // for the beats config files "fmt" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + 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/reconciler" "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" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // Environments variables and paths to the Elasticsearch CA certificates used in the beats configuration to describe @@ -44,17 +45,6 @@ var ( filebeatConfig string ) -// MonitoringConfig returns the Elasticsearch settings required to enable the collection of monitoring data -func MonitoringConfig(es esv1.Elasticsearch) commonv1.Config { - if !IsMonitoringMetricsDefined(es) { - return commonv1.Config{} - } - return commonv1.Config{Data: map[string]interface{}{ - esv1.XPackMonitoringCollectionEnabled: true, - esv1.XPackMonitoringElasticsearchCollectionEnabled: false, - }} -} - // ReconcileConfigSecrets reconciles the secrets holding the beats configuration func ReconcileConfigSecrets(client k8s.Client, es esv1.Elasticsearch) error { if IsMonitoringMetricsDefined(es) { diff --git a/pkg/controller/elasticsearch/stackmon/es_config.go b/pkg/controller/elasticsearch/stackmon/es_config.go new file mode 100644 index 0000000000..a3f954b160 --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/es_config.go @@ -0,0 +1,21 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" +) + +// MonitoringConfig returns the Elasticsearch settings to enable the collection of monitoring data +func MonitoringConfig(es esv1.Elasticsearch) commonv1.Config { + if !IsMonitoringMetricsDefined(es) { + return commonv1.Config{} + } + return commonv1.Config{Data: map[string]interface{}{ + esv1.XPackMonitoringCollectionEnabled: true, + esv1.XPackMonitoringElasticsearchCollectionEnabled: false, + }} +} From a9b4e49f7771bff03615fd016bc8a72bdebe8e43 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:10:04 +0200 Subject: [PATCH 53/83] Adjust TargetEsCaCertMountPathFormat --- pkg/controller/elasticsearch/stackmon/beat_config.go | 4 ++-- pkg/controller/elasticsearch/stackmon/filebeat.yml | 2 +- pkg/controller/elasticsearch/stackmon/metricbeat.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/beat_config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go index dfb8d47f3a..6e03d57cce 100644 --- a/pkg/controller/elasticsearch/stackmon/beat_config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -33,8 +33,8 @@ var ( esTargetPasswordEnvVarKeyFormat = "ES_%d_TARGET_PASSWORD" //nolint:gosec monitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" - monitoringMetricsTargetEsCaCertMountPathFormat = "/mnt/es/%d/monitoring/metrics/target" - monitoringLogsTargetEsCaCertMountPathFormat = "/mnt/es/%d/monitoring/logs/target" + monitoringMetricsTargetEsCaCertMountPathFormat = "/mnt/es/monitoring/metrics/target/%d" + monitoringLogsTargetEsCaCertMountPathFormat = "/mnt/es/monitoring/logs/target/%d" // metricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch //go:embed metricbeat.yml diff --git a/pkg/controller/elasticsearch/stackmon/filebeat.yml b/pkg/controller/elasticsearch/stackmon/filebeat.yml index 5182c0c8b9..f9d707024b 100644 --- a/pkg/controller/elasticsearch/stackmon/filebeat.yml +++ b/pkg/controller/elasticsearch/stackmon/filebeat.yml @@ -44,4 +44,4 @@ output.elasticsearch: hosts: ['${ES_0_TARGET_URL}'] username: ${ES_0_TARGET_USERNAME} password: ${ES_0_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/0/monitoring/logs/target/ca.crt"] + ssl.certificate_authorities: ["/mnt/es/monitoring/logs/target/0/ca.crt"] diff --git a/pkg/controller/elasticsearch/stackmon/metricbeat.yml b/pkg/controller/elasticsearch/stackmon/metricbeat.yml index 626b0d1dfb..bc5bcc43b0 100644 --- a/pkg/controller/elasticsearch/stackmon/metricbeat.yml +++ b/pkg/controller/elasticsearch/stackmon/metricbeat.yml @@ -26,4 +26,4 @@ output.elasticsearch: hosts: ['${ES_0_TARGET_URL}'] username: ${ES_0_TARGET_USERNAME} password: ${ES_0_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/0/monitoring/metrics/target/ca.crt"] + ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/target/0/ca.crt"] From ffa0aa087037df8317140a3f5dd335413b16925d Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:11:37 +0200 Subject: [PATCH 54/83] Reuse IsStackMonitoringDefined --- pkg/controller/elasticsearch/stackmon/container.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 32d4da6a0c..01561e5a01 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -53,17 +53,14 @@ func IsMonitoringLogsDefined(es esv1.Elasticsearch) bool { // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers // in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { - isMonitoringMetrics := IsMonitoringMetricsDefined(es) - isMonitoringLogs := IsMonitoringLogsDefined(es) - // No monitoring defined, skip - if !isMonitoringMetrics && !isMonitoringLogs { + if !IsStackMonitoringDefined(es) { return builder, nil } volumeLikes := make([]volume.VolumeLike, 0) - if isMonitoringMetrics { + if IsMonitoringMetricsDefined(es) { metricbeatVolumes := append( monitoringMetricsTargetCaCertSecretVolumes(es), metricbeatConfigSecretVolume(es), @@ -79,7 +76,7 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) builder.WithContainers(metricbeat) } - if isMonitoringLogs { + if IsMonitoringLogsDefined(es) { // Enable Stack logging to write Elasticsearch logs to disk builder.WithEnv(stackLoggingEnvVar()) From 6218a475798a439402ecaec66c91af3c752654de Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:12:41 +0200 Subject: [PATCH 55/83] Move and rename fileLogStyleEnvVar --- pkg/controller/elasticsearch/stackmon/container.go | 9 +-------- pkg/controller/elasticsearch/stackmon/es_config.go | 7 +++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 01561e5a01..4833000287 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -18,9 +18,6 @@ import ( ) const ( - esLogStyleEnvVarKey = "ES_LOG_STYLE" - esLogStyleEnvVarValue = "file" - metricbeatContainerName = "metricbeat" filebeatContainerName = "filebeat" @@ -78,7 +75,7 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) if IsMonitoringLogsDefined(es) { // Enable Stack logging to write Elasticsearch logs to disk - builder.WithEnv(stackLoggingEnvVar()) + builder.WithEnv(fileLogStyleEnvVar()) filebeatVolumes := append( monitoringLogsTargetCaCertSecretVolumes(es), @@ -104,10 +101,6 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) return builder, nil } -func stackLoggingEnvVar() corev1.EnvVar { - return corev1.EnvVar{Name: esLogStyleEnvVarKey, Value: esLogStyleEnvVarValue} -} - func metricbeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (corev1.Container, error) { image, err := fullContainerImage(es, container.MetricbeatImage) if err != nil { diff --git a/pkg/controller/elasticsearch/stackmon/es_config.go b/pkg/controller/elasticsearch/stackmon/es_config.go index a3f954b160..2222ddb209 100644 --- a/pkg/controller/elasticsearch/stackmon/es_config.go +++ b/pkg/controller/elasticsearch/stackmon/es_config.go @@ -5,6 +5,8 @@ package stackmon import ( + corev1 "k8s.io/api/core/v1" + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" ) @@ -19,3 +21,8 @@ func MonitoringConfig(es esv1.Elasticsearch) commonv1.Config { esv1.XPackMonitoringElasticsearchCollectionEnabled: false, }} } + +// fileLogStyleEnvVar returns the environment variable to configure the Elasticsearch container to write logs to disk +func fileLogStyleEnvVar() corev1.EnvVar { + return corev1.EnvVar{Name: "ES_LOG_STYLE", Value: "file"} +} From 170f106e241e23f99b061a5b57a96f29c7078899 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:15:04 +0200 Subject: [PATCH 56/83] Adjust comments in filebeat.yml --- pkg/controller/elasticsearch/stackmon/filebeat.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/controller/elasticsearch/stackmon/filebeat.yml b/pkg/controller/elasticsearch/stackmon/filebeat.yml index f9d707024b..bb00d3b701 100644 --- a/pkg/controller/elasticsearch/stackmon/filebeat.yml +++ b/pkg/controller/elasticsearch/stackmon/filebeat.yml @@ -1,5 +1,5 @@ filebeat.modules: - # https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-elasticsearch.html + # https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-elasticsearch.html - module: elasticsearch server: enabled: true @@ -40,6 +40,7 @@ processors: - add_cloud_metadata: {} - add_host_metadata: {} +# only one target ES can be referenced so far so we take it as ordinal 0 output.elasticsearch: hosts: ['${ES_0_TARGET_URL}'] username: ${ES_0_TARGET_USERNAME} From 00042a63be6c74f33d46885f659c62136a2b2af2 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:21:51 +0200 Subject: [PATCH 57/83] Document TestEsStackMonitoring --- test/e2e/es/stack_monitoring_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/e2e/es/stack_monitoring_test.go b/test/e2e/es/stack_monitoring_test.go index f8c45be9e6..19e40f4267 100644 --- a/test/e2e/es/stack_monitoring_test.go +++ b/test/e2e/es/stack_monitoring_test.go @@ -19,15 +19,18 @@ import ( "github.com/elastic/cloud-on-k8s/test/e2e/test/elasticsearch" ) -// TestStackMonitoring -func TestStackMonitoring(t *testing.T) { +// TestESStackMonitoring tests that when an Elasticsearch cluster is configured with monitoring, its log and metrics are +// correctly delivered to the referenced monitoring Elasticsearch clusters. +// It tests that the monitored ES pods have 3 containers ready and that there are documents indexed in the beat indexes +// of the monitoring Elasticsearch clusters. +func TestESStackMonitoring(t *testing.T) { // only execute this test on supported version err := stackmon.IsSupportedVersion(test.Ctx().ElasticStackVersion) if err != nil { t.SkipNow() } - // Create 1 monitored and 2 monitoring clusters to collect separately metrics and logs + // create 1 monitored and 2 monitoring clusters to collect separately metrics and logs metrics := elasticsearch.NewBuilder("test-es-mon-metrics"). WithESMasterDataNodes(2, elasticsearch.DefaultResources) logs := elasticsearch.NewBuilder("test-es-mon-logs"). @@ -36,7 +39,7 @@ func TestStackMonitoring(t *testing.T) { WithESMasterDataNodes(1, elasticsearch.DefaultResources). WithMonitoring(metrics.Ref(), logs.Ref()) - // Checks that the beats have sent data in the monitoring clusters + // checks that the sidecar beats have sent data in the monitoring clusters steps := func(k *test.K8sClient) test.StepList { checks := stackMonitoringChecks{metrics, logs, k} return test.StepList{ From f6975f35ef9afcb971db986b5d12a36b076ed98a Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:22:16 +0200 Subject: [PATCH 58/83] Add CheckBeatSidecars to TestESStackMonitoring --- test/e2e/es/stack_monitoring_test.go | 31 ++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/test/e2e/es/stack_monitoring_test.go b/test/e2e/es/stack_monitoring_test.go index 19e40f4267..9cd707cd02 100644 --- a/test/e2e/es/stack_monitoring_test.go +++ b/test/e2e/es/stack_monitoring_test.go @@ -15,6 +15,7 @@ import ( esClient "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/client" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" "github.com/elastic/cloud-on-k8s/test/e2e/test" "github.com/elastic/cloud-on-k8s/test/e2e/test/elasticsearch" ) @@ -41,8 +42,9 @@ func TestESStackMonitoring(t *testing.T) { // checks that the sidecar beats have sent data in the monitoring clusters steps := func(k *test.K8sClient) test.StepList { - checks := stackMonitoringChecks{metrics, logs, k} + checks := stackMonitoringChecks{monitored, metrics, logs, k} return test.StepList{ + checks.CheckBeatSidecars(), checks.CheckMetricbeatIndex(), checks.CheckFilebeatIndex(), } @@ -52,9 +54,30 @@ func TestESStackMonitoring(t *testing.T) { } type stackMonitoringChecks struct { - metrics elasticsearch.Builder - logs elasticsearch.Builder - k *test.K8sClient + monitored elasticsearch.Builder + metrics elasticsearch.Builder + logs elasticsearch.Builder + k *test.K8sClient +} + +func (c *stackMonitoringChecks) CheckBeatSidecars() test.Step { + return test.Step{ + Name: "Check that beat sidecars are running", + Test: test.Eventually(func() error { + pods, err := c.k.GetPods(test.ESPodListOptions(c.monitored.Elasticsearch.Namespace, c.monitored.Elasticsearch.Name)...) + if err != nil { + return err + } + for _, pod := range pods { + if len(pod.Spec.Containers) != 3 { + return fmt.Errorf("expected %d containers, got %d", 3, len(pod.Spec.Containers)) + } + if !k8s.IsPodReady(pod) { + return fmt.Errorf("pod %s not ready", pod.Name) + } + } + return nil + })} } func (c *stackMonitoringChecks) CheckMetricbeatIndex() test.Step { From cf5c596591598f73916b54b98323e7483fae63f5 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 13:13:23 +0200 Subject: [PATCH 59/83] Revert fullContainerImage --- .../elasticsearch/stackmon/container.go | 52 ++------------ .../elasticsearch/stackmon/container_test.go | 68 ------------------- 2 files changed, 7 insertions(+), 113 deletions(-) delete mode 100644 pkg/controller/elasticsearch/stackmon/container_test.go diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 4833000287..93e1373553 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -5,9 +5,7 @@ package stackmon import ( - "errors" "path/filepath" - "strings" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/common/container" @@ -66,11 +64,7 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) volumeLikes = append(volumeLikes, metricbeatVolumes...) // Inject Metricbeat sidecar container - metricbeat, err := metricbeatContainer(es, metricbeatVolumes) - if err != nil { - return nil, err - } - builder.WithContainers(metricbeat) + builder.WithContainers(metricbeatContainer(es, metricbeatVolumes)) } if IsMonitoringLogsDefined(es) { @@ -84,11 +78,7 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) volumeLikes = append(volumeLikes, filebeatVolumes...) // Inject Filebeat sidecar container - filebeat, err := filebeatContainer(es, filebeatVolumes) - if err != nil { - return nil, err - } - builder.WithContainers(filebeat) + builder.WithContainers(filebeatContainer(es, filebeatVolumes)) } // Inject volumes @@ -101,12 +91,7 @@ func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) return builder, nil } -func metricbeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (corev1.Container, error) { - image, err := fullContainerImage(es, container.MetricbeatImage) - if err != nil { - return corev1.Container{}, err - } - +func metricbeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) corev1.Container { volumeMounts := make([]corev1.VolumeMount, 0) for _, v := range volumes { volumeMounts = append(volumeMounts, v.VolumeMount()) @@ -116,19 +101,14 @@ func metricbeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (co return corev1.Container{ Name: metricbeatContainerName, - Image: image, + Image: container.ImageRepository(container.MetricbeatImage, es.Spec.Version), Args: []string{"-c", filepath.Join(metricbeatConfigDirMountPath, metricbeatConfigKey), "-e"}, Env: append(envVars, defaults.PodDownwardEnvVars()...), VolumeMounts: volumeMounts, - }, nil -} - -func filebeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (corev1.Container, error) { - image, err := fullContainerImage(es, container.FilebeatImage) - if err != nil { - return corev1.Container{}, err } +} +func filebeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) corev1.Container { volumeMounts := []corev1.VolumeMount{ esvolume.DefaultLogsVolumeMount, // mount Elasticsearch logs volume into the Filebeat container } @@ -140,27 +120,9 @@ func filebeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) (core return corev1.Container{ Name: filebeatContainerName, - Image: image, + Image: container.ImageRepository(container.FilebeatImage, es.Spec.Version), Args: []string{"-c", filepath.Join(filebeatConfigDirMountPath, filebeatConfigKey), "-e"}, Env: append(envVars, defaults.PodDownwardEnvVars()...), VolumeMounts: volumeMounts, - }, nil -} - -// fullContainerImage returns the full Beat container image with the image registry. -// If the Elasticsearch specification is configured with a custom image, we do best effort by trying to derive the Beat -// image from the Elasticsearch custom image with an image name replacement -// (/elasticsearch/elasticsearch: becomes /beats/:) -func fullContainerImage(es esv1.Elasticsearch, defaultImage container.Image) (string, error) { - fullCustomImage := es.Spec.Image - if fullCustomImage != "" { - esImage := string(container.ElasticsearchImage) - // Check if Elasticsearch image follows official Elastic naming - if strings.Contains(fullCustomImage, esImage) { - // Derive the Beat image from the ES custom image, there is no guarantee that the resulted image exists - return strings.ReplaceAll(fullCustomImage, esImage, string(defaultImage)), nil - } - return "", errors.New("stack monitoring not supported with custom image") } - return container.ImageRepository(defaultImage, es.Spec.Version), nil } diff --git a/pkg/controller/elasticsearch/stackmon/container_test.go b/pkg/controller/elasticsearch/stackmon/container_test.go deleted file mode 100644 index 28aaff66ca..0000000000 --- a/pkg/controller/elasticsearch/stackmon/container_test.go +++ /dev/null @@ -1,68 +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; -// you may not use this file except in compliance with the Elastic License. - -package stackmon - -import ( - "errors" - "testing" - - esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/container" - "github.com/stretchr/testify/require" -) - -func TestFullContainerImage(t *testing.T) { - tests := []struct { - name string - es esv1.Elasticsearch - defaultImage container.Image - fullImage string - err error - }{ - { - name: "with default Elasticsearch image", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Version: "7.14.1", - }, - }, - defaultImage: "beats/filebeat", - fullImage: "docker.elastic.co/beats/filebeat:7.14.1", - }, - { - name: "with custom Elasticsearch image", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Image: "my.registry.space/elasticsearch/elasticsearch:7.15.0", - }, - }, - defaultImage: "beats/metricbeat", - fullImage: "my.registry.space/beats/metricbeat:7.15.0", - }, - { - name: "with custom Elasticsearch image that doesn't follow the Elastic scheme", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Image: "my.registry.space/es/es:7.14.0", - }, - }, - defaultImage: "beats/filebeat", - err: errors.New("stack monitoring not supported with custom image"), - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - image, err := fullContainerImage(tc.es, tc.defaultImage) - - if err != nil { - require.Error(t, tc.err) - require.Equal(t, tc.err, err) - } else { - require.Equal(t, tc.fullImage, image) - } - }) - } -} From 742fe9f154b3e403a5e8ec39e00b0b6dfe3f1f06 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 14:10:21 +0200 Subject: [PATCH 60/83] Unit tests for Validate --- .../elasticsearch/stackmon/container.go | 10 +- .../elasticsearch/stackmon/validations.go | 2 +- .../stackmon/validations_test.go | 107 ++++++++++++++++++ 3 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 pkg/controller/elasticsearch/stackmon/validations_test.go diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 93e1373553..af2a44337d 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -23,10 +23,6 @@ const ( filebeatConfigKey = "filebeat.yml" ) -func IsStackMonitoringDefined(es esv1.Elasticsearch) bool { - return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) -} - func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { for _, ref := range es.Spec.Monitoring.Metrics.ElasticsearchRefs { if !ref.IsDefined() { @@ -45,11 +41,15 @@ func IsMonitoringLogsDefined(es esv1.Elasticsearch) bool { return len(es.Spec.Monitoring.Logs.ElasticsearchRefs) > 0 } +func isStackMonitoringDefined(es esv1.Elasticsearch) bool { + return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) +} + // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers // in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { // No monitoring defined, skip - if !IsStackMonitoringDefined(es) { + if !isStackMonitoringDefined(es) { return builder, nil } diff --git a/pkg/controller/elasticsearch/stackmon/validations.go b/pkg/controller/elasticsearch/stackmon/validations.go index c6c080d3d6..07d1a0da47 100644 --- a/pkg/controller/elasticsearch/stackmon/validations.go +++ b/pkg/controller/elasticsearch/stackmon/validations.go @@ -28,7 +28,7 @@ var ( // Validate validates that the Elasticsearch version is supported for Stack Monitoring and that there is exactly one // Elasticsearch reference defined when Stack Monitoring is defined func Validate(es esv1.Elasticsearch) field.ErrorList { - if IsStackMonitoringDefined(es) { + if isStackMonitoringDefined(es) { err := IsSupportedVersion(es.Spec.Version) if err != nil { return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, diff --git a/pkg/controller/elasticsearch/stackmon/validations_test.go b/pkg/controller/elasticsearch/stackmon/validations_test.go new file mode 100644 index 0000000000..daea468297 --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/validations_test.go @@ -0,0 +1,107 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "testing" + + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + "github.com/stretchr/testify/require" +) + +func TestValidate(t *testing.T) { + tests := []struct { + name string + es esv1.Elasticsearch + isErr bool + }{ + { + name: "without monitoring", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.13.1", + }, + }, + isErr: false, + }, + { + name: "with monitoring", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.0", + Monitoring: esv1.Monitoring{ + Metrics: esv1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + Logs: esv1.LogsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + }, + }, + }, + isErr: false, + }, + { + name: "with not supported version", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.13.1", + Monitoring: esv1.Monitoring{ + Metrics: esv1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + }, + }, + }, + isErr: true, + }, + { + name: "with not only one elasticsearch ref for metrics", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.0", + Monitoring: esv1.Monitoring{ + Metrics: esv1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + {Name: "m1", Namespace: "b"}, + {Name: "m2", Namespace: "c"}, + }, + }, + }, + }, + }, + isErr: true, + }, + { + name: "with not only one elasticsearch ref for logs", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.0", + Monitoring: esv1.Monitoring{ + Logs: esv1.LogsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{ + {Name: "m1", Namespace: "b"}, + {Name: "m2", Namespace: "c"}, + }, + }, + }, + }, + }, + isErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := Validate(tc.es) + if len(err) > 0 { + require.True(t, tc.isErr) + } else { + require.False(t, tc.isErr) + } + }) + } +} From d45f5a2bfd2d2bb7d2a94659b74a2097b9364dac Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 14:11:10 +0200 Subject: [PATCH 61/83] Unit tests for WithMonitoring --- .../elasticsearch/stackmon/container_test.go | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 pkg/controller/elasticsearch/stackmon/container_test.go diff --git a/pkg/controller/elasticsearch/stackmon/container_test.go b/pkg/controller/elasticsearch/stackmon/container_test.go new file mode 100644 index 0000000000..e4dd247c7a --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/container_test.go @@ -0,0 +1,135 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "testing" + + 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/defaults" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" +) + +func TestWithMonitoring(t *testing.T) { + tests := []struct { + name string + es esv1.Elasticsearch + containersLength int + esEnvVarsLength int + podVolumesLength int + beatVolumeMountsLength int + }{ + { + name: "without monitoring", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.1", + }, + }, + containersLength: 1, + }, + { + name: "with metrics monitoring", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.1", + Monitoring: esv1.Monitoring{ + Metrics: esv1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + }, + }, + }, + containersLength: 2, + esEnvVarsLength: 0, + podVolumesLength: 3, + beatVolumeMountsLength: 3, + }, + { + name: "with logs monitoring", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.1", + Monitoring: esv1.Monitoring{ + Logs: esv1.LogsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + }, + }, + }, + containersLength: 2, + esEnvVarsLength: 1, + podVolumesLength: 2, + beatVolumeMountsLength: 3, + }, + { + name: "with metrics and logs monitoring", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.1", + Monitoring: esv1.Monitoring{ + Metrics: esv1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + Logs: esv1.LogsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + }, + }, + }, + containersLength: 3, + esEnvVarsLength: 1, + podVolumesLength: 5, + beatVolumeMountsLength: 3, + }, + { + name: "with metrics and logs monitoring with different es ref", + es: esv1.Elasticsearch{ + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.1", + Monitoring: esv1.Monitoring{ + Metrics: esv1.MetricsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, + }, + Logs: esv1.LogsMonitoring{ + ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m2", Namespace: "c"}}, + }, + }, + }, + }, + containersLength: 3, + esEnvVarsLength: 1, + podVolumesLength: 5, + beatVolumeMountsLength: 3, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + builder := defaults.NewPodTemplateBuilder(corev1.PodTemplateSpec{}, esv1.ElasticsearchContainerName) + builder, err := WithMonitoring(builder, tc.es) + assert.NoError(t, err) + assert.Equal(t, tc.containersLength, len(builder.PodTemplate.Spec.Containers)) + assert.Equal(t, tc.esEnvVarsLength, len(builder.PodTemplate.Spec.Containers[0].Env)) + assert.Equal(t, tc.podVolumesLength, len(builder.PodTemplate.Spec.Volumes)) + if IsMonitoringMetricsDefined(tc.es) { + for _, c := range builder.PodTemplate.Spec.Containers { + if c.Name == "metricbeat" { + assert.Equal(t, tc.beatVolumeMountsLength, len(c.VolumeMounts)) + } + } + } + if IsMonitoringLogsDefined(tc.es) { + for _, c := range builder.PodTemplate.Spec.Containers { + if c.Name == "filebeat" { + assert.Equal(t, tc.beatVolumeMountsLength, len(c.VolumeMounts)) + } + } + } + }) + } +} From 05dcd977b6d6246dd97c8137cea816cb09cf620f Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 15:29:35 +0200 Subject: [PATCH 62/83] Remove useless health=green query param --- test/e2e/es/stack_monitoring_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/es/stack_monitoring_test.go b/test/e2e/es/stack_monitoring_test.go index 9cd707cd02..cf9c9b2875 100644 --- a/test/e2e/es/stack_monitoring_test.go +++ b/test/e2e/es/stack_monitoring_test.go @@ -119,7 +119,7 @@ type Index struct { } func AreIndexedDocs(esClient esClient.Client, indexPattern string) error { - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/_cat/indices/%s?health=green&format=json", indexPattern), nil) //nolint:noctx + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/_cat/indices/%s?format=json", indexPattern), nil) //nolint:noctx if err != nil { return err } From 12f3bd44139a2626d03d28e5577c967f4016cfb8 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 15:28:57 +0200 Subject: [PATCH 63/83] Unit test TestPodTemplateBuilder_WithContainers --- .../common/defaults/pod_template_test.go | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/pkg/controller/common/defaults/pod_template_test.go b/pkg/controller/common/defaults/pod_template_test.go index 1fa156f099..ad1bf53848 100644 --- a/pkg/controller/common/defaults/pod_template_test.go +++ b/pkg/controller/common/defaults/pod_template_test.go @@ -1161,3 +1161,50 @@ func TestPodTemplateBuilder_WithPreStopHook(t *testing.T) { }) } } + +func TestPodTemplateBuilder_WithContainers(t *testing.T) { + tests := []struct { + name string + PodTemplate corev1.PodTemplateSpec + containerName string + container corev1.Container + postWithContainers func(*PodTemplateBuilder) + want corev1.PodTemplateSpec + }{ + { + name: "add an additional container then configure the main container", + PodTemplate: corev1.PodTemplateSpec{}, + containerName: "maincontainer", + container: corev1.Container{ + Name: "sidecar", + }, + postWithContainers: func(b *PodTemplateBuilder) { + b.WithEnv(corev1.EnvVar{Name: "USERNAME", Value: "elastic"}) + }, + want: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + AutomountServiceAccountToken: &varFalse, + Containers: []corev1.Container{ + { + Name: "maincontainer", + Env: []corev1.EnvVar{{Name: "USERNAME", Value: "elastic"}}, + }, + { + Name: "sidecar", + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := NewPodTemplateBuilder(tt.PodTemplate, tt.containerName) + b.WithContainers(tt.container) + tt.postWithContainers(b) + if got := b.PodTemplate; !reflect.DeepEqual(got, tt.want) { + t.Errorf("PodTemplateBuilder.WithContainers() = %v, want %v", got, tt.want) + } + }) + } +} From 8e72f7c6ba6b0ae76cfe6237e611112e37a114ff Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 24 Jun 2021 17:19:43 +0200 Subject: [PATCH 64/83] Support container override with pod template --- .../common/defaults/pod_template.go | 17 ++++++++- .../common/defaults/pod_template_test.go | 38 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/pkg/controller/common/defaults/pod_template.go b/pkg/controller/common/defaults/pod_template.go index 5771b310ce..af2c5d2ef2 100644 --- a/pkg/controller/common/defaults/pod_template.go +++ b/pkg/controller/common/defaults/pod_template.go @@ -188,8 +188,21 @@ func (b *PodTemplateBuilder) WithTerminationGracePeriod(period int64) *PodTempla // It also ensures that the base container defaulter still points to the container in the list because append() // creates a new slice. func (b *PodTemplateBuilder) WithContainers(containers ...corev1.Container) *PodTemplateBuilder { - b.PodTemplate.Spec.Containers = append(b.PodTemplate.Spec.Containers, containers...) - b.setContainerDefaulter() + for _, c := range containers { + found := false + for i := range b.PodTemplate.Spec.Containers { + podTplContainer := b.PodTemplate.Spec.Containers[i] + if c.Name == podTplContainer.Name { + found = true + // inherits default values from container already defined on the pod template + b.PodTemplate.Spec.Containers[i] = container.NewDefaulter(&podTplContainer).From(c).Container() + } + } + if !found { + b.PodTemplate.Spec.Containers = append(b.PodTemplate.Spec.Containers, c) + b.setContainerDefaulter() + } + } return b } diff --git a/pkg/controller/common/defaults/pod_template_test.go b/pkg/controller/common/defaults/pod_template_test.go index ad1bf53848..f3f245802f 100644 --- a/pkg/controller/common/defaults/pod_template_test.go +++ b/pkg/controller/common/defaults/pod_template_test.go @@ -1196,6 +1196,44 @@ func TestPodTemplateBuilder_WithContainers(t *testing.T) { }, }, }, + { + name: "override additional container using pod template", + PodTemplate: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + AutomountServiceAccountToken: &varFalse, + Containers: []corev1.Container{ + { + Name: "maincontainer", + }, + { + Name: "sidecar", + Image: "registry.space/blurb/sidecar:1.0", + }, + }, + }, + }, + containerName: "maincontainer", + container: corev1.Container{ + Name: "sidecar", + Image: "docker.elastic.co/elastic/metricbeat:7.14.0", + }, + postWithContainers: func(builder *PodTemplateBuilder) { + }, + want: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + AutomountServiceAccountToken: &varFalse, + Containers: []corev1.Container{ + { + Name: "maincontainer", + }, + { + Name: "sidecar", + Image: "registry.space/blurb/sidecar:1.0", + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 2f5b7963bcecb56dbad0ca04cc08840cbdc656c9 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 1 Jul 2021 10:30:51 +0200 Subject: [PATCH 65/83] common/stackmon package --- pkg/controller/common/stackmon/beat.go | 91 +++++++++++ pkg/controller/common/stackmon/beat_config.go | 146 ++++++++++++++++++ pkg/controller/common/stackmon/monitoring.go | 19 +++ 3 files changed, 256 insertions(+) create mode 100644 pkg/controller/common/stackmon/beat.go create mode 100644 pkg/controller/common/stackmon/beat_config.go create mode 100644 pkg/controller/common/stackmon/monitoring.go diff --git a/pkg/controller/common/stackmon/beat.go b/pkg/controller/common/stackmon/beat.go new file mode 100644 index 0000000000..ee937d2e88 --- /dev/null +++ b/pkg/controller/common/stackmon/beat.go @@ -0,0 +1,91 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "hash" + + corev1 "k8s.io/api/core/v1" + + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/container" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/defaults" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" +) + +func NewMetricbeatBuilder(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatBuilder, error) { + return NewBeatBuilder(client, "metricbeat", container.MetricbeatImage, resource, + resource.GetMonitoringMetricsAssociation(), baseConfig, additionalVolume) +} + +func NewFilebeatBuilder(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatBuilder, error) { + return NewBeatBuilder(client, "filebeat", container.FilebeatImage, resource, + resource.GetMonitoringLogsAssociation(), baseConfig, additionalVolume) +} + +// BeatBuilder helps with building a beat sidecar container to monitor an Elastic Stack application. It focuses on +// building the container, the secret holding the configuration file and the associated volumes for the pod. +type BeatBuilder struct { + container corev1.Container + configHash hash.Hash + configSecret corev1.Secret + volumes []volume.VolumeLike +} + +func NewBeatBuilder(client k8s.Client, beatName string, image container.Image, resource HasMonitoring, + associations []commonv1.Association, baseConfig string, additionalVolume volume.VolumeLike, +) (BeatBuilder, error) { + // build the beat config + config, err := newBeatConfig(client, beatName, resource, associations, baseConfig) + if err != nil { + return BeatBuilder{}, err + } + + // add additional volume (ex: CA volume of the monitored ES for Metricbeat) + volumes := config.volumes + if additionalVolume != nil { + volumes = append(volumes, additionalVolume) + } + + // prepare the volume mounts for the beat container from all provided volumes + volumeMounts := make([]corev1.VolumeMount, len(volumes)) + for i, v := range volumes { + volumeMounts[i] = v.VolumeMount() + } + + return BeatBuilder{ + container: corev1.Container{ + Name: beatName, + Image: container.ImageRepository(image, resource.Version()), + Args: []string{"-c", config.filepath, "-e"}, + Env: defaults.PodDownwardEnvVars(), + VolumeMounts: volumeMounts, + }, + configHash: config.hash, + configSecret: config.secret, + volumes: volumes, + }, nil +} + +func (b BeatBuilder) Container() corev1.Container { + return b.container +} + +func (b BeatBuilder) ConfigHash() []byte { + return b.configHash.Sum(nil) +} + +func (b BeatBuilder) ConfigSecret() corev1.Secret { + return b.configSecret +} + +func (b BeatBuilder) Volumes() []corev1.Volume { + volumes := make([]corev1.Volume, 0) + for _, v := range b.volumes { + volumes = append(volumes, v.Volume()) + } + return volumes +} diff --git a/pkg/controller/common/stackmon/beat_config.go b/pkg/controller/common/stackmon/beat_config.go new file mode 100644 index 0000000000..14619fbd79 --- /dev/null +++ b/pkg/controller/common/stackmon/beat_config.go @@ -0,0 +1,146 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "crypto/sha256" + "fmt" + "hash" + "path/filepath" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + commonv1 "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/certificates" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/settings" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" +) + +// beatConfig helps to create a beat configuration +type beatConfig struct { + filepath string + hash hash.Hash + secret corev1.Secret + volumes []volume.VolumeLike +} + +func newBeatConfig(client k8s.Client, beatName string, resource HasMonitoring, associations []commonv1.Association, baseConfig string) (beatConfig, error) { + if len(associations) != 1 { + // should never happen because of the pre-creation validation + return beatConfig{}, errors.New("only one Elasticsearch reference is supported for Stack Monitoring") + } + assoc := associations[0] + + // build the output section of the beat configuration file + outputCfg, caVolume, err := buildOutputConfig(client, assoc) + if err != nil { + return beatConfig{}, err + } + outputConfig := map[string]interface{}{ + "output": map[string]interface{}{ + "elasticsearch": outputCfg, + }, + } + + // name for the config secret and the associated config volume for the es pod + configName := fmt.Sprintf("%s-%s-%s-config", resource.NSN().Name, resource.ShortKind(), beatName) + configFilename := fmt.Sprintf("%s.yml", beatName) + configDirPath := fmt.Sprintf("/etc/%s-config", beatName) + + // add the config volume + configVolume := volume.NewSecretVolumeWithMountPath(configName, configName, configDirPath) + configFilepath := filepath.Join(configDirPath, configFilename) + volumes := []volume.VolumeLike{configVolume} + + // add the CA volume + if caVolume != nil { + volumes = append(volumes, caVolume) + } + + // merge the base config with the generated part + configBytes, err := mergeConfig(baseConfig, outputConfig) + if err != nil { + return beatConfig{}, err + } + + configHash := sha256.New224() + configHash.Write(configBytes) + + configSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: configName, + Namespace: resource.NSN().Namespace, + Labels: label.NewLabels(resource.NSN()), + }, + Data: map[string][]byte{ + configFilename: configBytes, + }, + } + + return beatConfig{ + filepath: configFilepath, + hash: configHash, + secret: configSecret, + volumes: volumes, + }, err +} + +func buildOutputConfig(client k8s.Client, assoc commonv1.Association) (map[string]interface{}, volume.VolumeLike, error) { + username, password, err := association.ElasticsearchAuthSettings(client, assoc) + if err != nil { + return nil, volume.SecretVolume{}, err + } + + outputConfig := map[string]interface{}{ + "username": username, + "password": password, + "hosts": []string{assoc.AssociationConf().GetURL()}, + } + + caDirPath := fmt.Sprintf( + "/mnt/elastic-internal/%s-association/%s/%s/certs", + assoc.AssociationType(), assoc.AssociationRef().Namespace, assoc.AssociationRef().Name, + ) + + var caVolume volume.VolumeLike + if assoc.AssociationConf().GetCACertProvided() { + sslCAPath := filepath.Join(caDirPath, certificates.CAFileName) + outputConfig["ssl.certificate_authorities"] = []string{sslCAPath} + caVolume = volume.NewSecretVolumeWithMountPath( + assoc.AssociationConf().GetCASecretName(), assoc.AssociationConf().GetCASecretName(), caDirPath, + ) + } + + return outputConfig, caVolume, nil +} + +func mergeConfig(rawConfig string, config map[string]interface{}) ([]byte, error) { + cfg, err := settings.ParseConfig([]byte(rawConfig)) + if err != nil { + return nil, err + } + + outputCfg, err := settings.NewCanonicalConfigFrom(config) + if err != nil { + return nil, err + } + + err = cfg.MergeWith(outputCfg) + if err != nil { + return nil, err + } + + cfgBytes, err := cfg.Render() + if err != nil { + return nil, err + } + + return cfgBytes, nil +} diff --git a/pkg/controller/common/stackmon/monitoring.go b/pkg/controller/common/stackmon/monitoring.go new file mode 100644 index 0000000000..44b31c43fa --- /dev/null +++ b/pkg/controller/common/stackmon/monitoring.go @@ -0,0 +1,19 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + "k8s.io/apimachinery/pkg/types" +) + +// HasMonitoring is the interface implemented by an Elastic Stack application that supports Stack Monitoring () +type HasMonitoring interface { + GetMonitoringMetricsAssociation() []commonv1.Association + GetMonitoringLogsAssociation() []commonv1.Association + NSN() types.NamespacedName + ShortKind() string + Version() string +} From a9584a21cd3c3db32704181372f1d12b4d7f7021 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 1 Jul 2021 10:31:36 +0200 Subject: [PATCH 66/83] ES impl for HasMonitoring --- .../elasticsearch/v1/elasticsearch_types.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 61a8129ded..1cac67c226 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -20,7 +20,8 @@ const ( ElasticsearchContainerName = "elasticsearch" // Kind is inferred from the struct name using reflection in SchemeBuilder.Register() // we duplicate it as a constant here for practical purposes. - Kind = "Elasticsearch" + Kind = "Elasticsearch" + ShortKind = "es" ) // ElasticsearchSpec holds the specification of an Elasticsearch cluster. @@ -239,6 +240,20 @@ func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, s return nil } +// HasMonitoring methods + +func (es *Elasticsearch) NSN() types.NamespacedName { + return types.NamespacedName{Name: es.Name, Namespace: es.Namespace} +} + +func (es *Elasticsearch) ShortKind() string { + return ShortKind +} + +func (es *Elasticsearch) Version() string { + return es.Spec.Version +} + // VolumeClaimDeletePolicy describes the delete policy for handling PersistentVolumeClaims that hold Elasticsearch data. // Inspired by https://github.com/kubernetes/enhancements/pull/2440 type VolumeClaimDeletePolicy string From e60c0d9812e312b6c87c3fe713d58486e21614d3 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 1 Jul 2021 10:36:32 +0200 Subject: [PATCH 67/83] Refactoring of elasticsearch/stackmon --- pkg/controller/elasticsearch/driver/nodes.go | 2 +- .../elasticsearch/nodespec/podspec.go | 3 +- .../elasticsearch/nodespec/podspec_test.go | 6 +- .../elasticsearch/nodespec/resources.go | 4 +- .../elasticsearch/nodespec/statefulset.go | 3 +- .../elasticsearch/stackmon/beat_config.go | 139 ++++++++---------- .../elasticsearch/stackmon/container.go | 134 ++++++++--------- .../elasticsearch/stackmon/container_test.go | 137 ++++++++++------- .../elasticsearch/stackmon/filebeat.yml | 7 +- .../elasticsearch/stackmon/metricbeat.tpl.yml | 28 ++++ .../elasticsearch/stackmon/metricbeat.yml | 29 ---- .../elasticsearch/stackmon/validations.go | 2 +- .../stackmon/validations_test.go | 3 +- .../elasticsearch/stackmon/volume.go | 81 ---------- .../elasticsearch/user/predefined.go | 16 ++ pkg/controller/elasticsearch/user/roles.go | 2 +- 16 files changed, 268 insertions(+), 328 deletions(-) create mode 100644 pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml delete mode 100644 pkg/controller/elasticsearch/stackmon/metricbeat.yml delete mode 100644 pkg/controller/elasticsearch/stackmon/volume.go diff --git a/pkg/controller/elasticsearch/driver/nodes.go b/pkg/controller/elasticsearch/driver/nodes.go index 0feb4e852d..95096c3fd5 100644 --- a/pkg/controller/elasticsearch/driver/nodes.go +++ b/pkg/controller/elasticsearch/driver/nodes.go @@ -78,7 +78,7 @@ func (d *defaultDriver) reconcileNodeSpecs( return results.WithError(err) } - expectedResources, err := nodespec.BuildExpectedResources(d.ES, keystoreResources, actualStatefulSets, d.OperatorParameters.IPFamily, d.OperatorParameters.SetDefaultSecurityContext) + expectedResources, err := nodespec.BuildExpectedResources(d.Client, d.ES, keystoreResources, actualStatefulSets, d.OperatorParameters.IPFamily, d.OperatorParameters.SetDefaultSecurityContext) if err != nil { return results.WithError(err) } diff --git a/pkg/controller/elasticsearch/nodespec/podspec.go b/pkg/controller/elasticsearch/nodespec/podspec.go index 17917bd93b..25d04d3df9 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec.go +++ b/pkg/controller/elasticsearch/nodespec/podspec.go @@ -40,6 +40,7 @@ const defaultFsGroup = 1000 // BuildPodTemplateSpec builds a new PodTemplateSpec for an Elasticsearch node. func BuildPodTemplateSpec( + client k8s.Client, es esv1.Elasticsearch, nodeSet esv1.NodeSet, cfg settings.CanonicalConfig, @@ -91,7 +92,7 @@ func BuildPodTemplateSpec( WithInitContainerDefaults(corev1.EnvVar{Name: settings.HeadlessServiceName, Value: headlessServiceName}). WithPreStopHook(*NewPreStopHook()) - builder, err = stackmon.WithMonitoring(builder, es) + builder, err = stackmon.WithMonitoring(client, builder, es) if err != nil { return corev1.PodTemplateSpec{}, err } diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index e760c03ce9..281a4fa70b 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -14,7 +14,7 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/initcontainer" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/settings" - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/stackmon" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" "github.com/elastic/cloud-on-k8s/pkg/utils/pointer" "github.com/go-test/deep" "github.com/stretchr/testify/assert" @@ -168,7 +168,7 @@ func TestBuildPodTemplateSpecWithDefaultSecurityContext(t *testing.T) { cfg, err := settings.NewMergedESConfig(es.Name, tt.version, corev1.IPv4Protocol, es.Spec.HTTP, *es.Spec.NodeSets[0].Config, commonv1.Config{}) require.NoError(t, err) - actual, err := BuildPodTemplateSpec(es, es.Spec.NodeSets[0], cfg, nil, tt.setDefaultFSGroup) + actual, err := BuildPodTemplateSpec(k8s.NewFakeClient(), es, es.Spec.NodeSets[0], cfg, nil, tt.setDefaultFSGroup) require.NoError(t, err) require.Equal(t, tt.wantSecurityContext, actual.Spec.SecurityContext) }) @@ -182,7 +182,7 @@ func TestBuildPodTemplateSpec(t *testing.T) { cfg, err := settings.NewMergedESConfig(sampleES.Name, ver, corev1.IPv4Protocol, sampleES.Spec.HTTP, *nodeSet.Config, commonv1.Config{}) require.NoError(t, err) - actual, err := BuildPodTemplateSpec(sampleES, sampleES.Spec.NodeSets[0], cfg, nil, false) + actual, err := BuildPodTemplateSpec(k8s.NewFakeClient(), sampleES, sampleES.Spec.NodeSets[0], cfg, nil, false) require.NoError(t, err) // build expected PodTemplateSpec diff --git a/pkg/controller/elasticsearch/nodespec/resources.go b/pkg/controller/elasticsearch/nodespec/resources.go index 2cfc54f095..679d28eefb 100644 --- a/pkg/controller/elasticsearch/nodespec/resources.go +++ b/pkg/controller/elasticsearch/nodespec/resources.go @@ -5,6 +5,7 @@ package nodespec import ( + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -36,6 +37,7 @@ func (l ResourcesList) StatefulSets() sset.StatefulSetList { } func BuildExpectedResources( + client k8s.Client, es esv1.Elasticsearch, keystoreResources *keystore.Resources, existingStatefulSets sset.StatefulSetList, @@ -61,7 +63,7 @@ func BuildExpectedResources( } // build stateful set and associated headless service - statefulSet, err := BuildStatefulSet(es, nodeSpec, cfg, keystoreResources, existingStatefulSets, setDefaultSecurityContext) + statefulSet, err := BuildStatefulSet(client, es, nodeSpec, cfg, keystoreResources, existingStatefulSets, setDefaultSecurityContext) if err != nil { return nil, err } diff --git a/pkg/controller/elasticsearch/nodespec/statefulset.go b/pkg/controller/elasticsearch/nodespec/statefulset.go index f92c7f711c..cc3eef57ef 100644 --- a/pkg/controller/elasticsearch/nodespec/statefulset.go +++ b/pkg/controller/elasticsearch/nodespec/statefulset.go @@ -54,6 +54,7 @@ func HeadlessService(es *esv1.Elasticsearch, ssetName string) corev1.Service { } func BuildStatefulSet( + client k8s.Client, es esv1.Elasticsearch, nodeSet esv1.NodeSet, cfg settings.CanonicalConfig, @@ -74,7 +75,7 @@ func BuildStatefulSet( ) // build pod template - podTemplate, err := BuildPodTemplateSpec(es, nodeSet, cfg, keystoreResources, setDefaultSecurityContext) + podTemplate, err := BuildPodTemplateSpec(client, es, nodeSet, cfg, keystoreResources, setDefaultSecurityContext) if err != nil { return appsv1.StatefulSet{}, err } diff --git a/pkg/controller/elasticsearch/stackmon/beat_config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go index 6e03d57cce..329005cc93 100644 --- a/pkg/controller/elasticsearch/stackmon/beat_config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -5,116 +5,101 @@ package stackmon import ( + "bytes" _ "embed" // for the beats config files "fmt" + "path/filepath" + "text/template" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - 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/certificates" "github.com/elastic/cloud-on-k8s/pkg/controller/common/reconciler" - "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/network" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) -// Environments variables and paths to the Elasticsearch CA certificates used in the beats configuration to describe -// how to connect to Elasticsearch. -// Warning: environment variables and CA cert paths defined below are also used in the embedded files. var ( - esSourceURLEnvVarKey = "ES_SOURCE_URL" - esSourceURLEnvVarValue = "https://localhost:9200" - esSourceUsernameEnvVarKey = "ES_SOURCE_USERNAME" - esSourcePasswordEnvVarKey = "ES_SOURCE_PASSWORD" //nolint:gosec - - esTargetURLEnvVarKeyFormat = "ES_%d_TARGET_URL" - esTargetUsernameEnvVarKeyFormat = "ES_%d_TARGET_USERNAME" - esTargetPasswordEnvVarKeyFormat = "ES_%d_TARGET_PASSWORD" //nolint:gosec - - monitoringMetricsSourceEsCaCertMountPath = "/mnt/es/monitoring/metrics/source" - monitoringMetricsTargetEsCaCertMountPathFormat = "/mnt/es/monitoring/metrics/target/%d" - monitoringLogsTargetEsCaCertMountPathFormat = "/mnt/es/monitoring/logs/target/%d" - - // metricbeatConfig is a static configuration for Metricbeat to collect monitoring data about Elasticsearch - //go:embed metricbeat.yml - metricbeatConfig string + // metricbeatConfigTemplate is a configuration template for Metricbeat to collect monitoring data about Elasticsearch + //go:embed metricbeat.tpl.yml + metricbeatConfigTemplate string // filebeatConfig is a static configuration for Filebeat to collect Elasticsearch logs //go:embed filebeat.yml filebeatConfig string ) -// ReconcileConfigSecrets reconciles the secrets holding the beats configuration +// ReconcileConfigSecrets reconciles the secrets holding beats configuration func ReconcileConfigSecrets(client k8s.Client, es esv1.Elasticsearch) error { if IsMonitoringMetricsDefined(es) { - secret := beatConfigSecret(es, metricbeatConfigSecretName, metricbeatConfigKey, metricbeatConfig) - if _, err := reconciler.ReconcileSecret(client, secret, &es); err != nil { + b, err := MetricbeatBuilder(client, es) + if err != nil { + return err + } + + if _, err := reconciler.ReconcileSecret(client, b.ConfigSecret(), &es); err != nil { return err } } if IsMonitoringLogsDefined(es) { - secret := beatConfigSecret(es, filebeatConfigSecretName, filebeatConfigKey, filebeatConfig) - if _, err := reconciler.ReconcileSecret(client, secret, &es); err != nil { + b, err := FilebeatBuilder(client, es) + if err != nil { + return err + } + + if _, err := reconciler.ReconcileSecret(client, b.ConfigSecret(), &es); err != nil { return err } } + return nil } -// beatConfigSecret returns the data for a Secret holding a beat configuration -func beatConfigSecret( - es esv1.Elasticsearch, - secretNamer func(es esv1.Elasticsearch) string, - beatConfigKey string, - beatConfig string, -) corev1.Secret { - return corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretNamer(es), - Namespace: es.GetNamespace(), - Labels: label.NewLabels(k8s.ExtractNamespacedName(&es)), - }, - Data: map[string][]byte{ - beatConfigKey: []byte(beatConfig), - }, - } +// esConfigData holds data to configure the Metricbeat Elasticsearch module +type esConfigData struct { + URL string + Username string + Password string + IsSSL bool + SSLPath string + SSLMode string } -// monitoringSourceEnvVars returns the environment variables describing how to connect to the monitored Elasticsearch cluster -func monitoringSourceEnvVars(es esv1.Elasticsearch) []corev1.EnvVar { - return []corev1.EnvVar{ - {Name: esSourceURLEnvVarKey, Value: esSourceURLEnvVarValue}, - {Name: esSourceUsernameEnvVarKey, Value: user.ElasticUserName}, - {Name: esSourcePasswordEnvVarKey, ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: esv1.ElasticUserSecret(es.Name)}, - Key: user.ElasticUserName, - }, - }}, +// buildMetricbeatConfig builds the base Metricbeat config with the associated volume holding the CA of the monitored ES +func buildMetricbeatBaseConfig(client k8s.Client, es esv1.Elasticsearch) (string, volume.VolumeLike, error) { + password, err := user.GetElasticUserPassword(client, es) + if err != nil { + return "", nil, err + } + + configData := esConfigData{ + URL: fmt.Sprintf("%s://localhost:%d", es.Spec.HTTP.Protocol(), network.HTTPPort), + Username: user.MonitoringUserName, + Password: password, + IsSSL: es.Spec.HTTP.TLS.Enabled(), } -} -// monitoringTargetEnvVars returns the environment variables describing how to connect to Elasticsearch clusters -// referenced in the given associations -func monitoringTargetEnvVars(assocs []commonv1.Association) []corev1.EnvVar { - vars := make([]corev1.EnvVar, 0) - for i, assoc := range assocs { - assocConf := assoc.AssociationConf() - vars = append(vars, []corev1.EnvVar{ - {Name: fmt.Sprintf(esTargetURLEnvVarKeyFormat, i), Value: assocConf.GetURL()}, - {Name: fmt.Sprintf(esTargetUsernameEnvVarKeyFormat, i), Value: assocConf.GetAuthSecretKey()}, - {Name: fmt.Sprintf(esTargetPasswordEnvVarKeyFormat, i), ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: assocConf.GetAuthSecretName(), - }, - Key: assocConf.GetAuthSecretKey(), - }, - }}}..., + var caVolume volume.VolumeLike + if configData.IsSSL { + caVolume = volume.NewSecretVolumeWithMountPath( + certificates.PublicCertsSecretName(esv1.ESNamer, es.Name), + fmt.Sprintf("%s-%s-monitoring-local-ca", es.Name, es.ShortKind()), + fmt.Sprintf("/mnt/elastic-internal/es-monitoring/%s/%s/certs", es.Namespace, es.Name), ) + + configData.IsSSL = true + configData.SSLPath = filepath.Join(caVolume.VolumeMount().MountPath, certificates.CAFileName) + configData.SSLMode = "certificate" + } + + // render the config template with the config data + var metricbeatConfig bytes.Buffer + err = template.Must(template.New("").Parse(metricbeatConfigTemplate)).Execute(&metricbeatConfig, configData) + if err != nil { + return "", nil, err } - return vars + + return metricbeatConfig.String(), caVolume, nil } diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index af2a44337d..a9e036cf85 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -5,22 +5,22 @@ package stackmon import ( - "path/filepath" + "crypto/sha256" + "fmt" + + corev1 "k8s.io/api/core/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/defaults" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" + common "github.com/elastic/cloud-on-k8s/pkg/controller/common/stackmon" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" - corev1 "k8s.io/api/core/v1" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) const ( - metricbeatContainerName = "metricbeat" - filebeatContainerName = "filebeat" - - metricbeatConfigKey = "metricbeat.yml" - filebeatConfigKey = "filebeat.yml" + // cfgHashLabel is used to store a hash of the Metricbeat and Filebeat configurations. + // Using only one label for both configs to save labels. + cfgHashLabel = "elasticsearch.k8s.elastic.co/monitoring-config-hash" ) func IsMonitoringMetricsDefined(es esv1.Elasticsearch) bool { @@ -41,88 +41,78 @@ func IsMonitoringLogsDefined(es esv1.Elasticsearch) bool { return len(es.Spec.Monitoring.Logs.ElasticsearchRefs) > 0 } -func isStackMonitoringDefined(es esv1.Elasticsearch) bool { +func isMonitoringDefined(es esv1.Elasticsearch) bool { return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) } -// WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers -// in the Elasticsearch pod and injects volumes for Metricbeat/Filebeat configs and ES source/target CA certs. -func WithMonitoring(builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { - // No monitoring defined, skip - if !isStackMonitoringDefined(es) { - return builder, nil +func MetricbeatBuilder(client k8s.Client, es esv1.Elasticsearch) (common.BeatBuilder, error) { + metricbeatConfig, sourceEsCaVolume, err := buildMetricbeatBaseConfig(client, es) + if err != nil { + return common.BeatBuilder{}, err } - volumeLikes := make([]volume.VolumeLike, 0) - - if IsMonitoringMetricsDefined(es) { - metricbeatVolumes := append( - monitoringMetricsTargetCaCertSecretVolumes(es), - metricbeatConfigSecretVolume(es), - monitoringMetricsSourceCaCertSecretVolume(es), - ) - volumeLikes = append(volumeLikes, metricbeatVolumes...) - - // Inject Metricbeat sidecar container - builder.WithContainers(metricbeatContainer(es, metricbeatVolumes)) + metricbeatBuilder, err := common.NewMetricbeatBuilder(client, &es, metricbeatConfig, sourceEsCaVolume) + if err != nil { + return common.BeatBuilder{}, err } - if IsMonitoringLogsDefined(es) { - // Enable Stack logging to write Elasticsearch logs to disk - builder.WithEnv(fileLogStyleEnvVar()) + return metricbeatBuilder, nil +} + +func FilebeatBuilder(client k8s.Client, es esv1.Elasticsearch) (common.BeatBuilder, error) { + filebeatBuilder, err := common.NewFilebeatBuilder(client, &es, filebeatConfig, nil) + if err != nil { + return common.BeatBuilder{}, err + } - filebeatVolumes := append( - monitoringLogsTargetCaCertSecretVolumes(es), - filebeatConfigSecretVolume(es), - ) - volumeLikes = append(volumeLikes, filebeatVolumes...) + return filebeatBuilder, nil +} - // Inject Filebeat sidecar container - builder.WithContainers(filebeatContainer(es, filebeatVolumes)) +// WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers +// in the Elasticsearch pod and injects the volumes for the beat configurations and the ES CA certificates. +func WithMonitoring(client k8s.Client, builder *defaults.PodTemplateBuilder, es esv1.Elasticsearch) (*defaults.PodTemplateBuilder, error) { + // no monitoring defined, skip + if !isMonitoringDefined(es) { + return builder, nil } - // Inject volumes + configHash := sha256.New224() volumes := make([]corev1.Volume, 0) - for _, v := range volumeLikes { - volumes = append(volumes, v.Volume()) - } - builder.WithVolumes(volumes...) - return builder, nil -} + if IsMonitoringMetricsDefined(es) { + beatBuilder, err := MetricbeatBuilder(client, es) + if err != nil { + return nil, err + } -func metricbeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) corev1.Container { - volumeMounts := make([]corev1.VolumeMount, 0) - for _, v := range volumes { - volumeMounts = append(volumeMounts, v.VolumeMount()) + volumes = append(volumes, beatBuilder.Volumes()...) + builder.WithContainers(beatBuilder.Container()) + configHash.Write(beatBuilder.ConfigHash()) } - envVars := append(monitoringSourceEnvVars(es), monitoringTargetEnvVars(es.GetMonitoringMetricsAssociation())...) + if IsMonitoringLogsDefined(es) { + // enable Stack logging to write Elasticsearch logs to disk + builder.WithEnv(fileLogStyleEnvVar()) - return corev1.Container{ - Name: metricbeatContainerName, - Image: container.ImageRepository(container.MetricbeatImage, es.Spec.Version), - Args: []string{"-c", filepath.Join(metricbeatConfigDirMountPath, metricbeatConfigKey), "-e"}, - Env: append(envVars, defaults.PodDownwardEnvVars()...), - VolumeMounts: volumeMounts, - } -} + beatBuilder, err := FilebeatBuilder(client, es) + if err != nil { + return nil, err + } -func filebeatContainer(es esv1.Elasticsearch, volumes []volume.VolumeLike) corev1.Container { - volumeMounts := []corev1.VolumeMount{ - esvolume.DefaultLogsVolumeMount, // mount Elasticsearch logs volume into the Filebeat container - } - for _, v := range volumes { - volumeMounts = append(volumeMounts, v.VolumeMount()) - } + volumes = append(volumes, beatBuilder.Volumes()...) + filebeat := beatBuilder.Container() - envVars := monitoringTargetEnvVars(es.GetMonitoringLogsAssociation()) + // share the ES logs volume into the Filebeat container + filebeat.VolumeMounts = append(filebeat.VolumeMounts, esvolume.DefaultLogsVolumeMount) - return corev1.Container{ - Name: filebeatContainerName, - Image: container.ImageRepository(container.FilebeatImage, es.Spec.Version), - Args: []string{"-c", filepath.Join(filebeatConfigDirMountPath, filebeatConfigKey), "-e"}, - Env: append(envVars, defaults.PodDownwardEnvVars()...), - VolumeMounts: volumeMounts, + builder.WithContainers(filebeat) + configHash.Write(beatBuilder.ConfigHash()) } + + // add the config hash label to ensure pod rotation when an ES password or a CA are rotated + builder.WithLabels(map[string]string{cfgHashLabel: fmt.Sprintf("%x", configHash.Sum(nil))}) + // inject all volumes + builder.WithVolumes(volumes...) + + return builder, nil } diff --git a/pkg/controller/elasticsearch/stackmon/container_test.go b/pkg/controller/elasticsearch/stackmon/container_test.go index e4dd247c7a..68cee9bd86 100644 --- a/pkg/controller/elasticsearch/stackmon/container_test.go +++ b/pkg/controller/elasticsearch/stackmon/container_test.go @@ -7,17 +7,67 @@ package stackmon import ( "testing" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + 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/defaults" - "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" + "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) func TestWithMonitoring(t *testing.T) { + sampleEs := esv1.Elasticsearch{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + Namespace: "aerospace", + }, + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.0", + }, + } + monitoringEsRef := []commonv1.ObjectSelector{{Name: "monitoring", Namespace: "observability"}} + logsEsRef := []commonv1.ObjectSelector{{Name: "logs", Namespace: "observability"}} + + fakeElasticUserSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "sample-es-elastic-user", Namespace: "aerospace"}, + Data: map[string][]byte{"elastic": []byte("1234567890")}, + } + fakeMetricsBeatUserSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "sample-observability-monitoring-beat-es-mon-user", Namespace: "aerospace"}, + Data: map[string][]byte{"aerospace-sample-observability-monitoring-beat-es-mon-user": []byte("1234567890")}, + } + fakeLogsBeatUserSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "sample-observability-logs-beat-es-mon-user", Namespace: "aerospace"}, + Data: map[string][]byte{"aerospace-sample-observability-logs-beat-es-mon-user": []byte("1234567890")}, + } + fakeEsHTTPCertSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "sample-es-http-certs-public", Namespace: "aerospace"}, + Data: map[string][]byte{"ca.crt": []byte("7H1515N074r341C3r71F1C473")}, + } + fakeClient := k8s.NewFakeClient(&fakeElasticUserSecret, &fakeMetricsBeatUserSecret, &fakeLogsBeatUserSecret, &fakeEsHTTPCertSecret) + + monitoringAssocConf := commonv1.AssociationConf{ + AuthSecretName: "sample-observability-monitoring-beat-es-mon-user", + AuthSecretKey: "aerospace-sample-observability-monitoring-beat-es-mon-user", + CACertProvided: true, + CASecretName: "sample-es-monitoring-observability-monitoring-ca", + URL: "https://monitoring-es-http.observability.svc:9200", + Version: "7.14.0", + } + logsAssocConf := commonv1.AssociationConf{ + AuthSecretName: "sample-observability-logs-beat-es-mon-user", + AuthSecretKey: "aerospace-sample-observability-logs-beat-es-mon-user", + CACertProvided: true, + CASecretName: "sample-es-logs-observability-monitoring-ca", + URL: "https://logs-es-http.observability.svc:9200", + Version: "7.14.0", + } + tests := []struct { name string - es esv1.Elasticsearch + es func() esv1.Elasticsearch containersLength int esEnvVarsLength int podVolumesLength int @@ -25,24 +75,17 @@ func TestWithMonitoring(t *testing.T) { }{ { name: "without monitoring", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Version: "7.14.1", - }, + es: func() esv1.Elasticsearch { + return sampleEs }, containersLength: 1, }, { name: "with metrics monitoring", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Version: "7.14.1", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, - }, - }, - }, + es: func() esv1.Elasticsearch { + sampleEs.Spec.Monitoring.Metrics.ElasticsearchRefs = monitoringEsRef + sampleEs.GetMonitoringMetricsAssociation()[0].SetAssociationConf(&monitoringAssocConf) + return sampleEs }, containersLength: 2, esEnvVarsLength: 0, @@ -51,15 +94,11 @@ func TestWithMonitoring(t *testing.T) { }, { name: "with logs monitoring", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Version: "7.14.1", - Monitoring: esv1.Monitoring{ - Logs: esv1.LogsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, - }, - }, - }, + es: func() esv1.Elasticsearch { + sampleEs.Spec.Monitoring.Metrics.ElasticsearchRefs = nil + sampleEs.Spec.Monitoring.Logs.ElasticsearchRefs = monitoringEsRef + sampleEs.GetMonitoringLogsAssociation()[0].SetAssociationConf(&monitoringAssocConf) + return sampleEs }, containersLength: 2, esEnvVarsLength: 1, @@ -68,38 +107,26 @@ func TestWithMonitoring(t *testing.T) { }, { name: "with metrics and logs monitoring", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Version: "7.14.1", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, - }, - Logs: esv1.LogsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, - }, - }, - }, + es: func() esv1.Elasticsearch { + sampleEs.Spec.Monitoring.Metrics.ElasticsearchRefs = monitoringEsRef + sampleEs.GetMonitoringMetricsAssociation()[0].SetAssociationConf(&monitoringAssocConf) + sampleEs.Spec.Monitoring.Logs.ElasticsearchRefs = monitoringEsRef + sampleEs.GetMonitoringLogsAssociation()[0].SetAssociationConf(&monitoringAssocConf) + return sampleEs }, containersLength: 3, esEnvVarsLength: 1, - podVolumesLength: 5, + podVolumesLength: 4, beatVolumeMountsLength: 3, }, { name: "with metrics and logs monitoring with different es ref", - es: esv1.Elasticsearch{ - Spec: esv1.ElasticsearchSpec{ - Version: "7.14.1", - Monitoring: esv1.Monitoring{ - Metrics: esv1.MetricsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m1", Namespace: "b"}}, - }, - Logs: esv1.LogsMonitoring{ - ElasticsearchRefs: []commonv1.ObjectSelector{{Name: "m2", Namespace: "c"}}, - }, - }, - }, + es: func() esv1.Elasticsearch { + sampleEs.Spec.Monitoring.Metrics.ElasticsearchRefs = monitoringEsRef + sampleEs.GetMonitoringMetricsAssociation()[0].SetAssociationConf(&monitoringAssocConf) + sampleEs.Spec.Monitoring.Logs.ElasticsearchRefs = logsEsRef + sampleEs.GetMonitoringLogsAssociation()[0].SetAssociationConf(&logsAssocConf) + return sampleEs }, containersLength: 3, esEnvVarsLength: 1, @@ -110,20 +137,24 @@ func TestWithMonitoring(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { + es := tc.es() builder := defaults.NewPodTemplateBuilder(corev1.PodTemplateSpec{}, esv1.ElasticsearchContainerName) - builder, err := WithMonitoring(builder, tc.es) + _, err := WithMonitoring(fakeClient, builder, es) assert.NoError(t, err) + assert.Equal(t, tc.containersLength, len(builder.PodTemplate.Spec.Containers)) assert.Equal(t, tc.esEnvVarsLength, len(builder.PodTemplate.Spec.Containers[0].Env)) assert.Equal(t, tc.podVolumesLength, len(builder.PodTemplate.Spec.Volumes)) - if IsMonitoringMetricsDefined(tc.es) { + + if IsMonitoringMetricsDefined(es) { for _, c := range builder.PodTemplate.Spec.Containers { if c.Name == "metricbeat" { assert.Equal(t, tc.beatVolumeMountsLength, len(c.VolumeMounts)) } } } - if IsMonitoringLogsDefined(tc.es) { + + if IsMonitoringLogsDefined(es) { for _, c := range builder.PodTemplate.Spec.Containers { if c.Name == "filebeat" { assert.Equal(t, tc.beatVolumeMountsLength, len(c.VolumeMounts)) diff --git a/pkg/controller/elasticsearch/stackmon/filebeat.yml b/pkg/controller/elasticsearch/stackmon/filebeat.yml index bb00d3b701..d942cfe423 100644 --- a/pkg/controller/elasticsearch/stackmon/filebeat.yml +++ b/pkg/controller/elasticsearch/stackmon/filebeat.yml @@ -40,9 +40,4 @@ processors: - add_cloud_metadata: {} - add_host_metadata: {} -# only one target ES can be referenced so far so we take it as ordinal 0 -output.elasticsearch: - hosts: ['${ES_0_TARGET_URL}'] - username: ${ES_0_TARGET_USERNAME} - password: ${ES_0_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/logs/target/0/ca.crt"] +# Elasticsearch output configuration is generated and added here \ No newline at end of file diff --git a/pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml b/pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml new file mode 100644 index 0000000000..aee4ca8b17 --- /dev/null +++ b/pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml @@ -0,0 +1,28 @@ +metricbeat.modules: + - module: elasticsearch + metricsets: + - ccr + - cluster_stats + - enrich + - index + - index_recovery + - index_summary + - ml_job + - node_stats + - pending_tasks + - shard + period: 10s + xpack.enabled: true + hosts: ["{{ .URL }}"] + username: {{ .Username }} + password: {{ .Password }} + {{- if .IsSSL }} + ssl.certificate_authorities: ["{{ .SSLPath }}"] + ssl.verification_mode: "{{ .SSLMode }}" + {{ end }} + +processors: + - add_cloud_metadata: {} + - add_host_metadata: {} + +# Elasticsearch output configuration is generated diff --git a/pkg/controller/elasticsearch/stackmon/metricbeat.yml b/pkg/controller/elasticsearch/stackmon/metricbeat.yml deleted file mode 100644 index bc5bcc43b0..0000000000 --- a/pkg/controller/elasticsearch/stackmon/metricbeat.yml +++ /dev/null @@ -1,29 +0,0 @@ -metricbeat.modules: - - module: elasticsearch - metricsets: - - ccr - - cluster_stats - - enrich - - index - - index_recovery - - index_summary - - ml_job - - node_stats - - shard - period: 10s - xpack.enabled: true - hosts: ["${ES_SOURCE_URL}"] - username: ${ES_SOURCE_USERNAME} - password: ${ES_SOURCE_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/source/ca.crt"] - ssl.verification_mode: "certificate" - -processors: - - add_cloud_metadata: {} - - add_host_metadata: {} - -output.elasticsearch: - hosts: ['${ES_0_TARGET_URL}'] - username: ${ES_0_TARGET_USERNAME} - password: ${ES_0_TARGET_PASSWORD} - ssl.certificate_authorities: ["/mnt/es/monitoring/metrics/target/0/ca.crt"] diff --git a/pkg/controller/elasticsearch/stackmon/validations.go b/pkg/controller/elasticsearch/stackmon/validations.go index 07d1a0da47..b9d7e75dd6 100644 --- a/pkg/controller/elasticsearch/stackmon/validations.go +++ b/pkg/controller/elasticsearch/stackmon/validations.go @@ -28,7 +28,7 @@ var ( // Validate validates that the Elasticsearch version is supported for Stack Monitoring and that there is exactly one // Elasticsearch reference defined when Stack Monitoring is defined func Validate(es esv1.Elasticsearch) field.ErrorList { - if isStackMonitoringDefined(es) { + if isMonitoringDefined(es) { err := IsSupportedVersion(es.Spec.Version) if err != nil { return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, diff --git a/pkg/controller/elasticsearch/stackmon/validations_test.go b/pkg/controller/elasticsearch/stackmon/validations_test.go index daea468297..3883e320e6 100644 --- a/pkg/controller/elasticsearch/stackmon/validations_test.go +++ b/pkg/controller/elasticsearch/stackmon/validations_test.go @@ -7,9 +7,10 @@ package stackmon import ( "testing" + "github.com/stretchr/testify/require" + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" - "github.com/stretchr/testify/require" ) func TestValidate(t *testing.T) { diff --git a/pkg/controller/elasticsearch/stackmon/volume.go b/pkg/controller/elasticsearch/stackmon/volume.go deleted file mode 100644 index 2b45344b57..0000000000 --- a/pkg/controller/elasticsearch/stackmon/volume.go +++ /dev/null @@ -1,81 +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; -// you may not use this file except in compliance with the Elastic License. - -package stackmon - -import ( - "fmt" - - esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/certificates" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" -) - -const ( - metricbeatConfigVolumeName = "metricbeat-config" - metricbeatConfigDirMountPath = "/etc/metricbeat-config" - - filebeatConfigVolumeName = "filebeat-config" - filebeatConfigDirMountPath = "/etc/filebeat-config" - - monitoringMetricsSourceEsCaCertVolumeName = "es-monitoring-metrics-source-certs" - monitoringMetricsTargetEsCaCertVolumeNameFormat = "es-monitoring-metrics-target-certs-%d" - monitoringLogsTargetEsCaCertVolumeNameFormat = "es-monitoring-logs-target-certs-%d" -) - -func metricbeatConfigSecretName(es esv1.Elasticsearch) string { - return esv1.ESNamer.Suffix(es.Name, metricbeatConfigVolumeName) -} - -func metricbeatConfigSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { - return volume.NewSecretVolumeWithMountPath( - metricbeatConfigSecretName(es), - metricbeatConfigVolumeName, - metricbeatConfigDirMountPath, - ) -} - -func filebeatConfigSecretName(es esv1.Elasticsearch) string { - return esv1.ESNamer.Suffix(es.Name, filebeatConfigVolumeName) -} - -func filebeatConfigSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { - return volume.NewSecretVolumeWithMountPath( - filebeatConfigSecretName(es), - filebeatConfigVolumeName, - filebeatConfigDirMountPath, - ) -} - -func monitoringMetricsSourceCaCertSecretVolume(es esv1.Elasticsearch) volume.SecretVolume { - return volume.NewSecretVolumeWithMountPath( - certificates.PublicCertsSecretName(esv1.ESNamer, es.Name), - monitoringMetricsSourceEsCaCertVolumeName, - monitoringMetricsSourceEsCaCertMountPath, - ) -} - -func monitoringMetricsTargetCaCertSecretVolumes(es esv1.Elasticsearch) []volume.VolumeLike { - volumes := make([]volume.VolumeLike, 0) - for i, assoc := range es.GetMonitoringMetricsAssociation() { - volumes = append(volumes, volume.NewSecretVolumeWithMountPath( - assoc.AssociationConf().GetCASecretName(), - fmt.Sprintf(monitoringMetricsTargetEsCaCertVolumeNameFormat, i), - fmt.Sprintf(monitoringMetricsTargetEsCaCertMountPathFormat, i), - )) - } - return volumes -} - -func monitoringLogsTargetCaCertSecretVolumes(es esv1.Elasticsearch) []volume.VolumeLike { - volumes := make([]volume.VolumeLike, 0) - for i, assoc := range es.GetMonitoringLogsAssociation() { - volumes = append(volumes, volume.NewSecretVolumeWithMountPath( - assoc.AssociationConf().GetCASecretName(), - fmt.Sprintf(monitoringLogsTargetEsCaCertVolumeNameFormat, i), - fmt.Sprintf(monitoringLogsTargetEsCaCertMountPathFormat, i), - )) - } - return volumes -} diff --git a/pkg/controller/elasticsearch/user/predefined.go b/pkg/controller/elasticsearch/user/predefined.go index aefcd1daf0..20afd80b5f 100644 --- a/pkg/controller/elasticsearch/user/predefined.go +++ b/pkg/controller/elasticsearch/user/predefined.go @@ -13,6 +13,7 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/label" "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user/filerealm" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" + "github.com/pkg/errors" "golang.org/x/crypto/bcrypt" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -149,3 +150,18 @@ func reuseOrGenerateHash(users users, fileRealm filerealm.Realm) (users, error) } return users, nil } + +func GetElasticUserPassword(c k8s.Client, es esv1.Elasticsearch) (string, error) { + secretObjKey := types.NamespacedName{Namespace: es.Namespace, Name: esv1.ElasticUserSecret(es.Name)} + var secret corev1.Secret + if err := c.Get(context.Background(), secretObjKey, &secret); err != nil { + return "", err + } + + passwordBytes, ok := secret.Data[ElasticUserName] + if !ok { + return "", errors.Errorf("auth secret key %s doesn't exist", ElasticUserName) + } + + return string(passwordBytes), nil +} diff --git a/pkg/controller/elasticsearch/user/roles.go b/pkg/controller/elasticsearch/user/roles.go index cc8cb3ecc1..bd6c8a7d58 100644 --- a/pkg/controller/elasticsearch/user/roles.go +++ b/pkg/controller/elasticsearch/user/roles.go @@ -113,7 +113,7 @@ var ( Privileges: []string{"create_index", "view_index_metadata", "index", "indices:admin/aliases"}, }, { - Names: []string{"filebeat-*"}, + Names: []string{"filebeat-*"}, Privileges: []string{"create_index", "view_index_metadata", "create_doc", "indices:admin/aliases"}, }, }, From 7737cefd3d14311e793bb423d7f2c116b810c853 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 1 Jul 2021 10:39:40 +0200 Subject: [PATCH 68/83] Remove redundant with_monitoring unit tests with container_test.go --- .../elasticsearch/nodespec/podspec_test.go | 91 ------------------- 1 file changed, 91 deletions(-) diff --git a/pkg/controller/elasticsearch/nodespec/podspec_test.go b/pkg/controller/elasticsearch/nodespec/podspec_test.go index 281a4fa70b..d266d9685f 100644 --- a/pkg/controller/elasticsearch/nodespec/podspec_test.go +++ b/pkg/controller/elasticsearch/nodespec/podspec_test.go @@ -319,94 +319,3 @@ func Test_getDefaultContainerPorts(t *testing.T) { }) } } - -func TestWithMonitoring(t *testing.T) { - monitoringRef := commonv1.ObjectSelector{ - Name: "m1", - Namespace: "c", - } - fakeAssocConf := commonv1.AssociationConf{ - AuthSecretName: "name-c-m1-beat-mon-user", - AuthSecretKey: "default-name-c-m1-beat-mon-user", - CACertProvided: true, - CASecretName: "name-es-mon-c-m1-ca", - URL: "https://m1-es-http.c.svc:9200", - Version: "7.14.0", - } - tt := []struct { - name string - es func() esv1.Elasticsearch - expectedXPackMonitoringConfigKeys int - expectedContainerLen int - }{ - { - name: "without monitoring", - es: func() esv1.Elasticsearch { - return sampleES - }, - expectedXPackMonitoringConfigKeys: 0, - expectedContainerLen: 2, - }, - { - name: "with logs monitoring", - es: func() esv1.Elasticsearch { - es := sampleES - es.Spec.Version = "7.14.0" - es.Spec.Monitoring.Logs.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} - return es - }, - expectedXPackMonitoringConfigKeys: 0, - expectedContainerLen: 3, - }, - { - name: "with metrics monitoring", - es: func() esv1.Elasticsearch { - es := sampleES - es.Spec.Version = "7.14.0" - es.Spec.Monitoring.Metrics.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} - return es - }, - expectedXPackMonitoringConfigKeys: 2, - expectedContainerLen: 3, - }, - { - name: "with logs and metrics monitoring", - es: func() esv1.Elasticsearch { - es := sampleES - es.Spec.Version = "7.14.0" - es.Spec.Monitoring.Metrics.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} - es.Spec.Monitoring.Logs.ElasticsearchRefs = []commonv1.ObjectSelector{monitoringRef} - return es - }, - expectedXPackMonitoringConfigKeys: 2, - expectedContainerLen: 4, - }, - } - - for _, tc := range tt { - t.Run(tc.name, func(t *testing.T) { - es := tc.es() - nodeSet := es.Spec.NodeSets[0] - ver, err := version.Parse(es.Spec.Version) - require.NoError(t, err) - - // Check that the Elasticsearch config contains XPack monitoring settings only when metrics monitoring config is defined - cfg, err := settings.NewMergedESConfig(es.Name, ver, corev1.IPv4Protocol, es.Spec.HTTP, *nodeSet.Config, stackmon.MonitoringConfig(es)) - require.NoError(t, err) - require.Len(t, cfg.HasKeys([]string{esv1.XPackMonitoringCollectionEnabled, esv1.XPackMonitoringElasticsearchCollectionEnabled}), tc.expectedXPackMonitoringConfigKeys) - - // Fake association conf - if stackmon.IsMonitoringMetricsDefined(es) { - es.GetMonitoringMetricsAssociation()[0].SetAssociationConf(&fakeAssocConf) - } - if stackmon.IsMonitoringLogsDefined(es) { - es.GetMonitoringLogsAssociation()[0].SetAssociationConf(&fakeAssocConf) - } - - actual, err := BuildPodTemplateSpec(es, es.Spec.NodeSets[0], cfg, nil, false) - require.NoError(t, err) - // Check that the beat sidecar containers are present - require.Len(t, actual.Spec.Containers, tc.expectedContainerLen) - }) - } -} From 5b92f6d80b810fdbd4eaa96c516193ad8eb69a32 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 1 Jul 2021 10:40:19 +0200 Subject: [PATCH 69/83] Dedicated es user to collect metrics --- pkg/controller/elasticsearch/stackmon/beat_config.go | 2 +- .../elasticsearch/stackmon/container_test.go | 2 +- pkg/controller/elasticsearch/user/predefined.go | 11 +++++++---- pkg/controller/elasticsearch/user/predefined_test.go | 2 +- pkg/controller/elasticsearch/user/roles.go | 2 ++ 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/beat_config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go index 329005cc93..a5673f457b 100644 --- a/pkg/controller/elasticsearch/stackmon/beat_config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -69,7 +69,7 @@ type esConfigData struct { // buildMetricbeatConfig builds the base Metricbeat config with the associated volume holding the CA of the monitored ES func buildMetricbeatBaseConfig(client k8s.Client, es esv1.Elasticsearch) (string, volume.VolumeLike, error) { - password, err := user.GetElasticUserPassword(client, es) + password, err := user.GetMonitoringUserPassword(client, es) if err != nil { return "", nil, err } diff --git a/pkg/controller/elasticsearch/stackmon/container_test.go b/pkg/controller/elasticsearch/stackmon/container_test.go index 68cee9bd86..6d23ef2264 100644 --- a/pkg/controller/elasticsearch/stackmon/container_test.go +++ b/pkg/controller/elasticsearch/stackmon/container_test.go @@ -31,7 +31,7 @@ func TestWithMonitoring(t *testing.T) { logsEsRef := []commonv1.ObjectSelector{{Name: "logs", Namespace: "observability"}} fakeElasticUserSecret := corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "sample-es-elastic-user", Namespace: "aerospace"}, + ObjectMeta: metav1.ObjectMeta{Name: "sample-es-internal-users", Namespace: "aerospace"}, Data: map[string][]byte{"elastic": []byte("1234567890")}, } fakeMetricsBeatUserSecret := corev1.Secret{ diff --git a/pkg/controller/elasticsearch/user/predefined.go b/pkg/controller/elasticsearch/user/predefined.go index 20afd80b5f..db2dc4118b 100644 --- a/pkg/controller/elasticsearch/user/predefined.go +++ b/pkg/controller/elasticsearch/user/predefined.go @@ -29,6 +29,8 @@ const ( ControllerUserName = "elastic-internal" // ProbeUserName is used for the Elasticsearch readiness probe. ProbeUserName = "elastic-internal-probe" + // MonitoringUserName is used for the Elasticsearch monitoring. + MonitoringUserName = "elastic-internal-monitoring" ) // reconcileElasticUser reconciles a single secret holding the "elastic" user password. @@ -56,6 +58,7 @@ func reconcileInternalUsers(c k8s.Client, es esv1.Elasticsearch, existingFileRea users{ {Name: ControllerUserName, Roles: []string{SuperUserBuiltinRole}}, {Name: ProbeUserName, Roles: []string{ProbeUserRole}}, + {Name: MonitoringUserName, Roles: []string{RemoteMonitoringCollectorBuiltinRole}}, }, esv1.InternalUsersSecret(es.Name), true, @@ -151,16 +154,16 @@ func reuseOrGenerateHash(users users, fileRealm filerealm.Realm) (users, error) return users, nil } -func GetElasticUserPassword(c k8s.Client, es esv1.Elasticsearch) (string, error) { - secretObjKey := types.NamespacedName{Namespace: es.Namespace, Name: esv1.ElasticUserSecret(es.Name)} +func GetMonitoringUserPassword(c k8s.Client, es esv1.Elasticsearch) (string, error) { + secretObjKey := types.NamespacedName{Namespace: es.Namespace, Name: esv1.InternalUsersSecret(es.Name)} var secret corev1.Secret if err := c.Get(context.Background(), secretObjKey, &secret); err != nil { return "", err } - passwordBytes, ok := secret.Data[ElasticUserName] + passwordBytes, ok := secret.Data[MonitoringUserName] if !ok { - return "", errors.Errorf("auth secret key %s doesn't exist", ElasticUserName) + return "", errors.Errorf("auth secret key %s doesn't exist", MonitoringUserName) } return string(passwordBytes), nil diff --git a/pkg/controller/elasticsearch/user/predefined_test.go b/pkg/controller/elasticsearch/user/predefined_test.go index 10f98910d6..5bee1aeedc 100644 --- a/pkg/controller/elasticsearch/user/predefined_test.go +++ b/pkg/controller/elasticsearch/user/predefined_test.go @@ -226,7 +226,7 @@ func Test_reconcileInternalUsers(t *testing.T) { got, err := reconcileInternalUsers(c, es, tt.existingFileRealm) require.NoError(t, err) // check returned users - require.Len(t, got, 2) + require.Len(t, got, 3) controllerUser := got[0] probeUser := got[1] // names and roles are always the same diff --git a/pkg/controller/elasticsearch/user/roles.go b/pkg/controller/elasticsearch/user/roles.go index bd6c8a7d58..6a16364077 100644 --- a/pkg/controller/elasticsearch/user/roles.go +++ b/pkg/controller/elasticsearch/user/roles.go @@ -21,6 +21,8 @@ const ( SuperUserBuiltinRole = "superuser" // ProbeUserRole is the name of the role used by the internal probe user. ProbeUserRole = "elastic_internal_probe_user" + // RemoteMonitoringCollectorBuiltinRole is the name of the built-in remote_monitoring_collector role. + RemoteMonitoringCollectorBuiltinRole = "remote_monitoring_collector" // ApmUserRoleV6 is the name of the role used by 6.8.x APMServer instances to connect to Elasticsearch. ApmUserRoleV6 = "eck_apm_user_role_v6" From f1139cce04e371c82e9bb665e6bc6a7fd469a0cc Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 1 Jul 2021 10:58:42 +0200 Subject: [PATCH 70/83] Adjust dedicated monitoring role --- pkg/controller/elasticsearch/user/roles.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/controller/elasticsearch/user/roles.go b/pkg/controller/elasticsearch/user/roles.go index 6a16364077..38646937b7 100644 --- a/pkg/controller/elasticsearch/user/roles.go +++ b/pkg/controller/elasticsearch/user/roles.go @@ -93,7 +93,8 @@ var ( }, }, }, - // StackMonitoringUserRole is a dedicated role for Stack Monitoring with Metricbeat and Filebeat. + // StackMonitoringUserRole is a dedicated role for Stack Monitoring with Metricbeat and Filebeat used for the + // user sending monitoring data. // See: https://www.elastic.co/guide/en/beats/filebeat/7.13/privileges-to-publish-monitoring.html. StackMonitoringUserRole: esclient.Role{ Cluster: []string{ @@ -112,11 +113,11 @@ var ( }, { Names: []string{"metricbeat-*"}, - Privileges: []string{"create_index", "view_index_metadata", "index", "indices:admin/aliases"}, + Privileges: []string{"manage", "read", "create_doc", "view_index_metadata", "create_index"}, }, { - Names: []string{"filebeat-*"}, - Privileges: []string{"create_index", "view_index_metadata", "create_doc", "indices:admin/aliases"}, + Names: []string{"filebeat-*"}, + Privileges: []string{"manage", "read", "create_doc", "view_index_metadata", "create_index"}, }, }, }, From 6e788c8c63d7b543f8d23ec66cd998f0f238b564 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Thu, 1 Jul 2021 12:27:46 +0200 Subject: [PATCH 71/83] Adjust unit tests following the addition of user elastic-internal-monitoring --- pkg/controller/elasticsearch/stackmon/container_test.go | 2 +- pkg/controller/elasticsearch/user/reconcile_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/container_test.go b/pkg/controller/elasticsearch/stackmon/container_test.go index 6d23ef2264..b81a9a0f0d 100644 --- a/pkg/controller/elasticsearch/stackmon/container_test.go +++ b/pkg/controller/elasticsearch/stackmon/container_test.go @@ -32,7 +32,7 @@ func TestWithMonitoring(t *testing.T) { fakeElasticUserSecret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Name: "sample-es-internal-users", Namespace: "aerospace"}, - Data: map[string][]byte{"elastic": []byte("1234567890")}, + Data: map[string][]byte{"elastic-internal-monitoring": []byte("1234567890")}, } fakeMetricsBeatUserSecret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Name: "sample-observability-monitoring-beat-es-mon-user", Namespace: "aerospace"}, diff --git a/pkg/controller/elasticsearch/user/reconcile_test.go b/pkg/controller/elasticsearch/user/reconcile_test.go index 88fbbe41b2..1481fb69f5 100644 --- a/pkg/controller/elasticsearch/user/reconcile_test.go +++ b/pkg/controller/elasticsearch/user/reconcile_test.go @@ -68,7 +68,7 @@ func Test_aggregateFileRealm(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, controllerUser.Password) actualUsers := fileRealm.UserNames() - require.ElementsMatch(t, []string{"elastic", "elastic-internal", "elastic-internal-probe", "user1", "user2", "user3"}, actualUsers) + require.ElementsMatch(t, []string{"elastic", "elastic-internal", "elastic-internal-probe", "elastic-internal-monitoring", "user1", "user2", "user3"}, actualUsers) } func Test_aggregateRoles(t *testing.T) { From f531e93759bb09bf7b4cbaac0d40f58451049337 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 10:32:58 +0200 Subject: [PATCH 72/83] Use 7.14.0-SNAPSHOT as MinStackVersion --- pkg/controller/elasticsearch/stackmon/validations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/validations.go b/pkg/controller/elasticsearch/stackmon/validations.go index b9d7e75dd6..c6df588042 100644 --- a/pkg/controller/elasticsearch/stackmon/validations.go +++ b/pkg/controller/elasticsearch/stackmon/validations.go @@ -19,10 +19,10 @@ const ( ) var ( - // Minimum Stack version to enable Stack Monitoring. + // MinStackVersion is the minimum Stack version to enable Stack Monitoring on an Elastic Stack application.. // This requirement comes from the fact that we configure Elasticsearch to write logs to disk for Filebeat // via the env var ES_LOG_STYLE available from this version. - MinStackVersion = version.MustParse("7.14.0") + MinStackVersion = version.MustParse("7.14.0-SNAPSHOT") ) // Validate validates that the Elasticsearch version is supported for Stack Monitoring and that there is exactly one From 1b035c9a23b39f9632652d0c0d8b4d8879a87a63 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 10:40:49 +0200 Subject: [PATCH 73/83] BeatSidecar constructor and public fields --- pkg/controller/common/stackmon/beat.go | 62 +++++++------------ .../elasticsearch/stackmon/beat_config.go | 8 +-- .../elasticsearch/stackmon/container.go | 34 +++++----- 3 files changed, 45 insertions(+), 59 deletions(-) diff --git a/pkg/controller/common/stackmon/beat.go b/pkg/controller/common/stackmon/beat.go index ee937d2e88..2cb701a8fc 100644 --- a/pkg/controller/common/stackmon/beat.go +++ b/pkg/controller/common/stackmon/beat.go @@ -16,32 +16,32 @@ import ( "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) -func NewMetricbeatBuilder(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatBuilder, error) { - return NewBeatBuilder(client, "metricbeat", container.MetricbeatImage, resource, +func NewMetricBeatSidecar(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { + return NewBeatSidecar(client, "metricbeat", resource, resource.GetMonitoringMetricsAssociation(), baseConfig, additionalVolume) } -func NewFilebeatBuilder(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatBuilder, error) { - return NewBeatBuilder(client, "filebeat", container.FilebeatImage, resource, +func NewFileBeatSidecar(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { + return NewBeatSidecar(client, "filebeat", resource, resource.GetMonitoringLogsAssociation(), baseConfig, additionalVolume) } -// BeatBuilder helps with building a beat sidecar container to monitor an Elastic Stack application. It focuses on +// BeatSidecar helps with building a beat sidecar container to monitor an Elastic Stack application. It focuses on // building the container, the secret holding the configuration file and the associated volumes for the pod. -type BeatBuilder struct { - container corev1.Container - configHash hash.Hash - configSecret corev1.Secret - volumes []volume.VolumeLike +type BeatSidecar struct { + Container corev1.Container + ConfigHash hash.Hash + ConfigSecret corev1.Secret + Volumes []corev1.Volume } -func NewBeatBuilder(client k8s.Client, beatName string, image container.Image, resource HasMonitoring, +func NewBeatSidecar(client k8s.Client, beatName string, resource HasMonitoring, associations []commonv1.Association, baseConfig string, additionalVolume volume.VolumeLike, -) (BeatBuilder, error) { +) (BeatSidecar, error) { // build the beat config config, err := newBeatConfig(client, beatName, resource, associations, baseConfig) if err != nil { - return BeatBuilder{}, err + return BeatSidecar{}, err } // add additional volume (ex: CA volume of the monitored ES for Metricbeat) @@ -56,36 +56,22 @@ func NewBeatBuilder(client k8s.Client, beatName string, image container.Image, r volumeMounts[i] = v.VolumeMount() } - return BeatBuilder{ - container: corev1.Container{ + // prepare the volumes for the pod + podVolumes := make([]corev1.Volume, 0) + for _, v := range volumes { + podVolumes = append(podVolumes, v.Volume()) + } + + return BeatSidecar{ + Container: corev1.Container{ Name: beatName, Image: container.ImageRepository(image, resource.Version()), Args: []string{"-c", config.filepath, "-e"}, Env: defaults.PodDownwardEnvVars(), VolumeMounts: volumeMounts, }, - configHash: config.hash, - configSecret: config.secret, - volumes: volumes, + ConfigHash: config.hash, + ConfigSecret: config.secret, + Volumes: podVolumes, }, nil } - -func (b BeatBuilder) Container() corev1.Container { - return b.container -} - -func (b BeatBuilder) ConfigHash() []byte { - return b.configHash.Sum(nil) -} - -func (b BeatBuilder) ConfigSecret() corev1.Secret { - return b.configSecret -} - -func (b BeatBuilder) Volumes() []corev1.Volume { - volumes := make([]corev1.Volume, 0) - for _, v := range b.volumes { - volumes = append(volumes, v.Volume()) - } - return volumes -} diff --git a/pkg/controller/elasticsearch/stackmon/beat_config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go index a5673f457b..a967d3d5c6 100644 --- a/pkg/controller/elasticsearch/stackmon/beat_config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -33,23 +33,23 @@ var ( // ReconcileConfigSecrets reconciles the secrets holding beats configuration func ReconcileConfigSecrets(client k8s.Client, es esv1.Elasticsearch) error { if IsMonitoringMetricsDefined(es) { - b, err := MetricbeatBuilder(client, es) + b, err := Metricbeat(client, es) if err != nil { return err } - if _, err := reconciler.ReconcileSecret(client, b.ConfigSecret(), &es); err != nil { + if _, err := reconciler.ReconcileSecret(client, b.ConfigSecret, &es); err != nil { return err } } if IsMonitoringLogsDefined(es) { - b, err := FilebeatBuilder(client, es) + b, err := Filebeat(client, es) if err != nil { return err } - if _, err := reconciler.ReconcileSecret(client, b.ConfigSecret(), &es); err != nil { + if _, err := reconciler.ReconcileSecret(client, b.ConfigSecret, &es); err != nil { return err } } diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index a9e036cf85..7c84a69350 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -45,27 +45,27 @@ func isMonitoringDefined(es esv1.Elasticsearch) bool { return IsMonitoringMetricsDefined(es) || IsMonitoringLogsDefined(es) } -func MetricbeatBuilder(client k8s.Client, es esv1.Elasticsearch) (common.BeatBuilder, error) { +func Metricbeat(client k8s.Client, es esv1.Elasticsearch) (common.BeatSidecar, error) { metricbeatConfig, sourceEsCaVolume, err := buildMetricbeatBaseConfig(client, es) if err != nil { - return common.BeatBuilder{}, err + return common.BeatSidecar{}, err } - metricbeatBuilder, err := common.NewMetricbeatBuilder(client, &es, metricbeatConfig, sourceEsCaVolume) + metricbeat, err := common.NewMetricBeatSidecar(client, &es, metricbeatConfig, sourceEsCaVolume) if err != nil { - return common.BeatBuilder{}, err + return common.BeatSidecar{}, err } - return metricbeatBuilder, nil + return metricbeat, nil } -func FilebeatBuilder(client k8s.Client, es esv1.Elasticsearch) (common.BeatBuilder, error) { - filebeatBuilder, err := common.NewFilebeatBuilder(client, &es, filebeatConfig, nil) +func Filebeat(client k8s.Client, es esv1.Elasticsearch) (common.BeatSidecar, error) { + filebeat, err := common.NewFileBeatSidecar(client, &es, filebeatConfig, nil) if err != nil { - return common.BeatBuilder{}, err + return common.BeatSidecar{}, err } - return filebeatBuilder, nil + return filebeat, nil } // WithMonitoring updates the Elasticsearch Pod template builder to deploy Metricbeat and Filebeat in sidecar containers @@ -80,33 +80,33 @@ func WithMonitoring(client k8s.Client, builder *defaults.PodTemplateBuilder, es volumes := make([]corev1.Volume, 0) if IsMonitoringMetricsDefined(es) { - beatBuilder, err := MetricbeatBuilder(client, es) + b, err := Metricbeat(client, es) if err != nil { return nil, err } - volumes = append(volumes, beatBuilder.Volumes()...) - builder.WithContainers(beatBuilder.Container()) - configHash.Write(beatBuilder.ConfigHash()) + volumes = append(volumes, b.Volumes...) + builder.WithContainers(b.Container) + configHash.Write(b.ConfigHash.Sum(nil)) } if IsMonitoringLogsDefined(es) { // enable Stack logging to write Elasticsearch logs to disk builder.WithEnv(fileLogStyleEnvVar()) - beatBuilder, err := FilebeatBuilder(client, es) + b, err := Filebeat(client, es) if err != nil { return nil, err } - volumes = append(volumes, beatBuilder.Volumes()...) - filebeat := beatBuilder.Container() + volumes = append(volumes, b.Volumes...) + filebeat := b.Container // share the ES logs volume into the Filebeat container filebeat.VolumeMounts = append(filebeat.VolumeMounts, esvolume.DefaultLogsVolumeMount) builder.WithContainers(filebeat) - configHash.Write(beatBuilder.ConfigHash()) + configHash.Write(b.ConfigHash.Sum(nil)) } // add the config hash label to ensure pod rotation when an ES password or a CA are rotated From f1a45c9d68e9f6175192a6503188620229d274cb Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 10:42:11 +0200 Subject: [PATCH 74/83] Simplify HasMonitoring interface with metav1.Object --- pkg/apis/elasticsearch/v1/elasticsearch_types.go | 14 -------------- pkg/controller/common/stackmon/beat.go | 13 ++++++------- pkg/controller/common/stackmon/beat_config.go | 6 +++--- pkg/controller/common/stackmon/monitoring.go | 6 ++---- .../elasticsearch/stackmon/beat_config.go | 2 +- pkg/controller/elasticsearch/stackmon/container.go | 7 +++++-- 6 files changed, 17 insertions(+), 31 deletions(-) diff --git a/pkg/apis/elasticsearch/v1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1/elasticsearch_types.go index 1cac67c226..f0912f11e4 100644 --- a/pkg/apis/elasticsearch/v1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1/elasticsearch_types.go @@ -240,20 +240,6 @@ func (es *Elasticsearch) SetAssociationStatusMap(typ commonv1.AssociationType, s return nil } -// HasMonitoring methods - -func (es *Elasticsearch) NSN() types.NamespacedName { - return types.NamespacedName{Name: es.Name, Namespace: es.Namespace} -} - -func (es *Elasticsearch) ShortKind() string { - return ShortKind -} - -func (es *Elasticsearch) Version() string { - return es.Spec.Version -} - // 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/controller/common/stackmon/beat.go b/pkg/controller/common/stackmon/beat.go index 2cb701a8fc..188f1dbfe0 100644 --- a/pkg/controller/common/stackmon/beat.go +++ b/pkg/controller/common/stackmon/beat.go @@ -10,19 +10,18 @@ import ( corev1 "k8s.io/api/core/v1" commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" - "github.com/elastic/cloud-on-k8s/pkg/controller/common/container" "github.com/elastic/cloud-on-k8s/pkg/controller/common/defaults" "github.com/elastic/cloud-on-k8s/pkg/controller/common/volume" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" ) -func NewMetricBeatSidecar(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { - return NewBeatSidecar(client, "metricbeat", resource, +func NewMetricBeatSidecar(client k8s.Client, resource HasMonitoring, image string, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { + return NewBeatSidecar(client, "metricbeat", image, resource, resource.GetMonitoringMetricsAssociation(), baseConfig, additionalVolume) } -func NewFileBeatSidecar(client k8s.Client, resource HasMonitoring, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { - return NewBeatSidecar(client, "filebeat", resource, +func NewFileBeatSidecar(client k8s.Client, resource HasMonitoring, image string, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { + return NewBeatSidecar(client, "filebeat", image, resource, resource.GetMonitoringLogsAssociation(), baseConfig, additionalVolume) } @@ -35,7 +34,7 @@ type BeatSidecar struct { Volumes []corev1.Volume } -func NewBeatSidecar(client k8s.Client, beatName string, resource HasMonitoring, +func NewBeatSidecar(client k8s.Client, beatName string, image string, resource HasMonitoring, associations []commonv1.Association, baseConfig string, additionalVolume volume.VolumeLike, ) (BeatSidecar, error) { // build the beat config @@ -65,7 +64,7 @@ func NewBeatSidecar(client k8s.Client, beatName string, resource HasMonitoring, return BeatSidecar{ Container: corev1.Container{ Name: beatName, - Image: container.ImageRepository(image, resource.Version()), + Image: image, Args: []string{"-c", config.filepath, "-e"}, Env: defaults.PodDownwardEnvVars(), VolumeMounts: volumeMounts, diff --git a/pkg/controller/common/stackmon/beat_config.go b/pkg/controller/common/stackmon/beat_config.go index 14619fbd79..e3a0176ffc 100644 --- a/pkg/controller/common/stackmon/beat_config.go +++ b/pkg/controller/common/stackmon/beat_config.go @@ -50,7 +50,7 @@ func newBeatConfig(client k8s.Client, beatName string, resource HasMonitoring, a } // name for the config secret and the associated config volume for the es pod - configName := fmt.Sprintf("%s-%s-%s-config", resource.NSN().Name, resource.ShortKind(), beatName) + configName := fmt.Sprintf("%s-%s-%s-config", resource.GetName(), assoc.AssociationType(), beatName) configFilename := fmt.Sprintf("%s.yml", beatName) configDirPath := fmt.Sprintf("/etc/%s-config", beatName) @@ -76,8 +76,8 @@ func newBeatConfig(client k8s.Client, beatName string, resource HasMonitoring, a configSecret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: configName, - Namespace: resource.NSN().Namespace, - Labels: label.NewLabels(resource.NSN()), + Namespace: resource.GetNamespace(), + Labels: label.NewLabels(k8s.ExtractNamespacedName(resource)), }, Data: map[string][]byte{ configFilename: configBytes, diff --git a/pkg/controller/common/stackmon/monitoring.go b/pkg/controller/common/stackmon/monitoring.go index 44b31c43fa..41d6cfbf61 100644 --- a/pkg/controller/common/stackmon/monitoring.go +++ b/pkg/controller/common/stackmon/monitoring.go @@ -6,14 +6,12 @@ package stackmon import ( commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" - "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // HasMonitoring is the interface implemented by an Elastic Stack application that supports Stack Monitoring () type HasMonitoring interface { + metav1.Object GetMonitoringMetricsAssociation() []commonv1.Association GetMonitoringLogsAssociation() []commonv1.Association - NSN() types.NamespacedName - ShortKind() string - Version() string } diff --git a/pkg/controller/elasticsearch/stackmon/beat_config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go index a967d3d5c6..33029500f5 100644 --- a/pkg/controller/elasticsearch/stackmon/beat_config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -85,7 +85,7 @@ func buildMetricbeatBaseConfig(client k8s.Client, es esv1.Elasticsearch) (string if configData.IsSSL { caVolume = volume.NewSecretVolumeWithMountPath( certificates.PublicCertsSecretName(esv1.ESNamer, es.Name), - fmt.Sprintf("%s-%s-monitoring-local-ca", es.Name, es.ShortKind()), + fmt.Sprintf("%s-es-monitoring-local-ca", es.Name), fmt.Sprintf("/mnt/elastic-internal/es-monitoring/%s/%s/certs", es.Namespace, es.Name), ) diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/container.go index 7c84a69350..7caee61416 100644 --- a/pkg/controller/elasticsearch/stackmon/container.go +++ b/pkg/controller/elasticsearch/stackmon/container.go @@ -11,6 +11,7 @@ import ( corev1 "k8s.io/api/core/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/defaults" common "github.com/elastic/cloud-on-k8s/pkg/controller/common/stackmon" esvolume "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/volume" @@ -51,7 +52,8 @@ func Metricbeat(client k8s.Client, es esv1.Elasticsearch) (common.BeatSidecar, e return common.BeatSidecar{}, err } - metricbeat, err := common.NewMetricBeatSidecar(client, &es, metricbeatConfig, sourceEsCaVolume) + image := container.ImageRepository(container.MetricbeatImage, es.Spec.Version) + metricbeat, err := common.NewMetricBeatSidecar(client, &es, image, metricbeatConfig, sourceEsCaVolume) if err != nil { return common.BeatSidecar{}, err } @@ -60,7 +62,8 @@ func Metricbeat(client k8s.Client, es esv1.Elasticsearch) (common.BeatSidecar, e } func Filebeat(client k8s.Client, es esv1.Elasticsearch) (common.BeatSidecar, error) { - filebeat, err := common.NewFileBeatSidecar(client, &es, filebeatConfig, nil) + image := container.ImageRepository(container.MetricbeatImage, es.Spec.Version) + filebeat, err := common.NewFileBeatSidecar(client, &es, image, filebeatConfig, nil) if err != nil { return common.BeatSidecar{}, err } From 324bb051ec96aa448430f4b08b31a246d684eba7 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 10:49:12 +0200 Subject: [PATCH 75/83] Files renaming --- pkg/controller/common/stackmon/{beat_config.go => config.go} | 0 pkg/controller/common/stackmon/{beat.go => sidecar.go} | 0 .../elasticsearch/stackmon/{container.go => sidecar.go} | 0 .../elasticsearch/stackmon/{container_test.go => sidecar_test.go} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename pkg/controller/common/stackmon/{beat_config.go => config.go} (100%) rename pkg/controller/common/stackmon/{beat.go => sidecar.go} (100%) rename pkg/controller/elasticsearch/stackmon/{container.go => sidecar.go} (100%) rename pkg/controller/elasticsearch/stackmon/{container_test.go => sidecar_test.go} (100%) diff --git a/pkg/controller/common/stackmon/beat_config.go b/pkg/controller/common/stackmon/config.go similarity index 100% rename from pkg/controller/common/stackmon/beat_config.go rename to pkg/controller/common/stackmon/config.go diff --git a/pkg/controller/common/stackmon/beat.go b/pkg/controller/common/stackmon/sidecar.go similarity index 100% rename from pkg/controller/common/stackmon/beat.go rename to pkg/controller/common/stackmon/sidecar.go diff --git a/pkg/controller/elasticsearch/stackmon/container.go b/pkg/controller/elasticsearch/stackmon/sidecar.go similarity index 100% rename from pkg/controller/elasticsearch/stackmon/container.go rename to pkg/controller/elasticsearch/stackmon/sidecar.go diff --git a/pkg/controller/elasticsearch/stackmon/container_test.go b/pkg/controller/elasticsearch/stackmon/sidecar_test.go similarity index 100% rename from pkg/controller/elasticsearch/stackmon/container_test.go rename to pkg/controller/elasticsearch/stackmon/sidecar_test.go From d7b7b1362ab1ec7de039d787404c54e670537a04 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 10:55:27 +0200 Subject: [PATCH 76/83] indentation --- pkg/controller/common/stackmon/sidecar.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/controller/common/stackmon/sidecar.go b/pkg/controller/common/stackmon/sidecar.go index 188f1dbfe0..2be074fe3a 100644 --- a/pkg/controller/common/stackmon/sidecar.go +++ b/pkg/controller/common/stackmon/sidecar.go @@ -16,13 +16,11 @@ import ( ) func NewMetricBeatSidecar(client k8s.Client, resource HasMonitoring, image string, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { - return NewBeatSidecar(client, "metricbeat", image, resource, - resource.GetMonitoringMetricsAssociation(), baseConfig, additionalVolume) + return NewBeatSidecar(client, "metricbeat", image, resource, resource.GetMonitoringMetricsAssociation(), baseConfig, additionalVolume) } func NewFileBeatSidecar(client k8s.Client, resource HasMonitoring, image string, baseConfig string, additionalVolume volume.VolumeLike) (BeatSidecar, error) { - return NewBeatSidecar(client, "filebeat", image, resource, - resource.GetMonitoringLogsAssociation(), baseConfig, additionalVolume) + return NewBeatSidecar(client, "filebeat", image, resource, resource.GetMonitoringLogsAssociation(), baseConfig, additionalVolume) } // BeatSidecar helps with building a beat sidecar container to monitor an Elastic Stack application. It focuses on From 07c1bdd9cb4ae926cef67a8a163f8a2d3c6fba1a Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 15:12:00 +0200 Subject: [PATCH 77/83] Accumulate validation errors --- .../elasticsearch/stackmon/validations.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/controller/elasticsearch/stackmon/validations.go b/pkg/controller/elasticsearch/stackmon/validations.go index c6df588042..45dd417557 100644 --- a/pkg/controller/elasticsearch/stackmon/validations.go +++ b/pkg/controller/elasticsearch/stackmon/validations.go @@ -28,24 +28,25 @@ var ( // Validate validates that the Elasticsearch version is supported for Stack Monitoring and that there is exactly one // Elasticsearch reference defined when Stack Monitoring is defined func Validate(es esv1.Elasticsearch) field.ErrorList { + var errs field.ErrorList if isMonitoringDefined(es) { err := IsSupportedVersion(es.Spec.Version) if err != nil { - return field.ErrorList{field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, - fmt.Sprintf(unsupportedVersionForStackMonitoringMsg, MinStackVersion))} + errs = append(errs, field.Invalid(field.NewPath("spec").Child("version"), es.Spec.Version, + fmt.Sprintf(unsupportedVersionForStackMonitoringMsg, MinStackVersion))) } } if IsMonitoringMetricsDefined(es) && len(es.Spec.Monitoring.Metrics.ElasticsearchRefs) != 1 { - return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), + errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("metrics").Child("elasticsearchRefs"), es.Spec.Monitoring.Metrics.ElasticsearchRefs, - fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Metrics"))} + fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Metrics"))) } if IsMonitoringLogsDefined(es) && len(es.Spec.Monitoring.Logs.ElasticsearchRefs) != 1 { - return field.ErrorList{field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), + errs = append(errs, field.Invalid(field.NewPath("spec").Child("monitoring").Child("logs").Child("elasticsearchRefs"), es.Spec.Monitoring.Logs.ElasticsearchRefs, - fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Logs"))} + fmt.Sprintf(invalidStackMonitoringElasticsearchRefsMsg, "Logs"))) } - return field.ErrorList{} + return errs } // IsSupportedVersion returns true if the Elasticsearch version is supported for Stack Monitoring, else returns false From 718eed6d1ec2eeee29f2126124925f2e9e7b0f06 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 15:15:08 +0200 Subject: [PATCH 78/83] Remove redundant code --- pkg/controller/elasticsearch/stackmon/beat_config.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/controller/elasticsearch/stackmon/beat_config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go index 33029500f5..0e81e7ae5d 100644 --- a/pkg/controller/elasticsearch/stackmon/beat_config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -89,7 +89,6 @@ func buildMetricbeatBaseConfig(client k8s.Client, es esv1.Elasticsearch) (string fmt.Sprintf("/mnt/elastic-internal/es-monitoring/%s/%s/certs", es.Namespace, es.Name), ) - configData.IsSSL = true configData.SSLPath = filepath.Join(caVolume.VolumeMount().MountPath, certificates.CAFileName) configData.SSLMode = "certificate" } From b49530f613ce8c50dbb849b166edba46f218a7a6 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 15:32:55 +0200 Subject: [PATCH 79/83] Update ES secrets check in E2E tests --- test/e2e/test/elasticsearch/checks_k8s.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/test/elasticsearch/checks_k8s.go b/test/e2e/test/elasticsearch/checks_k8s.go index 9951dc8799..041ca21c26 100644 --- a/test/e2e/test/elasticsearch/checks_k8s.go +++ b/test/e2e/test/elasticsearch/checks_k8s.go @@ -129,7 +129,7 @@ func CheckSecrets(b Builder, k *test.K8sClient) test.Step { }, { Name: esName + "-es-internal-users", - Keys: []string{"elastic-internal", "elastic-internal-probe"}, + Keys: []string{"elastic-internal", "elastic-internal-monitoring", "elastic-internal-probe"}, Labels: map[string]string{ "common.k8s.elastic.co/type": "elasticsearch", "eck.k8s.elastic.co/credentials": "true", From f4759fdf29b95db696582793cba3d056d276b88c Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 16:25:13 +0200 Subject: [PATCH 80/83] Fix FilebeatImage --- pkg/controller/elasticsearch/stackmon/sidecar.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/elasticsearch/stackmon/sidecar.go b/pkg/controller/elasticsearch/stackmon/sidecar.go index 7caee61416..f1e380914d 100644 --- a/pkg/controller/elasticsearch/stackmon/sidecar.go +++ b/pkg/controller/elasticsearch/stackmon/sidecar.go @@ -62,7 +62,7 @@ func Metricbeat(client k8s.Client, es esv1.Elasticsearch) (common.BeatSidecar, e } func Filebeat(client k8s.Client, es esv1.Elasticsearch) (common.BeatSidecar, error) { - image := container.ImageRepository(container.MetricbeatImage, es.Spec.Version) + image := container.ImageRepository(container.FilebeatImage, es.Spec.Version) filebeat, err := common.NewFileBeatSidecar(client, &es, image, filebeatConfig, nil) if err != nil { return common.BeatSidecar{}, err From c26faa5232b10ff88f4a14aad9f08260bf0815d6 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 17:52:29 +0200 Subject: [PATCH 81/83] Better control of volume names --- pkg/controller/common/stackmon/config.go | 5 +- pkg/controller/common/stackmon/name.go | 30 ++++++++++ pkg/controller/common/stackmon/name_test.go | 60 +++++++++++++++++++ .../elasticsearch/stackmon/beat_config.go | 2 +- .../elasticsearch/stackmon/sidecar_test.go | 2 +- 5 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 pkg/controller/common/stackmon/name.go create mode 100644 pkg/controller/common/stackmon/name_test.go diff --git a/pkg/controller/common/stackmon/config.go b/pkg/controller/common/stackmon/config.go index e3a0176ffc..8e21ba2f3f 100644 --- a/pkg/controller/common/stackmon/config.go +++ b/pkg/controller/common/stackmon/config.go @@ -50,7 +50,7 @@ func newBeatConfig(client k8s.Client, beatName string, resource HasMonitoring, a } // name for the config secret and the associated config volume for the es pod - configName := fmt.Sprintf("%s-%s-%s-config", resource.GetName(), assoc.AssociationType(), beatName) + configName := configVolumeName(resource.GetName(), beatName) configFilename := fmt.Sprintf("%s.yml", beatName) configDirPath := fmt.Sprintf("/etc/%s-config", beatName) @@ -113,8 +113,9 @@ func buildOutputConfig(client k8s.Client, assoc commonv1.Association) (map[strin if assoc.AssociationConf().GetCACertProvided() { sslCAPath := filepath.Join(caDirPath, certificates.CAFileName) outputConfig["ssl.certificate_authorities"] = []string{sslCAPath} + volumeName := caVolumeName(assoc) caVolume = volume.NewSecretVolumeWithMountPath( - assoc.AssociationConf().GetCASecretName(), assoc.AssociationConf().GetCASecretName(), caDirPath, + assoc.AssociationConf().GetCASecretName(), volumeName, caDirPath, ) } diff --git a/pkg/controller/common/stackmon/name.go b/pkg/controller/common/stackmon/name.go new file mode 100644 index 0000000000..3774d03e1b --- /dev/null +++ b/pkg/controller/common/stackmon/name.go @@ -0,0 +1,30 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "crypto/sha256" + "fmt" + + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/name" +) + +const maxVolumeNameLength = 63 + +var VolumeNamer = name.Namer{ + MaxSuffixLength: name.MaxSuffixLength, + MaxNameLength: maxVolumeNameLength, +} + +func configVolumeName(name string, beatName string) string { + return VolumeNamer.Suffix(name, beatName, "config") +} + +func caVolumeName(assoc commonv1.Association) string { + nsn := assoc.AssociationRef().Namespace+assoc.AssociationRef().Name + nsnHash := fmt.Sprintf("%x", sha256.Sum256([]byte(nsn)))[0:6] + return VolumeNamer.Suffix(string(assoc.AssociationType()), nsnHash, "ca") +} diff --git a/pkg/controller/common/stackmon/name_test.go b/pkg/controller/common/stackmon/name_test.go new file mode 100644 index 0000000000..dea2129147 --- /dev/null +++ b/pkg/controller/common/stackmon/name_test.go @@ -0,0 +1,60 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package stackmon + +import ( + "testing" + + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" + esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestConfigVolumeName(t *testing.T) { + name := configVolumeName( + "extremely-long-and-unwieldy-name-that-exceeds-the-limit", + "metricbeat", + ) + assert.LessOrEqual(t, len(name), maxVolumeNameLength) + assert.Equal(t, "extremely-long-and-unwieldy-name-that-exceeds-metricbeat-config", name) +} + +func TestCAVolumeName(t *testing.T) { + es := esv1.Elasticsearch{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + Namespace: "aerospace", + }, + Spec: esv1.ElasticsearchSpec{ + Version: "7.14.0", + Monitoring: esv1.Monitoring{ + Metrics: esv1.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{ + ElasticsearchRefs: []commonv1.ObjectSelector{{ + Name: "extremely-long-and-unwieldy-name-that-exceeds-the-limit", + Namespace: "extremely-long-and-unwieldy-namespace-that-exceeds-the-limit"}}, + }, + }, + }, + } + + name := caVolumeName(es.GetMonitoringMetricsAssociation()[0]) + assert.LessOrEqual(t, len(name), maxVolumeNameLength) + assert.Equal(t, "es-monitoring-954c60-ca", name) + + name = caVolumeName(es.GetMonitoringLogsAssociation()[0]) + assert.LessOrEqual(t, len(name), maxVolumeNameLength) + assert.Equal(t, "es-monitoring-954c60-ca", name) + + es.Spec.Monitoring.Logs.ElasticsearchRefs[0].Name = "another-name" + newName := caVolumeName(es.GetMonitoringLogsAssociation()[0]) + assert.NotEqual(t, name, newName) + assert.Equal(t, "es-monitoring-ae0f57-ca", newName) +} diff --git a/pkg/controller/elasticsearch/stackmon/beat_config.go b/pkg/controller/elasticsearch/stackmon/beat_config.go index 0e81e7ae5d..3dd06bb15e 100644 --- a/pkg/controller/elasticsearch/stackmon/beat_config.go +++ b/pkg/controller/elasticsearch/stackmon/beat_config.go @@ -85,7 +85,7 @@ func buildMetricbeatBaseConfig(client k8s.Client, es esv1.Elasticsearch) (string if configData.IsSSL { caVolume = volume.NewSecretVolumeWithMountPath( certificates.PublicCertsSecretName(esv1.ESNamer, es.Name), - fmt.Sprintf("%s-es-monitoring-local-ca", es.Name), + "es-monitoring-local-ca", fmt.Sprintf("/mnt/elastic-internal/es-monitoring/%s/%s/certs", es.Namespace, es.Name), ) diff --git a/pkg/controller/elasticsearch/stackmon/sidecar_test.go b/pkg/controller/elasticsearch/stackmon/sidecar_test.go index b81a9a0f0d..ef3047c50e 100644 --- a/pkg/controller/elasticsearch/stackmon/sidecar_test.go +++ b/pkg/controller/elasticsearch/stackmon/sidecar_test.go @@ -111,7 +111,7 @@ func TestWithMonitoring(t *testing.T) { sampleEs.Spec.Monitoring.Metrics.ElasticsearchRefs = monitoringEsRef sampleEs.GetMonitoringMetricsAssociation()[0].SetAssociationConf(&monitoringAssocConf) sampleEs.Spec.Monitoring.Logs.ElasticsearchRefs = monitoringEsRef - sampleEs.GetMonitoringLogsAssociation()[0].SetAssociationConf(&monitoringAssocConf) + sampleEs.GetMonitoringLogsAssociation()[0].SetAssociationConf(&logsAssocConf) return sampleEs }, containersLength: 3, From 31c2465c9a188c800c65fa3e598baf44e614a6d1 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Mon, 5 Jul 2021 21:56:58 +0200 Subject: [PATCH 82/83] Run generate --- config/crds/v1/all-crds.yaml | 8 ++++---- config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml | 8 ++++---- config/crds/v1beta1/all-crds.yaml | 8 ++++---- .../crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml | 8 ++++---- .../eck-operator-crds/templates/all-crds-legacy.yaml | 8 ++++---- .../charts/eck-operator-crds/templates/all-crds.yaml | 8 ++++---- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/config/crds/v1/all-crds.yaml b/config/crds/v1/all-crds.yaml index 906bbb4d43..e92de62ae1 100644 --- a/config/crds/v1/all-crds.yaml +++ b/config/crds/v1/all-crds.yaml @@ -6233,10 +6233,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name 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 5b97cc32d7..f69c18cdbc 100644 --- a/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml +++ b/config/crds/v1/bases/kibana.k8s.elastic.co_kibanas.yaml @@ -98,10 +98,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/config/crds/v1beta1/all-crds.yaml b/config/crds/v1beta1/all-crds.yaml index 954f56b92f..73289bb240 100644 --- a/config/crds/v1beta1/all-crds.yaml +++ b/config/crds/v1beta1/all-crds.yaml @@ -3896,10 +3896,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name diff --git a/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml b/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml index f8399fc5f4..208788a0d3 100644 --- a/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml +++ b/config/crds/v1beta1/bases/kibana.k8s.elastic.co_kibanas.yaml @@ -101,10 +101,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name diff --git a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml index db4e816697..84e785a78c 100644 --- a/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml +++ b/deploy/eck-operator/charts/eck-operator-crds/templates/all-crds-legacy.yaml @@ -3941,10 +3941,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes service - which will be 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 - will be used. + 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 required: - name 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 1c103ab673..d748f95277 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 @@ -6278,10 +6278,10 @@ spec: type: string serviceName: description: ServiceName is the name of an existing Kubernetes - service which will be 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 will be used. + 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 required: - name From ccd7e12df9eb01b43e145672e569265aed8beba2 Mon Sep 17 00:00:00 2001 From: Thibault Richard Date: Tue, 6 Jul 2021 11:11:28 +0200 Subject: [PATCH 83/83] Update E2E test Kibana CheckStatus --- test/e2e/test/kibana/checks_k8s.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/e2e/test/kibana/checks_k8s.go b/test/e2e/test/kibana/checks_k8s.go index 78fb6f4e7d..940f03c1cb 100644 --- a/test/e2e/test/kibana/checks_k8s.go +++ b/test/e2e/test/kibana/checks_k8s.go @@ -105,19 +105,15 @@ func CheckStatus(b Builder, k *test.K8sClient) test.Step { if err := k.Client.Get(context.Background(), k8s.ExtractNamespacedName(&b.Kibana), &kb); err != nil { return err } - // don't check the association status that may vary across tests - kb.Status.AssociationStatus = "" - kb.Status.ElasticsearchAssociationStatus = "" - kb.Status.EnterpriseSearchAssociationStatus = "" + // don't check the association statuses that may vary across tests expected := kbv1.KibanaStatus{ DeploymentStatus: commonv1.DeploymentStatus{ AvailableNodes: b.Kibana.Spec.Count, Version: b.Kibana.Spec.Version, Health: "green", }, - AssociationStatus: "", } - if kb.Status != expected { + if kb.Status.DeploymentStatus != expected.DeploymentStatus { return fmt.Errorf("expected status %+v but got %+v", expected, kb.Status) } return nil