-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Hms standalone rest server with spring boot #6327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same nexus related issue
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| <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 --> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> | ||
|
|
@@ -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> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> | ||
|
|
@@ -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> | ||
|
|
@@ -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> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we even need to define the goal? |
||
| </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 { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we move it under the |
||
| 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; | ||
| } | ||
| } |

There was a problem hiding this comment.
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."
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abstractdog no it didn't work, you can see that previous build failed saying these dependencies were missing in wonder.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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)