diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java index 080e65b1fee..6d09561fcca 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java @@ -31,12 +31,14 @@ import com.cloud.agent.Listener; import com.cloud.agent.StartupCommandProcessor; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.SetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.manager.AgentAttache; import com.cloud.agent.manager.Commands; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConnectionException; import com.cloud.exception.OperationTimedoutException; +import com.cloud.host.HostEnvironment; import com.cloud.host.HostVO; import com.cloud.host.Status.Event; import com.cloud.host.dao.HostDao; @@ -100,6 +102,11 @@ public class DirectAgentManagerSimpleImpl implements AgentManager { } catch (ConfigurationException e) { logger.debug("Failed to load resource:" + e.toString()); } + HostEnvironment env = new HostEnvironment(); + SetupCommand cmd = new SetupCommand(env); + cmd.setNeedSetup(true); + + resource.executeRequest(cmd); } @Override diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java index 2f5e7aebf26..072535b37b8 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java @@ -69,7 +69,7 @@ public class DirectAgentTest { private long dcId; private long clusterId; private long hostId; - private String hostGuid = "759ee4c9-a15a-297b-67c6-ac267d8aa429"; + private String hostGuid = "9d4c9db8-32f7-25c3-0435-eab4bf3adcea"; @Before public void setUp() { HostVO host = hostDao.findByGuid(hostGuid); @@ -102,7 +102,7 @@ public class DirectAgentTest { host.setName("devcloud xen host"); host.setType(Host.Type.Routing); host.setHypervisorType(HypervisorType.XenServer); - host.setPrivateIpAddress("192.168.56.2"); + host.setPrivateIpAddress("192.168.56.10"); host.setDataCenterId(dc.getId()); host.setVersion("6.0.1"); host.setAvailable(true); @@ -133,7 +133,7 @@ public class DirectAgentTest { public void testDownloadTemplate() { ImageOnPrimayDataStoreTO image = Mockito.mock(ImageOnPrimayDataStoreTO.class); PrimaryDataStoreTO primaryStore = Mockito.mock(PrimaryDataStoreTO.class); - Mockito.when(primaryStore.getUuid()).thenReturn("cd10cac1-4772-92e5-5da6-c2bc16b1ce1b"); + Mockito.when(primaryStore.getUuid()).thenReturn("9f3f9262-3f77-09cc-2df7-0d8475676260"); Mockito.when(image.getPrimaryDataStore()).thenReturn(primaryStore); ImageDataStoreTO imageStore = Mockito.mock(ImageDataStoreTO.class); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockHostEndpointRpcServerDirectCallResource.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockHostEndpointRpcServerDirectCallResource.java new file mode 100644 index 00000000000..f2272ce58b9 --- /dev/null +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockHostEndpointRpcServerDirectCallResource.java @@ -0,0 +1,87 @@ +/* + * 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 org.apache.cloudstack.storage.test; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; + + +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; + +import org.apache.cloudstack.storage.HostEndpointRpcServer; +import org.apache.cloudstack.storage.HypervisorHostEndPoint; + +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.OperationTimedoutException; + + +public class MockHostEndpointRpcServerDirectCallResource implements HostEndpointRpcServer { + private static final Logger s_logger = Logger.getLogger(MockHostEndpointRpcServerDirectCallResource.class); + private ScheduledExecutorService executor; + @Inject + AgentManager agentMgr; + public MockHostEndpointRpcServerDirectCallResource() { + executor = Executors.newScheduledThreadPool(10); + } + protected class MockRpcCallBack implements Runnable { + private final Command cmd; + private final long hostId; + private final AsyncCompletionCallback callback; + public MockRpcCallBack(long hostId, Command cmd, final AsyncCompletionCallback callback) { + this.cmd = cmd; + this.callback = callback; + this.hostId = hostId; + } + @Override + public void run() { + try { + Answer answer = agentMgr.send(hostId, cmd); + callback.complete(answer); + } catch (Exception e) { + s_logger.debug("send command failed:" + e.toString()); + } + } + + } + + public void sendCommandAsync(HypervisorHostEndPoint host, final Command command, final AsyncCompletionCallback callback) { + executor.schedule(new MockRpcCallBack(host.getHostId(), command, callback), 10, TimeUnit.SECONDS); + } + + @Override + public Answer sendCommand(HypervisorHostEndPoint host, Command command) { + Answer answer; + try { + answer = agentMgr.send(host.getHostId(), command); + return answer; + } catch (AgentUnavailableException e) { + return null; + } catch (OperationTimedoutException e) { + return null; + } + } +} diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockHypervsiorHostEndPointRpcServer.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockHypervsiorHostEndPointRpcServer.java index 35b5bb1edd6..6c5ee1918f2 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockHypervsiorHostEndPointRpcServer.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockHypervsiorHostEndPointRpcServer.java @@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.HostEndpointRpcServer; +import org.apache.cloudstack.storage.HypervisorHostEndPoint; import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageCmd; import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageAnswer; import org.apache.cloudstack.storage.command.CreateVolumeAnswer; @@ -63,7 +64,14 @@ public class MockHypervsiorHostEndPointRpcServer implements HostEndpointRpcServe } } - public void sendCommandAsync(String host, final Command command, final AsyncCompletionCallback callback) { + + public void sendCommandAsync(HypervisorHostEndPoint host, final Command command, final AsyncCompletionCallback callback) { executor.schedule(new MockRpcCallBack(command, callback), 10, TimeUnit.SECONDS); } + + @Override + public Answer sendCommand(HypervisorHostEndPoint host, Command command) { + // TODO Auto-generated method stub + return null; + } } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index 59a7554e98e..238de2bb50d 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -158,7 +158,7 @@ public class volumeServiceTest { HostVO host = new HostVO(UUID.randomUUID().toString()); host.setName("devcloud xen host"); host.setType(Host.Type.Routing); - host.setPrivateIpAddress("192.168.56.2"); + host.setPrivateIpAddress("192.168.56.10"); host.setDataCenterId(dc.getId()); host.setVersion("6.0.1"); host.setAvailable(true); @@ -237,7 +237,7 @@ public class volumeServiceTest { PrimaryDataStoreProvider provider = primaryDataStoreProviderMgr.getDataStoreProvider("default primary data store provider"); Map params = new HashMap(); - params.put("url", "nfs://test/test"); + params.put("url", "nfs://localhost/primarynfs"); params.put("dcId", dcId.toString()); params.put("clusterId", clusterId.toString()); params.put("name", "my primary data store"); diff --git a/engine/storage/src/org/apache/cloudstack/storage/HostEndpointRpcServer.java b/engine/storage/src/org/apache/cloudstack/storage/HostEndpointRpcServer.java index 25ebc7fa191..a316223b24d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/HostEndpointRpcServer.java +++ b/engine/storage/src/org/apache/cloudstack/storage/HostEndpointRpcServer.java @@ -24,5 +24,6 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; public interface HostEndpointRpcServer { - void sendCommandAsync(String host, final Command command, final AsyncCompletionCallback callback); + void sendCommandAsync(HypervisorHostEndPoint ep, final Command command, final AsyncCompletionCallback callback); + Answer sendCommand(HypervisorHostEndPoint ep, final Command command); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java b/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java index 7e5387dfc82..a2e9ea9f34a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java @@ -42,24 +42,22 @@ public class HypervisorHostEndPoint implements EndPoint { this.hostId = hostId; this.hostAddress = hostAddress; } + + public String getHostAddr() { + return this.hostAddress; + } + + public long getHostId() { + return this.hostId; + } @Override public Answer sendMessage(Command cmd) { - Answer answer = null; - try { - answer = agentMgr.send(hostId, cmd); - } catch (AgentUnavailableException e) { - s_logger.debug("Unable to send command:" + cmd + ", due to: " + e.toString()); - } catch (OperationTimedoutException e) { - s_logger.debug("Unable to send command:" + cmd + ", due to: " + e.toString()); - } catch (Exception e) { - s_logger.debug("Unable to send command:" + cmd + ", due to: " + e.toString()); - } - return answer; + return rpcServer.sendCommand(this, cmd); } @Override public void sendMessageAsync(Command cmd, AsyncCompletionCallback callback) { - rpcServer.sendCommandAsync(this.hostAddress, cmd, callback); + rpcServer.sendCommandAsync(this, cmd, callback); } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java b/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java index de7b386a3ff..09758694ce5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java +++ b/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java @@ -20,19 +20,23 @@ package org.apache.cloudstack.storage; import javax.inject.Inject; +import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.framework.async.AsyncRpcConext; import org.apache.cloudstack.framework.rpc.RpcCallbackListener; import org.apache.cloudstack.framework.rpc.RpcException; import org.apache.cloudstack.framework.rpc.RpcProvider; import org.apache.cloudstack.framework.rpc.RpcServiceDispatcher; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.utils.exception.CloudRuntimeException; @Component public class HypervsiorHostEndPointRpcServer implements HostEndpointRpcServer { - + private static final Logger s_logger = Logger.getLogger(HypervsiorHostEndPointRpcServer.class); private RpcProvider _rpcProvider; @Inject public HypervsiorHostEndPointRpcServer(RpcProvider rpcProvider) { @@ -41,8 +45,8 @@ public class HypervsiorHostEndPointRpcServer implements HostEndpointRpcServer { } @Override - public void sendCommandAsync(String host, final Command command, final AsyncCompletionCallback callback) { - _rpcProvider.newCall(host).addCallbackListener(new RpcCallbackListener() { + public void sendCommandAsync(HypervisorHostEndPoint host, final Command command, final AsyncCompletionCallback callback) { + _rpcProvider.newCall(host.getHostAddr()).addCallbackListener(new RpcCallbackListener() { @Override public void onSuccess(Answer result) { callback.complete(result); @@ -55,4 +59,50 @@ public class HypervsiorHostEndPointRpcServer implements HostEndpointRpcServer { } }).apply(); } + + private class SendCommandContext extends AsyncRpcConext { + private T answer; + + public SendCommandContext(AsyncCompletionCallback callback) { + super(callback); + } + + public void setAnswer(T answer) { + this.answer = answer; + } + + public T getAnswer() { + return this.answer; + } + + } + + @Override + public Answer sendCommand(HypervisorHostEndPoint host, Command command) { + SendCommandContext context = new SendCommandContext(null); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().sendCommandCallback(null, null)) + .setContext(context); + + this.sendCommandAsync(host, command, caller); + + synchronized (context) { + try { + context.wait(); + } catch (InterruptedException e) { + s_logger.debug(e.toString()); + throw new CloudRuntimeException("wait on context is interrupted", e); + } + } + + return context.getAnswer(); + } + + protected Object sendCommandCallback(AsyncCallbackDispatcher callback, SendCommandContext context) { + context.setAnswer((Answer)callback.getResult()); + synchronized(context) { + context.notify(); + } + return null; + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreAnswer.java b/engine/storage/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreAnswer.java new file mode 100644 index 00000000000..cd15030084d --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreAnswer.java @@ -0,0 +1,55 @@ +/* + * 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 org.apache.cloudstack.storage.command; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class AttachPrimaryDataStoreAnswer extends Answer { + private String uuid; + private long capacity; + private long avail; + public AttachPrimaryDataStoreAnswer(Command cmd) { + super(cmd); + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getUuid() { + return this.uuid; + } + + public void setCapacity(long capacity) { + this.capacity = capacity; + } + + public long getCapacity() { + return this.capacity; + } + + public void setAvailable(long avail) { + this.avail = avail; + } + + public long getAvailable() { + return this.avail; + } +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreCmd.java b/engine/storage/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreCmd.java new file mode 100644 index 00000000000..53400a3d22b --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/command/AttachPrimaryDataStoreCmd.java @@ -0,0 +1,41 @@ +/* + * 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 org.apache.cloudstack.storage.command; + +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; + +import com.cloud.agent.api.Command; + +public class AttachPrimaryDataStoreCmd extends Command implements StorageSubSystemCommand { + private final PrimaryDataStoreTO dataStore; + public AttachPrimaryDataStoreCmd(PrimaryDataStoreInfo dataStore) { + this.dataStore = new PrimaryDataStoreTO(dataStore); + } + + public PrimaryDataStoreTO getDataStore() { + return this.dataStore; + } + + @Override + public boolean executeInSequence() { + // TODO Auto-generated method stub + return false; + } +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java index dc304a113c0..7f55797a4f4 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java @@ -23,12 +23,15 @@ import java.util.Map; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; +import org.apache.cloudstack.storage.EndPoint; +import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; import org.apache.cloudstack.storage.datastore.DataStoreStatus; +import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle { - protected PrimaryDataStoreInfo dataStore; + protected PrimaryDataStore dataStore; protected PrimaryDataStoreDao dataStoreDao; public DefaultPrimaryDataStoreLifeCycleImpl(PrimaryDataStoreDao dataStoreDao) { this.dataStoreDao = dataStoreDao; @@ -36,7 +39,7 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif @Override public void setDataStore(PrimaryDataStoreInfo dataStore) { - this.dataStore = dataStore; + this.dataStore = (PrimaryDataStore)dataStore; } @Override @@ -50,11 +53,18 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif @Override public boolean attachCluster(ClusterScope scope) { - PrimaryDataStoreVO dataStore = dataStoreDao.findById(this.dataStore.getId()); - dataStore.setDataCenterId(scope.getZoneId()); - dataStore.setPodId(scope.getPodId()); - dataStore.setClusterId(scope.getScopeId()); - dataStoreDao.update(this.dataStore.getId(), dataStore); + PrimaryDataStoreVO dataStoreVO = dataStoreDao.findById(this.dataStore.getId()); + dataStoreVO.setDataCenterId(scope.getZoneId()); + dataStoreVO.setPodId(scope.getPodId()); + dataStoreVO.setClusterId(scope.getScopeId()); + dataStoreVO.setStatus(DataStoreStatus.Up); + dataStoreDao.update(dataStoreVO.getId(), dataStoreVO); + + //send down createStoragePool command to all the hosts in the cluster + AttachPrimaryDataStoreCmd cmd = new AttachPrimaryDataStoreCmd(this.dataStore); + for (EndPoint ep : dataStore.getEndPoints()) { + ep.sendMessage(cmd); + } return false; } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 611913a823f..9cd1bf635e3 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -5042,7 +5042,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe boolean add = cmd.getAdd(); if( add ) { try { - SR sr = getStorageRepository(conn, pool); + SR sr = getStorageRepository(conn, pool.getUuid()); setupHeartbeatSr(conn, sr, false); long capacity = sr.getPhysicalSize(conn); long available = capacity - sr.getPhysicalUtilisation(conn); @@ -5065,7 +5065,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } else { try { - SR sr = getStorageRepository(conn, pool); + SR sr = getStorageRepository(conn, pool.getUuid()); String srUuid = sr.getUuid(conn); String result = callHostPluginPremium(conn, "setup_heartbeat_file", "host", _host.uuid, "sr", srUuid, "add", "false"); if (result == null || !result.split("#")[1].equals("0")) { @@ -5330,7 +5330,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe Connection conn = getConnection(); StorageFilerTO poolTO = cmd.getPool(); try { - SR sr = getStorageRepository(conn, poolTO); + SR sr = getStorageRepository(conn, poolTO.getUuid()); removeSR(conn, sr); Answer answer = new Answer(cmd, true, "success"); return answer; @@ -5587,7 +5587,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe DiskProfile dskch = cmd.getDiskCharacteristics(); VDI vdi = null; try { - SR poolSr = getStorageRepository(conn, pool); + SR poolSr = getStorageRepository(conn, pool.getUuid()); if (cmd.getTemplateUrl() != null) { VDI tmpltvdi = null; @@ -5973,7 +5973,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String remoteVolumesMountPath = uri.getHost() + ":" + uri.getPath() + "/volumes/"; String volumeFolder = String.valueOf(cmd.getVolumeId()) + "/"; String mountpoint = remoteVolumesMountPath + volumeFolder; - SR primaryStoragePool = getStorageRepository(conn, poolTO); + SR primaryStoragePool = getStorageRepository(conn, poolTO.getUuid()); String srUuid = primaryStoragePool.getUuid(conn); if (toSecondaryStorage) { // Create the volume folder @@ -6685,30 +6685,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - protected SR getStorageRepository(Connection conn, StorageFilerTO pool) { + protected SR getStorageRepository(Connection conn, String uuid) { Set srs; try { - srs = SR.getByNameLabel(conn, pool.getUuid()); + srs = SR.getByNameLabel(conn, uuid); } catch (XenAPIException e) { - throw new CloudRuntimeException("Unable to get SR " + pool.getUuid() + " due to " + e.toString(), e); + throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.toString(), e); } catch (Exception e) { - throw new CloudRuntimeException("Unable to get SR " + pool.getUuid() + " due to " + e.getMessage(), e); + throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.getMessage(), e); } if (srs.size() > 1) { - throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + pool.getUuid()); + throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + uuid); } else if (srs.size() == 1) { SR sr = srs.iterator().next(); if (s_logger.isDebugEnabled()) { - s_logger.debug("SR retrieved for " + pool.getId()); + s_logger.debug("SR retrieved for " + uuid); } if (checkSR(conn, sr)) { return sr; } - throw new CloudRuntimeException("SR check failed for storage pool: " + pool.getUuid() + "on host:" + _host.uuid); + throw new CloudRuntimeException("SR check failed for storage pool: " + uuid + "on host:" + _host.uuid); } else { - throw new CloudRuntimeException("Can not see storage pool: " + pool.getUuid() + " from on host:" + _host.uuid); + throw new CloudRuntimeException("Can not see storage pool: " + uuid + " from on host:" + _host.uuid); } } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java index 8789bb7f753..f47b080dc24 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java @@ -28,6 +28,8 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer; +import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageCmd; import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageAnswer; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; @@ -51,7 +53,10 @@ import org.apache.xmlrpc.XmlRpcException; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.storage.template.TemplateInfo; import com.cloud.utils.exception.CloudRuntimeException; import com.xensource.xenapi.Connection; import com.xensource.xenapi.PBD; @@ -72,11 +77,25 @@ public class XenServerStorageResource { public Answer handleStorageCommands(StorageSubSystemCommand command) { if (command instanceof CopyTemplateToPrimaryStorageCmd) { return this.execute((CopyTemplateToPrimaryStorageCmd)command); + } else if (command instanceof AttachPrimaryDataStoreCmd) { + return this.execute((AttachPrimaryDataStoreCmd)command); } return new Answer((Command)command, false, "not implemented yet"); } - private long getTemplateSize(String url) { + private long getTemplateSize(Connection conn, String url) { + String size = hypervisorResource.callHostPlugin(conn, "storagePlugin", "getTemplateSize", "srcUrl", url); + if (size == "" || size == null) { + throw new CloudRuntimeException("Can't get template size"); + } + + try { + return Long.parseLong(size); + } catch (NumberFormatException e) { + throw new CloudRuntimeException("Failed to get template lenght", e); + } + + /* HttpHead method = new HttpHead(url); DefaultHttpClient client = new DefaultHttpClient(); try { @@ -93,7 +112,7 @@ public class XenServerStorageResource { throw new CloudRuntimeException("Failed to get template lenght", e); } catch (NumberFormatException e) { throw new CloudRuntimeException("Failed to get template lenght", e); - } + }*/ } private void downloadHttpToLocalFile(String destFilePath, String url) { @@ -143,17 +162,17 @@ public class XenServerStorageResource { boolean result = false; try { - Set srs = SR.getByNameLabel(conn, primaryStoreUuid); - if (srs.size() != 1) { + SR sr = SR.getByUuid(conn, primaryStoreUuid); + if (sr == null) { throw new CloudRuntimeException("storage uuid: " + primaryStoreUuid + " is not unique"); } - poolsr = srs.iterator().next(); + poolsr = sr; VDI.Record vdir = new VDI.Record(); vdir.nameLabel = "Base-Image-" + UUID.randomUUID().toString(); vdir.SR = poolsr; vdir.type = Types.VdiType.USER; - vdir.virtualSize = getTemplateSize(template.getPath()); + vdir.virtualSize = getTemplateSize(conn, template.getPath()); vdi = VDI.create(conn, vdir); vdir = vdi.getRecord(conn); @@ -172,7 +191,7 @@ public class XenServerStorageResource { String vdiPath = pbdLocation + "/" + vdiLocation + ".vhd"; //download a url into vdipath //downloadHttpToLocalFile(vdiPath, template.getPath()); - hypervisorResource.callHostPlugin(conn, "vmopsStorage", "downloadTemplateFromUrl", "destPath", vdiPath, "srcUrl", template.getPath()); + hypervisorResource.callHostPlugin(conn, "storagePlugin", "downloadTemplateFromUrl", "destPath", vdiPath, "srcUrl", template.getPath()); result = true; return new CopyTemplateToPrimaryStorageAnswer(cmd, vdi.getUuid(conn)); } catch (BadServerResponse e) { @@ -199,6 +218,35 @@ public class XenServerStorageResource { return new Answer(cmd, false, "Failed to download template"); } + protected Answer execute(AttachPrimaryDataStoreCmd cmd) { + PrimaryDataStoreTO dataStore = cmd.getDataStore(); + Connection conn = hypervisorResource.getConnection(); + try { + SR sr = hypervisorResource.getStorageRepository(conn, dataStore.getUuid()); + hypervisorResource.setupHeartbeatSr(conn, sr, false); + long capacity = sr.getPhysicalSize(conn); + long available = capacity - sr.getPhysicalUtilisation(conn); + if (capacity == -1) { + String msg = "Pool capacity is -1! pool: "; + s_logger.warn(msg); + return new Answer(cmd, false, msg); + } + AttachPrimaryDataStoreAnswer answer = new AttachPrimaryDataStoreAnswer(cmd); + answer.setCapacity(capacity); + answer.setUuid(sr.getUuid(conn)); + answer.setAvailable(available); + return answer; + } catch (XenAPIException e) { + String msg = "AttachPrimaryDataStoreCmd add XenAPIException:" + e.toString(); + s_logger.warn(msg, e); + return new Answer(cmd, false, msg); + } catch (Exception e) { + String msg = "AttachPrimaryDataStoreCmd failed:" + e.getMessage(); + s_logger.warn(msg, e); + return new Answer(cmd, false, msg); + } + } + protected Answer execute(CopyTemplateToPrimaryStorageCmd cmd) { ImageOnPrimayDataStoreTO imageTO = cmd.getImage(); TemplateTO template = imageTO.getTemplate(); diff --git a/scripts/vm/hypervisor/xenserver/mockxcpplugin.py b/scripts/vm/hypervisor/xenserver/mockxcpplugin.py new file mode 100644 index 00000000000..0de24ca956b --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/mockxcpplugin.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +# 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. + +# This is for test purpose, to test xcp plugin + +import sys +import XenAPI +import os.path +import traceback +import socket +def getHost(): + hostname = socket.gethostname() + url = "http://localhost" + session = XenAPI.Session(url) + session.xenapi.login_with_password("root", "password") + host = session.xenapi.host + hosts = session.xenapi.host.get_by_name_label(hostname) + if len(hosts) != 1: + print "can't find host:" + hostname + sys.exit(1) + localhost = hosts[0] + return [host, localhost] + +def callPlugin(pluginName, func, params): + hostPair = getHost() + host = hostPair[0] + localhost = hostPair[1] + return host.call_plugin(localhost, pluginName, func, params) + +def main(): + if len(sys.argv) < 3: + print "args: pluginName funcName params" + sys.exit(1) + + pluginName = sys.argv[1] + funcName = sys.argv[2] + + paramList = sys.argv[3:] + if (len(paramList) % 2) != 0: + print "params must be name/value pair" + sys.exit(2) + params = {} + pos = 0; + for i in range(len(paramList) / 2): + params[str(paramList[pos])] = str(paramList[pos+1]) + pos = pos + 2 + print "call: " + pluginName + " " + funcName + ", with params: " + str(params) + print "return: " + callPlugin(pluginName, funcName, params) + +if __name__ == "__main__": + main() diff --git a/scripts/vm/hypervisor/xenserver/storagePlugin b/scripts/vm/hypervisor/xenserver/storagePlugin index df1c340752e..7cb6e354a1e 100755 --- a/scripts/vm/hypervisor/xenserver/storagePlugin +++ b/scripts/vm/hypervisor/xenserver/storagePlugin @@ -22,24 +22,23 @@ import os, sys, time import XenAPIPlugin -sys.path.extend(["/opt/xensource/sm/", "/usr/local/sbin/", "/sbin/"]) +sys.path.extend(["/usr/lib/xcp/sm/", "/usr/local/sbin/", "/sbin/"]) +import util import base64 -import hostvmstats import socket import stat import tempfile -import util import subprocess import zlib import urllib2 -from util import CommandException +import traceback def echo(fn): def wrapped(*v, **k): name = fn.__name__ - util.SMlog("#### VMOPS enter %s ####" % name ) + util.SMlog("#### xen plugin enter %s ####" % name ) res = fn(*v, **k) - util.SMlog("#### VMOPS exit %s ####" % name ) + util.SMlog("#### xen plugin exit %s ####" % name ) return res return wrapped @@ -47,10 +46,26 @@ def echo(fn): def downloadTemplateFromUrl(session, args): destPath = args["destPath"] srcUrl = args["srcUrl"] - template = urllib2.urlopen(srcUrl) - destFile = open(destPath, "wb") - destFile.write(template.read()) - destFile.close() + try: + template = urllib2.urlopen(srcUrl) + destFile = open(destPath, "wb") + destFile.write(template.read()) + destFile.close() + return "success" + except: + util.SMlog("exception: " + str(sys.exc_info())) + return "" +@echo +def getTemplateSize(session, args): + srcUrl = args["srcUrl"] + try: + template = urllib2.urlopen(srcUrl) + headers = template.info() + return str(headers["Content-Length"]) + except: + return "" if __name__ == "__main__": - XenAPIPlugin.dispatch({"downloadTemplateFromUrl": downloadTemplateFromUrl}) + XenAPIPlugin.dispatch({"downloadTemplateFromUrl": downloadTemplateFromUrl + ,"getTemplateSize": getTemplateSize + }) diff --git a/scripts/vm/hypervisor/xenserver/xcposs/patch b/scripts/vm/hypervisor/xenserver/xcposs/patch index 2ab94219498..1b615b77fdb 100644 --- a/scripts/vm/hypervisor/xenserver/xcposs/patch +++ b/scripts/vm/hypervisor/xenserver/xcposs/patch @@ -64,3 +64,4 @@ cloud-prepare-upgrade.sh=..,0755,/usr/lib/xcp/bin getRouterStatus.sh=../../../../network/domr/,0755,/usr/lib/xcp/bin bumpUpPriority.sh=../../../../network/domr/,0755,/usr/lib/xcp/bin getDomRVersion.sh=../../../../network/domr/,0755,/usr/lib/xcp/bin +storagePlugin=.,0755,/usr/lib/xcp/plugins