com.cloud.agent.vmdata.JettyVmDataServer.java Source code

Java tutorial

Introduction

Here is the source code for com.cloud.agent.vmdata.JettyVmDataServer.java

Source

// Copyright 2012 Citrix Systems, Inc. Licensed under the
// Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License.  Citrix Systems, Inc.
// reserves all rights not expressly granted by 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.
// 
// Automatically generated by addcopyright.py at 04/03/2012
package com.cloud.agent.vmdata;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.File;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.Local;
import javax.naming.ConfigurationException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.DefaultHandler;
import org.mortbay.jetty.handler.HandlerList;
import org.mortbay.jetty.handler.ResourceHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.thread.QueuedThreadPool;

import com.cloud.agent.api.Answer;
import com.cloud.agent.api.routing.VmDataCommand;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.network.Networks.TrafficType;
import com.cloud.storage.JavaStorageLayer;
import com.cloud.storage.StorageLayer;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.Script;

/**
 * Serves vm data using embedded Jetty server
 * 
 */
@Local(value = { VmDataServer.class })
public class JettyVmDataServer implements VmDataServer {
    private static final Logger s_logger = Logger.getLogger(JettyVmDataServer.class);

    public static final String USER_DATA = "user-data";
    public static final String META_DATA = "meta-data";
    protected String _vmDataDir;
    protected Server _jetty;
    protected String _hostIp;
    protected Map<String, String> _ipVmMap = new HashMap<String, String>();
    protected StorageLayer _fs = new JavaStorageLayer();

    public class VmDataServlet extends HttpServlet {

        private static final long serialVersionUID = -1640031398971742349L;

        JettyVmDataServer _vmDataServer;
        String _dataType; // userdata or meta-data

        public VmDataServlet(JettyVmDataServer dataServer, String dataType) {
            this._vmDataServer = dataServer;
            this._dataType = dataType;
        }

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            int port = req.getServerPort();
            if (port != 80 && port != 8000) {
                resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Request not understood");
                return;
            }
            if (_dataType.equalsIgnoreCase(USER_DATA)) {
                handleUserData(req, resp);
            } else if (_dataType.equalsIgnoreCase(META_DATA)) {
                handleMetaData(req, resp);
            }
        }

        protected void handleUserData(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            String metadataItem = req.getPathInfo();
            String requester = req.getRemoteAddr();
            resp.setContentType("text/html");
            resp.setStatus(HttpServletResponse.SC_OK);
            String data = null;
            if (metadataItem != null) {
                String[] path = metadataItem.split("/");
                if (path.length > 1) {
                    metadataItem = path[1];
                }
            }

            if (metadataItem != null)
                data = _vmDataServer.getVmDataItem(requester, metadataItem);

            if (data != null) {
                resp.getWriter().print(data);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
                resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Request not found");
            }

        }

        protected void handleMetaData(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            String metadataItem = req.getPathInfo();
            String requester = req.getRemoteAddr();
            resp.setContentType("text/html");
            resp.setStatus(HttpServletResponse.SC_OK);
            String metaData = _vmDataServer.getVmDataItem(requester, metadataItem);
            if (metaData != null) {
                resp.getWriter().print(_vmDataServer.getVmDataItem(requester, metadataItem));
            } else {
                resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Request not found");
            }
        }

    }

    @Override
    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
        boolean success = true;
        try {
            int vmDataPort = 80;
            int fileservingPort = 8000;
            _vmDataDir = (String) params.get("vm.data.dir");
            String port = (String) params.get("vm.data.port");
            if (port != null) {
                vmDataPort = Integer.parseInt(port);
            }
            port = (String) params.get("file.server.port");
            if (port != null) {
                fileservingPort = Integer.parseInt(port);
            }
            _hostIp = (String) params.get("host.ip");

            if (_vmDataDir == null) {
                _vmDataDir = "/var/www/html";
            }
            success = _fs.mkdirs(_vmDataDir);
            success = success && buildIpVmMap();
            if (success) {
                setupJetty(vmDataPort, fileservingPort);
            }
        } catch (Exception e) {
            s_logger.warn("Failed to configure jetty", e);
            throw new ConfigurationException("Failed to configure jetty!!");
        }
        return success;
    }

    protected boolean buildIpVmMap() {
        String[] dirs = _fs.listFiles(_vmDataDir);
        for (String dir : dirs) {
            String[] path = dir.split("/");
            String vm = path[path.length - 1];
            if (vm.startsWith("i-")) {
                String[] dataFiles = _fs.listFiles(dir);
                for (String dfile : dataFiles) {
                    String path2[] = dfile.split("/");
                    String ipv4file = path2[path2.length - 1];
                    if (ipv4file.equalsIgnoreCase("local-ipv4")) {
                        try {
                            BufferedReader input = new BufferedReader(new FileReader(dfile));
                            String line = null;
                            while ((line = input.readLine()) != null) {
                                if (NetUtils.isValidIp(line)) {
                                    _ipVmMap.put(line, vm);
                                    s_logger.info("Found ip " + line + " for vm " + vm);
                                } else {
                                    s_logger.info("Invalid ip " + line + " for vm " + vm);
                                }
                            }
                        } catch (FileNotFoundException e) {
                            s_logger.warn("Failed to find file " + dfile);
                        } catch (IOException e) {
                            s_logger.warn("Failed to get ip address of " + vm);
                        }

                    }
                }
            }
        }
        return true;
    }

    public String getVmDataItem(String requester, String dataItem) {
        String vmName = _ipVmMap.get(requester);
        if (vmName == null) {
            return null;
        }
        String vmDataFile = _vmDataDir + File.separator + vmName + File.separator + dataItem;
        try {
            BufferedReader input = new BufferedReader(new FileReader(vmDataFile));
            StringBuilder result = new StringBuilder();
            String line = null;
            while ((line = input.readLine()) != null) {
                result.append(line);
            }
            input.close();
            return result.toString();
        } catch (FileNotFoundException e) {
            s_logger.warn("Failed to find requested file " + vmDataFile);
            return null;
        } catch (IOException e) {
            s_logger.warn("Failed to read requested file " + vmDataFile);
            return null;
        }
    }

    private void setupJetty(int vmDataPort, int fileservingPort) throws Exception {
        _jetty = new Server();

        SelectChannelConnector connector0 = new SelectChannelConnector();
        connector0.setHost(_hostIp);
        connector0.setPort(fileservingPort);
        connector0.setMaxIdleTime(30000);
        connector0.setRequestBufferSize(8192);

        SelectChannelConnector connector1 = new SelectChannelConnector();
        connector1.setHost(_hostIp);
        connector1.setPort(vmDataPort);
        connector1.setThreadPool(new QueuedThreadPool(5));
        connector1.setMaxIdleTime(30000);
        connector1.setRequestBufferSize(8192);

        _jetty.setConnectors(new Connector[] { connector0, connector1 });

        Context root = new Context(_jetty, "/latest", Context.SESSIONS);
        root.setResourceBase(_vmDataDir);
        root.addServlet(new ServletHolder(new VmDataServlet(this, USER_DATA)), "/*");

        ResourceHandler resource_handler = new ResourceHandler();
        resource_handler.setResourceBase("/var/lib/images/");

        HandlerList handlers = new HandlerList();
        handlers.setHandlers(new Handler[] { root, resource_handler, new DefaultHandler() });
        _jetty.setHandler(handlers);

        _jetty.start();
        // _jetty.join();
    }

    @Override
    public boolean start() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean stop() {
        return true;
    }

    @Override
    public String getName() {
        return "JettyVmDataServer";
    }

    @Override
    public Answer handleVmDataCommand(VmDataCommand cmd) {
        String vmDataDir = _vmDataDir + File.separator + cmd.getVmName();

        Script.runSimpleBashScript("rm -rf " + vmDataDir);
        _fs.mkdirs(vmDataDir);

        for (String[] item : cmd.getVmData()) {
            try {
                _fs.create(vmDataDir, item[1]);
                String vmDataFile = vmDataDir + File.separator + item[1];
                byte[] data;
                if (item[2] != null) {
                    if (item[1].equals("user-data")) {
                        data = Base64.decodeBase64(item[2]);
                    } else {
                        data = item[2].getBytes();
                    }
                    if (data != null && data.length > 0) {
                        FileOutputStream writer = new FileOutputStream(vmDataFile);
                        writer.write(data);
                        writer.close();
                    }
                }
            } catch (IOException e) {
                s_logger.warn("Failed to write vm data item " + item[1], e);
                return new Answer(cmd, false, "Failed to write vm data item " + item[1]);
            }
        }
        return new Answer(cmd);

    }

    @Override
    public void handleVmStarted(VirtualMachineTO vm) {
        for (NicTO nic : vm.getNics()) {
            if (nic.getType() == TrafficType.Guest) {
                if (nic.getIp() != null) {
                    String ipv4File = _vmDataDir + File.separator + vm.getName() + File.separator + "local-ipv4";
                    try {
                        _fs.create(_vmDataDir + File.separator + vm.getName(), "local-ipv4");
                        BufferedWriter writer = new BufferedWriter(new FileWriter(ipv4File));
                        writer.write(nic.getIp());
                        _ipVmMap.put(nic.getIp(), vm.getName());
                        writer.close();
                    } catch (IOException e) {
                        s_logger.warn("Failed to create or write to local-ipv4 file " + ipv4File, e);
                    }

                }

            }
        }
    }

    @Override
    public void handleVmStopped(String vmName) {
        String vmDataDir = _vmDataDir + File.separator + vmName;
        Script.runSimpleBashScript("rm -rf " + vmDataDir);
    }
}