Package com.cloud.agent

Source Code of com.cloud.agent.VmmAgentShell$AgentBootStrapHandler

// 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 com.cloud.agent;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.naming.ConfigurationException;

import org.apache.log4j.Logger;

import com.cloud.agent.Agent.ExitStatus;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StartupVMMAgentCommand;
import com.cloud.agent.dao.StorageComponent;
import com.cloud.agent.dao.impl.PropertiesStorage;
import com.cloud.agent.transport.Request;
import com.cloud.resource.ServerResource;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.backoff.BackoffAlgorithm;
import com.cloud.utils.backoff.impl.ConstantTimeBackoff;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.MacAddress;
import com.cloud.utils.nio.HandlerFactory;
import com.cloud.utils.nio.Link;
import com.cloud.utils.nio.NioServer;
import com.cloud.utils.nio.Task;

/**
* Implementation of agent shell to run the agents on System Center Virtual Machine manager
**/

public class VmmAgentShell implements IAgentShell, HandlerFactory {

    private static final Logger s_logger = Logger.getLogger(VmmAgentShell.class.getName());
    private final Properties _properties = new Properties();
    private final Map<String, Object> _cmdLineProperties = new HashMap<String, Object>();
    private StorageComponent _storage;
    private BackoffAlgorithm _backoff;
    private String _version;
    private String _zone;
    private String _pod;
    private String _cluster;
    private String _host;
    private String _privateIp;
    private int _port;
    private int _proxyPort;
    private int _workers;
    private String _guid;
    static private NioServer _connection;
    static private int _listenerPort=9000;   
    private int _nextAgentId = 1;
    private volatile boolean _exit = false;
    private int _pingRetries;
    private final Thread _consoleProxyMain = null;
    private final List<Agent> _agents = new ArrayList<Agent>();

    public VmmAgentShell() {
    }

    @Override
    public Properties getProperties() {
        return _properties;
    }

    @Override
    public BackoffAlgorithm getBackoffAlgorithm() {
        return _backoff;
    }

    @Override
    public int getPingRetries() {
        return _pingRetries;
    }

    @Override
    public String getZone() {
        return _zone;
    }

    @Override
    public String getPod() {
        return _pod;
    }

    @Override
    public String getHost() {
        return _host;
    }

    @Override
    public String getPrivateIp() {
        return _privateIp;
    }

    @Override
    public int getPort() {
        return _port;
    }

    @Override
    public int getProxyPort() {
        return _proxyPort;
    }

    @Override
    public int getWorkers() {
        return _workers;
    }

    @Override
    public String getGuid() {
        return _guid;
    }

    @Override
    public void upgradeAgent(String url) {
        // TODO Auto-generated method stub

    }

    @Override
    public String getVersion() {
        return _version;
    }

    @Override
    public Map<String, Object> getCmdLineProperties() {
        // TODO Auto-generated method stub
        return _cmdLineProperties;
    }

    public String getProperty(String prefix, String name) {
        if(prefix != null)
            return _properties.getProperty(prefix + "." + name);

        return _properties.getProperty(name);
    }

    @Override
    public String getPersistentProperty(String prefix, String name) {
        if(prefix != null)
            return _storage.get(prefix + "." + name);
        return _storage.get(name);
    }

    @Override
    public void setPersistentProperty(String prefix, String name, String value) {
        if(prefix != null)
            _storage.persist(prefix + "." + name, value);
        else
            _storage.persist(name, value);   
    }

    private void loadProperties() throws ConfigurationException {
        final File file = PropertiesUtil.findConfigFile("agent.properties");
        if (file == null) {
            throw new ConfigurationException("Unable to find agent.properties.");
        }

        s_logger.info("agent.properties found at " + file.getAbsolutePath());

        try {
            _properties.load(new FileInputStream(file));
        } catch (final FileNotFoundException ex) {
            throw new CloudRuntimeException("Cannot find the file: " + file.getAbsolutePath(), ex);
        } catch (final IOException ex) {
            throw new CloudRuntimeException("IOException in reading " + file.getAbsolutePath(), ex);
        }
    }

