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

Support self provisioned ES in streaming strategy #842

Merged

Conversation

pavolloffay
Copy link
Member

Signed-off-by: Pavol Loffay ploffay@redhat.com

Makefile Outdated
@@ -115,6 +115,11 @@ e2e-tests-self-provisioned-es: prepare-e2e-tests deploy-es-operator
@echo Running Self provisioned Elasticsearch end-to-end tests...
@STORAGE_NAMESPACE=$(STORAGE_NAMESPACE) ES_OPERATOR_NAMESPACE=$(ES_OPERATOR_NAMESPACE) ES_OPERATOR_IMAGE=$(ES_OPERATOR_IMAGE) go test -tags=self_provisioned_elasticsearch ./test/e2e/... $(TEST_OPTIONS)

.PHONY: e2e-tests-self-provisioned-es-kafka
e2e-tests-self-provisioned-es-kafka: prepare-e2e-tests deploy-kafka-operator
Copy link
Member Author

Choose a reason for hiding this comment

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

@kevinearls could you please create a jira to run this in the internal build?

Copy link
Contributor

Choose a reason for hiding this comment

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

@pavolloffay I've added a note to TRACING-806 to check once this is merged. I think it will cover that case.

@@ -25,7 +27,7 @@ import (
"github.com/jaegertracing/jaeger-operator/pkg/util"
)

