/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hdfs; import java.io.IOException; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.security.auth.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.hdfs.protocol.AvatarProtocol; import org.apache.hadoop.hdfs.protocol.AvatarConstants.Avatar; import org.apache.hadoop.hdfs.protocol.AvatarConstants.InstanceId; import org.apache.hadoop.hdfs.protocol.AvatarConstants.StartupOption; import org.apache.hadoop.hdfs.server.namenode.AvatarNode; import org.apache.hadoop.hdfs.server.namenode.AvatarNodeZkUtil; import org.apache.hadoop.io.retry.RetryPolicies; import org.apache.hadoop.io.retry.RetryPolicy; import org.apache.hadoop.io.retry.RetryProxy; import org.apache.hadoop.ipc.RPC; import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.security.UnixUserGroupInformation; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; /** * A {@link AvatarZKShell} that allows browsing configured avatar policies. */ public class AvatarZKShell extends Configured implements Tool { public static final Log LOG = LogFactory .getLog("org.apache.hadoop.AvatarShell"); // AvatarShell deals with hdfs configuration so need to add these static { Configuration.addDefaultResource("hdfs-default.xml"); Configuration.addDefaultResource("hdfs-site.xml"); Configuration.addDefaultResource("avatar-default.xml"); Configuration.addDefaultResource("avatar-site.xml"); } public AvatarProtocol avatarnode; AvatarProtocol rpcAvatarnode; private UnixUserGroupInformation ugi; volatile boolean clientRunning = true; private Configuration conf; // We need to keep the default configuration around with // Avatar specific fields unmodified private Configuration originalConf; /** * Start AvatarShell. * <p> * The AvatarShell connects to the specified AvatarNode and performs basic * configuration options. * * @throws IOException */ public AvatarZKShell() { this(new Configuration()); } /** * The AvatarShell connects to the specified AvatarNode and performs basic * configuration options. * * @param conf * The Hadoop configuration * @throws IOException */ public AvatarZKShell(Configuration conf) { super(conf); this.conf = this.originalConf = conf; } public void initAvatarRPC() throws IOException { try { this.ugi = UnixUserGroupInformation.login(conf, true); } catch (LoginException e) { throw (IOException) (new IOException().initCause(e)); } this.rpcAvatarnode = createRPCAvatarnode(AvatarNode.getAddress(conf), conf, ugi); this.avatarnode = createAvatarnode(rpcAvatarnode); } public static AvatarProtocol createAvatarnode(Configuration conf) throws IOException { return createAvatarnode(AvatarNode.getAddress(conf), conf); } public static AvatarProtocol createAvatarnode( InetSocketAddress avatarNodeAddr, Configuration conf) throws IOException { try { return createAvatarnode(createRPCAvatarnode(avatarNodeAddr, conf, UnixUserGroupInformation.login(conf, true))); } catch (LoginException e) { throw (IOException) (new IOException().initCause(e)); } } private static AvatarProtocol createRPCAvatarnode( InetSocketAddress avatarNodeAddr, Configuration conf, UnixUserGroupInformation ugi) throws IOException { LOG.info("AvatarShell connecting to " + avatarNodeAddr); return (AvatarProtocol) RPC.getProxy(AvatarProtocol.class, AvatarProtocol.versionID, avatarNodeAddr, ugi, conf, NetUtils.getSocketFactory(conf, AvatarProtocol.class)); } private static AvatarProtocol createAvatarnode(AvatarProtocol rpcAvatarnode) throws IOException { Map<Class<? extends Exception>, RetryPolicy> remoteExceptionToPolicyMap = new HashMap<Class<? extends Exception>, RetryPolicy>(); Map<Class<? extends Exception>, RetryPolicy> exceptionToPolicyMap = new HashMap<Class<? extends Exception>, RetryPolicy>(); exceptionToPolicyMap.put(RemoteException.class, RetryPolicies .retryByRemoteException(RetryPolicies.TRY_ONCE_THEN_FAIL, remoteExceptionToPolicyMap)); RetryPolicy methodPolicy = RetryPolicies.retryByException( RetryPolicies.TRY_ONCE_THEN_FAIL, exceptionToPolicyMap); Map<String, RetryPolicy> methodNameToPolicyMap = new HashMap<String, RetryPolicy>(); methodNameToPolicyMap.put("create", methodPolicy); return (AvatarProtocol) RetryProxy.create(AvatarProtocol.class, rpcAvatarnode, methodNameToPolicyMap); } /** * Close the connection to the avatarNode. */ public synchronized void close() throws IOException { if (clientRunning) { clientRunning = false; RPC.stopProxy(rpcAvatarnode); } } /** * Displays format of commands. */ private static void printUsage(String cmd) { if ("-updateZK".equals(cmd)) { System.err.println("Usage: java AvatarZKShell [-service serviceName]" + " [-updateZK -{zero|one}]"); } else if ("-clearZK".equals(cmd)) { System.err.println("Usage: java AvatarZKShell [-service serviceName]" + " [-clearZK]"); } else { System.err.println("Usage: java AvatarZKShell [-service serviceName]"); System.err.println(" [-updateZK -{zero|one} [-force]]"); System.err.println(" [-clearZK]"); System.err.println(" [-createZK -{zero|one}]"); System.err.println(" [-getZK]"); System.err.println(); ToolRunner.printGenericCommandUsage(System.err); } } public static Configuration updateConf(String instance, Configuration conf) { InstanceId instanceId = InstanceId.NODEZERO; // Some instances might use fs.default.name0 and some might use // dfs.namenode.rpc-address. if (instance.equalsIgnoreCase(StartupOption.NODEONE.getName())) { if (conf.get(AvatarNode.DFS_NAMENODE_RPC_ADDRESS1_KEY) == null && conf.get("fs.default.name1") == null) { LOG.error("Configuration error: Cannot find dfs.namenode.rpc-address1 or fs.default.name1"); return null; } instanceId = InstanceId.NODEONE; } else if (instance.equalsIgnoreCase(StartupOption.NODEZERO.getName())) { if (conf.get(AvatarNode.DFS_NAMENODE_RPC_ADDRESS0_KEY) == null && conf.get("fs.default.name0") == null) { LOG.error("Configuration error: Cannot find dfs.namenode.rpc-address0 or fs.default.name0"); return null; } instanceId = InstanceId.NODEZERO; } else { return null; } return AvatarNode.updateAddressConf(conf, instanceId); } /** * run */ public int run(String argv[]) throws Exception { if (argv.length < 1) { printUsage(""); return -1; } int exitCode = 0; String zkCmd = null; String serviceName = null; String instance = null; boolean force = false; // enforce to specify service if configured if (!AvatarShell.isServiceSpecified("AvatarZKShell", conf, argv)) { return -1; } for(int i=0; i < argv.length; i++) { String cmd = argv[i]; // // verify that we have enough command line parameters // if ("-service".equals(cmd)) { if (i+1 == argv.length ) { printUsage(cmd); return -1; } serviceName = argv[++i]; } else if ("-updateZK".equals(cmd)) { zkCmd = cmd; if (i+1 == argv.length ) { printUsage(cmd); return -1; } instance = argv[++i]; if (i+1 < argv.length && argv[i+1].equals("-force")) { force = true; i++; } } else if ("-clearZK".equals(cmd)) { zkCmd = cmd; } else if ("-createZK".equals(cmd)) { zkCmd = cmd; if (i+1 == argv.length) { printUsage(cmd); return -1; } instance = argv[++i]; } else if ("-getZK".equals(cmd)) { zkCmd = cmd; } else { exitCode = -1; System.err.println(cmd.substring(1) + ": Unknown command"); printUsage(""); } } // make sure that command is provided if (zkCmd == null ) { printUsage(""); return -1; } Collection<String> services; if (serviceName != null) { // for one service if (!AvatarNode.validateServiceName(conf, serviceName)) { return -1; } services = new ArrayList<String>(1); services.add(serviceName); } else { // for all configured services services = DFSUtil.getNameServiceIds(conf); if (services.size() == 0) { //non-federation services.add(""); } } try { for (String service : services) { AvatarNode.initializeGenericKeys(originalConf, service); if ("-updateZK".equals(zkCmd) || "-createZK".equals(zkCmd)) { if (instance == null || (conf=updateConf(instance, originalConf)) == null) { printUsage(zkCmd); return -1; } } if ("-updateZK".equals(zkCmd)) { updateZooKeeper(force, service, instance); } else if ("-clearZK".equals(zkCmd)) { clearZooKeeper(service); } else if ("-createZK".equals(zkCmd)) { updateZooKeeper(true, false, service, instance); } else if ("-getZK".equals(zkCmd)) { getZooKeeper(service); } } } catch (IllegalArgumentException arge) { exitCode = -1; arge.printStackTrace(); System.err.println(zkCmd.substring(1) + ": " + arge.getLocalizedMessage()); printUsage(zkCmd); } catch (RemoteException e) { exitCode = -1; try { String[] content; content = e.getLocalizedMessage().split("\n"); System.err.println(zkCmd.substring(1) + ": " + content[0]); } catch (Exception ex) { System.err.println(zkCmd.substring(1) + ": " + ex.getLocalizedMessage()); } } catch (IOException e) { // // IO exception encountered locally. // exitCode = -1; System.err.println(zkCmd.substring(1) + ": " + e.getLocalizedMessage()); e.printStackTrace(); } catch (Throwable re) { exitCode = -1; System.err.println(zkCmd.substring(1) + ": " + re.getLocalizedMessage()); re.printStackTrace(); } finally { } return exitCode; } public void getZooKeeper(String serviceName) throws IOException, KeeperException, InterruptedException { AvatarNodeZkUtil.printZookeeperEntries(originalConf, conf, serviceName, System.out); } public void clearZooKeeper(String serviceName) throws IOException { AvatarNodeZkUtil.clearZookeeper(originalConf, conf, serviceName); } public void updateZooKeeper(boolean force, String serviceName, String instance) throws IOException { updateZooKeeper(force, true, serviceName, instance); } /* * This method tries to update the information in ZooKeeper For every address * of the NameNode it is being run for (fs.default.name, * dfs.namenode.dn-address, dfs.namenode.http.address) if they are present. It * also creates information for aliases in ZooKeeper for lists of strings in * fs.default.name.aliases, dfs.namenode.dn-address.aliases and * dfs.namenode.http.address.aliases * * Each address it transformed to the address of the zNode to be created by * substituting all . and : characters to /. The slash is also added in the * front to make it a valid zNode address. So dfs.domain.com:9000 will be * /dfs/domain/com/9000 * * If any part of the path does not exist it is created automatically */ public void updateZooKeeper(boolean force, boolean toOverwrite, String serviceName, String primary) throws IOException { if (!force) { initAvatarRPC(); Avatar avatar = avatarnode.getAvatar(); if (avatar != Avatar.ACTIVE) { throw new IOException( "Cannot update ZooKeeper information to point to " + "the AvatarNode in Standby mode"); } } AvatarNodeZkUtil.updateZooKeeper(originalConf, conf, toOverwrite, serviceName, primary); } public static class DummyWatcher implements Watcher { @Override public void process(WatchedEvent event) { // This is a dummy watcher since we are only doing creates and deletes } } /** * main() has some simple utility methods */ public static void main(String argv[]) throws Exception { DnsMonitorSecurityManager.setTheManager(); AvatarZKShell shell = null; shell = new AvatarZKShell(); int res; try { res = ToolRunner.run(shell, argv); } finally { shell.close(); } System.exit(res); } }