All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.kv.impl.admin.VerifyConfiguration Maven / Gradle / Ivy

Go to download

NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.

The newest version!
/*-
 * Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle NoSQL
 * Database made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle NoSQL Database for a copy of the license and
 * additional information.
 */

package oracle.kv.impl.admin;

import static oracle.kv.impl.param.ParameterState.ADMIN_TYPE;
import static oracle.kv.impl.param.ParameterState.ARBNODE_TYPE;
import static oracle.kv.impl.param.ParameterState.REPNODE_TYPE;
import static oracle.kv.impl.util.JsonUtils.createObjectNode;
import static oracle.kv.impl.util.JsonUtils.getArray;
import static oracle.kv.impl.util.JsonUtils.getAsText;
import static oracle.kv.impl.util.ObjectUtil.checkNull;

import java.io.IOException;
import java.io.Serializable;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import oracle.kv.KVVersion;
import oracle.kv.impl.admin.CommandResult.CommandFails;
import oracle.kv.impl.admin.CommandResult.CommandSucceeds;
import oracle.kv.impl.admin.TopologyCheck.CONFIG_STATUS;
import oracle.kv.impl.admin.TopologyCheck.CreateRNRemedy;
import oracle.kv.impl.admin.TopologyCheck.RNLocationInput;
import oracle.kv.impl.admin.TopologyCheck.Remedy;
import oracle.kv.impl.admin.TopologyCheck.RemoveRNRemedy;
import oracle.kv.impl.admin.TopologyCheck.TOPO_STATUS;
import oracle.kv.impl.admin.TopologyCheck.UpdateANParamsRemedy;
import oracle.kv.impl.admin.TopologyCheck.UpdateAdminParamsRemedy;
import oracle.kv.impl.admin.TopologyCheck.UpdateRNParamsRemedy;
import oracle.kv.impl.admin.TopologyCheckUtils.SNServices;
import oracle.kv.impl.admin.param.GroupNodeParams;
import oracle.kv.impl.admin.param.Parameters;
import oracle.kv.impl.admin.param.RepNodeParams;
import oracle.kv.impl.admin.topo.Rules;
import oracle.kv.impl.admin.topo.Rules.Results;
import oracle.kv.impl.admin.topo.Validations.RulesProblem;
import oracle.kv.impl.arb.ArbNodeStatus;
import oracle.kv.impl.arb.admin.ArbNodeAdminAPI;
import oracle.kv.impl.arb.admin.ArbNodeAdminFaultException;
import oracle.kv.impl.fault.CommandFaultException;
import oracle.kv.impl.param.LoadParameters;
import oracle.kv.impl.param.Parameter;
import oracle.kv.impl.param.ParameterMap;
import oracle.kv.impl.param.ParameterState;
import oracle.kv.impl.param.SizeParameter;
import oracle.kv.impl.rep.RepNodeStatus;
import oracle.kv.impl.rep.RequestTypeUpdater.RequestType;
import oracle.kv.impl.rep.admin.IllegalRepNodeServiceStateException;
import oracle.kv.impl.rep.admin.RepNodeAdminAPI;
import oracle.kv.impl.rep.admin.RepNodeAdminFaultException;
import oracle.kv.impl.security.login.LoginManager;
import oracle.kv.impl.sna.StorageNodeAgentAPI;
import oracle.kv.impl.sna.StorageNodeInfo;
import oracle.kv.impl.sna.StorageNodeStatus;
import oracle.kv.impl.topo.AdminId;
import oracle.kv.impl.topo.ArbNode;
import oracle.kv.impl.topo.ArbNodeId;
import oracle.kv.impl.topo.Datacenter;
import oracle.kv.impl.topo.RepGroup;
import oracle.kv.impl.topo.RepGroupId;
import oracle.kv.impl.topo.RepNode;
import oracle.kv.impl.topo.RepNodeId;
import oracle.kv.impl.topo.ResourceId;
import oracle.kv.impl.topo.ResourceId.ResourceType;
import oracle.kv.impl.topo.StorageNodeId;
import oracle.kv.impl.topo.Topology;
import oracle.kv.impl.util.ConfigurableService.ServiceStatus;
import oracle.kv.impl.util.ObjectUtil;
import oracle.kv.impl.util.TopologyPrinter;
import oracle.kv.impl.util.VersionUtil;
import oracle.kv.impl.util.registry.RegistryUtils;
import oracle.kv.util.ErrorMessage;
import oracle.kv.util.Ping;
import oracle.kv.util.Ping.AdminStatusFunction;
import oracle.kv.util.Ping.ArbNodeStatusFunction;
import oracle.kv.util.Ping.RepNodeStatusFunction;
import oracle.kv.util.PingDisplay;

import com.sleepycat.je.rep.ReplicatedEnvironment.State;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;

