package io.fathom.cloud;
import static org.junit.Assert.assertEquals;
import io.fathom.cloud.identity.services.KeyPairs;
import io.fathom.cloud.openstack.client.OpenstackClient;
import io.fathom.cloud.openstack.client.identity.AuthTokenProvider;
import io.fathom.cloud.openstack.client.identity.OpenstackIdentityClient;
import io.fathom.cloud.openstack.client.identity.TokenProvider;
import io.fathom.cloud.openstack.client.identity.model.V2ProjectList;
import io.fathom.cloud.ssh.SshConfig;
import io.fathom.cloud.ssh.SshContext;
import io.fathom.cloud.ssh.jsch.SshContextImpl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.KeyPair;
import java.util.Properties;
import org.apache.curator.test.TestingServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.fathomdb.Configuration;
import com.fathomdb.config.ConfigurationImpl;
import com.fathomdb.crypto.OpenSshUtils;
import com.google.common.base.Charsets;
public class TestCloudServer {
static TestingServer zkTestServer;
static Path workdir;
static CloudServer server;
static SshContext sshContext;
@BeforeClass
public static void startServer() throws Exception {
zkTestServer = new TestingServer(2181);
workdir = Files.createTempDirectory("unittest");
Properties properties = new Properties();
properties.setProperty("zookeeper.servers", zkTestServer.getConnectString());
properties.setProperty("metadata.host", "127.0.0.1");
KeyPair sshKeyPair = KeyPairs.generateKeyPair();
Path privateKey = workdir.resolve("id_rsa");
Path publicKey = workdir.resolve("id_rsa.pub");
Files.write(privateKey, KeyPairs.serializePem(sshKeyPair.getPrivate()).getBytes(Charsets.UTF_8));
Files.write(publicKey, OpenSshUtils.serialize(sshKeyPair.getPublic()).getBytes(Charsets.UTF_8));
Path authorizedKeysPath = workdir.resolve("authorized_keys");
properties.setProperty("sshd.authorized_keys", "authorized_keys");
String authorizedKeys = OpenSshUtils.serialize(sshKeyPair.getPublic()) + " unittest";
Files.write(authorizedKeysPath, authorizedKeys.getBytes(Charsets.UTF_8));
sshContext = new SshContextImpl("root", privateKey.toFile());
Configuration configuration = ConfigurationImpl.from(workdir.toFile(), properties);
server = CloudServer.build(configuration);
server.start();
}
@AfterClass
public static void cleanup() throws Exception {
server.stop();
java.nio.file.Files.walkFileTree(workdir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
@Test
public void testLogin() throws Exception {
URI identityUri = URI.create("http://127.0.0.1:8080/openstack/identity/");
OpenstackIdentityClient identityClient = OpenstackIdentityClient.build(identityUri);
String username = "admin";
String password = "secret";
String project = "__system__";
runSshCommand("id-passwordrecovery-create", "-o", workdir.resolve("passwordrecovery").toString());
runSshCommand("id-user-create", "-u", username, "-p", password);
runSshCommand("id-domainrole-grant", "-touser", username, "-r", "admin");
runSshCommand("id-project-create", "-u", username, "-p", password, "-proj", project);
runSshCommand("id-role-grant", "-u", username, "-p", password, "-touser", username, "-proj", project, "-r",
"admin");
{
TokenProvider tokenProvider = AuthTokenProvider.build(identityClient, project, username, password);
OpenstackClient client = OpenstackClient.build(tokenProvider);
V2ProjectList projects = client.getIdentity().listProjects();
assertEquals(1, projects.tenants.size());
assertEquals(project, projects.tenants.get(0).name);
assertEquals(true, projects.tenants.get(0).enabled);
}
String password2 = "moresecrets";
runSshCommand("id-password-change", "-u", username, "-p", password2, "-o", workdir.resolve("passwordrecovery")
.toString());
{
TokenProvider tokenProvider = AuthTokenProvider.build(identityClient, project, username, password2);
OpenstackClient client = OpenstackClient.build(tokenProvider);
V2ProjectList projects = client.getIdentity().listProjects();
assertEquals(1, projects.tenants.size());
assertEquals(project, projects.tenants.get(0).name);
assertEquals(true, projects.tenants.get(0).enabled);
}
}
private void runSshCommand(String... args) throws Exception {
SshConfig sshConfig = sshContext.buildConfig(new InetSocketAddress("127.0.0.1", 2222));
StringBuilder cmd = new StringBuilder();
for (String arg : args) {
if (cmd.length() != 0) {
cmd.append(' ');
}
// TODO: Check for spaces and quote??
cmd.append(arg);
}
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
int exitCode = sshConfig.execute(cmd.toString(), stdout, stderr);
if (exitCode != 0) {
System.out.println("Command: " + cmd);
System.out.println("STDOUT: " + new String(stdout.toByteArray(), Charsets.UTF_8));
System.out.println("STDERR: " + new String(stderr.toByteArray(), Charsets.UTF_8));
throw new IllegalStateException("Non-zero exit code returned: " + exitCode);
}
}
}