quarkiverse / quarkus-google-cloud-services

Google Cloud Services Quarkus Extensions
https://docs.quarkiverse.io/quarkus-google-cloud-services/main/index.html
Apache License 2.0
54 stars 33 forks source link

Spanner does not work against emulator host #400

Open snazy opened 1 year ago

snazy commented 1 year ago

The current state of the Google Cloud Spanner Quarkus extension does not work at all using the Spanner emulator. The reason is actually pretty simple: it requires valid credentials and there is no way around it, even the documented approach does not work.

A way to make it work properly with an emulator is pretty simple, and does not require the hack from the docs described in the link above.

The current code is pretty straight forward, but makes using an emulator practically impossible, because it has a hard dependency via @Inject GoogleCredentials googleCredentials;.

A way around that and the hack is to programmatically request the GoogleCredentialy and only bark, it the emulator host is not present, like in this piece of code:

@ApplicationScope
public class SpannerProducer {

    @Inject
    GcpConfigHolder gcpConfigHolder;

    @Inject
    SpannerConfiguration spannerConfiguration;

    @Produces
    @Singleton
    @Default
    public Spanner storage() throws IOException {
        GoogleCredentials googleCredentials = null;
        Exception googleCredentialsException = null;
        try {
            googleCredentials = Arc.container().instance(GoogleCredentials.class).get();
        } catch (Exception e) {
            googleCredentialsException = e;
        }

        GcpBootstrapConfiguration gcpConfiguration = gcpConfigHolder.getBootstrapConfig();
        SpannerOptions.Builder builder =
            SpannerOptions.newBuilder().setProjectId(gcpConfiguration.projectId.orElse(null));
        if (!spannerConfiguration.emulatorHost().isPresent()) {
            builder.setEmulatorHost(spannerConfiguration.emulatorHost().get());
        } else {
            if (googleCredentials == null) {
                if (googleCredentialsException != null) {
                    throw new RuntimeException("No GoogleCredentials available", googleCredentialsException);
                } else {
                    throw new RuntimeException("No GoogleCredentials available");
                }
            }
            builder.setCredentials(googleCredentials);
        }

        return builder.build().getService();
    }
loicmathieu commented 1 year ago

In fact it can be done more elegantly by injecting an Instance<GoogleCredentials> and use instance.isAvailable(). There is multiple places where this can be done as this issue exists in multiple extensions.