diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java index a4b29dea..a0032d1c 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java @@ -28,8 +28,8 @@ import com.google.auth.Credentials; import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.NoCredentials; +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; import com.google.common.base.MoreObjects; -import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.spanner.adapter.v1.AdapterClient; import com.google.spanner.adapter.v1.AdapterSettings; @@ -95,7 +95,7 @@ void start() { try { Credentials credentials = options.getCredentials(); - if (options.usePlainText() || !Strings.isNullOrEmpty(options.getExperimentalHostEndpoint())) { + if (options.usePlainText() || options.getInstanceType() == InstanceType.OMNI) { credentials = null; } else if (credentials == null) { credentials = GoogleCredentials.getApplicationDefault(); @@ -114,8 +114,7 @@ void start() { if (options.usePlainText()) { LOG.warn("Using plain text channel. This should not be used in production."); channelProviderBuilder.setChannelConfigurator(ManagedChannelBuilder::usePlaintext); - } else if (!Strings.isNullOrEmpty(options.getExperimentalHostEndpoint()) - && options.useClientCert()) { + } else if (options.getInstanceType() == InstanceType.OMNI && options.useClientCert()) { SslContext mTLSContext = GrpcSslContexts.forClient() .keyManager( @@ -160,11 +159,7 @@ void start() { options.getChannelProvider(), channelProviderBuilder.build())) .setCredentialsProvider(credentialsProvider) .setHeaderProvider(headerProvider); - if (!Strings.isNullOrEmpty(options.getExperimentalHostEndpoint())) { - settingsBuilder.setEndpoint(options.getExperimentalHostEndpoint()); - } else { - settingsBuilder.setEndpoint(options.getSpannerEndpoint()); - } + settingsBuilder.setEndpoint(options.getSpannerEndpoint()); AdapterSettings settings = settingsBuilder.build(); diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java index 4a91308f..0121967d 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java @@ -17,6 +17,7 @@ import com.google.api.gax.rpc.TransportChannelProvider; import com.google.auth.Credentials; +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; import com.google.cloud.spanner.adapter.metrics.BuiltInMetricsRecorder; import com.google.common.base.Strings; import java.net.InetAddress; @@ -25,7 +26,6 @@ /** Options for creating the {@link Adapter}. */ class AdapterOptions { - private static final String DEFAULT_SPANNER_ENDPOINT = "spanner.googleapis.com:443"; private static final int DEFAULT_NUM_GRPC_CHANNELS = 4; @@ -42,13 +42,12 @@ static class Builder { private BuiltInMetricsRecorder metricsRecorder; private boolean useVirtualThreads = false; private boolean usePlainText = false; - private String experimentalHostEndpoint = null; + private InstanceType instanceType = InstanceType.CLOUD; private String clientCertPath = null; private String clientKeyPath = null; /** The Cloud Spanner endpoint. */ Builder spannerEndpoint(String spannerEndpoint) { - validateHostConflict(spannerEndpoint, this.experimentalHostEndpoint); this.spannerEndpoint = spannerEndpoint; return this; } @@ -118,30 +117,19 @@ Builder usePlainText(boolean usePlainText) { return this; } - /** (Optional) Experimental host endpoint. */ - Builder setExperimentalHostEndpoint(String experimentalHostEndpoint) { - validateHostConflict(this.spannerEndpoint, experimentalHostEndpoint); - this.experimentalHostEndpoint = experimentalHostEndpoint; + /** (Optional) Set the instance type. */ + Builder setInstanceType(InstanceType instanceType) { + this.instanceType = instanceType; return this; } - /** (Optional) Use mTLS connection to communicate with Experimental Host instance. */ + /** (Optional) Use mTLS connection to communicate with Spanner Omni instance. */ Builder useClientCert(String clientCertPath, String clientKeyPath) { this.clientCertPath = clientCertPath; this.clientKeyPath = clientKeyPath; return this; } - private void validateHostConflict( - String spannerEndpointToCheck, String experimentalHostEndpointToCheck) { - if (!Strings.isNullOrEmpty(spannerEndpointToCheck) - && !spannerEndpointToCheck.equals(DEFAULT_SPANNER_ENDPOINT) - && !Strings.isNullOrEmpty(experimentalHostEndpointToCheck)) { - throw new IllegalArgumentException( - "Only one of Spanner Host or Experimental Host can be set."); - } - } - AdapterOptions build() { return new AdapterOptions(this); } @@ -158,7 +146,7 @@ AdapterOptions build() { private BuiltInMetricsRecorder metricsRecorder; private boolean useVirtualThreads; private boolean usePlainText; - private String experimentalHostEndpoint; + private InstanceType instanceType; private String clientCertPath; private String clientKeyPath; @@ -174,7 +162,7 @@ private AdapterOptions(Builder builder) { this.metricsRecorder = builder.metricsRecorder; this.useVirtualThreads = builder.useVirtualThreads; this.usePlainText = builder.usePlainText; - this.experimentalHostEndpoint = builder.experimentalHostEndpoint; + this.instanceType = builder.instanceType; this.clientCertPath = builder.clientCertPath; this.clientKeyPath = builder.clientKeyPath; } @@ -227,8 +215,8 @@ boolean usePlainText() { return usePlainText; } - String getExperimentalHostEndpoint() { - return experimentalHostEndpoint; + InstanceType getInstanceType() { + return instanceType; } boolean useClientCert() { diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java index 866a6e07..ec0a8670 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java @@ -18,7 +18,6 @@ import com.google.cloud.spanner.adapter.metrics.BuiltInMetricsProvider; import com.google.cloud.spanner.adapter.metrics.BuiltInMetricsRecorder; -import com.google.common.base.Strings; import com.google.spanner.adapter.v1.DatabaseName; import io.opentelemetry.api.OpenTelemetry; import java.io.IOException; @@ -100,7 +99,7 @@ public class Launcher { private static final BuiltInMetricsProvider builtInMetricsProvider = BuiltInMetricsProvider.INSTANCE; - private static final String EXPERIMENTAL_HOST_ID = "default"; + private static final String SPANNER_OMNI_ID = "default"; private final AdapterFactory adapterFactory; private final List adapters = new ArrayList<>(); private HealthCheckServer healthCheckServer; @@ -229,7 +228,7 @@ private AdapterOptions buildAdapterOptions( .numGrpcChannels(config.getNumGrpcChannels()) .metricsRecorder(metricsRecorder) .usePlainText(config.usePlainText()) - .setExperimentalHostEndpoint(config.getExperimentalHostEndpoint()) + .setInstanceType(config.getInstanceType()) .useClientCert(config.getClientCertPath(), config.getClientKeyPath()); if (config.getMaxCommitDelayMillis() != null) { opBuilder.maxCommitDelay(Duration.ofMillis(config.getMaxCommitDelayMillis())); @@ -255,8 +254,8 @@ private DatabaseName resolveDatabaseName(ListenerConfig config) { return DatabaseName.parse(uriOrId); } - if (!Strings.isNullOrEmpty(config.getExperimentalHostEndpoint())) { - return DatabaseName.of(EXPERIMENTAL_HOST_ID, EXPERIMENTAL_HOST_ID, uriOrId); + if (config.getInstanceType() == SpannerCqlSessionBuilder.InstanceType.OMNI) { + return DatabaseName.of(SPANNER_OMNI_ID, SPANNER_OMNI_ID, uriOrId); } // User is trying to connect to Cloud Spanner instance with an invalid database URI. We diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java index 128bb332..37773cd5 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner.adapter; +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; import com.google.cloud.spanner.adapter.configs.ConfigConstants; import com.google.cloud.spanner.adapter.configs.ListenerConfigs; import com.google.cloud.spanner.adapter.configs.UserConfigs; @@ -60,16 +61,24 @@ static LauncherConfig fromUserConfigs(UserConfigs userConfigs) throws UnknownHos final String globalSpannerEndpoint; final boolean globalEnableBuiltInMetrics; final boolean usePlainText; - final String experimentalHostEndpoint; + final InstanceType instanceType; final String clientCertPath; final String clientKeyPath; HealthCheckConfig healthCheckConfig = null; if (userConfigs.getGlobalClientConfigs() != null) { - globalSpannerEndpoint = - userConfigs.getGlobalClientConfigs().getSpannerEndpoint() != null - ? userConfigs.getGlobalClientConfigs().getSpannerEndpoint() - : ConfigConstants.DEFAULT_SPANNER_ENDPOINT; + String expHost = userConfigs.getGlobalClientConfigs().getExperimentalHostEndpoint(); + InstanceType type = userConfigs.getGlobalClientConfigs().getInstanceType(); + if (!Strings.isNullOrEmpty(expHost)) { + globalSpannerEndpoint = expHost; + instanceType = InstanceType.OMNI; + } else { + globalSpannerEndpoint = + userConfigs.getGlobalClientConfigs().getSpannerEndpoint() != null + ? userConfigs.getGlobalClientConfigs().getSpannerEndpoint() + : ConfigConstants.DEFAULT_SPANNER_ENDPOINT; + instanceType = type != null ? type : InstanceType.CLOUD; + } globalEnableBuiltInMetrics = userConfigs.getGlobalClientConfigs().getEnableBuiltInMetrics() != null && userConfigs.getGlobalClientConfigs().getEnableBuiltInMetrics(); @@ -81,14 +90,13 @@ static LauncherConfig fromUserConfigs(UserConfigs userConfigs) throws UnknownHos usePlainText = userConfigs.getGlobalClientConfigs().getUsePlainText() != null && userConfigs.getGlobalClientConfigs().getUsePlainText(); - experimentalHostEndpoint = userConfigs.getGlobalClientConfigs().getExperimentalHostEndpoint(); clientCertPath = userConfigs.getGlobalClientConfigs().getClientCertPath(); clientKeyPath = userConfigs.getGlobalClientConfigs().getClientKeyPath(); } else { globalSpannerEndpoint = ConfigConstants.DEFAULT_SPANNER_ENDPOINT; globalEnableBuiltInMetrics = false; usePlainText = false; - experimentalHostEndpoint = null; + instanceType = InstanceType.CLOUD; clientCertPath = null; clientKeyPath = null; } @@ -102,7 +110,7 @@ static LauncherConfig fromUserConfigs(UserConfigs userConfigs) throws UnknownHos globalSpannerEndpoint, globalEnableBuiltInMetrics, usePlainText, - experimentalHostEndpoint, + instanceType, clientCertPath, clientKeyPath)); } @@ -138,7 +146,7 @@ private static void validateListenerConfig(ListenerConfigs listener) { /** Encapsulates the configuration for a single Adapter listener. */ final class ListenerConfig { - private static final String EXPERIMENTAL_HOST_ID = "default"; + private static final String SPANNER_OMNI_ID = "default"; private final String databaseUri; private final InetAddress hostAddress; private final int port; @@ -147,7 +155,7 @@ final class ListenerConfig { @Nullable private final Integer maxCommitDelayMillis; private final boolean enableBuiltInMetrics; private final boolean usePlainText; - private final String experimentalHostEndpoint; + private final InstanceType instanceType; private String clientCertPath; private String clientKeyPath; @@ -160,7 +168,7 @@ private ListenerConfig(Builder builder) { this.maxCommitDelayMillis = builder.maxCommitDelayMillis; this.enableBuiltInMetrics = builder.enableBuiltInMetrics; this.usePlainText = builder.usePlainText; - this.experimentalHostEndpoint = builder.experimentalHostEndpoint; + this.instanceType = builder.instanceType; this.clientCertPath = builder.clientCertPath; this.clientKeyPath = builder.clientKeyPath; } @@ -198,8 +206,8 @@ public boolean usePlainText() { return usePlainText; } - public String getExperimentalHostEndpoint() { - return experimentalHostEndpoint; + public InstanceType getInstanceType() { + return instanceType; } public String getClientCertPath() { @@ -215,7 +223,7 @@ static ListenerConfig fromListenerConfigs( String globalSpannerEndpoint, boolean globalEnableBuiltInMetrics, boolean usePlainText, - String experimentalHostEndpoint, + InstanceType instanceType, String clientCertPath, String clientKeyPath) throws UnknownHostException { @@ -235,7 +243,7 @@ static ListenerConfig fromListenerConfigs( .numGrpcChannels(numGrpcChannels) .maxCommitDelayMillis(maxCommitDelayMillis) .enableBuiltInMetrics(globalEnableBuiltInMetrics) - .setExperimentalHostEndpoint(experimentalHostEndpoint) + .setInstanceType(instanceType) .usePlainText(usePlainText) .useClientCert(clientCertPath, clientKeyPath) .build(); @@ -265,15 +273,21 @@ static ListenerConfig fromProperties(Map properties) throws Unkn boolean usePlainText = Boolean.parseBoolean( properties.getOrDefault(ConfigConstants.USE_PLAINTEXT_PROP_KEY, "false")); + String typeStr = properties.get(ConfigConstants.INSTANCE_TYPE_PROP_KEY); + InstanceType instanceType = + typeStr != null ? InstanceType.valueOf(typeStr.toUpperCase()) : InstanceType.CLOUD; String experimentalHostEndpoint = properties.get(ConfigConstants.EXPERIMENTAL_HOST_ENDPOINT_PROP_KEY); + if (!Strings.isNullOrEmpty(experimentalHostEndpoint)) { + spannerEndpoint = experimentalHostEndpoint; + instanceType = InstanceType.OMNI; + } String clientCertPath = properties.get(ConfigConstants.CLIENT_CERT_PATH_PROP_KEY); String clientKeyPath = properties.get(ConfigConstants.CLIENT_KEY_PATH_PROP_KEY); String databaseUri = properties.get(ConfigConstants.DATABASE_URI_PROP_KEY); - if (!Strings.isNullOrEmpty(experimentalHostEndpoint)) { + if (instanceType == InstanceType.OMNI) { if (!DatabaseName.isParsableFrom(databaseUri)) { - databaseUri = - DatabaseName.of(EXPERIMENTAL_HOST_ID, EXPERIMENTAL_HOST_ID, databaseUri).toString(); + databaseUri = DatabaseName.of(SPANNER_OMNI_ID, SPANNER_OMNI_ID, databaseUri).toString(); } } @@ -286,7 +300,7 @@ static ListenerConfig fromProperties(Map properties) throws Unkn .maxCommitDelayMillis(maxCommitDelayMillis) .enableBuiltInMetrics(enableBuiltInMetrics) .usePlainText(usePlainText) - .setExperimentalHostEndpoint(experimentalHostEndpoint) + .setInstanceType(instanceType) .useClientCert(clientCertPath, clientKeyPath) .build(); } @@ -304,20 +318,10 @@ static class Builder { @Nullable private Integer maxCommitDelayMillis; private boolean enableBuiltInMetrics; private boolean usePlainText; - private String experimentalHostEndpoint; + private InstanceType instanceType = InstanceType.CLOUD; private String clientCertPath; private String clientKeyPath; - private void validateHostConflict( - String spannerEndpointToCheck, String experimentalHostEndpointToCheck) { - if (!Strings.isNullOrEmpty(spannerEndpointToCheck) - && !spannerEndpointToCheck.equals(ConfigConstants.DEFAULT_SPANNER_ENDPOINT) - && !Strings.isNullOrEmpty(experimentalHostEndpointToCheck)) { - throw new IllegalArgumentException( - "Only one of Spanner Host or Experimental Host can be set."); - } - } - public Builder databaseUri(String databaseUri) { this.databaseUri = databaseUri; return this; @@ -334,7 +338,6 @@ public Builder port(int port) { } public Builder spannerEndpoint(String spannerEndpoint) { - validateHostConflict(spannerEndpoint, this.experimentalHostEndpoint); this.spannerEndpoint = spannerEndpoint; return this; } @@ -359,9 +362,8 @@ public Builder usePlainText(boolean usePlainText) { return this; } - public Builder setExperimentalHostEndpoint(String experimentalHostEndpoint) { - validateHostConflict(this.spannerEndpoint, experimentalHostEndpoint); - this.experimentalHostEndpoint = experimentalHostEndpoint; + public Builder setInstanceType(InstanceType instanceType) { + this.instanceType = instanceType; return this; } diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/SpannerCqlSessionBuilder.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/SpannerCqlSessionBuilder.java index 8ff4e328..edc3e30c 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/SpannerCqlSessionBuilder.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/SpannerCqlSessionBuilder.java @@ -46,6 +46,13 @@ @NotThreadSafe public final class SpannerCqlSessionBuilder extends SessionBuilder { + + /** Specifies the type of Spanner instance to connect to (CLOUD or OMNI). */ + public enum InstanceType { + CLOUD, + OMNI + } + private static final Logger LOG = LoggerFactory.getLogger(SpannerCqlSessionBuilder.class); private final BuiltInMetricsProvider builtInMetricsProvider = BuiltInMetricsProvider.INSTANCE; private static final int DEFAULT_PORT = 9042; @@ -54,7 +61,7 @@ public final class SpannerCqlSessionBuilder private static final int LARGEST_MAX_COMMIT_DELAY_MILLIS = 500; private static final String DEFAULT_SPANNER_ENDPOINT = "spanner.googleapis.com:443"; private static final String ENV_VAR_SPANNER_ENDPOINT = "SPANNER_ENDPOINT"; - private static final String EXPERIMENTAL_HOST_ID = "default"; + private static final String SPANNER_OMNI_ID = "default"; private InetAddress iNetAddress; private int port; @@ -68,7 +75,7 @@ public final class SpannerCqlSessionBuilder private Credentials credentials; private boolean useVirtualThreads; private boolean usePlainText; - private String experimentalHostEndpoint; + private InstanceType instanceType = InstanceType.CLOUD; private String clientCertPath = null; private String clientKeyPath = null; @@ -160,15 +167,32 @@ public SpannerCqlSessionBuilder setUsePlainText(boolean usePlainText) { return this; } - /** (Optional, default null) Experimental Host endpoint */ + /** + * (Optional, default CLOUD) Specifies the type of Spanner instance to connect to. Setting it to + * OMNI is mandatory when connecting to a Spanner Omni instance. + */ + public SpannerCqlSessionBuilder setInstanceType(InstanceType instanceType) { + this.instanceType = instanceType; + return this; + } + + /** + * (Optional, default null) Experimental Host endpoint. + * + * @deprecated Use {@link #setHost(String)} and {@link #setInstanceType(InstanceType)} instead. + */ + @Deprecated public SpannerCqlSessionBuilder setExperimentalHostEndpoint(String experimentalHostEndpoint) { - this.experimentalHostEndpoint = experimentalHostEndpoint; + if (!Strings.isNullOrEmpty(experimentalHostEndpoint)) { + this.host = experimentalHostEndpoint; + this.instanceType = InstanceType.OMNI; + } return this; } /** - * (Optional, default null) Enables mTLS connection to experimental host endpoint using client - * certificate and key This should only be used for connecting to experimental host instances. + * (Optional, default null) Enables mTLS connection to Spanner Omni instance using client + * certificate and key. This should only be used for connecting to Spanner Omni instances. */ public SpannerCqlSessionBuilder setClientCertPathAndKey( String clientCertPath, String clientKeyPath) { @@ -279,10 +303,8 @@ private void checkMaxCommitDelay() { private void createAndStartAdapter() { - if (!Strings.isNullOrEmpty(experimentalHostEndpoint) - && !DatabaseName.isParsableFrom(databaseUri)) { - databaseUri = - DatabaseName.of(EXPERIMENTAL_HOST_ID, EXPERIMENTAL_HOST_ID, databaseUri).toString(); + if (instanceType == InstanceType.OMNI && !DatabaseName.isParsableFrom(databaseUri)) { + databaseUri = DatabaseName.of(SPANNER_OMNI_ID, SPANNER_OMNI_ID, databaseUri).toString(); } DatabaseName databaseName = DatabaseName.parse(databaseUri); OpenTelemetry openTelemetry = @@ -308,7 +330,7 @@ private void createAndStartAdapter() { .metricsRecorder(metricsRecorder) .useVirtualThreads(useVirtualThreads) .usePlainText(usePlainText) - .setExperimentalHostEndpoint(experimentalHostEndpoint) + .setInstanceType(instanceType) .useClientCert(clientCertPath, clientKeyPath) .build(); adapter = new Adapter(adapterOptions); diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java index 596f3e63..04105a6a 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java @@ -36,7 +36,14 @@ private ConfigConstants() {} public static final String HEALTH_CHECK_PORT_PROP_KEY = "healthCheckPort"; public static final String CONFIG_FILE_PROP_KEY = "configFilePath"; public static final String USE_PLAINTEXT_PROP_KEY = "usePlainText"; + + /** + * @deprecated Use {@link #SPANNER_ENDPOINT_PROP_KEY} and {@link #INSTANCE_TYPE_PROP_KEY} instead. + */ + @Deprecated public static final String EXPERIMENTAL_HOST_ENDPOINT_PROP_KEY = "experimentalHostEndpoint"; + + public static final String INSTANCE_TYPE_PROP_KEY = "instanceType"; public static final String CLIENT_CERT_PATH_PROP_KEY = "clientCertPath"; public static final String CLIENT_KEY_PATH_PROP_KEY = "clientKeyPath"; } diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java index 0fe2a30e..04ad5e83 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner.adapter.configs; +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; import com.google.common.base.Strings; import java.util.Map; @@ -25,7 +26,7 @@ public class GlobalClientConfigs { private final Boolean enableBuiltInMetrics; private final String healthCheckEndpoint; private final Boolean usePlainText; - private final String experimentalHostEndpoint; + private final InstanceType instanceType; private final String clientCertPath; private final String clientKeyPath; @@ -35,20 +36,64 @@ public GlobalClientConfigs( String healthCheckEndpoint, Boolean usePlainText, String experimentalHostEndpoint, + InstanceType instanceType, String clientCertPath, String clientKeyPath) { + if (!Strings.isNullOrEmpty(experimentalHostEndpoint)) { + if (Strings.isNullOrEmpty(spannerEndpoint)) { + spannerEndpoint = experimentalHostEndpoint; + } + if (instanceType == null) { + instanceType = InstanceType.OMNI; + } + } this.spannerEndpoint = spannerEndpoint; this.enableBuiltInMetrics = enableBuiltInMetrics; this.healthCheckEndpoint = healthCheckEndpoint; this.usePlainText = usePlainText; - this.experimentalHostEndpoint = experimentalHostEndpoint; + this.instanceType = instanceType; this.clientCertPath = clientCertPath; this.clientKeyPath = clientKeyPath; } + /** + * @deprecated Use {@link #GlobalClientConfigs(String, Boolean, String, Boolean, String, + * InstanceType, String, String)} instead. + */ + @Deprecated + public GlobalClientConfigs( + String spannerEndpoint, + Boolean enableBuiltInMetrics, + String healthCheckEndpoint, + Boolean usePlainText, + String experimentalHostEndpoint, + String instanceType, + String clientCertPath, + String clientKeyPath) { + this( + spannerEndpoint, + enableBuiltInMetrics, + healthCheckEndpoint, + usePlainText, + experimentalHostEndpoint, + Strings.isNullOrEmpty(instanceType) + ? null + : InstanceType.valueOf(instanceType.toUpperCase()), + clientCertPath, + clientKeyPath); + } + public GlobalClientConfigs( String spannerEndpoint, Boolean enableBuiltInMetrics, String healthCheckEndpoint) { - this(spannerEndpoint, enableBuiltInMetrics, healthCheckEndpoint, null, null, null, null); + this( + spannerEndpoint, + enableBuiltInMetrics, + healthCheckEndpoint, + null, + null, + (InstanceType) null, + null, + null); } public GlobalClientConfigs( @@ -57,9 +102,21 @@ public GlobalClientConfigs( String healthCheckEndpoint, Boolean usePlainText) { this( - spannerEndpoint, enableBuiltInMetrics, healthCheckEndpoint, usePlainText, null, null, null); + spannerEndpoint, + enableBuiltInMetrics, + healthCheckEndpoint, + usePlainText, + null, + (InstanceType) null, + null, + null); } + /** + * @deprecated Use {@link #GlobalClientConfigs(String, Boolean, String, Boolean, String, + * InstanceType, String, String)} instead. + */ + @Deprecated public GlobalClientConfigs( String spannerEndpoint, Boolean enableBuiltInMetrics, @@ -72,6 +129,7 @@ public GlobalClientConfigs( healthCheckEndpoint, usePlainText, experimentalHostEndpoint, + (InstanceType) null, null, null); } @@ -82,15 +140,24 @@ public static GlobalClientConfigs fromMap(Map yamlMap) { String healthCheckEndpoint = (String) yamlMap.get("healthCheckEndpoint"); Boolean usePlainText = (Boolean) yamlMap.get("usePlainText"); String experimentalHostEndpoint = (String) yamlMap.get("experimentalHostEndpoint"); + String instanceTypeStr = (String) yamlMap.get("instanceType"); + InstanceType instanceType = + Strings.isNullOrEmpty(instanceTypeStr) + ? null + : InstanceType.valueOf(instanceTypeStr.toUpperCase()); String clientCertPath = (String) yamlMap.get("clientCertPath"); String clientKeyPath = (String) yamlMap.get("clientKeyPath"); + if (Strings.isNullOrEmpty(clientCertPath) || Strings.isNullOrEmpty(clientKeyPath)) { return new GlobalClientConfigs( spannerEndpoint, enableBuiltInMetrics, healthCheckEndpoint, usePlainText, - experimentalHostEndpoint); + experimentalHostEndpoint, + instanceType, + null, + null); } return new GlobalClientConfigs( spannerEndpoint, @@ -98,6 +165,7 @@ public static GlobalClientConfigs fromMap(Map yamlMap) { healthCheckEndpoint, usePlainText, experimentalHostEndpoint, + instanceType, clientCertPath, clientKeyPath); } @@ -118,8 +186,16 @@ public Boolean getUsePlainText() { return usePlainText; } + /** + * @deprecated Use {@link #getSpannerEndpoint()} and {@link #getInstanceType()} instead. + */ + @Deprecated public String getExperimentalHostEndpoint() { - return experimentalHostEndpoint; + return instanceType == InstanceType.OMNI ? spannerEndpoint : null; + } + + public InstanceType getInstanceType() { + return instanceType; } public String getClientCertPath() { diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/AdapterOptionsTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/AdapterOptionsTest.java new file mode 100644 index 00000000..3eb8271a --- /dev/null +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/AdapterOptionsTest.java @@ -0,0 +1,47 @@ +/* +Copyright 2026 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package com.google.cloud.spanner.adapter; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class AdapterOptionsTest { + + @Test + public void testDefaultInstanceType_isCloud() { + AdapterOptions options = AdapterOptions.newBuilder().build(); + + assertThat(options.getInstanceType()).isEqualTo(InstanceType.CLOUD); + } + + @Test + public void testSetSpannerEndpointAndInstanceType_newWay() { + AdapterOptions options = + AdapterOptions.newBuilder() + .spannerEndpoint("omni-host:15000") + .setInstanceType(InstanceType.OMNI) + .build(); + + assertThat(options.getSpannerEndpoint()).isEqualTo("omni-host:15000"); + assertThat(options.getInstanceType()).isEqualTo(InstanceType.OMNI); + } +} diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java index 90564907..be2b77b6 100644 --- a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; import com.google.cloud.spanner.adapter.configs.GlobalClientConfigs; import com.google.cloud.spanner.adapter.configs.ListenerConfigs; import com.google.cloud.spanner.adapter.configs.SpannerConfigs; @@ -97,11 +98,13 @@ public void testParse_withConfigFileAndOtherParams_usesConfigFile() throws Excep assertThat(listenerConfig1.getDatabaseUri()) .isEqualTo("projects/my-project/instances/my-instance/databases/my-database"); assertThat(listenerConfig1.getPort()).isEqualTo(9042); + assertThat(listenerConfig1.getInstanceType()).isEqualTo(InstanceType.CLOUD); ListenerConfig listenerConfig2 = config.getListeners().get(1); assertThat(listenerConfig2.getDatabaseUri()) .isEqualTo("projects/my-project/instances/my-instance/databases/my-database-2"); assertThat(listenerConfig2.getPort()).isEqualTo(9043); + assertThat(listenerConfig2.getInstanceType()).isEqualTo(InstanceType.CLOUD); } @Test @@ -117,6 +120,7 @@ public void testParse_withValidUsePlainTextConfigFile() throws Exception { ListenerConfig listenerConfig1 = config.getListeners().get(0); assertThat(listenerConfig1.getSpannerEndpoint()).isEqualTo("localhost:15000"); assertThat(listenerConfig1.usePlainText()).isTrue(); + assertThat(listenerConfig1.getInstanceType()).isEqualTo(InstanceType.CLOUD); ListenerConfig listenerConfig2 = config.getListeners().get(1); assertThat(listenerConfig2.getDatabaseUri()) @@ -124,6 +128,7 @@ public void testParse_withValidUsePlainTextConfigFile() throws Exception { assertThat(listenerConfig2.getPort()).isEqualTo(9043); assertThat(listenerConfig2.getSpannerEndpoint()).isEqualTo("localhost:15000"); assertThat(listenerConfig2.usePlainText()).isTrue(); + assertThat(listenerConfig2.getInstanceType()).isEqualTo(InstanceType.CLOUD); } @Test @@ -151,6 +156,7 @@ public void testParse_withSystemProperties() throws Exception { assertThat(listenerConfig.getNumGrpcChannels()).isEqualTo(8); assertThat(listenerConfig.getMaxCommitDelayMillis()).isEqualTo(100); assertThat(listenerConfig.isEnableBuiltInMetrics()).isTrue(); + assertThat(listenerConfig.getInstanceType()).isEqualTo(InstanceType.CLOUD); assertThat(config.getHealthCheckConfig()).isNotNull(); assertThat(config.getHealthCheckConfig().getPort()).isEqualTo(8080); } @@ -261,7 +267,9 @@ public void testParse_withValidUseClientCertConfigFile() throws Exception { assertThat(config.getListeners()).hasSize(2); ListenerConfig listenerConfig1 = config.getListeners().get(0); assertThat(listenerConfig1.usePlainText()).isFalse(); - assertThat(listenerConfig1.getExperimentalHostEndpoint()).isEqualTo("localhost:15000"); + assertThat(listenerConfig1.getSpannerEndpoint()).isEqualTo("localhost:15000"); + assertThat(listenerConfig1.getInstanceType()) + .isEqualTo(SpannerCqlSessionBuilder.InstanceType.OMNI); assertThat(listenerConfig1.getClientCertPath()).isEqualTo("/path/to/client.crt"); assertThat(listenerConfig1.getClientKeyPath()).isEqualTo("/path/to/client.key.pkcs8"); @@ -270,22 +278,10 @@ public void testParse_withValidUseClientCertConfigFile() throws Exception { .isEqualTo("projects/my-project/instances/my-instance/databases/my-database-2"); assertThat(listenerConfig2.getPort()).isEqualTo(9043); assertThat(listenerConfig2.usePlainText()).isFalse(); - assertThat(listenerConfig2.getExperimentalHostEndpoint()).isEqualTo("localhost:15000"); + assertThat(listenerConfig2.getSpannerEndpoint()).isEqualTo("localhost:15000"); + assertThat(listenerConfig2.getInstanceType()) + .isEqualTo(SpannerCqlSessionBuilder.InstanceType.OMNI); assertThat(listenerConfig2.getClientCertPath()).isEqualTo("/path/to/client.crt"); assertThat(listenerConfig2.getClientKeyPath()).isEqualTo("/path/to/client.key.pkcs8"); } - - @Test - public void testParse_withHostConflictConfigFile_throwsIOException() throws Exception { - String configFile = - getClass().getClassLoader().getResource("invalid-host-conflict-config.yaml").getFile(); - Map properties = new HashMap<>(); - properties.put("configFilePath", configFile); - - IOException thrown = - assertThrows(IOException.class, () -> LauncherConfigParser.parse(properties)); - assertThat(thrown.getCause()).isInstanceOf(IllegalArgumentException.class); - assertThat(thrown.getCause().getMessage()) - .contains("Only one of Spanner Host or Experimental Host can be set."); - } } diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java index 6988c4ac..9d39fc68 100644 --- a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java @@ -237,7 +237,7 @@ public void testShutdownHook_stopsAllInstances() throws Exception { } @Test - public void testRun_withUseClientCertMode_startsAdapterWithOptions() throws Exception { + public void testRun_withUseClientCertMode_deprecatedButWorks() throws Exception { Map properties = new HashMap<>(); properties.put("databaseUri", DEFAULT_DATABASE_URI); properties.put("host", "127.0.0.1"); @@ -266,7 +266,45 @@ public void testRun_withUseClientCertMode_startsAdapterWithOptions() throws Exce assertThat(options.getNumGrpcChannels()).isEqualTo(8); assertThat(options.getMaxCommitDelay().get().toMillis()).isEqualTo(100); assertThat(options.usePlainText()).isFalse(); - assertThat(options.getExperimentalHostEndpoint()).isEqualTo("localhost:15000"); + assertThat(options.getSpannerEndpoint()).isEqualTo("localhost:15000"); + assertThat(options.getInstanceType()).isEqualTo(SpannerCqlSessionBuilder.InstanceType.OMNI); + assertThat(options.getClientCertPath()).isEqualTo("/path/to/client.crt"); + assertThat(options.getClientKeyPath()).isEqualTo("/path/to/client.key.pkcs8"); + } + + @Test + public void testRun_withUseClientCertMode_startsAdapterWithOptions() throws Exception { + Map properties = new HashMap<>(); + properties.put("databaseUri", DEFAULT_DATABASE_URI); + properties.put("host", "127.0.0.1"); + properties.put("port", "9042"); + properties.put("numGrpcChannels", "8"); + properties.put("maxCommitDelayMillis", "100"); + properties.put("enableBuiltInMetrics", "true"); + properties.put("healthCheckPort", "8080"); + properties.put("spannerEndpoint", "localhost:15000"); + properties.put("instanceType", "omni"); + properties.put("clientCertPath", "/path/to/client.crt"); + properties.put("clientKeyPath", "/path/to/client.key.pkcs8"); + LauncherConfig config = LauncherConfig.fromProperties(properties); + + launcher.run(config); + + verify(mockAdapterFactory, times(1)).createAdapter(adapterOptionsCaptor.capture()); + verify(mockAdapterFactory, times(1)).createHealthCheckServer(any(), eq(8080)); + verify(mockAdapter, times(1)).start(); + verify(mockHealthCheckServer).start(); + verify(mockHealthCheckServer).setReady(true); + + AdapterOptions options = adapterOptionsCaptor.getValue(); + assertThat(options.getDatabaseUri()).isEqualTo(DEFAULT_DATABASE_URI); + assertThat(options.getTcpPort()).isEqualTo(9042); + assertThat(options.getInetAddress()).isEqualTo(InetAddress.getByName("127.0.0.1")); + assertThat(options.getNumGrpcChannels()).isEqualTo(8); + assertThat(options.getMaxCommitDelay().get().toMillis()).isEqualTo(100); + assertThat(options.usePlainText()).isFalse(); + assertThat(options.getSpannerEndpoint()).isEqualTo("localhost:15000"); + assertThat(options.getInstanceType()).isEqualTo(SpannerCqlSessionBuilder.InstanceType.OMNI); assertThat(options.getClientCertPath()).isEqualTo("/path/to/client.crt"); assertThat(options.getClientKeyPath()).isEqualTo("/path/to/client.key.pkcs8"); } diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/SpannerCqlSessionBuilderTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/SpannerCqlSessionBuilderTest.java new file mode 100644 index 00000000..d8540903 --- /dev/null +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/SpannerCqlSessionBuilderTest.java @@ -0,0 +1,62 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package com.google.cloud.spanner.adapter; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; +import java.lang.reflect.Field; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class SpannerCqlSessionBuilderTest { + + @Test + public void testSetExperimentalHostEndpoint_deprecatedButWorks() throws Exception { + SpannerCqlSessionBuilder builder = new SpannerCqlSessionBuilder(); + builder.setExperimentalHostEndpoint("experimental-host:15000"); + + Field hostField = SpannerCqlSessionBuilder.class.getDeclaredField("host"); + hostField.setAccessible(true); + String host = (String) hostField.get(builder); + assertThat(host).isEqualTo("experimental-host:15000"); + + Field instanceTypeField = SpannerCqlSessionBuilder.class.getDeclaredField("instanceType"); + instanceTypeField.setAccessible(true); + InstanceType instanceType = (InstanceType) instanceTypeField.get(builder); + assertThat(instanceType).isEqualTo(InstanceType.OMNI); + } + + @Test + public void testSetHostAndType_newWay() throws Exception { + SpannerCqlSessionBuilder builder = new SpannerCqlSessionBuilder(); + builder.setHost("omni-host:15000"); + builder.setInstanceType(InstanceType.OMNI); + + Field hostField = SpannerCqlSessionBuilder.class.getDeclaredField("host"); + hostField.setAccessible(true); + String host = (String) hostField.get(builder); + assertThat(host).isEqualTo("omni-host:15000"); + + Field instanceTypeField = SpannerCqlSessionBuilder.class.getDeclaredField("instanceType"); + instanceTypeField.setAccessible(true); + InstanceType instanceType = (InstanceType) instanceTypeField.get(builder); + assertThat(instanceType).isEqualTo(InstanceType.OMNI); + } +} diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/configs/YamlConfigLoaderTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/configs/YamlConfigLoaderTest.java index 19547aa7..28a793fc 100644 --- a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/configs/YamlConfigLoaderTest.java +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/configs/YamlConfigLoaderTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; import java.io.IOException; import java.io.InputStream; import java.util.List; @@ -178,8 +179,10 @@ public void testLoad_validUseClientCertYamlFile_parsesCorrectly() throws IOExcep assertThat(userConfigs).isNotNull(); assertThat(userConfigs.getGlobalClientConfigs()).isNotNull(); - assertThat(userConfigs.getGlobalClientConfigs().getExperimentalHostEndpoint()) + assertThat(userConfigs.getGlobalClientConfigs().getSpannerEndpoint()) .isEqualTo("localhost:15000"); + assertThat(userConfigs.getGlobalClientConfigs().getInstanceType()) + .isEqualTo(InstanceType.OMNI); assertThat(userConfigs.getGlobalClientConfigs().getEnableBuiltInMetrics()).isTrue(); assertThat(userConfigs.getGlobalClientConfigs().getHealthCheckEndpoint()) .isEqualTo("127.0.0.1:8080"); diff --git a/google-cloud-spanner-cassandra/src/test/resources/invalid-host-conflict-config.yaml b/google-cloud-spanner-cassandra/src/test/resources/invalid-host-conflict-config.yaml deleted file mode 100644 index 9182ace9..00000000 --- a/google-cloud-spanner-cassandra/src/test/resources/invalid-host-conflict-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -globalClientConfigs: - spannerEndpoint: "custom-spanner.com:443" - experimentalHostEndpoint: "experimental-spanner.com:443" - enableBuiltInMetrics: true - healthCheckEndpoint: "127.0.0.1:8080" -listeners: - - name: "listener_1" - host: "127.0.0.1" - port: 9042 - spanner: - databaseUri: "projects/my-project/instances/my-instance/databases/my-database" \ No newline at end of file diff --git a/google-cloud-spanner-cassandra/src/test/resources/valid-useclientcert-config.yaml b/google-cloud-spanner-cassandra/src/test/resources/valid-useclientcert-config.yaml index 4753c86f..bf757bf9 100644 --- a/google-cloud-spanner-cassandra/src/test/resources/valid-useclientcert-config.yaml +++ b/google-cloud-spanner-cassandra/src/test/resources/valid-useclientcert-config.yaml @@ -2,7 +2,8 @@ globalClientConfigs: enableBuiltInMetrics: true healthCheckEndpoint: "127.0.0.1:8080" - experimentalHostEndpoint: "localhost:15000" + spannerEndpoint: "localhost:15000" + instanceType: "omni" clientCertPath: "/path/to/client.crt" clientKeyPath: "/path/to/client.key.pkcs8" diff --git a/integration-tests/src/test/java/com/google/cloud/spanner/adapter/utils/SpannerContext.java b/integration-tests/src/test/java/com/google/cloud/spanner/adapter/utils/SpannerContext.java index 165611f4..980faa0d 100644 --- a/integration-tests/src/test/java/com/google/cloud/spanner/adapter/utils/SpannerContext.java +++ b/integration-tests/src/test/java/com/google/cloud/spanner/adapter/utils/SpannerContext.java @@ -28,6 +28,7 @@ import com.google.cloud.spanner.adapter.SpannerCqlRetryPolicy; import com.google.cloud.spanner.adapter.SpannerCqlSession; import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder; +import com.google.cloud.spanner.adapter.SpannerCqlSessionBuilder.InstanceType; import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient; import com.google.cloud.spanner.admin.database.v1.DatabaseAdminSettings; import com.google.common.base.Strings; @@ -49,13 +50,12 @@ public class SpannerContext extends DatabaseContext { private static final String ENV_VAR_SPANNER_ENDPOINT = "SPANNER_ENDPOINT"; - private static final String EXPERIMENTAL_HOST_ENDPOINT_PROPERTY = - "spanner_cassandra.experimental_host"; + private static final String INSTANCE_TYPE_PROPERTY = "spanner_cassandra.instance_type"; private static final String USE_PLAIN_TEXT_PROPERTY = "spanner_cassandra.use_plain_text"; private static final String CLIENT_CERT_PATH_PROPERTY = "spanner_cassandra.client_cert_path"; private static final String CLIENT_KEY_PATH_PROPERTY = "spanner_cassandra.client_key_path"; - private static final String EXPERIMENTAL_HOST_INSTANCE = "projects/default/instances/default"; - private static final String EXPERIMENTAL_HOST_ID = "default"; + private static final String SPANNER_OMNI_INSTANCE = "projects/default/instances/default"; + private static final String SPANNER_OMNI_ID = "default"; private static final String DEFAULT_SPANNER_ENDPOINT = "spanner.googleapis.com:443"; @@ -64,21 +64,35 @@ public class SpannerContext extends DatabaseContext { private final DatabaseName databaseName; private DatabaseAdminClient databaseAdminClient; - private Spanner experimentalHostSpanner; + private Spanner spannerOmni; private CqlSession session; - /* Determines whether endpoint is an experimental host */ - private boolean isRunningOnExperimentalHost() { - return !Strings.isNullOrEmpty(System.getProperty(EXPERIMENTAL_HOST_ENDPOINT_PROPERTY)); + private InstanceType getInstanceType() { + String typeProp = System.getProperty(INSTANCE_TYPE_PROPERTY); + if (!Strings.isNullOrEmpty(typeProp)) { + return InstanceType.valueOf(typeProp.toUpperCase()); + } + if (!Strings.isNullOrEmpty(getSpannerEndpoint())) { + return InstanceType.OMNI; + } + return InstanceType.CLOUD; + } + + private String getSpannerEndpoint() { + String endpoint = System.getProperty(ENV_VAR_SPANNER_ENDPOINT); + if (Strings.isNullOrEmpty(endpoint)) { + endpoint = System.getenv(ENV_VAR_SPANNER_ENDPOINT); + } + return endpoint; } public SpannerContext() { super("Spanner"); databaseId = keyspace; final String instanceNameStr = - !isRunningOnExperimentalHost() + getInstanceType() != InstanceType.OMNI ? System.getenv("INTEGRATION_TEST_INSTANCE") - : EXPERIMENTAL_HOST_INSTANCE; + : SPANNER_OMNI_INSTANCE; if (instanceNameStr == null) { throw new NullPointerException("Environment variable INTEGRATION_TEST_INSTANCE must be set"); } @@ -100,7 +114,7 @@ public CqlSession getSession() { @Override public void createTables(TableDefinition... tableDefinitions) throws Exception { - if (databaseAdminClient == null && !isRunningOnExperimentalHost()) { + if (databaseAdminClient == null && getInstanceType() != InstanceType.OMNI) { throw new IllegalStateException("initialize() not called."); } List ddls = new ArrayList<>(); @@ -108,13 +122,13 @@ public void createTables(TableDefinition... tableDefinitions) throws Exception { ddls.add("DROP TABLE IF EXISTS " + tableDefinition.tableName); ddls.add(generateSpannerDdl(tableDefinition.tableName, tableDefinition.columnDefinitions)); } - if (isRunningOnExperimentalHost()) { - if (experimentalHostSpanner == null) { + if (getInstanceType() == InstanceType.OMNI) { + if (spannerOmni == null) { throw new IllegalStateException("initialize() not called."); } - experimentalHostSpanner + spannerOmni .getDatabaseAdminClient() - .updateDatabaseDdl(EXPERIMENTAL_HOST_ID, databaseId, ddls, null) + .updateDatabaseDdl(SPANNER_OMNI_ID, databaseId, ddls, null) .get(5, TimeUnit.MINUTES); } else { databaseAdminClient.updateDatabaseDdlAsync(databaseName, ddls).get(5, TimeUnit.MINUTES); @@ -128,9 +142,9 @@ private int findFreePort() throws IOException { } } - private void initializeExperimentalHostSpanner() { - String endpoint = System.getProperty(EXPERIMENTAL_HOST_ENDPOINT_PROPERTY); - if (!endpoint.startsWith("http")) { + private void initializeSpannerOmni() { + String endpoint = getSpannerEndpoint(); + if (!Strings.isNullOrEmpty(endpoint) && !endpoint.startsWith("http")) { if (Boolean.getBoolean(USE_PLAIN_TEXT_PROPERTY)) { endpoint = "http://" + endpoint; } else { @@ -149,13 +163,13 @@ private void initializeExperimentalHostSpanner() { System.getProperty(CLIENT_CERT_PATH_PROPERTY), System.getProperty(CLIENT_KEY_PATH_PROPERTY)); } - experimentalHostSpanner = builder.build().getService(); + spannerOmni = builder.build().getService(); } @Override public void initialize() throws Exception { - if (!isRunningOnExperimentalHost()) { - experimentalHostSpanner = null; + if (getInstanceType() != InstanceType.OMNI) { + spannerOmni = null; final String env_var_endpoint = System.getenv(ENV_VAR_SPANNER_ENDPOINT); DatabaseAdminSettings settings = DatabaseAdminSettings.newBuilder() @@ -166,12 +180,12 @@ public void initialize() throws Exception { .createDatabaseAsync(instanceName, "CREATE DATABASE " + databaseId) .get(5, TimeUnit.MINUTES); } else { - initializeExperimentalHostSpanner(); + initializeSpannerOmni(); databaseAdminClient = null; - experimentalHostSpanner + spannerOmni .getDatabaseAdminClient() .createDatabase( - EXPERIMENTAL_HOST_ID, + SPANNER_OMNI_ID, "CREATE DATABASE " + databaseId, Dialect.GOOGLE_STANDARD_SQL, Collections.emptyList()) @@ -200,10 +214,12 @@ public void initialize() throws Exception { DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT, Duration.ofMinutes(5)) .withDuration(DefaultDriverOption.HEARTBEAT_TIMEOUT, Duration.ofMinutes(1)) .build()); - if (isRunningOnExperimentalHost()) { - sessionBuilder - .setExperimentalHostEndpoint(System.getProperty(EXPERIMENTAL_HOST_ENDPOINT_PROPERTY)) - .setUsePlainText(false); + if (getInstanceType() == InstanceType.OMNI) { + String endpoint = getSpannerEndpoint(); + if (!Strings.isNullOrEmpty(endpoint)) { + sessionBuilder.setHost(endpoint); + } + sessionBuilder.setInstanceType(InstanceType.OMNI).setUsePlainText(false); if (Boolean.getBoolean(USE_PLAIN_TEXT_PROPERTY)) { sessionBuilder.setUsePlainText(true); } else if (!Strings.isNullOrEmpty(System.getProperty(CLIENT_CERT_PATH_PROPERTY)) @@ -221,11 +237,9 @@ public void cleanup() throws Exception { if (databaseAdminClient != null) { databaseAdminClient.dropDatabase(databaseName); databaseAdminClient.close(); - } else if (experimentalHostSpanner != null) { - experimentalHostSpanner - .getDatabaseAdminClient() - .dropDatabase(EXPERIMENTAL_HOST_ID, databaseId); - experimentalHostSpanner.close(); + } else if (spannerOmni != null) { + spannerOmni.getDatabaseAdminClient().dropDatabase(SPANNER_OMNI_ID, databaseId); + spannerOmni.close(); } if (session != null) { session.close();