io.hops.hopsworks.api.tensorflow.TensorboardProxyServlet.java Source code

Java tutorial

Introduction

Here is the source code for io.hops.hopsworks.api.tensorflow.TensorboardProxyServlet.java

Source

/*
 * Changes to this file committed after and not including commit-id: ccc0d2c5f9a5ac661e60e6eaf138de7889928b8b
 * are released under the following license:
 *
 * This file is part of Hopsworks
 * Copyright (C) 2018, Logical Clocks AB. All rights reserved
 *
 * Hopsworks is free software: you can redistribute it and/or modify it under the terms of
 * the GNU Affero General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Hopsworks is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <https://www.gnu.org/licenses/>.
 *
 * Changes to this file committed before and including commit-id: ccc0d2c5f9a5ac661e60e6eaf138de7889928b8b
 * are released under the following license:
 *
 * Copyright (C) 2013 - 2018, Logical Clocks AB and RISE SICS AB. All rights reserved
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package io.hops.hopsworks.api.tensorflow;

import io.hops.hopsworks.api.kibana.ProxyServlet;
import io.hops.hopsworks.common.dao.jobhistory.YarnApplicationstate;
import io.hops.hopsworks.common.dao.jobhistory.YarnApplicationstateFacade;
import io.hops.hopsworks.common.dao.project.team.ProjectTeam;
import io.hops.hopsworks.common.dao.tensorflow.TensorBoard;
import io.hops.hopsworks.common.dao.tensorflow.TensorBoardFacade;
import io.hops.hopsworks.common.dao.user.UserFacade;
import io.hops.hopsworks.common.dao.user.Users;
import io.hops.hopsworks.common.exception.ProjectException;
import io.hops.hopsworks.common.hdfs.HdfsUsersController;
import io.hops.hopsworks.common.project.ProjectController;
import io.hops.hopsworks.common.project.ProjectDTO;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.http.client.utils.URIUtils;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Response;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TensorboardProxyServlet extends ProxyServlet {

    @EJB
    private YarnApplicationstateFacade yarnApplicationstateFacade;
    @EJB
    private UserFacade userFacade;
    @EJB
    private HdfsUsersController hdfsUsersBean;
    @EJB
    private ProjectController projectController;
    @EJB
    private TensorBoardFacade tensorBoardFacade;

    private final static Logger LOGGER = Logger.getLogger(TensorboardProxyServlet.class.getName());

    // A request will come in with the format: 
    // http://127.0.0.1:8080/hopsworks-api/tensorboard/application_1507065031551_0005/hopsworks0:59460/#graphs
    // 
    @Override
    protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
            throws ServletException, IOException {
        String email = servletRequest.getUserPrincipal().getName();
        LOGGER.log(Level.FINE, "Request URL: {0}", servletRequest.getRequestURL());

        String uri = servletRequest.getRequestURI();
        // valid hostname regex:
        // https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
        Pattern urlPattern = Pattern.compile("([a-zA-Z0-9\\-\\.]{2,255}:[0-9]{4,6})(/.*$)");
        Matcher urlMatcher = urlPattern.matcher(uri);
        String hostPortPair = "";
        String uriToFinish = "/";
        if (urlMatcher.find()) {
            hostPortPair = urlMatcher.group(1);
            uriToFinish = urlMatcher.group(2);
        }
        if (hostPortPair.isEmpty()) {
            throw new ServletException("Couldn't extract host:port from: " + servletRequest.getRequestURI());
        }

        Pattern appPattern = Pattern.compile("(application_.*?_\\d*)");
        Matcher appMatcher = appPattern.matcher(servletRequest.getRequestURI());

        Pattern elasticPattern = Pattern.compile("(experiments)");
        Matcher elasticMatcher = elasticPattern.matcher(servletRequest.getRequestURI());
        if (elasticMatcher.find()) {

            List<TensorBoard> TBList = tensorBoardFacade.findByUserEmail(email);
            if (TBList == null) {
                servletResponse.sendError(Response.Status.FORBIDDEN.getStatusCode(),
                        "This TensorBoard is not running right now");
            }
            boolean foundTB = false;
            for (TensorBoard tb : TBList) {
                if (tb.getEndpoint().equals(hostPortPair)) {
                    foundTB = true;
                    break;
                }
            }

            if (!foundTB) {
                servletResponse.sendError(Response.Status.FORBIDDEN.getStatusCode(),
                        "This TensorBoard is not running right now");
                return;
            }

            targetUri = uriToFinish;

            String theHost = "http://" + hostPortPair;
            URI targetUriHost;
            try {
                targetUriObj = new URI(targetUri);
                targetUriHost = new URI(theHost);
            } catch (Exception e) {
                throw new ServletException("Trying to process targetUri init parameter: ", e);
            }
            targetHost = URIUtils.extractHost(targetUriHost);
            servletRequest.setAttribute(ATTR_TARGET_URI, targetUri);
            servletRequest.setAttribute(ATTR_TARGET_HOST, targetHost);
            servletRequest.setAttribute(ATTR_URI_FINISH, uriToFinish);
            servletRequest.setAttribute(ATTR_HOST_PORT, hostPortPair);

            try {
                super.service(servletRequest, servletResponse);
            } catch (IOException ex) {
                sendErrorResponse(servletResponse,
                        "This TensorBoard is not ready to serve requests right now, " + "try refreshing the page");
                return;
            }

        } else if (appMatcher.find()) {
            String appId = appMatcher.group(1);
            YarnApplicationstate appState = yarnApplicationstateFacade.findByAppId(appId);
            if (appState == null) {
                servletResponse.sendError(Response.Status.FORBIDDEN.getStatusCode(),
                        "You don't have the access right for this application");
                return;
            }
            String projectName = hdfsUsersBean.getProjectName(appState.getAppuser());
            ProjectDTO project;
            try {
                project = projectController.getProjectByName(projectName);
            } catch (ProjectException ex) {
                throw new ServletException(ex);
            }

            Users user = userFacade.findByEmail(email);

            boolean inTeam = false;
            for (ProjectTeam pt : project.getProjectTeam()) {
                if (pt.getUser().equals(user)) {
                    inTeam = true;
                    break;
                }
            }
            if (!inTeam) {
                servletResponse.sendError(Response.Status.FORBIDDEN.getStatusCode(),
                        "You don't have the access right for this application");
                return;
            }
            if (appState.getAppsmstate() != null
                    && (appState.getAppsmstate().equalsIgnoreCase(YarnApplicationState.FINISHED.toString())
                            || appState.getAppsmstate().equalsIgnoreCase(YarnApplicationState.KILLED.toString()))) {
                sendErrorResponse(servletResponse, "This TensorBoard has finished running");
                return;
            }
            targetUri = uriToFinish;

            String theHost = "http://" + hostPortPair;
            URI targetUriHost;
            try {
                targetUriObj = new URI(targetUri);
                targetUriHost = new URI(theHost);
            } catch (Exception e) {
                throw new ServletException("Trying to process targetUri init parameter: ", e);
            }
            targetHost = URIUtils.extractHost(targetUriHost);
            servletRequest.setAttribute(ATTR_TARGET_URI, targetUri);
            servletRequest.setAttribute(ATTR_TARGET_HOST, targetHost);
            servletRequest.setAttribute(ATTR_URI_FINISH, uriToFinish);
            servletRequest.setAttribute(ATTR_HOST_PORT, hostPortPair);

            try {
                super.service(servletRequest, servletResponse);
            } catch (IOException ex) {
                sendErrorResponse(servletResponse, "This TensorBoard is not running right now");
                return;
            }

        } else {
            servletResponse.sendError(Response.Status.FORBIDDEN.getStatusCode(),
                    "You don't have the access right for this application");
            return;
        }

    }

    private void sendErrorResponse(ServletResponse servletResponse, String message) throws IOException {
        servletResponse.setContentType("text/html");
        PrintWriter out = servletResponse.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title></title>");
        out.println("</head>");
        out.println("<body>");
        out.println(message);
        out.println("</body>");
        out.println("</html>");
    }

    /**
     * Reads the request URI from {@code servletRequest} and rewrites it,
     * considering targetUri.
     * It's used to make the new request.
     */
    @Override
    protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
        StringBuilder uri = new StringBuilder(500);
        String theUri = getTargetUri(servletRequest);
        uri.append(theUri);
        // Handle the path given to the servlet
        if (servletRequest.getPathInfo() != null) {//ex: /my/path.html
            String pathInfo = servletRequest.getPathInfo();
            pathInfo = pathInfo.substring(1);
            String targetUrl = ((String) servletRequest.getAttribute(ATTR_HOST_PORT))
                    + ((String) servletRequest.getAttribute(ATTR_URI_FINISH));
            if (pathInfo.contains(targetUrl)) {
                pathInfo = pathInfo.substring(pathInfo.indexOf(targetUrl) + targetUrl.length());
            } else {
                pathInfo = "";
            }
            uri.append(encodeUriQuery(pathInfo));
        }
        // Handle the query string & fragment
        //ex:(following '?'): name=value&foo=bar#fragment
        String queryString = servletRequest.getQueryString();
        String fragment = null;
        //split off fragment from queryString, updating queryString if found
        if (queryString != null) {
            int fragIdx = queryString.indexOf('#');
            if (fragIdx >= 0) {
                fragment = queryString.substring(fragIdx + 2); // '#!', not '#'
                //        fragment = queryString.substring(fragIdx + 1);
                queryString = queryString.substring(0, fragIdx);
            }
        }

        queryString = rewriteQueryStringFromRequest(servletRequest, queryString);
        if (queryString != null && queryString.length() > 0) {
            uri.append('?');
            uri.append(encodeUriQuery(queryString));
        }

        if (doSendUrlFragment && fragment != null) {
            uri.append('#');
            uri.append(encodeUriQuery(fragment));
        }
        return uri.toString();
    }

    public static String getHTML(String urlToRead) throws Exception {
        StringBuilder result = new StringBuilder();
        URL url = new URL(urlToRead);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line;
        while ((line = rd.readLine()) != null) {
            result.append(line);
        }
        rd.close();
        conn.disconnect();
        return result.toString();
    }

}