View Javadoc

1   /*
2    * JBoss, Home of Professional Open Source.
3    * Copyright 2013, Red Hat Middleware LLC, and individual contributors
4    * as indicated by the @author tags. See the copyright.txt file in the
5    * distribution for a full listing of individual contributors.
6    *
7    * This is free software; you can redistribute it and/or modify it
8    * under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */
22  package org.redhat.vmtruckloader.vmware.action;
23  
24  import java.rmi.RemoteException;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.redhat.vmtruckloader.vmware.VMWareMachineService;
30  import org.redhat.vmtruckloader.vmware.VMWareManagedObjectUtils;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import com.vmware.vim25.ConcurrentAccess;
35  import com.vmware.vim25.DVPortgroupConfigInfo;
36  import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
37  import com.vmware.vim25.DuplicateName;
38  import com.vmware.vim25.FileFault;
39  import com.vmware.vim25.InsufficientResourcesFault;
40  import com.vmware.vim25.InvalidDatastore;
41  import com.vmware.vim25.InvalidName;
42  import com.vmware.vim25.InvalidState;
43  import com.vmware.vim25.RuntimeFault;
44  import com.vmware.vim25.TaskInProgress;
45  import com.vmware.vim25.VirtualDevice;
46  import com.vmware.vim25.VirtualDeviceBackingInfo;
47  import com.vmware.vim25.VirtualDeviceConfigSpec;
48  import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
49  import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
50  import com.vmware.vim25.VirtualMachineConfigSpec;
51  import com.vmware.vim25.VirtualVmxnet3;
52  import com.vmware.vim25.VmConfigFault;
53  import com.vmware.vim25.mo.DistributedVirtualPortgroup;
54  import com.vmware.vim25.mo.ManagedEntity;
55  import com.vmware.vim25.mo.ServiceInstance;
56  import com.vmware.vim25.mo.VirtualMachine;
57  import com.vmware.vim25.mo.VmwareDistributedVirtualSwitch;
58  
59  /**
60   * @author Romain Pelisse - <romain@redhat.com>
61   *
62   */
63  public class MoveVirtualMachineToNetworkCallback extends AbstractVMWareActionCallback<Void> { //NOPMD, can't reduce the number of catches
64  
65      private static final Logger LOGGER = LoggerFactory.getLogger(VMWareMachineService.class);
66  
67      private String netName;
68      private String name;
69  
70      public MoveVirtualMachineToNetworkCallback(String netName, String name) {
71      	super();
72          this.netName = netName;
73          this.name = name;
74      }
75  
76      @Override
77      public Void doInVmware(ServiceInstance serviceInstance) {
78          final VirtualMachine vm = checkVmConfigState(VMWareManagedObjectUtils.getVm(serviceInstance, name));
79  
80          final String[] virtualPortConfig = findEthernetConfig(serviceInstance, netName);
81          if ( virtualPortConfig.length < 2 )
82              throw new IllegalArgumentException("The netname provided [" + netName + "] is incorrect");
83         final String portGroupKey = virtualPortConfig[0];
84         final String switchUuid = virtualPortConfig[1];
85  
86          final VirtualDeviceConfigSpec ethernet = retrieveAndUpdateEthernetPort(vm.getConfig().getHardware().getDevice(),
87                  createVirtualPortBackingInfo(portGroupKey,switchUuid));
88          if ( ethernet == null )
89              invalidState("No ethernet found for VM:" + name + ", can't move it to " + netName);
90  
91          ethernet.setOperation(VirtualDeviceConfigSpecOperation.edit);
92  
93          final VirtualMachineConfigSpec spec = new VirtualMachineConfigSpec();
94          spec.setDeviceChange(new VirtualDeviceConfigSpec[] { ethernet } );
95          reconfigureVM(vm, spec);
96          return null;
97      }
98  
99      private static void reconfigureVM(VirtualMachine vm, VirtualMachineConfigSpec spec) { //NOPMD, can't reduce the number of catches
100         try {
101             vm.reconfigVM_Task(spec);
102         } catch (InvalidName e) {
103             throw new IllegalArgumentException(e);
104         } catch (VmConfigFault e) {
105             throw new IllegalArgumentException(e);
106         } catch (DuplicateName e) {
107             throw new IllegalArgumentException(e);
108         } catch (TaskInProgress e) {
109             throw new IllegalStateException(e);
110         } catch (FileFault e) {
111             throw new IllegalStateException(e);
112         } catch (InvalidState e) {
113             throw new IllegalStateException(e);
114         } catch (ConcurrentAccess e) {
115             throw new IllegalStateException(e);
116         } catch (InvalidDatastore e) {
117             throw new IllegalArgumentException(e);
118         } catch (InsufficientResourcesFault e) {
119             throw new IllegalStateException(e);
120         } catch (RuntimeFault e) {
121             throw new IllegalStateException(e);
122         } catch (RemoteException e) {
123             throw new IllegalStateException(e);
124         }
125     }
126 
127     private static VirtualDeviceConfigSpec retrieveAndUpdateEthernetPort(VirtualDevice[] devices, VirtualDeviceBackingInfo netBackingInfo) {
128         VirtualDeviceConfigSpec ethernet = null;
129         for ( VirtualDevice device : devices ) {
130             if ( device instanceof VirtualVmxnet3 ) {
131                 final VirtualVmxnet3 xnet3 = (VirtualVmxnet3) device;
132                 xnet3.setBacking(netBackingInfo);
133                 ethernet = specFromDevice(xnet3);
134             }
135         }
136         return ethernet;
137     }
138 
139     private static void invalidState(final String mssg) {
140         LOGGER.warn(mssg);
141         throw new IllegalStateException(mssg);
142     }
143 
144     private VirtualMachine checkVmConfigState(VirtualMachine vm) {
145         if ( vm == null || vm.getConfig() == null || vm.getConfig().getHardware() == null || vm.getConfig().getHardware().getDevice() == null) {
146             invalidState("VM " + name + " has no config or hardware infos. Something is wrong, aborting moving the VM to VLAN" + netName);
147         }
148         return vm;
149     }
150     
151     private static VirtualEthernetCardDistributedVirtualPortBackingInfo createVirtualPortBackingInfo(String portGroupKey, String switchUuid) {
152 		final VirtualEthernetCardDistributedVirtualPortBackingInfo netBacking = new VirtualEthernetCardDistributedVirtualPortBackingInfo();
153 		final DistributedVirtualSwitchPortConnection port = new DistributedVirtualSwitchPortConnection();
154 		port.setPortgroupKey(portGroupKey);
155 		port.setSwitchUuid(switchUuid);
156 		netBacking.setPort(port);
157 		return netBacking;
158 	}
159     
160 	private static VirtualDeviceConfigSpec specFromDevice(VirtualDevice device) {
161 		final VirtualDeviceConfigSpec spec = new VirtualDeviceConfigSpec();
162 		spec.setOperation(VirtualDeviceConfigSpecOperation.add);
163 		spec.setDevice(device);
164 		return spec;
165 	}
166 
167 	/**
168 	 * find port group key and virtual switch uuid for a network
169 	 * @param vc           the virtual center
170 	 * @param networkName  the network name
171 	 * @return String array with port group key and switch uuid
172 	 */
173 	private String[] findEthernetConfig(ServiceInstance serviceInstance, String networkName) {
174 		String networkNameEncoded = networkName.replaceAll("/", "%2f"); // slashes have to be encoded :-/
175 		System.out.println("NetworkName:" + networkName);
176 		Map<String, VmwareDistributedVirtualSwitch> switches = new HashMap<String, VmwareDistributedVirtualSwitch>();				
177 		List<ManagedEntity> switchList = VMWareManagedObjectUtils.getManagedEntities(serviceInstance,VmwareDistributedVirtualSwitch.class.getSimpleName());
178 		for (ManagedEntity me: switchList) {
179 			VmwareDistributedVirtualSwitch sw = (VmwareDistributedVirtualSwitch)me;
180 			switches.put(sw.getMOR().get_value(), sw);
181 			System.out.println("Switch found:" + sw.getName() + "[" + sw.getNetworkResourcePool() + "]");
182 		}
183 
184 		List<ManagedEntity> managedEntities = VMWareManagedObjectUtils.getManagedEntities(serviceInstance,DistributedVirtualPortgroup.class.getSimpleName());
185 		for (ManagedEntity me: managedEntities) {
186 			DistributedVirtualPortgroup g = (DistributedVirtualPortgroup)me;
187 			if (g.getName().equals(networkNameEncoded)) {
188 				String switchKey = ((DVPortgroupConfigInfo)g.getConfig()).getDistributedVirtualSwitch().get_value();
189 				VmwareDistributedVirtualSwitch sw = switches.get(switchKey);
190 				System.out.println("VirtualSwitch found:" + g.getName() + "[" + g.getKey() + "]");
191 				return new String[] { g.getKey(), sw.getUuid() };
192 			}
193 		}
194 		return new String[0];
195 	}
196 
197 }