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  
23  package org.redhat.vmtruckloader.vmware.action;
24  
25  import java.rmi.RemoteException;
26  
27  import org.redhat.vmtruckloader.service.MachineSpecification;
28  import org.redhat.vmtruckloader.vmware.VMWareMachineSpecsUtils;
29  import org.redhat.vmtruckloader.vmware.VMWareManagedObjectUtils;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  import com.vmware.vim25.VirtualDevice;
34  import com.vmware.vim25.VirtualDeviceConfigSpec;
35  import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
36  import com.vmware.vim25.VirtualEthernetCard;
37  import com.vmware.vim25.VirtualMachineCloneSpec;
38  import com.vmware.vim25.VirtualMachineRelocateSpec;
39  import com.vmware.vim25.mo.Datastore;
40  import com.vmware.vim25.mo.Folder;
41  import com.vmware.vim25.mo.ResourcePool;
42  import com.vmware.vim25.mo.ServiceInstance;
43  import com.vmware.vim25.mo.Task;
44  import com.vmware.vim25.mo.VirtualMachine;
45  
46  /**
47   * Clone a VM - not really tested...
48   *
49   * @author Duncan Doyle - <ddoyle@redhat.com>
50   * @author Romain Pelisse - <romain@redhat.com>
51   *
52   */
53  public class CloneMachineCallback extends AbstractVMWareActionCallback<MachineSpecification> {
54  
55  	private static final Logger LOGGER = LoggerFactory.getLogger(CloneMachineCallback.class);
56  	private final String sourceMachineName;
57  	private MachineSpecification spec;
58  
59  	public CloneMachineCallback(final String sourceMachineName, MachineSpecification machineSpecification) {
60  		this.sourceMachineName = sourceMachineName;
61  		this.spec = machineSpecification;
62  	}
63  
64  	private VirtualMachineRelocateSpec buildRelocateSpec(ServiceInstance serviceInstance) {
65  		VirtualMachineRelocateSpec relocateSpec = new VirtualMachineRelocateSpec();
66  
67  		final String mssg = "Can't retrieve ResourcePool named " + spec.getResourcePoolName();
68  		ResourcePool pool = VMWareManagedObjectUtils.findResourcePoolByName(serviceInstance, spec.getResourcePoolName());
69  		if ( pool == null ) {
70  			LOGGER.error(mssg);
71  			throw new IllegalArgumentException(mssg);
72  		}
73  		relocateSpec.pool = pool.getMOR();
74  
75  		Datastore store = VMWareManagedObjectUtils.findDataStore(spec.getDatastoreName(), spec.getDiskSize(), serviceInstance);
76  		relocateSpec.datastore = store.getMOR();
77  
78  		return relocateSpec;
79  	}
80  
81  	private void specDebugInfo(VirtualMachineCloneSpec cloneSpec, VirtualMachine sourceVm) {
82  		if ( LOGGER.isDebugEnabled() ) {
83  			LOGGER.debug("- sourceVm.getParent():" +  sourceVm.getParent());
84  			LOGGER.debug("- name:" +  spec.getHostname() );
85  			LOGGER.debug("- cloneSpec:" +  cloneSpec.toString() );
86  		}
87  	}
88  
89  	private void retrieveAndRemoveExistingEthernetCard(VirtualMachine sourceVm,VirtualMachineCloneSpec cloneSpec ) {
90          if ( sourceVm == null )
91              throw new IllegalArgumentException("SourceVM is 'null', can't clone VM");
92  		for ( VirtualDevice device : sourceVm.getConfig().getHardware().getDevice() ) {
93  			if ( LOGGER.isDebugEnabled() )
94  				LOGGER.debug("Device found:" + device.getDeviceInfo().getLabel() + "[" + device.getClass() + "]");
95  			if ( device instanceof VirtualEthernetCard )  {
96  				VirtualEthernetCard nic = (VirtualEthernetCard) device;
97  				VirtualDeviceConfigSpec nicSpec = new VirtualDeviceConfigSpec();
98  				nicSpec.setDevice(nic);
99  				nicSpec.setOperation(VirtualDeviceConfigSpecOperation.remove);
100 				cloneSpec.getConfig().deviceChange[1] = nicSpec;
101 			}
102 		}
103 	}
104 
105 	@Override
106 	public MachineSpecification doInVmware(ServiceInstance serviceInstance) {
107 		VirtualMachineRelocateSpec relocateSpec = buildRelocateSpec(serviceInstance);
108 
109 		VirtualMachineCloneSpec cloneSpec = new VirtualMachineCloneSpec();
110 		cloneSpec.template = false;
111 		cloneSpec.powerOn = false;
112 		cloneSpec.location = relocateSpec;
113 		cloneSpec.setConfig(VMWareMachineSpecsUtils.buildVmSpec(serviceInstance, this.spec));
114 
115 		VirtualMachine sourceVm = VMWareManagedObjectUtils.getVm(serviceInstance, sourceMachineName);
116 		retrieveAndRemoveExistingEthernetCard(sourceVm, cloneSpec);
117 		Task task;
118 		try {
119 			specDebugInfo(cloneSpec, sourceVm);
120 			Folder setupFolder = VMWareManagedObjectUtils.lookVmFolder(serviceInstance, spec.getFolder());
121 
122 			task = sourceVm.cloneVM_Task(setupFolder, spec.getHostname(), cloneSpec);
123 			LOGGER.debug("TaskKey = " + task.getTaskInfo().key);
124 
125 			try {
126 				String status = task.waitForTask();
127 				if ( ! Task.SUCCESS.equals(status))
128                     throw new IllegalStateException("Operation fails (status:" + status + ") - resulting clone, if any, may not be in a consistent state." +
129                             "Also checks if there is not already a VM called " + spec.getHostname());
130 			} catch (InterruptedException ie) {
131 				LOGGER.error("Interrupted while waiting for cloning of machine '" + sourceMachineName + "' to '"
132 						+ spec.getHostname() + "' in resource pool '" + spec.getHostname() + "'.", ie);
133 				Thread.currentThread().interrupt();
134 			}
135 			return new VirtualMachineTransformer(spec).getMacAddress(VMWareManagedObjectUtils.getVm(serviceInstance, spec.getVmName()));
136 		} catch (RemoteException re) {
137 			String errorMessage = "Error while cloning '" + sourceMachineName + "' to '" + spec.getHostname() + "' in resource pool '"
138 					+ spec.getResourcePoolName() + "'.";
139 			LOGGER.error(errorMessage, re);
140 			throw new IllegalArgumentException(errorMessage, re);
141 		}
142 	}
143 }