/*
* 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 java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.redhat.vmtruckloader.vmware.VMWareMachineService;
import org.redhat.vmtruckloader.vmware.VMWareManagedObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vmware.vim25.ConcurrentAccess;
import com.vmware.vim25.DVPortgroupConfigInfo;
import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
import com.vmware.vim25.DuplicateName;
import com.vmware.vim25.FileFault;
import com.vmware.vim25.InsufficientResourcesFault;
import com.vmware.vim25.InvalidDatastore;
import com.vmware.vim25.InvalidName;
import com.vmware.vim25.InvalidState;
import com.vmware.vim25.RuntimeFault;
import com.vmware.vim25.TaskInProgress;
import com.vmware.vim25.VirtualDevice;
import com.vmware.vim25.VirtualDeviceBackingInfo;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
import com.vmware.vim25.VirtualMachineConfigSpec;
import com.vmware.vim25.VirtualVmxnet3;
import com.vmware.vim25.VmConfigFault;
import com.vmware.vim25.mo.DistributedVirtualPortgroup;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.VirtualMachine;
import com.vmware.vim25.mo.VmwareDistributedVirtualSwitch;
/**
* @author Romain Pelisse - <romain@redhat.com>
*
*/
public class MoveVirtualMachineToNetworkCallback extends AbstractVMWareActionCallback<Void> { //NOPMD, can't reduce the number of catches
private static final Logger LOGGER = LoggerFactory.getLogger(VMWareMachineService.class);
private String netName;
private String name;
public MoveVirtualMachineToNetworkCallback(String netName, String name) {
super();
this.netName = netName;
this.name = name;
}
@Override
public Void doInVmware(ServiceInstance serviceInstance) {
final VirtualMachine vm = checkVmConfigState(VMWareManagedObjectUtils.getVm(serviceInstance, name));
final String[] virtualPortConfig = findEthernetConfig(serviceInstance, netName);
if ( virtualPortConfig.length < 2 )
throw new IllegalArgumentException("The netname provided [" + netName + "] is incorrect");
final String portGroupKey = virtualPortConfig[0];
final String switchUuid = virtualPortConfig[1];
final VirtualDeviceConfigSpec ethernet = retrieveAndUpdateEthernetPort(vm.getConfig().getHardware().getDevice(),
createVirtualPortBackingInfo(portGroupKey,switchUuid));
if ( ethernet == null )
invalidState("No ethernet found for VM:" + name + ", can't move it to " + netName);
ethernet.setOperation(VirtualDeviceConfigSpecOperation.edit);
final VirtualMachineConfigSpec spec = new VirtualMachineConfigSpec();
spec.setDeviceChange(new VirtualDeviceConfigSpec[] { ethernet } );
reconfigureVM(vm, spec);
return null;
}
private static void reconfigureVM(VirtualMachine vm, VirtualMachineConfigSpec spec) { //NOPMD, can't reduce the number of catches
try {
vm.reconfigVM_Task(spec);
} catch (InvalidName e) {
throw new IllegalArgumentException(e);
} catch (VmConfigFault e) {
throw new IllegalArgumentException(e);
} catch (DuplicateName e) {
throw new IllegalArgumentException(e);
} catch (TaskInProgress e) {
throw new IllegalStateException(e);
} catch (FileFault e) {
throw new IllegalStateException(e);
} catch (InvalidState e) {
throw new IllegalStateException(e);
} catch (ConcurrentAccess e) {
throw new IllegalStateException(e);
} catch (InvalidDatastore e) {
throw new IllegalArgumentException(e);
} catch (InsufficientResourcesFault e) {
throw new IllegalStateException(e);
} catch (RuntimeFault e) {
throw new IllegalStateException(e);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
private static VirtualDeviceConfigSpec retrieveAndUpdateEthernetPort(VirtualDevice[] devices, VirtualDeviceBackingInfo netBackingInfo) {
VirtualDeviceConfigSpec ethernet = null;
for ( VirtualDevice device : devices ) {
if ( device instanceof VirtualVmxnet3 ) {
final VirtualVmxnet3 xnet3 = (VirtualVmxnet3) device;
xnet3.setBacking(netBackingInfo);
ethernet = specFromDevice(xnet3);
}
}
return ethernet;
}
private static void invalidState(final String mssg) {
LOGGER.warn(mssg);
throw new IllegalStateException(mssg);
}
private VirtualMachine checkVmConfigState(VirtualMachine vm) {
if ( vm == null || vm.getConfig() == null || vm.getConfig().getHardware() == null || vm.getConfig().getHardware().getDevice() == null) {
invalidState("VM " + name + " has no config or hardware infos. Something is wrong, aborting moving the VM to VLAN" + netName);
}
return vm;
}
private static VirtualEthernetCardDistributedVirtualPortBackingInfo createVirtualPortBackingInfo(String portGroupKey, String switchUuid) {
final VirtualEthernetCardDistributedVirtualPortBackingInfo netBacking = new VirtualEthernetCardDistributedVirtualPortBackingInfo();
final DistributedVirtualSwitchPortConnection port = new DistributedVirtualSwitchPortConnection();
port.setPortgroupKey(portGroupKey);
port.setSwitchUuid(switchUuid);
netBacking.setPort(port);
return netBacking;
}
private static VirtualDeviceConfigSpec specFromDevice(VirtualDevice device) {
final VirtualDeviceConfigSpec spec = new VirtualDeviceConfigSpec();
spec.setOperation(VirtualDeviceConfigSpecOperation.add);
spec.setDevice(device);
return spec;
}
/**
* find port group key and virtual switch uuid for a network
* @param vc the virtual center
* @param networkName the network name
* @return String array with port group key and switch uuid
*/
private String[] findEthernetConfig(ServiceInstance serviceInstance, String networkName) {
String networkNameEncoded = networkName.replaceAll("/", "%2f"); // slashes have to be encoded :-/
System.out.println("NetworkName:" + networkName);
Map<String, VmwareDistributedVirtualSwitch> switches = new HashMap<String, VmwareDistributedVirtualSwitch>();
List<ManagedEntity> switchList = VMWareManagedObjectUtils.getManagedEntities(serviceInstance,VmwareDistributedVirtualSwitch.class.getSimpleName());
for (ManagedEntity me: switchList) {
VmwareDistributedVirtualSwitch sw = (VmwareDistributedVirtualSwitch)me;
switches.put(sw.getMOR().get_value(), sw);
System.out.println("Switch found:" + sw.getName() + "[" + sw.getNetworkResourcePool() + "]");
}
List<ManagedEntity> managedEntities = VMWareManagedObjectUtils.getManagedEntities(serviceInstance,DistributedVirtualPortgroup.class.getSimpleName());
for (ManagedEntity me: managedEntities) {
DistributedVirtualPortgroup g = (DistributedVirtualPortgroup)me;
if (g.getName().equals(networkNameEncoded)) {
String switchKey = ((DVPortgroupConfigInfo)g.getConfig()).getDistributedVirtualSwitch().get_value();
VmwareDistributedVirtualSwitch sw = switches.get(switchKey);
System.out.println("VirtualSwitch found:" + g.getName() + "[" + g.getKey() + "]");
return new String[] { g.getKey(), sw.getUuid() };
}
}
return new String[0];
}
}