pkg/controller/remotecluster/fixtures.go (164 lines of code) (raw):
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License 2.0;
// you may not use this file except in compliance with the Elastic License 2.0.
package remotecluster
import (
"context"
"fmt"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
commonv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/common/v1"
esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1"
"github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/certificates"
"github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/certificates/transport"
esclient "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client"
)
// -- Fake ES client
type fakeESClient struct {
esclient.Client
// fake responses
getCrossClusterAPIKeys []string
// recorded requests
invalidateCrossClusterAPIKey []string
crossClusterAPIKeyCreateRequests []esclient.CrossClusterAPIKeyCreateRequest
existingCrossClusterAPIKeys esclient.CrossClusterAPIKeyList
updateCrossClusterAPIKey map[string]esclient.CrossClusterAPIKeyUpdateRequest
}
func (f *fakeESClient) CreateCrossClusterAPIKey(ctx context.Context, crossClusterAPIKeyCreateRequest esclient.CrossClusterAPIKeyCreateRequest) (esclient.CrossClusterAPIKeyCreateResponse, error) {
f.crossClusterAPIKeyCreateRequests = append(f.crossClusterAPIKeyCreateRequests, crossClusterAPIKeyCreateRequest)
return esclient.CrossClusterAPIKeyCreateResponse{
ID: fmt.Sprintf("generated-id-from-fake-es-client-%s", crossClusterAPIKeyCreateRequest.Name),
Name: crossClusterAPIKeyCreateRequest.Name,
Encoded: fmt.Sprintf("generated-encoded-key-from-fake-es-client-for-%s", crossClusterAPIKeyCreateRequest.Name),
}, nil
}
func (f *fakeESClient) GetCrossClusterAPIKeys(_ context.Context, name string) (esclient.CrossClusterAPIKeyList, error) {
f.getCrossClusterAPIKeys = append(f.getCrossClusterAPIKeys, name)
return f.existingCrossClusterAPIKeys, nil
}
func (f *fakeESClient) InvalidateCrossClusterAPIKey(_ context.Context, name string) error {
f.invalidateCrossClusterAPIKey = append(f.invalidateCrossClusterAPIKey, name)
return nil
}
func (f *fakeESClient) UpdateCrossClusterAPIKey(_ context.Context, name string, updateRequest esclient.CrossClusterAPIKeyUpdateRequest) (esclient.CrossClusterAPIKeyUpdateResponse, error) {
if f.updateCrossClusterAPIKey == nil {
f.updateCrossClusterAPIKey = make(map[string]esclient.CrossClusterAPIKeyUpdateRequest)
}
f.updateCrossClusterAPIKey[name] = updateRequest
return esclient.CrossClusterAPIKeyUpdateResponse{}, nil
}
// -- Fake cluster builder
type clusterBuilder struct {
name, namespace, version string
remoteClusters []esv1.RemoteCluster
}
func newClusterBuilder(namespace, name, version string) *clusterBuilder {
return &clusterBuilder{
name: name,
namespace: namespace,
version: version,
}
}
func (cb *clusterBuilder) withRemoteCluster(namespace, name string) *clusterBuilder {
cb.remoteClusters = append(cb.remoteClusters,
esv1.RemoteCluster{
Name: fmt.Sprintf("alias-from-%s-%s-to-%s-%s", cb.namespace, cb.name, namespace, name),
ElasticsearchRef: commonv1.LocalObjectSelector{
Name: name,
Namespace: namespace,
},
})
return cb
}
func (cb *clusterBuilder) withAPIKey(namespace, name string, apiKey *esv1.RemoteClusterAPIKey) *clusterBuilder {
cb.remoteClusters = append(cb.remoteClusters,
esv1.RemoteCluster{
Name: fmt.Sprintf("generated-alias-from-%s-%s-to-%s-%s-with-api-key", cb.namespace, cb.name, namespace, name),
ElasticsearchRef: commonv1.LocalObjectSelector{
Name: name,
Namespace: namespace,
},
APIKey: apiKey,
})
return cb
}
func (cb *clusterBuilder) build() []client.Object {
remoteClusters := make([]esv1.RemoteCluster, len(cb.remoteClusters))
for i, remoteCluster := range cb.remoteClusters {
remoteCluster := remoteCluster.DeepCopy()
remoteClusters[i] = *remoteCluster
}
return []client.Object{
&esv1.Elasticsearch{
ObjectMeta: v1.ObjectMeta{
Namespace: cb.namespace,
Name: cb.name,
},
Spec: esv1.ElasticsearchSpec{
Version: cb.version,
RemoteClusters: remoteClusters,
},
Status: esv1.ElasticsearchStatus{
AvailableNodes: 3,
Version: cb.version,
},
},
&corev1.Pod{
ObjectMeta: v1.ObjectMeta{
Namespace: cb.namespace,
Name: fmt.Sprintf("es-%s-%s-1", cb.namespace, cb.name),
Labels: map[string]string{
label.ClusterNameLabelName: cb.name,
},
},
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
},
},
}
}
type fakeAccessReviewer struct {
allowed bool
err error
}
func (f *fakeAccessReviewer) AccessAllowed(_ context.Context, _ string, _ string, _ runtime.Object) (bool, error) {
return f.allowed, f.err
}
func fakePublicCa(namespace, name string) *corev1.Secret {
namespacedName := types.NamespacedName{
Name: name,
Namespace: namespace,
}
transportPublicCertKey := transport.PublicCertsSecretRef(namespacedName)
return &corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: transportPublicCertKey.Namespace,
Name: transportPublicCertKey.Name,
},
Data: map[string][]byte{
certificates.CAFileName: []byte(namespacedName.String()),
},
}
}
// remoteCa builds an expected remote Ca
func remoteCa(localNamespace, localName, remoteNamespace, remoteName string) *corev1.Secret {
remoteNamespacedName := types.NamespacedName{
Name: remoteName,
Namespace: remoteNamespace,
}
return &corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: localNamespace,
Name: remoteCASecretName(localName, remoteNamespacedName),
Labels: map[string]string{
"common.k8s.elastic.co/type": "remote-ca",
"elasticsearch.k8s.elastic.co/cluster-name": localName,
"elasticsearch.k8s.elastic.co/remote-cluster-name": remoteName,
"elasticsearch.k8s.elastic.co/remote-cluster-namespace": remoteNamespace,
},
},
Data: map[string][]byte{
certificates.CAFileName: []byte(remoteNamespacedName.String()),
},
}
}
func withDataCert(caSecret *corev1.Secret, newCa []byte) *corev1.Secret {
caSecret.Data[certificates.CAFileName] = newCa
return caSecret
}