From fd0c08615df9440061e5ae664dcfa3f5a7600568 Mon Sep 17 00:00:00 2001 From: Noble Paul Date: Wed, 23 Sep 2020 21:55:51 +1000 Subject: [PATCH] SOLR-14890: Refactor code to use annotations for configset API (#1911) --- .../OverseerConfigSetMessageHandler.java | 24 ++--- .../org/apache/solr/cloud/ZkController.java | 28 +----- .../api/collections/CreateCollectionCmd.java | 19 ++-- .../api/collections/DeleteCollectionCmd.java | 4 +- .../org/apache/solr/core/CoreContainer.java | 5 +- .../org/apache/solr/handler/ClusterAPI.java | 70 +++++++++++--- .../solr/handler/admin/ConfigSetsHandler.java | 61 ++++++------ .../handler/admin/ConfigSetsHandlerApi.java | 93 ------------------- .../handler/admin/TestCollectionAPIs.java | 2 +- .../solr/handler/admin/TestConfigsApi.java | 19 ++-- .../solrj/request/CollectionApiMapping.java | 75 --------------- .../solrj/request/beans/CreateConfigInfo.java | 32 +++++++ .../org/apache/solr/common/MapWriterMap.java | 4 +- .../apispec/cluster.configs.Commands.json | 34 ------- .../apispec/cluster.configs.delete.json | 12 --- .../resources/apispec/cluster.configs.json | 12 --- .../solr/common/util/JsonValidatorTest.java | 1 - 17 files changed, 164 insertions(+), 331 deletions(-) delete mode 100644 solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/CreateConfigInfo.java delete mode 100644 solr/solrj/src/resources/apispec/cluster.configs.Commands.json delete mode 100644 solr/solrj/src/resources/apispec/cluster.configs.delete.json delete mode 100644 solr/solrj/src/resources/apispec/cluster.configs.json diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerConfigSetMessageHandler.java b/solr/core/src/java/org/apache/solr/cloud/OverseerConfigSetMessageHandler.java index 4f5b28f83e32..9af5a6f8c898 100644 --- a/solr/core/src/java/org/apache/solr/cloud/OverseerConfigSetMessageHandler.java +++ b/solr/core/src/java/org/apache/solr/cloud/OverseerConfigSetMessageHandler.java @@ -16,6 +16,17 @@ */ package org.apache.solr.cloud; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.cloud.DocCollection; @@ -32,21 +43,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.invoke.MethodHandles; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - import static org.apache.solr.common.params.CommonParams.NAME; import static org.apache.solr.common.params.ConfigSetParams.ConfigSetAction.CREATE; import static org.apache.solr.common.util.Utils.toJSONString; -import static org.apache.solr.handler.admin.ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME; +import static org.apache.solr.handler.admin.ConfigSetsHandler.DEFAULT_CONFIGSET_NAME; /** * A {@link OverseerMessageHandler} that handles ConfigSets API related diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkController.java b/solr/core/src/java/org/apache/solr/cloud/ZkController.java index dc4c210e7db0..c29623df68df 100644 --- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java +++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java @@ -65,30 +65,8 @@ import org.apache.solr.common.AlreadyClosedException; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; -import org.apache.solr.common.cloud.BeforeReconnect; -import org.apache.solr.common.cloud.ClusterState; -import org.apache.solr.common.cloud.ConnectionManager; -import org.apache.solr.common.cloud.DefaultConnectionStrategy; -import org.apache.solr.common.cloud.DefaultZkACLProvider; -import org.apache.solr.common.cloud.DefaultZkCredentialsProvider; -import org.apache.solr.common.cloud.DocCollection; -import org.apache.solr.common.cloud.DocCollectionWatcher; -import org.apache.solr.common.cloud.LiveNodesListener; -import org.apache.solr.common.cloud.NodesSysPropsCacher; -import org.apache.solr.common.cloud.OnReconnect; -import org.apache.solr.common.cloud.Replica; +import org.apache.solr.common.cloud.*; import org.apache.solr.common.cloud.Replica.Type; -import org.apache.solr.common.cloud.Slice; -import org.apache.solr.common.cloud.SolrZkClient; -import org.apache.solr.common.cloud.ZkACLProvider; -import org.apache.solr.common.cloud.ZkCmdExecutor; -import org.apache.solr.common.cloud.ZkConfigManager; -import org.apache.solr.common.cloud.ZkCoreNodeProps; -import org.apache.solr.common.cloud.ZkCredentialsProvider; -import org.apache.solr.common.cloud.ZkMaintenanceUtils; -import org.apache.solr.common.cloud.ZkNodeProps; -import org.apache.solr.common.cloud.ZkStateReader; -import org.apache.solr.common.cloud.ZooKeeperException; import org.apache.solr.common.params.CollectionParams; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CoreAdminParams; @@ -106,7 +84,7 @@ import org.apache.solr.core.CoreDescriptor; import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrCoreInitializationException; -import org.apache.solr.handler.admin.ConfigSetsHandlerApi; +import org.apache.solr.handler.admin.ConfigSetsHandler; import org.apache.solr.handler.component.HttpShardHandler; import org.apache.solr.logging.MDCLoggingContext; import org.apache.solr.search.SolrIndexSearcher; @@ -908,7 +886,7 @@ private static void bootstrapDefaultConfigSet(SolrZkClient zkClient) throws Keep , "intended to be the default. Current 'solr.default.confdir' value:" , System.getProperty(SolrDispatchFilter.SOLR_DEFAULT_CONFDIR_ATTRIBUTE)); } else { - ZkMaintenanceUtils.upConfig(zkClient, Paths.get(configDirPath), ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME); + ZkMaintenanceUtils.upConfig(zkClient, Paths.get(configDirPath), ConfigSetsHandler.DEFAULT_CONFIGSET_NAME); } } } diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java index 854ee9ab9340..d3567880badf 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java @@ -32,11 +32,11 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.apache.solr.client.solrj.cloud.DistribStateManager; -import org.apache.solr.client.solrj.cloud.SolrCloudManager; import org.apache.solr.client.solrj.cloud.AlreadyExistsException; import org.apache.solr.client.solrj.cloud.BadVersionException; +import org.apache.solr.client.solrj.cloud.DistribStateManager; import org.apache.solr.client.solrj.cloud.NotEmptyException; +import org.apache.solr.client.solrj.cloud.SolrCloudManager; import org.apache.solr.client.solrj.cloud.VersionedData; import org.apache.solr.cloud.Overseer; import org.apache.solr.cloud.ZkController; @@ -63,7 +63,6 @@ import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.TimeSource; import org.apache.solr.common.util.Utils; -import org.apache.solr.handler.admin.ConfigSetsHandlerApi; import org.apache.solr.handler.component.ShardHandler; import org.apache.solr.handler.component.ShardRequest; import org.apache.solr.util.TimeOut; @@ -86,6 +85,8 @@ import static org.apache.solr.common.params.CommonAdminParams.WAIT_FOR_FINAL_STATE; import static org.apache.solr.common.params.CommonParams.NAME; import static org.apache.solr.common.util.StrUtils.formatString; +import static org.apache.solr.handler.admin.ConfigSetsHandler.DEFAULT_CONFIGSET_NAME; +import static org.apache.solr.handler.admin.ConfigSetsHandler.getSuffixedNameForAutoGeneratedConfigSet; public class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -300,7 +301,7 @@ public void call(ClusterState clusterState, ZkNodeProps message, @SuppressWarnin // Emit a warning about production use of data driven functionality boolean defaultConfigSetUsed = message.getStr(COLL_CONF) == null || - message.getStr(COLL_CONF).equals(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME); + message.getStr(COLL_CONF).equals(DEFAULT_CONFIGSET_NAME); if (defaultConfigSetUsed) { results.add("warning", "Using _default configset. Data driven schema functionality" + " is enabled by default, which is NOT RECOMMENDED for production use. To turn it off:" @@ -419,11 +420,11 @@ String getConfigName(String coll, ZkNodeProps message) throws KeeperException, I List configNames = null; try { configNames = ocmh.zkStateReader.getZkClient().getChildren(ZkConfigManager.CONFIGS_ZKNODE, null, true); - if (configNames.contains(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME)) { + if (configNames.contains(DEFAULT_CONFIGSET_NAME)) { if (CollectionAdminParams.SYSTEM_COLL.equals(coll)) { return coll; } else { - String intendedConfigSetName = ConfigSetsHandlerApi.getSuffixedNameForAutoGeneratedConfigSet(coll); + String intendedConfigSetName = getSuffixedNameForAutoGeneratedConfigSet(coll); copyDefaultConfigSetTo(configNames, intendedConfigSetName); return intendedConfigSetName; } @@ -452,7 +453,7 @@ private void copyDefaultConfigSetTo(List configNames, String targetConfi } // Copy _default into targetConfig try { - configManager.copyConfigDir(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME, targetConfig, new HashSet<>()); + configManager.copyConfigDir(DEFAULT_CONFIGSET_NAME, targetConfig, new HashSet<>()); } catch (Exception e) { throw new SolrException(ErrorCode.INVALID_STATE, "Error while copying _default to " + targetConfig, e); } @@ -580,9 +581,9 @@ private static void getConfName(DistribStateManager stateManager, String collect break; } // if _default exists, use that - if (configNames != null && configNames.contains(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME)) { + if (configNames != null && configNames.contains(DEFAULT_CONFIGSET_NAME)) { log.info("Could not find explicit collection configName, but found _default config set - using that set."); - collectionProps.put(ZkController.CONFIGNAME_PROP, ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME); + collectionProps.put(ZkController.CONFIGNAME_PROP, DEFAULT_CONFIGSET_NAME); break; } // if there is only one conf, use that diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java index 352d9e92aebb..5c080578790d 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java @@ -45,7 +45,7 @@ import org.apache.solr.common.util.Utils; import org.apache.solr.core.SolrInfoBean; import org.apache.solr.core.snapshots.SolrSnapshotManager; -import org.apache.solr.handler.admin.ConfigSetsHandlerApi; +import org.apache.solr.handler.admin.ConfigSetsHandler; import org.apache.solr.handler.admin.MetricsHistoryHandler; import org.apache.solr.metrics.SolrMetricManager; import org.apache.zookeeper.KeeperException; @@ -164,7 +164,7 @@ public void call(ClusterState state, ZkNodeProps message, @SuppressWarnings({"ra // delete related config set iff: it is auto generated AND not related to any other collection String configSetName = zkStateReader.readConfigName(collection); - if (ConfigSetsHandlerApi.isAutoGeneratedConfigSet(configSetName)) { + if (ConfigSetsHandler.isAutoGeneratedConfigSet(configSetName)) { boolean configSetIsUsedByOtherCollection = false; // make sure the configSet is not shared with other collections diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 8b0a9e07be06..f85115d36c13 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -720,9 +720,11 @@ public void load() { createHandler(ZK_PATH, ZookeeperInfoHandler.class.getName(), ZookeeperInfoHandler.class); createHandler(ZK_STATUS_PATH, ZookeeperStatusHandler.class.getName(), ZookeeperStatusHandler.class); collectionsHandler = createHandler(COLLECTIONS_HANDLER_PATH, cfg.getCollectionsHandlerClass(), CollectionsHandler.class); - ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler); + configSetsHandler = createHandler(CONFIGSETS_HANDLER_PATH, cfg.getConfigSetsHandlerClass(), ConfigSetsHandler.class); + ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler, configSetsHandler); containerHandlers.getApiBag().registerObject(clusterAPI); containerHandlers.getApiBag().registerObject(clusterAPI.commands); + containerHandlers.getApiBag().registerObject(clusterAPI.configSetCommands); /* * HealthCheckHandler needs to be initialized before InfoHandler, since the later one will call CoreContainer.getHealthCheckHandler(). * We don't register the handler here because it'll be registered inside InfoHandler @@ -730,7 +732,6 @@ public void load() { healthCheckHandler = loader.newInstance(cfg.getHealthCheckHandlerClass(), HealthCheckHandler.class, null, new Class[]{CoreContainer.class}, new Object[]{this}); infoHandler = createHandler(INFO_HANDLER_PATH, cfg.getInfoHandlerClass(), InfoHandler.class); coreAdminHandler = createHandler(CORES_HANDLER_PATH, cfg.getCoreAdminHandlerClass(), CoreAdminHandler.class); - configSetsHandler = createHandler(CONFIGSETS_HANDLER_PATH, cfg.getConfigSetsHandlerClass(), ConfigSetsHandler.class); // metricsHistoryHandler uses metricsHandler, so create it first metricsHandler = new MetricsHandler(this); diff --git a/solr/core/src/java/org/apache/solr/handler/ClusterAPI.java b/solr/core/src/java/org/apache/solr/handler/ClusterAPI.java index 5ce564ed5cfe..284825b63f21 100644 --- a/solr/core/src/java/org/apache/solr/handler/ClusterAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/ClusterAPI.java @@ -25,16 +25,20 @@ import org.apache.solr.api.EndPoint; import org.apache.solr.api.PayloadObj; import org.apache.solr.client.solrj.request.beans.ClusterPropInfo; +import org.apache.solr.client.solrj.request.beans.CreateConfigInfo; +import org.apache.solr.cloud.OverseerConfigSetMessageHandler; import org.apache.solr.cluster.placement.impl.PlacementPluginConfigImpl; import org.apache.solr.common.SolrException; import org.apache.solr.common.annotation.JsonProperty; import org.apache.solr.common.cloud.ClusterProperties; +import org.apache.solr.common.params.CommonParams; +import org.apache.solr.common.params.ConfigSetParams; import org.apache.solr.common.params.DefaultSolrParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.ReflectMapWriter; import org.apache.solr.common.util.Utils; -import org.apache.solr.core.CoreContainer; import org.apache.solr.handler.admin.CollectionsHandler; +import org.apache.solr.handler.admin.ConfigSetsHandler; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; @@ -48,31 +52,34 @@ import static org.apache.solr.common.params.CollectionParams.CollectionAction.REMOVEROLE; import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM; import static org.apache.solr.security.PermissionNameProvider.Name.COLL_READ_PERM; +import static org.apache.solr.security.PermissionNameProvider.Name.CONFIG_EDIT_PERM; +import static org.apache.solr.security.PermissionNameProvider.Name.CONFIG_READ_PERM; public class ClusterAPI { - private final CoreContainer coreContainer; +// private final CoreContainer coreContainer; private final CollectionsHandler collectionsHandler; + private final ConfigSetsHandler configSetsHandler; public final Commands commands = new Commands(); + public final ConfigSetCommands configSetCommands = new ConfigSetCommands(); - public ClusterAPI(CollectionsHandler ch) { + public ClusterAPI(CollectionsHandler ch, ConfigSetsHandler configSetsHandler) { this.collectionsHandler = ch; - this.coreContainer = ch.getCoreContainer(); + this.configSetsHandler = configSetsHandler; } - @EndPoint(method = GET, path = "/cluster/overseer", permission = COLL_READ_PERM) public void getOverseerStatus(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { - coreContainer.getCollectionsHandler().handleRequestBody(wrapParams(req, "action", OVERSEERSTATUS.toString()), rsp); + collectionsHandler.getCoreContainer().getCollectionsHandler().handleRequestBody(wrapParams(req, "action", OVERSEERSTATUS.toString()), rsp); } @EndPoint(method = GET, path = "/cluster", permission = COLL_READ_PERM) public void getCluster(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { - CollectionsHandler.CollectionOperation.LIST_OP.execute(req, rsp, coreContainer.getCollectionsHandler()); + CollectionsHandler.CollectionOperation.LIST_OP.execute(req, rsp, collectionsHandler.getCoreContainer().getCollectionsHandler()); } @EndPoint(method = DELETE, @@ -80,7 +87,45 @@ public void getCluster(SolrQueryRequest req, SolrQueryResponse rsp) throws Excep permission = COLL_EDIT_PERM) public void deleteCommandStatus(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { wrapParams(req, REQUESTID, req.getPathTemplateValues().get("id")); - CollectionsHandler.CollectionOperation.DELETESTATUS_OP.execute(req, rsp, coreContainer.getCollectionsHandler()); + CollectionsHandler.CollectionOperation.DELETESTATUS_OP.execute(req, rsp, collectionsHandler); + } + + @EndPoint(method = DELETE, + path = "/cluster/configs/{name}", + permission = CONFIG_EDIT_PERM + ) + public void deleteConfigSet(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { + req = wrapParams(req, + "action", ConfigSetParams.ConfigSetAction.DELETE.toString(), + CommonParams.NAME, req.getPathTemplateValues().get("name")); + configSetsHandler.handleRequestBody(req, rsp); + } + + @EndPoint(method = GET, + path = "/cluster/configs", + permission = CONFIG_READ_PERM) + public void listConfigSet(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { + ConfigSetsHandler.ConfigSetOperation.LIST_OP.call(req, rsp, configSetsHandler); + } + + @EndPoint(method = POST, + path = "/cluster/configs", + permission = CONFIG_EDIT_PERM + ) + public class ConfigSetCommands { + + @Command(name = "create") + @SuppressWarnings("unchecked") + public void create(PayloadObj obj) throws Exception { + Map mapVals = obj.get().toMap(new HashMap<>()); + Map customProps = (Map) mapVals.remove("properties"); + if(customProps!= null) { + customProps.forEach((k, o) -> mapVals.put(OverseerConfigSetMessageHandler.PROPERTY_PREFIX+"."+ k, o)); + } + mapVals.put("action", ConfigSetParams.ConfigSetAction.CREATE.toString()); + configSetsHandler.handleRequestBody(wrapParams(obj.getRequest(), mapVals), obj.getResponse()); + } + } public static SolrQueryRequest wrapParams(SolrQueryRequest req, Object... def) { @@ -111,7 +156,7 @@ public void getCommandStatus(SolrQueryRequest req, SolrQueryResponse rsp) throws path = "/cluster/nodes", permission = COLL_READ_PERM) public void getNodes(SolrQueryRequest req, SolrQueryResponse rsp) { - rsp.add("nodes", coreContainer.getZkController().getClusterState().getLiveNodes()); + rsp.add("nodes", collectionsHandler.getCoreContainer().getZkController().getClusterState().getLiveNodes()); } @EndPoint(method = POST, @@ -141,7 +186,7 @@ public void removeRole(PayloadObj obj) throws Exception { public void setObjProperty(PayloadObj obj) { //Not using the object directly here because the API differentiate between {name:null} and {} Map m = obj.getDataMap(); - ClusterProperties clusterProperties = new ClusterProperties(coreContainer.getZkController().getZkClient()); + ClusterProperties clusterProperties = new ClusterProperties(collectionsHandler.getCoreContainer().getZkController().getZkClient()); try { clusterProperties.setClusterProperties(m); } catch (Exception e) { @@ -150,9 +195,8 @@ public void setObjProperty(PayloadObj obj) { } @Command(name = "set-property") - @SuppressWarnings({"rawtypes", "unchecked"}) public void setProperty(PayloadObj> obj) throws Exception { - Map m = obj.get(); + Map m = obj.getDataMap(); m.put("action", CLUSTERPROP.toString()); collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(),m ), obj.getResponse()); } @@ -160,7 +204,7 @@ public void setProperty(PayloadObj> obj) throws Exception { @Command(name = "set-placement-plugin") public void setPlacementPlugin(PayloadObj> obj) { Map placementPluginConfig = obj.getDataMap(); - ClusterProperties clusterProperties = new ClusterProperties(coreContainer.getZkController().getZkClient()); + ClusterProperties clusterProperties = new ClusterProperties(collectionsHandler.getCoreContainer().getZkController().getZkClient()); // When the json contains { "set-placement-plugin" : null }, the map is empty, not null. final boolean unset = placementPluginConfig.isEmpty(); // Very basic sanity check. Real validation will be done when the config is used... diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java index bd06069f9cef..ff1a255102cb 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java @@ -19,7 +19,6 @@ import java.io.InputStream; import java.lang.invoke.MethodHandles; import java.nio.charset.StandardCharsets; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; @@ -32,7 +31,6 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.solr.api.Api; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.cloud.OverseerSolrResponse; import org.apache.solr.cloud.OverseerSolrResponseSerializer; @@ -70,17 +68,16 @@ import static org.apache.solr.common.params.ConfigSetParams.ConfigSetAction.CREATE; import static org.apache.solr.common.params.ConfigSetParams.ConfigSetAction.DELETE; import static org.apache.solr.common.params.ConfigSetParams.ConfigSetAction.LIST; -import static org.apache.solr.handler.admin.ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME; /** * A {@link org.apache.solr.request.SolrRequestHandler} for ConfigSets API requests. */ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionNameProvider { + final public static String DEFAULT_CONFIGSET_NAME = "_default"; + final public static String AUTOCREATED_CONFIGSET_SUFFIX = ".AUTOCREATED"; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); protected final CoreContainer coreContainer; public static long DEFAULT_ZK_TIMEOUT = 300 * 1000; - private final ConfigSetsHandlerApi configSetsHandlerApi = new ConfigSetsHandlerApi(this); - /** * Overloaded ctor to inject CoreContainer into the handler. * @@ -90,19 +87,18 @@ public ConfigSetsHandler(final CoreContainer coreContainer) { this.coreContainer = coreContainer; } + public static String getSuffixedNameForAutoGeneratedConfigSet(String configName) { + return configName + AUTOCREATED_CONFIGSET_SUFFIX; + } + + public static boolean isAutoGeneratedConfigSet(String configName) { + return configName != null && configName.endsWith(AUTOCREATED_CONFIGSET_SUFFIX); + } + @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { - if (coreContainer == null) { - throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, - "Core container instance missing"); - } - - // Make sure that the core is ZKAware - if (!coreContainer.isZooKeeperAware()) { - throw new SolrException(ErrorCode.BAD_REQUEST, - "Solr instance is not running in SolrCloud mode."); - } + checkErrors(); // Pick the action SolrParams params = req.getParams(); @@ -123,6 +119,19 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw rsp.setHttpCaching(false); } + protected void checkErrors() { + if (coreContainer == null) { + throw new SolrException(ErrorCode.BAD_REQUEST, + "Core container instance missing"); + } + + // Make sure that the core is ZKAware + if (!coreContainer.isZooKeeperAware()) { + throw new SolrException(ErrorCode.BAD_REQUEST, + "Solr instance is not running in SolrCloud mode."); + } + } + void invokeAction(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetAction action) throws Exception { ConfigSetOperation operation = ConfigSetOperation.get(action); if (log.isInfoEnabled()) { @@ -176,7 +185,7 @@ private void handleConfigUploadRequest(SolrQueryRequest req, SolrQueryResponse r // Create a node for the configuration in zookeeper boolean cleanup = req.getParams().getBool(ConfigSetParams.CLEANUP, false); - + Set filesToDelete; if (overwritesExisting && cleanup) { filesToDelete = getAllConfigsetFiles(zkClient, configPathInZk); @@ -347,10 +356,10 @@ public Category getCategory() { return Category.ADMIN; } - enum ConfigSetOperation { + public enum ConfigSetOperation { CREATE_OP(CREATE) { @Override - Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception { + public Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception { String baseConfigSetName = req.getParams().get(BASE_CONFIGSET, DEFAULT_CONFIGSET_NAME); Map props = CollectionsHandler.copy(req.getParams().required(), null, NAME); props.put(BASE_CONFIGSET, baseConfigSetName); @@ -359,14 +368,14 @@ Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSets }, DELETE_OP(DELETE) { @Override - Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception { + public Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception { return CollectionsHandler.copy(req.getParams().required(), null, NAME); } }, @SuppressWarnings({"unchecked"}) LIST_OP(LIST) { @Override - Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception { + public Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception { NamedList results = new NamedList<>(); SolrZkClient zk = h.coreContainer.getZkController().getZkStateReader().getZkClient(); ZkConfigManager zkConfigManager = new ZkConfigManager(zk); @@ -384,7 +393,7 @@ Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSets this.action = action; } - abstract Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception; + public abstract Map call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception; public static ConfigSetOperation get(ConfigSetAction action) { for (ConfigSetOperation op : values()) { @@ -394,16 +403,6 @@ public static ConfigSetOperation get(ConfigSetAction action) { } } - @Override - public Collection getApis() { - return configSetsHandlerApi.getApis(); - } - - @Override - public Boolean registerV2() { - return Boolean.TRUE; - } - @Override public Name getPermissionName(AuthorizationContext ctx) { String a = ctx.getParams().get(ConfigSetParams.ACTION); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java deleted file mode 100644 index 30450a8ff35f..000000000000 --- a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.solr.handler.admin; - -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; - -import org.apache.solr.client.solrj.request.CollectionApiMapping; -import org.apache.solr.client.solrj.request.CollectionApiMapping.ConfigSetMeta; -import org.apache.solr.handler.admin.ConfigSetsHandler.ConfigSetOperation; -import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.response.SolrQueryResponse; - -public class ConfigSetsHandlerApi extends BaseHandlerApiSupport { - - final public static String DEFAULT_CONFIGSET_NAME = "_default"; - final public static String AUTOCREATED_CONFIGSET_SUFFIX = ".AUTOCREATED"; - - - final ConfigSetsHandler configSetHandler; - static Collection apiCommands = createMapping(); - - public static String getSuffixedNameForAutoGeneratedConfigSet(String configName) { - return configName + AUTOCREATED_CONFIGSET_SUFFIX; - } - - public static boolean isAutoGeneratedConfigSet(String configName) { - return configName != null && configName.endsWith(AUTOCREATED_CONFIGSET_SUFFIX); - } - - private static Collection createMapping() { - Map result = new EnumMap<>(ConfigSetMeta.class); - - for (ConfigSetMeta meta : ConfigSetMeta.values()) - for (ConfigSetOperation op : ConfigSetOperation.values()) { - if (op.action == meta.action) { - result.put(meta, new ApiCommand() { - @Override - public CollectionApiMapping.CommandMeta meta() { - return meta; - } - - @Override - public void invoke(SolrQueryRequest req, SolrQueryResponse rsp, BaseHandlerApiSupport apiHandler) throws Exception { - ((ConfigSetsHandlerApi) apiHandler).configSetHandler.invokeAction(req, rsp, op.action); - } - }); - } - } - - for (ConfigSetMeta meta : ConfigSetMeta.values()) { - if(result.get(meta) == null){ - throw new RuntimeException("No implementation for "+ meta.name()); - } - } - - return result.values(); - } - - public ConfigSetsHandlerApi(ConfigSetsHandler configSetHandler) { - this.configSetHandler = configSetHandler; - } - - - @Override - protected Collection getCommands() { - return apiCommands; - } - - @Override - protected List getEndPoints() { - return Arrays.asList(CollectionApiMapping.ConfigSetEndPoint.values()); - } - -} diff --git a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java index 3890d8595e87..1308d0585ba4 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java @@ -86,7 +86,7 @@ public void testCommands() throws Exception { Collection apis = collectionsHandler.getApis(); for (Api api : apis) apiBag.register(api, Collections.emptyMap()); - ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler); + ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler,null); apiBag.registerObject(clusterAPI); apiBag.registerObject(clusterAPI.commands); } diff --git a/solr/core/src/test/org/apache/solr/handler/admin/TestConfigsApi.java b/solr/core/src/test/org/apache/solr/handler/admin/TestConfigsApi.java index 0452a1e47ee8..a77830f0c5b6 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/TestConfigsApi.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/TestConfigsApi.java @@ -21,13 +21,11 @@ import java.util.Map; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.api.Api; import org.apache.solr.api.ApiBag; import org.apache.solr.common.cloud.ZkNodeProps; +import org.apache.solr.handler.ClusterAPI; import org.apache.solr.response.SolrQueryResponse; -import org.apache.zookeeper.KeeperException; -import static java.util.Collections.EMPTY_MAP; import static org.apache.solr.client.solrj.SolrRequest.METHOD.DELETE; import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST; import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION; @@ -36,21 +34,28 @@ public class TestConfigsApi extends SolrTestCaseJ4 { - @SuppressWarnings({"unchecked"}) public void testCommands() throws Exception { try (ConfigSetsHandler handler = new ConfigSetsHandler(null) { + + @Override + protected void checkErrors() { + } + @Override protected void sendToZk(SolrQueryResponse rsp, ConfigSetOperation operation, - Map result) - throws KeeperException, InterruptedException { + Map result) { result.put(QUEUE_OPERATION, operation.action.toLower()); rsp.add(ZkNodeProps.class.getName(), new ZkNodeProps(result)); } }) { ApiBag apiBag = new ApiBag(false); - for (Api api : handler.getApis()) apiBag.register(api, EMPTY_MAP); + + ClusterAPI o = new ClusterAPI(null, handler); + apiBag.registerObject(o); + apiBag.registerObject(o.configSetCommands); +// for (Api api : handler.getApis()) apiBag.register(api, EMPTY_MAP); compareOutput(apiBag, "/cluster/configs/sample", DELETE, null, null, "{name :sample, operation:delete}"); diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java index 9d35e40e96a2..91227e056036 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java @@ -30,7 +30,6 @@ import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.common.params.CollectionParams.CollectionAction; -import org.apache.solr.common.params.ConfigSetParams.ConfigSetAction; import org.apache.solr.common.util.CommandOperation; import org.apache.solr.common.util.Pair; import org.apache.solr.common.util.Utils; @@ -38,9 +37,6 @@ import static org.apache.solr.client.solrj.SolrRequest.METHOD.DELETE; import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET; import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST; -import static org.apache.solr.client.solrj.request.CollectionApiMapping.ConfigSetEndPoint.CONFIG_COMMANDS; -import static org.apache.solr.client.solrj.request.CollectionApiMapping.ConfigSetEndPoint.CONFIG_DEL; -import static org.apache.solr.client.solrj.request.CollectionApiMapping.ConfigSetEndPoint.LIST_CONFIG; import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.CLUSTER_ALIASES; import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.COLLECTIONS; import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.COLLECTIONS_COMMANDS; @@ -181,23 +177,6 @@ public String getParamSubstitute(String param) { NAME, "collection", "propertyName", "name", "propertyValue", "value")), -/* ADD_ROLE(CLUSTER_CMD, - POST, - ADDROLE, - "add-role",null),*/ -/* REMOVE_ROLE(CLUSTER_CMD, - POST, - REMOVEROLE, - "remove-role",null),*/ - - /* SET_CLUSTER_PROPERTY(CLUSTER_CMD, - POST, - CLUSTERPROP, - "set-property",null),*/ - /* SET_CLUSTER_PROPERTY_OBJ(CLUSTER_CMD, - POST, - null, - "set-obj-property", null),*/ BACKUP_COLLECTION(COLLECTIONS_COMMANDS, POST, BACKUP, @@ -360,60 +339,6 @@ public interface V2EndPoint { String getSpecName(); } - public enum ConfigSetMeta implements CommandMeta { - LIST(LIST_CONFIG, GET,null, ConfigSetAction.LIST), - CREATE(CONFIG_COMMANDS, POST, "create", ConfigSetAction.CREATE), - DEL(CONFIG_DEL, DELETE, null, ConfigSetAction.DELETE) - ; - public final ConfigSetEndPoint endPoint; - public final SolrRequest.METHOD method; - public final String cmdName; - public final ConfigSetAction action; - - - ConfigSetMeta(ConfigSetEndPoint endPoint, SolrRequest.METHOD method, String cmdName, ConfigSetAction action) { - this.cmdName = cmdName; - this.endPoint = endPoint; - this.method = method; - this.action = action; - } - - @Override - public String getName() { - return cmdName; - } - - @Override - public SolrRequest.METHOD getHttpMethod() { - return method; - } - - @Override - public V2EndPoint getEndPoint() { - return endPoint; - } - - - } - public enum ConfigSetEndPoint implements V2EndPoint { - LIST_CONFIG("cluster.configs"), - CONFIG_COMMANDS("cluster.configs.Commands"), - CONFIG_DEL("cluster.configs.delete"); - - public final String spec; - - ConfigSetEndPoint(String spec) { - this.spec = spec; - } - - @Override - public String getSpecName() { - return spec; - } - } - - - @SuppressWarnings({"unchecked", "rawtypes"}) private static Collection getParamNames_(CommandOperation op, CommandMeta command) { Object o = op.getCommandData(); diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/CreateConfigInfo.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/CreateConfigInfo.java new file mode 100644 index 000000000000..5cd10b68eb8a --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/CreateConfigInfo.java @@ -0,0 +1,32 @@ +/* + * 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.solr.client.solrj.request.beans; + +import java.util.Map; + +import org.apache.solr.common.annotation.JsonProperty; +import org.apache.solr.common.util.ReflectMapWriter; + +public class CreateConfigInfo implements ReflectMapWriter { + @JsonProperty(required = true) + public String name; + @JsonProperty + public String baseConfigSet; + @JsonProperty + public Map properties; + +} diff --git a/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java b/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java index 8b35c9642a3a..c5f61648f5ac 100644 --- a/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java +++ b/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java @@ -51,8 +51,8 @@ public Object _get(List path, Object def) { @Override - @SuppressWarnings({"rawtypes"}) - public Map toMap(Map map) { + @SuppressWarnings("unchecked") + public Map toMap(Map map) { return delegate; } } diff --git a/solr/solrj/src/resources/apispec/cluster.configs.Commands.json b/solr/solrj/src/resources/apispec/cluster.configs.Commands.json deleted file mode 100644 index f8b3b3ae92a6..000000000000 --- a/solr/solrj/src/resources/apispec/cluster.configs.Commands.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "documentation": "https://lucene.apache.org/solr/guide/configsets-api.html#configsets-create", - "description": "Create configsets.", - "methods": [ - "POST" - ], - "url": { - "paths": [ - "/cluster/configs"] - }, - "commands": { - "create": { - "type" :"object", - "description": "Create a configset, based on another configset already in ZooKeeper.", - "documentation": "https://lucene.apache.org/solr/guide/configsets-api.html#configsets-create", - "properties": { - "name" :{ - "type" :"string", - "description" : "The name of the configset to be created." - }, - "baseConfigSet":{ - "type" : "string", - "description" :"The existing configset to copy as the basis for the new one." - }, - "properties" : { - "type":"object", - "description": "Additional key-value pairs, in the form of 'ConfigSetProp.=', as needed. These properties will override the same properties in the base configset.", - "additionalProperties" : true - } - }, - "required" : ["name"] - } - } -} diff --git a/solr/solrj/src/resources/apispec/cluster.configs.delete.json b/solr/solrj/src/resources/apispec/cluster.configs.delete.json deleted file mode 100644 index 20985b8ba57d..000000000000 --- a/solr/solrj/src/resources/apispec/cluster.configs.delete.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "documentation": "https://lucene.apache.org/solr/guide/configsets-api.html#configsets-delete", - "description": "Delete configsets. The name of the configset to delete must be provided as a path parameter.", - "methods": [ - "DELETE" - ], - "url": { - "paths": [ - "/cluster/configs/{name}" - ] - } -} diff --git a/solr/solrj/src/resources/apispec/cluster.configs.json b/solr/solrj/src/resources/apispec/cluster.configs.json deleted file mode 100644 index 45d91d9a62cf..000000000000 --- a/solr/solrj/src/resources/apispec/cluster.configs.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "documentation": "https://lucene.apache.org/solr/guide/configsets-api.html#configsets-list", - "description": "List all configsets in the cluster.", - "methods": [ - "GET" - ], - "url": { - "paths": [ - "/cluster/configs" - ] - } -} diff --git a/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java b/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java index b4807e3d373f..d539088617e8 100644 --- a/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java +++ b/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java @@ -39,7 +39,6 @@ public void testSchema() { checkSchema("cluster.security.RuleBasedAuthorization"); checkSchema("core.config.Commands"); checkSchema("core.SchemaEdit"); - checkSchema("cluster.configs.Commands"); }