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

io.cdap.cdap.internal.app.runtime.distributed.remote.SSHRemoteExecutionService Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2020 Cask Data, 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 io.cdap.cdap.internal.app.runtime.distributed.remote;

import com.google.common.io.Closeables;
import com.google.gson.Gson;
import io.cdap.cdap.app.runtime.ProgramStateWriter;
import io.cdap.cdap.common.conf.CConfiguration;
import io.cdap.cdap.common.conf.Constants;
import io.cdap.cdap.common.ssh.DefaultSSHSession;
import io.cdap.cdap.common.ssh.SSHConfig;
import io.cdap.cdap.internal.app.runtime.monitor.ServiceSocksProxyInfo;
import io.cdap.cdap.proto.id.ProgramRunId;
import io.cdap.cdap.runtime.spi.ssh.SSHSession;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ScheduledExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The service to maintain a SSH tunnel with remote port forwarding for the remote runtime to access
 * CDAP services via the tunnel.
 */
final class SSHRemoteExecutionService extends RemoteExecutionService {

  private static final Logger LOG = LoggerFactory.getLogger(SSHRemoteExecutionService.class);
  private static final Gson GSON = new Gson();

  private final SSHConfig sshConfig;
  private final int serviceSocksProxyPort;
  private SSHSession sshSession;

  SSHRemoteExecutionService(CConfiguration cConf, ProgramRunId programRunId,
      SSHConfig sshConfig, int serviceSocksProxyPort,
      RemoteProcessController remoteProcessController,
      ProgramStateWriter programStateWriter,
      ScheduledExecutorService scheduledExecutor) {
    super(cConf, programRunId, scheduledExecutor, remoteProcessController, programStateWriter);
    this.sshConfig = sshConfig;
    this.serviceSocksProxyPort = serviceSocksProxyPort;
  }

  @Override
  protected void doRunTask() throws Exception {
    if (sshSession != null && sshSession.isAlive()) {
      return;
    }
    Closeables.closeQuietly(sshSession);
    sshSession = createServiceProxyTunnel();
  }

  @Override
  protected void doShutdown() {
    Closeables.closeQuietly(sshSession);
    LOG.debug("Stopped ssh service for run {}", getProgramRunId());
  }

  /**
   * Creates a remote port forwarding SSH tunnel for remote runtime to access CDAP services.
   */
  private SSHSession createServiceProxyTunnel() throws IOException {
    SSHSession session = new DefaultSSHSession(sshConfig);
    ProgramRunId programRunId = getProgramRunId();

    // Creates a new remote port forwarding from the session.
    // We don't need to care about closing the forwarding as it will last until the session get closed,
    // in which the remote port forwarding will be closed automatically
    int remotePort = session.createRemotePortForward(0, serviceSocksProxyPort).getRemotePort();

    LOG.debug("Service SOCKS proxy started on port {} for program run {}", remotePort,
        programRunId);
    ServiceSocksProxyInfo info = new ServiceSocksProxyInfo(remotePort);

    // Upload the service socks proxy information to the remote runtime
    String targetPath = session.executeAndWait("echo `pwd`/" + programRunId.getRun()).trim();
    session.executeAndWait("mkdir -p " + targetPath);
    byte[] content = GSON.toJson(info).getBytes(StandardCharsets.UTF_8);
    String targetFileName =
        Constants.RuntimeMonitor.SERVICE_PROXY_FILE + "-" + programRunId.getRun() + ".json";
    String tmpFileName = targetFileName + "-" + System.currentTimeMillis() + ".tmp";
    //noinspection OctalInteger
    session.copy(new ByteArrayInputStream(content), "/tmp", tmpFileName, content.length, 0600, null,
        null);
    session.executeAndWait(String.format("mv /tmp/%s /tmp/%s", tmpFileName, targetFileName));
    LOG.debug("Service proxy file uploaded to remote runtime for program run {}", programRunId);

    return session;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy