<commit_before>/**
 * Elastic Grid
 * Copyright (C) 2008-2009 Elastic Grid, LLC.
 * 
 * This program 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.
 * 
 * This program 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 <http://www.gnu.org/licenses/>.
 */

package com.elasticgrid.amazon.boot;

import com.elasticgrid.config.EC2Configuration;
import com.elasticgrid.model.ClusterException;
import com.elasticgrid.model.ec2.EC2Node;
import com.elasticgrid.platforms.ec2.discovery.EC2ClusterLocator;
import com.xerox.amazonws.ec2.EC2Exception;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * Bootstrapper in charge of fetching the EC2 launch parameters and generating the EG configuration files.
 * The launch parameters are available in the <tt>/tmp/user-data</tt> file.
 *
 * @author <NAME>
 */
public class Bootstrapper {
    public static final String LAUNCH_PARAMETER_CLUSTER_NAME  = "CLUSTER_NAME";
    public static final String LAUNCH_PARAMETER_DROP_BUCKET   = "DROP_BUCKET";
    public static final String LAUNCH_PARAMETER_OVERRIDES_URL = "OVERRIDES_URL";
    public static final String LAUNCH_PARAMETER_YUM_PACKAGES  = "YUM_PACKAGES";
    public static final String LAUNCH_PARAMETER_ACCESS_ID     = "AWS_ACCESS_ID";
    public static final String LAUNCH_PARAMETER_SECRET_KEY    = "AWS_SECRET_KEY";
    public static final String LAUNCH_PARAMETER_EC2_SECURED   = "AWS_EC2_SECURED";
    public static final String LAUNCH_PARAMETER_SQS_SECURED   = "AWS_SQS_SECURED";
    public static final String LAUNCH_PARAMETER_EC2_KEYPAIR   = "AWS_EC2_KEYPAIR";
    public static final String LAUNCH_PARAMETER_EC2_AMI32     = "AWS_EC2_AMI32";
    public static final String LAUNCH_PARAMETER_EC2_AMI64     = "AWS_EC2_AMI64";

    public static final String LAUNCH_PARAMETERS_FILE = "/tmp/user-data";
    public static final String ELASTIC_GRID_CONFIGURATION_FILE = "config/eg.properties";

    private String egHome = System.getProperty("EG_HOME");

    private ScheduledExecutorService scheduler;

    public Bootstrapper() throws IOException, EC2Exception {
        // retreive EC2 launch parameters
        Properties launchParameters = fetchLaunchParameters();
        Properties egParameters = translateProperties(launchParameters);

        // save configuration into an Elastic Grid configuration file
        File file = saveConfiguration(egParameters);
        System.out.printf("Elastic Grid configuration file generated in '%s'\n", file.getAbsolutePath());

        // start Spring context
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/com/elasticgrid/amazon/boot/applicationContext.xml");

        // locate monitor node and write the location of the found monitor into $EG_HOME/config/monitor-host
        final EC2ClusterLocator locator = (EC2ClusterLocator) ctx.getBean("clusterLocator", EC2ClusterLocator.class);
        final String clusterName = launchParameters.getProperty(LAUNCH_PARAMETER_CLUSTER_NAME);

        // eventually wait for monitor to be up and running
        EC2Node monitor = null;
        scheduler = Executors.newSingleThreadScheduledExecutor();
        ScheduledFuture<EC2Node> future = scheduler.schedule(new LocateMonitorCallable(locator, clusterName), 0, TimeUnit.SECONDS);
        try {
            monitor = future.get();
        } catch (Exception e) {
            System.err.println("Could not find monitor host!");
            System.exit(-1);
        }

        try {
            InetAddress monitorHost = monitor.getAddress();
            String monitorHostAddress = monitorHost.getHostAddress();
            if (monitorHostAddress.equals(InetAddress.getLocalHost().getHostAddress())) {
                System.out.println("This host is going to be the new monitor!");
            } else {
                System.out.printf("Using monitor host: %s\n", monitorHost.getHostName());
                egParameters.put(EC2Configuration.EG_MONITOR_HOST, monitorHost.getHostName());
            }
            FileUtils.writeStringToFile(new File(egHome + File.separator + "config", "monitor-host"), monitorHost.getHostName());

            // get the currently running node
            Set<EC2Node> nodes = locator.findNodes(clusterName);
            EC2Node thisNode = null;
            for (EC2Node node : nodes) {
                if (node.getAddress().equals(InetAddress.getLocalHost()))
                    thisNode = node;
            }
            String profile = null;
            switch (thisNode.getProfile()) {
                case AGENT:
                    profile = "agent";
                    break;
                case MONITOR:
                    profile = "monitor";
                    break;
                case MONITOR_AND_AGENT:
                    profile = "monitor-and-agent";
                    break;
            }
            FileUtils.writeStringToFile(new File("/tmp/eg-node-to-start"), profile);
            System.out.printf("Local machine is morphed into a %s\n", profile);

            String overridesURL = "";
            if (launchParameters.containsKey(LAUNCH_PARAMETER_OVERRIDES_URL))
                overridesURL = launchParameters.getProperty(LAUNCH_PARAMETER_OVERRIDES_URL);
            FileUtils.writeStringToFile(new File("/tmp/overrides"), overridesURL);
        } catch (ClusterException e) {
            System.err.println("Could not find nodes in cluster!");
            System.exit(-1);
        }
    }

