package org.ukiuni.pacifista.virtual;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.ukiuni.pacifista.Local;
import org.ukiuni.pacifista.util.HttpUtil;
import org.ukiuni.pacifista.util.IOUtil;
import org.ukiuni.pacifista.util.ScriptingUtil;
import org.ukiuni.pacifista.util.StreamUtil;
public class VirtualBoxHost implements VirtualHost {
private String host;
private File baseDir;
private static final int READ_BUFFER_SIZE = 1024;
private Map<String, String> parameterMap = new HashMap<String, String>();
public VirtualBoxHost(File baseDir, String host) {
this.baseDir = baseDir;
this.host = host;
}
/*
* (non-Javadoc)
*
* @see
* org.ukiuni.pacifista.virtual.VirtualHost#setParameters(java.lang.String)
*/
@Override
public void setParameters(String parameters) {
ScriptingUtil.parseParameters(parameterMap, parameters);
}
/*
* (non-Javadoc)
*
* @see org.ukiuni.pacifista.virtual.VirtualHost#boot()
*/
@Override
public void boot() throws IOException, InterruptedException {
Local.executeNowait(new String[] { "VBoxHeadless", "-startvm", host });
}
/*
* (non-Javadoc)
*
* @see org.ukiuni.pacifista.virtual.VirtualHost#shutdown()
*/
@Override
public void shutdown() throws IOException, InterruptedException {
Local.execute(new String[] { "VBoxManage", "controlvm", host, "poweroff" });
}
/*
* (non-Javadoc)
*
* @see org.ukiuni.pacifista.virtual.VirtualHost#isRunning()
*/
@Override
public boolean isRunning() throws IOException, InterruptedException {
String result = Local.execute(new String[] { "VBoxManage", "list", "runningvms" });
if (result.contains("\"" + host + "\"")) {
return true;
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.ukiuni.pacifista.virtual.VirtualHost#isExist()
*/
@Override
public boolean isExist() throws IOException, InterruptedException {
try {
String line = Local.execute(new String[] { "VBoxManage", "showvminfo", host });
return !line.contains("Could not find a registered machine");
} catch (Throwable e) {
return false;
}
}
/*
* (non-Javadoc)
*
* @see
* org.ukiuni.pacifista.virtual.VirtualHost#downloadImage(java.lang.String)
*/
@Override
public String downloadImage(String url) throws IOException {
return downloadImage(url, null, 0);
}
/*
* (non-Javadoc)
*
* @see
* org.ukiuni.pacifista.virtual.VirtualHost#downloadImage(java.lang.String,
* java.lang.String, int)
*/
@Override
public String downloadImage(String url, String proxyHost, int proxyPort) throws IOException {
return downloadImage(url, proxyHost, proxyPort, null, null);
}
/*
* (non-Javadoc)
*
* @see
* org.ukiuni.pacifista.virtual.VirtualHost#downloadImage(java.lang.String,
* java.lang.String, int, java.lang.String, java.lang.String)
*/
@Override
public String downloadImage(String url, String proxyHost, int proxyPort, final String proxyUser, final String proxyPass) throws IOException {
File vmdir = new File(new File(baseDir, "vmimages"), host);
vmdir.mkdirs();
String vmFileName = new File(new URL(url).getFile()).getName();
File vmFile = new File(vmdir, vmFileName);
FileOutputStream out = new FileOutputStream(vmFile);
HttpUtil.download(url, out, proxyHost, proxyPort, proxyUser, proxyPass);
out.close();
if (vmFile.getName().endsWith(".box")) {
TarArchiveInputStream tarIn = null;
TarArchiveEntry entry;
try {
tarIn = new TarArchiveInputStream(new GZIPInputStream(new FileInputStream(vmFile)));
entry = tarIn.getNextTarEntry();
} catch (IOException e) {
IOUtil.close(tarIn);
tarIn = new TarArchiveInputStream(new FileInputStream(vmFile));
entry = tarIn.getNextTarEntry();
}
File tarDir = new File(vmdir, vmFileName.substring(0, vmFileName.length() - 4));
tarDir.mkdirs();
File returnFile = null;
while (null != entry) {
long leftSize = entry.getSize();
byte[] buffer = new byte[READ_BUFFER_SIZE];
File fileInTarFile = new File(tarDir, entry.getName());
FileOutputStream tarOut = new FileOutputStream(fileInTarFile);
while (leftSize > 0) {
int readSize = (int) (READ_BUFFER_SIZE < leftSize ? READ_BUFFER_SIZE : leftSize);
if (READ_BUFFER_SIZE != readSize) {
buffer = new byte[readSize];
}
int readed = tarIn.read(buffer, 0, readSize);
tarOut.write(buffer, 0, readed);
leftSize -= readSize;
}
tarOut.close();
if (fileInTarFile.getName().endsWith(".vmdk")) {
returnFile = fileInTarFile;
}
entry = tarIn.getNextTarEntry();
}
tarIn.close();
return returnFile.getAbsolutePath();
} else {
return vmFile.getAbsolutePath();
}
}
/*
* (non-Javadoc)
*
* @see org.ukiuni.pacifista.virtual.VirtualHost#create(java.lang.String)
*/
@Override
public InstanceSSHAddress create(String stragePath) throws IOException, InterruptedException {
int port = new Random().nextInt(65535);
create(stragePath, "RedHat_64", 512, port);
return new InstanceSSHAddress("localhost", port, null);
}
/*
* (non-Javadoc)
*
* @see org.ukiuni.pacifista.virtual.VirtualHost#create(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public InstanceSSHAddress create(String stragePath, String type, int memory, int port) throws IOException, InterruptedException {
if (!stragePath.startsWith("/")) {
stragePath = new File(baseDir, stragePath).getAbsolutePath();
}
String returnValue = Local.execute(new String[] { "VBoxManage", "createvm", "--name", host, "--ostype", type });
BufferedReader reader = new BufferedReader(new StringReader(returnValue));
String vboxFile = null;
String line = reader.readLine();
while (null != line) {
if (line.startsWith("Settings")) {
Matcher matcher = Pattern.compile("'(.+?)'").matcher(line);
matcher.find();
vboxFile = matcher.group().replace("\'", "");
}
line = reader.readLine();
}
Local.execute(new String[] { "VBoxManage", "registervm", vboxFile });
Local.execute(new String[] { "VBoxManage", "modifyvm", host, "--memory", String.valueOf(memory), "--nic1", "nat", "--nictype1", "82545EM" });
Local.execute(new String[] { "VBoxManage", "storagectl", host, "--name", host + "sata1", "--add", "sata", "--bootable", "on" });
Local.execute(new String[] { "VBoxManage", "-nologo", "internalcommands", "sethduuid", stragePath });
Local.execute(new String[] { "VBoxManage", "storageattach", host, "--storagectl", host + "sata1", "--port", "0", "--device", "0", "--type", "hdd", "--medium", stragePath });
openPort("tcp", port, 22);
String vagrantSettingFilePath = Local.find(new File(new File(baseDir, "vmimages"), host), "Vagrantfile");
if (null != vagrantSettingFilePath) {
Map<String, String> param = loadVagrantSetting(vagrantSettingFilePath);
if (param.containsKey("config.vm.base_mac")) {
Local.execute(new String[] { "VBoxManage", "modifyvm", host, "--macaddress1", param.get("config.vm.base_mac").replace("\"", "") });
}
}
return new InstanceSSHAddress("localhost", port, null);
}
private Map<String, String> loadVagrantSetting(String vagrantSettingFilePath) throws IOException {
Map<String, String> param = new HashMap<String, String>();
BufferedReader reader = new BufferedReader(new FileReader(vagrantSettingFilePath));
String line = reader.readLine();
while (line != null) {
if (line.contains("=")) {
int equalIndex = line.indexOf("=");
param.put(line.substring(0, equalIndex - 1).trim(), line.substring(equalIndex + 1).trim());
}
line = reader.readLine();
}
reader.close();
return param;
}
@Override
public void openPort(String protocol, int port) throws IOException, InterruptedException {
openPort(protocol, port, port);
}
public String openPort(String protocol, int localPort, int hostPort) throws IOException, InterruptedException {
return Local.execute(new String[] { "VBoxManage", "controlvm", host, "natpf1", "," + protocol + ",," + localPort + ",," + hostPort });
}
/*
* (non-Javadoc)
*
* @see org.ukiuni.pacifista.virtual.VirtualHost#remove()
*/
@Override
public void remove() throws IOException, InterruptedException {
try {
if (isRunning()) {
shutdown();
}
} catch (Throwable e) {
// do nothing
}
Process process = Runtime.getRuntime().exec(new String[] { "VBoxManage", "unregistervm", host, "--delete" });
int returnCode = process.waitFor();
if (0 != returnCode) {
throw new RuntimeException("create failed returnCode = " + returnCode + ", " + StreamUtil.inputToString(process.getErrorStream()));
}
}
}