Add VM work job dispatcher, MethodCapturer etc

This commit is contained in:
Kelven Yang 2013-04-30 18:12:23 -07:00
parent 9786f7b7bb
commit 86053cd8b2
18 changed files with 459 additions and 14 deletions

View File

@ -30,6 +30,10 @@ public class DataCenterDeployment implements DeploymentPlan {
boolean _recreateDisks;
ReservationContext _context;
public DataCenterDeployment() {
_dcId = 0;
}
public DataCenterDeployment(long dataCenterId) {
this(dataCenterId, null, null, null, null, null);
}

View File

@ -36,6 +36,7 @@ import com.cloud.user.Account;
*/
public interface VirtualMachineProfile<T extends VirtualMachine> {
// Making Param strong-typing looks like a over-kill to me
public static class Param {
public static final Param VmPassword = new Param("VmPassword");
@ -56,6 +57,27 @@ public interface VirtualMachineProfile<T extends VirtualMachine> {
public String getName() {
return name;
}
// Param is used in HashMap data-structure, we need to provide hashCode() and equals in order to
// make HashMap work
@Override
public int hashCode() {
if(name != null)
return name.hashCode();
return 0;
}
@Override
public boolean equals(Object other) {
if(other == null)
return false;
if(!(other instanceof Param))
return false;
assert(name != null);
return name.equals(((Param)other).getName());
}
}
String getHostName();

View File

@ -56,7 +56,7 @@ public class AsyncCallbackDispatcher<T, R> implements AsyncCompletionCallback {
public T getTarget() {
Enhancer en = new Enhancer();
en.setSuperclass(_targetObject.getClass());
en.setCallbacks(new Callback[]{new MethodInterceptor() {
en.setCallbacks(new Callback[] { new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {

View File

@ -31,7 +31,6 @@ import com.cloud.async.AsyncJob;
import com.cloud.async.AsyncJobDispatcher;
import com.cloud.async.AsyncJobManager;
import com.cloud.async.AsyncJobResult;
import com.cloud.async.SyncQueueManager;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
@ -46,7 +45,6 @@ public class ApiAsyncJobDispatcher extends AdapterBase implements AsyncJobDispat
@Inject private ApiDispatcher _dispatcher;
@Inject private AsyncJobManager _asyncJobMgr;
@Inject private SyncQueueManager _queueMgr;
@Inject private AccountDao _accountDao;
public ApiAsyncJobDispatcher() {

View File

@ -25,7 +25,7 @@ public class ApiSerializerHelper {
public static final Logger s_logger = Logger.getLogger(ApiSerializerHelper.class.getName());
public static String token = "/";
public static String toSerializedStringOld(Object result) {
public static String toSerializedString(Object result) {
if (result != null) {
Class<?> clz = result.getClass();
Gson gson = ApiGsonHelper.getBuilder().create();

View File

@ -175,7 +175,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
job.setInstanceId(null);
if (resultObject != null) {
job.setResult(ApiSerializerHelper.toSerializedStringOld(resultObject));
job.setResult(ApiSerializerHelper.toSerializedString(resultObject));
}
job.setLastUpdated(DateUtil.currentGMTTime());
@ -209,7 +209,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
job.setProcessStatus(processStatus);
if(resultObject != null) {
job.setResult(ApiSerializerHelper.toSerializedStringOld(resultObject));
job.setResult(ApiSerializerHelper.toSerializedString(resultObject));
}
job.setLastUpdated(DateUtil.currentGMTTime());
_jobDao.update(jobId, job);
@ -732,7 +732,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
}
private static String getSerializedErrorMessage(String errorMessage) {
return ApiSerializerHelper.toSerializedStringOld(getResetResultResponse(errorMessage));
return ApiSerializerHelper.toSerializedString(getResetResultResponse(errorMessage));
}
@Override

View File

@ -91,7 +91,7 @@ public class AsyncJobResult {
}
public void setResultObject(Object result) {
this.result = ApiSerializerHelper.toSerializedStringOld(result);
this.result = ApiSerializerHelper.toSerializedString(result);
}
@Override

View File

@ -597,6 +597,17 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
return advanceStart(vm, params, caller, account, null);
}
public <T extends VMInstanceVO> T advanceStartNew(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account, DeploymentPlan planToDeploy)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
vm = vmGuru.findById(vm.getId());
ServiceOfferingVO offering = _offeringDao.findById(vm.getServiceOfferingId());
VMTemplateVO template = _templateDao.findById(vm.getTemplateId());
return vm;
}
@Override
public <T extends VMInstanceVO> T advanceStart(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account, DeploymentPlan planToDeploy)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {

View File

@ -0,0 +1,54 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.vm;
public class VmWork {
long userId;
long accountId;
long vmId;
// VirtualMachineManagerImpl's method name that the work will be handled in the manager
// it should be unique in the implementation class
String targetMethodName;
public VmWork() {
}
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
public long getVmId() {
return vmId;
}
public void setVmId(long vmId) {
this.vmId = vmId;
}
}

View File

@ -0,0 +1,58 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.vm;
import javax.inject.Inject;
import com.cloud.api.ApiSerializerHelper;
import com.cloud.async.AsyncJob;
import com.cloud.async.AsyncJobDispatcher;
import com.cloud.async.AsyncJobManager;
import com.cloud.async.AsyncJobResult;
import com.cloud.user.AccountVO;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.component.AdapterBase;
public class VmWorkJobDispatcher extends AdapterBase implements AsyncJobDispatcher {
@Inject private VirtualMachineManager _vmMgr;
@Inject private AsyncJobManager _asyncJobMgr;
@Inject private AccountDao _accountDao;
@Override
public void RunJob(AsyncJob job) {
try {
VmWork work = (VmWork)ApiSerializerHelper.fromSerializedString(job.getCmdInfo());
assert(work != null);
AccountVO account = _accountDao.findById(work.getAccountId());
UserContext.registerContext(work.getUserId(), account, null, false);
try {
_asyncJobMgr.completeAsyncJob(job.getId(), AsyncJobResult.STATUS_SUCCEEDED, 0, null);
} finally {
UserContext.unregisterContext();
}
} catch(Throwable e) {
_asyncJobMgr.completeAsyncJob(job.getId(), AsyncJobResult.STATUS_FAILED, 0, null);
}
}
}

View File

@ -0,0 +1,74 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.vm;
import java.util.HashMap;
import java.util.Map;
import com.cloud.api.ApiSerializerHelper;
import com.cloud.deploy.DeploymentPlan;
public class VmWorkStart extends VmWork {
private DeploymentPlan plan;
// use serialization friendly map
private Map<String, String> rawParams;
public VmWorkStart() {
}
public DeploymentPlan getPlan() {
return plan;
}
public void setPlan(DeploymentPlan plan) {
this.plan = plan;
}
public Map<String, String> getRawParams() {
return rawParams;
}
public void setRawParams(Map<String, String> params) {
this.rawParams = params;
}
public Map<VirtualMachineProfile.Param, Object> getParams() {
Map<VirtualMachineProfile.Param, Object> map = new HashMap<VirtualMachineProfile.Param, Object>();
if(rawParams != null) {
// Strong-typing for VirtualMachineProfile.Param is really over-kill, have to deal with it anyway
for(Map.Entry<String, String> entry : rawParams.entrySet()) {
VirtualMachineProfile.Param key = new VirtualMachineProfile.Param(entry.getKey());
Object val = ApiSerializerHelper.fromSerializedString(entry.getValue());
map.put(key, val);
}
}
return map;
}
public void setParams( Map<VirtualMachineProfile.Param, Object> params) {
if(params != null) {
rawParams = new HashMap<String, String>();
for(Map.Entry<VirtualMachineProfile.Param, Object> entry : params.entrySet()) {
rawParams.put(entry.getKey().getName(), ApiSerializerHelper.toSerializedString(entry.getValue()));
}
}
}
}

View File

@ -168,7 +168,7 @@ public class KeystoreTest extends TestCase {
vm.setObjectName("virtualmachine");
*/
String result = ApiSerializerHelper.toSerializedStringOld(vm);
String result = ApiSerializerHelper.toSerializedString(vm);
// String result = "org.apache.cloudstack.api.response.UserVmResponse/virtualmachine/{\"id\":{\"_tableName\":\"vm_instance\",\"_value\":3},\"name\":\"i-2-3-KY\",\"displayname\":\"i-2-3-KY\",\"account\":\"admin\",\"projectid\":{\"_tableName\":\"projects\"},\"domainid\":{\"_tableName\":\"domain\",\"_value\":1},\"domain\":\"ROOT\",\"created\":\"2011-11-02T21:54:07-0700\",\"state\":\"Running\",\"haenable\":false,\"groupid\":{\"_tableName\":\"instance_group\"},\"zoneid\":{\"_tableName\":\"data_center\",\"_value\":1},\"zonename\":\"KY\",\"hostid\":{\"_tableName\":\"host\",\"_value\":1},\"hostname\":\"xenserver-basic\",\"templateid\":{\"_tableName\":\"vm_template\",\"_value\":2},\"templatename\":\"CentOS 5.3(64-bit) no GUI (XenServer)\",\"templatedisplaytext\":\"CentOS 5.3(64-bit) no GUI (XenServer)\",\"passwordenabled\":false,\"isoid\":{\"_tableName\":\"vm_template\"},\"serviceofferingid\":{\"_tableName\":\"disk_offering\",\"_value\":7},\"serviceofferingname\":\"Small Instance\",\"cpunumber\":1,\"cpuspeed\":500,\"memory\":512,\"guestosid\":{\"_tableName\":\"guest_os\",\"_value\":12},\"rootdeviceid\":0,\"rootdevicetype\":\"NetworkFilesystem\",\"securitygroup\":[],\"jobid\":{\"_tableName\":\"async_job\"},\"nic\":[{\"id\":7,\"networkid\":200,\"netmask\":\"255.255.255.0\",\"gateway\":\"10.1.1.1\",\"ipaddress\":\"10.1.1.116\",\"isolationuri\":\"vlan://1699\",\"broadcasturi\":\"vlan://1699\",\"traffictype\":\"Guest\",\"type\":\"Virtual\",\"isdefault\":true,\"macaddress\":\"02:00:39:a7:00:01\"}],\"hypervisor\":\"XenServer\"}";
System.out.println(result);
//Object obj = ApiSerializerHelper.fromSerializedString(result);
@ -177,7 +177,7 @@ public class KeystoreTest extends TestCase {
alert.setId("100");
alert.setDescription("Hello");
result = ApiSerializerHelper.toSerializedStringOld(alert);
result = ApiSerializerHelper.toSerializedString(alert);
System.out.println(result);
ApiSerializerHelper.fromSerializedString(result);
}

View File

@ -40,16 +40,12 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
import org.junit.Test;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import static org.mockito.Mockito.*;
import java.lang.reflect.Field;
import java.util.List;
public class VirtualMachineManagerImplTest {

View File

@ -0,0 +1,61 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.vm;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import junit.framework.TestCase;
import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.google.gson.Gson;
public class VmWorkTest extends TestCase {
Gson gson = new Gson();
@Test
public void testDeployPlanSerialization() {
DeploymentPlan plan = new DataCenterDeployment(1L);
ExcludeList excludeList = new ExcludeList();
excludeList.addCluster(1);
plan.setAvoids(excludeList);
String json = gson.toJson(plan);
DeploymentPlan planClone = gson.fromJson(json, DataCenterDeployment.class);
Assert.assertTrue(planClone.getDataCenterId() == plan.getDataCenterId());
}
@Test
public void testVmWorkStart() {
VmWorkStart work = new VmWorkStart();
Map<VirtualMachineProfile.Param, Object> params = new HashMap<VirtualMachineProfile.Param, Object>();
params.put(VirtualMachineProfile.Param.HaTag, "HA");
params.put(VirtualMachineProfile.Param.ControlNic, new Long(100));
work.setParams(params);
VmWorkStart workClone = gson.fromJson(gson.toJson(work), VmWorkStart.class);
Assert.assertTrue(work.getParams().size() == workClone.getParams().size());
Assert.assertTrue(work.getParams().get(VirtualMachineProfile.Param.HaTag).equals(workClone.getParams().get(VirtualMachineProfile.Param.HaTag)));
}
}

View File

@ -39,4 +39,17 @@ public class EnumUtils {
}
return defaultVal;
}
public static <T extends Enum<T>> T fromString(Class<T> clz, String value) {
assert(clz != null);
if(value != null) {
try {
return Enum.valueOf(clz, value.trim());
} catch(IllegalArgumentException ex) {
assert(false);
}
}
return null;
}
}

View File

@ -0,0 +1,113 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.utils;
import java.lang.reflect.Method;
import java.util.WeakHashMap;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/*
* This helper class provides a way to retrieve Method in a strong-type way. It takes advantage of power of
* Intelligent IDE(Eclipse) in code-editing
*
* DummyImpl dummy = new DummyImpl();
* MethodCapturer<DummyImpl> capturer = MethodCapturer.capture(dummy);
* Method method = capturer.get(capturer.instance().foo2());
*
*/
public class MethodCapturer<T> {
private final static int CACHE_SIZE = 1024;
private T _instance;
private Method _method;
private static WeakHashMap<Object, Object> s_cache = new WeakHashMap<Object, Object>();
private MethodCapturer() {
}
@SuppressWarnings("unchecked")
public static <T> MethodCapturer<T> capture(T obj) {
synchronized(s_cache) {
MethodCapturer<T> capturer = (MethodCapturer<T>)s_cache.get(obj);
if(capturer != null) {
return capturer;
}
final MethodCapturer<T> capturerNew = new MethodCapturer<T>();
Enhancer en = new Enhancer();
en.setSuperclass(obj.getClass());
en.setCallbacks(new Callback[] { new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
capturerNew.setMethod(arg1);
return null;
}
},
new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
return null;
}
}
});
en.setCallbackFilter(new CallbackFilter() {
public int accept(Method method) {
if (method.getParameterTypes().length == 0 && method.getName().equals("finalize")) {
return 1;
}
return 0;
}}
);
((MethodCapturer<T>)capturerNew).setInstance((T)en.create());
// We expect MethodCapturer is only used for singleton objects here, so we only maintain a limited cache
// here
if(s_cache.size() < CACHE_SIZE) {
s_cache.put(obj, capturerNew);
}
return capturerNew;
}
}
public T instance() {
return _instance;
}
private void setInstance(T instance) {
_instance = instance;
}
public Method get(Object... useless) {
return _method;
}
private void setMethod(Method method) {
_method = method;
}
}

View File

@ -25,4 +25,8 @@ public class DummyImpl implements DummyInterface {
public void foo() {
System.out.println("Basic foo implementation");
}
public int foo2() {
return 0;
}
}

View File

@ -0,0 +1,37 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.utils;
import java.lang.reflect.Method;
public class MethodCatpurerTest {
public MethodCatpurerTest() {
}
public void MethodCapturerTest() {
DummyImpl dummy = new DummyImpl();
MethodCapturer<DummyImpl> capturer = MethodCapturer.capture(dummy);
Method method = capturer.get(capturer.instance().foo2());
System.out.println("Method name: " + method.getName());
}
public static void main(String args[]) {
new MethodCatpurerTest().MethodCapturerTest();
}
}