Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed deployment of Elasticsearch via its operator #234

Merged
merged 2 commits into from
Feb 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,13 @@ spec:

== Elasticsearch storage

If no `es.server-urls` are provided Jaeger operator creates Elasticsearch CR based on the configuration
provided in storage section. Make sure link:https://github.com/openshift/elasticsearch-operator[elasticsearch-operator]
is running in your cluster otherwise Elasticsearch deployment will not be created. The Elasticsearch is meant
to be dedicated for a single Jaeger instance.
Under some circumstances, the Jaeger Operator can make use of the Elasticsearch operator to provision a suitable Elasticsearch cluster.

At the moment there can be only one Jaeger with Elasticsearch instance in a namespace.
IMPORTANT: this feature is experimental and currently works only on OpenShift clusters. Elasticsearch also requires the memory setting to be configured like `minishift ssh -- 'sudo sysctl -w vm.max_map_count=262144'`

Note that Elasticsearch requires virtual memory settings: `minikube ssh -- 'sudo sysctl -w vm.max_map_count=262144'`
When there are no `es.server-urls` options as part of a Jaeger `production` instance, the Jaeger Operator creates an Elasticsearch cluster via the Elasticsearch Operator by creating a CR based on the configuration provided in storage section. Make sure link:https://github.com/openshift/elasticsearch-operator[elasticsearch-operator] is running in your cluster otherwise the Elasticsearch deployment will not be created. The Elasticsearch cluster is meant to be dedicated for a single Jaeger instance.

IMPORTANT: At the moment there can be only one Jaeger with self-provisioned Elasticsearch instance per namespace.

== Accessing the UI

Expand Down
3 changes: 2 additions & 1 deletion pkg/apis/addtoscheme_io_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package apis

import (
"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
esv1alpha1 "github.com/jaegertracing/jaeger-operator/pkg/storage/elasticsearch/v1alpha1"
)

func init() {
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme)
AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme, esv1alpha1.SchemeBuilder.AddToScheme)
}
6 changes: 0 additions & 6 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package controller

import (
routev1 "github.com/openshift/api/route/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/manager"

esv1alpha1 "github.com/jaegertracing/jaeger-operator/pkg/storage/elasticsearch/v1alpha1"
)