/**
 * Object encapsulating various verification methods.
 *
 * 

Here is an annotated example of the output of the 'verify configuration' * command in JSON format. See the {@link Ping} class for information about * fields in common with the output of the ping command, and the * {@link CommandJsonUtils} class for information about fields that are pertain * to results and are derived from the CommandJsonUtils class. * *

 * {
 *   // These command result fields are common to all CLI commands
 *   "operation" : "configure",
 *   "return_code" : 5300,
 *   "description" : "Deploy failed: ConnectionIOException ......" ,
 *   "cmd_cleanup_job" : [ "plan repair-topology" ]
 *   // These fields are all the same as for Ping
 *   "topology" : ...,
 *   "shardStatus" : ...,
 *   "adminStatus" : ...,
 *   "zoneStatus" : ...,
 *   "snStatus" : ...,
 *
 *   "storewideLogName" : "localhost:/kvroot/mystore/log/mystore_{0..N}.log",
 *   "violations" : [ {
 *     "resourceId" : "admin2",
 *     "description" : "ping() failed for admin2 : [...]"
 *   }, {
 *     "resourceId" : "rg1-rn2",
 *     "description" : "ping() failed for rg1-rn2 : [...]"
 *   } ],
 *   // Warnings in same format as violations, if any
 *   "warnings" : [ ]
 * }
 * 
*/ public class VerifyConfiguration { private static final String eol = System.getProperty("line.separator"); private static final Comparator resourceComparator = new Comparator() { @Override public int compare(Problem p1, Problem p2) { return p1.getResourceId().toString().compareTo( p2.getResourceId().toString()); } }; private final Admin admin; private final boolean listAll; private final boolean showProgress; private final boolean json; private final Logger logger; private final TopologyCheck topoChecker; /* Collect output in JSON format. */ private final ObjectNode jsonTop; /* * Found violations are stored here. The collection of violations is cleared * each time verify is run. */ private final List violations; /* * Issues that are only advisory, and are not true violations. */ private final List warnings; /* * Violations that have suggested remedies that can be carried out by * the topology checker. */ private final Remedies remedies; /* * Available disk storage threshold below which we will display * verification notes. */ private static final long AVAILABLE_DISK_STORAGE_THRESHOLD = 5L * 1024L * 1024L * 1024L; private volatile VerifyType verifyType; enum VerifyType { TOPOLOGY, UPGRADE, PREREQUISITE; @Override public String toString() { return name().toLowerCase(); } } /** * Construct a verification object. * * @param admin the admin node * @param showProgress if true, log a line before checking each storage * node and its resident services. * @param listAll if true, list information for all services checked. * @param json if true, produce output in JSON format, otherwise in a * human-readable format * @param logger output is issued via this logger. */ public VerifyConfiguration(Admin admin, boolean showProgress, boolean listAll, boolean json, Logger logger) { this.admin = admin; this.showProgress = showProgress; this.listAll = listAll; this.json = json; this.logger = logger; violations = new ArrayList<>(); warnings = new ArrayList<>(); jsonTop = createObjectNode(); remedies = new Remedies(); topoChecker = new TopologyCheck("VerifyConfiguration", logger, admin.getCurrentTopology(), admin.getCurrentParameters()); } /** * Check whether the current topology obeys layout rules, and that the * store matches the layout, software version, and parameters described by * the most current topology and parameters. The verifyTopology() method * may be called multiple times in the life of a VerifyConfiguration * instance, but should be called serially. * * @return true if no violations were found. */ public boolean verifyTopology() { return verifyTopology(admin.getCurrentTopology(), admin.getLoginManager(), admin.getCurrentParameters(), true); } /** * Checks that the nodes in the store have been upgraded to the target * version. * * @param targetVersion * @return true if all nodes are up to date */ public boolean verifyUpgrade(KVVersion targetVersion, List snIds) { admin.getLogger().log(Level.INFO, "Verifying upgrade to target version: {0}", targetVersion.getNumericVersionString()); clear(); verifyType = VerifyType.UPGRADE; final Topology topology = admin.getCurrentTopology(); PingDisplay.topologyOverviewToJson(topology, null, jsonTop); storewideLogNameToJson(admin, jsonTop); final RegistryUtils registryUtils = new RegistryUtils(topology, admin.getLoginManager()); if (snIds == null) { snIds = topology.getSortedStorageNodeIds(); } final ArrayNode jsonSNs = listAll ? jsonTop.putArray("snStatus") : null; for (StorageNodeId snId : snIds) { verifySNUpgrade(snId, targetVersion, registryUtils, topology, jsonSNs); } problemsToJson(); VerifyResults vResults = getResults(); logger.log(Level.INFO, "{0}", vResults.display()); return vResults.okay(); } private void clear() { violations.clear(); warnings.clear(); remedies.clear(); jsonTop.removeAll(); verifyType = null; } private static void storewideLogNameToJson(Admin admin, ObjectNode jsonTop) { jsonTop.put("storewideLogName", admin.getStorewideLogName()); } private static String displayStorewideLogName(JsonNode jsonTop) { final String logName = getAsText(jsonTop, "storewideLogName"); if (logName == null) { return ""; } return "See " + logName + " for progress messages"; } private void problemsToJson() { problemsToJson(jsonTop, violations, "violations"); problemsToJson(jsonTop, warnings, "warnings"); } public static void problemsToJson(ObjectNode jsonTopNode, List problems, String field) { Collections.sort(problems, resourceComparator); final ArrayNode jsonProblems = jsonTopNode.putArray(field); for (Problem problem : problems) { jsonProblems.add(problemToJson(problem)); } } private static ObjectNode problemToJson(Problem problem) { final ObjectNode on = createObjectNode(); on.put("resourceId", problem.getResourceId().toString()); on.put("description", problem.toString()); return on; } private static String displayProblem(JsonNode node) { return "[" + getAsText(node, "resourceId", "?") + "]\t" + getAsText(node, "description", ""); } private void verifySNUpgrade(StorageNodeId snId, KVVersion targetVersion, RegistryUtils registryUtils, Topology topology, ArrayNode jsonSNs) { StorageNodeStatus snStatus = null; try { snStatus = registryUtils.getStorageNodeAgent(snId).ping(); } catch (RemoteException re) { violations.add(new RMIFailed(snId, re, "ping()", showProgress, logger)); } catch (NotBoundException nbe) { violations.add(new RMIFailed(snId, nbe, showProgress, logger)); } if (snStatus != null) { final KVVersion snVersion = snStatus.getKVVersion(); if (snVersion.compareTo(targetVersion) < 0) { warnings.add(new UpgradeNeeded(snId, snVersion, targetVersion, showProgress, logger)); } else { /* SN is at or above target. Make sure RNs/ANs are up-to-date */ verifyRNUpgrade(snVersion, topology.getHostedRepNodeIds(snId), registryUtils); verifyANUpgrade(snVersion, topology.getHostedArbNodeIds(snId), registryUtils); } } if (listAll) { final ObjectNode jsonSN = PingDisplay.storageNodeToJson( topology, topology.get(snId), snStatus); logger.info("Verify upgrade: " + PingDisplay.displayStorageNode(jsonSN)); jsonSNs.add(jsonSN); } } private void verifyRNUpgrade(KVVersion snVersion, Set hostedRepNodeIds, RegistryUtils registryUtils) { ServiceStatus rnStatus = null; for (RepNodeId rnId : hostedRepNodeIds) { try { final RepNodeAdminAPI rn = registryUtils.getRepNodeAdmin(rnId); rnStatus = rn.ping().getServiceStatus(); final KVVersion rnVersion = rn.getInfo().getSoftwareVersion(); if (rnVersion.compareTo(snVersion) != 0) { warnings.add(new UpgradeNeeded(rnId, rnVersion, snVersion, showProgress, logger)); } } catch (RemoteException re) { violations.add(new RMIFailed(rnId, re, "ping()", showProgress, logger)); } catch (NotBoundException nbe) { violations.add(new RMIFailed(rnId, nbe, showProgress, logger)); } catch (RepNodeAdminFaultException rnafe) { if (rnafe.getFaultClassName().equals( IllegalRepNodeServiceStateException.class.getName())) { violations.add( new StatusNotRight(rnId, ServiceStatus.RUNNING, rnStatus, showProgress, logger)); } else { throw rnafe; } } } } private void verifyANUpgrade(KVVersion snVersion, Set hostedArbNodeIds, RegistryUtils registryUtils) { ServiceStatus anStatus = null; for (ArbNodeId anId : hostedArbNodeIds) { try { final ArbNodeAdminAPI ana = registryUtils.getArbNodeAdmin(anId); anStatus = ana.ping().getServiceStatus(); final KVVersion anVersion = ana.getInfo().getSoftwareVersion(); if (anVersion.compareTo(snVersion) != 0) { warnings.add(new UpgradeNeeded(anId, anVersion, snVersion, showProgress, logger)); } } catch (RemoteException re) { violations.add(new RMIFailed(anId, re, "ping()", showProgress, logger)); } catch (NotBoundException nbe) { violations.add(new RMIFailed(anId, nbe, showProgress, logger)); } catch (ArbNodeAdminFaultException anafe) { if (anafe.getFaultClassName().equals( IllegalRepNodeServiceStateException.class.getName())) { violations.add( new StatusNotRight(anId, ServiceStatus.RUNNING, anStatus, showProgress, logger)); } else { throw anafe; } } } } /** * Checks that the nodes in the store meet the specified prerequisite * version in order to be upgraded to the target version. * * @param targetVersion * @param prerequisiteVersion * @return true if no violations were found */ public boolean verifyPrerequisite(KVVersion targetVersion, KVVersion prerequisiteVersion, List snIds) { admin.getLogger().log(Level.INFO, "Checking upgrade to target version: {0}, " + "prerequisite: {1}", new Object[]{targetVersion.getNumericVersionString(), prerequisiteVersion.getNumericVersionString()}); clear(); verifyType = VerifyType.PREREQUISITE; final Topology topology = admin.getCurrentTopology(); PingDisplay.topologyOverviewToJson(topology, null, jsonTop); storewideLogNameToJson(admin, jsonTop); final RegistryUtils registryUtils = new RegistryUtils(topology, admin.getLoginManager()); if (snIds == null) { snIds = topology.getSortedStorageNodeIds(); } final ArrayNode jsonSNs = listAll ? jsonTop.putArray("snStatus") : null; for (StorageNodeId snId : snIds) { verifySNPrerequisite(snId, targetVersion, prerequisiteVersion, registryUtils, topology, jsonSNs); } problemsToJson(); VerifyResults vResults = getResults(); logger.log(Level.INFO, "{0}", vResults.display()); return vResults.okay(); } private void verifySNPrerequisite(StorageNodeId snId, KVVersion targetVersion, KVVersion prerequisiteVersion, RegistryUtils registryUtils, Topology topology, ArrayNode jsonSNs) { StorageNodeStatus snStatus = null; try { final StorageNodeAgentAPI sna = registryUtils.getStorageNodeAgent(snId); snStatus = sna.ping(); } catch (RemoteException re) { violations.add(new RMIFailed(snId, re, "ping()", showProgress, logger)); } catch (NotBoundException nbe) { violations.add(new RMIFailed(snId, nbe, showProgress, logger)); } if (snStatus != null) { final KVVersion snVersion = snStatus.getKVVersion(); /* Check if the SN is too old (doesn't meet prereq) */ if (snVersion.compareTo(prerequisiteVersion) < 0) { violations.add(new UpgradeNeeded(snId, snVersion, prerequisiteVersion, showProgress, logger)); /* * Meets prereq, so check if the SN is too new (downgrade across * minor version) */ } else if (VersionUtil.compareMinorVersion(snVersion, targetVersion) > 0) { violations.add(new BadDowngrade(snId, snVersion, prerequisiteVersion, showProgress, logger)); } } if (listAll) { final ObjectNode jsonSN = PingDisplay.storageNodeToJson(topology, topology.get(snId), snStatus); logger.info("Verify prerequisite: " + PingDisplay.displayStorageNode(jsonSN)); jsonSNs.add(jsonSN); } } /** * Non-private entry point for unit tests. Provides a way to supply an * intentionally corrupt topology or parameters, to test for error cases. */ synchronized boolean verifyTopology(Topology topology, LoginManager loginMgr, Parameters currentParams, boolean topoIsDeployed) { clear(); verifyType = VerifyType.TOPOLOGY; PingDisplay.topologyOverviewToJson(topology, null, jsonTop); logger.info(PingDisplay.displayTopologyOverview(jsonTop)); storewideLogNameToJson(admin, jsonTop); RegistryUtils registryUtils = new RegistryUtils(topology, loginMgr); Results results = Rules.validate(topology, currentParams, topoIsDeployed); violations.addAll(results.getViolations()); warnings.addAll(results.getWarnings()); /* Add any remedies that were generated during the validate phase */ for (RulesProblem rp : results.getViolations()) { final Remedy remedy = rp.getRemedy(topoChecker); if (remedy != null) { remedies.add(remedy); } } checkServices(topology, currentParams, registryUtils); problemsToJson(); VerifyResults vResults = getResults(); logger.log(Level.INFO, "{0}", vResults.display()); return vResults.okay(); } /** Common information for both RNs and ANs. */ private static abstract class BasicNodeInfo { abstract State getState(); abstract ServiceStatus getStatus(); } /** Store ping and getParams results for an RN. */ private static class RepNodeInfo extends BasicNodeInfo { RepNodeStatus pingStatus; RemoteException pingRemoteException; NotBoundException pingNotBoundException; LoadParameters getParamsResult; RemoteException getParamsRemoteException; @Override State getState() { return (pingStatus != null) ? pingStatus.getReplicationState() : null; } @Override ServiceStatus getStatus() { return (pingStatus != null) ? pingStatus.getServiceStatus() : null; } } /** Store ping and getParams results for an AN. */ private static class ArbNodeInfo extends BasicNodeInfo { ArbNodeStatus pingStatus; RemoteException pingRemoteException; NotBoundException pingNotBoundException; LoadParameters getParamsResult; RemoteException getParamsRemoteException; @Override State getState() { return (pingStatus != null) ? pingStatus.getArbiterState() : null; } @Override ServiceStatus getStatus() { return (pingStatus != null) ? pingStatus.getServiceStatus() : null; } } /** * For each SN in the store, contact each service, conduct check. */ /* Suppress Eclipse warning for jsonSNs.add call */ @SuppressWarnings("null") private void checkServices(Topology topology, Parameters currentParams, RegistryUtils registryUtils) { /* Collect RN ping and getParams results, and master status info */ final Map rnInfoMap = new HashMap<>(); final Map anInfoMap = new HashMap<>(); final Map masterStatusMap = new HashMap<>(); rnPingAndGetParams( topology, registryUtils, rnInfoMap, masterStatusMap); anPingAndGetParams(topology, registryUtils, anInfoMap); /* Use rnInfoMap to provide RepNodeStatus values */ final RepNodeStatusFunction rnfunc = new RepNodeStatusFunction() { @Override public RepNodeStatus get(RepNode node) { final RepNodeInfo info = rnInfoMap.get(node.getResourceId()); if (info.pingStatus != null) { return info.pingStatus; } return null; } }; /* Use anInfoMap to provide ArbNodeStatus values */ final ArbNodeStatusFunction anfunc = new ArbNodeStatusFunction() { @Override public ArbNodeStatus get(ArbNode node) { final ArbNodeInfo info = anInfoMap.get(node.getResourceId()); if (info.pingStatus != null) { return info.pingStatus; } return null; } }; PingDisplay.shardOverviewToJson(topology, rnfunc, anfunc, null, jsonTop); final Map allAdminInfo = collectAdminInfo(currentParams, registryUtils); final AdminStatusFunction adminStatusFunc = new AdminStatusFunction() { @Override public AdminStatus get(AdminId adminId) { final AdminInfo adminInfo = allAdminInfo.get(adminId); return (adminInfo != null) ? adminInfo.adminStatus : null; } }; PingDisplay.adminOverviewToJson(currentParams, adminStatusFunc, jsonTop); final ArrayNode jsonZones = jsonTop.putArray("zoneStatus"); for (final Datacenter dc : topology.getSortedDatacenters()) { jsonZones.add( PingDisplay.zoneOverviewToJson(topology, dc, rnfunc, anfunc, null)); } Map sortedResources = TopologyCheckUtils.groupServicesBySN(topology, currentParams); final ArrayNode jsonSNs = listAll ? jsonTop.putArray("snStatus") : null; /* The check is done in SN order */ for (SNServices nodeInfo : sortedResources.values()) { StorageNodeId snId = nodeInfo.getStorageNodeId(); /* If show progress is set, log per Storage Node. */ if (showProgress) { String msg = "Verify: == checking storage node " + snId + " =="; logger.info(msg); } /* Check the StorageNodeAgent on this node. */ final ObjectNode jsonSN = checkStorageNode( registryUtils, topology, currentParams, snId, nodeInfo, rnInfoMap, anInfoMap); if (listAll) { jsonSNs.add(jsonSN); } /* If the Admin is there, check it. */ AdminId adminId = nodeInfo.getAdminId(); if (adminId != null) { checkAdmin(currentParams, adminId, allAdminInfo.get(adminId), jsonSN); } /* Check all RepNodes on this storage node. */ final ArrayNode jsonRNs = listAll ? jsonSN.putArray("rnStatus") : null; for (RepNodeId rnId : nodeInfo.getAllRepNodeIds()) { checkRepNode(topology, snId, rnId, currentParams, rnInfoMap.get(rnId), masterStatusMap.get( new RepGroupId(rnId.getGroupId())), jsonRNs); } /* Check all ArbNodes on this storage node. */ final ArrayNode jsonANs = listAll ? jsonSN.putArray("anStatus") : null; for (ArbNodeId anId : nodeInfo.getAllARBs()) { checkArbNode(topology, snId, anId, currentParams, anInfoMap.get(anId), jsonANs); } } } /* Suppress Eclipse warning for rna.getParams call */ @SuppressWarnings("null") private static void rnPingAndGetParams( Topology topology, RegistryUtils registryUtils, Map rnInfoMap, Map masterStatusMap) { for (final RepGroup rg : topology.getRepGroupMap().getAll()) { for (final RepNode rn : rg.getRepNodes()) { final RepNodeId rnId = rn.getResourceId(); RepNodeAdminAPI rna = null; final RepNodeInfo rnInfo = new RepNodeInfo(); try { rna = registryUtils.getRepNodeAdmin(rnId); rnInfo.pingStatus = rna.ping(); } catch (RemoteException re) { rnInfo.pingRemoteException = re; } catch (NotBoundException e) { rnInfo.pingNotBoundException = e; } if (rnInfo.pingStatus != null) { if (rnInfo.pingStatus.getReplicationState().isMaster()) { masterStatusMap.put(new RepGroupId(rnId.getGroupId()), rnInfo.pingStatus); } if (ServiceStatus.RUNNING.equals( rnInfo.pingStatus.getServiceStatus())) { try { rnInfo.getParamsResult = rna.getParams(); } catch (RemoteException re) { rnInfo.getParamsRemoteException = re; } } } rnInfoMap.put(rn.getResourceId(), rnInfo); } } } /* Suppress Eclipse warning for ana.getParams call */ @SuppressWarnings("null") private static void anPingAndGetParams( Topology topology, RegistryUtils registryUtils, Map anInfoMap) { for (final RepGroup rg : topology.getRepGroupMap().getAll()) { for (final ArbNode an : rg.getArbNodes()) { final ArbNodeId anId = an.getResourceId(); ArbNodeAdminAPI ana = null; final ArbNodeInfo anInfo = new ArbNodeInfo(); try { ana = registryUtils.getArbNodeAdmin(anId); anInfo.pingStatus = ana.ping(); } catch (RemoteException re) { anInfo.pingRemoteException = re; } catch (NotBoundException e) { anInfo.pingNotBoundException = e; } if (anInfo.pingStatus != null) { if (ServiceStatus.RUNNING.equals( anInfo.pingStatus.getServiceStatus())) { try { anInfo.getParamsResult = ana.getParams(); } catch (RemoteException re) { anInfo.getParamsRemoteException = re; } } } anInfoMap.put(an.getResourceId(), anInfo); } } } /** Store getAdminStatus results for an Admin. */ private static class AdminInfo { CommandServiceAPI cs; AdminStatus adminStatus; RemoteException remoteException; NotBoundException notBoundException; } private static Map collectAdminInfo( Parameters params, RegistryUtils regUtils) { final Map allAdminInfo = new HashMap<>(); for (final AdminId adminId : params.getAdminIds()) { final StorageNodeId snId = params.get(adminId).getStorageNodeId(); final AdminInfo adminInfo = new AdminInfo(); try { final CommandServiceAPI cs = regUtils.getAdmin(snId); adminInfo.cs = cs; adminInfo.adminStatus = cs.getAdminStatus(); } catch (RemoteException e) { adminInfo.remoteException = e; } catch (NotBoundException e) { adminInfo.notBoundException = e; } allAdminInfo.put(adminId, adminInfo); } return allAdminInfo; } /** * Ping this admin and check its params. */ private void checkAdmin(Parameters params, AdminId aId, AdminInfo adminInfo, ObjectNode jsonSN) { StorageNodeId hostSN = params.get(aId).getStorageNodeId(); boolean pingProblem = false; CommandServiceAPI cs = null; AdminStatus adminStatus = null; ServiceStatus status = ServiceStatus.UNREACHABLE; if (adminInfo.adminStatus != null) { cs = adminInfo.cs; adminStatus = adminInfo.adminStatus; status = adminStatus.getServiceStatus(); } else if (adminInfo.remoteException != null) { final RemoteException re = adminInfo.remoteException; violations.add(new RMIFailed(aId, re, "ping()",showProgress, logger)); pingProblem = true; } else { final NotBoundException e = adminInfo.notBoundException; violations.add(new RMIFailed(aId, e, showProgress, logger)); pingProblem = true; } /* * Check the JE HA metadata and SN remote config against the AdminDB * for this admin. */ Remedy remedy = topoChecker.checkAdminLocation(admin, aId); if (remedy.canFix()) { remedies.add(remedy); } if (!pingProblem) { if (status.equals(ServiceStatus.RUNNING)) { checkAdminParams(cs, params, aId, hostSN); } else { violations.add(new StatusNotRight(aId, ServiceStatus.RUNNING, status, showProgress, logger)); } } if (listAll) { final ObjectNode jsonAdmin = PingDisplay.adminToJson(aId, adminStatus); logger.info("Verify: " + PingDisplay.displayAdmin(jsonAdmin)); jsonSN.put("adminStatus", jsonAdmin); } } /** * Ping the storage node. If it does not respond, add it to the problem * list. If the version doesn't match that of the admin, also add that to * the list. */ @SuppressWarnings("null") private ObjectNode checkStorageNode(RegistryUtils regUtils, Topology topology, Parameters currentParams, StorageNodeId snId, SNServices nodeInfo, Map rnInfoMap, Map anInfoMap) { boolean pingProblem = false; StorageNodeStatus snStatus = null; StorageNodeAgentAPI sna = null; ServiceStatus status = ServiceStatus.UNREACHABLE; try { sna = regUtils.getStorageNodeAgent(snId); snStatus = sna.ping(); status = snStatus.getServiceStatus(); } catch (RemoteException re) { violations.add(new RMIFailed(snId, re, "ping()", showProgress, logger)); pingProblem = true; } catch (NotBoundException e) { violations.add(new RMIFailed(snId, e, showProgress, logger)); pingProblem = true; } ObjectNode jsonSN = null; if (listAll) { jsonSN = PingDisplay.storageNodeToJson( topology, topology.get(snId), snStatus); logger.info("Verify: " + PingDisplay.displayStorageNode(jsonSN)); } if (!pingProblem) { if (status.equals(ServiceStatus.RUNNING)) { checkSNParams(sna, snId, currentParams, nodeInfo, rnInfoMap, anInfoMap); } else { violations.add(new StatusNotRight(snId, ServiceStatus.RUNNING, status, showProgress, logger)); } if (!KVVersion.CURRENT_VERSION.equals(snStatus.getKVVersion())) { violations.add(new VersionDifference(snId, snStatus.getKVVersion(), showProgress, logger)); } final KVVersion storeVersion = getVersion( currentParams.getGlobalParams().getMap().get( ParameterState.GP_STORE_VERSION).asString()); if (storeVersion != null && storeVersion.compareTo(snStatus.getKVVersion()) > 0) { violations.add(new StoreVersionHigher(snId, storeVersion, snStatus.getKVVersion(), showProgress, logger)); } } return jsonSN; } /** * Check ping and getParams results for this repNode. */ private void checkRepNode(Topology topology, StorageNodeId snId, RepNodeId rnId, Parameters currentParams, RepNodeInfo rnInfo, RepNodeStatus masterStatus, ArrayNode jsonRNs) { boolean pingProblem = false; ServiceStatus status = ServiceStatus.UNREACHABLE; RepNodeStatus rnStatus = null; boolean isDisabled = currentParams.get(rnId).isDisabled(); ServiceStatus expected = isDisabled ? ServiceStatus.UNREACHABLE : ServiceStatus.RUNNING; if (rnInfo.pingStatus != null) { rnStatus = rnInfo.pingStatus; status = rnStatus.getServiceStatus(); } else if (rnInfo.pingRemoteException != null) { final RemoteException re = rnInfo.pingRemoteException; if (!expected.equals(ServiceStatus.UNREACHABLE)) { violations.add(new RMIFailed(rnId, re, "ping()", showProgress, logger)); pingProblem = true; } else { /* The RN is configured as being disabled, issue a warning */ reportStopped(rnId, snId); } } else { final NotBoundException e = rnInfo.pingNotBoundException; if (!expected.equals(ServiceStatus.UNREACHABLE)) { violations.add(new RMIFailed(rnId, e, showProgress, logger)); pingProblem = true; } else { /* The RN is configured as being disabled, issue a warning */ reportStopped(rnId, snId); } } if (!pingProblem) { if (status.equals(expected)) { if (status.equals(ServiceStatus.RUNNING)) { checkRNParams(rnId, topology, currentParams, rnInfo); } } else { violations.add(new StatusNotRight(rnId, expected, status, showProgress, logger)); } } if (rnStatus != null) { final String enabledRequestType = rnStatus.getEnabledRequestType(); if (!enabledRequestType.equalsIgnoreCase(RequestType.ALL.name())) { violations.add(new RequestsDisabled(rnId, enabledRequestType, showProgress, logger)); } final RepNodeParams repNodeParams = currentParams.get(rnId); /* * If storagedir is not specified then staticDirSize will be * 0L. RNs are part of rootdir in that case. We will just add * available and used storage size for getting approx static * Storage Size. */ long staticStorageSize = repNodeParams.getStorageDirectorySize(); final long availableStorageSize = rnStatus.getAvailableLogSize(); final long usedStorageSize = rnStatus.getUsedLogSize(); if (staticStorageSize == 0L) { staticStorageSize = usedStorageSize + availableStorageSize; } final String staticSizeInUnits = TopologyPrinter.getSizeInUnits(staticStorageSize); final String usedSizeInUnits = TopologyPrinter.getSizeInUnits(usedStorageSize); final String storageDirPath = repNodeParams.getStorageDirectoryPath(); final boolean isEnvironmentStatsAvailable = rnStatus.isEnvironmentStatsAvailable(); /* * Raise disk exceed and low violations/warnings only if * statistics are available */ if (isEnvironmentStatsAvailable) { if (availableStorageSize <= 0) { violations.add(new AvailableStorageExceeded( rnId, storageDirPath, staticSizeInUnits, usedSizeInUnits, showProgress, logger)); } else if (availableStorageSize <= AVAILABLE_DISK_STORAGE_THRESHOLD) { warnings.add(new AvailableStorageLow( rnId, storageDirPath, staticSizeInUnits, usedSizeInUnits, showProgress, logger)); } } } if (listAll) { final ObjectNode jsonRN = PingDisplay.repNodeToJson( topology.get(rnId), rnStatus, masterStatus, expected); logger.info("Verify: " + PingDisplay.displayRepNode(jsonRN)); jsonRNs.add(jsonRN); } } /** * Check ping and getParams results for this arbNode. */ private void checkArbNode(Topology topology, StorageNodeId snId, ArbNodeId anId, Parameters currentParams, ArbNodeInfo anInfo, ArrayNode jsonANs) { boolean pingProblem = false; ServiceStatus status = ServiceStatus.UNREACHABLE; ArbNodeStatus anStatus = null; boolean isDisabled = currentParams.get(anId).isDisabled(); ServiceStatus expected = isDisabled ? ServiceStatus.UNREACHABLE : ServiceStatus.RUNNING; if (anInfo.pingStatus != null) { anStatus = anInfo.pingStatus; status = anStatus.getServiceStatus(); } else if (anInfo.pingRemoteException != null) { final RemoteException re = anInfo.pingRemoteException; if (!expected.equals(ServiceStatus.UNREACHABLE)) { violations.add(new RMIFailed(anId, re, "ping()", showProgress, logger)); pingProblem = true; } else { /* The AN is configured as being disabled, issue a warning */ reportStopped(anId, snId); } } else { final NotBoundException e = anInfo.pingNotBoundException; if (!expected.equals(ServiceStatus.UNREACHABLE)) { violations.add(new RMIFailed(anId, e, showProgress, logger)); pingProblem = true; } else { /* The AN is configured as being disabled, issue a warning */ reportStopped(anId, snId); } } if (!pingProblem) { if (status.equals(expected)) { if (status.equals(ServiceStatus.RUNNING)) { checkANParams(anId, topology, currentParams, anInfo); } } else { violations.add(new StatusNotRight(anId, expected, status, showProgress, logger)); } } if (listAll) { final ObjectNode jsonAN = PingDisplay.arbNodeToJson( topology.get(anId), anStatus, expected); logger.info("Verify: " + PingDisplay.displayArbNode(jsonAN)); jsonANs.add(jsonAN); } } /** * Report that a RN or AN is not up. */ private void reportStopped(ResourceId resId, StorageNodeId snId) { warnings.add(new ServiceStopped(resId, snId, showProgress, logger, true)); /* * If there are no previously detected errors with this RN, and its * location is correct, suggest that it should be restarted. */ final boolean previousRemedy = remedies.remedyExists(resId); if (!previousRemedy) { remedies.add( new CreateRNRemedy(topoChecker, new RNLocationInput(TOPO_STATUS.HERE, CONFIG_STATUS.HERE), snId, resId, null /* jeHAInfo */)); } } /** Check SN configuration parameters against the admin database. */ private void checkSNParams(StorageNodeAgentAPI sna, StorageNodeId snId, Parameters currentParams, SNServices nodeInfo, Map rnInfoMap, Map anInfoMap) { LoadParameters remoteParams; try { remoteParams = sna.getParams(); } catch (RemoteException re) { violations.add(new RMIFailed(snId, re, "getParams", showProgress, logger)); return; } if (!checkParams(snId, remoteParams, currentParams.get(snId).getMap(), ParamMismatchLocation.CONFIG)) { return; } /* Check the SNAs storage directory map if present */ final ParameterMap storageDirMap = currentParams.get(snId).getStorageDirMap(); if (storageDirMap != null) { if (!checkParams(snId, remoteParams, storageDirMap, ParamMismatchLocation.CONFIG)) { return; } } else { if (remoteParams.getMap(ParameterState.BOOTSTRAP_MOUNT_POINTS) != null) { violations.add( new ParamMismatch( snId, "Parameter collection " + ParameterState.BOOTSTRAP_MOUNT_POINTS + " missing " + ParamMismatchLocation.CONFIG.describe(), showProgress, logger)); return; } } /* Check the SNAs RN log directory map if present */ final ParameterMap rnLogDirMap = currentParams.get(snId).getRNLogDirMap(); if (rnLogDirMap != null) { if (!checkParams(snId, remoteParams, rnLogDirMap, ParamMismatchLocation.CONFIG)) { return; } } else { if (remoteParams.getMap (ParameterState.BOOTSTRAP_RNLOG_MOUNT_POINTS) != null) { violations.add( new ParamMismatch( snId, "Parameter collection " + ParameterState.BOOTSTRAP_MOUNT_POINTS + " missing " + ParamMismatchLocation.CONFIG.describe(), showProgress, logger)); return; } } /* Check the SNAs Admin directory map if present */ final ParameterMap adminDirMap = currentParams.get(snId).getAdminDirMap(); if (adminDirMap != null) { if (!checkParams(snId, remoteParams, adminDirMap, ParamMismatchLocation.CONFIG)) { return; } } else { if (remoteParams.getMap (ParameterState.BOOTSTRAP_ADMIN_MOUNT_POINTS) != null) { violations.add( new ParamMismatch( snId, "Parameter collection " + ParameterState.BOOTSTRAP_ADMIN_MOUNT_POINTS + " missing " + ParamMismatchLocation.CONFIG.describe(), showProgress, logger)); return; } } if (!checkParams(snId, remoteParams, currentParams.getGlobalParams().getMap(), ParamMismatchLocation.CONFIG)) { return; } StorageNodeInfo snInfo = null; try { snInfo = sna.getStorageNodeInfo(); } catch (UnsupportedOperationException uoe) /* CHECKSTYLE:OFF */ { /* * UOE indicates that the SN has not yet been upgraded * to a version that supports getStorageNodeInfo(). Ignore * this exception as there will be a separate violation * created to warn about upgrade. */ } /* CHECKSTYLE:ON */ catch (RemoteException re) { violations.add(new RMIFailed(snId, re, "getStorageNodeInfo", showProgress, logger)); } /* * Parameters are OK. If a storage map exist, check the sizes against * the physical system. */ if (storageDirMap != null) { checkSizes(storageDirMap, snId, snInfo); } /* * Parameters are OK. If a RN log dir map exist, check the sizes * against the physical system. */ if (rnLogDirMap != null) { /* * TODO : Commenting this since rnlogdirsize are not * exposed yet. */ //checkSizes(rnLogDirMap, snId, snInfo); } /* * Parameters are OK. If a Admin dir map exist, check the sizes against * the physical system. */ if (adminDirMap != null) { checkSizes(adminDirMap, snId, snInfo); } /* * Make sure all services that are supposed to be on this SN, according * to the topo and params, the SN's config.xml, and the JE HA group * have location info that are all correct. * The RNs to check are the union of those that are in the SN's * config.xml and those in the topology. */ topoChecker.saveSNRemoteParams(snId, remoteParams); Set rnsToCheck = topoChecker.getPossibleRNs(snId); for (RepNodeId rnId: rnsToCheck) { check(snId, rnId, currentParams, remoteParams, rnInfoMap.get(rnId)); } /* * The Admins to check are the union of those that are in the SN's * config.xml and those in AdminDB params. */ ParameterMap adminMap = remoteParams.getMapByType(ParameterState.ADMIN_TYPE); if (adminMap != null) { AdminId aid = new AdminId(adminMap.getOrZeroInt(ParameterState.AP_ID)); if (nodeInfo.getAdminId() == null || !aid.equals(nodeInfo.getAdminId())) { violations.add(new ParamMismatch (snId, "Storage Node is managing admin " + aid + " but the admin does not know this", showProgress, logger)); } else { checkParams(aid, remoteParams, currentParams.get(aid).getMap(), ParamMismatchLocation.CONFIG); } } else if (nodeInfo.getAdminId() != null) { violations.add(new ParamMismatch (snId, "Storage Node is not managing an Admin but " + "the admin believes it is", showProgress, logger)); } Set ansToCheck = topoChecker.getPossibleANs(snId); for (ArbNodeId anId: ansToCheck) { check(snId, anId, currentParams, remoteParams, anInfoMap.get(anId)); } } public void checkSizes(ParameterMap dirMap, StorageNodeId snId, StorageNodeInfo snInfo) { final Map sizes = snInfo.getStorageDirectorySizes(); for (Parameter p : dirMap) { final String directory = p.getName(); final long requiredSize = SizeParameter.getSize(p); final Long reportedSize = sizes.get(directory); if (reportedSize == null) { /* Mount point not defined on SN? */ violations.add(new StorageDirectoryProblem(snId, directory, "directory information not reported", showProgress, logger)); } else if (reportedSize < 0) { /* SN encountered error getting size */ violations.add(new StorageDirectoryProblem(snId, directory, "node encountered error getting " + "directory information, see logs " + "for " + snId, showProgress, logger)); } else if (reportedSize < requiredSize) { /* Directory too small */ violations.add(new StorageDirectoryProblem(snId, directory, "required size: " + requiredSize + ", reported size: " + reportedSize, showProgress, logger)); } } } /** * See if this repNode's params match those held in the admin db. */ private void checkRNParams(RepNodeId rnId, Topology topology, Parameters currentParams, RepNodeInfo rnInfo) { /* Check results of asking the RN for its params */ LoadParameters remoteParams; if (rnInfo.getParamsResult != null) { remoteParams = rnInfo.getParamsResult; } else { final RemoteException re = rnInfo.getParamsRemoteException; violations.add(new RMIFailed(rnId, re, "getParams", showProgress, logger)); return; } checkServiceParams(topology.get(rnId).getStorageNodeId(), rnId, remoteParams, currentParams); } private void check(StorageNodeId snId, ResourceId resId, Parameters currentParams, LoadParameters remoteParams, BasicNodeInfo nodeInfo) { try { final Remedy remedy = topoChecker.checkLocation( admin, snId, resId, false /* calledByDeployNewRN */, false /* makeRNEnabled */, null /* oldSNId */, null /* storageDirectory */); if (remedy.canFix()) { logger.log(Level.INFO, "{0}", new Object[] {remedy}); Problem p; if (remedy instanceof CreateRNRemedy) { if ((nodeInfo != null) && nodeInfo.getStatus() != null && nodeInfo.getStatus().equals(ServiceStatus.RUNNING)) { /* * The CreateRNRemedy indicates that the node is either * not in the SN config or not in the JEHA group. Since * the node is running, this indicates that it is not * in the JEHA group. Could be transient. The * node is in the process of being added to the JEHA * group. */ p = new NotInGroup(resId, snId, showProgress, logger); } else { p = new ServiceStopped(resId, snId, showProgress, logger, false); /* isDisabled */ } } else { p = new ParamMismatch(resId, remedy.problemDescription(), showProgress, logger); } violations.add(p); remedies.add(remedy); } else { /* * If checking the RN location did not provide a fix, but * the RN appears in the current RN parameters, then check * parameters, and let that be what reports problems and * provides fixes. Otherwise, just report the parameter * mismatch. */ final GroupNodeParams currentNodeParams = (resId.getType() == ResourceType.REP_NODE) ? currentParams.get((RepNodeId)resId) : currentParams.get((ArbNodeId)resId); if (currentNodeParams != null) { checkParams(resId, remoteParams, currentNodeParams.getMap(), ParamMismatchLocation.CONFIG); } else { violations.add( new ParamMismatch(resId, remedy.problemDescription(), showProgress, logger)); } } } catch (RemoteException e) { violations.add (new RMIFailed(snId, e, "checkLocation", showProgress, logger)); } catch (NotBoundException e) { violations.add (new RMIFailed(snId, e, showProgress, logger)); } } /** * See if this arbNode's params match those held in the admin db. */ private void checkANParams(ArbNodeId anId, Topology topology, Parameters currentParams, ArbNodeInfo anInfo) { /* Check results of asking the RN for its params */ LoadParameters remoteParams; if (anInfo.getParamsResult != null) { remoteParams = anInfo.getParamsResult; } else { final RemoteException re = anInfo.getParamsRemoteException; violations.add(new RMIFailed(anId, re, "getParams", showProgress, logger)); return; } checkServiceParams(topology.get(anId).getStorageNodeId(), anId, remoteParams, currentParams); } /** * See if this Admin replica's params match those held in the admin db * of the master Admin. */ private void checkAdminParams(CommandServiceAPI cs, Parameters currentParams, AdminId targetAdminId, StorageNodeId hostSN) { final LoadParameters remoteParams; if (admin != null && targetAdminId.equals (admin.getParams().getAdminParams().getAdminId())) { /* * This is the local admin instance -- get the in-memory parameters * directly from the the local admin rather than RMI to allow unit * tests that use the Admin at a lower level than the RMI layer to * run correctly. */ remoteParams = admin.getAllParams(); } else { try { remoteParams = cs.getParams(); } catch (RemoteException re) { violations.add(new RMIFailed(targetAdminId, re, "getParams", showProgress, logger)); return; } } checkServiceParams(hostSN, targetAdminId, remoteParams, currentParams); } /** * Check that the service, SN, and global parameter values for the * in-memory parameters obtained from the specified running service match * the reference parameters from the admin DB. * * @param snId the ID of the SN hosting the service * @param rId the resource ID of the service * @param paramsToCheck service parameters to check * @param referenceParams admin DB parameters to check against * @return whether the parameters match */ private boolean checkServiceParams(StorageNodeId snId, ResourceId rId, LoadParameters paramsToCheck, Parameters referenceParams) { return /* Service parameters */ checkParams(rId, paramsToCheck, referenceParams.getMap(rId), ParamMismatchLocation.MEMORY) && /* Only consider SN parameters related to services */ checkParams(snId, paramsToCheck, referenceParams.get(snId).getMap(), ParamMismatchLocation.MEMORY, SNPCompareParamsFilter.getInstance()) && /* Global parameters */ checkParams(rId, paramsToCheck, referenceParams.getGlobalParams().getMap(), ParamMismatchLocation.MEMORY); } /** * Check if the parameters associated with the specified resource match the * ones in the reference parameters from the admin DB, ignoring * parameters that should typically be skipped in comparisons. * * @param rId the ID of the service * @param paramsToCheck service parameters to check * @param referenceParamMap admin DB parameters to check against * @param location where the parameters to check were found * @return whether the parameters match */ private boolean checkParams(ResourceId rId, LoadParameters paramsToCheck, ParameterMap referenceParamMap, ParamMismatchLocation location) { return checkParams(rId, paramsToCheck, referenceParamMap, location, CompareParamsFilter.getInstance()); } /** * Check if the parameters associated with the specified resource match the * ones in the reference parameters from the admin DB, using the specified * filter to determine which parameters to compare. * * @param rId the ID of the service * @param paramsToCheck service parameters to check * @param referenceParamMap admin DB parameters to check against * @param location where the parameters to check were found * @param filter returns the parameters to compare * @return whether the parameters match */ private boolean checkParams(ResourceId rId, LoadParameters paramsToCheck, ParameterMap referenceParamMap, ParamMismatchLocation location, CompareParamsFilter filter) { switch (compareParams(paramsToCheck, referenceParamMap, filter)) { case NO_DIFFS: return true; case MISSING: violations.add( new ParamMismatch(rId, "Parameter collection " + referenceParamMap.getType() + " missing " + location.describe(), showProgress, logger)); return false; default: violations.add(new ParamMismatch(rId, paramsToCheck.getMapByType( referenceParamMap.getType()), referenceParamMap, location, showProgress, logger)); if (referenceParamMap.getType().equals(ADMIN_TYPE)) { remedies.add(new UpdateAdminParamsRemedy(topoChecker, (AdminId) rId)); } else if (referenceParamMap.getType().equals(REPNODE_TYPE)) { remedies.add(new UpdateRNParamsRemedy(topoChecker, (RepNodeId) rId)); } else if (referenceParamMap.getType().equals(ARBNODE_TYPE)) { remedies.add(new UpdateANParamsRemedy(topoChecker, (ArbNodeId) rId)); } return false; } } /** Results of comparing parameters. */ public enum CompareParamsResult { /** No differences */ NO_DIFFS, /** The parameters were missing */ MISSING, /** There were differences, but no restart is required */ DIFFS, /** There were differences that require a restart */ DIFFS_RESTART; } /** * Compare service, SN, and global parameters from in-memory values * obtained from the specified running service with reference parameters * from the admin DB. * * @param snId the ID of the SN hosting the service * @param rId the resource ID of the service * @param paramsToCheck service parameters to check * @param referenceParams admin DB parameters to compare with * @return the result of the comparison */ public static CompareParamsResult compareServiceParams( StorageNodeId snId, ResourceId rId, LoadParameters paramsToCheck, Parameters referenceParams) { return compareServiceParams(snId, rId, paramsToCheck, referenceParams, CompareParamsFilter.getInstance(), SNPCompareParamsFilter.getInstance()); } /** * Method used by the admin thread that corrects parameter inconsistencies. * Compare service, SN, and global parameters from in-memory values * obtained from the specified running service with reference parameters * from the admin DB. This method will return results if there are * differences for the GP_STORE_VERSION parameter. * * @param snId the ID of the SN hosting the service * @param rId the resource ID of the service * @param paramsToCheck service parameters to check * @param referenceParams admin DB parameters to compare with * @return the result of the comparison */ public static CompareParamsResult compareServiceParamsPCon( StorageNodeId snId, ResourceId rId, LoadParameters paramsToCheck, Parameters referenceParams) { return compareServiceParams(snId, rId, paramsToCheck, referenceParams, PConCompareParamsFilter.getInstance(), SNPCompareParamsFilter.getInstance()); } private static CompareParamsResult compareServiceParams( StorageNodeId snId, ResourceId rId, LoadParameters paramsToCheck, Parameters referenceParams, CompareParamsFilter serviceFilter, CompareParamsFilter snFilter) { return combineCompareParamsResults( /* Service parameters */ compareParams(paramsToCheck, referenceParams.getMap(rId), serviceFilter), /* Only consider SN parameters related to services */ compareParams(paramsToCheck, referenceParams.get(snId).getMap(), snFilter), /* Global parameters */ compareParams(paramsToCheck, referenceParams.getGlobalParams().getMap(), serviceFilter)); } /** * Compares parameters obtained from a remote service or configuration * parameters to reference parameters, ignoring parameters that should * typically be skipped in comparisons. Checks the parameter map that * matches the name and type of the reference map. * * @param paramsToCheck the remote parameters to check * @param referenceParamMap the reference map to compare with * @return the result of the comparison */ public static CompareParamsResult compareParams( LoadParameters paramsToCheck, ParameterMap referenceParamMap) { return compareParams(paramsToCheck, referenceParamMap, CompareParamsFilter.getInstance()); } /** * Compares parameters obtained from a remote service or configuration * parameters to reference parameters, ignoring parameters that should * typically be skipped in comparisons. Checks the parameter map that * matches the name and type of the reference map. * * @param paramsToCheck the remote parameters to check * @param referenceParamMap the reference map to compare with * @return the result of the comparison */ public static CompareParamsResult compareParamsPCon( LoadParameters paramsToCheck, ParameterMap referenceParamMap) { return compareParams(paramsToCheck, referenceParamMap, PConCompareParamsFilter.getInstance()); } /** * Compares parameters obtained from a remote service or configuration * parameters to reference parameters, using the specified filter to * determine which parameters to compare. Checks the parameter map that * matches the name and type of the reference map. * * @param paramsToCheck the remote parameters to check * @param referenceParamMap the reference map to compare with * @param filter returns the parameters to compare * @return the result of the comparison */ private static CompareParamsResult compareParams( LoadParameters paramsToCheck, ParameterMap referenceParamMap, CompareParamsFilter filter) { ParameterMap mapToCheck = paramsToCheck.getMap( referenceParamMap.getName(), referenceParamMap.getType()); if (mapToCheck == null) { return CompareParamsResult.MISSING; } referenceParamMap = filter.filter(referenceParamMap); mapToCheck = filter.filter(mapToCheck); if (referenceParamMap.equals(mapToCheck)) { return CompareParamsResult.NO_DIFFS; } if (referenceParamMap.hasRestartRequiredDiff(mapToCheck)) { return CompareParamsResult.DIFFS_RESTART; } return CompareParamsResult.DIFFS; } /** * Combines the results of several parameter comparisons into a single * result. If any parameters were missing, returns MISSING. Otherwise, * returns DIFFS_RESTART if any different parameters require a restart, * DIFFS if there were only differences that do not require a restart, and * NO_DIFFS otherwise. */ public static CompareParamsResult combineCompareParamsResults( CompareParamsResult... results) { CompareParamsResult combinedResult = CompareParamsResult.NO_DIFFS; for (CompareParamsResult result : results) { switch (result) { case NO_DIFFS: continue; case MISSING: return CompareParamsResult.MISSING; case DIFFS: if (combinedResult == CompareParamsResult.NO_DIFFS) { combinedResult = CompareParamsResult.DIFFS; } continue; case DIFFS_RESTART: combinedResult = CompareParamsResult.DIFFS_RESTART; continue; } } return combinedResult; } /** * Filter to return the parts of a parameter map that should be considered * by default when performing a comparison. This class skips parameters * specified by {@link ParameterState#skipParams}, which includes the * disabled parameter. */ static class CompareParamsFilter { static final private CompareParamsFilter INSTANCE = new CompareParamsFilter(); static CompareParamsFilter getInstance() { return INSTANCE; } ParameterMap filter(ParameterMap map) { return map.filter(ParameterState.skipParams, false); } } /** * Filter to return the parts of a parameter map that should be considered * by default when performing a comparison by the Parameter Consistency * admin thread. This class skips parameters * specified by {@link ParameterState#skipParamsPCon}, which includes the * disabled parameter. */ static class PConCompareParamsFilter extends CompareParamsFilter { static final private PConCompareParamsFilter INSTANCE = new PConCompareParamsFilter(); static PConCompareParamsFilter getInstance() { return INSTANCE; } @Override ParameterMap filter(ParameterMap map) { return map.filter(ParameterState.skipParamsPCon, false); } } /** * Include only StorageNodeParams parameters that are used by services for * their own configuration. */ static class SNPCompareParamsFilter extends CompareParamsFilter { static final private SNPCompareParamsFilter INSTANCE = new SNPCompareParamsFilter(); static SNPCompareParamsFilter getInstance() { return INSTANCE; } @Override ParameterMap filter(ParameterMap map) { return map.filter(ParameterState.serviceParams, true); } } /** * Classes to record violations. */ public interface Problem { public ResourceId getResourceId(); } /** * Report a service that is stopped either because it is disabled or for * some other reason. */ public static class ServiceStopped implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final StorageNodeId snId; private final boolean isDisabled; ServiceStopped(ResourceId rId, StorageNodeId snId, boolean showProgress, Logger logger, boolean isDisabled) { this.rId = rId; this.snId = snId; this.isDisabled = isDisabled; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(rId).append(" on ").append(snId); if (isDisabled) { sb.append(" was previously stopped and"); } sb.append(" is not running. Consider restarting it with "); sb.append("'plan start-service'."); return sb.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((rId == null) ? 0 : rId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ServiceStopped)) { return false; } ServiceStopped other = (ServiceStopped) obj; if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } return true; } } /** * Report a RN or AN that is not yet a member of the replication group. */ public static class NotInGroup implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final StorageNodeId snId; NotInGroup(ResourceId rId, StorageNodeId snId, boolean showProgress, Logger logger) { this.rId = rId; this.snId = snId; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(rId).append(" on ").append(snId); sb.append(" is running but is not a member of "); sb.append("the replication group."); return sb.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((rId == null) ? 0 : rId.hashCode()); result = prime * result + ((snId == null) ? 0 : snId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof NotInGroup)) { return false; } NotInGroup other = (NotInGroup) obj; if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } if (snId == null) { if (other.snId != null) { return false; } } else if (!snId.equals(other.snId)) { return false; } return true; } } public static class StatusNotRight implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final ServiceStatus expected; private final ServiceStatus current; StatusNotRight(ResourceId rId, ServiceStatus expected, ServiceStatus current, boolean showProgress, Logger logger) { this.rId = rId; this.expected = expected; this.current = current; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } public ServiceStatus getExpectedStatus() { return expected; } public ServiceStatus getCurrentStatus() { return current; } @Override public String toString() { return "Expected status " + expected + " but was " + current; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((current == null) ? 0 : current.hashCode()); result = prime * result + ((expected == null) ? 0 : expected.hashCode()); result = prime * result + ((rId == null) ? 0 : rId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof StatusNotRight)) { return false; } StatusNotRight other = (StatusNotRight) obj; if (current != other.current) { return false; } if (expected != other.expected) { return false; } if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } return true; } } public static class RMIFailed implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final String desc; RMIFailed(ResourceId rId, RemoteException e, String methodName, boolean showProgress, Logger logger) { this.rId = rId; desc = methodName + " failed for " + rId + " : " + e.getMessage(); recordProgress(showProgress, logger, this); } RMIFailed(ResourceId rId, NotBoundException e, boolean showProgress, Logger logger) { this.rId = rId; desc = "No RMI service for " + rId + ": service name=" + e.getMessage(); recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { return desc; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + ((rId == null) ? 0 : rId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof RMIFailed)) { return false; } RMIFailed other = (RMIFailed) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } return true; } } /** Describes where a parameter mismatch was detected. */ enum ParamMismatchLocation { CONFIG("from configuration for service"), MEMORY("on service"); private final String description; private ParamMismatchLocation(String description) { this.description = description; } public String describe() { return description; } } public static class ParamMismatch implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final String mismatch; private static String getMismatchMessage( ResourceId resourceId, ParameterMap remoteCopy, ParameterMap adminCopy, ParamMismatchLocation location) { final ParameterMap onAdminButNotRemote = remoteCopy.diff(adminCopy, false); final ParameterMap onRemoteButNotAdmin = adminCopy.diff(remoteCopy, false); final StringBuilder sb = new StringBuilder(); if (!onAdminButNotRemote.isEmpty()) { sb.append(" Parameters in Admin database but not ") .append(location.describe()).append(" ") .append(resourceId) .append(": ") .append(onAdminButNotRemote.showContents()); } if (!onRemoteButNotAdmin.isEmpty()) { if (!onAdminButNotRemote.isEmpty()) { sb.append("\n"); } sb.append(" Parameters ") .append(location.describe()).append(" ") .append(resourceId) .append(" but not in Admin database: ") .append(onRemoteButNotAdmin.showContents()); } return sb.toString(); } ParamMismatch(ResourceId rId, ParameterMap remoteCopy, ParameterMap adminCopy, ParamMismatchLocation location, boolean showProgress, Logger logger) { this(rId, getMismatchMessage(rId, remoteCopy, adminCopy, location), showProgress, logger); } ParamMismatch(ResourceId rId, String msg, boolean showProgress, Logger logger) { this.rId = rId; mismatch = msg; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { return "Mismatch between metadata in admin service and " + rId + ":" + mismatch; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((mismatch == null) ? 0 : mismatch.hashCode()); result = prime * result + ((rId == null) ? 0 : rId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ParamMismatch)) { return false; } ParamMismatch other = (ParamMismatch) obj; if (mismatch == null) { if (other.mismatch != null) { return false; } } else if (!mismatch.equals(other.mismatch)) { return false; } if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } return true; } } public static class VersionDifference implements Problem, Serializable { private static final long serialVersionUID = 1L; private final StorageNodeId snId; private final String desc; VersionDifference(StorageNodeId snId, KVVersion snVersion, boolean showProgress, Logger logger) { this.snId = snId; desc = "Admin service version is " + KVVersion.CURRENT_VERSION + " but storage node version is " + snVersion; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return snId; } @Override public String toString() { return desc; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + ((snId == null) ? 0 : snId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof VersionDifference)) { return false; } VersionDifference other = (VersionDifference) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (snId == null) { if (other.snId != null) { return false; } } else if (!snId.equals(other.snId)) { return false; } return true; } } public static class StoreVersionHigher implements Problem, Serializable { private static final long serialVersionUID = 1L; private final StorageNodeId snId; private final String desc; StoreVersionHigher(StorageNodeId snId, KVVersion storeVersion, KVVersion snVersion, boolean showProgress, Logger logger) { this.snId = snId; desc = "KVStore version is " + storeVersion + " is greater than the storage node " + snId + " version " + snVersion; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return snId; } @Override public String toString() { return desc; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + ((snId == null) ? 0 : snId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof StoreVersionHigher)) { return false; } StoreVersionHigher other = (StoreVersionHigher) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (snId == null) { if (other.snId != null) { return false; } } else if (!snId.equals(other.snId)) { return false; } return true; } } public static class UpgradeNeeded implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final String desc; UpgradeNeeded(ResourceId rId, KVVersion rVersion, KVVersion targetVersion, boolean showProgress, Logger logger) { this.rId = rId; desc = "Node needs to be upgraded from " + rVersion.getNumericVersionString() + " to version " + targetVersion.getNumericVersionString() + " or newer"; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { return desc; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + ((rId == null) ? 0 : rId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof UpgradeNeeded)) { return false; } UpgradeNeeded other = (UpgradeNeeded) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } return true; } } public static class BadDowngrade implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final String desc; BadDowngrade(ResourceId rId, KVVersion rVersion, KVVersion targetVersion, boolean showProgress, Logger logger) { this.rId = rId; desc = "Node cannot be downgraded to " + targetVersion.getNumericVersionString() + " because it is already at a newer minor version " + rVersion.getNumericVersionString(); recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { return desc; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + ((rId == null) ? 0 : rId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof BadDowngrade)) { return false; } BadDowngrade other = (BadDowngrade) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } return true; } } /** * The problem that configuration violate enforced security requirement. * This problem is only built on client-side, Admin CLI currently. */ public static class SecurityViolation implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final String desc; public SecurityViolation(ResourceId rId, String desc) { this(rId, desc, false, null); } /* Not used currently */ SecurityViolation(ResourceId rId, String desc, boolean showProgress, Logger logger) { this.rId = rId; this.desc = desc; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { return desc; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + ((rId == null) ? 0 : rId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof SecurityViolation)) { return false; } SecurityViolation other = (SecurityViolation) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (rId == null) { if (other.rId != null) { return false; } } else if (!rId.equals(other.rId)) { return false; } return true; } } public static class StorageDirectoryProblem implements Problem, Serializable { private static final long serialVersionUID = 1L; private final StorageNodeId snId; private final String desc; private StorageDirectoryProblem(StorageNodeId snId, String directory, String msg, boolean showProgress, Logger logger) { assert snId != null; this.snId = snId; desc = "Problem with directory " + directory + " on " + snId + ", " + msg + "."; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return snId; } @Override public String toString() { return desc; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof StorageDirectoryProblem)) { return false; } final StorageDirectoryProblem other = (StorageDirectoryProblem)obj; if (snId != other.snId) { return false; } return desc.equals(other.desc); } @Override public int hashCode() { int hash = 3; hash = 97 * hash + Objects.hashCode(this.snId); hash = 97 * hash + Objects.hashCode(this.desc); return hash; } } public static class AvailableStorageExceeded implements Problem, Serializable { private static final long serialVersionUID = 1L; private final RepNodeId rnId; private final String desc; private final String path; private AvailableStorageExceeded(RepNodeId rnId, String storageDirPath, String staticStorageSize, String usedStorageSize, boolean showProgress, Logger logger) { assert rnId != null; this.rnId = rnId; this.path = storageDirPath; desc = "Storage directory on " + rnId + " has exceeded storage size" + " [" + path + " size:" + staticStorageSize + " used:" + usedStorageSize + "]"; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rnId; } @Override public String toString() { return desc; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof AvailableStorageExceeded)) { return false; } final AvailableStorageExceeded other = (AvailableStorageExceeded)obj; if (rnId != other.rnId) { return false; } return desc.equals(other.desc); } @Override public int hashCode() { int hash = 3; hash = 97 * hash + Objects.hashCode(this.rnId); hash = 97 * hash + Objects.hashCode(this.desc); return hash; } } public static class AvailableStorageLow implements Problem, Serializable { private static final long serialVersionUID = 1L; private final RepNodeId rnId; private final String desc; private final String path; private AvailableStorageLow(RepNodeId rnId, String storageDirPath, String staticStorageSize, String usedStorageSize, boolean showProgress, Logger logger) { assert rnId != null; this.rnId = rnId; this.path = storageDirPath; desc = "Storage directory on " + rnId + " is running low" + " [" + path + " size:" + staticStorageSize + " used:" + usedStorageSize + "]"; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rnId; } @Override public String toString() { return desc; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof AvailableStorageLow)) { return false; } final AvailableStorageLow other = (AvailableStorageLow)obj; if (rnId != other.rnId) { return false; } return desc.equals(other.desc); } @Override public int hashCode() { int hash = 3; hash = 97 * hash + Objects.hashCode(this.rnId); hash = 97 * hash + Objects.hashCode(this.desc); return hash; } } /** * Not all types of request are enabled on this node. */ public static class RequestsDisabled implements Problem, Serializable { private static final long serialVersionUID = 1L; private final ResourceId rId; private final String enabledRequestType; public RequestsDisabled(ResourceId rId, String desc) { this(rId, desc, false, null); } RequestsDisabled(ResourceId rId, String enabledRequestType, boolean showProgress, Logger logger) { ObjectUtil.checkNull("resourceId", rId); ObjectUtil.checkNull("enabledRequestType", enabledRequestType); this.rId = rId; this.enabledRequestType = enabledRequestType; recordProgress(showProgress, logger, this); } @Override public ResourceId getResourceId() { return rId; } @Override public String toString() { return "Not all request are enabled on " + rId + ", enabled request type is " + enabledRequestType; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + enabledRequestType.hashCode(); result = prime * result + rId.hashCode(); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof RequestsDisabled)) { return false; } RequestsDisabled other = (RequestsDisabled) obj; if (!enabledRequestType.equals(other.enabledRequestType)) { return false; } if (!rId.equals(other.rId)) { return false; } return true; } } private String getOperation() { StringBuilder operation = new StringBuilder("verify"); switch(verifyType) { case TOPOLOGY: operation.append(" configuration"); break; case UPGRADE: operation.append(" upgrade"); break; case PREREQUISITE: operation.append(" prerequisite"); break; default: break; } if(json) { operation.append(" -json"); } if(!showProgress) { operation.append(" -silent"); } return operation.toString(); } /* * Generate the verify command results based on following rules: * 1. If there isn't any violation, return CommandSucceeds * 2. If there are both violation and remedy, return CommandFails which * error code is 5400 and cleanup job is TOPO_REPAIR. * 3. If there is RMIFailed or StatusNotRight violation, we may need retry * the verify command again later. Then we will return CommandFails which * error code is 5300 and no cleanup job. * 4. Otherwise we will return CommandFails which error code is 5200. */ private CommandResult getCommandResult() { final boolean hasRemedy = !remedies.isEmpty(); if (violations == null || violations.isEmpty()) { if (hasRemedy) { return new CommandFails("variable hadRemedy is true although" + " there are no violations", ErrorMessage.NOSQL_5500, CommandResult.NO_CLEANUP_JOBS); } return new CommandSucceeds(null /* return value */); } if (hasRemedy) { return new CommandFails("There are violations. Please use " + Arrays.toString(CommandResult.TOPO_REPAIR) + " to recover and try again later", ErrorMessage.NOSQL_5400, CommandResult.TOPO_REPAIR); } for (Problem p : violations) { if (p instanceof RMIFailed) { return new CommandFails("Connect failed, please try again.", ErrorMessage.NOSQL_5300, CommandResult.NO_CLEANUP_JOBS); } if (p instanceof StatusNotRight) { final StatusNotRight stNotRight = (StatusNotRight) p; final ServiceStatus current = stNotRight.getCurrentStatus(); final ServiceStatus expected = stNotRight.getExpectedStatus(); if (expected == ServiceStatus.RUNNING && (current == ServiceStatus.STARTING || current == ServiceStatus.ERROR_RESTARTING)) { return new CommandFails( "Waiting for service status, try later", ErrorMessage.NOSQL_5300, CommandResult.NO_CLEANUP_JOBS); } } } return new CommandFails("There are violations.", ErrorMessage.NOSQL_5200, CommandResult.NO_CLEANUP_JOBS); } private String getOutput() { if (json) { return jsonResults(); } final StringBuilder sb = new StringBuilder(); sb.append("Verify: starting verification of ") .append(PingDisplay.displayTopologyOverview(jsonTop)).append(eol); sb.append(displayStorewideLogName(jsonTop)).append(eol); if (showProgress) { if (verifyType == VerifyType.TOPOLOGY) { sb.append("Verify: ") .append(PingDisplay.displayShardOverview(jsonTop)) .append(eol); sb.append("Verify: ") .append(PingDisplay.displayAdminOverview(jsonTop)) .append(eol); for (JsonNode jsonZone : getArray(jsonTop, "zoneStatus")) { sb.append("Verify: ") .append(PingDisplay.displayZoneOverview(jsonZone)) .append(eol); } } for (JsonNode jsonSN : getArray(jsonTop, "snStatus")) { final String snId = getAsText(jsonSN, "resourceId"); if (verifyType == VerifyType.TOPOLOGY) { sb.append("Verify: == checking storage node ") .append(snId).append(" ==").append(eol); } showProgressProblems(snId, sb); sb.append("Verify") .append((verifyType == VerifyType.TOPOLOGY) ? "" : (" " + verifyType)) .append(": ") .append(PingDisplay.displayStorageNode(jsonSN)).append(eol); final JsonNode jsonAdmin = jsonSN.get("adminStatus"); if (jsonAdmin != null) { showProgressProblems( getAsText(jsonAdmin, "resourceId"), sb); sb.append("Verify: ") .append(PingDisplay.displayAdmin(jsonAdmin)). append(eol); } for (JsonNode jsonRN : getArray(jsonSN, "rnStatus")) { showProgressProblems( getAsText(jsonRN, "resourceId"), sb); sb.append("Verify: ") .append(PingDisplay.displayRepNode(jsonRN)).append(eol); } for (JsonNode jsonAN : getArray(jsonSN, "anStatus")) { showProgressProblems( getAsText(jsonAN, "resourceId"), sb); sb.append("Verify: ") .append(PingDisplay.displayArbNode(jsonAN)).append(eol); } } sb.append(eol); } return appendViolations(sb).toString(); } private String jsonResults() { String operation = getOperation(); CommandResult result = getCommandResult(); try { CommandJsonUtils.updateNodeWithResult(jsonTop, operation, result); return CommandJsonUtils.toJsonString(jsonTop); } catch(IOException e) { throw new CommandFaultException(e.getMessage(), ErrorMessage.NOSQL_5500, CommandResult.NO_CLEANUP_JOBS); } } private StringBuilder appendViolations(StringBuilder sb) { final int numViolations = violations.size(); final int numWarnings = warnings.size(); if ((numViolations + numWarnings) == 0) { sb.append("Verification complete, no violations."); return sb; } sb.append("Verification complete, ").append(numViolations); sb.append((numViolations == 1) ? " violation, " : " violations, "); sb.append(numWarnings); sb.append((numWarnings == 1) ? " note" : " notes"); sb.append(" found.").append(eol); for (JsonNode jsonProblem : getArray(jsonTop, "violations")) { sb.append("Verification violation: ") .append(displayProblem(jsonProblem)).append(eol); } for (JsonNode jsonProblem : getArray(jsonTop, "warnings")) { sb.append("Verification note: ") .append(displayProblem(jsonProblem)).append(eol); } return sb; } private void showProgressProblems(String resourceId, StringBuilder sb) { if (showProgress) { for (Problem problem : violations) { if (resourceId.equals(problem.getResourceId().toString())) { sb.append("Verify: ") .append(problem.getResourceId()).append(": ") .append(problem).append(eol); } } for (Problem problem : warnings) { if (resourceId.equals(problem.getResourceId().toString())) { sb.append("Verify: ") .append(problem.getResourceId()).append(": ") .append(problem).append(eol); } } } } private static void recordProgress(boolean showProgress, Logger logger, Problem problem) { if (showProgress) { String msg = "Verify: " + problem.getResourceId() + ": " + problem; logger.info(msg); } } public VerifyResults getResults() { return new VerifyResults(getOutput(), violations, warnings); } public TopologyCheck getTopoChecker() { return topoChecker; } /** * Returns the list of remedies that should be applied, in order, to repair * the configuration problems that were found. The master Admin ID is used * to perform remedies related to the master admin last so that the most * progress can be made before potentially needing to restart the process * after transferring the master. * * @param masterAdminId the master Admin ID * @return the list of remedies */ public List getRemedies(AdminId masterAdminId) { return remedies.getRemedies(masterAdminId); } /* * TODO: Consider adding a more general facility for ordering remedies * if we have to add another ordering criterion. */ /** * Organize remedies by type, because CreateRNRemedy instances have to be * done first and RemoveRNRemedy ones have to be done last. */ private static class Remedies { private final List creates = new ArrayList<>(); private final List removes = new ArrayList<>(); private final List other = new ArrayList<>(); void clear() { creates.clear(); removes.clear(); other.clear(); } void add(Remedy remedy) { if (remedy instanceof CreateRNRemedy) { creates.add(remedy); } else if (remedy instanceof RemoveRNRemedy) { removes.add(remedy); } else { other.add(remedy); } } List getRemedies(AdminId masterAdminId) { checkNull("masterAdminId", masterAdminId); final List r = new ArrayList<>(); collectRemedies(r, creates, masterAdminId); collectRemedies(r, other, masterAdminId); collectRemedies(r, removes, masterAdminId); return r; } private void collectRemedies(List result, List add, AdminId masterAdminId) { boolean foundMasterAdmin = false; for (final Remedy remedy : add) { if (masterAdminId.equals(remedy.getResourceId())) { foundMasterAdmin = true; } else { result.add(remedy); } } if (foundMasterAdmin) { for (final Remedy remedy : add) { if (masterAdminId.equals(remedy.getResourceId())) { result.add(remedy); } } } } boolean remedyExists(ResourceId resourceId) { for (Remedy r : creates) { if (r.getResourceId().equals(resourceId)) { return true; } } for (Remedy r : other) { if (r.getResourceId().equals(resourceId)) { return true; } } for (Remedy r : removes) { if (r.getResourceId().equals(resourceId)) { return true; } } return false; } boolean isEmpty() { return creates.isEmpty() && removes.isEmpty() && other.isEmpty(); } } private KVVersion getVersion(String versionString) { KVVersion retVal = null; try { retVal = KVVersion.parseVersion(versionString); } catch (Exception e) { } return retVal; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy