Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions itests/qtest-iceberg/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@
<artifactId>hive-it-iceberg-qfile</artifactId>
<packaging>jar</packaging>
<name>Hive Integration - QFile Iceberg Tests</name>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

em, i am not sure about this
cc @zabetak, @abstractdog should we whitelist spring dependencies in Nexus? I originally thought that if a dependency is missing from the local repository, we always fetch it from Central."

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it should work without defining this repository, spring artifacts are present in central:
https://mvnrepository.com/artifact/org.springframework.boot

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the repo definition here is strange don't think we need it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I added that to check if the build passes with this definitions, not for production.
It wasn't able to find spring boot dependencies through the wonder repo.

Copy link
Contributor Author

@difin difin Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it should work without defining this repository, spring artifacts are present in central: https://mvnrepository.com/artifact/org.springframework.boot

@abstractdog no it didn't work, you can see that previous build failed saying these dependencies were missing in wonder.

Copy link
Contributor

@abstractdog abstractdog Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it sounds silly, but the same happens when I add a new tez staging artifact repo, it magically fails to fetch all artifacts for 2-3 times, and then it succeeds: I still think you should remove this, and we can check wonder artifactory logs what exactly happened when it tried to connect to the remote maven central (if it tried at all :D )
I'll check if I can provide easy access to you to the artifactory logs (e.g. kubeconfig)

<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<hive.path.to.root>../..</hive.path.to.root>
</properties>
Expand Down Expand Up @@ -475,6 +487,27 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring Boot test dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.7.18</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
</exclusion>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
Expand Down

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packaging/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@
<MIT>
https?://(www\.)?opensource\.org/licenses/mit(-license.php)?
</MIT>
<public-domain-1.0.html>
https?://creativecommons\.org/publicdomain/zero/1\.0/?
</public-domain-1.0.html>
</licenseUrlFileNames>
<licenseUrlFileNameSanitizers>
<licenseUrlFileNameSanitizer>
Expand Down
139 changes: 139 additions & 0 deletions standalone-metastore/metastore-rest-catalog/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,97 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>hive-standalone-metastore-rest-catalog</artifactId>
<name>Hive Metastore REST Catalog</name>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same nexus related issue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, build on Jenkins failed being unable to find spring boot dependencies before adding this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should set up jenkins in this case, where the local repository has a desired mirrored remote one, let me check the current configuration

Copy link
Contributor

@abstractdog abstractdog Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have all these remote repos configured for the single virtual repository (wonder), so it should work:
Screenshot 2026-02-20 at 16 48 29

I would try to remove the repo from pom.xml, and we'll investigate in the next round what's happening
I can even check the logs of the artifactory if you need, in case of errors

<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<standalone.metastore.path.to.root>..</standalone.metastore.path.to.root>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<log4j2.debug>false</log4j2.debug>
<iceberg.version>1.10.0</iceberg.version>
<spring-boot.version>2.7.18</spring-boot.version>
<!-- Override Spring Boot's Jetty 9.4.53 with Hive's 9.4.57 to avoid version conflicts -->
<jetty.version>9.4.57.v20241219</jetty.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Align all Jetty artifacts to Hive's version; Spring Boot 2.7.18 defaults to 9.4.53 -->
Copy link
Member

@deniskuzZ deniskuzZ Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we align hive to spring deps maybe?

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>${jetty.version}</version>
Copy link
Member

@deniskuzZ deniskuzZ Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it defined in dependency management somewhere? if not, maybe it should be

