quarkus-google-cloud-services icon indicating copy to clipboard operation
quarkus-google-cloud-services copied to clipboard

Spanner does not work against emulator host

Open snazy opened this issue 1 year ago • 1 comments

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();
    }

snazy avatar Mar 27 '23 07:03 snazy

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.

loicmathieu avatar Apr 18 '23 12:04 loicmathieu