diff --git a/cicd/cmd/run-it-smoke-tests/main.go b/cicd/cmd/run-it-smoke-tests/main.go
index 752c734536..2911f4383c 100644
--- a/cicd/cmd/run-it-smoke-tests/main.go
+++ b/cicd/cmd/run-it-smoke-tests/main.go
@@ -67,9 +67,11 @@ func main() {
flags.SpannerHost(),
flags.FailureMode(),
flags.RetryFailures(),
- flags.StaticOracleInstance(),
+ flags.StaticOracleHost(),
+ flags.StaticOracleSysPassword(),
flags.CloudProxyHost(),
- flags.CloudProxyPort(),
+ flags.CloudProxyMySqlPort(),
+ flags.CloudProxyPostgresPort(),
flags.CloudProxyPassword())
if err != nil {
log.Fatalf("%v\n", err)
diff --git a/cicd/cmd/run-it-tests/main.go b/cicd/cmd/run-it-tests/main.go
index 8a36ff9ccf..45de079cfe 100644
--- a/cicd/cmd/run-it-tests/main.go
+++ b/cicd/cmd/run-it-tests/main.go
@@ -68,9 +68,11 @@ func main() {
flags.SpannerHost(),
flags.FailureMode(),
flags.RetryFailures(),
- flags.StaticOracleInstance(),
+ flags.StaticOracleHost(),
+ flags.StaticOracleSysPassword(),
flags.CloudProxyHost(),
- flags.CloudProxyPort(),
+ flags.CloudProxyMySqlPort(),
+ flags.CloudProxyPostgresPort(),
flags.CloudProxyPassword())
if err != nil {
log.Fatalf("%v\n", err)
diff --git a/cicd/cmd/run-load-tests/main.go b/cicd/cmd/run-load-tests/main.go
index ca38e5dafd..379fc2eb90 100644
--- a/cicd/cmd/run-load-tests/main.go
+++ b/cicd/cmd/run-load-tests/main.go
@@ -67,9 +67,11 @@ func main() {
flags.ExportProject(),
flags.ExportDataset(),
flags.ExportTable(),
- flags.StaticOracleInstance(),
+ flags.StaticOracleHost(),
+ flags.StaticOracleSysPassword(),
flags.CloudProxyHost(),
- flags.CloudProxyPort(),
+ flags.CloudProxyMySqlPort(),
+ flags.CloudProxyPostgresPort(),
flags.CloudProxyPassword())
if err != nil {
log.Fatalf("%v\n", err)
diff --git a/cicd/internal/flags/it-flags.go b/cicd/internal/flags/it-flags.go
index f8a54e867e..cceac0b924 100644
--- a/cicd/internal/flags/it-flags.go
+++ b/cicd/internal/flags/it-flags.go
@@ -24,19 +24,21 @@ import (
// Avoid making these vars public.
var (
- dRegion string
- dProject string
- dArtifactBucket string
- dStageBucket string
- dHostIp string
- dPrivateConnectivity string
- dSpannerHost string
- dReleaseMode bool
- dRetryFailures string
- dCloudProxyHost string
- dCloudProxyPort string
- dCloudProxyPassword string
- dOracleInstance string
+ dRegion string
+ dProject string
+ dArtifactBucket string
+ dStageBucket string
+ dHostIp string
+ dPrivateConnectivity string
+ dSpannerHost string
+ dReleaseMode bool
+ dRetryFailures string
+ dCloudProxyHost string
+ dCloudProxyMySqlPort string
+ dCloudProxyPostgresPort string
+ dCloudProxyPassword string
+ dOracleHost string
+ dCloudOracleSysPassword string
)
// Registers all common flags. Must be called before flag.Parse().
@@ -51,9 +53,11 @@ func RegisterItFlags() {
flag.BoolVar(&dReleaseMode, "it-release", false, "(optional) Set if tests are being executed for a release")
flag.StringVar(&dRetryFailures, "it-retry-failures", "0", "Number of retries attempts for failing tests")
flag.StringVar(&dCloudProxyHost, "it-cloud-proxy-host", "10.128.0.34", "Hostname or IP address of static Cloud Auth Proxy")
- flag.StringVar(&dCloudProxyPort, "it-cloud-proxy-port", "33134", "Port number of static Cloud Auth Proxy")
+ flag.StringVar(&dCloudProxyMySqlPort, "it-cloud-proxy-mysql-port", "33134", "MySql port number on static Cloud Auth Proxy")
+ flag.StringVar(&dCloudProxyPostgresPort, "it-cloud-proxy-postgres-port", "33136", "Postgres port number on static Cloud Auth Proxy")
flag.StringVar(&dCloudProxyPassword, "it-cloud-proxy-password", "t>5xl%J(&qTK6?FaZ", "Password of static Cloud Auth Proxy")
- flag.StringVar(&dOracleInstance, "it-oracle-host", "10.128.0.90", "Hostname or IP address of static Oracle DB")
+ flag.StringVar(&dOracleHost, "it-oracle-host", "10.128.0.90", "Hostname or IP address of static Oracle DB")
+ flag.StringVar(&dCloudOracleSysPassword, "it-oracle-sys-password", "oracle", "sys password of static Oracle DB")
}
func Region() string {
@@ -119,14 +123,22 @@ func CloudProxyHost() string {
return "-DcloudProxyHost=" + dCloudProxyHost
}
-func CloudProxyPort() string {
- return "-DcloudProxyPort=" + dCloudProxyPort
+func CloudProxyMySqlPort() string {
+ return "-DcloudProxyMySqlPort=" + dCloudProxyMySqlPort
+}
+
+func CloudProxyPostgresPort() string {
+ return "-DcloudProxyPostgresPort=" + dCloudProxyPostgresPort
}
func CloudProxyPassword() string {
return "-DcloudProxyPassword=" + dCloudProxyPassword
}
-func StaticOracleInstance() string {
- return "-DcloudOracleHost=" + dOracleInstance
+func StaticOracleHost() string {
+ return "-DcloudOracleHost=" + dOracleHost
+}
+
+func StaticOracleSysPassword() string {
+ return "-DcloudOracleSysPassword=" + dCloudOracleSysPassword
}
diff --git a/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudMySQLResourceManager.java b/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudMySQLResourceManager.java
index b32cd6c820..37031c7863 100644
--- a/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudMySQLResourceManager.java
+++ b/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudMySQLResourceManager.java
@@ -18,6 +18,8 @@
package org.apache.beam.it.gcp.cloudsql;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Custom class for the MySQL implementation of {@link CloudSqlResourceManager} abstract class.
@@ -29,6 +31,8 @@
*/
public class CloudMySQLResourceManager extends CloudSqlResourceManager {
+ private static final Logger LOG = LoggerFactory.getLogger(CloudMySQLResourceManager.class);
+
private CloudMySQLResourceManager(Builder builder) {
super(builder);
}
@@ -49,6 +53,15 @@ public Builder(String testId) {
super(testId);
}
+ @Override
+ protected void configurePort() {
+ if (System.getProperty("cloudProxyMySqlPort") != null) {
+ this.setPort(Integer.parseInt(System.getProperty("cloudProxyMySqlPort")));
+ } else {
+ LOG.warn("Missing -DcloudProxyMySqlPort.");
+ }
+ }
+
@Override
public @NonNull CloudMySQLResourceManager build() {
return new CloudMySQLResourceManager(this);
diff --git a/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudOracleResourceManager.java b/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudOracleResourceManager.java
index 448d40c2f7..1e5081a77b 100644
--- a/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudOracleResourceManager.java
+++ b/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudOracleResourceManager.java
@@ -36,11 +36,16 @@ public class CloudOracleResourceManager extends CloudSqlResourceManager {
private static final Logger LOG = LoggerFactory.getLogger(CloudOracleResourceManager.class);
+ private static final String DEFAULT_SYSTEM_IDENTIFIER = "xe";
+
private static final int DEFAULT_ORACLE_PORT = 1521;
- private CloudOracleResourceManager(Builder builder) {
+ private String systemIdentifier;
+
+ protected CloudOracleResourceManager(Builder builder) {
super(builder);
+ this.systemIdentifier = builder.systemIdentifier;
System.setProperty("oracle.jdbc.timezoneAsRegion", "false");
}
@@ -65,27 +70,65 @@ public static Builder builder(String testId) {
return "SELECT * FROM " + tableName + " WHERE ROWNUM <= 1";
}
+ /**
+ * Return the SID of the connected DB.
+ *
+ * @return the SID.
+ */
+ public String getSystemIdentifier() {
+ return this.systemIdentifier;
+ }
+
/** Builder for {@link CloudOracleResourceManager}. */
public static final class Builder extends CloudSqlResourceManager.Builder {
+ private String systemIdentifier;
+
public Builder(String testId) {
super(testId);
- this.setDatabaseName("xe");
- this.setPort(DEFAULT_ORACLE_PORT);
-
- // Currently only supports static Oracle instance on GCE
- this.maybeUseStaticInstance();
+ this.setSystemIdentifier(DEFAULT_SYSTEM_IDENTIFIER);
+ this.setDatabaseName(this.systemIdentifier);
}
- public Builder maybeUseStaticInstance() {
+ @Override
+ protected void configureHost() {
if (System.getProperty("cloudOracleHost") != null) {
this.setHost(System.getProperty("cloudOracleHost"));
} else {
LOG.warn("Missing -DcloudOracleHost.");
}
- this.useStaticContainer();
+ }
+
+ @Override
+ protected void configurePort() {
+ if (System.getProperty("cloudOraclePort") != null) {
+ this.setPort(Integer.parseInt(System.getProperty("cloudOraclePort")));
+ } else {
+ this.setPort(DEFAULT_ORACLE_PORT);
+ }
+ }
+
+ @Override
+ protected void configureUsername() {
+ if (System.getProperty("cloudOracleUsername") != null) {
+ this.setUsername(System.getProperty("cloudOracleUsername"));
+ } else {
+ super.configureUsername();
+ }
+ }
+
+ @Override
+ protected void configurePassword() {
+ if (System.getProperty("cloudOraclePassword") != null) {
+ this.setPassword(System.getProperty("cloudOraclePassword"));
+ } else {
+ super.configurePassword();
+ }
+ }
+ public Builder setSystemIdentifier(String systemIdentifier) {
+ this.systemIdentifier = systemIdentifier;
return this;
}
diff --git a/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudPostgresResourceManager.java b/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudPostgresResourceManager.java
new file mode 100644
index 0000000000..756ce8d23d
--- /dev/null
+++ b/it/google-cloud-platform/src/main/java/org/apache/beam/it/gcp/cloudsql/CloudPostgresResourceManager.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.beam.it.gcp.cloudsql;
+
+import java.util.List;
+import java.util.Map;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Custom class for the Postgres implementation of {@link CloudSqlResourceManager} abstract class.
+ *
+ *
The class supports one database, and multiple tables per database object. A database is *
+ * created when the container first spins up, if one is not given.
+ *
+ *
A schema will also be created with the same name as the DB, unless one is manually set in the
+ * builder.
+ *
+ *
The class is thread-safe.
+ */
+public class CloudPostgresResourceManager extends CloudSqlResourceManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CloudPostgresResourceManager.class);
+
+ private static final String DEFAULT_POSTGRES_USERNAME = "postgres";
+
+ private String pgSchema;
+ private boolean createdSchema;
+
+ private CloudPostgresResourceManager(Builder builder) {
+ super(builder);
+ this.pgSchema = builder.schema;
+ this.createdSchema = false;
+
+ // Set schema set by builder or default to use same name as database
+ if (this.pgSchema == null) {
+ this.pgSchema = databaseName;
+ LOG.info("Creating Postgres schema {}.", this.pgSchema);
+ runSQLUpdate(String.format("CREATE SCHEMA IF NOT EXISTS %s", this.pgSchema));
+ this.createdSchema = true;
+ }
+ }
+
+ public static Builder builder(String testId) {
+ return new Builder(testId);
+ }
+
+ public String getSchema() {
+ return this.pgSchema;
+ }
+
+ public String getFullTableName(String tableName) {
+ return String.format("%s.%s", pgSchema, tableName);
+ }
+
+ @Override
+ public @NonNull String getJDBCPrefix() {
+ return "postgresql";
+ }
+
+ @Override
+ public boolean createTable(@NonNull String tableName, @NonNull JDBCSchema schema) {
+ boolean status = super.createTable(tableName, schema);
+
+ // Set table schema
+ runSQLUpdate(String.format("ALTER TABLE %s SET SCHEMA %s", tableName, pgSchema));
+ this.createdTables.remove(tableName);
+ this.createdTables.add(tableName);
+
+ return status;
+ }
+
+ @Override
+ public void dropTable(@NonNull String tableName) {
+ super.dropTable(getFullTableName(tableName));
+ }
+
+ @Override
+ public boolean write(String tableName, List