com.lithium.flow.shell.tunnel.ShellTunneler.java Source code

Java tutorial

Introduction

Here is the source code for com.lithium.flow.shell.tunnel.ShellTunneler.java

Source

/*
 * Copyright 2015 Lithium Technologies, Inc.
 *
 * 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 com.lithium.flow.shell.tunnel;

import static com.google.common.base.Preconditions.checkNotNull;

import com.lithium.flow.access.Access;
import com.lithium.flow.access.Login;
import com.lithium.flow.config.Config;
import com.lithium.flow.shell.Shore;
import com.lithium.flow.shell.Tunnel;
import com.lithium.flow.shell.Tunneler;
import com.lithium.flow.util.Logs;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;

/**
 * @author Matt Ayres
 */
public class ShellTunneler implements Tunneler {
    private static final Logger log = Logs.getLogger();

    private final Config config;
    private final Access access;
    private final Shore shore;
    private final List<Tunnel> tunnels = Lists.newCopyOnWriteArrayList();

    public ShellTunneler(@Nonnull Config config, @Nonnull Access access, @Nonnull Shore shore) {
        this.config = checkNotNull(config);
        this.access = checkNotNull(access);
        this.shore = checkNotNull(shore);
    }

    @Nonnull
    public Tunnel getTunnel(@Nonnull String host, int port, @Nullable String through) throws IOException {
        List<Login> logins = Lists.newArrayList();

        Login endLogin = access.getLogin(host);
        logins.add(endLogin);

        if (through != null) {
            logins.add(access.getLogin(through));
        }

        Optional<String> match = config.getMatch("shell.tunnels", endLogin.getHost());
        if (match.isPresent()) {
            for (String tunnel : Splitter.on(';').split(match.get())) {
                logins.add(access.getLogin(tunnel));
            }
        }

        Collections.reverse(logins);

        Tunnel tunnel = null;
        for (int i = 0; i < logins.size() - 1; i++) {
            Login thisLogin = logins.get(i);
            Login nextLogin = logins.get(i + 1);
            if (i == logins.size() - 2) {
                nextLogin = nextLogin.toBuilder().setPort(port).build();
            }

            log.debug("tunneling through {} to {}", thisLogin, nextLogin.getHostAndPort());

            Login login = thisLogin;
            if (tunnel != null) {
                login = login.toBuilder().setHost("localhost").setPort(tunnel.getPort()).build();
            }

            String message = login.getKeyPath() != null ? login.getKeyPath() : thisLogin.getDisplayString();
            Function<Boolean, String> pass = retry -> access.getPrompt().prompt(message, message, true, retry);
            login = login.toBuilder().setPass(pass).build();

            tunnel = shore.getShell(login).tunnel(0, nextLogin.getHost(), nextLogin.getPortOrDefault(22));
        }

        if (tunnel != null) {
            tunnels.add(tunnel);
            return tunnel;
        } else {
            return new NoTunnel(host, port);
        }
    }

    @Override
    public void close() throws IOException {
        tunnels.forEach(IOUtils::closeQuietly);
        shore.close();
    }
}