// AddToManagerFuncs is a list of functions to add all Controllers to the Manager
Expand All @@ -16,9 +13,6 @@ func AddToManager(m manager.Manager) error {
if err := routev1.AddToScheme(m.GetScheme()); err != nil {
return err
}
// TODO temporal fix https://github.com/jaegertracing/jaeger-operator/issues/206
gv := schema.GroupVersion{Group: "logging.openshift.io", Version: "v1alpha1"}
m.GetScheme().AddKnownTypes(gv, &esv1alpha1.Elasticsearch{})

for _, f := range AddToManagerFuncs {
if err := f(m); err != nil {
Expand Down
52 changes: 52 additions & 0 deletions pkg/controller/jaeger/elasticsearch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package jaeger

import (
"context"

log "github.com/sirupsen/logrus"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
"github.com/jaegertracing/jaeger-operator/pkg/inventory"
esv1alpha1 "github.com/jaegertracing/jaeger-operator/pkg/storage/elasticsearch/v1alpha1"
)

func (r *ReconcileJaeger) applyElasticsearches(jaeger v1alpha1.Jaeger, desired []esv1alpha1.Elasticsearch) error {
opts := client.MatchingLabels(map[string]string{
"app.kubernetes.io/instance": jaeger.Name,
"app.kubernetes.io/managed-by": "jaeger-operator",
})
list := &esv1alpha1.ElasticsearchList{}
if err := r.client.List(context.Background(), opts, list); err != nil {
return err
}

logFields := log.WithFields(log.Fields{
"namespace": jaeger.Namespace,
"instance": jaeger.Name,
})

inv := inventory.ForElasticsearches(list.Items, desired)
for _, d := range inv.Create {
logFields.WithField("elasticsearch", d.Name).Debug("creating elasticsearch")
if err := r.client.Create(context.Background(), &d); err != nil {
return err
}
}

for _, d := range inv.Update {
logFields.WithField("elasticsearch", d.Name).Debug("updating elasticsearch")
if err := r.client.Update(context.Background(), &d); err != nil {
return err
}
}

for _, d := range inv.Delete {
logFields.WithField("elasticsearch", d.Name).Debug("deleting elasticsearch")
if err := r.client.Delete(context.Background(), &d); err != nil {
return err
}
}

return nil
}
131 changes: 131 additions & 0 deletions pkg/controller/jaeger/elasticsearch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package jaeger

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
esv1alpha1 "github.com/jaegertracing/jaeger-operator/pkg/storage/elasticsearch/v1alpha1"
"github.com/jaegertracing/jaeger-operator/pkg/strategy"
)

func TestElasticsearchesCreate(t *testing.T) {
// prepare
nsn := types.NamespacedName{
Name: "TestElasticsearchesCreate",
}

objs := []runtime.Object{
v1alpha1.NewJaeger(nsn.Name),
}

req := reconcile.Request{
NamespacedName: nsn,
}

r, cl := getReconciler(objs)
r.strategyChooser = func(jaeger *v1alpha1.Jaeger) strategy.S {
s := strategy.New().WithElasticsearches([]esv1alpha1.Elasticsearch{{
ObjectMeta: metav1.ObjectMeta{
Name: nsn.Name,
},
}})
return s
}

// test
res, err := r.Reconcile(req)

// verify
assert.NoError(t, err)
assert.False(t, res.Requeue, "We don't requeue for now")

persisted := &esv1alpha1.Elasticsearch{}
persistedName := types.NamespacedName{
Name: nsn.Name,
Namespace: nsn.Namespace,
}
err = cl.Get(context.Background(), persistedName, persisted)
assert.Equal(t, persistedName.Name, persisted.Name)
assert.NoError(t, err)
}

func TestElasticsearchesUpdate(t *testing.T) {
// prepare
nsn := types.NamespacedName{
Name: "TestElasticsearchesUpdate",
}

orig := esv1alpha1.Elasticsearch{}
orig.Name = nsn.Name
orig.Annotations = map[string]string{"key": "value"}

objs := []runtime.Object{
v1alpha1.NewJaeger(nsn.Name),
&orig,
}

r, cl := getReconciler(objs)
r.strategyChooser = func(jaeger *v1alpha1.Jaeger) strategy.S {
updated := esv1alpha1.Elasticsearch{}
updated.Name = orig.Name
updated.Annotations = map[string]string{"key": "new-value"}

s := strategy.New().WithElasticsearches([]esv1alpha1.Elasticsearch{updated})
return s
}

// test
_, err := r.Reconcile(reconcile.Request{NamespacedName: nsn})
assert.NoError(t, err)

// verify
persisted := &esv1alpha1.Elasticsearch{}
persistedName := types.NamespacedName{
Name: orig.Name,
Namespace: orig.Namespace,
}
err = cl.Get(context.Background(), persistedName, persisted)
assert.Equal(t, "new-value", persisted.Annotations["key"])
assert.NoError(t, err)
}

func TestElasticsearchesDelete(t *testing.T) {
// prepare
nsn := types.NamespacedName{
Name: "TestElasticsearchesDelete",
}

orig := esv1alpha1.Elasticsearch{}
orig.Name = nsn.Name

objs := []runtime.Object{
v1alpha1.NewJaeger(nsn.Name),
&orig,
}

r, cl := getReconciler(objs)
r.strategyChooser = func(jaeger *v1alpha1.Jaeger) strategy.S {
return strategy.S{}
}

// test
_, err := r.Reconcile(reconcile.Request{NamespacedName: nsn})
assert.NoError(t, err)

// verify
persisted := &esv1alpha1.Elasticsearch{}
persistedName := types.NamespacedName{
Name: orig.Name,
Namespace: orig.Namespace,
}
err = cl.Get(context.Background(), persistedName, persisted)
assert.Empty(t, persisted.Name)
assert.Error(t, err) // not found
}
4 changes: 4 additions & 0 deletions pkg/controller/jaeger/jaeger_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ func defaultStrategyChooser(instance *v1alpha1.Jaeger) strategy.S {
}

func (r *ReconcileJaeger) apply(jaeger v1alpha1.Jaeger, str strategy.S) error {
if err := r.applyElasticsearches(jaeger, str.Elasticsearches()); err != nil {
return err
}

if err := r.applyRoles(jaeger, str.Roles()); err != nil {
return err
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/controller/jaeger/jaeger_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
esv1alpha1 "github.com/jaegertracing/jaeger-operator/pkg/storage/elasticsearch/v1alpha1"
"github.com/jaegertracing/jaeger-operator/pkg/strategy"
)

Expand Down Expand Up @@ -90,8 +91,16 @@ func TestDeletedInstance(t *testing.T) {

func getReconciler(objs []runtime.Object) (*ReconcileJaeger, client.Client) {
s := scheme.Scheme

// OpenShift Route
osv1.Install(s)

// Jaeger
s.AddKnownTypes(v1alpha1.SchemeGroupVersion, &v1alpha1.Jaeger{})

// Jaeger's Elasticsearch
s.AddKnownTypes(v1alpha1.SchemeGroupVersion, &esv1alpha1.Elasticsearch{}, &esv1alpha1.ElasticsearchList{})

cl := fake.NewFakeClient(objs...)
return &ReconcileJaeger{client: cl, scheme: s}, cl
}
62 changes: 62 additions & 0 deletions pkg/inventory/elasticsearch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package inventory

import (
esv1alpha1 "github.com/jaegertracing/jaeger-operator/pkg/storage/elasticsearch/v1alpha1"
)

// Elasticsearch represents the elastic search inventory based on the current and desired states
type Elasticsearch struct {
Create []esv1alpha1.Elasticsearch
Update []esv1alpha1.Elasticsearch
Delete []esv1alpha1.Elasticsearch
}

// ForElasticsearches builds a new elastic search inventory based on the existing and desired states
func ForElasticsearches(existing []esv1alpha1.Elasticsearch, desired []esv1alpha1.Elasticsearch) Elasticsearch {
update := []esv1alpha1.Elasticsearch{}
mcreate := esMap(desired)
mdelete := esMap(existing)

for k, v := range mcreate {
if t, ok := mdelete[k]; ok {
tp := t.DeepCopy()

tp.Spec = v.Spec
tp.ObjectMeta.OwnerReferences = v.ObjectMeta.OwnerReferences

for k, v := range v.ObjectMeta.Annotations {
tp.ObjectMeta.Annotations[k] = v
}

for k, v := range v.ObjectMeta.Labels {
tp.ObjectMeta.Labels[k] = v
}

update = append(update, *tp)
delete(mcreate, k)
delete(mdelete, k)
}
}

return Elasticsearch{
Create: esList(mcreate),
Update: update,
Delete: esList(mdelete),
}
}

func esMap(deps []esv1alpha1.Elasticsearch) map[string]esv1alpha1.Elasticsearch {
m := map[string]esv1alpha1.Elasticsearch{}
for _, d := range deps {
m[d.Name] = d
}
return m
}

func esList(m map[string]esv1alpha1.Elasticsearch) []esv1alpha1.Elasticsearch {
l := []esv1alpha1.Elasticsearch{}
for _, v := range m {
l = append(l, v)
}
return l
}
53 changes: 53 additions & 0 deletions pkg/inventory/elasticsearch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package inventory

import (
"testing"

"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

esv1alpha1 "github.com/jaegertracing/jaeger-operator/pkg/storage/elasticsearch/v1alpha1"
)

func TestElasticsearchInventory(t *testing.T) {
toCreate := esv1alpha1.Elasticsearch{
ObjectMeta: metav1.ObjectMeta{
Name: "to-create",
},
}
toUpdate := esv1alpha1.Elasticsearch{
ObjectMeta: metav1.ObjectMeta{
Name: "to-update",
},
Spec: esv1alpha1.ElasticsearchSpec{
ManagementState: esv1alpha1.ManagementStateManaged,
},
}
updated := esv1alpha1.Elasticsearch{
ObjectMeta: metav1.ObjectMeta{
Name: "to-update",
},
Spec: esv1alpha1.ElasticsearchSpec{
ManagementState: esv1alpha1.ManagementStateUnmanaged,
},
}
toDelete := esv1alpha1.Elasticsearch{
ObjectMeta: metav1.ObjectMeta{
Name: "to-delete",
},
}

existing := []esv1alpha1.Elasticsearch{toUpdate, toDelete}
desired := []esv1alpha1.Elasticsearch{updated, toCreate}

inv := ForElasticsearches(existing, desired)
assert.Len(t, inv.Create, 1)
assert.Equal(t, "to-create", inv.Create[0].Name)

assert.Len(t, inv.Update, 1)
assert.Equal(t, "to-update", inv.Update[0].Name)
assert.Equal(t, esv1alpha1.ManagementStateUnmanaged, inv.Update[0].Spec.ManagementState)

assert.Len(t, inv.Delete, 1)
assert.Equal(t, "to-delete", inv.Delete[0].Name)
}
Loading