package org.apache.mesos.hbase.config; import com.floreysoft.jmte.Engine; import com.google.inject.Inject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.mesos.hbase.state.IPersistentStateStore; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.ResourceHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.mesos.hbase.util.HBaseConstants; /** * This is the HTTP service which allows executors to fetch the configuration for hbase-site.xml. */ public class ConfigServer { private final Log log = LogFactory.getLog(ConfigServer.class); private Server server; private Engine engine; private HBaseFrameworkConfig hbaseFrameworkConfig; private IPersistentStateStore persistenceStore; @Inject public ConfigServer(HBaseFrameworkConfig hbaseFrameworkConfig, IPersistentStateStore persistenceStore) { this.hbaseFrameworkConfig = hbaseFrameworkConfig; this.persistenceStore = persistenceStore; engine = new Engine(); server = new Server(hbaseFrameworkConfig.getConfigServerPort()); ResourceHandler resourceHandler = new ResourceHandler(); resourceHandler.setResourceBase(hbaseFrameworkConfig.getExecutorPath()); HandlerList handlers = new HandlerList(); handlers.setHandlers(new Handler[]{ resourceHandler, new ServeHbaseConfigHandler()}); server.setHandler(handlers); try { server.start(); } catch (Exception e) { final String msg = "Unable to start jetty server"; log.error(msg, e); throw new ConfigServerException(msg, e); } } public void stop() throws ConfigServerException { try { server.stop(); } catch (Exception e) { final String msg = "Unable to stop the jetty service"; log.error(msg, e); throw new ConfigServerException(msg, e); } } private class ServeHbaseConfigHandler extends AbstractHandler { public synchronized void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { String pathRequested = request.getPathInfo().replace("/", ""); if (pathRequested.equalsIgnoreCase(HBaseConstants.HBASE_CONFIG_FILE_NAME)) { handleHbaseSite(baseRequest, request, response); } else if (pathRequested.equalsIgnoreCase(HBaseConstants.REGION_SERVERS_FILENAME)) { handleRegionServers(baseRequest, request, response); } else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); baseRequest.setHandled(true); } } private String getHbaseRootDir() { if (hbaseFrameworkConfig.usingMesosHdfs()) { return "hdfs://" + hbaseFrameworkConfig.getDfsNameServices() + "/hbase"; } else { return hbaseFrameworkConfig.getHbaseRootDir(); } } private void handleHbaseSite(Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { File confFile = new File(hbaseFrameworkConfig.getConfigPath()); if (!confFile.exists()) { throw new FileNotFoundException("Couldn't file config file: " + confFile.getPath() + ". Please make sure it exists."); } String view = new String(Files.readAllBytes(Paths.get(confFile.getPath())), Charset.defaultCharset()); Set<String> primaryNodes = new TreeSet<>(); primaryNodes.addAll(persistenceStore.getPrimaryNodes().keySet()); Map<String, Object> model = new HashMap<>(); Iterator<String> iter = primaryNodes.iterator(); if (iter.hasNext()) { model.put("primary1Hostname", iter.next()); } if (iter.hasNext()) { model.put("primary2Hostname", iter.next()); } model.put("hbaseRootDir", getHbaseRootDir()); model.put("frameworkName", hbaseFrameworkConfig.getFrameworkName()); model.put("dataDir", hbaseFrameworkConfig.getDataDir()); model.put("haZookeeperQuorum", hbaseFrameworkConfig.getHaZookeeperQuorum()); String content = engine.transform(view, model); response.setContentType("application/octet-stream;charset=utf-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + HBaseConstants.HBASE_CONFIG_FILE_NAME + "\" "); response.setHeader("Content-Transfer-Encoding", "binary"); response.setHeader("Content-Length", Integer.toString(content.length())); response.setStatus(HttpServletResponse.SC_OK); baseRequest.setHandled(true); response.getWriter().println(content); } private void handleRegionServers(Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { StringBuilder content = new StringBuilder(); Set<String> primaryNodes = new TreeSet<>(); primaryNodes.addAll(persistenceStore.getPrimaryNodes().keySet()); for(String primaryNode : primaryNodes) { content.append(primaryNode).append('\n'); } Set<String> regionNodes = new TreeSet<>(); regionNodes.addAll(persistenceStore.getRegionNodes().keySet()); for(String regionNode : regionNodes) { content.append(regionNode).append('\n'); } response.setContentType("application/octet-stream;charset=utf-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + HBaseConstants.REGION_SERVERS_FILENAME + "\" "); response.setHeader("Content-Transfer-Encoding", "binary"); response.setHeader("Content-Length", Integer.toString(content.length())); response.setStatus(HttpServletResponse.SC_OK); baseRequest.setHandled(true); response.getWriter().println(content); } } }