</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-continuation</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-xml</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-plus</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-common</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-client-impl</artifactId>
<version>${jetty.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
Expand All @@ -42,6 +127,37 @@
<artifactId>hive-iceberg-catalog</artifactId>
<version>${hive.version}</version>
</dependency>
<!-- Spring Boot dependencies - use Jetty instead of Tomcat for Java 21 compatibility -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why exclude logging?

</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we move versions to dependency management?

</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.9.17</version>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.apache.hive</groupId>
Expand Down Expand Up @@ -236,6 +352,13 @@
<artifactId>keycloak-admin-client</artifactId>
<scope>test</scope>
</dependency>
<!-- Required by keycloak-admin-client/Resteasy for jakarta.annotation.Priority -->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
Expand Down Expand Up @@ -303,6 +426,22 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>org.apache.iceberg.rest.standalone.StandaloneRESTCatalogServer</mainClass>
<classifier>exec</classifier>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
Copy link
Member

@deniskuzZ deniskuzZ Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we even need to define the goal?

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <mainClass>org.apache.iceberg.rest.standalone.StandaloneRESTCatalogServer</mainClass>
    </configuration>
</plugin>

</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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.iceberg.rest.standalone;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

/**
* Custom health indicator for HMS connectivity.
* Verifies that HMS is reachable via Thrift, not just that configuration is present.
* Used by Kubernetes readiness probes to determine if the server is ready to accept traffic.
*/
@Component
public class HMSReadinessHealthIndicator implements HealthIndicator {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we move it under the health package?

private static final Logger LOG = LoggerFactory.getLogger(HMSReadinessHealthIndicator.class);

private final Configuration conf;

public HMSReadinessHealthIndicator(Configuration conf) {
this.conf = conf;
}

@Override
public Health health() {
String hmsThriftUris = MetastoreConf.getVar(conf, ConfVars.THRIFT_URIS);
if (hmsThriftUris == null || hmsThriftUris.isEmpty()) {
return Health.down()
.withDetail("reason", "HMS Thrift URIs not configured")
.build();
}

try (HiveMetaStoreClient client = new HiveMetaStoreClient(conf)) {
// Lightweight call to verify HMS is reachable
client.getAllDatabases();
return Health.up()
.withDetail("hmsThriftUris", hmsThriftUris)
.withDetail("warehouse", MetastoreConf.getVar(conf, ConfVars.WAREHOUSE))
.build();
} catch (Exception e) {
LOG.warn("HMS connectivity check failed: {}", e.getMessage());
return Health.down()
.withDetail("hmsThriftUris", hmsThriftUris)
.withDetail("error", e.getMessage())
.build();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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.iceberg.rest.standalone;

import javax.servlet.http.HttpServlet;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
import org.apache.iceberg.rest.HMSCatalogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

/**
* Spring configuration for the Iceberg REST Catalog servlet.
* Extracted to separate concerns from the main application bootstrap.
*/
@org.springframework.context.annotation.Configuration
public class IcebergCatalogConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(IcebergCatalogConfiguration.class);

private final Configuration conf;

public IcebergCatalogConfiguration(Configuration conf) {
this.conf = conf;
}

@Bean
public ServletRegistrationBean<HttpServlet> restCatalogServlet() {
// Determine servlet path and port
String servletPath = MetastoreConf.getVar(conf, ConfVars.ICEBERG_CATALOG_SERVLET_PATH);
if (servletPath == null || servletPath.isEmpty()) {
servletPath = "iceberg";
MetastoreConf.setVar(conf, ConfVars.ICEBERG_CATALOG_SERVLET_PATH, servletPath);
}

int port = MetastoreConf.getIntVar(conf, ConfVars.CATALOG_SERVLET_PORT);
if (port == 0) {
port = 8080;
MetastoreConf.setLongVar(conf, ConfVars.CATALOG_SERVLET_PORT, port);
}

LOG.info("Creating REST Catalog servlet at /{}", servletPath);

// Create servlet from Iceberg factory
org.apache.hadoop.hive.metastore.ServletServerBuilder.Descriptor descriptor =
HMSCatalogFactory.createServlet(conf);
if (descriptor == null || descriptor.getServlet() == null) {
throw new IllegalStateException("Failed to create Iceberg REST Catalog servlet");
}

ServletRegistrationBean<HttpServlet> registration =
new ServletRegistrationBean<>(descriptor.getServlet(), "/" + servletPath + "/*");
registration.setName("IcebergRESTCatalog");
registration.setLoadOnStartup(1);

return registration;
}
}
Loading