Skip to content

Commit

Permalink
SOLR-14890: Refactor code to use annotations for configset API (apach…
Browse files Browse the repository at this point in the history
  • Loading branch information
noblepaul authored Sep 23, 2020
1 parent 12dd194 commit fd0c086
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 331 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
28 changes: 3 additions & 25 deletions solr/core/src/java/org/apache/solr/cloud/ZkController.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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());
Expand Down Expand Up @@ -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:"
Expand Down Expand Up @@ -419,11 +420,11 @@ String getConfigName(String coll, ZkNodeProps message) throws KeeperException, I
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;
}
Expand Down Expand Up @@ -452,7 +453,7 @@ private void copyDefaultConfigSetTo(List<String> 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);
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions solr/core/src/java/org/apache/solr/core/CoreContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -720,17 +720,18 @@ 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
*/
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);
Expand Down
70 changes: 57 additions & 13 deletions solr/core/src/java/org/apache/solr/handler/ClusterAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -48,39 +52,80 @@
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,
path = "/cluster/command-status/{id}",
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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -141,7 +186,7 @@ public void removeRole(PayloadObj<RoleInfo> obj) throws Exception {
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) {
Expand All @@ -150,17 +195,16 @@ public void setObjProperty(PayloadObj<ClusterPropInfo> obj) {
}

@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());
}

@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...
Expand Down
Loading

0 comments on commit fd0c086

Please sign in to comment.