This is an automated email from the ASF dual-hosted git repository.
Gabriel39 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 7d231485588 [fix](fe) Validate Hive HDFS HA properties during catalog
DDL (#68585)
7d231485588 is described below
commit 7d2314855883bab61255d77c6c18d8d535357a68
Author: Oliveira <[email protected]>
AuthorDate: Wed Sep 30 16:25:05 2026 +0800
[fix](fe) Validate Hive HDFS HA properties during catalog DDL (#68585)
### What problem does this PR solve?
Issue Number: DORIS-29461
Related PR: None
Problem Summary: Plugin-driven Hive catalogs accepted incomplete HDFS HA
properties during CREATE and ALTER. For example, a catalog with
`dfs.nameservices=ns1` but no `dfs.ha.namenodes.ns1`, or with an empty
nameservice list, could be persisted successfully and only fail when the
first external table accessed storage. The DDL validation path now binds
Hive storage properties before persisting the catalog, and HDFS HA
validation rejects empty nameservice entries and validates the required
NameNode, RPC address, and failover provider properties. The behavior is
covered by FE unit tests and an external regression suite.
### Release note
Hive Catalog CREATE and ALTER now reject incomplete HDFS HA
configurations during DDL validation.
### Check List (For Author)
- Test: Unit Test / Regression test
- FE unit tests: `PluginDrivenExternalCatalogConcurrencyTest`,
`HdfsPropertiesTest`
- External regression:
`external_table_p0/hive/test_hive_ha_catalog_validation`
- FE build and Checkstyle passed
- Behavior changed: Yes (invalid Hive HDFS HA configurations fail during
CREATE/ALTER instead of being deferred until storage access)
- Does this need documentation: No
---
.../org/apache/doris/datasource/CatalogMgr.java | 92 ++++++++++++++++------
.../plugin/PluginDrivenExternalCatalog.java | 25 ++++++
.../doris/datasource/storage/StorageAdapter.java | 2 +-
.../org/apache/doris/fs/FileSystemFactory.java | 14 ++--
...PluginDrivenExternalCatalogConcurrencyTest.java | 30 +++++++
.../hdfs/properties/HdfsConfigFileLoader.java | 3 +-
.../hdfs/properties/HdfsPropertiesUtils.java | 12 ++-
.../hdfs/properties/HdfsPropertiesTest.java | 25 +++++-
.../hive/test_hive_ha_catalog_validation.groovy | 91 +++++++++++++++++++++
9 files changed, 254 insertions(+), 40 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java
index d3fa79b847c..fb2ce39374d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java
@@ -288,6 +288,14 @@ public class CatalogMgr implements Writable,
GsonPostProcessable {
}
long id = Env.getCurrentEnv().getNextId();
CatalogIf catalog = CatalogFactory.createFromCommand(id, cmd);
+ if (catalog instanceof ExternalCatalog) {
+ try {
+ ((ExternalCatalog) catalog).checkProperties();
+ } catch (DdlException | RuntimeException e) {
+ catalog.onCreateFailure();
+ throw e;
+ }
+ }
createCatalogImpl(catalog, cmd.getCatalogName(),
cmd.isSetIfNotExists());
}
@@ -410,26 +418,60 @@ public class CatalogMgr implements Writable,
GsonPostProcessable {
* Modify the catalog property and write the meta log.
*/
public void alterCatalogProps(String catalogName, Map<String, String>
newProperties) throws UserException {
- Runnable accessControllerCleanup = () -> { };
- writeLock();
- try {
- CatalogIf catalog = nameToCatalog.get(catalogName);
- if (catalog == null) {
- throw new DdlException("No catalog found with name: " +
catalogName);
+ Map<String, String> updates = Maps.newHashMap(newProperties);
+ while (true) {
+ CatalogIf catalog;
+ Map<String, String> oldProperties;
+ readLock();
+ try {
+ catalog = nameToCatalog.get(catalogName);
+ if (catalog == null) {
+ throw new DdlException("No catalog found with name: " +
catalogName);
+ }
+ oldProperties = Maps.newHashMap(catalog.getProperties());
+ if (updates.containsKey("type") && !catalog.getType()
+ .equalsIgnoreCase(updates.get("type"))) {
+ throw new DdlException("Can't modify the type of catalog
property with name: " + catalogName);
+ }
+ } finally {
+ readUnlock();
}
- Map<String, String> oldProperties = catalog.getProperties();
- if (newProperties.containsKey("type") && !catalog.getType()
- .equalsIgnoreCase(newProperties.get("type"))) {
- throw new DdlException("Can't modify the type of catalog
property with name: " + catalogName);
+
+ // Filesystem binding may read Hadoop XML files. Validate the
detached snapshot before
+ // taking the global catalog write lock, then retry if another
ALTER changed the snapshot.
+ boolean validatedWithoutMutation = catalog instanceof
ExternalCatalog
+ && validateCatalogPropsBeforeUpdate((ExternalCatalog)
catalog, oldProperties, updates);
+ Runnable accessControllerCleanup = () -> { };
+ writeLock();
+ try {
+ if (nameToCatalog.get(catalogName) != catalog
+ || !oldProperties.equals(catalog.getProperties())) {
+ continue;
+ }
+ CatalogLog log = new CatalogLog();
+ log.setCatalogId(catalog.getId());
+ log.setNewProps(updates);
+ accessControllerCleanup = applyAlterCatalogProps(
+ log, oldProperties, false, true,
validatedWithoutMutation);
+
Env.getCurrentEnv().getEditLog().logCatalogLog(OperationType.OP_ALTER_CATALOG_PROPS,
log);
+ return;
+ } finally {
+ writeUnlock();
+ accessControllerCleanup.run();
}
- CatalogLog log = new CatalogLog();
- log.setCatalogId(catalog.getId());
- log.setNewProps(newProperties);
- accessControllerCleanup = applyAlterCatalogProps(log,
oldProperties, false, true);
-
Env.getCurrentEnv().getEditLog().logCatalogLog(OperationType.OP_ALTER_CATALOG_PROPS,
log);
- } finally {
- writeUnlock();
- accessControllerCleanup.run();
+ }
+ }
+
+ private boolean validateCatalogPropsBeforeUpdate(ExternalCatalog catalog,
Map<String, String> oldProperties,
+ Map<String, String> newProperties) throws DdlException {
+ try {
+ return catalog.validatePropertiesBeforeUpdate(oldProperties,
newProperties);
+ } catch (Exception validationException) {
+ if (validationException instanceof DdlException) {
+ throw (DdlException) validationException;
+ }
+ throw new DdlException("Invalid catalog properties: "
+ + validationException.getMessage(), validationException);
}
}
@@ -553,9 +595,6 @@ public class CatalogMgr implements Writable,
GsonPostProcessable {
private void createCatalogInternal(CatalogIf catalog, boolean isReplay)
throws DdlException {
writeLock();
try {
- if (!isReplay && catalog instanceof ExternalCatalog) {
- ((ExternalCatalog) catalog).checkProperties();
- }
Map<String, String> props = catalog.getProperties();
if (props.containsKey(METADATA_REFRESH_INTERVAL_SEC)) {
// need refresh
@@ -647,7 +686,7 @@ public class CatalogMgr implements Writable,
GsonPostProcessable {
Runnable accessControllerCleanup = () -> { };
writeLock();
try {
- accessControllerCleanup = applyAlterCatalogProps(log,
oldProperties, isReplay, true);
+ accessControllerCleanup = applyAlterCatalogProps(log,
oldProperties, isReplay, true, false);
} finally {
writeUnlock();
accessControllerCleanup.run();
@@ -655,16 +694,17 @@ public class CatalogMgr implements Writable,
GsonPostProcessable {
}
private Runnable applyAlterCatalogProps(CatalogLog log, Map<String,
String> oldProperties,
- boolean isReplay, boolean deferAccessControllerCleanup) throws
DdlException {
+ boolean isReplay, boolean deferAccessControllerCleanup, boolean
validatedWithoutMutation)
+ throws DdlException {
CatalogIf catalog = idToCatalog.get(log.getCatalogId());
if (catalog instanceof ExternalCatalog) {
Map<String, String> newProps = log.getNewProps();
- if (!isReplay) {
+ if (!isReplay && !validatedWithoutMutation) {
ExternalCatalog externalCatalog = (ExternalCatalog) catalog;
try {
- boolean validatedWithoutMutation =
externalCatalog.validatePropertiesBeforeUpdate(
+ boolean validatedWithoutMutationInLock =
externalCatalog.validatePropertiesBeforeUpdate(
oldProperties, newProps);
- if (!validatedWithoutMutation) {
+ if (!validatedWithoutMutationInLock) {
synchronized (externalCatalog) {
Map<String, String> currentProperties =
Maps.newHashMap(externalCatalog.getProperties());
try {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
index 85959852cf5..2a877d26b20 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
@@ -69,7 +69,9 @@ import
org.apache.doris.datasource.connector.converter.ConnectorColumnConverter;
import
org.apache.doris.datasource.connector.converter.ConnectorPartitionFieldConverter;
import org.apache.doris.datasource.log.ExternalObjectLog;
import org.apache.doris.datasource.log.InitCatalogLog;
+import org.apache.doris.foundation.property.StoragePropertiesException;
import org.apache.doris.foundation.security.JdbcDriverUrlSecurity;
+import org.apache.doris.fs.FileSystemFactory;
import org.apache.doris.nereids.trees.plans.commands.info.AddPartitionFieldOp;
import org.apache.doris.nereids.trees.plans.commands.info.CreateTableInfo;
import org.apache.doris.nereids.trees.plans.commands.info.DropPartitionFieldOp;
@@ -230,6 +232,7 @@ public class PluginDrivenExternalCatalog extends
ExternalCatalog {
} catch (IllegalArgumentException e) {
throw new DdlException(e.getMessage());
}
+ validateStorageProperties(catalogProperty);
// Validate function_rules JSON if present (shared across all
connector types).
String functionRules = catalogProperty.getOrDefault("function_rules",
null);
ExternalFunctionRules.check(functionRules);
@@ -253,11 +256,33 @@ public class PluginDrivenExternalCatalog extends
ExternalCatalog {
} catch (IllegalArgumentException e) {
throw new DdlException(e.getMessage(), e);
}
+ validateStorageProperties(candidateProperty);
checkDriverUrlsAgainstOperatorGate(candidate, updatedProperties);
ExternalFunctionRules.check(candidateProperty.getOrDefault("function_rules",
null));
return true;
}
+ /**
+ * Bind Hive catalog storage properties during DDL validation so HDFS
configuration errors are
+ * reported by CREATE/ALTER instead of being deferred until the first
table access.
+ */
+ private void validateStorageProperties(CatalogProperty property) throws
DdlException {
+ if (!"hms".equalsIgnoreCase(getType())) {
+ return;
+ }
+ String nameservices = property.getProperties().get("dfs.nameservices");
+ if (nameservices != null
+ && java.util.Arrays.stream(nameservices.split(","))
+ .map(String::trim).noneMatch(value -> !value.isEmpty())) {
+ throw new DdlException("Property dfs.nameservices must contain a
nameservice");
+ }
+ try {
+
FileSystemFactory.bindAllStorageProperties(property.getProperties());
+ } catch (IllegalArgumentException | StoragePropertiesException e) {
+ throw new DdlException(e.getMessage(), e);
+ }
+ }
+
/**
* Applies the operator's driver-jar gate ({@code jdbc_driver_secure_path}
/
* {@code jdbc_driver_url_white_list}) to every driver_url these
properties would make the connector
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/storage/StorageAdapter.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/storage/StorageAdapter.java
index e5df6e21196..0c42c095d33 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/storage/StorageAdapter.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/storage/StorageAdapter.java
@@ -206,7 +206,7 @@ public final class StorageAdapter {
* Broker/Local/Http verbatim backend maps stay clean — and only when a
* {@code *config.resources} key is present (the only consumer of the
marker).
*/
- private static Map<String, String> withHadoopConfigDir(Map<String, String>
props) {
+ public static Map<String, String> withHadoopConfigDir(Map<String, String>
props) {
if (props == null || props.containsKey("_HADOOP_CONFIG_DIR_")
|| StringUtils.isBlank(Config.hadoop_config_dir)) {
return props;
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/fs/FileSystemFactory.java
b/fe/fe-core/src/main/java/org/apache/doris/fs/FileSystemFactory.java
index bbf1ee84e21..a71d6c0a2e4 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/fs/FileSystemFactory.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/fs/FileSystemFactory.java
@@ -97,18 +97,19 @@ public final class FileSystemFactory {
*/
public static org.apache.doris.filesystem.FileSystem
getFileSystem(Map<String, String> properties)
throws IOException {
+ Map<String, String> normalizedProperties =
StorageAdapter.withHadoopConfigDir(properties);
FileSystemPluginManager mgr = pluginManager;
if (mgr != null) {
- return mgr.createFileSystem(properties);
+ return mgr.createFileSystem(normalizedProperties);
}
// Fallback: ServiceLoader discovery (unit-test / migration path)
List<FileSystemProvider> providers = getProviders();
List<String> tried = new ArrayList<>();
for (FileSystemProvider provider : providers) {
- if (provider.supports(properties)) {
+ if (provider.supports(normalizedProperties)) {
LOG.debug("FileSystemFactory: selected SPI provider '{}' for
keys={}",
provider.name(), properties.keySet());
- return provider.create(properties);
+ return provider.create(normalizedProperties);
}
tried.add(provider.name());
}
@@ -135,16 +136,17 @@ public final class FileSystemFactory {
// fe-core Config, so the HDFS plugin's config-resource loader reads
this system property instead. Keep
// the key in sync with HdfsConfigFileLoader.CONFIG_DIR_PROPERTY
("doris.hadoop.config.dir").
System.setProperty("doris.hadoop.config.dir",
Config.hadoop_config_dir);
+ Map<String, String> normalizedProperties =
StorageAdapter.withHadoopConfigDir(properties);
FileSystemPluginManager mgr = pluginManager;
if (mgr != null) {
- return new ArrayList<>(mgr.bindAll(properties));
+ return new ArrayList<>(mgr.bindAll(normalizedProperties));
}
// Fallback: ServiceLoader discovery (unit-test / migration path),
mirroring getFileSystem(Map).
List<org.apache.doris.filesystem.properties.StorageProperties> result
= new ArrayList<>();
for (FileSystemProvider provider : getProviders()) {
- if (provider.supports(properties)) {
+ if (provider.supports(normalizedProperties)) {
try {
- result.add(provider.bind(properties));
+ result.add(provider.bind(normalizedProperties));
} catch (UnsupportedOperationException e) {
LOG.debug("FileSystemProvider {} has no typed binding;
skipping in "
+ "bindAllStorageProperties", provider.name());
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
index 0b456b2cebb..2896ac58f58 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
@@ -100,6 +100,36 @@ public class PluginDrivenExternalCatalogConcurrencyTest {
Assertions.assertTrue(exception.getMessage().contains("short timezone
aliases are not supported"));
}
+ @Test
+ public void testCreateRejectsIncompleteHiveHaConfiguration() {
+ Map<String, String> properties = hiveCatalogProperties();
+ properties.put("dfs.nameservices", "ns1");
+ PluginDrivenExternalCatalog catalog = new PluginDrivenExternalCatalog(
+ 1L, "test-catalog", null, properties, "", null);
+
+ DdlException exception = Assertions.assertThrows(DdlException.class,
catalog::checkProperties);
+
Assertions.assertTrue(exception.getMessage().contains("dfs.ha.namenodes.ns1"),
exception.getMessage());
+ }
+
+ @Test
+ public void testAlterRejectsIncompleteHiveHaConfiguration() {
+ Map<String, String> properties = hiveCatalogProperties();
+ PluginDrivenExternalCatalog catalog = new PluginDrivenExternalCatalog(
+ 1L, "test-catalog", null, properties, "", null);
+
+ DdlException exception = Assertions.assertThrows(DdlException.class,
+ () -> catalog.validatePropertiesBeforeUpdate(properties,
+ Collections.singletonMap("dfs.nameservices", "ns1")));
+
Assertions.assertTrue(exception.getMessage().contains("dfs.ha.namenodes.ns1"),
exception.getMessage());
+ }
+
+ private static Map<String, String> hiveCatalogProperties() {
+ Map<String, String> properties = new HashMap<>();
+ properties.put("type", "hms");
+ properties.put("hive.metastore.uris", "thrift://localhost:9083");
+ return properties;
+ }
+
@Test
public void testPropertyUpdateInvalidatesCatalogCaches() throws Exception {
TestablePluginCatalog catalog = new TestablePluginCatalog(
diff --git
a/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsConfigFileLoader.java
b/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsConfigFileLoader.java
index 49dedf4173f..d45fd8365d6 100644
---
a/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsConfigFileLoader.java
+++
b/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsConfigFileLoader.java
@@ -46,7 +46,8 @@ public final class HdfsConfigFileLoader {
String dir = configDir == null ? "" : configDir;
Configuration conf = new Configuration();
for (String resource : resourcesPath.split(",")) {
- String path = dir + resource.trim();
+ String resourceName = resource.trim();
+ String path = new File(resourceName).isAbsolute() ? resourceName :
dir + resourceName;
File file = new File(path);
if (file.exists() && file.isFile()) {
conf.addResource(new Path(file.toURI()));
diff --git
a/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesUtils.java
b/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesUtils.java
index 18972d59eb2..ffea39df0ab 100644
---
a/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesUtils.java
+++
b/fe/fe-filesystem/fe-filesystem-hdfs-base/src/main/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesUtils.java
@@ -218,10 +218,14 @@ public class HdfsPropertiesUtils {
// No nameservice configured => HA is not enabled, nothing to
validate
return;
}
- for (String dfsservice : splitAndTrim(dfsNameservices)) {
- if (dfsservice.isEmpty()) {
- continue;
- }
+ // Keep runtime binding compatible with catalogs written by older
versions. Hadoop also
+ // ignores empty tokens produced by a trailing comma in
dfs.nameservices.
+ List<String> services = splitAndTrim(dfsNameservices);
+ if (services.isEmpty()) {
+ // Keep runtime binding compatible with catalogs persisted by
older versions.
+ return;
+ }
+ for (String dfsservice : services) {
// 2. Check dfs.ha.namenodes.<nameservice>
String haNnKey = HdfsClientConfigKeys.DFS_HA_NAMENODES_KEY_PREFIX
+ "." + dfsservice;
String namenodes = hdfsProperties.getOrDefault(haNnKey, "");
diff --git
a/fe/fe-filesystem/fe-filesystem-hdfs/src/test/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesTest.java
b/fe/fe-filesystem/fe-filesystem-hdfs/src/test/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesTest.java
index 5785ff84e99..e224054c642 100644
---
a/fe/fe-filesystem/fe-filesystem-hdfs/src/test/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesTest.java
+++
b/fe/fe-filesystem/fe-filesystem-hdfs/src/test/java/org/apache/doris/filesystem/hdfs/properties/HdfsPropertiesTest.java
@@ -63,6 +63,27 @@ class HdfsPropertiesTest {
Assertions.assertFalse(HdfsConfigBuilder.isKerberosEnabled(resolved));
}
+ @Test
+ void emptyNameserviceListRemainsCompatibleAtRuntime() {
+ Map<String, String> raw = new HashMap<>();
+ raw.put("dfs.nameservices", ",");
+
+ Assertions.assertDoesNotThrow(() -> resolve(raw));
+ }
+
+ @Test
+ void nameserviceListWithTrailingEmptyEntryRemainsCompatible() {
+ Map<String, String> raw = new HashMap<>();
+ raw.put("dfs.nameservices", "ns1,");
+ raw.put("dfs.ha.namenodes.ns1", "nn1,nn2");
+ raw.put("dfs.namenode.rpc-address.ns1.nn1", "host1:8020");
+ raw.put("dfs.namenode.rpc-address.ns1.nn2", "host2:8020");
+ raw.put("dfs.client.failover.proxy.provider.ns1",
+
"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
+
+ Assertions.assertDoesNotThrow(() -> resolve(raw));
+ }
+
@Test
void userOverriddenHadoopKeysArePreserved() {
Map<String, String> raw = new HashMap<>();
@@ -102,8 +123,8 @@ class HdfsPropertiesTest {
Map<String, String> raw = new HashMap<>();
raw.put("fs.defaultFS", "hdfs://ns");
- // No _HADOOP_CONFIG_DIR_ injected: the resource is given as a full
absolute path
- // and must load as-is (configDir falls back to "").
+ // An absolute resource must remain absolute even when the configured
Hadoop directory is set.
+ raw.put("_HADOOP_CONFIG_DIR_", tmp.resolve("configured").toString() +
"/");
raw.put("hadoop.config.resources", site.toString());
Map<String, String> resolved = resolve(raw);
diff --git
a/regression-test/suites/external_table_p0/hive/test_hive_ha_catalog_validation.groovy
b/regression-test/suites/external_table_p0/hive/test_hive_ha_catalog_validation.groovy
new file mode 100644
index 00000000000..2ee9ada8005
--- /dev/null
+++
b/regression-test/suites/external_table_p0/hive/test_hive_ha_catalog_validation.groovy
@@ -0,0 +1,91 @@
+// 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.
+
+suite("test_hive_ha_catalog_validation", "p0,external") {
+ sql "drop catalog if exists test_hive_ha_catalog_validation"
+
+ test {
+ sql """create catalog test_hive_ha_catalog_validation properties (
+ 'type' = 'hms',
+ 'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
+ 'test_connection' = 'false',
+ 'dfs.nameservices' = 'ns1'
+ )"""
+ exception "Missing property: dfs.ha.namenodes.ns1"
+ }
+
+ test {
+ sql """create catalog test_hive_ha_catalog_validation properties (
+ 'type' = 'hms',
+ 'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
+ 'test_connection' = 'false',
+ 'dfs.nameservices' = ','
+ )"""
+ exception "dfs.nameservices must contain a nameservice"
+ }
+
+ test {
+ sql """create catalog test_hive_ha_catalog_validation properties (
+ 'type' = 'hms',
+ 'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
+ 'test_connection' = 'false',
+ 'dfs.nameservices' = 'ns1,'
+ )"""
+ exception "Missing property: dfs.ha.namenodes.ns1"
+ }
+
+ test {
+ sql """create catalog test_hive_ha_catalog_validation properties (
+ 'type' = 'hms',
+ 'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
+ 'test_connection' = 'false',
+ 'dfs.nameservices' = 'ns1',
+ 'dfs.ha.namenodes.ns1' = 'nn1,nn2'
+ )"""
+ exception "Missing property: dfs.namenode.rpc-address.ns1.nn1"
+ }
+
+ test {
+ sql """create catalog test_hive_ha_catalog_validation properties (
+ 'type' = 'hms',
+ 'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
+ 'test_connection' = 'false',
+ 'dfs.nameservices' = 'ns1',
+ 'dfs.ha.namenodes.ns1' = 'nn1,nn2',
+ 'dfs.namenode.rpc-address.ns1.nn1' = '127.0.0.1:8020',
+ 'dfs.namenode.rpc-address.ns1.nn2' = '127.0.0.1:8021'
+ )"""
+ exception "Missing property: dfs.client.failover.proxy.provider.ns1"
+ }
+
+ sql """create catalog test_hive_ha_catalog_validation properties (
+ 'type' = 'hms',
+ 'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
+ 'test_connection' = 'false',
+ 'dfs.nameservices' = 'ns1',
+ 'dfs.ha.namenodes.ns1' = 'nn1,nn2',
+ 'dfs.namenode.rpc-address.ns1.nn1' = '127.0.0.1:8020',
+ 'dfs.namenode.rpc-address.ns1.nn2' = '127.0.0.1:8021',
+ 'dfs.client.failover.proxy.provider.ns1' =
'org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider'
+ )"""
+
+ test {
+ sql """alter catalog test_hive_ha_catalog_validation set properties (
+ 'dfs.nameservices' = 'ns2'
+ )"""
+ exception "Missing property: dfs.ha.namenodes.ns2"
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]