This is an automated email from the ASF dual-hosted git repository.

github-actions[bot] pushed a commit to branch cherry-pick-30687f68-to-branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git

commit 4dc358c4d9fdb3e66e3885adb1089e765eb0d37b
Author: roryqi <[email protected]>
AuthorDate: Fri Sep 4 16:33:58 2026 +0800

    [#12851] fix(iceberg-rest): Share the managed memory catalog in auxiliary 
mode (#12852)
    
    ### What changes were proposed in this pull request?
    
    - Expose the Iceberg backend owned by `IcebergCatalogOperations`.
    - Reuse that backend when the auxiliary Iceberg REST service serves a
    memory catalog.
    - Resolve the REST `default_catalog` alias to the configured Gravitino
    catalog.
    - Prevent the REST wrapper from closing the borrowed catalog.
    - Add regression tests covering namespace, table, and view creation for
    both explicit catalog names
      and the default catalog alias.
    
    ### Why are the changes needed?
    
    The auxiliary Iceberg REST service currently creates a second
    InMemoryCatalog. REST creates are
    written to that instance, while metadata import uses the instance owned
    by Gravitino CatalogManager.
    Because in-memory state is local to each instance, the import cannot
    find the newly created object
    and leaves Iceberg and Gravitino metadata inconsistent.
    
    Fix: #12851
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. Namespace, table, and view creation through the Iceberg REST API
    now succeeds with a memory
    backend, and the created objects are visible through the Gravitino
    metadata API.
    
    No public API or configuration property is added or removed.
    
    ### How was this patch tested?
    
    - `./gradlew spotlessApply`
    - `./gradlew :iceberg:iceberg-common:test --tests
    org.apache.gravitino.iceberg.common.ops.TestIcebergCatalogWrapper`
    - `./gradlew :catalogs:catalog-lakehouse-iceberg:compileJava`
    - `./gradlew :iceberg:iceberg-rest-server:test --tests
    
org.apache.gravitino.iceberg.service.TestIcebergCatalogWrapperManagerForREST`
    - `./gradlew :iceberg:iceberg-rest-server:test --tests
    org.apache.gravitino.iceberg.service.TestIcebergCatalogWrapperManagerForREST
    --tests
    
org.apache.gravitino.iceberg.service.dispatcher.TestIcebergNamespaceHookDispatcher
    --tests
    
org.apache.gravitino.iceberg.service.dispatcher.TestIcebergTableHookDispatcher
    --tests
    
org.apache.gravitino.iceberg.service.dispatcher.TestIcebergViewHookDispatcher`
    - `./gradlew :catalogs:catalog-lakehouse-iceberg:test --tests
    
org.apache.gravitino.catalog.lakehouse.iceberg.integration.test.CatalogIcebergRestIT
    -PskipTests -PtestMode=embedded -PjdbcBackend=h2 -PskipDockerTests=false
    -PskipWeb=true`
    # Conflicts:
    #       
catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogOperations.java
    #       
catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalogOperations.java
    #       core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java
    #       
iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
    #       
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
    #       
iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
---
 .../lakehouse/iceberg/IcebergConstants.java        |   3 +
 .../iceberg/IcebergCatalogOperations.java          |  55 +++++-
 .../iceberg/TestIcebergCatalogOperations.java      |  29 +++
 .../lakehouse/iceberg/TestIcebergSchema.java       |   3 +-
 .../apache/gravitino/catalog/CatalogManager.java   |  22 +++
 .../gravitino/connector/CatalogDropAware.java      |  29 +++
 .../gravitino/catalog/TestCatalogManager.java      |  13 ++
 .../iceberg/common/ops/IcebergCatalogWrapper.java  |   6 +-
 .../iceberg/common/utils/IcebergCatalogUtil.java   |  44 +++++
 .../common/ops/TestIcebergCatalogWrapper.java      |  27 +++
 .../common/utils/TestIcebergCatalogUtil.java       |  86 +++++++++
 .../service/IcebergCatalogWrapperManager.java      |   4 +
 .../provider/DynamicIcebergConfigProvider.java     |  21 ++
 .../TestIcebergCatalogWrapperManagerForREST.java   |  46 ++++-
 .../provider/TestDynamicIcebergConfigProvider.java | 214 +++++++++++++++++++++
 15 files changed, 597 insertions(+), 5 deletions(-)

diff --git 
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
 
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
index 354153b303..2d29e9e754 100644
--- 
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
+++ 
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
@@ -24,6 +24,9 @@ public class IcebergConstants {
   public static final String CATALOG_BACKEND = "catalog-backend";
   public static final String CATALOG_BACKEND_IMPL = "catalog-backend-impl";
 
+  /** Internal property containing the unique identifier of a Gravitino 
catalog. */
+  public static final String CATALOG_UUID = "catalog_uuid";
+
   public static final String GRAVITINO_JDBC_USER = "jdbc-user";
   public static final String ICEBERG_JDBC_USER = "jdbc.user";
 
diff --git 
a/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogOperations.java
 
b/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogOperations.java
index 457e5cbd55..311ccda7af 100644
--- 
a/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogOperations.java
+++ 
b/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogOperations.java
@@ -31,12 +31,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
+import javax.annotation.Nullable;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.SchemaChange;
 import 
org.apache.gravitino.catalog.lakehouse.iceberg.ops.IcebergCatalogWrapperHelper;
+import org.apache.gravitino.connector.CatalogDropAware;
 import org.apache.gravitino.connector.CatalogInfo;
 import org.apache.gravitino.connector.CatalogOperations;
 import org.apache.gravitino.connector.HasPropertyMetadata;
@@ -56,6 +58,7 @@ import 
org.apache.gravitino.iceberg.common.authentication.SupportsKerberos;
 import org.apache.gravitino.iceberg.common.ops.IcebergCatalogWrapper;
 import 
org.apache.gravitino.iceberg.common.ops.IcebergCatalogWrapper.IcebergTableChange;
 import 
org.apache.gravitino.iceberg.common.ops.KerberosAwareIcebergCatalogProxy;
+import org.apache.gravitino.iceberg.common.utils.IcebergCatalogUtil;
 import org.apache.gravitino.iceberg.common.utils.IcebergIdentifierUtils;
 import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.rel.Column;
@@ -90,7 +93,7 @@ import org.slf4j.LoggerFactory;
 
 /** Operations for interacting with an Apache Iceberg catalog in Apache 
Gravitino. */
 public class IcebergCatalogOperations
-    implements CatalogOperations, SupportsSchemas, TableCatalog, ViewCatalog {
+    implements CatalogOperations, SupportsSchemas, TableCatalog, ViewCatalog, 
CatalogDropAware {
 
   private static final String ICEBERG_TABLE_DOES_NOT_EXIST_MSG = "Iceberg 
table does not exist: %s";
 
@@ -98,6 +101,7 @@ public class IcebergCatalogOperations
 
   @VisibleForTesting IcebergCatalogWrapper icebergCatalogWrapper;
 
+  @VisibleForTesting @Nullable String catalogUuid;
   private IcebergCatalogWrapperHelper icebergCatalogWrapperHelper;
   private IcebergViewCatalogOperations icebergViewCatalogOperations;
 
@@ -122,11 +126,13 @@ public class IcebergCatalogOperations
 
     Map<String, String> resultConf = Maps.newHashMap(prefixMap);
     resultConf.putAll(gravitinoConfig);
-    resultConf.put("catalog_uuid", info.id().toString());
+    this.catalogUuid = info.id().toString();
+    resultConf.put(IcebergConstants.CATALOG_UUID, catalogUuid);
     IcebergConfig icebergConfig = new IcebergConfig(resultConf);
 
     IcebergCatalogWrapper rawWrapper = new 
IcebergCatalogWrapper(icebergConfig);
 
+<<<<<<< HEAD
     AuthenticationConfig authenticationConfig = new 
AuthenticationConfig(resultConf);
     this.icebergCatalogWrapper =
         authenticationConfig.isKerberosAuth() && rawWrapper.getCatalog() 
instanceof SupportsKerberos
@@ -135,6 +141,51 @@ public class IcebergCatalogOperations
     this.icebergCatalogWrapperHelper =
         new IcebergCatalogWrapperHelper(icebergCatalogWrapper.getCatalog());
     this.icebergViewCatalogOperations = new 
IcebergViewCatalogOperations(icebergCatalogWrapper);
+=======
+    try {
+      AuthenticationConfig authenticationConfig = new 
AuthenticationConfig(resultConf);
+      this.icebergCatalogWrapper =
+          authenticationConfig.isKerberosAuth()
+                  && rawWrapper.getCatalog() instanceof SupportsKerberos
+              ? new 
KerberosAwareIcebergCatalogProxy(rawWrapper).getProxy(icebergConfig)
+              : rawWrapper;
+      this.icebergCatalogWrapperHelper =
+          new IcebergCatalogWrapperHelper(icebergCatalogWrapper.getCatalog());
+      this.icebergViewCatalogOperations = new 
IcebergViewCatalogOperations(icebergCatalogWrapper);
+    } catch (NoSuchWarehouseException e) {
+      // A reachable server rejecting the `warehouse` selector is a user 
error. See issue #11943.
+      throw new IllegalArgumentException(
+          String.format(
+              "The 'warehouse' value '%s' could not be resolved by the Iceberg 
REST server. On "
+                  + "the REST backend 'warehouse' selects a catalog by name on 
the remote server "
+                  + "and is not a storage location; remove 'warehouse' to use 
the server's default "
+                  + "catalog, or set it to a catalog name/identifier that the 
server recognizes.",
+              icebergConfig.get(IcebergConfig.CATALOG_WAREHOUSE)),
+          e);
+    } catch (RESTException e) {
+      throw handleRestException(e);
+    }
+  }
+
+  @Override
+  public void onCatalogDropped() {
+    if (catalogUuid != null) {
+      IcebergCatalogUtil.removeMemoryCatalog(catalogUuid);
+    }
+  }
+
+  // Maps an Iceberg REST-client exception into Gravitino's taxonomy
+  @VisibleForTesting
+  static RuntimeException handleRestException(RESTException e) {
+    // Base RESTException (server unreachable) or ServiceUnavailableException 
(503): the downstream
+    // dependency is not available. getClass() matches the base type only, so 
the 4xx/5xx subtypes
+    // are excluded and pass through unchanged.
+    if (e.getClass() == RESTException.class || e instanceof 
ServiceUnavailableException) {
+      return new ConnectionFailedException(
+          e, "The Iceberg REST backend is unavailable: %s", e.getMessage());
+    }
+    return e;
+>>>>>>> 30687f68f ([#12851] fix(iceberg-rest): Share the managed memory 
catalog in auxiliary mode (#12852))
   }
 
   /** Closes the Iceberg catalog and releases the associated client pool. */
diff --git 
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalogOperations.java
 
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalogOperations.java
index dfbd129a23..e91b3eba65 100644
--- 
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalogOperations.java
+++ 
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalogOperations.java
@@ -29,6 +29,13 @@ import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.exceptions.GravitinoRuntimeException;
 import org.apache.gravitino.iceberg.common.ops.IcebergCatalogWrapper;
+<<<<<<< HEAD
+=======
+import org.apache.gravitino.iceberg.common.utils.IcebergCatalogUtil;
+import org.apache.iceberg.exceptions.BadRequestException;
+import org.apache.iceberg.exceptions.RESTException;
+import org.apache.iceberg.exceptions.ServiceUnavailableException;
+>>>>>>> 30687f68f ([#12851] fix(iceberg-rest): Share the managed memory 
catalog in auxiliary mode (#12852))
 import org.apache.iceberg.rest.responses.ListNamespacesResponse;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -95,4 +102,26 @@ public class TestIcebergCatalogOperations {
     Assertions.assertTrue(Arrays.stream(result).anyMatch(id -> 
"db1".equals(id.name())));
     Assertions.assertTrue(Arrays.stream(result).anyMatch(id -> 
"db2".equals(id.name())));
   }
+
+  @Test
+  public void testCatalogDropRemovesInternedMemoryCatalog() {
+    String catalogUuid = "catalog-uuid";
+    IcebergConfig config =
+        new IcebergConfig(
+            ImmutableMap.of(
+                IcebergConstants.CATALOG_BACKEND,
+                "memory",
+                IcebergConstants.CATALOG_UUID,
+                catalogUuid));
+    Object original = 
IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, config);
+
+    IcebergCatalogOperations catalogOperations = new 
IcebergCatalogOperations();
+    catalogOperations.catalogUuid = catalogUuid;
+    catalogOperations.onCatalogDropped();
+
+    Object replacement =
+        IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, 
config);
+    Assertions.assertNotSame(original, replacement);
+    IcebergCatalogUtil.removeMemoryCatalog(catalogUuid);
+  }
 }
diff --git 
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergSchema.java
 
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergSchema.java
index 9c9f6f5de5..c028c24b2e 100644
--- 
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergSchema.java
+++ 
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergSchema.java
@@ -187,7 +187,8 @@ public class TestIcebergSchema {
   private IcebergCatalog initIcebergCatalog(String name) {
     CatalogEntity entity =
         CatalogEntity.builder()
-            .withId(1L)
+            // Each test creates a different catalog, so it must also use a 
distinct catalog ID.
+            .withId(Integer.toUnsignedLong(name.hashCode()))
             .withName(name)
             .withNamespace(Namespace.of(META_LAKE_NAME))
             .withType(IcebergCatalog.Type.RELATIONAL)
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java 
b/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java
index d7e2739f07..e58fea74f0 100644
--- a/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java
+++ b/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java
@@ -79,6 +79,7 @@ import org.apache.gravitino.Namespace;
 import org.apache.gravitino.Schema;
 import org.apache.gravitino.StringIdentifier;
 import org.apache.gravitino.connector.BaseCatalog;
+import org.apache.gravitino.connector.CatalogDropAware;
 import org.apache.gravitino.connector.CatalogOperations;
 import org.apache.gravitino.connector.HasPropertyMetadata;
 import org.apache.gravitino.connector.SupportsSchemas;
@@ -1011,6 +1012,27 @@ public class CatalogManager implements 
CatalogDispatcher, Closeable {
             boolean deleted = store.delete(ident, EntityType.CATALOG, true);
             if (deleted) {
               markLocalMutation(ident);
+<<<<<<< HEAD
+=======
+              try {
+                catalogWrapper.doWithCatalogOps(
+                    operations -> {
+                      if (operations instanceof CatalogDropAware) {
+                        ((CatalogDropAware) operations).onCatalogDropped();
+                      }
+                      return null;
+                    });
+              } catch (Exception e) {
+                LOG.warn("Failed to clean up resources for dropped catalog 
{}", ident, e);
+              }
+              // Unmanaged: schemas removed only via store cascade — clean 
secrets captured above.
+              if (!managedStorage) {
+                for (Map<String, String> schemaProperties : 
unmanagedSchemaSecrets) {
+                  secretManager.deleteSecretsFromProperties(schemaProperties);
+                }
+              }
+              secretManager.deleteSecretsFromProperties(catalogProperties);
+>>>>>>> 30687f68f ([#12851] fix(iceberg-rest): Share the managed memory 
catalog in auxiliary mode (#12852))
             }
             catalogCache.invalidate(ident);
             return deleted;
diff --git 
a/core/src/main/java/org/apache/gravitino/connector/CatalogDropAware.java 
b/core/src/main/java/org/apache/gravitino/connector/CatalogDropAware.java
new file mode 100644
index 0000000000..2972808c1c
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/connector/CatalogDropAware.java
@@ -0,0 +1,29 @@
+/*
+ * 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.gravitino.connector;
+
+import org.apache.gravitino.annotation.Evolving;
+
+/** Supports cleanup that must run only when a catalog is permanently dropped. 
*/
+@Evolving
+public interface CatalogDropAware {
+
+  /** Performs cleanup after the catalog metadata has been permanently 
dropped. */
+  void onCatalogDropped();
+}
diff --git 
a/core/src/test/java/org/apache/gravitino/catalog/TestCatalogManager.java 
b/core/src/test/java/org/apache/gravitino/catalog/TestCatalogManager.java
index 4424dc848f..1be48b0d3a 100644
--- a/core/src/test/java/org/apache/gravitino/catalog/TestCatalogManager.java
+++ b/core/src/test/java/org/apache/gravitino/catalog/TestCatalogManager.java
@@ -57,6 +57,7 @@ import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.Schema;
 import org.apache.gravitino.connector.BaseCatalog;
+import org.apache.gravitino.connector.CatalogDropAware;
 import org.apache.gravitino.connector.CatalogOperations;
 import org.apache.gravitino.connector.capability.Capability;
 import org.apache.gravitino.connector.capability.CapabilityResult;
@@ -1108,10 +1109,21 @@ public class TestCatalogManager {
         Mockito.mock(CatalogManager.CatalogWrapper.class, 
Mockito.RETURNS_DEEP_STUBS);
     Capability capability = Mockito.mock(Capability.class);
     CapabilityResult unsupportedResult = CapabilityResult.unsupported("Not 
managed");
+    CatalogOperations operations =
+        Mockito.mock(
+            CatalogOperations.class,
+            Mockito.withSettings().extraInterfaces(CatalogDropAware.class));
     
Mockito.doReturn(catalogWrapper).when(catalogManager).loadCatalogAndWrap(ident);
     Mockito.doReturn(catalog).when(catalogWrapper).catalog();
     Mockito.doReturn(capability).when(catalogWrapper).capabilities();
     Mockito.doReturn(unsupportedResult).when(capability).managedStorage(any());
+    Mockito.doAnswer(
+            invocation -> {
+              ThrowableFunction<CatalogOperations, ?> function = 
invocation.getArgument(0);
+              return function.apply(operations);
+            })
+        .when(catalogWrapper)
+        .doWithCatalogOps(any());
 
     catalogManager.getCatalogCache().put(ident, catalogWrapper);
     boolean dropped = catalogManager.dropCatalog(ident);
@@ -1119,6 +1131,7 @@ public class TestCatalogManager {
     Assertions.assertTrue(dropped);
     Assertions.assertFalse(entityStore.exists(ident, EntityType.CATALOG));
     
Assertions.assertNull(catalogManager.getCatalogCache().getIfPresent(ident));
+    Mockito.verify((CatalogDropAware) operations).onCatalogDropped();
   }
 
   @Test
diff --git 
a/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/ops/IcebergCatalogWrapper.java
 
b/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/ops/IcebergCatalogWrapper.java
index 529c352cae..566c5289d0 100644
--- 
a/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/ops/IcebergCatalogWrapper.java
+++ 
b/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/ops/IcebergCatalogWrapper.java
@@ -29,6 +29,7 @@ import lombok.Setter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.gravitino.catalog.hadoop.fs.FileSystemUtils;
 import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergCatalogBackend;
+import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
 import org.apache.gravitino.iceberg.common.IcebergConfig;
 import org.apache.gravitino.iceberg.common.cache.SupportsMetadataLocation;
 import org.apache.gravitino.iceberg.common.cache.TableMetadataCache;
@@ -390,7 +391,10 @@ public class IcebergCatalogWrapper implements 
AutoCloseable {
     } else {
       LOG.info("Closing IcebergCatalogWrapper before catalog is initialized");
     }
-    if (loadedCatalog instanceof AutoCloseable) {
+    boolean internedMemoryCatalog =
+        catalogBackend == IcebergCatalogBackend.MEMORY
+            && 
icebergConfig.getAllConfig().containsKey(IcebergConstants.CATALOG_UUID);
+    if (!internedMemoryCatalog && loadedCatalog instanceof AutoCloseable) {
       // JdbcCatalog and ClosableHiveCatalog implement AutoCloseable and will 
handle their own
       // cleanup
       ((AutoCloseable) loadedCatalog).close();
diff --git 
a/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
 
b/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
index 6c12e60455..9ae4afe292 100644
--- 
a/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
+++ 
b/iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java
@@ -23,11 +23,13 @@ import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Maps;
+import java.io.IOException;
 import java.sql.SQLException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergCatalogBackend;
 import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
 import org.apache.gravitino.exceptions.ConnectionFailedException;
@@ -56,7 +58,28 @@ public class IcebergCatalogUtil {
 
   private static final Logger LOG = 
LoggerFactory.getLogger(IcebergCatalogUtil.class);
 
+<<<<<<< HEAD
+=======
+  /**
+   * Column that Iceberg adds to the {@code iceberg_tables} control table in 
its V1 view-support
+   * migration (see {@code JdbcUtil} in iceberg-core).
+   */
+  private static final String ICEBERG_TYPE_COLUMN = "iceberg_type";
+
+  private static final ConcurrentHashMap<String, InMemoryCatalog> 
MEMORY_CATALOGS =
+      new ConcurrentHashMap<>();
+
+>>>>>>> 30687f68f ([#12851] fix(iceberg-rest): Share the managed memory 
catalog in auxiliary mode (#12852))
   private static InMemoryCatalog loadMemoryCatalog(IcebergConfig 
icebergConfig) {
+    String catalogUuid = 
icebergConfig.getAllConfig().get(IcebergConstants.CATALOG_UUID);
+    if (catalogUuid == null) {
+      return createMemoryCatalog(icebergConfig);
+    }
+    return MEMORY_CATALOGS.computeIfAbsent(
+        catalogUuid, ignored -> createMemoryCatalog(icebergConfig));
+  }
+
+  private static InMemoryCatalog createMemoryCatalog(IcebergConfig 
icebergConfig) {
     String icebergCatalogName = icebergConfig.getCatalogBackendName();
     InMemoryCatalog memoryCatalog = new 
MemoryCatalogWithMetadataLocationSupport();
     Map<String, String> resultProperties = 
icebergConfig.getIcebergCatalogProperties();
@@ -68,6 +91,27 @@ public class IcebergCatalogUtil {
     return memoryCatalog;
   }
 
+  /**
+   * Removes the in-memory Iceberg catalog associated with a permanently 
dropped Gravitino catalog.
+   *
+   * @param catalogUuid the unique Gravitino catalog identifier
+   */
+  public static void removeMemoryCatalog(String catalogUuid) {
+    InMemoryCatalog memoryCatalog = MEMORY_CATALOGS.remove(catalogUuid);
+    if (memoryCatalog != null) {
+      try {
+        memoryCatalog.close();
+      } catch (IOException e) {
+        LOG.warn("Failed to close dropped in-memory Iceberg catalog {}", 
catalogUuid, e);
+      }
+    }
+  }
+
+  @VisibleForTesting
+  static void clearMemoryCatalogs() {
+    MEMORY_CATALOGS.clear();
+  }
+
   private static HiveCatalog loadHiveCatalog(IcebergConfig icebergConfig) {
     ClosableHiveCatalog hiveCatalog = new 
HiveCatalogWithMetadataLocationSupport();
     HdfsConfiguration hdfsConfiguration = new HdfsConfiguration();
diff --git 
a/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/ops/TestIcebergCatalogWrapper.java
 
b/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/ops/TestIcebergCatalogWrapper.java
index e34f1becb3..e6928e56a8 100644
--- 
a/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/ops/TestIcebergCatalogWrapper.java
+++ 
b/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/ops/TestIcebergCatalogWrapper.java
@@ -30,8 +30,12 @@ import 
org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
 import org.apache.gravitino.iceberg.common.IcebergConfig;
 import org.apache.gravitino.iceberg.common.cache.SupportsMetadataLocation;
 import org.apache.gravitino.iceberg.common.cache.TableMetadataCache;
+import org.apache.gravitino.iceberg.common.utils.IcebergCatalogUtil;
 import org.apache.iceberg.TableMetadata;
+import org.apache.iceberg.catalog.Catalog;
+import org.apache.iceberg.catalog.Namespace;
 import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.iceberg.rest.requests.CreateNamespaceRequest;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
@@ -57,6 +61,29 @@ public class TestIcebergCatalogWrapper {
         });
   }
 
+  @Test
+  public void testMemoryCatalogSurvivesWrapperClose() throws Exception {
+    String catalogUuid = "catalog-1";
+    IcebergConfig config =
+        new IcebergConfig(
+            Map.of(
+                IcebergConstants.CATALOG_BACKEND,
+                "memory",
+                IcebergConstants.CATALOG_UUID,
+                catalogUuid));
+    IcebergCatalogWrapper firstWrapper = new IcebergCatalogWrapper(config);
+    Catalog firstCatalog = firstWrapper.getCatalog();
+    Namespace namespace = Namespace.of("preserved");
+    
firstWrapper.createNamespace(CreateNamespaceRequest.builder().withNamespace(namespace).build());
+
+    firstWrapper.close();
+    IcebergCatalogWrapper secondWrapper = new IcebergCatalogWrapper(config);
+
+    Assertions.assertSame(firstCatalog, secondWrapper.getCatalog());
+    Assertions.assertTrue(secondWrapper.namespaceExists(namespace));
+    IcebergCatalogUtil.removeMemoryCatalog(catalogUuid);
+  }
+
   @Test
   public void testMetadataCacheShouldInitializeOnFirstAccessAndClose(@TempDir 
Path warehouseDir)
       throws Exception {
diff --git 
a/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/utils/TestIcebergCatalogUtil.java
 
b/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/utils/TestIcebergCatalogUtil.java
index ade4237456..89cf6f7897 100644
--- 
a/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/utils/TestIcebergCatalogUtil.java
+++ 
b/iceberg/iceberg-common/src/test/java/org/apache/gravitino/iceberg/common/utils/TestIcebergCatalogUtil.java
@@ -36,6 +36,7 @@ import org.apache.iceberg.inmemory.InMemoryCatalog;
 import org.apache.iceberg.jdbc.JdbcCatalog;
 import org.apache.iceberg.jdbc.JdbcCatalogWithMetadataLocationSupport;
 import org.apache.iceberg.types.Types;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
@@ -44,6 +45,91 @@ public class TestIcebergCatalogUtil {
 
   @TempDir private Path warehouse;
 
+  @AfterEach
+  void tearDown() {
+    IcebergCatalogUtil.clearMemoryCatalogs();
+  }
+
+  @Test
+  void testMemoryCatalogIsInternedByCatalogUuid() {
+    Map<String, String> properties =
+        Map.of(
+            IcebergConstants.CATALOG_BACKEND, "memory", 
IcebergConstants.CATALOG_UUID, "catalog-1");
+    IcebergConfig config = new IcebergConfig(properties);
+
+    InMemoryCatalog first =
+        (InMemoryCatalog)
+            
IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, config);
+    Namespace namespace = Namespace.of("shared");
+    first.createNamespace(namespace);
+    InMemoryCatalog second =
+        (InMemoryCatalog)
+            
IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, config);
+
+    Assertions.assertSame(first, second);
+    Assertions.assertTrue(second.namespaceExists(namespace));
+  }
+
+  @Test
+  void testMemoryCatalogsWithDifferentUuidsAreIsolated() {
+    IcebergConfig firstConfig =
+        new IcebergConfig(
+            Map.of(
+                IcebergConstants.CATALOG_BACKEND,
+                "memory",
+                IcebergConstants.CATALOG_UUID,
+                "catalog-1"));
+    IcebergConfig secondConfig =
+        new IcebergConfig(
+            Map.of(
+                IcebergConstants.CATALOG_BACKEND,
+                "memory",
+                IcebergConstants.CATALOG_UUID,
+                "catalog-2"));
+
+    Catalog first =
+        IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, 
firstConfig);
+    Catalog second =
+        IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, 
secondConfig);
+
+    Assertions.assertNotSame(first, second);
+  }
+
+  @Test
+  void testMemoryCatalogWithoutUuidIsNotInterned() {
+    IcebergConfig config = new 
IcebergConfig(Map.of(IcebergConstants.CATALOG_BACKEND, "memory"));
+
+    Catalog first = 
IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, config);
+    Catalog second = 
IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, config);
+
+    Assertions.assertNotSame(first, second);
+  }
+
+  @Test
+  void testDroppedMemoryCatalogIsRemoved() {
+    String catalogUuid = "catalog-1";
+    IcebergConfig config =
+        new IcebergConfig(
+            Map.of(
+                IcebergConstants.CATALOG_BACKEND,
+                "memory",
+                IcebergConstants.CATALOG_UUID,
+                catalogUuid));
+    InMemoryCatalog original =
+        (InMemoryCatalog)
+            
IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, config);
+    Namespace namespace = Namespace.of("removed");
+    original.createNamespace(namespace);
+
+    IcebergCatalogUtil.removeMemoryCatalog(catalogUuid);
+    InMemoryCatalog replacement =
+        (InMemoryCatalog)
+            
IcebergCatalogUtil.loadCatalogBackend(IcebergCatalogBackend.MEMORY, config);
+
+    Assertions.assertNotSame(original, replacement);
+    Assertions.assertFalse(replacement.namespaceExists(namespace));
+  }
+
   @Test
   void testLoadCatalog() {
     Catalog catalog;
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergCatalogWrapperManager.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergCatalogWrapperManager.java
index ce2df6910a..3a3c518f30 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergCatalogWrapperManager.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergCatalogWrapperManager.java
@@ -30,6 +30,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import org.apache.gravitino.GravitinoEnv;
 import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergCatalogBackend;
+import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
 import org.apache.gravitino.iceberg.common.IcebergConfig;
 import org.apache.gravitino.iceberg.common.authentication.AuthenticationConfig;
@@ -84,6 +85,9 @@ public class IcebergCatalogWrapperManager implements 
AutoCloseable {
               ident -> {
                 if (ident.namespace().level(0).equals(metalakeName)) {
                   catalogWrapperCache.invalidate(ident.name());
+                  if 
(ident.name().equals(configProvider.getDefaultCatalogName())) {
+                    
catalogWrapperCache.invalidate(IcebergConstants.ICEBERG_REST_DEFAULT_CATALOG);
+                  }
                 }
               });
     }
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
index 43ec66812e..feb37ba4ca 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
@@ -116,6 +116,7 @@ public class DynamicIcebergConfigProvider implements 
IcebergConfigProvider {
     // fields into the properties map so the JDBC backend can connect.
     Map<String, String> catalogProperties;
     if (catalog instanceof BaseCatalog) {
+<<<<<<< HEAD
       catalogProperties = ((BaseCatalog<?>) 
catalog).propertiesWithCredentialProviders();
     } else {
       catalogProperties = new HashMap<>(catalog.properties());
@@ -131,6 +132,26 @@ public class DynamicIcebergConfigProvider implements 
IcebergConfigProvider {
                   catalogProperties.putIfAbsent(
                       IcebergConstants.GRAVITINO_JDBC_PASSWORD, 
jdbc.jdbcPassword());
                 });
+=======
+      BaseCatalog<?> baseCatalog = (BaseCatalog<?>) catalog;
+      Map<String, String> props =
+          new HashMap<>(
+              GravitinoEnv.getInstance()
+                  .secretManager()
+                  
.toPlaintextProperties(baseCatalog.propertiesWithCredentialProviders()));
+      props.put(IcebergConstants.CATALOG_UUID, 
baseCatalog.entity().id().toString());
+      return props;
+    }
+    Map<String, String> props =
+        new HashMap<>(catalog.properties() == null ? Map.of() : 
catalog.properties());
+    try {
+      SupportsSecrets supportsSecrets = catalog.supportsSecrets();
+      if (supportsSecrets != null) {
+        Map<String, String> secrets = supportsSecrets.getSecrets();
+        if (secrets != null) {
+          props.putAll(secrets);
+        }
+>>>>>>> 30687f68f ([#12851] fix(iceberg-rest): Share the managed memory 
catalog in auxiliary mode (#12852))
       }
     }
     return 
Optional.of(getIcebergConfigFromCatalogProperties(catalogProperties));
diff --git 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergCatalogWrapperManagerForREST.java
 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergCatalogWrapperManagerForREST.java
index 2d4386b730..45eb62f69e 100644
--- 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergCatalogWrapperManagerForREST.java
+++ 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergCatalogWrapperManagerForREST.java
@@ -21,9 +21,13 @@ package org.apache.gravitino.iceberg.service;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.gravitino.GravitinoEnv;
+import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.catalog.CatalogManager;
 import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
 import org.apache.gravitino.iceberg.common.IcebergConfig;
@@ -42,11 +46,12 @@ import org.mockito.Mockito;
 public class TestIcebergCatalogWrapperManagerForREST {
 
   private static final String DEFAULT_CATALOG = "memory";
+  private static CatalogManager mockCatalogManager;
 
   @BeforeAll
   public static void setup() throws IllegalAccessException {
     // Mock CatalogManager for GravitinoEnv to avoid initialization errors
-    CatalogManager mockCatalogManager = Mockito.mock(CatalogManager.class);
+    mockCatalogManager = Mockito.mock(CatalogManager.class);
     FieldUtils.writeField(GravitinoEnv.getInstance(), "catalogManager", 
mockCatalogManager, true);
   }
 
@@ -145,6 +150,45 @@ public class TestIcebergCatalogWrapperManagerForREST {
     Assertions.assertEquals(CatalogWrapperForREST.class, wrapper.getClass());
   }
 
+  @Test
+  public void testDefaultCatalogAliasInvalidatedWhenCatalogRemoved() throws 
Exception {
+    Mockito.clearInvocations(mockCatalogManager);
+    AtomicReference<Consumer<NameIdentifier>> removeListener = new 
AtomicReference<>();
+    Mockito.doAnswer(
+            invocation -> {
+              removeListener.set(invocation.getArgument(0));
+              return null;
+            })
+        .when(mockCatalogManager)
+        .addCatalogCacheRemoveListener(Mockito.any());
+
+    IcebergConfigProvider configProvider = 
Mockito.mock(IcebergConfigProvider.class);
+    Mockito.when(configProvider.getDefaultCatalogName()).thenReturn("test");
+    IcebergConfig icebergConfig =
+        new IcebergConfig(
+            ImmutableMap.of(
+                IcebergConstants.CATALOG_BACKEND,
+                "memory",
+                IcebergConstants.WAREHOUSE,
+                "/tmp/warehouse"));
+    Mockito.when(
+            
configProvider.getIcebergCatalogConfig(IcebergConstants.ICEBERG_REST_DEFAULT_CATALOG))
+        .thenReturn(Optional.of(icebergConfig));
+
+    try (IcebergCatalogWrapperManager manager =
+        new IcebergCatalogWrapperManager(Maps.newHashMap(), configProvider, 
true, "metalake")) {
+      IcebergRESTServerContext.create(configProvider, false, false, true, 
manager);
+      CatalogWrapperForREST original =
+          
manager.getCatalogWrapper(IcebergConstants.ICEBERG_REST_DEFAULT_CATALOG);
+
+      removeListener.get().accept(NameIdentifier.of("metalake", "test"));
+
+      CatalogWrapperForREST replacement =
+          
manager.getCatalogWrapper(IcebergConstants.ICEBERG_REST_DEFAULT_CATALOG);
+      Assertions.assertNotSame(original, replacement);
+    }
+  }
+
   private static IcebergCatalogWrapperManager newManager() {
     Map<String, String> config = Maps.newHashMap();
     IcebergConfigProvider configProvider = 
IcebergConfigProviderFactory.create(config);
diff --git 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
index d5b2024152..39c0464681 100644
--- 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
+++ 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
@@ -39,6 +39,17 @@ import 
org.apache.gravitino.exceptions.NoSuchCatalogException;
 import org.apache.gravitino.iceberg.common.IcebergConfig;
 import org.apache.gravitino.iceberg.common.ops.IcebergCatalogWrapper;
 import 
org.apache.gravitino.iceberg.service.authorization.IcebergRESTServerContext;
+<<<<<<< HEAD
+=======
+import org.apache.gravitino.meta.CatalogEntity;
+import org.apache.gravitino.secret.SecretBinding;
+import org.apache.gravitino.secret.SecretManager;
+import org.apache.gravitino.secret.SecretMaterial;
+import org.apache.gravitino.secret.SecretPropertyUtils;
+import org.apache.gravitino.secret.SecretProviderRegistry;
+import org.apache.gravitino.secret.SupportsSecrets;
+import org.apache.gravitino.secret.memory.InMemorySecretsProvider;
+>>>>>>> 30687f68f ([#12851] fix(iceberg-rest): Share the managed memory 
catalog in auxiliary mode (#12852))
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.apache.iceberg.hive.HiveCatalog;
 import org.apache.iceberg.jdbc.JdbcCatalog;
@@ -584,4 +595,207 @@ public class TestDynamicIcebergConfigProvider {
     executor.shutdown();
     executor.awaitTermination(5, TimeUnit.SECONDS);
   }
+<<<<<<< HEAD
+=======
+
+  @Test
+  public void testMergeSecrets() {
+    String metalakeName = "test_metalake";
+    String catalogName = "jdbc_catalog";
+
+    Catalog mockCatalog = Mockito.mock(Catalog.class);
+    SupportsSecrets supportsSecrets = Mockito.mock(SupportsSecrets.class);
+    Mockito.when(mockCatalog.provider()).thenReturn("lakehouse-iceberg");
+    Mockito.when(mockCatalog.properties())
+        .thenReturn(
+            new HashMap<String, String>() {
+              {
+                put(IcebergConstants.CATALOG_BACKEND, "jdbc");
+                put(IcebergConstants.CATALOG_BACKEND_NAME, catalogName);
+                put(IcebergConstants.WAREHOUSE, "s3://bucket/wh");
+              }
+            });
+    Mockito.when(mockCatalog.supportsSecrets()).thenReturn(supportsSecrets);
+    Mockito.when(supportsSecrets.getSecrets())
+        .thenReturn(Map.of(IcebergConstants.GRAVITINO_JDBC_PASSWORD, 
"secret-pwd"));
+
+    Map<String, String> properties = new HashMap<>();
+    properties.put(IcebergConstants.GRAVITINO_URI, "http://localhost:8090";);
+    properties.put(IcebergConstants.GRAVITINO_METALAKE, metalakeName);
+
+    DynamicIcebergConfigProvider provider = new DynamicIcebergConfigProvider();
+    provider.initialize(properties);
+    setMockCatalogFetcher(provider, Map.of(catalogName, mockCatalog));
+
+    Optional<IcebergConfig> config = 
provider.getIcebergCatalogConfig(catalogName);
+    Assertions.assertTrue(config.isPresent());
+    Assertions.assertEquals(
+        "secret-pwd",
+        
config.get().getIcebergCatalogProperties().get(IcebergConstants.GRAVITINO_JDBC_PASSWORD));
+  }
+
+  @Test
+  public void testCredsOverrideSecrets() {
+    String metalakeName = "test_metalake";
+    String catalogName = "jdbc_catalog";
+
+    Catalog mockCatalog =
+        Mockito.mock(
+            Catalog.class,
+            Mockito.withSettings()
+                .extraInterfaces(SupportsCredentials.class, 
SupportsSecrets.class));
+    SupportsSecrets supportsSecrets = (SupportsSecrets) mockCatalog;
+    SupportsCredentials supportsCredentials = (SupportsCredentials) 
mockCatalog;
+
+    Mockito.when(mockCatalog.provider()).thenReturn("lakehouse-iceberg");
+    Mockito.when(mockCatalog.properties())
+        .thenReturn(
+            new HashMap<String, String>() {
+              {
+                put(IcebergConstants.CATALOG_BACKEND, "jdbc");
+                put(IcebergConstants.CATALOG_BACKEND_NAME, catalogName);
+              }
+            });
+    Mockito.when(mockCatalog.supportsSecrets()).thenReturn(supportsSecrets);
+    Mockito.when(supportsSecrets.getSecrets())
+        .thenReturn(
+            Map.of(
+                IcebergConstants.GRAVITINO_JDBC_USER,
+                "from-secret",
+                IcebergConstants.GRAVITINO_JDBC_PASSWORD,
+                "secret-pwd"));
+    Mockito.when(supportsCredentials.getCredentials())
+        .thenReturn(new Credential[] {new JdbcCredential("cred-user", 
"cred-pwd")});
+
+    Map<String, String> properties = new HashMap<>();
+    properties.put(IcebergConstants.GRAVITINO_URI, "http://localhost:8090";);
+    properties.put(IcebergConstants.GRAVITINO_METALAKE, metalakeName);
+
+    DynamicIcebergConfigProvider provider = new DynamicIcebergConfigProvider();
+    provider.initialize(properties);
+    setMockCatalogFetcher(provider, Map.of(catalogName, mockCatalog));
+
+    Optional<IcebergConfig> config = 
provider.getIcebergCatalogConfig(catalogName);
+    Assertions.assertTrue(config.isPresent());
+    Map<String, String> icebergProps = 
config.get().getIcebergCatalogProperties();
+    Assertions.assertEquals("cred-user", 
icebergProps.get(IcebergConstants.GRAVITINO_JDBC_USER));
+    Assertions.assertEquals("cred-pwd", 
icebergProps.get(IcebergConstants.GRAVITINO_JDBC_PASSWORD));
+  }
+
+  @Test
+  public void testMergeMemorySecrets() {
+    try (SecretManager sm = memorySecretManager()) {
+      Map<String, String> entityProps = new HashMap<>();
+      entityProps.put(IcebergConstants.GRAVITINO_JDBC_USER, "root");
+      List<SecretMaterial> writes =
+          sm.assembleSecretMaterials(
+              Map.of(IcebergConstants.GRAVITINO_JDBC_USER, "root"),
+              entityProps,
+              "catalog",
+              3L,
+              Map.of(
+                  IcebergConstants.GRAVITINO_JDBC_PASSWORD,
+                  new SecretBinding("memory", "mem-jdbc-pwd")),
+              Map.of());
+      sm.writeSecrets(writes);
+      Map<String, String> secrets = SecretPropertyUtils.buildSecrets(sm, 
entityProps);
+
+      String metalakeName = "test_metalake";
+      String catalogName = "jdbc_catalog";
+      Catalog mockCatalog = Mockito.mock(Catalog.class);
+      SupportsSecrets supportsSecrets = Mockito.mock(SupportsSecrets.class);
+      Mockito.when(mockCatalog.provider()).thenReturn("lakehouse-iceberg");
+      Mockito.when(mockCatalog.properties())
+          .thenReturn(
+              new HashMap<String, String>() {
+                {
+                  put(IcebergConstants.CATALOG_BACKEND, "jdbc");
+                  put(IcebergConstants.CATALOG_BACKEND_NAME, catalogName);
+                }
+              });
+      Mockito.when(mockCatalog.supportsSecrets()).thenReturn(supportsSecrets);
+      Mockito.when(supportsSecrets.getSecrets()).thenReturn(secrets);
+
+      Map<String, String> properties = new HashMap<>();
+      properties.put(IcebergConstants.GRAVITINO_URI, "http://localhost:8090";);
+      properties.put(IcebergConstants.GRAVITINO_METALAKE, metalakeName);
+
+      DynamicIcebergConfigProvider provider = new 
DynamicIcebergConfigProvider();
+      provider.initialize(properties);
+      setMockCatalogFetcher(provider, Map.of(catalogName, mockCatalog));
+
+      Optional<IcebergConfig> config = 
provider.getIcebergCatalogConfig(catalogName);
+      Assertions.assertTrue(config.isPresent());
+      Assertions.assertEquals(
+          "mem-jdbc-pwd",
+          
config.get().getIcebergCatalogProperties().get(IcebergConstants.GRAVITINO_JDBC_PASSWORD));
+    }
+  }
+
+  @Test
+  public void testAuxPlaintext() throws Exception {
+    try (SecretManager sm = memorySecretManager()) {
+      String metalakeName = "test_metalake";
+      String catalogName = "jdbc_catalog";
+
+      Map<String, String> entityProps = new HashMap<>();
+      entityProps.put(IcebergConstants.CATALOG_BACKEND, "jdbc");
+      entityProps.put(IcebergConstants.CATALOG_BACKEND_NAME, catalogName);
+      entityProps.put(IcebergConstants.GRAVITINO_JDBC_USER, "root");
+      List<SecretMaterial> writes =
+          sm.assembleSecretMaterials(
+              Map.of(IcebergConstants.GRAVITINO_JDBC_USER, "root"),
+              entityProps,
+              "catalog",
+              9L,
+              Map.of(
+                  IcebergConstants.GRAVITINO_JDBC_PASSWORD,
+                  new SecretBinding("memory", "aux-mem-pwd")),
+              Map.of());
+      sm.writeSecrets(writes);
+
+      @SuppressWarnings("unchecked")
+      BaseCatalog<?> baseCatalog = Mockito.mock(BaseCatalog.class);
+      CatalogEntity catalogEntity = Mockito.mock(CatalogEntity.class);
+      Mockito.when(baseCatalog.provider()).thenReturn("lakehouse-iceberg");
+      
Mockito.when(baseCatalog.propertiesWithCredentialProviders()).thenReturn(entityProps);
+      Mockito.when(baseCatalog.entity()).thenReturn(catalogEntity);
+      Mockito.when(catalogEntity.id()).thenReturn(9L);
+
+      FieldUtils.writeField(GravitinoEnv.getInstance(), "secretManager", sm, 
true);
+
+      Map<String, String> properties = new HashMap<>();
+      properties.put(IcebergConstants.GRAVITINO_URI, "http://localhost:8090";);
+      properties.put(IcebergConstants.GRAVITINO_METALAKE, metalakeName);
+
+      DynamicIcebergConfigProvider provider = new 
DynamicIcebergConfigProvider();
+      provider.initialize(properties);
+      setMockCatalogFetcher(provider, Map.of(catalogName, baseCatalog));
+
+      Optional<IcebergConfig> config = 
provider.getIcebergCatalogConfig(catalogName);
+      Assertions.assertTrue(config.isPresent());
+      Assertions.assertEquals(
+          "aux-mem-pwd",
+          
config.get().getIcebergCatalogProperties().get(IcebergConstants.GRAVITINO_JDBC_PASSWORD));
+      Assertions.assertEquals(
+          "root",
+          
config.get().getIcebergCatalogProperties().get(IcebergConstants.GRAVITINO_JDBC_USER));
+      Assertions.assertEquals(
+          "9", 
config.get().getIcebergCatalogProperties().get(IcebergConstants.CATALOG_UUID));
+    }
+  }
+
+  private static SecretManager memorySecretManager() {
+    Config config = new Config(false) {};
+    Properties properties = new Properties();
+    properties.setProperty(SecretProviderRegistry.GRAVITINO_SECRET_PROVIDERS, 
"memory");
+    properties.setProperty(
+        SecretProviderRegistry.GRAVITINO_SECRET_PROVIDER_PREFIX
+            + "memory."
+            + SecretProviderRegistry.CLASS_NAME,
+        InMemorySecretsProvider.class.getName());
+    config.loadFromProperties(properties);
+    return new SecretManager(config);
+  }
+>>>>>>> 30687f68f ([#12851] fix(iceberg-rest): Share the managed memory 
catalog in auxiliary mode (#12852))
 }

Reply via email to