/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.redhat.vmtruckloader.vmware.action;
import java.rmi.RemoteException;
import org.redhat.vmtruckloader.service.MachineSpecification;
import org.redhat.vmtruckloader.vmware.VMWareMachineSpecsUtils;
import org.redhat.vmtruckloader.vmware.VMWareManagedObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vmware.vim25.VirtualDevice;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
import com.vmware.vim25.VirtualEthernetCard;
import com.vmware.vim25.VirtualMachineCloneSpec;
import com.vmware.vim25.VirtualMachineRelocateSpec;
import com.vmware.vim25.mo.Datastore;
import com.vmware.vim25.mo.Folder;
import com.vmware.vim25.mo.ResourcePool;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VirtualMachine;
/**
* Clone a VM - not really tested...
*
* @author Duncan Doyle - <ddoyle@redhat.com>
* @author Romain Pelisse - <romain@redhat.com>
*
*/
public class CloneMachineCallback extends AbstractVMWareActionCallback<MachineSpecification> {
private static final Logger LOGGER = LoggerFactory.getLogger(CloneMachineCallback.class);
private final String sourceMachineName;
private MachineSpecification spec;
public CloneMachineCallback(final String sourceMachineName, MachineSpecification machineSpecification) {
this.sourceMachineName = sourceMachineName;
this.spec = machineSpecification;
}
private VirtualMachineRelocateSpec buildRelocateSpec(ServiceInstance serviceInstance) {
VirtualMachineRelocateSpec relocateSpec = new VirtualMachineRelocateSpec();
final String mssg = "Can't retrieve ResourcePool named " + spec.getResourcePoolName();
ResourcePool pool = VMWareManagedObjectUtils.findResourcePoolByName(serviceInstance, spec.getResourcePoolName());
if ( pool == null ) {
LOGGER.error(mssg);
throw new IllegalArgumentException(mssg);
}
relocateSpec.pool = pool.getMOR();
Datastore store = VMWareManagedObjectUtils.findDataStore(spec.getDatastoreName(), spec.getDiskSize(), serviceInstance);
relocateSpec.datastore = store.getMOR();
return relocateSpec;
}
private void specDebugInfo(VirtualMachineCloneSpec cloneSpec, VirtualMachine sourceVm) {
if ( LOGGER.isDebugEnabled() ) {
LOGGER.debug("- sourceVm.getParent():" + sourceVm.getParent());
LOGGER.debug("- name:" + spec.getHostname() );
LOGGER.debug("- cloneSpec:" + cloneSpec.toString() );
}
}
private void retrieveAndRemoveExistingEthernetCard(VirtualMachine sourceVm,VirtualMachineCloneSpec cloneSpec ) {
if ( sourceVm == null )
throw new IllegalArgumentException("SourceVM is 'null', can't clone VM");
for ( VirtualDevice device : sourceVm.getConfig().getHardware().getDevice() ) {
if ( LOGGER.isDebugEnabled() )
LOGGER.debug("Device found:" + device.getDeviceInfo().getLabel() + "[" + device.getClass() + "]");
if ( device instanceof VirtualEthernetCard ) {
VirtualEthernetCard nic = (VirtualEthernetCard) device;
VirtualDeviceConfigSpec nicSpec = new VirtualDeviceConfigSpec();
nicSpec.setDevice(nic);
nicSpec.setOperation(VirtualDeviceConfigSpecOperation.remove);
cloneSpec.getConfig().deviceChange[1] = nicSpec;
}
}
}
@Override
public MachineSpecification doInVmware(ServiceInstance serviceInstance) {
VirtualMachineRelocateSpec relocateSpec = buildRelocateSpec(serviceInstance);
VirtualMachineCloneSpec cloneSpec = new VirtualMachineCloneSpec();
cloneSpec.template = false;
cloneSpec.powerOn = false;
cloneSpec.location = relocateSpec;
cloneSpec.setConfig(VMWareMachineSpecsUtils.buildVmSpec(serviceInstance, this.spec));
VirtualMachine sourceVm = VMWareManagedObjectUtils.getVm(serviceInstance, sourceMachineName);
retrieveAndRemoveExistingEthernetCard(sourceVm, cloneSpec);
Task task;
try {
specDebugInfo(cloneSpec, sourceVm);
Folder setupFolder = VMWareManagedObjectUtils.lookVmFolder(serviceInstance, spec.getFolder());
task = sourceVm.cloneVM_Task(setupFolder, spec.getHostname(), cloneSpec);
LOGGER.debug("TaskKey = " + task.getTaskInfo().key);
try {
String status = task.waitForTask();
if ( ! Task.SUCCESS.equals(status))
throw new IllegalStateException("Operation fails (status:" + status + ") - resulting clone, if any, may not be in a consistent state." +
"Also checks if there is not already a VM called " + spec.getHostname());
} catch (InterruptedException ie) {
LOGGER.error("Interrupted while waiting for cloning of machine '" + sourceMachineName + "' to '"
+ spec.getHostname() + "' in resource pool '" + spec.getHostname() + "'.", ie);
Thread.currentThread().interrupt();
}
return new VirtualMachineTransformer(spec).getMacAddress(VMWareManagedObjectUtils.getVm(serviceInstance, spec.getVmName()));
} catch (RemoteException re) {
String errorMessage = "Error while cloning '" + sourceMachineName + "' to '" + spec.getHostname() + "' in resource pool '"
+ spec.getResourcePoolName() + "'.";
LOGGER.error(errorMessage, re);
throw new IllegalArgumentException(errorMessage, re);
}
}
}