    /**
     * At boot time, a file is generated into {@link #LAUNCH_PARAMETERS_FILE}.
     * This method retreive the content of the file and parse it as if it was a Java configuration file.
     * @return the {@link Properties} object
     * @throws IOException if the file generated at boot time can't be found or read<commit_msg>Will it fix temporarly the problem?<commit_after>/**
 * Elastic Grid
 * Copyright (C) 2008-2009 Elastic Grid, LLC.
 * 
 * This program 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.
 * 
 * This program 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 <http://www.gnu.org/licenses/>.
 */

package com.elasticgrid.amazon.boot;

import com.elasticgrid.config.EC2Configuration;
import com.elasticgrid.config.GenericConfiguration;
import com.elasticgrid.model.ClusterException;
import com.elasticgrid.model.NodeProfile;
import com.elasticgrid.model.ec2.EC2Node;
import com.elasticgrid.model.ec2.EC2NodeType;
import com.elasticgrid.platforms.ec2.discovery.EC2ClusterLocator;
import com.xerox.amazonws.ec2.EC2Exception;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * Bootstrapper in charge of fetching the EC2 launch parameters and generating the EG configuration files.
 * The launch parameters are available in the <tt>/tmp/user-data</tt> file.
 *
 * @author <NAME>
 */
public class Bootstrapper {
    public static final String LAUNCH_PARAMETER_CLUSTER_NAME  = "CLUSTER_NAME";
    public static final String LAUNCH_PARAMETER_DROP_BUCKET   = "DROP_BUCKET";
    public static final String LAUNCH_PARAMETER_OVERRIDES_URL = "OVERRIDES_URL";
    public static final String LAUNCH_PARAMETER_YUM_PACKAGES  = "YUM_PACKAGES";
    public static final String LAUNCH_PARAMETER_ACCESS_ID     = "AWS_ACCESS_ID";
    public static final String LAUNCH_PARAMETER_SECRET_KEY    = "AWS_SECRET_KEY";
    public static final String LAUNCH_PARAMETER_EC2_SECURED   = "AWS_EC2_SECURED";
    public static final String LAUNCH_PARAMETER_SQS_SECURED   = "AWS_SQS_SECURED";
    public static final String LAUNCH_PARAMETER_EC2_KEYPAIR   = "AWS_EC2_KEYPAIR";
    public static final String LAUNCH_PARAMETER_EC2_AMI32     = "AWS_EC2_AMI32";
    public static final String LAUNCH_PARAMETER_EC2_AMI64     = "AWS_EC2_AMI64";

    public static final String LAUNCH_PARAMETERS_FILE = "/tmp/user-data";
    public static final String ELASTIC_GRID_CONFIGURATION_FILE = "config/eg.properties";

    private String egHome = System.getProperty("EG_HOME");

    private ScheduledExecutorService scheduler;

    public Bootstrapper() throws IOException, EC2Exception {
        // retreive EC2 launch parameters
        Properties launchParameters = fetchLaunchParameters();
        Properties egParameters = translateProperties(launchParameters);

        // save configuration into an Elastic Grid configuration file
        File file = saveConfiguration(egParameters);
        System.out.printf("Elastic Grid configuration file generated in '%s'\n", file.getAbsolutePath());

        // start Spring context
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/com/elasticgrid/amazon/boot/applicationContext.xml");
        final EC2ClusterLocator locator = (EC2ClusterLocator) ctx.getBean("clusterLocator", EC2ClusterLocator.class);
        final String clusterName = launchParameters.getProperty(LAUNCH_PARAMETER_CLUSTER_NAME);

        // get the currently running node
        EC2Node thisNode = null;
        String profile = null;
        try {
            Set<EC2Node> nodes = locator.findNodes(clusterName);
            for (EC2Node node : nodes) {
                if (node.getAddress().equals(InetAddress.getLocalHost()))
                    thisNode = node;
            }
            switch (thisNode.getProfile()) {
                case AGENT:
                    profile = "agent";
                    break;
                case MONITOR:
                    profile = "monitor";
                    break;
                case MONITOR_AND_AGENT:
                    profile = "monitor-and-agent";
                    break;
            }
            FileUtils.writeStringToFile(new File("/tmp/eg-node-to-start"), profile);
            System.out.printf("Local machine is morphed into a %s\n", profile);
        } catch (ClusterException e) {
            System.err.println("Could not find nodes in cluster!");
            System.exit(-1);
        }

        // eventually wait for monitor to be up and running
        EC2Node monitor = null;
        if ("agent".equals(profile)) {
            scheduler = Executors.newSingleThreadScheduledExecutor();
            ScheduledFuture<EC2Node> future = scheduler.schedule(new LocateMonitorCallable(locator, clusterName), 0, TimeUnit.SECONDS);
            try {
                monitor = future.get();
            } catch (Exception e) {
                System.err.println("Could not find monitor host!");
                System.exit(-1);
            }
        } else {
            monitor = thisNode;
        }

        InetAddress monitorHost = monitor.getAddress();
        String monitorHostAddress = monitorHost.getHostAddress();
        if (monitorHostAddress.equals(InetAddress.getLocalHost().getHostAddress())) {
            System.out.println("This host is going to be the new monitor!");
        } else {
            System.out.printf("Using monitor host: %s\n", monitorHost.getHostName());
            egParameters.put(EC2Configuration.EG_MONITOR_HOST, monitorHost.getHostName());
        }
        FileUtils.writeStringToFile(new File(egHome + File.separator + "config", "monitor-host"), monitorHost.getHostName());

        String overridesURL = "";
        if (launchParameters.containsKey(LAUNCH_PARAMETER_OVERRIDES_URL))
            overridesURL = launchParameters.getProperty(LAUNCH_PARAMETER_OVERRIDES_URL);
        FileUtils.writeStringToFile(new File("/tmp/overrides"), overridesURL);
    }

    /**
     * At boot time, a file is generated into {@link #LAUNCH_PARAMETERS_FILE}.
     * This method retreive the content of the file and parse it as if it was a Java configuration file.
     * @return the {@link Properties} object
     * @throws IOException if the file generated at boot time can't be found or read
{'fraction_non_alphanumeric': 0.08401846242607817, 'fraction_numerical': 0.006923409779316313, 'mean_word_length': 3.1332339791356185, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '987697', 'n_tokens_mistral': 3834, 'n_tokens_neox': 3777, 'n_words': 1040}