Package bear.plugins

Source Code of bear.plugins.ServerToolPlugin

/*
* Copyright (C) 2013 Andrey Chaschev.
*
* Licensed 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 bear.plugins;

import bear.console.AbstractConsole;
import bear.console.ConsoleCallbackResult;
import bear.console.ConsoleCallbackResultType;
import bear.context.Fun;
import bear.core.Env;
import bear.core.GlobalContext;
import bear.core.SessionContext;
import bear.core.except.NoSuchFileException;
import bear.main.event.NoticeEventToUI;
import bear.plugins.misc.*;
import bear.plugins.sh.SystemSession;
import bear.session.DynamicVariable;
import bear.session.Variables;
import bear.task.*;
import bear.vcs.CommandLineResult;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static bear.core.SessionContext.ui;
import static bear.session.Variables.*;
import static java.lang.String.format;

/**
* @author Andrey Chaschev chaschev@gmail.com
*/
public abstract class ServerToolPlugin extends ZippedToolPlugin {
    public static final org.apache.logging.log4j.Logger logger = LogManager.getLogger(ServerToolPlugin.class);

    protected UpstartPlugin upstart;
    protected FileWatchDogPlugin watchDog;
    protected ReleasesPlugin releases;

    public final DynamicVariable<String>
        projectPath = equalTo(bear.vcsBranchLocalPath).desc("Project root dir"),
        execName = concat(toolname, condition(bear.isNativeUnix, newVar("").temp(), newVar(".bat").temp()).desc("'play' or 'play.bat'")),
        instancePath = undefined(),
        instanceLogsPath = concat(bear.appLogsPath, "/", toolname, "-%s"),
        appName = concat(toolname, "-app"),
        instancePorts = newVar("9000"),
        user = equalTo(bear.sshUsername),
        group = equalTo(bear.sshUsername),
        userWithGroup = concat(user, ".", group),
        multiServiceName = concat(bear.name, "-%s"),
        singleServiceName = equalTo(bear.name),
        groupName = equalTo(bear.name),
        envString = newVar("production"),
        consoleLogPath = concat(instanceLogsPath, "/", envString, ".log"),
        execPath = equalTo(toolname);

    public final DynamicVariable<Env> env = convert(envString, toEnum(Env.class));

    public final DynamicVariable<Boolean> useUpstart = newVar(true);

    public final DynamicVariable<Function<ConfigureServiceInput, Void>> configureService = dynamic(new Fun<SessionContext, Function<ConfigureServiceInput, Void>>() {
        @Override
        public Function<ConfigureServiceInput, Void> apply(final SessionContext $) {
            return voidEmptyFunction();
        }
    });

    public final DynamicVariable<Function<String, String>> createScriptText = undefined();

    public final DynamicVariable<UpstartServices> customUpstart = dynamic(new Fun<SessionContext, UpstartServices>() {
        @Override
        public UpstartServices apply(SessionContext $) {
            List<String> ports = $.var(portsSplit);

            boolean single = ports.size() == 1;

            List<UpstartService> serviceList = new ArrayList<UpstartService>(ports.size());

            for (String port : ports) {
                $.sys.mkdirs(instancePath(port, $), format($.var(instanceLogsPath), port)).run();

                String scriptText = $.var(createScriptText).apply(port);

                UpstartService upstartService = new UpstartService(
                    single ? $.var(singleServiceName) : format($.var(multiServiceName), port),
                    $.var(bear.fullName),
                    scriptText
                ).setUser($.var(user));

                serviceList.add(upstartService.cd(instancePath(port, $)));

                $.var(configureService).apply(new ConfigureServiceInput(port, upstartService));
            }

            return new UpstartServices(
                single ? Optional.<String>absent() : Optional.of($.var(groupName)),
                serviceList
            );
        }
    });

    public final DynamicVariable<WatchDogGroup>
        watchStartDogGroup = newVar(null);

    public final DynamicVariable<Integer>
        startupTimeoutMs = equalTo(bear.buildTimeoutMs);

    public final DynamicVariable<Boolean>
        useWatchDog = newVar(true);

