
automately.core.services.container.ContainerService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of automately-core Show documentation
Show all versions of automately-core Show documentation
A Scalable Web Application Platform
package automately.core.services.container;
import automately.core.data.User;
import automately.core.file.VirtualFile;
import automately.core.file.VirtualFileSystem;
import automately.core.services.core.AutomatelyService;
import com.hazelcast.core.IMap;
import com.jcraft.jsch.*;
import com.spotify.docker.client.*;
import com.spotify.docker.client.messages.*;
import io.jsync.app.core.Cluster;
import io.jsync.app.core.Logger;
import io.jsync.buffer.Buffer;
import io.jsync.json.JsonObject;
import io.jsync.utils.CryptoUtils;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang3.ArrayUtils;
import java.io.*;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.*;
import static automately.core.util.file.FileUtil.purgeDirectory;
/**
* The ContainerService is an Automately Service and an API that can be used to
* utilize docker containers within the host machine. It is designed to interact with
* docker on the local machine. This will change in the future.
*/
public class ContainerService extends AutomatelyService {
public static boolean BIND_RANDOM = true;
private static String BROADCAST_ADDRESS = "0.0.0.0";
// This provides the build directive for the default
// docker image. This is very important because we need
// certain things to be set in the vm for proper support.
private static String[] DEFAULT_DOCKER_DATA = {
"FROM ubuntu:latest",
"MAINTAINER Tony Rice ",
"LABEL version=\"0.0.8\"",
"\n",
"RUN apt-get update && apt-get install -y \\",
" openssh-server \\",
" software-properties-common \\",
" python-software-properties \\",
" nano \\",
" git \\",
" curl \\",
" apt-transport-https \\",
" && mkdir /var/run/sshd \\",
" && add-apt-repository -y ppa:webupd8team/java && \\",
" apt-get update -y -q && \\",
" (echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections) && \\",
" apt-get install -y oracle-java8-installer && \\",
" apt-get upgrade -y && (curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -) && \\",
" (curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -) && \\",
" (curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list) && \\",
" apt-get update -y -q && \\",
" apt-get install -y nodejs dart php5-cli php5-mcrypt php5-mysql\n\n",
"RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config",
"RUN echo \"export VISIBLE=now\" >> /etc/profile",
"ENV NOTVISIBLE \"in users profile\"",
"\n",
"EXPOSE 22",
"CMD [\"/usr/sbin/sshd\", \"-D\"]"
};
public static String DEFAULT_IMAGE = "automately-ubuntu";
private static DockerClient docker;
private static Path containerPath = Paths.get("/var/run/automately/container/");
private static Logger logger;
private static IMap userContainers = null;
private static Cluster cluster = null;
private static Set localContainers = new LinkedHashSet<>();
private static void checkInitialized() {
if (!initialized()) {
throw new RuntimeException("The default DockerClient has not been initialized.");
}
}
@Override
public void start(Cluster owner) {
cluster = owner;
logger = owner.logger();
try {
if (cluster.config().isDebug()) {
containerPath = Paths.get("tmp/container/");
}
logger.info("Verifying access to " + containerPath.toAbsolutePath().toString());
if (!Files.isWritable(containerPath) && Files.exists(containerPath)) {
logger.fatal("Cannot write to " + containerPath.toAbsolutePath().toString());
return;
}
if (!Files.exists(containerPath)) {
Files.createDirectories(containerPath);
}
docker = DefaultDockerClient.builder()
.uri(DefaultDockerClient.DEFAULT_UNIX_ENDPOINT)
.build();
if (!docker.ping().equals("OK")) {
logger.fatal("Could not create the default DockerClient. (Ping Failed)");
}
// TODO detect default bridge
logger.info("Searching for the default (docker0) docker \"bridge\" interface...");
NetworkInterface bridgeInterface = null;
Enumeration nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface iface : Collections.list(nets)){
if(iface.getDisplayName().matches("^docker0$")){
logger.info("Found the default (docker0) docker \"bridge\" interface...");
bridgeInterface = iface;
break;
}
}
if(bridgeInterface == null){
logger.fatal("Could not find the default (docker0) docker \"bridge\" interface!");
return;
}
logger.info("Using the docker \"bridge\" interface: " + bridgeInterface);
logger.info("Searching for the host address for the \"bridge\" interface...");
InetAddress addr = null;
for(InterfaceAddress ifaceaddr : bridgeInterface.getInterfaceAddresses()){
if(ifaceaddr.getBroadcast() != null){
// this means it is not an ipv6 address
addr = ifaceaddr.getAddress();
logger.info("Found the host address for the host address for the \"bridge\" interface: " + addr.getCanonicalHostName());
break;
}
}
if(addr == null){
logger.fatal("Could not find the host address for the \"bridge\" interface!");
return;
}
logger.info("Using the host address: " + addr);
String broadcastAddress;
JsonObject containerConfig = coreConfig().getObject("docker", new JsonObject());
if(!containerConfig.containsField("broadcast_address")){
logger.info("Creating default configuration...");
containerConfig.putString("broadcast_address", "0.0.0.0");
containerConfig.putBoolean("broadcast_all", false);
coreConfig().putObject("docker", containerConfig);
cluster.config().save();
}
broadcastAddress = containerConfig.getString("broadcast_address", "0.0.0.0");
// Attempt to retrieve an actual address
if(broadcastAddress.equals("0.0.0.0") &&
!containerConfig.getBoolean("broadcast_all", false)){
// There should be a default interface defined
logger.info("Searching for the default \"broadcast\" interface and address...");
nets = NetworkInterface.getNetworkInterfaces();
i:
for (NetworkInterface iface : Collections.list(nets)){
if(!iface.isLoopback() && !iface.getDisplayName().matches("^docker\\d+$")){
for(InterfaceAddress ifaceaddr : iface.getInterfaceAddresses()){
if(ifaceaddr.getBroadcast() != null){
broadcastAddress = ifaceaddr.getAddress().getHostAddress();
logger.info("Found possible default \"broadcast\" address: " + broadcastAddress + " (can be changed by updated \"broadcast_address\")");
containerConfig.putString("broadcast_address", broadcastAddress);
coreConfig().putObject("docker", containerConfig);
cluster.config().save();
break i;
}
}
}
}
}
// The broadcast address is used to bind ports
// exposed on the container. This address
// Should be accessible via other containers
BROADCAST_ADDRESS = broadcastAddress;
userContainers = cluster().data().persistentMap(ContainerService.class.getCanonicalName() + ".user.containers");
logger.info("Building the default Docker image...");
io.jsync.buffer.Buffer dockerData = new Buffer(String.join("\n", DEFAULT_DOCKER_DATA));
buildImage(DEFAULT_IMAGE, dockerData);
logger.info("Cleaning up old containers...");
for(String containerId : userContainers.keySet()){
JsonObject containerData = userContainers.get(containerId);
if(containerData.getString("broadcast_address", "").equals(BROADCAST_ADDRESS)){
logger.info("Killing \"" + containerId + "\"...");
try {
docker.killContainer(containerId);
docker.removeContainer(containerId, true);
} catch (Exception ignored){
// We want to catch this just in case the container doesn't exist
}
userContainers.remove(containerId);
}
}
} catch (IOException | DockerException | InterruptedException e) {
e.printStackTrace();
docker = null;
logger.fatal("Could not create the default DockerClient: " + e.getMessage());
}
}
@Override
public void stop() {
try {
if (initialized()) {
for(SecureContainer container : localContainers){
try {
if(!container.killed() || container.running()){
container.kill();
}
} catch (Exception ignored){}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
docker = null;
}
}
@Override
public String name() {
return getClass().getCanonicalName();
}
/**
* This method returns true if the ContainerService has been initialized on this cluster.
* @return
*/
public static boolean initialized() {
return docker != null && userContainers != null && cluster != null;
}
/**
* buildImage() is used to build and store docker images from raw data.
* @param imageName the name if the image you wish to build
* @param dockerFileData the data of the Dockerfile you are building
*/
public static void buildImage(String imageName, io.jsync.buffer.Buffer dockerFileData){
checkInitialized();
try {
Path tmpDocker = Paths.get("/tmp/" + imageName + "_tmp");
if (Files.exists(tmpDocker)) {
purgeDirectory(tmpDocker);
}
Files.createDirectory(tmpDocker);
Path dockerFile = tmpDocker.resolve("Dockerfile");
Files.write(dockerFile, dockerFileData.getBytes());
// This should definitely not be fatal
if (!Files.exists(tmpDocker)) {
logger.fatal("Could not create the file " + dockerFile);
return;
}
logger.info("Building the docker image \"" + imageName + "\"...");
docker.build(tmpDocker, imageName, msg -> {
if (msg.stream() != null && !msg.stream().isEmpty()) {
logger.info(msg.stream().trim());
}
});
logger.info("The docker image \"" + imageName + "\" has been built.");
} catch (Exception e) {
// Todo throw a proper error
e.printStackTrace();
}
}
public static SecureContainer create(String containerName, User user, String imageName, boolean killOnRestart, String[] exposedPorts, String[] pathBindings) {
checkInitialized();
try {
containerName = containerName.trim();
/**
* Begin container file setup.
*/
String userHash = CryptoUtils.calculateHmacSHA1(user.username + user.token() + user.created.toString(), user.username + containerName);
Path userPath = containerPath.resolve(userHash + "/");
if (!Files.exists(userPath)) {
Files.createDirectory(userPath);
}
/**
* End container file setup.
*/
// This directories are created by default just
// in case we want to connect to a container via
// ssh
pathBindings = ArrayUtils.addAll(pathBindings, "ssh/:/root/.ssh/");
Set directoryBindings = new LinkedHashSet<>();
Set finalBinds = new LinkedHashSet<>();
for(String bind : pathBindings){
Path bindPath = userPath.resolve(bind.split(":")[0].trim());
String bindTo = bind.split(":")[1].trim();
boolean readOnly = bind.split(":").length > 2 && bind.split(":")[2].equals("ro");
// Todo make better
if (!Files.exists(bindPath)) {
Files.createDirectory(bindPath);
}
String fullBind = bindPath.toAbsolutePath().toAbsolutePath() + ":" + bindTo;
if(readOnly){
fullBind += ":ro";
}
finalBinds.add(fullBind);
directoryBindings.add(bindTo);
}
// TODO Implement custom port bindings and such
String[] ports = {"22"};
ports = ArrayUtils.addAll(ports, exposedPorts);
Map> portBindings = new HashMap<>();
for (String port : ports) {
List hostPorts = new ArrayList<>();
String newPort = "";
if (!BIND_RANDOM) {
newPort = port;
}
hostPorts.add(PortBinding.of(BROADCAST_ADDRESS, newPort));
portBindings.put(port, hostPorts);
}
long memoryLimit = ((long) (5242880))/2;
HostConfig hostConfig = HostConfig.builder()
.memory(memoryLimit) // TODO fix this
.binds(finalBinds.toArray(new String[finalBinds.size()]))
.portBindings(portBindings)
.privileged(false) // This must be always false for security reasons (may change in the future)
.networkMode("bridge") // TODO firewall hosts
.build();
if(imageName == null || imageName.isEmpty()){
imageName = DEFAULT_IMAGE; // Using the Default Container
}
Iterator iterator = docker.listImages(DockerClient.ListImagesParam.allImages()).iterator();
boolean imageFound = false;
while (iterator.hasNext()){
Image image = iterator.next();
if(image.repoTags().contains(imageName)){
imageFound = true;
break;
}
}
if(!imageFound){
logger.info("Attempting to pull the image \"" + imageName + "\" from the default Docker repository.");
docker.pull(imageName, p -> {
logger.info(p.toString());
});
}
ContainerConfig containerConfig = ContainerConfig.builder().image(imageName)
.memory(memoryLimit)
.volumes(directoryBindings).hostConfig(hostConfig)
.exposedPorts(ports).build();
ContainerCreation creation;
creation = docker.createContainer(containerConfig);
JsonObject containerData = new JsonObject();
containerData.putString("userToken", user.token());
containerData.putString("id", creation.id());
containerData.putString("host", cluster.hazelcast().getCluster().getLocalMember().getUuid());
// This is stored so we can access ports
containerData.putString("broadcast_address", BROADCAST_ADDRESS);
containerData.putBoolean("kill_on_restart", killOnRestart);
SecureContainer container = new SecureContainer(containerName, creation.id(), user, userPath);
userContainers.put(creation.id(), containerData);
localContainers.add(container);
return container;
} catch (Exception e) {
if(cluster.config().isDebug()){
e.printStackTrace();
}
throw new RuntimeException("Failed to create a new SecureContainer.", e);
}
}
public static SecureContainer create(String containerName, User user, String imageName, boolean killOnRestart, String[] exposedPorts){
return create(containerName, user, imageName, killOnRestart, exposedPorts, null);
}
public static SecureContainer create(String containerName, User user, String imageName, boolean killOnRestart){
return create(containerName, user, imageName, killOnRestart, null, null);
}
public static SecureContainer create(String containerName, User user, String imageName){
return create(containerName, user, imageName, true, null, null);
}
public static SecureContainer connect(User user, String containerName, String containerId) {
checkInitialized();
try {
for (Container container : docker.listContainers(DockerClient.ListContainersParam.allContainers())) {
if (container.id().equals(containerId)) {
// TODO Ensure the user directory exists
containerName = containerName.trim();
String userHash = CryptoUtils.calculateHmacSHA1(user.username + user.token() + user.created.toString(), user.username + containerId);
Path userPath = containerPath.resolve(userHash + "/");
if (!Files.exists(userPath)) {
// Ensure the container is killed
docker.killContainer(containerId);
return null;
}
SecureContainer nContainer = new SecureContainer(containerName, containerId, user, containerPath.resolve(userHash + "/"));
JsonObject containerData = userContainers.get(containerId);
if(containerData == null){
containerData = new JsonObject();
}
containerData.putString("userToken", user.token());
containerData.putString("id", containerId);
containerData.putString("host", cluster.hazelcast().getCluster().getLocalMember().getUuid());
userContainers.put(containerId, containerData);
localContainers.add(nContainer);
return nContainer;
}
}
} catch (DockerException | InterruptedException e) {
throw new RuntimeException(e);
}
return null;
}
public static class SecureContainer {
private static JSch ssh;
private String containerId;
private User user;
private boolean initialized = false;
private PortBinding shellPort = null;
private PortBinding webPort = null;
private String defaultWebPort = "8080";
private boolean connected = false;
private Session session;
private Path dataPath = null;
private String name;
private boolean killed = false;
protected SecureContainer(String name, String containerId, User user, Path dataPath) {
if (containerId == null) {
throw new NullPointerException();
}
this.containerId = containerId;
this.dataPath = dataPath;
this.user = user;
this.name = name;
}
public String id() {
return containerId;
}
public String name(){
return this.name;
}
public PortBinding shellPort(){
return shellPort;
}
public PortBinding webPort(){
return webPort;
}
public void setDefaultWebPort(Number webPort){
if(webPort == null){
throw new NullArgumentException("webPort cannot be null");
}
if(webPort.intValue() <= 0){
throw new IllegalArgumentException("webPort must be greater than 0");
}
defaultWebPort = String.valueOf(webPort.intValue());
}
public void uploadPath(String srcPath, String dest) {
if(killed){
throw new RuntimeException("This container has been killed.");
}
if (!initialized()) {
throw new RuntimeException("This container does not seem to be initialized.");
}
try {
Session session = ssh.getSession("root", shellPort.hostIp(), Integer.parseInt(shellPort.hostPort()));
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp channelSftp = (ChannelSftp) channel;
String uploadPath = VirtualFileSystem.getPathAlias(dest);
srcPath = VirtualFileSystem.getPathAlias(srcPath);
channelSftp.mkdir(uploadPath);
channelSftp.cd(uploadPath);
for(VirtualFile file : VirtualFileSystem.getUserFiles(user, srcPath, 0, 0, true, false, true)){
String destFile = uploadPath + file.pathAlias.replace(srcPath, "") + file.name;
io.jsync.buffer.Buffer buffer = VirtualFileSystem.readFileData(file);
if(buffer != null){
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer.getBytes());
channelSftp.put(byteArrayInputStream, destFile);
}
}
channelSftp.exit();
session.disconnect();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed connect to a secure shell session.", e);
}
}
public void uploadFile(String srcFile, String dest) {
if(killed){
throw new RuntimeException("This container has been killed.");
}
if (!initialized()) {
throw new RuntimeException("This container does not seem to be initialized.");
}
try {
Session session = ssh.getSession("root", shellPort.hostIp(), Integer.parseInt(shellPort.hostPort()));
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp channelSftp = (ChannelSftp) channel;
String uploadPath = VirtualFileSystem.getPathAlias(dest);
String srcPath = VirtualFileSystem.getPathAlias(srcFile);
channelSftp.mkdir(uploadPath);
channelSftp.cd(uploadPath);
VirtualFile file = VirtualFileSystem.getUserFile(user, srcPath);
if(file != null){
String destFile = uploadPath + file.pathAlias.replace(srcPath, "") + file.name;
io.jsync.buffer.Buffer buffer = VirtualFileSystem.readFileData(file);
if(buffer != null){
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer.getBytes());
channelSftp.put(byteArrayInputStream, destFile);
}
}
channelSftp.exit();
session.disconnect();
} catch (Exception e) {
throw new RuntimeException("Failed connect to a secure shell session.", e);
}
}
public boolean running() {
try {
return docker.inspectContainer(containerId).state().running();
} catch (DockerException | InterruptedException ignored) {
}
return false;
}
public boolean paused() {
try {
return docker.inspectContainer(containerId).state().paused();
} catch (DockerException | InterruptedException ignored) {
}
return false;
}
public boolean restarting() {
try {
return docker.inspectContainer(containerId).state().restarting();
} catch (DockerException | InterruptedException ignored) {
}
return false;
}
public boolean killed(){
return killed;
}
public boolean oomKilled() {
try {
return docker.inspectContainer(containerId).state().oomKilled();
} catch (DockerException | InterruptedException ignored) {
}
return false;
}
public int exitCode() {
try {
return docker.inspectContainer(containerId).state().exitCode();
} catch (DockerException | InterruptedException ignored) {
}
return -1;
}
public String error() {
try {
return docker.inspectContainer(containerId).state().error();
} catch (DockerException | InterruptedException ignored) {
}
return "";
}
public ExecState exec(String... command) {
return exec(true, null, null, command);
}
public ExecState exec(boolean waitForFinish, OutputStream stdout, OutputStream stderr, String... command) {
try {
if(killed){
throw new RuntimeException("This container has been killed.");
}
if (!initialized()) {
throw new RuntimeException("This container does not seem to be initialized.");
}
logger.info("Container Exec (" + containerId + ") " + Arrays.toString(command));
String execId = docker.execCreate(containerId, command, DockerClient.ExecParameter.STDOUT, DockerClient.ExecParameter.STDERR);
if (waitForFinish) {
LogStream logStream = docker.execStart(execId);
if(stdout != null && stderr != null){
logStream.attach(stdout, stderr);
}
while (docker.execInspect(execId).running()) {
Thread.sleep(5);
}
// A timeout to make the exec wait a little bit
Thread.sleep(150);
String out = logStream.readFully().trim();
if (!out.isEmpty()) {
logger.info("Container Exec Result (" + containerId + ") " + out);
}
return docker.execInspect(execId);
} else {
docker.execStart(execId);
Thread.sleep(150);
return docker.execInspect(execId);
}
} catch (IOException | DockerException | InterruptedException e) {
throw new RuntimeException(e);
}
}
public void disconnect(){
if(killed){
throw new RuntimeException("This container has been killed.");
}
if (!initialized()) {
throw new RuntimeException("This container does not seem to be initialized.");
}
if(!connected()){
throw new RuntimeException("You are not currently connected to a shell session.");
}
try {
session.disconnect();
session = null;
connected = false;
} catch (Exception ignored){};
}
public boolean connected() {
return (session != null && session.isConnected()) && connected;
}
public void connect(InputStream in, OutputStream out) {
if (connected()) {
throw new RuntimeException("You are already connected to a secure session.");
}
if(killed){
throw new RuntimeException("This container has been killed.");
}
if (!initialized()) {
throw new RuntimeException("This container does not seem to be initialized.");
}
try {
session = ssh.getSession("root", shellPort.hostIp(), Integer.parseInt(shellPort.hostPort()));
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = session.openChannel("shell");
channel.setInputStream(in);
channel.setOutputStream(out);
channel.connect();
connected = true;
} catch (Exception e) {
e.printStackTrace();
session = null;
connected = false;
throw new RuntimeException("Failed connect to a secure shell session.", e);
}
}
public boolean initialized() {
return initialized && shellPort != null;
}
public void initialize() {
try {
if(killed){
throw new RuntimeException("This container has been killed.");
}
if (initialized()) {
throw new RuntimeException("Cannot call initialize() when the container is already initialized.");
}
if (!running()) {
docker.startContainer(containerId);
while (!running() && error().isEmpty() && !paused()) {
Thread.sleep(15);
}
}
initialized = running();
if (!docker.inspectContainer(containerId).networkSettings().ports().containsKey("22") || !docker.inspectContainer(containerId).networkSettings().ports().get("22").iterator().hasNext()) {
throw new RuntimeException("There was an error initializing the SecureContainer \"" + containerId + "\".");
}
shellPort = docker.inspectContainer(containerId).networkSettings().ports().get("22").iterator().next();
// For right now the only port we want exposed is what we consider the "web port"
if (docker.inspectContainer(containerId).networkSettings().ports().containsKey(defaultWebPort) &&
docker.inspectContainer(containerId).networkSettings().ports().get(defaultWebPort).iterator().hasNext()) {
webPort = docker.inspectContainer(containerId).networkSettings().ports().get(defaultWebPort).iterator().next();
}
// TODO update container data
JsonObject containerData = userContainers.get(containerId);
if(containerData == null){
containerData = new JsonObject();
}
containerData.putString("userToken", user.token());
containerData.putString("id", containerId);
containerData.putString("host", cluster.hazelcast().getCluster().getLocalMember().getUuid());
containerData.putString("shell_port", shellPort.hostPort());
containerData.putString("shell_host", shellPort.hostIp());
if(webPort != null){
containerData.putString("web_port", webPort.hostPort());
containerData.putString("web_host", webPort.hostIp());
}
logger.info("Storing container data: " + containerData.encode());
userContainers.put(containerId, containerData);
if (ssh == null) {
ssh = new JSch();
}
Path pkeyFile = dataPath.resolve("ssh/id_rsa");
Path pukeyFile = dataPath.resolve("ssh/id_rsa.pub");
Path akeyFile = dataPath.resolve("ssh/authorized_keys");
// If it already exists we do not need to create it.
if (!(Files.exists(akeyFile) && Files.exists(pkeyFile))) {
KeyPair kpair = KeyPair.genKeyPair(ssh, KeyPair.RSA);
// Write the private key to a secure directory and set the permissions
String pkeyPath = pkeyFile.toAbsolutePath().toString();
kpair.writePrivateKey(pkeyPath);
kpair.writePublicKey(pukeyFile.toAbsolutePath().toString(), "Auth Key");
kpair.writePublicKey(akeyFile.toAbsolutePath().toString(), "Auth Key");
if (!Files.exists(pkeyFile)) {
throw new FileNotFoundException(pkeyFile.toAbsolutePath().toString());
}
Set keyPerms = new LinkedHashSet<>();
keyPerms.add(PosixFilePermission.OWNER_READ);
keyPerms.add(PosixFilePermission.GROUP_READ);
keyPerms.add(PosixFilePermission.OWNER_WRITE);
keyPerms.add(PosixFilePermission.OWNER_WRITE);
Files.setPosixFilePermissions(pkeyFile, keyPerms);
Files.setPosixFilePermissions(pukeyFile, keyPerms);
Files.setPosixFilePermissions(akeyFile, keyPerms);
kpair.dispose();
// We want to change the permissions
exec("chown", "-R", "root:root", "/root/.ssh/");
}
// We must change the permissions by running exec within the VM just in case
// We don't have the correct permissions. (TODO change this)
exec("chmod", "0755", "/root/.ssh/id_rsa");
exec("chmod", "0755", "/root/.ssh/id_rsa.pub");
KeyPair kp = KeyPair.load(ssh, pkeyFile.toAbsolutePath().toString());
ssh.addIdentity(user.token(), kp.forSSHAgent(), null, null);
exec("chmod", "0600", "/root/.ssh/id_rsa");
exec("chmod", "0600", "/root/.ssh/id_rsa.pub");
} catch (DockerException | InterruptedException | IOException | JSchException e) {
e.printStackTrace();
throw new RuntimeException("There was an issue while attempting to initialize this container.", e);
}
}
public void kill() {
try {
if (connected()) {
session.disconnect();
}
docker.killContainer(containerId);
docker.removeContainer(containerId, true);
} catch (Exception ignored) {
} finally {
initialized = false;
shellPort = null;
session = null;
ssh = null;
connected = false;
killed = true;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy