All Downloads are FREE. Search and download functionalities are using the official Maven repository.

automately.core.Automately Maven / Gradle / Ivy

There is a newer version: 1.8.8
Show newest version
package automately.core;

import automately.core.data.Job;
import automately.core.data.Meta;
import automately.core.data.User;
import automately.core.file.VirtualFile;
import automately.core.file.VirtualFileService;
import automately.core.services.api.ApiServer;
import automately.core.services.container.ContainerService;
import automately.core.services.core.AutomatelyService;
import automately.core.services.ssh.SSHDaemonService;
import automately.core.services.job.JobServer;
import automately.core.services.job.script.objects.network.http.HttpServerService;
import automately.core.services.sdk.SdkSockJSServer;
import automately.core.services.sdk.eventbus.SdkAuthManager;
import automately.core.services.sdk.eventbus.SdkEventManager;
import automately.core.data.UserData;
import com.hazelcast.core.IMap;
import io.jsync.app.ClusterApp;
import io.jsync.app.core.Cluster;
import io.jsync.app.core.Config;
import io.jsync.app.core.Logger;
import io.jsync.app.core.service.ClusterService;
import io.jsync.json.JsonObject;
import io.jsync.utils.Token;
import org.apache.commons.lang3.ArrayUtils;

import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Automately is a {@link io.jsync.app.ClusterApp}
 */
public class Automately extends ClusterApp {

    static {
        // By default we don't want hazelcast to phone home
        System.setProperty("hazelcast.phone.home.enabled", "false");
        System.setProperty("async.pool.eventloop.size", String.valueOf(Runtime.getRuntime().availableProcessors() * 5));
        System.setProperty("async.pool.worker.size", String.valueOf(Runtime.getRuntime().availableProcessors() * 20));
    }

    /**
     * Running this will result in the initialization of the default Automately instance
     * and will join the cluster by default.
     *
     * @param args the jcluster arguments that you want to use
     * @throws Exception
     */
    public static void main(final String[] args) {
        System.out.println("Automately Core Version: " + getVersion());
        // We must initialize the jsync.io cluster app properly
        ClusterApp.initialize(new Automately(), ArrayUtils.add(args, "--join"));
    }

    /**
     * getBackendVersion() is a useful method to return the of the Automately Backend.
     * @return
     */
    public static String getVersion() {
        try {
            Properties properties = new Properties();
            properties.load(Automately.class.getResourceAsStream("application.properties"));
            return String.valueOf(properties.get("automately.core.version"));
        } catch (Exception ignored) {
        }
        return "debugBuild";
    }

    @Override
    public void prepareConfig(Config config) {
        if (config.isDefault()) {
            config.setRole("all");
        }
        if (!config.rawConfig().containsField("automately")) {
            config.rawConfig().putObject("automately", new JsonObject());
        }
        if (!config.rawConfig().getObject("automately").containsField("core")) {
            config.rawConfig().getObject("automately")
                    .putObject("core", new JsonObject());
        }

    }

    @Override
    public void prepareCluster(Cluster cluster) {

        Logger logger = cluster().logger();

        /**
         * This {@link io.jsync.app.core.ClusterService} is required so we can initialize some things
         * at the startup of the cluster. This is IMPORTANT.
         */
        ClusterService baseService = new AutomatelyService() {
            @Override
            public String name() {
                return "AutomatelyBaseServices";
            }

            @Override
            public void start(Cluster cluster) {

                logger.info("Initializing the default data indexes...");

                IMap users = cluster().data().persistentMap("users");
                IMap userMeta = cluster().data().persistentMap("users.meta");
                IMap jobs = cluster().data().persistentMap("jobs");
                IMap files = cluster().data().persistentMap("files");

                users.addIndex("token", false);
                users.addIndex("username", false);
                users.addIndex("created", true);

                userMeta.addIndex("userToken", false);
                userMeta.addIndex("key", false);

                jobs.addIndex("userToken", false);
                jobs.addIndex("token", false);
                jobs.addIndex("service", false);
                jobs.addIndex("lite", false);
                jobs.addIndex("status", false);
                jobs.addIndex("updated", true);

                files.addIndex("userToken", false);
                files.addIndex("token", false);
                files.addIndex("name", false);
                files.addIndex("pathAlias", false);
                files.addIndex("updated", true);
                files.addIndex("isPublic", false);

                logger.info("Checking the cluster for \"admin\" user.");

                // This line will ensure that all the user data is loaded in the cluster
                // We do this just to make sure that it happens. This is necessarily needed.
                cluster.data().persistentMap("users");

                // This basically tells the cluster
                if(!cluster.hazelcast().getPartitionService().isClusterSafe()){
                    // Let's go ahead and start up some stuff
                    // If the cluster is big it may take up to 10 minutes for it to be ready
                    cluster.hazelcast().getPartitionService().forceLocalMemberToBeSafe(10, TimeUnit.MINUTES);
                }

                // Honestly we really don't care what server we are.
                // We still need a darn admin user.
                if (UserData.getUserByUsername("admin") == null) { // We want to ensure the data member creates this user

                    logger.warn("The \"admin\" user was not found so we are creating it for you.");

                    User user = new User();
                    user.username = "admin";
                    user.admin = true;
                    user.enabled = true;
                    users().set(user.token(), user);

                    // For security reasons we want to generate a random password.
                    String defaultPassword = Token.generateToken().toString() + Token.generateToken().toString();

                    UserData.setUserPassword(user, defaultPassword);
                    UserData.setMetaDefaults(user);

                    logger.info("The default \"admin\" user password is \"" + defaultPassword + "\".");

                    logger.info("The \"admin\" user private key is " + user.key);
                    logger.info("The \"admin\" user public key is " + user.publicKey);
                }

                User adminUser = UserData.getUserByUsername("admin");

                if (adminUser != null) {

                    // This is a failsafe just in case a password was not set.
                    if (!UserData.containsMeta(adminUser, "password")) {
                        String defaultPassword = Token.generateToken().toString() + Token.generateToken().toString();

                        logger.info("The default \"admin\" user password is \"" + defaultPassword + "\".");

                        UserData.setUserPassword(adminUser, defaultPassword);
                        UserData.setMetaDefaults(adminUser);
                    }
                }

                if (!cluster.data().getMap("global.temp.data").containsKey("systemStart")) {
                    cluster.data().getMap("global.temp.data").put("systemStart", new Date().getTime());
                }

            }

            @Override
            public void stop() {

            }

        };

        try {

            Config config = cluster.config();

            cluster.addService(baseService);

            /**
             * Add VirtualFileSupport. This needs to be on every member of the cluster and loaded before any other member
             */
            cluster.addService(new VirtualFileService());
            cluster.addService(new HttpServerService());

            // This service is very important for container support
            // and only needs to be started on members utilizing the JobServer.
            if(config.isAll() || config.isRole("job")){
                cluster.addService(new ContainerService());
            }

            // JCluster Roles: default, all, client, data

            // Automately Roles: all, api, job, screenshot

            // All members of the cluster have the JobServer service
            // We don't need to add special services for the job
            cluster.addService(new JobServer());

            // TODO add a hazelcast only member

            if (config.isRole("api")) {
                cluster.addService(new SSHDaemonService());

                cluster.addService(new ApiServer());

                cluster.addService(new SdkAuthManager());
                cluster.addService(new SdkEventManager());
                cluster.addService(new SdkSockJSServer());

            } else if (config.isRole("sdk")) {
                cluster.addService(new SdkAuthManager());
                cluster.addService(new SdkEventManager());
                cluster.addService(new SdkSockJSServer());

            } else if (config.isAll()) {
                // Experimental support for now
                cluster.addService(new SSHDaemonService());

                // API Server
                cluster.addService(new ApiServer());
                // SDK Server
                cluster.addService(new SdkAuthManager());
                cluster.addService(new SdkEventManager());
                cluster.addService(new SdkSockJSServer());
            }

        } catch (Exception e) {
            throw new RuntimeException("There was an issue while attempting to prepare the cluster.", e);
        }

    }


    /**
     * This is a helper method to return the core automately configuration
     *
     * @return returns a JsonObject that contains all the data in {automately:{core:{}}}
     */
    private JsonObject coreConfig() {
        return cluster().config().rawConfig().getObject("automately").getObject("core");
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy