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

Add support for Cassandra create-schema job #71

Merged
merged 3 commits into from
Oct 19, 2018
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
3 changes: 2 additions & 1 deletion CONTRIBUTING.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
----
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -68,6 +68,10 @@ run: crd
es:
@kubectl create -f ./test/elasticsearch.yml 2>&1 | grep -v "already exists" || true

.PHONY: cassandra
cassandra:
@kubectl create -f ./test/cassandra.yml 2>&1 | grep -v "already exists" || true

.PHONY: crd
crd:
@kubectl create -f deploy/crd.yaml 2>&1 | grep -v "already exists" || true
Expand Down
47 changes: 47 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering if it would be safer to default to false? If someone is using an existing jaeger cassandra storage - what is the impact of the job running, is it a noop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current scripts are noop, as they have an "if not exists" clause:

https://github.com/jaegertracing/jaeger/blob/7d9d212b6d947742055fb4e38180152da687acf5/plugin/storage/cassandra/schema/v001.cql.tmpl#L25

But it might be a good idea to add a flag to the binary, to get this enabled/disabled by default, as we discussed today in the meeting. Something for a follow up PR, to be discussed with the ES parts?


[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:
Expand Down
15 changes: 15 additions & 0 deletions deploy/examples/with-cassandra.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: io.jaegertracing/v1alpha1
kind: Jaeger
metadata:
name: with-cassandra
spec:
strategy: all-in-one
storage:
type: cassandra
options:
cassandra:
servers: cassandra
keyspace: jaeger_v1_datacenter3
cassandra-create-schema:
datacenter: "datacenter3"
mode: "test"
7 changes: 6 additions & 1 deletion deploy/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ rules:
- ingresses
verbs:
- "*"

- apiGroups:
- batch
resources:
- jobs
verbs:
- "*"
---

kind: RoleBinding
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/io/v1alpha1/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,9 @@ func (o *Options) ToArgs() []string {

return nil
}

// Map returns a map representing the option entries. Items are flattened, with dots as separators. For instance
// an option "cassandra" with a nested "servers" object becomes an entry with the key "cassandra.servers"
func (o *Options) Map() map[string]string {
return o.opts
}
6 changes: 6 additions & 0 deletions pkg/apis/io/v1alpha1/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,9 @@ func TestMultipleSubValues(t *testing.T) {
args := o.ToArgs()
assert.Len(t, args, 3)
}

func TestExposedMap(t *testing.T) {
o := NewOptions(nil)
o.UnmarshalJSON([]byte(`{"cassandra": {"servers": "cassandra:9042"}}`))
assert.Equal(t, "cassandra:9042", o.Map()["cassandra.servers"])
}
13 changes: 11 additions & 2 deletions pkg/apis/io/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ type JaegerAgentSpec struct {

// JaegerStorageSpec defines the common storage options to be used for the query and collector
type JaegerStorageSpec struct {
Type string `json:"type"` // can be `memory` (default), `cassandra`, `elasticsearch`, `kafka` or `managed`
Options Options `json:"options"`
Type string `json:"type"` // can be `memory` (default), `cassandra`, `elasticsearch`, `kafka` or `managed`
Options Options `json:"options"`
CassandraCreateSchema JaegerCassandraCreateSchemaSpec `json:"cassandra-create-schema"`
}

// JaegerCassandraCreateSchemaSpec holds the options related to the create-schema batch job
type JaegerCassandraCreateSchemaSpec struct {
Enabled *bool `json:"enabled"`
Image string `json:"image"`
Datacenter string `json:"datacenter"`
Mode string `json:"mode"`
}
17 changes: 17 additions & 0 deletions pkg/apis/io/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/cmd/start/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func NewStartCommand() *cobra.Command {
cmd.Flags().StringP("jaeger-all-in-one-image", "", "jaegertracing/all-in-one", "The Docker image for the Jaeger all-in-one")
viper.BindPFlag("jaeger-all-in-one-image", cmd.Flags().Lookup("jaeger-all-in-one-image"))

cmd.Flags().StringP("jaeger-cassandra-schema-image", "", "jaegertracing/jaeger-cassandra-schema", "The Docker image for the Jaeger Cassandra Schema")
viper.BindPFlag("jaeger-cassandra-schema-image", cmd.Flags().Lookup("jaeger-cassandra-schema-image"))

return cmd
}

Expand Down
10 changes: 8 additions & 2 deletions pkg/controller/all-in-one.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (

"github.com/operator-framework/operator-sdk/pkg/sdk"
"github.com/sirupsen/logrus"
batchv1 "k8s.io/api/batch/v1"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
"github.com/jaegertracing/jaeger-operator/pkg/deployment"
"github.com/jaegertracing/jaeger-operator/pkg/storage"
)

type allInOneController struct {
Expand All @@ -22,7 +24,7 @@ func newAllInOneController(ctx context.Context, jaeger *v1alpha1.Jaeger) *allInO
}
}

func (c allInOneController) Create() []sdk.Object {
func (c *allInOneController) Create() []sdk.Object {
logrus.Debugf("Creating all-in-one for '%v'", c.jaeger.Name)

dep := deployment.NewAllInOne(c.jaeger)
Expand All @@ -43,7 +45,11 @@ func (c allInOneController) Create() []sdk.Object {
return os
}

func (c allInOneController) Update() []sdk.Object {
func (c *allInOneController) Update() []sdk.Object {
logrus.Debug("Update isn't available for all-in-one")
return []sdk.Object{}
}

func (c *allInOneController) Dependencies() []batchv1.Job {
return storage.Dependencies(c.jaeger)
}
7 changes: 7 additions & 0 deletions pkg/controller/all-in-one_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"

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

func init() {
Expand Down Expand Up @@ -41,6 +42,12 @@ func TestUpdateAllInOneDeployment(t *testing.T) {
assert.Len(t, objs, 0)
}

func TestDelegateAllInOneDepedencies(t *testing.T) {
// for now, we just have storage dependencies
c := newAllInOneController(context.TODO(), v1alpha1.NewJaeger("TestDelegateAllInOneDepedencies"))
assert.Equal(t, c.Dependencies(), storage.Dependencies(c.jaeger))
}

func assertDeploymentsAndServicesForAllInOne(t *testing.T, name string, objs []sdk.Object, hasDaemonSet bool) {
if hasDaemonSet {
assert.Len(t, objs, 7)
Expand Down
2 changes: 2 additions & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (

"github.com/operator-framework/operator-sdk/pkg/sdk"
"github.com/sirupsen/logrus"
batchv1 "k8s.io/api/batch/v1"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
)

// Controller knows what type of deployments to build based on a given spec
type Controller interface {
Dependencies() []batchv1.Job
Create() []sdk.Object
Update() []sdk.Object
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/controller/production.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (

"github.com/operator-framework/operator-sdk/pkg/sdk"
"github.com/sirupsen/logrus"
batchv1 "k8s.io/api/batch/v1"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
"github.com/jaegertracing/jaeger-operator/pkg/deployment"
"github.com/jaegertracing/jaeger-operator/pkg/storage"
)

type productionController struct {
Expand Down Expand Up @@ -56,3 +58,7 @@ func (c *productionController) Update() []sdk.Object {
logrus.Debug("Update isn't yet available")
return []sdk.Object{}
}

func (c *productionController) Dependencies() []batchv1.Job {
return storage.Dependencies(c.jaeger)
}
7 changes: 7 additions & 0 deletions pkg/controller/production_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

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

func init() {
Expand Down Expand Up @@ -77,6 +78,12 @@ func TestOptionsArePassed(t *testing.T) {
}
}

func TestDelegateProductionDepedencies(t *testing.T) {
// for now, we just have storage dependencies
c := newProductionController(context.TODO(), v1alpha1.NewJaeger("TestDelegateProductionDepedencies"))
assert.Equal(t, c.Dependencies(), storage.Dependencies(c.jaeger))
}

func assertDeploymentsAndServicesForProduction(t *testing.T, name string, objs []sdk.Object, hasDaemonSet bool) {
if hasDaemonSet {
assert.Len(t, objs, 7)
Expand Down
Loading