org.apache.stratos.cloud.controller.publisher.CartridgeInstanceDataPublisherTask.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.stratos.cloud.controller.publisher.CartridgeInstanceDataPublisherTask.java

Source

/*
*  Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*  WSO2 Inc. 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.stratos.cloud.controller.publisher;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.databridge.agent.thrift.Agent;
import org.wso2.carbon.databridge.agent.thrift.DataPublisher;
import org.wso2.carbon.databridge.agent.thrift.conf.AgentConfiguration;
import org.wso2.carbon.databridge.commons.Event;
import org.wso2.carbon.databridge.commons.exception.NoStreamDefinitionExistException;
import org.wso2.carbon.ntask.core.Task;
import org.apache.stratos.cloud.controller.exception.CloudControllerException;
import org.apache.stratos.cloud.controller.runtime.FasterLookUpDataHolder;
import org.apache.stratos.cloud.controller.util.CloudControllerConstants;
import org.apache.stratos.cloud.controller.util.CartridgeInstanceData;
import org.apache.stratos.cloud.controller.util.IaasContext;
import org.apache.stratos.cloud.controller.util.IaasProvider;
import org.apache.stratos.cloud.controller.util.ServiceContext;
import org.wso2.carbon.utils.CarbonUtils;

import com.google.common.collect.MapDifference;
import com.google.common.collect.MapDifference.ValueDifference;
import com.google.common.collect.Maps;

public class CartridgeInstanceDataPublisherTask implements Task {

    private static final Log log = LogFactory.getLog(CartridgeInstanceDataPublisherTask.class);
    private static DataPublisher dataPublisher;
    private static String streamId;
    private static final String cloudControllerEventStreamVersion = "1.0.0";
    private static List<CartridgeInstanceData> dataToBePublished;

    protected enum NodeStatus {
        PENDING, RUNNING, SUSPENDED, TERMINATED, ERROR, UNRECOGNIZED
    };

    @Override
    public void execute() {

        publish();
    }

    public static void publish() {
        if (FasterLookUpDataHolder.getInstance().isPublisherRunning() ||
        // this is a temporary fix to avoid task execution - limitation with ntask
                !FasterLookUpDataHolder.getInstance().getEnableBAMDataPublisher()) {
            return;
        }

        log.debug(CloudControllerConstants.DATA_PUB_TASK_NAME + " cycle started.");
        FasterLookUpDataHolder.getInstance().setPublisherRunning(true);
        dataToBePublished = new ArrayList<CartridgeInstanceData>();

        if (dataPublisher == null) {
            createDataPublisher();

            //If we cannot create a data publisher we should give up
            //this means data will not be published
            if (dataPublisher == null) {
                log.error("Data Publisher cannot be created or found.");
                release();
                return;
            }
        }

        if (streamId == null) {
            try {
                streamId = dataPublisher.findStream(CloudControllerConstants.CLOUD_CONTROLLER_EVENT_STREAM,
                        cloudControllerEventStreamVersion);
            } catch (NoStreamDefinitionExistException e) {
                log.info("Defining the event stream because it was not found in BAM");
                try {
                    defineStream();
                } catch (Exception ex) {
                    String msg = "Error occurred while defining the event stream for publishing Cloud Controller data. "
                            + ex.getMessage();
                    log.error(msg, ex);
                    //We do not want to proceed without an event stream. Therefore we return.
                    release();
                    return;
                }
            } catch (Exception exc) {
                log.error("Error occurred while searching for stream id. " + exc.getMessage(), exc);
                //We do not want to proceed without an event stream. Therefore we return.
                release();
                return;
            }
        }

        // build the new node - state Map
        Map<String, String> newNodeToStateMap;
        try {
            newNodeToStateMap = getNodeIdToStatusMap();
        } catch (Exception e) {

            release();
            throw new CloudControllerException(e.getMessage(), e);

        }

        // compare it with old map and populate data to be published with ones newly added
        // and once whose state got changed
        populateNewlyAddedOrStateChangedNodes(newNodeToStateMap);

        // issue events for the ones obtained from above
        for (CartridgeInstanceData dataObj : dataToBePublished) {
            StringBuffer temp = new StringBuffer("");

            String privateIpAddresses = "";
            // Concatenate private IP addresses
            for (String ip : dataObj.getMetaData().getPrivateAddresses()) {
                temp.append(ip + ",");
            }

            if (!"".equals(temp.toString())) {
                // remove comma at the end of the string
                privateIpAddresses = temp.toString().substring(0, temp.toString().length() - 1);
            }

            temp = new StringBuffer("");
            String publicIpAddresses = "";
            // Concatenate public IP addresses
            for (String ip : dataObj.getMetaData().getPublicAddresses()) {
                temp.append(ip + ",");
            }

            if (!"".equals(temp.toString())) {
                // remove comma at the end of the string
                publicIpAddresses = temp.toString().substring(0, temp.toString().length() - 1);
            }

            try {

                Event cloudControllerEvent = new Event(streamId, System.currentTimeMillis(), new Object[] {}, null,
                        new Object[] { dataObj.getNodeId(), dataObj.getType(), dataObj.getDomain(),
                                dataObj.getSubDomain(), dataObj.getAlias(), dataObj.getTenantRange(),
                                String.valueOf(dataObj.isMultiTenant()), dataObj.getIaas(), dataObj.getStatus(),
                                dataObj.getMetaData().getHostname(),
                                dataObj.getMetaData().getHardware().getHypervisor(),
                                String.valueOf(dataObj.getMetaData().getHardware().getRam()),
                                dataObj.getMetaData().getImageId(),
                                String.valueOf(dataObj.getMetaData().getLoginPort()),
                                dataObj.getMetaData().getOperatingSystem().getName(),
                                dataObj.getMetaData().getOperatingSystem().getVersion(),
                                dataObj.getMetaData().getOperatingSystem().getArch(),
                                String.valueOf(dataObj.getMetaData().getOperatingSystem().is64Bit()),
                                privateIpAddresses, publicIpAddresses });

                dataPublisher.publish(cloudControllerEvent);

                log.debug("Data published : " + cloudControllerEvent.toString());

            } catch (Exception e) {
                String msg = "Error occurred while publishing Cartridge instance event to BAM. ";
                log.error(msg, e);
                release();
                throw new CloudControllerException(msg, e);
            }

        }

        // replace old map with new one only if data is published
        FasterLookUpDataHolder.getInstance().setNodeIdToStatusMap(newNodeToStateMap);

        //TODO remove
        //        CassandraDataRetriever.init();
        //        CassandraDataRetriever.connect();
        //        HiveQueryExecutor hive = new HiveQueryExecutor();
        //        hive.createHiveTable();
        //        System.out.println("***********");
        //        for (String str : hive.getRunningNodeIds()) {
        //         
        //            System.out.println(str);
        //        }
        //        System.out.println("***********");
        release();
    }

    private static void release() {
        FasterLookUpDataHolder.getInstance().setPublisherRunning(false);
    }

    private static void defineStream() throws Exception {
        streamId = dataPublisher.defineStream("{" + "  'name':'"
                + CloudControllerConstants.CLOUD_CONTROLLER_EVENT_STREAM + "'," + "  'version':'"
                + cloudControllerEventStreamVersion + "'," + "  'nickName': 'cloud.controller',"
                + "  'description': 'Instances booted up by the Cloud Controller '," + "  'metaData':[],"
                + "  'payloadData':[" + "          {'name':'" + CloudControllerConstants.NODE_ID_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.CARTRIDGE_TYPE_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.DOMAIN_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.SUB_DOMAIN_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.ALIAS_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.TENANT_RANGE_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.IS_MULTI_TENANT_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.IAAS_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.STATUS_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.HOST_NAME_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.HYPERVISOR_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.RAM_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.IMAGE_ID_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.LOGIN_PORT_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.OS_NAME_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.OS_VERSION_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.OS_ARCH_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.OS_BIT_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.PRIV_IP_COL
                + "','type':'STRING'}," + "          {'name':'" + CloudControllerConstants.PUB_IP_COL
                + "','type':'STRING'}" + "  ]" + "}");

    }

    @Override
    public void init() {

        // this is a temporary fix to avoid task execution - limitation with ntask
        if (!FasterLookUpDataHolder.getInstance().getEnableBAMDataPublisher()) {
            log.debug("BAM data publisher is disabled. ");
            return;
        }

        if ((dataPublisher = FasterLookUpDataHolder.getInstance().getDataPublisher()) == null) {
            createDataPublisher();
        }
        streamId = FasterLookUpDataHolder.getInstance().getStreamId();

    }

    @Override
    public void setProperties(Map<String, String> arg0) {
    }

    private static void createDataPublisher() {
        //creating the agent
        AgentConfiguration agentConfiguration = new AgentConfiguration();

        ServerConfiguration serverConfig = CarbonUtils.getServerConfiguration();
        String trustStorePath = serverConfig.getFirstProperty("Security.TrustStore.Location");
        String trustStorePassword = serverConfig.getFirstProperty("Security.TrustStore.Password");
        String bamServerUrl = serverConfig.getFirstProperty("BamServerURL");
        String adminUsername = FasterLookUpDataHolder.getInstance().getBamUsername();
        String adminPassword = FasterLookUpDataHolder.getInstance().getBamPassword();

        System.setProperty("javax.net.ssl.trustStore", trustStorePath);
        System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);

        Agent agent = new Agent(agentConfiguration);

        try {
            dataPublisher = new DataPublisher(bamServerUrl, adminUsername, adminPassword, agent);
            FasterLookUpDataHolder.getInstance().setDataPublisher(dataPublisher);

        } catch (Exception e) {
            String msg = "Unable to create a data publisher to " + bamServerUrl
                    + ". Usage Agent will not function properly. ";
            log.error(msg, e);
            throw new CloudControllerException(msg, e);
        }

    }

    private static void bundleData(String key, String val, ServiceContext serviceCtxt) {

        CartridgeInstanceData instanceData = new CartridgeInstanceData();
        instanceData.setNodeId(key);
        instanceData.setStatus(val);
        instanceData.setDomain(serviceCtxt.getDomainName());
        instanceData.setSubDomain(serviceCtxt.getSubDomainName());
        instanceData.setAlias("".equals(serviceCtxt.getProperty(CloudControllerConstants.ALIAS_PROPERTY)) ? "NULL"
                : serviceCtxt.getProperty(CloudControllerConstants.ALIAS_PROPERTY));
        instanceData.setTenantRange("".equals(serviceCtxt.getProperty(CloudControllerConstants.TENANT_ID_PROPERTY))
                ? serviceCtxt.getTenantRange()
                : serviceCtxt.getProperty(CloudControllerConstants.TENANT_ID_PROPERTY));

        if (serviceCtxt.getCartridge() != null) {
            instanceData.setMultiTenant(serviceCtxt.getCartridge().isMultiTenant());

            for (IaasProvider iaas : serviceCtxt.getCartridge().getIaases()) {

                IaasContext ctxt = null;
                if ((ctxt = serviceCtxt.getIaasContext(iaas.getType())) == null) {
                    ctxt = serviceCtxt.addIaasContext(iaas.getType());
                }

                if (ctxt.didISpawn(key)) {
                    instanceData.setIaas(iaas.getType());
                    instanceData.setMetaData(ctxt.getNode(key));

                    // clear to be removed data
                    ctxt.removeToBeRemovedNodeId(key);

                    // if the node is terminated
                    if (val.equals(NodeStatus.TERMINATED.toString())) {
                        // since this node is terminated
                        FasterLookUpDataHolder.getInstance().removeNodeId(key);

                        // remove node meta data
                        ctxt.removeNodeMetadata(ctxt.getNode(key));
                    }

                    break;
                }
            }

            instanceData.setType(serviceCtxt.getCartridge().getType());
        } else {
            log.warn("Cartridge is null for Service Context : (domain: " + serviceCtxt.getDomainName()
                    + ", sub domain: " + serviceCtxt.getSubDomainName() + ")");
        }

        dataToBePublished.add(instanceData);

    }

    private static Map<String, String> getNodeIdToStatusMap() throws Exception {

        Map<String, String> statusMap = new HashMap<String, String>();

        // iterate through all ServiceContexts
        for (Iterator<?> it1 = FasterLookUpDataHolder.getInstance().getServiceContexts().entrySet().iterator(); it1
                .hasNext();) {
            @SuppressWarnings("unchecked")
            Map.Entry<String, Map<String, ServiceContext>> entry = (Map.Entry<String, Map<String, ServiceContext>>) it1
                    .next();

            Map<String, ServiceContext> map = (Map<String, ServiceContext>) entry.getValue();

            for (Iterator<ServiceContext> it2 = map.values().iterator(); it2.hasNext();) {
                ServiceContext subjectedSerCtxt = (ServiceContext) it2.next();

                if (subjectedSerCtxt != null && subjectedSerCtxt.getCartridge() != null) {
                    List<IaasProvider> iaases = subjectedSerCtxt.getCartridge().getIaases();

                    for (IaasProvider iaas : iaases) {

                        ComputeService computeService = iaas.getComputeService();

                        if (computeService == null) {
                            continue;
                        }

                        IaasContext ctxt = null;
                        if ((ctxt = subjectedSerCtxt.getIaasContext(iaas.getType())) == null) {
                            ctxt = subjectedSerCtxt.addIaasContext(iaas.getType());
                        }

                        // get list of node Ids
                        List<String> nodeIds = ctxt.getAllNodeIds();

                        if (nodeIds.isEmpty()) {

                            continue;
                        }

                        try {

                            // get all the nodes spawned by this IaasContext
                            Set<? extends ComputeMetadata> set = computeService.listNodes();

                            Iterator<? extends ComputeMetadata> iterator = set.iterator();

                            // traverse through all nodes of this ComputeService object
                            while (iterator.hasNext()) {
                                NodeMetadata nodeMetadata = (NodeMetadataImpl) iterator.next();

                                // if this node belongs to the requested domain
                                if (nodeIds.contains(nodeMetadata.getId())) {

                                    statusMap.put(nodeMetadata.getId(), nodeMetadata.getStatus().toString());

                                    ctxt.addNodeMetadata(nodeMetadata);
                                }

                            }

                        } catch (Exception e) {
                            log.error(e.getMessage(), e);
                            throw e;
                        }

                    }
                }
            }

        }
        return statusMap;

    }

    private static void populateNewlyAddedOrStateChangedNodes(Map<String, String> newMap) {

        MapDifference<String, String> diff = Maps.difference(newMap,
                FasterLookUpDataHolder.getInstance().getNodeIdToStatusMap());

        // adding newly added nodes
        Map<String, String> newlyAddedNodes = diff.entriesOnlyOnLeft();

        for (Iterator<?> it = newlyAddedNodes.entrySet().iterator(); it.hasNext();) {
            @SuppressWarnings("unchecked")
            Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
            String key = entry.getKey();
            String val = entry.getValue();
            ServiceContext ctxt = FasterLookUpDataHolder.getInstance().getServiceContext(key);

            log.debug("------ Node id: " + key + " --- node status: " + val + " -------- ctxt: " + ctxt);

            if (ctxt != null && key != null && val != null) {
                // bundle the data to be published
                bundleData(key, val, ctxt);
            }

        }

        // adding nodes with state changes
        Map<String, ValueDifference<String>> stateChangedNodes = diff.entriesDiffering();

        for (Iterator<?> it = stateChangedNodes.entrySet().iterator(); it.hasNext();) {
            @SuppressWarnings("unchecked")
            Map.Entry<String, ValueDifference<String>> entry = (Map.Entry<String, ValueDifference<String>>) it
                    .next();

            String key = entry.getKey();
            String newState = entry.getValue().leftValue();
            ServiceContext ctxt = FasterLookUpDataHolder.getInstance().getServiceContext(key);

            log.debug("------- Node id: " + key + " --- node status: " + newState + " -------- ctxt: " + ctxt);

            if (ctxt != null && key != null && newState != null) {
                // bundle the data to be published
                bundleData(key, newState, ctxt);
            }

        }

    }

}