This is an automated email from the ASF dual-hosted git repository. mayanks pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
The following commit(s) were added to refs/heads/master by this push: new 7299b56 Add admin endpoint for Pinot Minon. (#6822) 7299b56 is described below commit 7299b56ef3ca30a1730a24382a2701b8b2fc5c65 Author: Mayank Shrivastava <maya...@apache.org> AuthorDate: Tue Apr 20 18:05:15 2021 -0700 Add admin endpoint for Pinot Minon. (#6822) The Pinot Minion component, unlike other components, was missing an admin endpoint. In this PR, we added an admin endpoint for Pinot Minion. - The endpoint uses Jersey http server (same as other components). - Setup swagger for Minion. - Also, added the endpoint `/appconfigs` similiar to other components. (See: https://github.com/apache/incubator-pinot/pull/6817). --- .../apache/pinot/core/util/ListenerConfigUtil.java | 21 +++++ pinot-minion/pom.xml | 4 + .../pinot/minion/MinionAdminApiApplication.java | 103 +++++++++++++++++++++ .../org/apache/pinot/minion/MinionStarter.java | 24 +++++ .../api/resources/PinotMinionAppConfigs.java | 52 +++++++++++ .../apache/pinot/spi/utils/CommonConstants.java | 3 + 6 files changed, 207 insertions(+) diff --git a/pinot-core/src/main/java/org/apache/pinot/core/util/ListenerConfigUtil.java b/pinot-core/src/main/java/org/apache/pinot/core/util/ListenerConfigUtil.java index 01936c2..9282ef5 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/util/ListenerConfigUtil.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/util/ListenerConfigUtil.java @@ -143,6 +143,27 @@ public final class ListenerConfigUtil { return listeners; } + public static List<ListenerConfig> buildMinionAdminConfigs(PinotConfiguration minionConf) { + List<ListenerConfig> listeners = new ArrayList<>(); + + String adminApiPortString = minionConf.getProperty(CommonConstants.Minion.CONFIG_OF_ADMIN_API_PORT); + if (adminApiPortString != null) { + listeners.add(new ListenerConfig(CommonConstants.HTTP_PROTOCOL, DEFAULT_HOST, Integer.parseInt(adminApiPortString), + CommonConstants.HTTP_PROTOCOL, new TlsConfig())); + } + + TlsConfig tlsDefaults = TlsUtils.extractTlsConfig(minionConf, CommonConstants.Minion.MINION_TLS_PREFIX); + listeners.addAll(buildListenerConfigs(minionConf, "pinot.minion.adminapi", tlsDefaults)); + + // support legacy behavior < 0.7.0 + if (listeners.isEmpty()) { + listeners.add(new ListenerConfig(CommonConstants.HTTP_PROTOCOL, DEFAULT_HOST, + CommonConstants.Minion.DEFAULT_ADMIN_API_PORT, CommonConstants.HTTP_PROTOCOL, new TlsConfig())); + } + + return listeners; + } + private static ListenerConfig buildListenerConfig(PinotConfiguration config, String namespace, String protocol, TlsConfig tlsConfig) { String protocolNamespace = namespace + DOT_ACCESS_PROTOCOLS + "." + protocol; diff --git a/pinot-minion/pom.xml b/pinot-minion/pom.xml index 949da8d..ffe9f7f 100644 --- a/pinot-minion/pom.xml +++ b/pinot-minion/pom.xml @@ -97,5 +97,9 @@ <artifactId>pinot-yammer</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>io.swagger</groupId> + <artifactId>swagger-jersey2-jaxrs</artifactId> + </dependency> </dependencies> </project> diff --git a/pinot-minion/src/main/java/org/apache/pinot/minion/MinionAdminApiApplication.java b/pinot-minion/src/main/java/org/apache/pinot/minion/MinionAdminApiApplication.java new file mode 100644 index 0000000..12b5058 --- /dev/null +++ b/pinot-minion/src/main/java/org/apache/pinot/minion/MinionAdminApiApplication.java @@ -0,0 +1,103 @@ +/** + * 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.pinot.minion; + +import io.swagger.jaxrs.config.BeanConfig; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; +import org.apache.pinot.core.transport.ListenerConfig; +import org.apache.pinot.core.util.ListenerConfigUtil; +import org.apache.pinot.spi.env.PinotConfiguration; +import org.apache.pinot.spi.utils.CommonConstants; +import org.glassfish.grizzly.http.server.CLStaticHttpHandler; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.internal.inject.AbstractBinder; +import org.glassfish.jersey.server.ResourceConfig; + + +/** + * Admin APP for Pinot Minion. + * <ul> + * <li>Starts a http server.</li> + * <li>Sets up swagger.</li> + * </ul> + */ +public class MinionAdminApiApplication extends ResourceConfig { + private static final String RESOURCE_PACKAGE = "org.apache.pinot.minion.api.resources"; + public static final String PINOT_CONFIGURATION = "pinotConfiguration"; + + private HttpServer _httpServer; + + public MinionAdminApiApplication(PinotConfiguration minionConf) { + packages(RESOURCE_PACKAGE); + property(PINOT_CONFIGURATION, minionConf); + + register(new AbstractBinder() { + @Override + protected void configure() { + // TODO: Add bindings as needed in future. + } + }); + + registerClasses(io.swagger.jaxrs.listing.ApiListingResource.class); + registerClasses(io.swagger.jaxrs.listing.SwaggerSerializers.class); + } + + public void start(List<ListenerConfig> listenerConfigs) { + _httpServer = ListenerConfigUtil.buildHttpServer(this, listenerConfigs); + + try { + _httpServer.start(); + } catch (IOException e) { + throw new RuntimeException("Failed to start http server", e); + } + + setupSwagger(); + } + + private void setupSwagger() { + BeanConfig beanConfig = new BeanConfig(); + beanConfig.setTitle("Pinot Minion API"); + beanConfig.setDescription("APIs for accessing Pinot Minion information"); + beanConfig.setContact("https://github.com/apache/incubator-pinot"); + beanConfig.setVersion("1.0"); + beanConfig.setSchemes(new String[]{CommonConstants.HTTP_PROTOCOL, CommonConstants.HTTPS_PROTOCOL}); + beanConfig.setBasePath("/"); + beanConfig.setResourcePackage(RESOURCE_PACKAGE); + beanConfig.setScan(true); + + HttpHandler httpHandler = new CLStaticHttpHandler(MinionAdminApiApplication.class.getClassLoader(), "/api/"); + // map both /api and /help to swagger docs. /api because it looks nice. /help for backward compatibility + _httpServer.getServerConfiguration().addHttpHandler(httpHandler, "/api/", "/help/"); + + URL swaggerDistLocation = + MinionAdminApiApplication.class.getClassLoader().getResource("META-INF/resources/webjars/swagger-ui/3.18.2/"); + CLStaticHttpHandler swaggerDist = new CLStaticHttpHandler(new URLClassLoader(new URL[]{swaggerDistLocation})); + _httpServer.getServerConfiguration().addHttpHandler(swaggerDist, "/swaggerui-dist/"); + } + + public void stop() { + if (_httpServer != null) { + _httpServer.shutdownNow(); + } + } +} diff --git a/pinot-minion/src/main/java/org/apache/pinot/minion/MinionStarter.java b/pinot-minion/src/main/java/org/apache/pinot/minion/MinionStarter.java index 0615d28..6cd3346 100644 --- a/pinot-minion/src/main/java/org/apache/pinot/minion/MinionStarter.java +++ b/pinot-minion/src/main/java/org/apache/pinot/minion/MinionStarter.java @@ -20,8 +20,10 @@ package org.apache.pinot.minion; import java.io.File; import java.io.IOException; +import java.util.List; import javax.net.ssl.SSLContext; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.helix.HelixAdmin; import org.apache.helix.HelixManager; import org.apache.helix.InstanceType; @@ -34,6 +36,10 @@ import org.apache.pinot.common.metrics.PinotMetricUtils; import org.apache.pinot.common.utils.ClientSSLContextGenerator; import org.apache.pinot.common.utils.ServiceStatus; import org.apache.pinot.common.utils.fetcher.SegmentFetcherFactory; +import org.apache.pinot.core.transport.ListenerConfig; +import org.apache.pinot.core.transport.TlsConfig; +import org.apache.pinot.core.util.ListenerConfigUtil; +import org.apache.pinot.core.util.TlsUtils; import org.apache.pinot.minion.event.EventObserverFactoryRegistry; import org.apache.pinot.minion.event.MinionEventObserverFactory; import org.apache.pinot.minion.executor.MinionTaskZkMetadataManager; @@ -68,6 +74,8 @@ public class MinionStarter implements ServiceStartable { private final HelixManager _helixManager; private final TaskExecutorFactoryRegistry _taskExecutorFactoryRegistry; private final EventObserverFactoryRegistry _eventObserverFactoryRegistry; + private MinionAdminApiApplication _minionAdminApplication; + private final List<ListenerConfig> _listenerConfigs; public MinionStarter(String helixClusterName, String zkAddress, PinotConfiguration config) throws Exception { @@ -78,6 +86,7 @@ public class MinionStarter implements ServiceStartable { int port = _config.getProperty(CommonConstants.Helix.KEY_OF_MINION_PORT, CommonConstants.Minion.DEFAULT_HELIX_PORT); _instanceId = _config.getProperty(CommonConstants.Helix.Instance.INSTANCE_ID_KEY, CommonConstants.Helix.PREFIX_OF_MINION_INSTANCE + host + "_" + port); + _listenerConfigs = ListenerConfigUtil.buildMinionAdminConfigs(_config); setupHelixSystemProperties(); _helixManager = new ZKHelixManager(helixClusterName, _instanceId, InstanceType.PARTICIPANT, zkAddress); MinionTaskZkMetadataManager minionTaskZkMetadataManager = new MinionTaskZkMetadataManager(_helixManager); @@ -160,6 +169,14 @@ public class MinionStarter implements ServiceStartable { minionMetrics.initializeGlobalMeters(); minionContext.setMinionMetrics(minionMetrics); + // Install default SSL context if necessary (even if not force-enabled everywhere) + TlsConfig tlsDefaults = TlsUtils.extractTlsConfig(_config, CommonConstants.Minion.MINION_TLS_PREFIX); + if (StringUtils.isNotBlank(tlsDefaults.getKeyStorePath()) || StringUtils + .isNotBlank(tlsDefaults.getTrustStorePath())) { + LOGGER.info("Installing default SSL context for any client requests"); + TlsUtils.installDefaultSSLSocketFactory(tlsDefaults); + } + // initialize authentication minionContext.setTaskAuthToken(_config.getProperty(CommonConstants.Minion.CONFIG_OF_TASK_AUTH_TOKEN)); @@ -195,6 +212,10 @@ public class MinionStarter implements ServiceStartable { addInstanceTagIfNeeded(); minionContext.setHelixPropertyStore(_helixManager.getHelixPropertyStore()); + LOGGER.info("Starting minion admin application on: {}", ListenerConfigUtil.toString(_listenerConfigs)); + _minionAdminApplication = new MinionAdminApiApplication(_config); + _minionAdminApplication.start(_listenerConfigs); + // Initialize health check callback LOGGER.info("Initializing health check callback"); ServiceStatus.setServiceStatusCallback(_instanceId, new ServiceStatus.ServiceStatusCallback() { @@ -225,6 +246,9 @@ public class MinionStarter implements ServiceStartable { } catch (IOException e) { LOGGER.warn("Caught exception closing PinotFS classes", e); } + LOGGER.info("Shutting down admin application"); + _minionAdminApplication.stop(); + LOGGER.info("Stopping Pinot minion: " + _instanceId); _helixManager.disconnect(); LOGGER.info("Deregistering service status handler"); diff --git a/pinot-minion/src/main/java/org/apache/pinot/minion/api/resources/PinotMinionAppConfigs.java b/pinot-minion/src/main/java/org/apache/pinot/minion/api/resources/PinotMinionAppConfigs.java new file mode 100644 index 0000000..6d4b4ec --- /dev/null +++ b/pinot-minion/src/main/java/org/apache/pinot/minion/api/resources/PinotMinionAppConfigs.java @@ -0,0 +1,52 @@ +/** + * 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.pinot.minion.api.resources; + +import io.swagger.annotations.Api; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import org.apache.pinot.common.utils.PinotAppConfigs; +import org.apache.pinot.minion.MinionAdminApiApplication; +import org.apache.pinot.spi.env.PinotConfiguration; + + +/** + * Resource for getting the app configs {@link PinotAppConfigs} for + * Pinot Minion instance. + */ +@Api(tags = "AppConfig") +@Path("/") +public class PinotMinionAppConfigs { + @Context + private Application _application; + + @GET + @Path("/appconfigs") + @Produces(MediaType.APPLICATION_JSON) + public String getAppConfigs() { + PinotConfiguration pinotConfiguration = + (PinotConfiguration) _application.getProperties().get(MinionAdminApiApplication.PINOT_CONFIGURATION); + PinotAppConfigs pinotAppConfigs = new PinotAppConfigs(pinotConfiguration); + return pinotAppConfigs.toJSONString(); + } +} diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java index 3e42d75..534a3a0 100644 --- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java +++ b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java @@ -386,6 +386,9 @@ public class CommonConstants { * E.g. null (auth disabled), "Basic abcdef..." (basic auth), "Bearer 123def..." (oauth2) */ public static final String CONFIG_OF_TASK_AUTH_TOKEN = "task.auth.token"; + public static final String CONFIG_OF_ADMIN_API_PORT = "pinot.minion.adminapi.port"; + public static final String MINION_TLS_PREFIX = "pinot.minion.tls"; + public static final int DEFAULT_ADMIN_API_PORT = 6500; } public static class Segment { --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org