From ce20b9ab0c9eb458bf5bc020aaa070f82e7d8988 Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Tue, 9 Jun 2020 15:31:09 +0200 Subject: [PATCH] Add KibanaRef to Beats --- cmd/manager/main.go | 5 +- config/crds/all-crds.yaml | 24 +++- .../crds/bases/beat.k8s.elastic.co_beats.yaml | 24 +++- pkg/apis/apm/v1/apmserver_types.go | 4 +- pkg/apis/beat/v1beta1/beat_types.go | 123 +++++++++++++----- .../beat/v1beta1/zz_generated.deepcopy.go | 50 ++++++- pkg/apis/common/v1/association.go | 3 + .../association/controller/apm_es.go | 8 +- .../association/controller/apm_kibana.go | 6 +- .../association/controller/beat_es.go | 18 +-- pkg/controller/beat/common/config.go | 68 ++++++---- pkg/controller/beat/common/driver.go | 2 +- pkg/controller/beat/common/health.go | 8 +- pkg/controller/beat/common/pod.go | 27 ++-- pkg/controller/beat/common/reconcile.go | 3 +- pkg/controller/beat/controller.go | 2 +- .../common/association/association.go | 14 +- pkg/controller/elasticsearch/user/roles.go | 3 + pkg/controller/kibana/driver.go | 2 +- 19 files changed, 293 insertions(+), 101 deletions(-) diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 06df2f17b48..fd44a97b61b 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -349,7 +349,6 @@ func execute() { if manageBeatAutodiscoverRBAC { beatcommon.EnableAutodiscoverRBACManagement() } - if err = apmserver.Add(mgr, params); err != nil { log.Error(err, "unable to create controller", "controller", "ApmServer") os.Exit(1) @@ -390,6 +389,10 @@ func execute() { log.Error(err, "unable to create controller", "controller", "beat-es-association") os.Exit(1) } + if err = associationctl.AddBeatKibana(mgr, accessReviewer, params); err != nil { + log.Error(err, "unable to create controller", "controller", "beat-kibana-association") + os.Exit(1) + } if err = remoteca.Add(mgr, accessReviewer, params); err != nil { log.Error(err, "unable to create controller", "controller", "RemoteClusterCertificateAuthorites") diff --git a/config/crds/all-crds.yaml b/config/crds/all-crds.yaml index 7da53c175fa..24b6282a2d4 100644 --- a/config/crds/all-crds.yaml +++ b/config/crds/all-crds.yaml @@ -555,6 +555,21 @@ spec: description: Image is the Beat Docker image to deploy. Version and Type have to match the Beat in the image. type: string + kibanaRef: + description: KibanaRef is a reference to a Kibana instance running in + the same Kubernetes cluster. It allows APM agent central configuration + management in Kibana. + 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 + required: + - name + type: object serviceAccountName: description: ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only @@ -576,17 +591,20 @@ spec: status: description: BeatStatus defines the observed state of a Beat. properties: - associationStatus: - description: AssociationStatus is the status of an association resource. - type: string availableNodes: format: int32 type: integer + elasticsearchAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string expectedNodes: format: int32 type: integer health: type: string + kibanaAssocationStatus: + description: AssociationStatus is the status of an association resource. + type: string type: object version: v1beta1 versions: diff --git a/config/crds/bases/beat.k8s.elastic.co_beats.yaml b/config/crds/bases/beat.k8s.elastic.co_beats.yaml index 7d3c513864c..1343b33cd32 100644 --- a/config/crds/bases/beat.k8s.elastic.co_beats.yaml +++ b/config/crds/bases/beat.k8s.elastic.co_beats.yaml @@ -12160,6 +12160,21 @@ spec: description: Image is the Beat Docker image to deploy. Version and Type have to match the Beat in the image. type: string + kibanaRef: + description: KibanaRef is a reference to a Kibana instance running in + the same Kubernetes cluster. It allows APM agent central configuration + management in Kibana. + 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 + required: + - name + type: object serviceAccountName: description: ServiceAccountName is used to check access from the current resource to Elasticsearch resource in a different namespace. Can only @@ -12181,17 +12196,20 @@ spec: status: description: BeatStatus defines the observed state of a Beat. properties: - associationStatus: - description: AssociationStatus is the status of an association resource. - type: string availableNodes: format: int32 type: integer + elasticsearchAssociationStatus: + description: AssociationStatus is the status of an association resource. + type: string expectedNodes: format: int32 type: integer health: type: string + kibanaAssocationStatus: + description: AssociationStatus is the status of an association resource. + type: string type: object type: object version: v1beta1 diff --git a/pkg/apis/apm/v1/apmserver_types.go b/pkg/apis/apm/v1/apmserver_types.go index f78ecbe5295..e17f558076b 100644 --- a/pkg/apis/apm/v1/apmserver_types.go +++ b/pkg/apis/apm/v1/apmserver_types.go @@ -210,11 +210,11 @@ func (akb *ApmKibanaAssociation) Associated() commonv1.Associated { } func (akb *ApmKibanaAssociation) AssociationConfAnnotationName() string { - return "association.k8s.elastic.co/kb-conf" + return commonv1.KibanaConfigAnnotationName } func (akb *ApmKibanaAssociation) AssociatedType() string { - return "kibana" + return commonv1.KibanaAssociationType } func (akb *ApmKibanaAssociation) AssociationRef() commonv1.ObjectSelector { diff --git a/pkg/apis/beat/v1beta1/beat_types.go b/pkg/apis/beat/v1beta1/beat_types.go index 38132993549..a6413e27fe7 100644 --- a/pkg/apis/beat/v1beta1/beat_types.go +++ b/pkg/apis/beat/v1beta1/beat_types.go @@ -25,6 +25,10 @@ type BeatSpec struct { // +kubebuilder:validation:Optional ElasticsearchRef commonv1.ObjectSelector `json:"elasticsearchRef,omitempty"` + // KibanaRef is a reference to a Kibana instance running in the same Kubernetes cluster. + // It allows automatic setup of dashboards and visualizations. + KibanaRef commonv1.ObjectSelector `json:"kibanaRef,omitempty"` + // Image is the Beat Docker image to deploy. Version and Type have to match the Beat in the image. // +kubebuilder:validation:Optional Image string `json:"image,omitempty"` @@ -70,7 +74,10 @@ type BeatStatus struct { Health BeatHealth `json:"health,omitempty"` // +kubebuilder:validation:Optional - Association commonv1.AssociationStatus `json:"associationStatus,omitempty"` + ElasticsearchAssociation commonv1.AssociationStatus `json:"elasticsearchAssociationStatus,omitempty"` + + // +kubebuilder:validation:Optional + KibanaAssocation commonv1.AssociationStatus `json:"kibanaAssocationStatus,omitempty"` } type BeatHealth string @@ -106,65 +113,121 @@ type Beat struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec BeatSpec `json:"spec,omitempty"` - Status BeatStatus `json:"status,omitempty"` - assocConf *commonv1.AssociationConf `json:"-"` //nolint:govet + Spec BeatSpec `json:"spec,omitempty"` + Status BeatStatus `json:"status,omitempty"` + esAssocConf *commonv1.AssociationConf `json:"-"` // nolint:govet + kbAssocConf *commonv1.AssociationConf `json:"-"` // nolint:govet +} + +var _ commonv1.Associated = &Beat{} + +func (b *Beat) GetAssociations() []commonv1.Association { + return []commonv1.Association{ + &BeatESAssociation{Beat: b}, + &BeatKibanaAssociation{Beat: b}, + } +} + +func (b *Beat) ServiceAccountName() string { + return b.Spec.ServiceAccountName +} + +type BeatESAssociation struct { + *Beat } -func (b *Beat) Associated() commonv1.Associated { - if b != nil { - return b +var _ commonv1.Association = &BeatESAssociation{} + +func (b *BeatESAssociation) Associated() commonv1.Associated { + if b == nil { + return nil + } + if b.Beat == nil { + b.Beat = &Beat{} } - return &Beat{} + return b.Beat } -func (b *Beat) AssociatedType() string { +func (b *BeatESAssociation) AssociatedType() string { return commonv1.ElasticsearchAssociationType } -func (b *Beat) AssociationRef() commonv1.ObjectSelector { +func (b *BeatESAssociation) AssociationRef() commonv1.ObjectSelector { return b.Spec.ElasticsearchRef.WithDefaultNamespace(b.Namespace) } -func (b *Beat) AssociationConfAnnotationName() string { +func (b *BeatESAssociation) AssociationConfAnnotationName() string { return commonv1.ElasticsearchConfigAnnotationName } -func (b *Beat) GetAssociations() []commonv1.Association { - return []commonv1.Association{b} +func (b *BeatESAssociation) AssociationConf() *commonv1.AssociationConf { + return b.esAssocConf } -// IsMarkedForDeletion returns true if the Beat is going to be deleted -func (b *Beat) IsMarkedForDeletion() bool { - return !b.DeletionTimestamp.IsZero() +func (b *BeatESAssociation) SetAssociationConf(conf *commonv1.AssociationConf) { + b.esAssocConf = conf } -func (b *Beat) ServiceAccountName() string { - return b.Spec.ServiceAccountName +func (b *BeatESAssociation) AssociationStatus() commonv1.AssociationStatus { + return b.Status.ElasticsearchAssociation } -func (b *Beat) ElasticsearchRef() commonv1.ObjectSelector { - return b.Spec.ElasticsearchRef +func (b *BeatESAssociation) SetAssociationStatus(status commonv1.AssociationStatus) { + b.Status.ElasticsearchAssociation = status } -func (b *Beat) AssociationConf() *commonv1.AssociationConf { - return b.assocConf +type BeatKibanaAssociation struct { + *Beat } -func (b *Beat) SetAssociationConf(assocConf *commonv1.AssociationConf) { - b.assocConf = assocConf +var _ commonv1.Association = &BeatKibanaAssociation{} + +func (b *BeatKibanaAssociation) AssociationConf() *commonv1.AssociationConf { + return b.kbAssocConf } -func (b *Beat) AssociationStatus() commonv1.AssociationStatus { - return b.Status.Association +func (b *BeatKibanaAssociation) SetAssociationConf(conf *commonv1.AssociationConf) { + b.kbAssocConf = conf } -func (b *Beat) SetAssociationStatus(status commonv1.AssociationStatus) { - b.Status.Association = status +func (b *BeatKibanaAssociation) AssociationStatus() commonv1.AssociationStatus { + return b.Status.KibanaAssocation } -var _ commonv1.Associated = &Beat{} -var _ commonv1.Association = &Beat{} +func (b *BeatKibanaAssociation) SetAssociationStatus(status commonv1.AssociationStatus) { + b.Status.KibanaAssocation = status +} + +func (b *BeatKibanaAssociation) Associated() commonv1.Associated { + if b == nil { + return nil + } + if b.Beat == nil { + b.Beat = &Beat{} + } + return b.Beat +} + +func (b *BeatKibanaAssociation) AssociatedType() string { + return commonv1.KibanaAssociationType +} + +func (b *BeatKibanaAssociation) AssociationRef() commonv1.ObjectSelector { + return b.Spec.KibanaRef.WithDefaultNamespace(b.Namespace) +} + +func (b *BeatKibanaAssociation) AssociationConfAnnotationName() string { + return commonv1.KibanaConfigAnnotationName +} + +// IsMarkedForDeletion returns true if the Beat is going to be deleted +func (b *Beat) IsMarkedForDeletion() bool { + return !b.DeletionTimestamp.IsZero() +} + +func (b *Beat) ElasticsearchRef() commonv1.ObjectSelector { + return b.Spec.ElasticsearchRef +} // +kubebuilder:object:root=true diff --git a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go index 93e1f0eab8b..7f87e88cfdf 100644 --- a/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/beat/v1beta1/zz_generated.deepcopy.go @@ -20,8 +20,13 @@ func (in *Beat) DeepCopyInto(out *Beat) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status - if in.assocConf != nil { - in, out := &in.assocConf, &out.assocConf + if in.esAssocConf != nil { + in, out := &in.esAssocConf, &out.esAssocConf + *out = new(v1.AssociationConf) + **out = **in + } + if in.kbAssocConf != nil { + in, out := &in.kbAssocConf, &out.kbAssocConf *out = new(v1.AssociationConf) **out = **in } @@ -45,6 +50,46 @@ func (in *Beat) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BeatESAssociation) DeepCopyInto(out *BeatESAssociation) { + *out = *in + if in.Beat != nil { + in, out := &in.Beat, &out.Beat + *out = new(Beat) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BeatESAssociation. +func (in *BeatESAssociation) DeepCopy() *BeatESAssociation { + if in == nil { + return nil + } + out := new(BeatESAssociation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BeatKibanaAssociation) DeepCopyInto(out *BeatKibanaAssociation) { + *out = *in + if in.Beat != nil { + in, out := &in.Beat, &out.Beat + *out = new(Beat) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BeatKibanaAssociation. +func (in *BeatKibanaAssociation) DeepCopy() *BeatKibanaAssociation { + if in == nil { + return nil + } + out := new(BeatKibanaAssociation) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BeatList) DeepCopyInto(out *BeatList) { *out = *in @@ -81,6 +126,7 @@ func (in *BeatList) DeepCopyObject() runtime.Object { func (in *BeatSpec) DeepCopyInto(out *BeatSpec) { *out = *in out.ElasticsearchRef = in.ElasticsearchRef + out.KibanaRef = in.KibanaRef if in.Config != nil { in, out := &in.Config, &out.Config *out = (*in).DeepCopy() diff --git a/pkg/apis/common/v1/association.go b/pkg/apis/common/v1/association.go index 52c4e0fdcde..3e6bc59eeb8 100644 --- a/pkg/apis/common/v1/association.go +++ b/pkg/apis/common/v1/association.go @@ -16,6 +16,9 @@ const ( ElasticsearchConfigAnnotationName = "association.k8s.elastic.co/es-conf" ElasticsearchAssociationType = "elasticsearch" + KibanaAssociationType = "kibana" + KibanaConfigAnnotationName = "association.k8s.elastic.co/kb-conf" + AssociationUnknown AssociationStatus = "" AssociationPending AssociationStatus = "Pending" AssociationEstablished AssociationStatus = "Established" diff --git a/pkg/controller/association/controller/apm_es.go b/pkg/controller/association/controller/apm_es.go index 5f316c0b8f1..e2e2d6d5ac3 100644 --- a/pkg/controller/association/controller/apm_es.go +++ b/pkg/controller/association/controller/apm_es.go @@ -29,7 +29,7 @@ const ( // ApmAssociationLabelNamespace marks resources created for an association originating from APM. ApmAssociationLabelNamespace = "apmassociation.k8s.elastic.co/namespace" // ApmAssociationLabelNamespace marks resources created for an association originating from APM. - ApmAssociationTypeLabelNamespace = "apmassociation.k8s.elastic.co/type" + ApmAssociationLabelType = "apmassociation.k8s.elastic.co/type" ) func AddApmES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { @@ -44,9 +44,9 @@ func AddApmES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params op AssociationName: "apm-es", AssociationLabels: func(associated types.NamespacedName) map[string]string { return map[string]string{ - ApmAssociationLabelName: associated.Name, - ApmAssociationLabelNamespace: associated.Namespace, - ApmAssociationTypeLabelNamespace: commonv1.ElasticsearchAssociationType, + ApmAssociationLabelName: associated.Name, + ApmAssociationLabelNamespace: associated.Namespace, + ApmAssociationLabelType: commonv1.ElasticsearchAssociationType, } }, UserSecretSuffix: "apm-user", diff --git a/pkg/controller/association/controller/apm_kibana.go b/pkg/controller/association/controller/apm_kibana.go index 248c91b7203..0b3357dde72 100644 --- a/pkg/controller/association/controller/apm_kibana.go +++ b/pkg/controller/association/controller/apm_kibana.go @@ -33,9 +33,9 @@ func AddApmKibana(mgr manager.Manager, accessReviewer rbac.AccessReviewer, param AssociationName: "apm-kibana", AssociationLabels: func(associated types.NamespacedName) map[string]string { return map[string]string{ - ApmAssociationLabelName: associated.Name, - ApmAssociationLabelNamespace: associated.Namespace, - ApmAssociationTypeLabelNamespace: "kibana", + ApmAssociationLabelName: associated.Name, + ApmAssociationLabelNamespace: associated.Namespace, + ApmAssociationLabelType: "kibana", } }, UserSecretSuffix: "apm-kb-user", diff --git a/pkg/controller/association/controller/beat_es.go b/pkg/controller/association/controller/beat_es.go index 97aea1451a7..7126e40c23d 100644 --- a/pkg/controller/association/controller/beat_es.go +++ b/pkg/controller/association/controller/beat_es.go @@ -20,16 +20,17 @@ import ( ) const ( - // BeatESAssociationLabelName marks resources created by this controller for easier retrieval. - BeatESAssociationLabelName = "beatassociation.k8s.elastic.co/name" - - // BeatESAssociationLabelNamespace marks resources created by this controller for easier retrieval. - BeatESAssociationLabelNamespace = "beatassociation.k8s.elastic.co/namespace" + // BeatAssociationLabelName marks resources created by this controller for easier retrieval. + BeatAssociationLabelName = "beatassociation.k8s.elastic.co/name" + // BeatAssociationLabelNamespace marks resources created by this controller for easier retrieval. + BeatAssociationLabelNamespace = "beatassociation.k8s.elastic.co/namespace" + // BeatAssociationLabelType marks the type of association + BeatAssociationLabelType = "beatassociation.k8s.elastic.co/type" ) func AddBeatES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params operator.Parameters) error { return association.AddAssociationController(mgr, accessReviewer, params, association.AssociationInfo{ - AssociationObjTemplate: func() commonv1.Association { return &beatv1beta1.Beat{} }, + AssociationObjTemplate: func() commonv1.Association { return &beatv1beta1.BeatESAssociation{} }, ElasticsearchRef: func(c k8s.Client, association commonv1.Association) (bool, commonv1.ObjectSelector, error) { return true, association.AssociationRef(), nil }, @@ -39,8 +40,9 @@ func AddBeatES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params o AssociatedShortName: "beat", AssociationLabels: func(associated types.NamespacedName) map[string]string { return map[string]string{ - BeatESAssociationLabelName: associated.Name, - BeatESAssociationLabelNamespace: associated.Namespace, + BeatAssociationLabelName: associated.Name, + BeatAssociationLabelNamespace: associated.Namespace, + BeatAssociationLabelType: commonv1.ElasticsearchAssociationType, } }, UserSecretSuffix: "beat-user", diff --git a/pkg/controller/beat/common/config.go b/pkg/controller/beat/common/config.go index 633dcc50e31..bfcd2d10e9d 100644 --- a/pkg/controller/beat/common/config.go +++ b/pkg/controller/beat/common/config.go @@ -13,7 +13,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" beatv1beta1 "github.com/elastic/cloud-on-k8s/pkg/apis/beat/v1beta1" - 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" "github.com/elastic/cloud-on-k8s/pkg/controller/common/reconciler" @@ -22,39 +21,54 @@ import ( ) // setOutput will set the output section in Beat config according to the association configuration. -func setOutput(cfg *settings.CanonicalConfig, client k8s.Client, associated commonv1.Association) error { +func buildOutputConfig(client k8s.Client, associated beatv1beta1.BeatESAssociation) (*settings.CanonicalConfig, error) { if !associated.AssociationConf().IsConfigured() { - return nil + return settings.NewCanonicalConfig(), nil } - username, password, err := association.ElasticsearchAuthSettings(client, associated) + username, password, err := association.ElasticsearchAuthSettings(client, &associated) if err != nil { - return err + return settings.NewCanonicalConfig(), err } - esOutput := settings.MustCanonicalConfig( - map[string]interface{}{ - "output.elasticsearch": map[string]interface{}{ - "hosts": []string{associated.AssociationConf().GetURL()}, - "username": username, - "password": password, - }, - }) - - if err := cfg.MergeWith(esOutput); err != nil { - return err + esOutput := map[string]interface{}{ + "output.elasticsearch": map[string]interface{}{ + "hosts": []string{associated.AssociationConf().GetURL()}, + "username": username, + "password": password, + }, } if associated.AssociationConf().GetCACertProvided() { - if err := cfg.MergeWith(settings.MustCanonicalConfig( - map[string]interface{}{ - "output.elasticsearch.ssl.certificate_authorities": path.Join(CAMountPath, CAFileName), - })); err != nil { - return err - } + esOutput["output.elasticsearch.ssl.certificate_authorities"] = []string{path.Join(certificatesDir(&associated), CAFileName)} } - return nil + return settings.MustCanonicalConfig(esOutput), nil +} + +func buildKibanaConfig(client k8s.Client, associated beatv1beta1.BeatKibanaAssociation) (*settings.CanonicalConfig, error) { + if !associated.AssociationConf().IsConfigured() { + return settings.NewCanonicalConfig(), nil + } + + username, password, err := association.ElasticsearchAuthSettings(client, &associated) + if err != nil { + return settings.NewCanonicalConfig(), err + } + + kibanaCfg := map[string]interface{}{ + "setup.dashboards.enabled": true, + "setup.kibana": map[string]interface{}{ + "host": associated.AssociationConf().GetURL(), + "username": username, + "password": password, + }, + } + + if associated.AssociationConf().GetCACertProvided() { + kibanaCfg["setup.kibana.ssl.certificate_authorities"] = []string{path.Join(certificatesDir(&associated), CAFileName)} + } + return settings.MustCanonicalConfig(kibanaCfg), nil } func buildBeatConfig( @@ -65,10 +79,16 @@ func buildBeatConfig( ) ([]byte, error) { cfg := settings.NewCanonicalConfig() - if err := setOutput(cfg, client, &beat); err != nil { + outputCfg, err := buildOutputConfig(client, beatv1beta1.BeatESAssociation{Beat: &beat}) + if err != nil { return nil, err } + kibanaCfg, err := buildKibanaConfig(client, beatv1beta1.BeatKibanaAssociation{Beat: &beat}) + err = cfg.MergeWith(outputCfg, kibanaCfg) + if err != nil { + return nil, err + } // use only the default config or only the provided config - no overriding, no merging userConfig := beat.Spec.Config if userConfig == nil { diff --git a/pkg/controller/beat/common/driver.go b/pkg/controller/beat/common/driver.go index 1257581e35e..56e5aa30b2a 100644 --- a/pkg/controller/beat/common/driver.go +++ b/pkg/controller/beat/common/driver.go @@ -76,7 +76,7 @@ func Reconcile( } // we need to deref the secret here (if any) to include it in the configHash otherwise Beat will not be rolled on content changes - if err := commonassociation.WriteAssocToConfigHash(params.Client, ¶ms.Beat, configHash); err != nil { + if err := commonassociation.WriteAssocToConfigHash(params.Client, params.Beat.GetAssociations(), configHash); err != nil { return results.WithError(err) } diff --git a/pkg/controller/beat/common/health.go b/pkg/controller/beat/common/health.go index 675d371e108..aac7343c2d0 100644 --- a/pkg/controller/beat/common/health.go +++ b/pkg/controller/beat/common/health.go @@ -10,9 +10,11 @@ import ( ) // CalculateHealth returns health of the Beat based on association status, desired count and ready count. -func CalculateHealth(associated v1.Association, ready, desired int32) beatv1beta1.BeatHealth { - if associated.AssociationConf().IsConfigured() && associated.AssociationStatus() != v1.AssociationEstablished { - return beatv1beta1.BeatRedHealth +func CalculateHealth(associated []v1.Association, ready, desired int32) beatv1beta1.BeatHealth { + for _, assoc := range associated { + if assoc.AssociationConf().IsConfigured() && assoc.AssociationStatus() != v1.AssociationEstablished { + return beatv1beta1.BeatRedHealth + } } switch { diff --git a/pkg/controller/beat/common/pod.go b/pkg/controller/beat/common/pod.go index ced1e0a7295..5d8b789826e 100644 --- a/pkg/controller/beat/common/pod.go +++ b/pkg/controller/beat/common/pod.go @@ -8,6 +8,7 @@ import ( "fmt" "hash" + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -19,9 +20,8 @@ import ( ) const ( - CAVolumeName = "es-certs" - CAMountPath = "/mnt/elastic-internal/es-certs/" - CAFileName = "ca.crt" + CABaseMountPath = "/mnt/elastic-internal/" + CAFileName = "ca.crt" ConfigVolumeName = "config" ConfigMountPath = "/etc/beat.yml" @@ -51,6 +51,10 @@ var ( } ) +func certificatesDir(association commonv1.Association) string { + return fmt.Sprintf("%s/%s-certs", CABaseMountPath, association.AssociatedType()) +} + func buildPodTemplate( params DriverParams, defaultImage container.Image, @@ -114,11 +118,18 @@ func buildPodTemplate( dataVolume, } - if params.Beat.AssociationConf().CAIsConfigured() { - volumes = append(volumes, volume.NewSecretVolumeWithMountPath( - params.Beat.AssociationConf().GetCASecretName(), - CAVolumeName, - CAMountPath)) + for _, association := range params.Beat.GetAssociations() { + if !association.AssociationConf().CAIsConfigured() { + continue + } + caSecretName := association.AssociationConf().GetCASecretName() + caVolume := volume.NewSecretVolumeWithMountPath( + caSecretName, + association.AssociatedType()+"-certs", + certificatesDir(association), + ) + volumes = append(volumes, caVolume) + } for _, v := range volumes { diff --git a/pkg/controller/beat/common/reconcile.go b/pkg/controller/beat/common/reconcile.go index e078d5aa510..2c519fe86c4 100644 --- a/pkg/controller/beat/common/reconcile.go +++ b/pkg/controller/beat/common/reconcile.go @@ -137,8 +137,7 @@ func updateStatus(params DriverParams, ready, desired int32) error { beat.Status.AvailableNodes = ready beat.Status.ExpectedNodes = desired - beat.Status.Health = CalculateHealth(&beat, ready, desired) - beat.Status.Association = beat.AssociationStatus() + beat.Status.Health = CalculateHealth(beat.GetAssociations(), ready, desired) return params.Client.Status().Update(&beat) } diff --git a/pkg/controller/beat/controller.go b/pkg/controller/beat/controller.go index 61be0d1f319..ad65646d35e 100644 --- a/pkg/controller/beat/controller.go +++ b/pkg/controller/beat/controller.go @@ -180,7 +180,7 @@ func (r *ReconcileBeat) Reconcile(request reconcile.Request) (reconcile.Result, func (r *ReconcileBeat) doReconcile(ctx context.Context, beat beatv1beta1.Beat) *reconciler.Results { results := reconciler.NewResult(ctx) - if !association.IsConfiguredIfSet(&beat, r.recorder) { + if !association.AreConfiguredIfSet(beat.GetAssociations(), r.recorder) { return results } diff --git a/pkg/controller/common/association/association.go b/pkg/controller/common/association/association.go index 0d9836b1613..50d8b0de17d 100644 --- a/pkg/controller/common/association/association.go +++ b/pkg/controller/common/association/association.go @@ -17,12 +17,16 @@ import ( ) // WriteAssocToConfigHash dereferences auth secret (if any) to include it in the configHash. -func WriteAssocToConfigHash(client k8s.Client, assoc commonv1.Association, configHash hash.Hash) error { - if err := writeAuthSecretToConfigHash(client, assoc, configHash); err != nil { - return err +func WriteAssocToConfigHash(client k8s.Client, associations []commonv1.Association, configHash hash.Hash) error { + for _, assoc := range associations { + if err := writeAuthSecretToConfigHash(client, assoc, configHash); err != nil { + return err + } + if err := writeCASecretToConfigHash(client, assoc, configHash); err != nil { + return err + } } - - return writeCASecretToConfigHash(client, assoc, configHash) + return nil } func writeAuthSecretToConfigHash(client k8s.Client, assoc commonv1.Association, configHash hash.Hash) error { diff --git a/pkg/controller/elasticsearch/user/roles.go b/pkg/controller/elasticsearch/user/roles.go index f47ffa011eb..f2734ed6824 100644 --- a/pkg/controller/elasticsearch/user/roles.go +++ b/pkg/controller/elasticsearch/user/roles.go @@ -28,6 +28,9 @@ const ( // ApmAgentUserRole is the name of the role used by APMServer instances to connect to Kibana ApmAgentUserRole = "eck_apm_agent_user_role" + + // KibanaUserBuiltinRole is the name of the built-in Kibana user role + KibanaUserBuiltinRole = "kibana_user" ) var ( diff --git a/pkg/controller/kibana/driver.go b/pkg/controller/kibana/driver.go index 6f3faae13ff..a85676a1349 100644 --- a/pkg/controller/kibana/driver.go +++ b/pkg/controller/kibana/driver.go @@ -212,7 +212,7 @@ func (d *driver) deploymentParams(kb *kbv1.Kibana) (deployment.Params, error) { } // we need to deref the secret here to include it in the checksum otherwise Kibana will not be rolled on contents changes - if err := commonassociation.WriteAssocToConfigHash(d.client, kb, configChecksum); err != nil { + if err := commonassociation.WriteAssocToConfigHash(d.client, kb.GetAssociations(), configChecksum); err != nil { return deployment.Params{}, err }