001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.agent;
017
018import java.util.HashMap;
019import java.util.HashSet;
020import java.util.Map;
021import java.util.Set;
022import java.util.concurrent.CompletableFuture;
023
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027import org.ametys.runtime.config.Config;
028import org.ametys.runtime.plugin.Init;
029
030import net.bluemind.agent.config.SSLConfig;
031import net.bluemind.agent.server.AgentServerModule;
032import net.bluemind.agent.server.Command;
033import net.bluemind.agent.server.internal.config.ServerConfig;
034
035/**
036 * Launch the bluemind agent server, with port forwarding plugin
037 *
038 */
039public class BlueMindAgentServerLauncher implements Init
040{
041    /** Avalon Role */
042    public static final String ROLE = BlueMindAgentServerLauncher.class.getName();
043    
044    private static final Logger LOGGER = LoggerFactory.getLogger(BlueMindAgentServerLauncher.class);
045    
046    //set of active command list that will be deleted in case of re-start (so the server will not need to be stopped and restarted)
047    private static Set<Command> _activeCommandlist;
048
049    public void init() throws Exception
050    {
051        this.cancelAllCommands();
052        Boolean activated = Config.getInstance().getValueAsBoolean("plugins.agent.activated");
053        if (activated)
054        {
055            String listenAddress = Config.getInstance().getValueAsString("bluemind.agent.listening.ip");
056            Long listenPort = Config.getInstance().getValueAsLong("bluemind.agent.listening.port");
057            
058            BlueMindAgentServerLauncher.startServer(listenAddress, listenPort.intValue()) //
059                .thenRun(BlueMindAgentServerLauncher::startPortForwarding) //
060                .exceptionally((e) ->
061                {
062                    LOGGER.warn("Error while running bm-agent-server", e);
063                    return null;
064                });
065        }
066    }
067    
068    private void cancelAllCommands()
069    {
070        if (_activeCommandlist != null)
071        {
072            for (Command command : _activeCommandlist)
073            {
074                Command deleteCommand = new Command(Command.METHOD.DELETE.name(), command.command, command.agentId, command.pathParameters, command.queryParameters);
075                AgentServerModule.command(deleteCommand);
076            }
077            _activeCommandlist.clear();
078        }
079        else
080        {
081            _activeCommandlist = new HashSet<>();
082        }
083    }
084
085    private static CompletableFuture<Void> startServer(String listenAddress, int listenPort)
086    {
087        LOGGER.info("start bm-agent server");
088        CompletableFuture<Void> future = new CompletableFuture<>();
089        ServerConfig serverConfig = new ServerConfig(listenAddress, listenPort, SSLConfig.noSSL(), null);
090        AgentServerModule.run(serverConfig, () ->
091        {
092            future.complete(null);
093        });
094        return future;
095    }
096
097    private static void startPortForwarding()
098    {
099        String portForwarding = Config.getInstance().getValueAsString("bluemind.agent.listening.port.forwarding");
100        
101        for (String portForwardingConfig : portForwarding.split("\\n"))
102        {
103            String[] split = portForwardingConfig.split(":");
104            if (split.length != 4)
105            {
106                LOGGER.info("Port forwarding configuration error : " + portForwardingConfig);
107            }
108            else
109            {
110                LOGGER.info("Port forwarding started : " + portForwardingConfig);
111                Command command = getPortForwardingCommand(split[0], split[1], split[2], split[3]);
112                _activeCommandlist.add(command);
113                AgentServerModule.command(command);
114            }
115        }
116    }
117    
118    private static Command getPortForwardingCommand(String agentName, String localPort, String host, String targetPort)
119    {
120        String[] pathParameters = new String[0];
121        Map<String, String> queryParameters = new HashMap<>();
122        queryParameters.put("port", targetPort);
123        queryParameters.put("host", host);
124        queryParameters.put("localPort", localPort);
125        Command command = new Command(Command.METHOD.GET.name(), "port-redirect", agentName, pathParameters, queryParameters);
126        return command;
127    }
128}