    public final DynamicVariable<List<String>> portsSplit = split(instancePorts, COMMA_SPLITTER);


    public final DynamicVariable<Boolean>
        clean = Variables.equalTo(bear.clean).desc("clean project before build");

    public ServerToolPlugin(GlobalContext global) {
        super(global);
    }

    @Override
    public void initPlugin() {
        super.initPlugin();
        instancePath.setEqualTo(concat(releases.currentReleaseLinkPath, "/instances/", toolname, "-%s"));
    }

    public void resetConsolePath(SessionContext $, String logPath) {
        $.sys.permissions(logPath).withPermissions("u+rwx,g+rwx,o+rwx").withUser($.var(userWithGroup)).sudo().run().throwIfNot(NoSuchFileException.class);
        $.sys.resetFile(logPath, true);
    }

    protected CommandLineResult<?> serviceCommand(SessionContext $, String command) {
        List<String> ports = $.var(portsSplit);
        boolean isSingle = ports.size() == 1;
        SystemSession.OSHelper helper = $.sys.getOsInfo().getHelper();

        for (String port : ports) {
            String serviceCommand = helper.upstartCommand(format($.var(isSingle ? singleServiceName : multiServiceName), port), command);
            $.sys.captureBuilder(serviceCommand).sudo().run().throwIfError();
        }

        return CommandLineResult.OK;
    }

    public final TaskDef<Object, TaskResult<?>> start = new TaskDef<Object, TaskResult<?>>(new NamedSupplier<Object, TaskResult<?>>("server.start", new SingleTaskSupplier<Object, TaskResult<?>>() {
        @Override
        public Task<Object, TaskResult<?>> createNewSession(SessionContext $, final Task<Object, TaskResult<?>> parent, final TaskDef<Object, TaskResult<?>> def) {
            return new Task<Object, TaskResult<?>>(parent, def, $) {
                @Override
                protected TaskResult<?> exec(SessionRunner runner) {
                    $.log("starting the {} app...", $(toolname));

                    Optional<Release> optionalRelease = $.var(releases.activatedRelease);

                    if (!optionalRelease.isPresent()) {
                        return TaskResult.error("there is no release to start!");
                    }

                    TaskResult<?> r;

                    //bear.installationInProgress is for tomcat
                    //useUpstart is for other plugins
                    if ($(bear.installationInProgress) || $(useUpstart)) {
                        UpstartServices services = $(customUpstart);

                        r = $.runSession(
                            upstart.create.singleTaskSupplier().createNewSession($, parent, upstart.create),
                            services);

                        if (!r.ok()) return r;
                    }

                    if ($(useWatchDog)) {
                        spawnStartWatchDogs($, $(portsSplit));
                    }

                    r = serviceCommand($, "start");

                    printCurrentReleases($);

                    return r;
                }
            };
        }
    }));

    public String instancePath(String port, SessionContext $) {
        return path(instancePath, port, $);
    }

    public String path(DynamicVariable<String> pathVar, String port, SessionContext $) {
        return format($.var(pathVar), port);
    }

    // todo extract common things
    // from this abstract method

    protected abstract void spawnStartWatchDogs(final SessionContext $, List<String> ports);

    public final TaskDef<Object, TaskResult<?>> stop = new TaskDef<Object, TaskResult<?>>(new NamedSupplier<Object, TaskResult<?>>("server.stop", new SingleTaskSupplier<Object, TaskResult<?>>() {
        @Override
        public Task<Object, TaskResult<?>> createNewSession(SessionContext $, Task<Object, TaskResult<?>> parent, TaskDef<Object, TaskResult<?>> def) {
            return new Task<Object, TaskResult<?>>(parent, def, $) {

                @Override
                protected TaskResult<?> exec(SessionRunner runner) {
                    $.log("stopping the app (stage)...");

                    CommandLineResult<?> r;

                    try {
                        r = serviceCommand($, "stop");

                        if (!r.ok()) {
                            logger.warn("unable to stop service: {}", r);
                        }
                    } catch (Exception e) {
                        logger.warn("unable to stop service: ", e);
                    }

                    return TaskResult.OK;
                }
            };

        }
    }));

    public final TaskDef<Object, TaskResult<?>> watchStart = new TaskDef<Object, TaskResult<?>>(new NamedSupplier<Object, TaskResult<?>>("server.watchStart", new SingleTaskSupplier<Object, TaskResult<?>>() {
        @Override
        public Task<Object, TaskResult<?>> createNewSession(SessionContext $, Task<Object, TaskResult<?>> parent, TaskDef<Object, TaskResult<?>> def) {
            return new Task<Object, TaskResult<?>>(parent, new TaskCallable<Object, TaskResult<?>>() {
                @Override
                public TaskResult<?> call(SessionContext $, Task<Object, TaskResult<?>> task) throws Exception {
                    TaskResult<?> r;
                    if (!$.var(useWatchDog)) {
                        r = TaskResult.OK;
                    } else {
                        WatchDogGroup watchDogGroup = $.var(watchStartDogGroup);

                        boolean awaitOk = watchDogGroup.latch().await($.var(startupTimeoutMs), TimeUnit.MILLISECONDS);

                        if (awaitOk) {
                            r = watchDogGroup.getResult();
                        } else {
                            r = TaskResult.error(watchDogGroup.latch().getCount() + " instances did not start in " +
                                TimeUnit.MILLISECONDS.toSeconds($.var(startupTimeoutMs)) + " seconds");
                        }
                    }

                    printCurrentReleases($);

                    return r;
                }
            });
        }
    }));


    private void printCurrentReleases(SessionContext $) {
        logger.info("current releases:\n{}", $.var(releases.session).show());
    }

    public String consoleLogPath(String port, SessionContext $) {
        return format($.var(consoleLogPath), port);
    }

    protected NoticeEventToUI newNotice(String message, SessionContext $) {
        return new NoticeEventToUI($.var(bear.fullName), message);
    }

    protected String newStartedMessage(SessionContext $, String port) {
        return "started instance at " +
            $.getName() +":" + port + ", release " + ", release " + $.var(releases.session).getCurrentRelease().get().name();
    }

    protected String sendMessage(Level level, String message, SessionContext $) {
        logger.log(level, message);
        ui.log(level, newNotice(message, $));

        return message;
    }

    protected String newSeemToHaveStartedMessage(SessionContext $, String port) {
        return "seem to have started after timeout, node instance at " +
            $.getName() + ":" + port + ", release " + $.var(releases.session).getCurrentRelease().get().name();
    }

    protected String newCantStartMessage(SessionContext $, String port) {
        return "unable to start instance at " +
            $.getName() +":" + port + ", release " + $.var(releases.session).getCurrentRelease().get().name();
    }

    protected ConsoleCallbackResult notStartedResult(SessionContext $, String port) {
        return new ConsoleCallbackResult(ConsoleCallbackResultType.EXCEPTION, sendMessage(Level.ERROR, newCantStartMessage($, port), $));
    }

    protected void seemsHaveStarted(final AbstractConsole.Terminal console, final SessionContext $, final String port) {
        $.getGlobal().getScheduler().schedule(new Runnable() {
            @Override
            public void run() {
                if(!console.isDone()){
                    console.finishWithResult(new ConsoleCallbackResult(ConsoleCallbackResultType.DONE,
                        sendMessage(Level.INFO, newSeemToHaveStartedMessage($, port), $)));
                }
            }
        }, 5, TimeUnit.SECONDS);
    }

    protected ConsoleCallbackResult startedResult(SessionContext $, String port) {
        return new ConsoleCallbackResult(ConsoleCallbackResultType.DONE, sendMessage(Level.INFO, newStartedMessage($, port), $));
    }

    public static <T> Function<T, Void> voidEmptyFunction() {
        return VOID_EMPTY_FUNCTION;
    }


    private static final Function VOID_EMPTY_FUNCTION = new Function() {
        @Nullable
        @Override
        public Void apply(Object input) {
            return null;
        }
    };

}
TOP

Related Classes of bear.plugins.ServerToolPlugin

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.