    protected boolean parseCommand(final String[] args) throws ConfigurationException {
        String host = null;
        String workers = null;
        String port = null;
        String zone = null;
        String pod = null;
        String guid = null;
        for (int i = 0; i < args.length; i++) {
            final String[] tokens = args[i].split("=");
            if (tokens.length != 2) {
                System.out.println("Invalid Parameter: " + args[i]);
                continue;
            }

            // save command line properties
            _cmdLineProperties.put(tokens[0], tokens[1]);

            if (tokens[0].equalsIgnoreCase("port")) {
                port = tokens[1];
            } else if (tokens[0].equalsIgnoreCase("threads")) {
                workers = tokens[1];
            } else if (tokens[0].equalsIgnoreCase("host")) {
                host = tokens[1];
            } else if(tokens[0].equalsIgnoreCase("zone")) {
                zone = tokens[1];
            } else if(tokens[0].equalsIgnoreCase("pod")) {
                pod = tokens[1];
            } else if(tokens[0].equalsIgnoreCase("guid")) {
                guid = tokens[1];
            } else if(tokens[0].equalsIgnoreCase("eth1ip")) {
                _privateIp = tokens[1];
            }
        }

        if (port == null) {
            port = getProperty(null, "port");
        }

        _port = NumbersUtil.parseInt(port, 8250);

        _proxyPort = NumbersUtil.parseInt(getProperty(null, "consoleproxy.httpListenPort"), 443);

        if (workers == null) {
            workers = getProperty(null, "workers");
        }

        _workers = NumbersUtil.parseInt(workers, 5);

        if (host == null) {
            host = getProperty(null, "host");
        }

        if (host == null) {
            host = "localhost";
        }
        _host = host;

        if(zone != null)
            _zone = zone;
        else
            _zone = getProperty(null, "zone");
        if (_zone == null || (_zone.startsWith("@") && _zone.endsWith("@"))) {
            _zone = "default";
        }

        if(pod != null)
            _pod = pod;
        else
            _pod = getProperty(null, "pod");
        if (_pod == null || (_pod.startsWith("@") && _pod.endsWith("@"))) {
            _pod = "default";
        }

        if (_host == null || (_host.startsWith("@") && _host.endsWith("@"))) {
            throw new ConfigurationException("Host is not configured correctly: " + _host);
        }

        final String retries = getProperty(null, "ping.retries");
        _pingRetries  = NumbersUtil.parseInt(retries, 5);

        String value = getProperty(null, "developer");
        boolean developer = Boolean.parseBoolean(value);

        if(guid != null)
            _guid = guid;
        else
            _guid = getProperty(null, "guid");
        if (_guid == null) {
            if (!developer) {
                throw new ConfigurationException("Unable to find the guid");
            }
            _guid = MacAddress.getMacAddress().toString(":");
        }

        return true;
   

    private void launchAgentFromTypeInfo() throws ConfigurationException {
        String typeInfo = getProperty(null, "type");
        if (typeInfo == null) {
            s_logger.error("Unable to retrieve the type");
            throw new ConfigurationException("Unable to retrieve the type of this agent.");
        }
        s_logger.trace("Launching agent based on type=" + typeInfo);
    }   

    private void launchAgent() throws ConfigurationException {
        String resourceClassNames = getProperty(null, "resource");
        s_logger.trace("resource=" + resourceClassNames);
        if(resourceClassNames != null) {
            launchAgentFromClassInfo(resourceClassNames);
            return;
        }

        launchAgentFromTypeInfo();
    }   

    private void init(String[] args) throws ConfigurationException{

        final Class<?> c = this.getClass();
        _version = c.getPackage().getImplementationVersion();
        if (_version == null) {
            throw new CloudRuntimeException("Unable to find the implementation version of this agent");
        }
        s_logger.info("Implementation Version is " + _version);

        parseCommand(args);

        s_logger.info("Defaulting to using properties file for storage");
        _storage = new PropertiesStorage();
        _storage.configure("Storage", new HashMap<String, Object>());

        // merge with properties from command line to let resource access command line parameters
        for(Map.Entry<String, Object> cmdLineProp : getCmdLineProperties().entrySet()) {
            _properties.put(cmdLineProp.getKey(), cmdLineProp.getValue());
        }

        s_logger.info("Defaulting to the constant time backoff algorithm");
        _backoff = new ConstantTimeBackoff();
        _backoff.configure("ConstantTimeBackoff", new HashMap<String, Object>());
   

    private void launchAgentFromClassInfo(String resourceClassNames) throws ConfigurationException {
        String[] names = resourceClassNames.split("\\|");
        for(String name: names) {
            Class<?> impl;
            try {
                impl = Class.forName(name);
                final Constructor<?> constructor = impl.getDeclaredConstructor();
                constructor.setAccessible(true);
                ServerResource resource = (ServerResource)constructor.newInstance();
                launchAgent(getNextAgentId(), resource);
            } catch (final ClassNotFoundException e) {
                throw new ConfigurationException("Resource class not found: " + name);
            } catch (final SecurityException e) {
                throw new ConfigurationException("Security excetion when loading resource: " + name);
            } catch (final NoSuchMethodException e) {
                throw new ConfigurationException("Method not found excetion when loading resource: " + name);
            } catch (final IllegalArgumentException e) {
                throw new ConfigurationException("Illegal argument excetion when loading resource: " + name);
            } catch (final InstantiationException e) {
                throw new ConfigurationException("Instantiation excetion when loading resource: " + name);
            } catch (final IllegalAccessException e) {
                throw new ConfigurationException("Illegal access exception when loading resource: " + name);
            } catch (final InvocationTargetException e) {
                throw new ConfigurationException("Invocation target exception when loading resource: " + name);
            }
        }
    }

    private void launchAgent(int localAgentId, ServerResource resource) throws ConfigurationException {
        // we don't track agent after it is launched for now
        Agent agent = new Agent(this, localAgentId, resource);
        _agents.add(agent);
        agent.start();
    }

    public synchronized int getNextAgentId() {
        return _nextAgentId++;
    }

    private void run(String[] args) {

        try {
            System.setProperty("java.net.preferIPv4Stack","true");     
            loadProperties();
            init(args);

            String instance = getProperty(null, "instance");
            if (instance == null) {
                instance = "";
            } else {
                instance += ".";
            }

            // TODO need to do this check. For Agentshell running on windows needs different approach
            //final String run = "agent." + instance + "pid";
            //s_logger.debug("Checking to see if " + run + "exists.");
            //ProcessUtil.pidCheck(run);         


            // TODO: For Hyper-V agent.properties need to be revamped to support multiple agents
            // corresponding to multiple clusters but running on a SCVMM host

            // read the persistent storage and launch the agents
            //launchAgent();

            // FIXME get rid of this approach of agent listening for boot strap commands from the management server

            // now listen for bootstrap request from the management server and launch agents
            _connection = new NioServer("VmmAgentShell", _listenerPort, 1, this);
            _connection.start();
            s_logger.info("SCVMM agent is listening on port " +_listenerPort + " for bootstrap command from management server");
            while(_connection.isRunning());
        } catch(final ConfigurationException e) {
            s_logger.error("Unable to start agent: " + e.getMessage());
            System.out.println("Unable to start agent: " + e.getMessage());
            System.exit(ExitStatus.Configuration.value());
        } catch (final Exception e) {
            s_logger.error("Unable to start agent: ", e);
            System.out.println("Unable to start agent: " + e.getMessage());
            System.exit(ExitStatus.Error.value());
        }
    }

    @Override
    public Task create(com.cloud.utils.nio.Task.Type type, Link link,
            byte[] data) {
        return new AgentBootStrapHandler(type, link, data);
    }

    public void stop() {
        _exit = true;
        if(_consoleProxyMain != null) {
            _consoleProxyMain.interrupt();
        }
    } 

    public static void main(String[] args) {

        VmmAgentShell shell = new VmmAgentShell();
        Runtime.getRuntime().addShutdownHook(new ShutdownThread(shell));   
        shell.run(args);
    }  

    // class to handle the bootstrap command from the management server
    private class AgentBootStrapHandler extends Task {

        public AgentBootStrapHandler(Task.Type type, Link link, byte[] data) {
            super(type, link, data);
        }

        @Override
        protected void doTask(Task task) throws Exception {
            final Type type = task.getType();
            s_logger.info("recieved task of type "+ type.toString() +" to handle in BootStrapTakHandler");
            if (type == Task.Type.DATA)
            {
                final byte[] data = task.getData();
                final Request request = Request.parse(data);
                final Command cmd = request.getCommand();

                if (cmd instanceof StartupVMMAgentCommand) {

                    StartupVMMAgentCommand vmmCmd = (StartupVMMAgentCommand) cmd;

                    _zone = Long.toString(vmmCmd.getDataCenter());
                    _cmdLineProperties.put("zone", _zone);

                    _pod = Long.toString(vmmCmd.getPod());
                    _cmdLineProperties.put("pod", _pod);

                    _cluster = vmmCmd.getClusterName();
                    _cmdLineProperties.put("cluster", _cluster);

                    _guid = vmmCmd.getGuid();
                    _cmdLineProperties.put("guid", _guid);

                    _host = vmmCmd.getManagementServerIP();
                    _port =  NumbersUtil.parseInt(vmmCmd.getport(), 8250);

                    s_logger.info("Recieved boot strap command from management server with parameters " +
                            " Zone:"+  _zone + " "+
                            " Cluster:"+ _cluster + " "+
                            " pod:"+_pod + " "+
                            " host:"+ _host +" "+
                            " port:"+_port);

                    launchAgentFromClassInfo("com.cloud.hypervisor.hyperv.resource.HypervResource");

                    // TODO: persist the info in agent.properties for agent restarts
                }
            }
        }
    }

    private static class ShutdownThread extends Thread {
        VmmAgentShell _shell;
        public ShutdownThread(VmmAgentShell shell) {
            this._shell = shell;
        }

        @Override
        public void run() {
            _shell.stop();
        }
    } 

}
TOP

Related Classes of com.cloud.agent.VmmAgentShell$AgentBootStrapHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.