func newStreamingStrategy(ctx context.Context, jaeger *v1.Jaeger) S {
func newStreamingStrategy(ctx context.Context, jaeger *v1.Jaeger, es *storage.ElasticsearchDeployment) S {
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem to belong here... We can't expect to add a cassandra, badger, in-memory to the strategies. There has to be a better way to do this.

Copy link
Member Author

Choose a reason for hiding this comment

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

The main motivation is to set path to cert generation scrip. Tests use a different path than binary.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be done via viper, or added to the context? Sounds a bit outside of the scope to change the strategy signature just to be able to get some information internal to the auto-provisioning of one of the storages...

Copy link
Member Author

Choose a reason for hiding this comment

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

So when creating the self-provisioned ES we need two things: path to cert generation script and more importantly secretes from the environment.

The path could be done via viper (although there are downsides of using viper in the impl packages, it's cleaner to pass params directly if we are talking about a package down in the stack).

Anyways the production strategy is using exactly the same construction.

Copy link
Contributor

Choose a reason for hiding this comment

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

It sounds reasonable to me to require access to a configuration value (via viper or not) if the path to the cert generation is required. In fact, we are using viper already in this source for other purposes:

if viper.GetString("platform") == v1.FlagPlatformOpenShift {
if q := route.NewQueryRoute(jaeger).Get(); nil != q {
manifest.routes = append(manifest.routes, *q)
}
} else {
if q := ingress.NewQueryIngress(jaeger).Get(); nil != q {
manifest.ingresses = append(manifest.ingresses, *q)
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Can't they be mounted in the file system directly from the secrets, like it's done in the Kafka auto-provisioning?

kuVolume := corev1.Volume{
Name: fmt.Sprintf("kafkauser-%s", ku.Name),
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: ku.Name,
},
},
}
// this is the volume containing the CA cluster cert
kuCAVolume := corev1.Volume{
Name: fmt.Sprintf("kafkauser-%s-cluster-ca", jaeger.Name), // the cluster name is the jaeger name
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: fmt.Sprintf("%s-cluster-ca-cert", jaeger.Name),
},
},
}
commonSpec.Volumes = append(commonSpec.Volumes, kuVolume, kuCAVolume)
// and finally, the mount paths to have the secrets in the container file system
kuVolumeMount := corev1.VolumeMount{
Name: fmt.Sprintf("kafkauser-%s", ku.Name),
MountPath: clientCertPath,
}
kuCAVolumeMount := corev1.VolumeMount{
Name: fmt.Sprintf("kafkauser-%s-cluster-ca", jaeger.Name), // the cluster name is the jaeger name
MountPath: clusterCAPath,
}
commonSpec.VolumeMounts = append(commonSpec.VolumeMounts, kuVolumeMount, kuCAVolumeMount)

Copy link
Member Author

Choose a reason for hiding this comment

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

They are mounted to Jaeger filesystem. But for the use case I am mentioned we need certs in the operator filesystem and not Jaeger instance (see the operator in my previous comment). The cert generation script then assures certs are valid and not expired...

Copy link
Contributor

Choose a reason for hiding this comment

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

But for the use case I am mentioned we need certs in the operator filesystem and not Jaeger instance (see the operator in my previous comment). The cert generation script then assures certs are valid and not expired...

This is another signal that there's a mismatch between things that should be operator-scoped and operand-scoped. Renewal of the certs, as well as creating/managing the secrets are operations that should be made by the operator independent of the reconciliation logic. The reconciliation logic should only be about the operand.

Copy link
Member Author

Choose a reason for hiding this comment

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

Renewal of the certs, as well as creating/managing the secrets are operations that should be made by the operator independent of the reconciliation logic.

Why handling objects/dependencie/whatever is required for the operand part of the reconciliation? My understanding of reconciliation logic is to prepare objects/dependencie/whatever for the operand.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know, you said it yourself, but I probably misunderstood what you meant...

IIRC the certs are copied to operator filesystem in case of operator restart (or rescheduling to another node?)

manifest.dependencies = storage.Dependencies(jaeger)

// assembles the pieces for an elasticsearch self-provisioned deployment via the elasticsearch operator
if storage.ShouldDeployElasticsearch(jaeger.Spec.Storage) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Most of this new code seems to be duplicated from the production strategy. Can't we find a way to reuse it? Duplicating a couple of lines is fine, but this is a bit more than just a couple...

if storage.ShouldDeployElasticsearch(jaeger.Spec.Storage) {
err := es.CreateCerts()
if err != nil {
jaeger.Logger().WithError(err).Error("failed to create Elasticsearch certificates, Elasticsearch won't be deployed")
} else {
c.secrets = es.ExtractSecrets()
c.elasticsearches = append(c.elasticsearches, *es.Elasticsearch())
es.InjectStorageConfiguration(&queryDep.Spec.Template.Spec)
es.InjectStorageConfiguration(&cDep.Spec.Template.Spec)
if indexCleaner != nil {
es.InjectSecretsConfiguration(&indexCleaner.Spec.JobTemplate.Spec.Template.Spec)
}
for i := range esRollover {
es.InjectSecretsConfiguration(&esRollover[i].Spec.JobTemplate.Spec.Template.Spec)
}
for i := range c.dependencies {
es.InjectSecretsConfiguration(&c.dependencies[i].Spec.Template.Spec)
}
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

I can extract this to a func, but anyways the whole streaming strategy is mostly copy of production strategy with added ingester.

Copy link
Contributor

Choose a reason for hiding this comment

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

I can understand the streaming strategy code being very similar to the production when it comes to the assembled objects (deployments, services, ...), as the final set of objects is quite similar, but the logic around the self-provisioning of ES could be abstracted away. For instance, here's how the auto-provisioning of Kafka happens:

// we provision a Kafka when no brokers have been set, or, when we are not in the first run,
// when we know we've been the ones placing the broker information in the configuration
if (!pfound && !cfound) || provisioned {
jaeger.Logger().Info("Provisioning Kafka, this might take a while...")
manifest = autoProvisionKafka(ctx, jaeger, manifest)
}

The strategy itself needs to know only whether the provisioning should happen. The auto-provision procedure will accept a manifest, and return a modified manifest, which might or not contain the Kafka objects required to do the provisioning.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have moved it to a shared func.

Signed-off-by: Pavol Loffay <ploffay@redhat.com>
Signed-off-by: Pavol Loffay <ploffay@redhat.com>
@pavolloffay
Copy link
Member Author

@jpkrohling I have moved the ES cert generation to jaeger controller as discussed on the call. Please have a look. If that is fine I will run e2e tests on OCP before merging.

Copy link
Contributor

@jpkrohling jpkrohling left a comment

Choose a reason for hiding this comment

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

LGTM!

@@ -248,6 +237,31 @@ func (r *ReconcileJaeger) apply(ctx context.Context, jaeger v1.Jaeger, str strat
return jaeger, tracing.HandleError(err, span)
}

// ES cert handling requires secretes from environment
Copy link
Contributor

Choose a reason for hiding this comment

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

s/secretes/secrets

@@ -7,6 +7,8 @@ import (
"strings"
"time"

"github.com/jaegertracing/jaeger-operator/pkg/storage"
Copy link
Contributor

Choose a reason for hiding this comment

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

Was it placed here by make format?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes

It either places it after core imports or after 3rd party imports in a separate block. However when I put it into operator imports it leaves it there.

Signed-off-by: Pavol Loffay <ploffay@redhat.com>
Signed-off-by: Pavol Loffay <ploffay@redhat.com>
@pavolloffay pavolloffay merged commit 6ee63aa into jaegertracing:master Jan 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants