/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is available at http://www.abiquo.com/.....
*
* The Initial Developer of the Original Code is Soluciones Grid, S.L. (www.abiquo.com),
* Consell de Cent 296 principal 2�, 08007 Barcelona, Spain.
* No portions of the Code have been created by third parties.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* Graphical User Interface of this software may be used under the terms
* of the Common Public Attribution License Version 1.0 (the "CPAL License",
* available at http://cpal.abiquo.com), in which case the provisions of CPAL
* License are applicable instead of those above. In relation of this portions
* of the Code, a Legal Notice according to Exhibits A and B of CPAL Licence
* should be provided in any distribution of the corresponding Code to Graphical
* User Interface.
*/
package com.abiquo.abicloud.machine.impl;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.virtualbox.StorageBus;
import com.abiquo.abicloud.exception.VirtualMachineException;
import com.abiquo.abicloud.hypervisor.impl.VirtualBoxHypervisor;
import com.abiquo.abicloud.model.AbsVirtualMachine;
import com.abiquo.abicloud.model.VirtualDisk;
import com.abiquo.abicloud.model.config.VirtualMachineConfiguration;
import com.abiquo.abicloud.utils.FileUtils;
import com.sun.xml.ws.commons.virtualbox.IConsole;
import com.sun.xml.ws.commons.virtualbox.IHardDisk2;
import com.sun.xml.ws.commons.virtualbox.IHardDiskFormat;
import com.sun.xml.ws.commons.virtualbox.IMachine;
import com.sun.xml.ws.commons.virtualbox.IMedium;
import com.sun.xml.ws.commons.virtualbox.INetworkAdapter;
import com.sun.xml.ws.commons.virtualbox.IProgress;
import com.sun.xml.ws.commons.virtualbox.ISession;
import com.sun.xml.ws.commons.virtualbox.ISnapshot;
import com.sun.xml.ws.commons.virtualbox.IVRDPServer;
import com.sun.xml.ws.commons.virtualbox.IVirtualBox;
/**
* The virtualBox machine representation.
*
* @author abiquo
*/
public class VirtualBoxMachine extends AbsVirtualMachine
{
/** The logger */
private static final Logger logger = LoggerFactory.getLogger(VirtualBoxMachine.class);
/** The v box hyper. */
private VirtualBoxHypervisor vBoxHyper;
/** The machine. */
private IMachine machine;
/** The machine name. */
private String machineName;
/** the memory ram in Mbytes */
private long memoryRam;
/** The number of cpus */
private int cpuNumbers;
/** The machine id. */
private UUID machineId;
/** The remote desktop port */
private int rdpPort;
/**
* Instantiates a new virtual box machine.
*
* @param config the config
* @throws VirtualMachineException the virtual machine exception
*/
public VirtualBoxMachine(VirtualMachineConfiguration config) throws VirtualMachineException
{
super(config);
if (config.isSetHypervisor() & config.getHyper() instanceof VirtualBoxHypervisor)
{
vBoxHyper = (VirtualBoxHypervisor) config.getHyper();
}
else
{
throw new VirtualMachineException("VirtualBoxMachiner requires a VirtualBoxHypervisor "
+ "on VirtualMachineConfiguration, not a "
+ config.getHyper().getClass().getCanonicalName());
}
machineName = config.getMachineName();
machineId = config.getMachineId();
rdpPort = config.getRdPort();
cpuNumbers = config.getCpuNumber();
memoryRam = config.getRamAllocationUnits() / (1024 * 1024);
deployMachine();
logger.info("Created virtual box machine name:" + config.getMachineName() + "\t ID:"
+ config.getMachineId().toString() + "\t " + "using hypervisor connection at "
+ config.getHyper().getAddress().toString());
}
/**
* Deploys the machine.
*/
protected void deployMachine()
{
vBoxHyper.reconnect();
IMachine targetMachine;
// Getting the virtualBox hypervisor
IVirtualBox vbox = vBoxHyper.getVirtualBox();
// Creating the machine implies 4 steps
// 1. Creating the mutable machine, or opening if it was created
// targetMachine =
// vbox.openMachine("/root/.VirtualBox/Machines/XUbuntu/XUbuntu.xml");
logger.info("Creating the virtual machine in the hypervisor");
// TODO if the vbox WS is shutdown the connection shall be done
targetMachine =
vbox.createMachine(config.getMachineName(), "Other", null, config.getMachineId());
// 2. Assigning the VDI to the virtualMachine
VirtualDisk virtualDisk = config.getVirtualDiskBase();
logger.info("Assigning the virtual disk:" + virtualDisk.getLocation());
IHardDisk2 newVDI = null;
/*
* try { newVDI = vbox.openHardDisk2(virtualDisk.getLocation()); } catch (Exception e) {
* newVDI = vbox.findHardDisk2(virtualDisk.getLocation()); }
*/
/*
* try { newVDI = copyVDI(virtualDisk.getLocation()); } catch (IOException e) {
* logger.info("A problem was occured when copying the file"); }
*/
newVDI = cloneVDI(virtualDisk.getLocation());
// 3. Saving settings ¿? We do it below
// targetMachine.saveSettings();
// 4. Registering machine
vbox.registerMachine(targetMachine);
// Getting the session
ISession oSession = vBoxHyper.getSession();
vbox.openSession(oSession, targetMachine.getId());
targetMachine = oSession.getMachine();
// Definining RAM and CPU number
targetMachine.setMemorySize(memoryRam);
targetMachine.setCPUCount(new Long(cpuNumbers));
// Attaching the network adapter
long slot = 0;
INetworkAdapter networkAdapter = targetMachine.getNetworkAdapter(slot);
networkAdapter.setEnabled(true);
/*
* networkAdapter.attachToHostInterface(); networkAdapter.setHostInterface("eth0");
*/
networkAdapter.attachToNAT();
// System.out.println(diskVDI.getId().toString());
// Opening needed ports
/*
* logger.info("Opening web server ports");
* targetMachine.setExtraData("VBoxInternal/Devices/pcnet/0/LUN#0/Config/web/HostPort",
* "80");
* targetMachine.setExtraData("VBoxInternal/Devices/pcnet/0/LUN#0/Config/web/GuestPort",
* "80");
* targetMachine.setExtraData("VBoxInternal/Devices/pcnet/0/LUN#0/Config/web/Protocol",
* "TCP");
*/
/*
* targetMachine.setExtraData("VBoxInternal/Devices/pcnet/0/LUN#0/Config/mw/HostPort" ,
* "60606");targetMachine.setExtraData(
* "VBoxInternal/Devices/pcnet/0/LUN#0/Config/mw/GuestPort", "60606"); targetMachine
* .setExtraData("VBoxInternal/Devices/pcnet/0/LUN#0/Config/mw/Protocol" , "TCP");
*/
// logger.info("The ID is:{}", newVDI.getProperty("uuid"));
IMedium newVDIMedium = IMedium.cast(newVDI);
logger.info("Attaching the harddisk with the id: {}", newVDIMedium.getId());
targetMachine.attachHardDisk2(newVDIMedium.getId(), StorageBus.IDE, 0, 0);
targetMachine.saveSettings();
// Closing the sessions
if (targetMachine != null)
{
targetMachine.releaseRemote();
}
if (oSession != null)
{
oSession.close();
}
}
/**
* Clones a VDI
*
* @param vditoClone the location of the vdi to clone
* @return the new VDI cloned
*/
private IHardDisk2 cloneVDI(String vditoClone)
{
IVirtualBox vbox = vBoxHyper.getVirtualBox();
IHardDisk2 diskVDI;
try
{
diskVDI = vbox.openHardDisk2(vditoClone);
}
catch (Exception e)
{
diskVDI = vbox.findHardDisk2(vditoClone);
}
logger.info("Creating the new hard disk with format: {} in the location: {}", diskVDI
.getFormat(), vbox.getSystemProperties().getDefaultHardDiskFolder());
UUID newVDIuuid = UUID.randomUUID();
IHardDisk2 newVDI =
vbox.createHardDisk2(diskVDI.getFormat(), vbox.getSystemProperties()
.getDefaultHardDiskFolder()
+ File.separatorChar + newVDIuuid + ".vdi");
logger.info("Cloning the disk");
// IProgress progress = diskVDI.cloneTo(newVDI);
IProgress progress = diskVDI.cloneTo(newVDI);
progress.waitForCompletion(1000000);
long rc = progress.getResultCode();
if (rc != 0)
logger.warn("Cloning failed!");
return newVDI;
}
/**
* Opens a remote session.
*/
private void openRemoteSession()
{
String sessionType = "vrdp";
String env = "DISPLAY=:0.0";
logger.info("Opening the remote session");
// openExistingSession();
ISession oSession = vBoxHyper.getSession();
IProgress oProgress =
vBoxHyper.getVirtualBox().openRemoteSession(oSession, config.getMachineId(),
sessionType, env);
logger.info("Session for VM " + config.getMachineId().toString() + " is opened...");
oProgress.waitForCompletion(10000);
long rc = oProgress.getResultCode();
if (rc != 0)
{
logger.warn("Session failed!");
}
if (oSession != null)
{
oSession.close();
}
}
private void openExistingSession()
{
try
{
vBoxHyper.getVirtualBox().openExistingSession(vBoxHyper.getSession(), machineId);
}
catch (Exception e)
{
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
/**
* Opens a session.
*
* @return the i console
*/
private IConsole openSession()
{
/*
* if(!vBoxHyper.getSession().getState().equals(org.virtualbox.SessionState .OPEN)) {
* logger.info("Opening a new session"); logger.info(vBoxHyper.getSession().getRef());
* logger.info(machineId.toString());
* vBoxHyper.getVirtualBox().openSession(vBoxHyper.getSession(), machineId); } else {
* logger.info("Opening existing session");
* vBoxHyper.getVirtualBox().openExistingSession(vBoxHyper.getSession(), machineId); }
*/
vBoxHyper.getVirtualBox().openExistingSession(vBoxHyper.getSession(), machineId);
return vBoxHyper.getConsole();
}
/**
* Closes a session.
*/
private void closeSession()
{
vBoxHyper.getSession().close();
}
/**
* Starts the virtual machine execution.
*/
public void powerOnMachine()
{
// TODO As the manual powerup doesn't work properly, we open a remote
// session
vBoxHyper.reconnect();
// openRemoteSession();
IVirtualBox vbox = vBoxHyper.getVirtualBox();
ISession oSession = vBoxHyper.getSession();
vbox.openSession(oSession, machineId);
IMachine machine = vBoxHyper.getConsole().getMachine();
IVRDPServer vrdpserver = machine.getVRDPServer();
vrdpserver.setEnabled(true);
logger.info("Activating the VRDP port: " + rdpPort);
vrdpserver.setPort(new Long(rdpPort));
machine.saveSettings();
if (oSession != null)
{
oSession.close();
}
openRemoteSession();
/*
* vbox.openSession(oSession, machineId); IProgress oProgress =
* vBoxHyper.getConsole().powerUp(); oProgress.waitForCompletion(200000);
* logger.info("powerON"); long rc = oProgress.getResultCode(); if (rc != 0) {
* logger.error("Session failed!"); } if (oSession != null) { oSession.close(); }
*/
/*
* //Opening a new session vBoxHyper.getVirtualBox().openSession(vBoxHyper.getSession(),
* machineId); IProgress oProgress = vBoxHyper.getConsole().powerUp();
* logger.info("powerON"); oProgress.waitForCompletion(20000); // TODO: getResultCode
* closeSession();
*/
}
/**
* Stops the virtual machine execution.
*/
public void powerOffMachine()
{
// openSession().powerDown();
// TODO: getResultCode
vBoxHyper.reconnect();
openExistingSession();
vBoxHyper.getConsole().powerDown();
logger.info("powered off");
// closeSession();
}
/**
* Pauses the virtual machine execution.
*/
public void pauseMachine()
{
// openSession().pause();
vBoxHyper.reconnect();
openExistingSession();
vBoxHyper.getConsole().pause();
logger.info("paused");
// closeSession();
}
/**
* Resumes the virtual machine execution.
*/
public void resumeMachine()
{
// openSession().resume();
vBoxHyper.reconnect();
openExistingSession();
vBoxHyper.getConsole().resume();
logger.info("resumed");
// closeSession();
}
/**
* Resets the virtual machine.
*/
public void resetMachine()
{
// openSession().reset();
vBoxHyper.reconnect();
openExistingSession();
vBoxHyper.getConsole().reset();
logger.info("reset");
// closeSession();
}
// ///////////////////////////////////
/*
* (non-Javadoc)
* @see com.abiquo.abicloud.model.AbsVirtualMachine#findSnapshot(java.lang.String )
*/
public void findSnapshot(String name)
{
ISnapshot snap;
// openSession();
snap = machine.findSnapshot(name);
// TODO do something with it
// closeSession();
String msg = "This method is not implemented for this hypervisor plugin";
logger.error(msg);
}
// TODO
/*
* (non-Javadoc)
* @see com.abiquo.abicloud.model.AbsVirtualMachine#setCurrentSnapshot(java.util .UUID)
*/
public void setCurrentSnapshot(UUID id)
{
String msg = "This method is not implemented for this hypervisor plugin";
logger.error(msg);
}
// TODO
/*
* (non-Javadoc)
* @see com.abiquo.abicloud.model.AbsVirtualMachine#takeSnapshot(java.lang.String )
*/
public void takeSnapshot(String name)
{
String msg = "This method is not implemented for this hypervisor plugin";
logger.error(msg);
}
// TODO
/*
* (non-Javadoc)
* @see com.abiquo.abicloud.model.AbsVirtualMachine#populateEvent()
*/
public void populateEvent()
{
String msg = "This method is not implemented for this hypervisor plugin";
logger.error(msg);
}
/*
* (non-Javadoc)
* @see com.abiquo.abicloud.model.AbsVirtualMachine#deleteMachine()
*/
@Override
public void deleteMachine()
{
vBoxHyper.reconnect();
// Getting the virtualBox hypervisor
IVirtualBox vbox = vBoxHyper.getVirtualBox();
// Detaching Hard disk
IMachine targetMachine;
// Getting the session
ISession oSession = vBoxHyper.getSession();
targetMachine = vbox.findMachine(machineName);
logger.info("The machine has the ID:" + targetMachine.getId());
UUID machineId = targetMachine.getId();
// TODO Waits for a seconds to be sure that the session is in the right state
try
{
Thread.sleep(3000);
}
catch (InterruptedException e)
{
logger.error("An error waiting the session to be closed was occurred: "
+ e.getMessage());
}
vbox.openSession(oSession, machineId);
// Detaching hard disk
targetMachine = oSession.getMachine();
// TODO delete all the attached disks
IHardDisk2 diskVDI = targetMachine.getHardDisk2(StorageBus.IDE, 0, 0);
targetMachine.detachHardDisk2(StorageBus.IDE, 0, 0);
targetMachine.saveSettings();
IProgress progress = diskVDI.deleteStorage();
progress.waitForCompletion(100000);
long rc = progress.getResultCode();
if (rc != 0)
{
logger.error("An eror was occurred deleting the storage");
}
// Closing the open session
if (oSession != null)
{
oSession.close();
}
// Deregistering machine
targetMachine = vbox.unregisterMachine(machineId);
// Deleting machine settings
// vbox.openSession(oSession,machineId);
targetMachine.deleteSettings();
// oSession.getMachine().deleteSettings();
// Closing the sessions
}
@Override
public void reconfigVM(VirtualMachineConfiguration newConfiguration)
throws VirtualMachineException
{
String msg = "This method is not implemented for this hypervisor plugin";
logger.error(msg);
throw new VirtualMachineException(msg);
}
}