SOLR-14890: Refactor code to use annotations for configset API (#1911)

This commit is contained in:
Noble Paul 2020-09-23 21:55:51 +10:00 committed by GitHub
parent 12dd19427e
commit fd0c08615d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 164 additions and 331 deletions

View File

@ -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.apache.zookeeper.KeeperException;
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

View File

@ -65,30 +65,8 @@ import org.apache.solr.cloud.overseer.SliceMutator;
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.CoreContainer;
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 @@ public class ZkController implements Closeable {
, "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);
}
}
}

View File

@ -32,11 +32,11 @@ import java.util.Properties;
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.NamedList;
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.ASYNC;
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 class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd
// 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 @@ public class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd
List<String> 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 @@ public class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd
}
// 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 @@ public class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd
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

View File

@ -45,7 +45,7 @@ import org.apache.solr.common.util.TimeSource;
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 class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
// 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

View File

@ -720,9 +720,11 @@ public class CoreContainer {
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 class CoreContainer {
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);

View File

@ -25,16 +25,20 @@ import org.apache.solr.api.Command;
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.OV
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 class ClusterAPI {
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<CreateConfigInfo> obj) throws Exception {
Map<String, Object> mapVals = obj.get().toMap(new HashMap<>());
Map<String,Object> customProps = (Map<String, Object>) 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 class ClusterAPI {
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 class ClusterAPI {
public void setObjProperty(PayloadObj<ClusterPropInfo> 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 class ClusterAPI {
}
@Command(name = "set-property")
@SuppressWarnings({"rawtypes", "unchecked"})
public void setProperty(PayloadObj<Map<String,String>> obj) throws Exception {
Map m = obj.get();
Map<String,Object> m = obj.getDataMap();
m.put("action", CLUSTERPROP.toString());
collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(),m ), obj.getResponse());
}
@ -160,7 +204,7 @@ public class ClusterAPI {
@Command(name = "set-placement-plugin")
public void setPlacementPlugin(PayloadObj<Map<String, Object>> obj) {
Map<String, Object> 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...

View File

@ -19,7 +19,6 @@ package org.apache.solr.handler.admin;
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 java.util.zip.ZipInputStream;
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.CommonParams.NAME;
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 class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
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 class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
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()) {
@ -347,10 +356,10 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
return Category.ADMIN;
}
enum ConfigSetOperation {
public enum ConfigSetOperation {
CREATE_OP(CREATE) {
@Override
Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception {
public Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception {
String baseConfigSetName = req.getParams().get(BASE_CONFIGSET, DEFAULT_CONFIGSET_NAME);
Map<String, Object> props = CollectionsHandler.copy(req.getParams().required(), null, NAME);
props.put(BASE_CONFIGSET, baseConfigSetName);
@ -359,14 +368,14 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
},
DELETE_OP(DELETE) {
@Override
Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception {
public Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception {
return CollectionsHandler.copy(req.getParams().required(), null, NAME);
}
},
@SuppressWarnings({"unchecked"})
LIST_OP(LIST) {
@Override
Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception {
public Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception {
NamedList<Object> results = new NamedList<>();
SolrZkClient zk = h.coreContainer.getZkController().getZkStateReader().getZkClient();
ZkConfigManager zkConfigManager = new ZkConfigManager(zk);
@ -384,7 +393,7 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
this.action = action;
}
abstract Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception;
public abstract Map<String, Object> call(SolrQueryRequest req, SolrQueryResponse rsp, ConfigSetsHandler h) throws Exception;
public static ConfigSetOperation get(ConfigSetAction action) {
for (ConfigSetOperation op : values()) {
@ -394,16 +403,6 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
}
}
@Override
public Collection<Api> getApis() {
return configSetsHandlerApi.getApis();
}
@Override
public Boolean registerV2() {
return Boolean.TRUE;
}
@Override
public Name getPermissionName(AuthorizationContext ctx) {
String a = ctx.getParams().get(ConfigSetParams.ACTION);

View File

@ -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<ApiCommand> 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<ApiCommand> createMapping() {
Map<ConfigSetMeta, ApiCommand> 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<ApiCommand> getCommands() {
return apiCommands;
}
@Override
protected List<CollectionApiMapping.V2EndPoint> getEndPoints() {
return Arrays.asList(CollectionApiMapping.ConfigSetEndPoint.values());
}
}

View File

@ -86,7 +86,7 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
Collection<Api> 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);
}

View File

@ -21,13 +21,11 @@ package org.apache.solr.handler.admin;
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 @@ import static org.apache.solr.handler.admin.TestCollectionAPIs.compareOutput;
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<String, Object> result)
throws KeeperException, InterruptedException {
Map<String, Object> 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}");

View File

@ -30,7 +30,6 @@ import java.util.stream.Stream;
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 org.apache.solr.common.util.Utils;
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 class CollectionApiMapping {
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 class CollectionApiMapping {
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<String> getParamNames_(CommandOperation op, CommandMeta command) {
Object o = op.getCommandData();

View File

@ -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<String,Object> properties;
}

View File

@ -51,8 +51,8 @@ public class MapWriterMap implements MapWriter {
@Override
@SuppressWarnings({"rawtypes"})
public Map toMap(Map<String, Object> map) {
@SuppressWarnings("unchecked")
public Map<String,Object> toMap(Map<String, Object> map) {
return delegate;
}
}

View File

@ -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.<key>=<value>', as needed. These properties will override the same properties in the base configset.",
"additionalProperties" : true
}
},
"required" : ["name"]
}
}
}

View File

@ -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}"
]
}
}

View File

@ -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"
]
}
}

View File

@ -39,7 +39,6 @@ public class JsonValidatorTest extends SolrTestCaseJ4 {
checkSchema("cluster.security.RuleBasedAuthorization");
checkSchema("core.config.Commands");
checkSchema("core.SchemaEdit");
checkSchema("cluster.configs.Commands");
}