From 12f5a4c6f6eeaad1fb03bed3c95eb74e822e1a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraci=20Paix=C3=A3o=20Kr=C3=B6hling?= Date: Thu, 18 Oct 2018 11:28:01 +0200 Subject: [PATCH] Added e2e tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juraci Paixão Kröhling --- CONTRIBUTING.adoc | 3 +- Makefile | 2 +- README.adoc | 47 ++++++++++++++++++++ deploy/rbac.yaml | 7 ++- pkg/storage/cassandra_dependencies.go | 5 ++- test/e2e/cassandra.go | 63 +++++++++++++++++++++++++++ test/e2e/jaeger_test.go | 1 + test/e2e/wait_util.go | 26 +++++++++++ 8 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 test/e2e/cassandra.go diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index a4e97ba28..c3b9a06b3 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -111,9 +111,10 @@ Accessing the provided "address" in your web browser should display the Jaeger U ==== Storage configuration -There's a template under the `test` directory that can be used to setup an Elasticsearch cluster. Alternatively, the following command can be executed to install it: +There are a set of templates under the `test` directory that can be used to setup an Elasticsearch and/or Cassandra cluster. Alternatively, the following commands can be executed to install it: [source,bash] ---- make es +make cassandra ---- diff --git a/Makefile b/Makefile index 31f6395a9..fd72a90c1 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ unit-tests: @go test $(PACKAGES) -cover -coverprofile=cover.out .PHONY: e2e-tests -e2e-tests: es crd build docker push +e2e-tests: cassandra es crd build docker push @echo Running end-to-end tests... @cp deploy/rbac.yaml deploy/test/namespace-manifests.yaml @echo "---" >> deploy/test/namespace-manifests.yaml diff --git a/README.adoc b/README.adoc index b46b35fb8..ff165c105 100644 --- a/README.adoc +++ b/README.adoc @@ -242,6 +242,53 @@ spec: fieldPath: status.hostIP ---- +== Schema migration + +=== Cassandra + +When the storage type is set to Cassandra, the operator will automatically create a batch job that creates the required schema for Jaeger to run. This batch job will block the Jaeger installation, so that it starts only after the schema is successfuly created. The creation of this batch job can be disabled by setting the `enabled` property to `false`: + +[source,yaml] +---- +apiVersion: io.jaegertracing/v1alpha1 +kind: Jaeger +metadata: + name: cassandra-without-create-schema +spec: + strategy: all-in-one + storage: + type: cassandra + cassandra-create-schema: + enabled: false # <1> +---- +<1> Defaults to `true` + +Further aspects of the batch job can be configured as well. An example with all the possible options is shown below: + +[source,yaml] +---- +apiVersion: io.jaegertracing/v1alpha1 +kind: Jaeger +metadata: + name: cassandra-with-create-schema +spec: + strategy: all-in-one # <1> + storage: + type: cassandra + options: # <2> + cassandra: + servers: cassandra + keyspace: jaeger_v1_datacenter3 + cassandra-create-schema: # <3> + datacenter: "datacenter3" + mode: "test" +---- +<1> The same works for `production` +<2> These options are for the regular Jaeger components, like `collector` and `query` +<3> The options for the `create-schema` job + +NOTE: the default create-schema job uses `MODE=prod`, which implies a replication factor of `2`, using `NetworkTopologyStrategy` as the class, effectively meaning that at least 3 nodes are required in the Cassandra cluster. If a `SimpleStrategy` is desired, set the mode to `test`, which then sets the replication factor of `1`. Refer to the link:https://github.com/jaegertracing/jaeger/blob/v1.7.0/plugin/storage/cassandra/schema/create.sh[create-schema script] for more details. + == Removing an instance To remove an instance, just use the `delete` command with the file used for the instance creation: diff --git a/deploy/rbac.yaml b/deploy/rbac.yaml index 05f4f7fae..f647aee6c 100644 --- a/deploy/rbac.yaml +++ b/deploy/rbac.yaml @@ -36,7 +36,12 @@ rules: - ingresses verbs: - "*" - +- apiGroups: + - batch + resources: + - jobs + verbs: + - "*" --- kind: RoleBinding diff --git a/pkg/storage/cassandra_dependencies.go b/pkg/storage/cassandra_dependencies.go index 208c751b4..631cb342d 100644 --- a/pkg/storage/cassandra_dependencies.go +++ b/pkg/storage/cassandra_dependencies.go @@ -25,8 +25,9 @@ func cassandraDeps(jaeger *v1alpha1.Jaeger) []batchv1.Job { } if jaeger.Spec.Storage.CassandraCreateSchema.Datacenter == "" { - logrus.WithField("instance", jaeger.Name).Info("Datacenter not specified. Using 'dc1' for the cassandra-create-schema job.") - jaeger.Spec.Storage.CassandraCreateSchema.Datacenter = "dc1" + // the default in the create-schema is "dc1", but the default in Jaeger is "test"! We align with Jaeger here + logrus.WithField("instance", jaeger.Name).Info("Datacenter not specified. Using 'test' for the cassandra-create-schema job.") + jaeger.Spec.Storage.CassandraCreateSchema.Datacenter = "test" } if jaeger.Spec.Storage.CassandraCreateSchema.Mode == "" { diff --git a/test/e2e/cassandra.go b/test/e2e/cassandra.go new file mode 100644 index 000000000..d740d87a7 --- /dev/null +++ b/test/e2e/cassandra.go @@ -0,0 +1,63 @@ +package e2e + +import ( + goctx "context" + "fmt" + "testing" + + "github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1" + framework "github.com/operator-framework/operator-sdk/pkg/test" + "github.com/operator-framework/operator-sdk/pkg/test/e2eutil" + "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Cassandra runs a test with Cassandra as the backing storage +func Cassandra(t *testing.T) { + ctx := prepare(t) + defer ctx.Cleanup() + + if err := cassandraTest(t, framework.Global, ctx); err != nil { + t.Fatal(err) + } +} + +func cassandraTest(t *testing.T, f *framework.Framework, ctx *framework.TestCtx) error { + cleanupOptions := &framework.CleanupOptions{TestContext: ctx, Timeout: timeout, RetryInterval: retryInterval} + namespace, err := ctx.GetNamespace() + if err != nil { + return fmt.Errorf("could not get namespace: %v", err) + } + + j := &v1alpha1.Jaeger{ + TypeMeta: metav1.TypeMeta{ + Kind: "Jaeger", + APIVersion: "io.jaegertracing/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "with-cassandra", + Namespace: namespace, + }, + Spec: v1alpha1.JaegerSpec{ + Strategy: "all-in-one", + AllInOne: v1alpha1.JaegerAllInOneSpec{}, + Storage: v1alpha1.JaegerStorageSpec{ + Type: "cassandra", + Options: v1alpha1.NewOptions(map[string]interface{}{"cassandra.servers": "cassandra.default.svc"}), + }, + }, + } + + logrus.Infof("passing %v", j) + err = f.Client.Create(goctx.TODO(), j, cleanupOptions) + if err != nil { + return err + } + + err = WaitForJob(t, f.KubeClient, namespace, "with-cassandra-cassandra-schema-job", retryInterval, timeout) + if err != nil { + return err + } + + return e2eutil.WaitForDeployment(t, f.KubeClient, namespace, "with-cassandra", 1, retryInterval, timeout) +} diff --git a/test/e2e/jaeger_test.go b/test/e2e/jaeger_test.go index 74c7f4e14..401ee1858 100644 --- a/test/e2e/jaeger_test.go +++ b/test/e2e/jaeger_test.go @@ -37,6 +37,7 @@ func TestJaeger(t *testing.T) { t.Run("daemonset", DaemonSet) t.Run("sidecar", Sidecar) + t.Run("cassandra", Cassandra) }) } diff --git a/test/e2e/wait_util.go b/test/e2e/wait_util.go index a638de734..c1993f6c6 100644 --- a/test/e2e/wait_util.go +++ b/test/e2e/wait_util.go @@ -87,3 +87,29 @@ func WaitForIngress(t *testing.T, kubeclient kubernetes.Interface, namespace, na t.Logf("Ingress available\n") return nil } + +// WaitForJob checks to see if a given job has the completed successfuly +// See #WaitForDeployment for the full semantics +func WaitForJob(t *testing.T, kubeclient kubernetes.Interface, namespace, name string, retryInterval, timeout time.Duration) error { + err := wait.Poll(retryInterval, timeout, func() (done bool, err error) { + job, err := kubeclient.BatchV1().Jobs(namespace).Get(name, metav1.GetOptions{IncludeUninitialized: true}) + if err != nil { + if apierrors.IsNotFound(err) { + t.Logf("Waiting for availability of %s job\n", name) + return false, nil + } + return false, err + } + + if job.Status.Succeeded > 0 && job.Status.Failed == 0 && job.Status.Active == 0 { + return true, nil + } + t.Logf("Waiting for job %s to succeed. Succeeded: %d, failed: %d, active: %d\n", name, job.Status.Succeeded, job.Status.Failed, job.Status.Active) + return false, nil + }) + if err != nil { + return err + } + t.Logf("Jobs succeeded\n") + return nil +}