use of org.apache.ignite.spi.IgniteNodeValidationResult in project ignite by apache.
the class ValidationOnNodeJoinUtils method validateNode.
/**
* Checks a joining node to configuration consistency.
*
* @param node Node.
* @param discoData Disco data.
* @param marsh Marsh.
* @param ctx Context.
* @param cacheDescProvider Cache descriptor provider.
*/
@Nullable
static IgniteNodeValidationResult validateNode(ClusterNode node, DiscoveryDataBag.JoiningNodeDiscoveryData discoData, Marshaller marsh, GridKernalContext ctx, Function<String, DynamicCacheDescriptor> cacheDescProvider) {
if (discoData.hasJoiningNodeData() && discoData.joiningNodeData() instanceof CacheJoinNodeDiscoveryData) {
CacheJoinNodeDiscoveryData nodeData = (CacheJoinNodeDiscoveryData) discoData.joiningNodeData();
boolean isGridActive = ctx.state().clusterState().active();
StringBuilder errorMsg = new StringBuilder();
if (!node.isClient()) {
validateRmtRegions(node, ctx).forEach(error -> {
if (errorMsg.length() > 0)
errorMsg.append("\n");
errorMsg.append(error);
});
}
SecurityContext secCtx = null;
if (ctx.security().enabled()) {
try {
secCtx = nodeSecurityContext(marsh, U.resolveClassLoader(ctx.config()), node);
} catch (SecurityException se) {
errorMsg.append(se.getMessage());
}
}
for (CacheJoinNodeDiscoveryData.CacheInfo cacheInfo : nodeData.caches().values()) {
if (secCtx != null && cacheInfo.cacheType() == CacheType.USER) {
try (OperationSecurityContext s = ctx.security().withContext(secCtx)) {
GridCacheProcessor.authorizeCacheCreate(ctx.security(), cacheInfo.cacheData().config());
} catch (SecurityException ex) {
if (errorMsg.length() > 0)
errorMsg.append("\n");
errorMsg.append(ex.getMessage());
}
}
DynamicCacheDescriptor locDesc = cacheDescProvider.apply(cacheInfo.cacheData().config().getName());
if (locDesc == null)
continue;
String joinedSchema = cacheInfo.cacheData().config().getSqlSchema();
Collection<QueryEntity> joinedQryEntities = cacheInfo.cacheData().queryEntities();
String locSchema = locDesc.cacheConfiguration().getSqlSchema();
// QuerySchema is empty and schema name is null (when indexing enabled dynamically).
if (!F.eq(joinedSchema, locSchema) && (locSchema != null || !locDesc.schema().isEmpty()) && (joinedSchema != null || !F.isEmpty(joinedQryEntities))) {
errorMsg.append(String.format(SQL_SCHEMA_CONFLICTS_MESSAGE, locDesc.cacheName(), joinedSchema, locSchema));
}
QuerySchemaPatch schemaPatch = locDesc.makeSchemaPatch(joinedQryEntities);
if (schemaPatch.hasConflicts() || (isGridActive && !schemaPatch.isEmpty())) {
if (errorMsg.length() > 0)
errorMsg.append("\n");
if (schemaPatch.hasConflicts()) {
errorMsg.append(String.format(MERGE_OF_CONFIG_CONFLICTS_MESSAGE, locDesc.cacheName(), schemaPatch.getConflictsMessage()));
} else
errorMsg.append(String.format(MERGE_OF_CONFIG_REQUIRED_MESSAGE, locDesc.cacheName()));
}
// This check must be done on join, otherwise group encryption key will be
// written to metastore regardless of validation check and could trigger WAL write failures.
boolean locEnc = locDesc.cacheConfiguration().isEncryptionEnabled();
boolean rmtEnc = cacheInfo.cacheData().config().isEncryptionEnabled();
if (locEnc != rmtEnc) {
if (errorMsg.length() > 0)
errorMsg.append("\n");
// Message will be printed on remote node, so need to swap local and remote.
errorMsg.append(String.format(ENCRYPT_MISMATCH_MESSAGE, locDesc.cacheName(), rmtEnc, locEnc));
}
}
if (errorMsg.length() > 0) {
String msg = errorMsg.toString();
return new IgniteNodeValidationResult(node.id(), msg);
}
}
return null;
}
use of org.apache.ignite.spi.IgniteNodeValidationResult in project ignite by apache.
the class GridManagerAdapter method onKernalStart.
/**
* {@inheritDoc}
*/
@Override
public final void onKernalStart(boolean active) throws IgniteCheckedException {
for (final IgniteSpi spi : spis) {
try {
spi.onContextInitialized(new IgniteSpiContext() {
@Override
public boolean isStopping() {
return ctx.isStopping();
}
@Override
public Collection<ClusterNode> remoteNodes() {
return ctx.discovery().remoteNodes();
}
@Override
public Collection<ClusterNode> nodes() {
return ctx.discovery().allNodes();
}
@Override
public ClusterNode localNode() {
return ctx.discovery().localNode();
}
@Override
public Collection<ClusterNode> remoteDaemonNodes() {
final Collection<ClusterNode> all = ctx.discovery().daemonNodes();
return !localNode().isDaemon() ? all : F.view(all, new IgnitePredicate<ClusterNode>() {
@Override
public boolean apply(ClusterNode n) {
return n.isDaemon();
}
});
}
@Nullable
@Override
public ClusterNode node(UUID nodeId) {
A.notNull(nodeId, "nodeId");
return ctx.discovery().node(nodeId);
}
@Override
public boolean pingNode(UUID nodeId) {
A.notNull(nodeId, "nodeId");
try {
return ctx.discovery().pingNode(nodeId);
} catch (IgniteCheckedException e) {
throw U.convertException(e);
}
}
@Override
public void send(ClusterNode node, Serializable msg, String topic) throws IgniteSpiException {
A.notNull(node, "node");
A.notNull(msg, "msg");
A.notNull(topic, "topic");
try {
if (msg instanceof Message)
ctx.io().sendToCustomTopic(node, topic, (Message) msg, SYSTEM_POOL);
else
ctx.io().sendUserMessage(Collections.singletonList(node), msg, topic, false, 0, false);
} catch (IgniteCheckedException e) {
throw unwrapException(e);
}
}
@Override
public void addLocalMessageListener(Object topic, IgniteBiPredicate<UUID, ?> p) {
A.notNull(topic, "topic");
A.notNull(p, "p");
ctx.io().addUserMessageListener(topic, p);
}
@Override
public void removeLocalMessageListener(Object topic, IgniteBiPredicate<UUID, ?> p) {
A.notNull(topic, "topic");
A.notNull(topic, "p");
ctx.io().removeUserMessageListener(topic, p);
}
@Override
public void addMessageListener(GridMessageListener lsnr, String topic) {
A.notNull(lsnr, "lsnr");
A.notNull(topic, "topic");
ctx.io().addMessageListener(topic, lsnr);
}
@Override
public boolean removeMessageListener(GridMessageListener lsnr, String topic) {
A.notNull(lsnr, "lsnr");
A.notNull(topic, "topic");
return ctx.io().removeMessageListener(topic, lsnr);
}
@Override
public void addLocalEventListener(GridLocalEventListener lsnr, int... types) {
A.notNull(lsnr, "lsnr");
ctx.event().addLocalEventListener(lsnr, types);
}
@Override
public boolean removeLocalEventListener(GridLocalEventListener lsnr) {
A.notNull(lsnr, "lsnr");
return ctx.event().removeLocalEventListener(lsnr);
}
@Override
public boolean isEventRecordable(int... types) {
for (int t : types) if (!ctx.event().isRecordable(t))
return false;
return true;
}
@Override
public void recordEvent(Event evt) {
A.notNull(evt, "evt");
if (ctx.event().isRecordable(evt.type()))
ctx.event().record(evt);
}
@Override
public void registerPort(int port, IgnitePortProtocol proto) {
ctx.ports().registerPort(port, proto, spi.getClass());
}
@Override
public void deregisterPort(int port, IgnitePortProtocol proto) {
ctx.ports().deregisterPort(port, proto, spi.getClass());
}
@Override
public void deregisterPorts() {
ctx.ports().deregisterPorts(spi.getClass());
}
@Nullable
@Override
public <K, V> V get(String cacheName, K key) {
return ctx.cache().<K, V>jcache(cacheName).get(key);
}
@Nullable
@Override
public <K, V> V put(String cacheName, K key, V val, long ttl) {
try {
if (ttl > 0) {
ExpiryPolicy plc = new TouchedExpiryPolicy(new Duration(MILLISECONDS, ttl));
IgniteCache<K, V> cache = ctx.cache().<K, V>publicJCache(cacheName).withExpiryPolicy(plc);
return cache.getAndPut(key, val);
} else
return ctx.cache().<K, V>jcache(cacheName).getAndPut(key, val);
} catch (IgniteCheckedException e) {
throw CU.convertToCacheException(e);
}
}
@Nullable
@Override
public <K, V> V putIfAbsent(String cacheName, K key, V val, long ttl) {
try {
if (ttl > 0) {
ExpiryPolicy plc = new TouchedExpiryPolicy(new Duration(MILLISECONDS, ttl));
IgniteCache<K, V> cache = ctx.cache().<K, V>publicJCache(cacheName).withExpiryPolicy(plc);
return cache.getAndPutIfAbsent(key, val);
} else
return ctx.cache().<K, V>jcache(cacheName).getAndPutIfAbsent(key, val);
} catch (IgniteCheckedException e) {
throw CU.convertToCacheException(e);
}
}
@Nullable
@Override
public <K, V> V remove(String cacheName, K key) {
return ctx.cache().<K, V>jcache(cacheName).getAndRemove(key);
}
@Override
public <K> boolean containsKey(String cacheName, K key) {
return ctx.cache().cache(cacheName).containsKey(key);
}
@Override
public int partition(String cacheName, Object key) {
return ctx.cache().cache(cacheName).affinity().partition(key);
}
@Override
public IgniteNodeValidationResult validateNode(ClusterNode node) {
for (GridComponent comp : ctx) {
IgniteNodeValidationResult err = comp.validateNode(node);
if (err != null)
return err;
}
return null;
}
@Nullable
@Override
public IgniteNodeValidationResult validateNode(ClusterNode node, DiscoveryDataBag discoData) {
for (GridComponent comp : ctx) {
if (comp.discoveryDataType() == null)
continue;
IgniteNodeValidationResult err = comp.validateNode(node, discoData.newJoinerDiscoveryData(comp.discoveryDataType().ordinal()));
if (err != null)
return err;
}
return null;
}
@Override
public Collection<SecuritySubject> authenticatedSubjects() {
try {
return ctx.security().authenticatedSubjects();
} catch (IgniteCheckedException e) {
throw U.convertException(e);
}
}
@Override
public SecuritySubject authenticatedSubject(UUID subjId) {
try {
return ctx.security().authenticatedSubject(subjId);
} catch (IgniteCheckedException e) {
throw U.convertException(e);
}
}
@Override
public MessageFormatter messageFormatter() {
return ctx.io().formatter();
}
@Override
public MessageFactory messageFactory() {
return ctx.io().messageFactory();
}
@Override
public boolean tryFailNode(UUID nodeId, @Nullable String warning) {
return ctx.discovery().tryFailNode(nodeId, warning);
}
@Override
public void failNode(UUID nodeId, @Nullable String warning) {
ctx.discovery().failNode(nodeId, warning);
}
@Override
public void addTimeoutObject(IgniteSpiTimeoutObject obj) {
ctx.timeout().addTimeoutObject(new GridSpiTimeoutObject(obj));
}
@Override
public void removeTimeoutObject(IgniteSpiTimeoutObject obj) {
ctx.timeout().removeTimeoutObject(new GridSpiTimeoutObject(obj));
}
@Override
public Map<String, Object> nodeAttributes() {
return ctx.nodeAttributes();
}
@Override
public boolean communicationFailureResolveSupported() {
return ctx.discovery().communicationErrorResolveSupported();
}
@Override
public void resolveCommunicationFailure(ClusterNode node, Exception err) {
ctx.discovery().resolveCommunicationError(node, err);
}
@Override
public ReadOnlyMetricRegistry getOrCreateMetricRegistry(String name) {
return ctx.metric().registry(name);
}
@Override
public void removeMetricRegistry(String name) {
ctx.metric().remove(name);
}
@Override
public Iterable<ReadOnlyMetricRegistry> metricRegistries() {
return ctx.metric();
}
@Override
public void addMetricRegistryCreationListener(Consumer<ReadOnlyMetricRegistry> lsnr) {
ctx.metric().addMetricRegistryCreationListener(lsnr);
}
/**
* @param e Exception to handle.
* @return GridSpiException Converted exception.
*/
private IgniteSpiException unwrapException(IgniteCheckedException e) {
// Avoid double-wrapping.
if (e.getCause() instanceof IgniteSpiException)
return (IgniteSpiException) e.getCause();
return new IgniteSpiException("Failed to execute SPI context method.", e);
}
});
} catch (IgniteSpiException e) {
throw new IgniteCheckedException("Failed to initialize SPI context.", e);
}
}
onKernalStart0();
}
use of org.apache.ignite.spi.IgniteNodeValidationResult in project ignite by apache.
the class IgniteNodeValidationFailedEventTest method testNodeValidationFailedEvent.
/**
*/
@Test
public void testNodeValidationFailedEvent() throws Exception {
startGrid(0);
CountDownLatch evtLatch = new CountDownLatch(1);
AtomicReference<Event> listenedEvtRef = new AtomicReference<>();
grid(0).events().localListen(evt -> {
assertTrue(listenedEvtRef.compareAndSet(null, evt));
evtLatch.countDown();
return true;
}, EVT_NODE_VALIDATION_FAILED);
startGrid(1);
String invalidNodeName = getTestIgniteInstanceName(2);
IgniteConfiguration invalidCfg = getConfiguration(invalidNodeName).setPluginProviders(new TestSecurityPluginProvider("login", "", ALLOW_ALL, false));
assertThrowsWithCause(() -> startGrid(optimize(invalidCfg)), IgniteSpiException.class);
evtLatch.await();
Event listenedEvt = listenedEvtRef.get();
assertTrue(listenedEvt instanceof NodeValidationFailedEvent);
NodeValidationFailedEvent validationEvt = (NodeValidationFailedEvent) listenedEvt;
assertEquals(invalidNodeName, validationEvt.eventNode().attribute(ATTR_NODE_CONSISTENT_ID));
IgniteNodeValidationResult validationRes = validationEvt.validationResult();
assertNotNull(validationRes);
String errMsg = validationRes.message();
assertNotNull(errMsg);
assertTrue(errMsg.contains("Local node's grid security processor class is not equal to remote node's grid security processor class"));
}
use of org.apache.ignite.spi.IgniteNodeValidationResult in project ignite by apache.
the class ZookeeperDiscoveryImpl method validateJoiningNode.
/**
* @param joiningNodeData Joining node data.
* @return Validation result.
*/
private ZkNodeValidateResult validateJoiningNode(ZkJoiningNodeData joiningNodeData) {
ZookeeperClusterNode node = joiningNodeData.node();
ZookeeperClusterNode node0 = rtState.top.nodesById.get(node.id());
if (node0 != null) {
U.error(log, "Failed to include node in cluster, node with the same ID already exists [joiningNode=" + node + ", existingNode=" + node0 + ']');
// Note: exception message is checked in tests.
return new ZkNodeValidateResult("Node with the same ID already exists: " + node0);
}
ZkNodeValidateResult res = authenticateNode(node);
if (res.err != null)
return res;
IgniteNodeValidationResult err = spi.getSpiContext().validateNode(node);
if (err == null) {
DiscoveryDataBag joiningNodeBag = new DiscoveryDataBag(node.id(), joiningNodeData.node().isClient());
joiningNodeBag.joiningNodeData(joiningNodeData.discoveryData());
err = spi.getSpiContext().validateNode(node, joiningNodeBag);
}
if (err != null) {
spi.getSpiContext().recordEvent(new NodeValidationFailedEvent(locNode, node, err));
LT.warn(log, err.message());
res.err = err.sendMessage();
}
return res;
}
use of org.apache.ignite.spi.IgniteNodeValidationResult in project ignite by apache.
the class GridCacheProcessor method validateHashIdResolvers.
/**
* @param node Joining node.
* @return Validation result or {@code null} in case of success.
*/
@Nullable
private IgniteNodeValidationResult validateHashIdResolvers(ClusterNode node) {
if (!node.isClient()) {
for (DynamicCacheDescriptor desc : cacheDescriptors().values()) {
CacheConfiguration cfg = desc.cacheConfiguration();
if (cfg.getAffinity() instanceof RendezvousAffinityFunction) {
RendezvousAffinityFunction aff = (RendezvousAffinityFunction) cfg.getAffinity();
Object nodeHashObj = aff.resolveNodeHash(node);
for (ClusterNode topNode : ctx.discovery().allNodes()) {
Object topNodeHashObj = aff.resolveNodeHash(topNode);
if (nodeHashObj.hashCode() == topNodeHashObj.hashCode()) {
String errMsg = "Failed to add node to topology because it has the same hash code for " + "partitioned affinity as one of existing nodes [cacheName=" + cfg.getName() + ", existingNodeId=" + topNode.id() + ']';
String sndMsg = "Failed to add node to topology because it has the same hash code for " + "partitioned affinity as one of existing nodes [cacheName=" + cfg.getName() + ", existingNodeId=" + topNode.id() + ']';
return new IgniteNodeValidationResult(topNode.id(), errMsg, sndMsg);
}
}
}
}
}
return null;
}
Aggregations