blob: 4e6460be4bd10332f2d50b858bb21bc5dc458d8e [file] [log] [blame]
/*
* Copyright 2009-2012 by The Regents of the University of California
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may obtain a copy of the License from
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.uci.ics.asterix.installer.command;
import java.io.File;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import org.kohsuke.args4j.Option;
import edu.uci.ics.asterix.event.management.EventUtil;
import edu.uci.ics.asterix.event.schema.cluster.Cluster;
import edu.uci.ics.asterix.event.schema.cluster.MasterNode;
import edu.uci.ics.asterix.event.schema.cluster.Node;
import edu.uci.ics.asterix.installer.driver.InstallerDriver;
import edu.uci.ics.asterix.installer.driver.InstallerUtil;
import edu.uci.ics.asterix.installer.model.ProcessInfo;
import edu.uci.ics.asterix.installer.schema.conf.Configuration;
import edu.uci.ics.asterix.installer.schema.conf.Zookeeper;
public class ValidateCommand extends AbstractCommand {
private static final String OK = " [" + "OK" + "]";
private static final String ERROR = " [" + "ERROR" + "]";
private static final String WARNING = " [" + "WARNING" + "]";
@Override
protected void execCommand() throws Exception {
ValidateConfig vConfig = (ValidateConfig) config;
logValidationResult("Environment", validateEnvironment());
if (((ValidateConfig) config).cluster != null) {
logValidationResult("Cluster configuration", validateCluster(vConfig.cluster));
} else {
logValidationResult("Managix Configuration", validateConfiguration());
}
}
private void logValidationResult(String prefix, boolean isValid) {
if (!isValid) {
LOGGER.fatal(prefix + ERROR);
} else {
LOGGER.info(prefix + OK);
}
}
@Override
protected CommandConfig getCommandConfig() {
return new ValidateConfig();
}
@Override
protected String getUsageDescription() {
return "\nValidate the installer's configuration or a cluster configuration" + "\nUsage"
+ "\nFor validating the installer configuration" + "\nuse managix validate"
+ "\n\nFor validating a cluster configuration"
+ "\nuse managix validate -c <path to the cluster configuration file>";
}
public boolean validateEnvironment() throws Exception {
boolean valid = true;
String managixHome = System.getenv(InstallerDriver.ENV_MANAGIX_HOME);
if (managixHome == null) {
valid = false;
LOGGER.fatal(InstallerDriver.ENV_MANAGIX_HOME + " not set " + ERROR);
} else {
File home = new File(managixHome);
if (!home.exists()) {
valid = false;
LOGGER.fatal(InstallerDriver.ENV_MANAGIX_HOME + ": " + home.getAbsolutePath() + " does not exist!"
+ ERROR);
}
}
return valid;
}
public boolean validateCluster(String clusterPath) throws Exception {
boolean valid = true;
Cluster cluster = null;
File f = new File(clusterPath);
List<String> ipAddresses = new ArrayList<String>();
if (!f.exists() || !f.isFile()) {
LOGGER.error(" Invalid path " + f.getAbsolutePath() + ERROR);
valid = false;
} else {
cluster = EventUtil.getCluster(clusterPath);
validateClusterProperties(cluster);
Set<String> servers = new HashSet<String>();
Set<String> serverIds = new HashSet<String>();
servers.add(cluster.getMasterNode().getClusterIp());
serverIds.add(cluster.getMasterNode().getId());
MasterNode masterNode = cluster.getMasterNode();
Node master = new Node(masterNode.getId(), masterNode.getClusterIp(), masterNode.getJavaOpts(),
masterNode.getJavaHome(), masterNode.getLogdir(), null, null, null);
ipAddresses.add(masterNode.getClusterIp());
valid = valid & validateNodeConfiguration(master, cluster);
for (Node node : cluster.getNode()) {
servers.add(node.getClusterIp());
if (serverIds.contains(node.getId())) {
valid = false;
LOGGER.error("Duplicate node id :" + node.getId() + ERROR);
} else {
valid = valid & validateNodeConfiguration(node, cluster);
if (!ipAddresses.contains(node.getClusterIp())) {
ipAddresses.add(node.getClusterIp());
}
}
}
}
if (valid) {
String username = cluster.getUsername();
if (username == null) {
username = System.getProperty("user.name");
}
valid = checkPasswordLessSSHLogin(username, ipAddresses);
}
return valid;
}
private boolean checkPasswordLessSSHLogin(String username, List<String> ipAddresses) throws Exception {
String script = InstallerDriver.getManagixHome() + File.separator + InstallerDriver.MANAGIX_INTERNAL_DIR
+ File.separator + "scripts" + File.separator + "validate_ssh.sh";
List<String> args = ipAddresses;
args.add(0, username);
String output = InstallerUtil.executeLocalScript(script, args);
ipAddresses.remove(0);
for (String line : output.split("\n")) {
ipAddresses.remove(line);
}
if (ipAddresses.size() > 0) {
LOGGER.error(" Password-less SSH (from user account: " + username + " )"
+ " not configured for the following hosts");
for (String failedIp : ipAddresses) {
System.out.println(failedIp);
}
return false;
}
return true;
}
private void validateClusterProperties(Cluster cluster) {
List<String> tempDirs = new ArrayList<String>();
if (cluster.getLogdir() != null && checkTemporaryPath(cluster.getLogdir())) {
tempDirs.add("Log directory: " + cluster.getLogdir());
}
if (cluster.getIodevices() != null && checkTemporaryPath(cluster.getIodevices())) {
tempDirs.add("IO Device: " + cluster.getIodevices());
}
if (tempDirs.size() > 0) {
StringBuffer msg = new StringBuffer();
msg.append("The following paths are subject to be cleaned up by OS");
for (String tempDir : tempDirs) {
msg.append("\n" + tempDir + WARNING);
}
LOGGER.warn(msg);
}
}
private boolean validateNodeConfiguration(Node node, Cluster cluster) {
boolean valid = true;
valid = checkNodeReachability(node.getClusterIp());
if (node.getJavaHome() == null || node.getJavaHome().length() == 0) {
if (cluster.getJavaHome() == null || cluster.getJavaHome().length() == 0) {
valid = false;
LOGGER.fatal("java_home not defined at cluster/node level for node: " + node.getId() + ERROR);
}
}
if (node.getLogdir() == null || node.getLogdir().length() == 0) {
if (cluster.getLogdir() == null || cluster.getLogdir().length() == 0) {
valid = false;
LOGGER.fatal("log_dir not defined at cluster/node level for node: " + node.getId() + ERROR);
}
}
if (node.getStore() == null || node.getStore().length() == 0) {
if (!cluster.getMasterNode().getId().equals(node.getId())
&& (cluster.getStore() == null || cluster.getStore().length() == 0)) {
valid = false;
LOGGER.fatal("store not defined at cluster/node level for node: " + node.getId() + ERROR);
}
}
if (node.getIodevices() == null || node.getIodevices().length() == 0) {
if (!cluster.getMasterNode().getId().equals(node.getId())
&& (cluster.getIodevices() == null || cluster.getIodevices().length() == 0)) {
valid = false;
LOGGER.fatal("iodevice(s) not defined at cluster/node level for node: " + node.getId() + ERROR);
}
}
return valid;
}
private boolean checkTemporaryPath(String logdir) {
return logdir.startsWith(System.getProperty("java.io.tmpdir"));
}
public boolean validateConfiguration() throws Exception {
String managixHome = System.getenv(InstallerDriver.ENV_MANAGIX_HOME);
File configFile = new File(managixHome + File.separator + InstallerDriver.MANAGIX_CONF_XML);
JAXBContext configCtx = JAXBContext.newInstance(Configuration.class);
Unmarshaller unmarshaller = configCtx.createUnmarshaller();
Configuration conf = (Configuration) unmarshaller.unmarshal(configFile);
return validateZookeeperConfiguration(conf);
}
private boolean validateZookeeperConfiguration(Configuration conf) throws Exception {
boolean valid = true;
Zookeeper zk = conf.getZookeeper();
if (zk.getHomeDir() == null || zk.getHomeDir().length() == 0) {
valid = false;
LOGGER.fatal("Zookeeper home dir not configured" + ERROR);
} else if (checkTemporaryPath(zk.getHomeDir())) {
LOGGER.warn("Zookeeper home dir is subject to be cleaned up by OS" + WARNING);
}
if (zk.getServers().getServer() == null || zk.getServers().getServer().isEmpty()) {
valid = false;
LOGGER.fatal("Zookeeper servers not configured" + ERROR);
}
if (zk.getServers().getJavaHome() == null || zk.getServers().getJavaHome().length() == 0) {
valid = false;
LOGGER.fatal("Java home not set for Zookeeper server in " + InstallerDriver.getManagixHome()
+ File.separator + InstallerDriver.MANAGIX_CONF_XML);
}
for (String server : zk.getServers().getServer()) {
valid = valid && checkNodeReachability(server);
}
if (valid)
valid = valid & checkPasswordLessSSHLogin(System.getProperty("user.name"), zk.getServers().getServer());
{
}
return valid;
}
private boolean checkNodeReachability(String server) {
boolean reachable = true;
try {
InetAddress address = InetAddress.getByName(server);
if (!address.isReachable(1000)) {
LOGGER.fatal("\n" + "Server: " + server + " unreachable" + ERROR);
reachable = false;
}
} catch (Exception e) {
reachable = false;
LOGGER.fatal("\n" + "Server: " + server + " Invalid address" + ERROR);
}
return reachable;
}
}
class ValidateConfig extends CommandConfig {
@Option(name = "-c", required = false, usage = "Path to the cluster configuration xml")
public String cluster;
}