From 3423c5d74f062820f2e6f99b22fabe2526d3dd00 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Tue, 30 Oct 2012 17:34:46 -0700 Subject: [PATCH] add volume service skeleton --- .../apache/cloudstack/storage/BaseType.java | 40 + .../apache/cloudstack/storage/EndPoint.java | 5 +- .../storage/HypervisorHostEndPoint.java | 55 ++ .../storage/command/CreateVolumeAnswer.java | 36 + .../storage/command/CreateVolumeCommand.java | 42 + .../DefaultPrimaryDataStoreImpl.java | 67 +- .../storage/datastore/PrimaryDataStore.java | 3 + .../storage/datastore/db/DataStoreVO.java | 6 +- .../db/PrimaryDataStoreProviderVO.java | 17 +- .../DefaultPrimaryDataStoreDriverImpl.java | 36 +- .../DefaultPrimaryDataStoreManagerImpl.java | 15 +- .../PrimaryDataStoreProviderManager.java | 2 +- .../PrimaryDataStoreProviderManagerImpl.java} | 18 +- .../storage/datastore/type/DataStoreType.java | 23 + .../storage/datastore/type/ISCSI.java | 31 + .../datastore/type/NetworkFileSystem.java | 31 + .../storage/datastore/type/SharedMount.java | 29 + .../DefaultPrimaryEndpointSelector.java | 40 - .../storage/filesystem/DefaultFileSystem.java | 59 -- .../storage/image/db/ImageDataDao.java | 71 ++ .../storage/image/db/ImageDataDaoImpl.java | 925 ++++++++++++++++++ .../storage/image/db/ImageDataVO.java | 381 ++++++++ .../storage/image/format/BAREMETAL.java | 31 + .../cloudstack/storage/image/format/ISO.java | 31 + .../storage/image/format/ImageFormat.java | 23 + .../image/format/ImageFormatHelper.java | 44 + .../cloudstack/storage/image/format/OVA.java | 31 + .../storage/image/format/QCOW2.java | 31 + .../storage/image/format/Unknown.java | 32 + .../cloudstack/storage/image/format/VHD.java | 29 + .../provider/ImageDataStoreProvider.java | 25 + .../storage/image/store/ImageDataStore.java | 23 + .../manager/PrimaryDataStoreManagerImpl.java | 13 + .../cloudstack/storage/volume/Volume.java | 49 +- .../cloudstack/storage/volume/VolumeInfo.java | 76 ++ .../storage/volume/VolumeService.java | 3 +- .../storage/volume/VolumeServiceImpl.java | 11 +- .../storage/volume/VolumeState.java | 6 +- .../storage/volume/db/VolumeVO.java | 3 +- .../volume/disktype/VolumeDiskTypeHelper.java | 15 +- .../storage/volume/type/VolumeType.java | 1 - .../storage/volume/type/VolumeTypeBase.java | 15 +- .../storage/volume/type/VolumeTypeHelper.java | 14 +- .../storage/test/volumeServiceTest.java | 32 +- server/src/com/cloud/host/dao/HostDao.java | 1 + .../src/com/cloud/host/dao/HostDaoImpl.java | 21 +- 46 files changed, 2332 insertions(+), 160 deletions(-) create mode 100644 platform/storage/src/org/apache/cloudstack/storage/BaseType.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeAnswer.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java rename platform/storage/src/org/apache/cloudstack/storage/{epselector/DefaultNfsSecondaryEndPointSelector.java => datastore/provider/PrimaryDataStoreProviderManagerImpl.java} (57%) create mode 100644 platform/storage/src/org/apache/cloudstack/storage/datastore/type/DataStoreType.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/datastore/type/ISCSI.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/datastore/type/NetworkFileSystem.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/datastore/type/SharedMount.java delete mode 100644 platform/storage/src/org/apache/cloudstack/storage/epselector/DefaultPrimaryEndpointSelector.java delete mode 100644 platform/storage/src/org/apache/cloudstack/storage/filesystem/DefaultFileSystem.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/BAREMETAL.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/ISO.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormat.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormatHelper.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/OVA.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/QCOW2.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/Unknown.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/format/VHD.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/provider/ImageDataStoreProvider.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/image/store/ImageDataStore.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/VolumeInfo.java diff --git a/platform/storage/src/org/apache/cloudstack/storage/BaseType.java b/platform/storage/src/org/apache/cloudstack/storage/BaseType.java new file mode 100644 index 00000000000..12acc7d65a9 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/BaseType.java @@ -0,0 +1,40 @@ +/* + * 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; + +public abstract class BaseType { + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that instanceof String) { + if (this.toString().equalsIgnoreCase((String)that)) { + return true; + } + } else if (that instanceof BaseType) { + BaseType th = (BaseType)that; + if (this.toString().equalsIgnoreCase(th.toString())) { + return true; + } + } else { + return false; + } + return false; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/EndPoint.java b/platform/storage/src/org/apache/cloudstack/storage/EndPoint.java index 8cb01a13fc7..0a3dfa2d28d 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/EndPoint.java +++ b/platform/storage/src/org/apache/cloudstack/storage/EndPoint.java @@ -1,5 +1,8 @@ package org.apache.cloudstack.storage; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + public interface EndPoint { - public String getEndPoint(); + public Answer sendMessage(Command cmd); } diff --git a/platform/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java b/platform/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java new file mode 100644 index 00000000000..8bd51c7c580 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.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; + +import javax.inject.Inject; + +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 HypervisorHostEndPoint implements EndPoint { + private static final Logger s_logger = Logger.getLogger(HypervisorHostEndPoint.class); + private long hostId; + @Inject + AgentManager agentMgr; + public HypervisorHostEndPoint(long hostId) { + this.hostId = 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; + } + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeAnswer.java b/platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeAnswer.java new file mode 100644 index 00000000000..e75307c547d --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeAnswer.java @@ -0,0 +1,36 @@ +/* + * 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; + +public class CreateVolumeAnswer extends Answer { + private String volumeUuid; + protected CreateVolumeAnswer() { + super(); + } + + public CreateVolumeAnswer(String volumeUuid) { + this.volumeUuid = volumeUuid; + } + + public String getVolumeUuid() { + return this.volumeUuid; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java b/platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java new file mode 100644 index 00000000000..243e0167da1 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java @@ -0,0 +1,42 @@ +/* + * 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.storage.volume.VolumeInfo; + +import com.cloud.agent.api.Command; + +public class CreateVolumeCommand extends Command { + protected VolumeInfo volumeInfo; + public CreateVolumeCommand(VolumeInfo volumeInfo) { + super(); + this.volumeInfo = volumeInfo; + } + + protected CreateVolumeCommand() { + super(); + } + + @Override + public boolean executeInSequence() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStoreImpl.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStoreImpl.java index ae2d620579c..ea22b2314cd 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStoreImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStoreImpl.java @@ -1,22 +1,38 @@ package org.apache.cloudstack.storage.datastore; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.storage.EndPoint; +import org.apache.cloudstack.storage.HypervisorHostEndPoint; import org.apache.cloudstack.storage.datastore.db.DataStoreVO; import org.apache.cloudstack.storage.datastore.driver.PrimaryDataStoreDriver; import org.apache.cloudstack.storage.volume.Volume; +import org.apache.cloudstack.storage.volume.VolumeEvent; import org.apache.cloudstack.storage.volume.db.VolumeDao; import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.apache.cloudstack.storage.volume.disktype.VolumeDiskType; +import org.apache.log4j.Logger; + +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.utils.component.ComponentInject; +import com.cloud.utils.exception.CloudRuntimeException; + +import edu.emory.mathcs.backport.java.util.Collections; public class DefaultPrimaryDataStoreImpl implements PrimaryDataStore { + private static final Logger s_logger = Logger.getLogger(DefaultPrimaryDataStoreImpl.class); protected PrimaryDataStoreDriver driver; protected DataStoreVO pdsv; protected PrimaryDataStoreInfo pdsInfo; @Inject - public VolumeDao volumeDao; + private VolumeDao volumeDao; + @Inject + private HostDao hostDao; public DefaultPrimaryDataStoreImpl(PrimaryDataStoreDriver driver, DataStoreVO pdsv, PrimaryDataStoreInfo pdsInfo) { this.driver = driver; this.pdsv = pdsv; @@ -53,9 +69,50 @@ public class DefaultPrimaryDataStoreImpl implements PrimaryDataStore { return null; } - vol.setVolumeDiskType(diskType); - this.driver.createVolume(vol); - vol.update(); - return vol; + boolean result = vol.stateTransit(VolumeEvent.CreateRequested); + if (!result) { + return null; + } + + try { + vol.setVolumeDiskType(diskType); + result = this.driver.createVolume(vol); + vol.update(); + return vol; + } catch (Exception e) { + result = false; + s_logger.debug("Failed to create volume: " + e.toString()); + throw new CloudRuntimeException(e.toString()); + } finally { + if (result == true) { + vol.stateTransit(VolumeEvent.OperationSucceeded); + } else { + vol.stateTransit(VolumeEvent.OperationFailed); + } + } + + } + + @Override + public List getEndPoints() { + Long clusterId = pdsv.getClusterId(); + if (clusterId == null) { + return null; + } + List endpoints = new ArrayList(); + List hosts = hostDao.findHypervisorHostInCluster(clusterId); + for (HostVO host : hosts) { + HypervisorHostEndPoint ep = new HypervisorHostEndPoint(host.getId()); + ComponentInject.inject(ep); + endpoints.add(ep); + } + Collections.shuffle(endpoints); + return endpoints; + } + + @Override + public PrimaryDataStoreInfo getDataStoreInfo() { + // TODO Auto-generated method stub + return null; } } diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java index 3e06156e779..7efa56177ea 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.storage.datastore; import java.util.List; +import org.apache.cloudstack.storage.EndPoint; import org.apache.cloudstack.storage.volume.Volume; import org.apache.cloudstack.storage.volume.disktype.VolumeDiskType; @@ -28,4 +29,6 @@ public interface PrimaryDataStore { List getVolumes(); boolean deleteVolume(long id); Volume createVolume(long id, VolumeDiskType diskType); + List getEndPoints(); + PrimaryDataStoreInfo getDataStoreInfo(); } diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreVO.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreVO.java index 960d7c88648..52f3bbf1e74 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreVO.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreVO.java @@ -82,7 +82,7 @@ public class DataStoreVO implements Identity { private DataStoreStatus status; @Column(name="storage_provider", updatable=true, nullable=false) - private String storageProvider; + private Long storageProvider; @Column(name="storage_type", nullable=false) private String storageType; @@ -147,11 +147,11 @@ public class DataStoreVO implements Identity { return availableBytes; } - public String getStorageProvider() { + public Long getStorageProviderId() { return storageProvider; } - public void setStorageProvider(String provider) { + public void setStorageProviderId(Long provider) { storageProvider = provider; } diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreProviderVO.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreProviderVO.java index 0ec6bf0f589..0d155802464 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreProviderVO.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreProviderVO.java @@ -18,6 +18,21 @@ */ package org.apache.cloudstack.storage.datastore.db; -public class PrimaryDataStoreProviderVO { +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.TableGenerator; +@Entity +@Table(name="data_store_provider") +public class PrimaryDataStoreProviderVO { + @Id + @TableGenerator(name="data_store_provider_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="data_store_provider_seq", allocationSize=1) + @Column(name="id", updatable=false, nullable = false) + private long id; + + public long getId() { + return id; + } } diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java index d1e69768552..935f2140b86 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java @@ -1,17 +1,47 @@ package org.apache.cloudstack.storage.datastore.driver; +import java.util.List; + import org.apache.cloudstack.storage.EndPoint; +import org.apache.cloudstack.storage.command.CreateVolumeAnswer; +import org.apache.cloudstack.storage.command.CreateVolumeCommand; import org.apache.cloudstack.storage.volume.Volume; +import org.apache.cloudstack.storage.volume.VolumeInfo; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.agent.api.Answer; + @Component public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver { - + private static final Logger s_logger = Logger.getLogger(DefaultPrimaryDataStoreDriverImpl.class); @Override public boolean createVolume(Volume vol) { - // TODO Auto-generated method stub - return false; + //The default driver will send createvolume command to one of hosts which can access its datastore + List endPoints = vol.getDataStore().getEndPoints(); + int retries = 3; + VolumeInfo volInfo = new VolumeInfo(vol); + CreateVolumeCommand createCmd = new CreateVolumeCommand(volInfo); + Answer answer = null; + int i = 0; + boolean result = false; + + for (EndPoint ep : endPoints) { + answer = ep.sendMessage(createCmd); + if (answer == null) { + if (i < retries) { + s_logger.debug("create volume failed, retrying: " + i); + } + i++; + } else { + CreateVolumeAnswer volAnswer = (CreateVolumeAnswer)answer; + vol.setUuid(volAnswer.getVolumeUuid()); + result = true; + } + } + + return result; } @Override diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreManagerImpl.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreManagerImpl.java index dfa4663ad29..4949b2faf67 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreManagerImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreManagerImpl.java @@ -21,18 +21,29 @@ package org.apache.cloudstack.storage.datastore.manager; import javax.inject.Inject; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; +import org.apache.cloudstack.storage.datastore.db.DataStoreVO; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreProviderDao; import org.apache.cloudstack.storage.datastore.lifecycle.PrimaryDataStoreLifeCycle; +import org.apache.cloudstack.storage.datastore.provider.PrimaryDataStoreProvider; +import org.apache.cloudstack.storage.datastore.provider.PrimaryDataStoreProviderManager; import org.springframework.stereotype.Component; @Component public class DefaultPrimaryDataStoreManagerImpl implements PrimaryDataStoreManager { @Inject PrimaryDataStoreProviderDao dataStoreProviderDao; + @Inject + PrimaryDataStoreProviderManager providerManager; + @Inject + PrimaryDataStoreDao dataStoreDao; @Override public PrimaryDataStore getPrimaryDataStore(long dataStoreId) { - // TODO Auto-generated method stub - return null; + DataStoreVO dataStoreVO = dataStoreDao.findById(dataStoreId); + Long providerId = dataStoreVO.getStorageProviderId(); + PrimaryDataStoreProvider provider = providerManager.getDataStoreProvider(providerId); + PrimaryDataStore dataStore = provider.getDataStore(dataStoreId); + return dataStore; } @Override diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProviderManager.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProviderManager.java index a01c96c0dbc..4ef9a5c75ee 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProviderManager.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProviderManager.java @@ -1,5 +1,5 @@ package org.apache.cloudstack.storage.datastore.provider; public interface PrimaryDataStoreProviderManager { - public PrimaryDataStoreProvider getDataStoreProvider(String providerUuid); + public PrimaryDataStoreProvider getDataStoreProvider(Long providerId); } diff --git a/platform/storage/src/org/apache/cloudstack/storage/epselector/DefaultNfsSecondaryEndPointSelector.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProviderManagerImpl.java similarity index 57% rename from platform/storage/src/org/apache/cloudstack/storage/epselector/DefaultNfsSecondaryEndPointSelector.java rename to platform/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProviderManagerImpl.java index b9de406dc20..08755530c11 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/epselector/DefaultNfsSecondaryEndPointSelector.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProviderManagerImpl.java @@ -16,21 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.epselector; +package org.apache.cloudstack.storage.datastore.provider; -import java.util.List; +import org.springframework.stereotype.Component; -import org.apache.cloudstack.platform.subsystem.api.storage.DataStore; -import org.apache.cloudstack.platform.subsystem.api.storage.DataStoreEndPoint; -import org.apache.cloudstack.platform.subsystem.api.storage.DataStoreEndPointSelector; -import org.apache.cloudstack.platform.subsystem.api.storage.StorageEvent; +@Component +public class PrimaryDataStoreProviderManagerImpl implements PrimaryDataStoreProviderManager { -public class DefaultNfsSecondaryEndPointSelector implements DataStoreEndPointSelector { - protected DataStore _ds; - public DefaultNfsSecondaryEndPointSelector(DataStore ds) { - _ds = ds; - } - public List getEndPoints(StorageEvent event) { + @Override + public PrimaryDataStoreProvider getDataStoreProvider(Long providerId) { // TODO Auto-generated method stub return null; } diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/type/DataStoreType.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/DataStoreType.java new file mode 100644 index 00000000000..8f3fe8ca8ca --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/DataStoreType.java @@ -0,0 +1,23 @@ +/* + * 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.datastore.type; + +public interface DataStoreType { + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/type/ISCSI.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/ISCSI.java new file mode 100644 index 00000000000..26d36def426 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/ISCSI.java @@ -0,0 +1,31 @@ +/* + * 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.datastore.type; + +import org.apache.cloudstack.storage.BaseType; +import org.springframework.stereotype.Component; + +@Component +public class ISCSI extends BaseType implements DataStoreType { + private final String type = "iscsi"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/type/NetworkFileSystem.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/NetworkFileSystem.java new file mode 100644 index 00000000000..9340975f87c --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/NetworkFileSystem.java @@ -0,0 +1,31 @@ +/* + * 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.datastore.type; + +import org.apache.cloudstack.storage.BaseType; +import org.springframework.stereotype.Component; + +@Component +public class NetworkFileSystem extends BaseType implements DataStoreType { + private final String type = "nfs"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastore/type/SharedMount.java b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/SharedMount.java new file mode 100644 index 00000000000..c97a8939833 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/datastore/type/SharedMount.java @@ -0,0 +1,29 @@ +/* + * 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.datastore.type; + +import org.apache.cloudstack.storage.BaseType; + +public class SharedMount extends BaseType implements DataStoreType { + private final String type = "SharedMountPoint"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/epselector/DefaultPrimaryEndpointSelector.java b/platform/storage/src/org/apache/cloudstack/storage/epselector/DefaultPrimaryEndpointSelector.java deleted file mode 100644 index 33ccb4224ad..00000000000 --- a/platform/storage/src/org/apache/cloudstack/storage/epselector/DefaultPrimaryEndpointSelector.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.apache.cloudstack.storage.epselector; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.cloudstack.platform.subsystem.api.storage.DataStore; -import org.apache.cloudstack.platform.subsystem.api.storage.DataStoreEndPoint; -import org.apache.cloudstack.platform.subsystem.api.storage.DataStoreEndPointSelector; -import org.apache.cloudstack.platform.subsystem.api.storage.StorageEvent; - -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.resource.ResourceManager; -import com.cloud.utils.component.Inject; - -public class DefaultPrimaryEndpointSelector implements - DataStoreEndPointSelector { - protected DataStore _ds; - - @Inject - protected ResourceManager _resourceMgr; - - public DefaultPrimaryEndpointSelector(DataStore ds) { - _ds = ds; - } - - public List getEndPoints() { - List allHosts = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.Routing, _ds.getCluterId(), _ds.getPodId(), _ds.getZoneId()); - List dseps = new ArrayList(); - for (HostVO host : allHosts) { - dseps.add(new DataStoreEndPoint(host.getId(), host.getPrivateIpAddress())); - } - return dseps; - } - - public List getEndPoints(StorageEvent event) { - // TODO Auto-generated method stub - return null; - } -} diff --git a/platform/storage/src/org/apache/cloudstack/storage/filesystem/DefaultFileSystem.java b/platform/storage/src/org/apache/cloudstack/storage/filesystem/DefaultFileSystem.java deleted file mode 100644 index 7176cea95b2..00000000000 --- a/platform/storage/src/org/apache/cloudstack/storage/filesystem/DefaultFileSystem.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.apache.cloudstack.storage.filesystem; - -import org.apache.cloudstack.platform.subsystem.api.storage.DataObject; -import org.apache.cloudstack.platform.subsystem.api.storage.DataStore; -import org.apache.cloudstack.platform.subsystem.api.storage.FileSystem; - -public class DefaultFileSystem implements FileSystem { - - public DataObject create(DataObject obj) { - // TODO Auto-generated method stub - return null; - } - - public DataObject copy(DataObject Obj, DataStore destStore) { - // TODO Auto-generated method stub - return null; - } - - public DataObject copy(DataObject obj, DataObject destObj) { - // TODO Auto-generated method stub - return null; - } - - public DataObject move(DataObject srcObj, DataObject destObj) { - // TODO Auto-generated method stub - return null; - } - - public boolean delete(DataObject obj) { - // TODO Auto-generated method stub - return false; - } - - public long getStats(DataObject obj) { - // TODO Auto-generated method stub - return 0; - } - - public String getFileType() { - // TODO Auto-generated method stub - return null; - } - - public boolean isWritable(DataObject obj) { - // TODO Auto-generated method stub - return false; - } - - public boolean contains(DataObject obj) { - // TODO Auto-generated method stub - return false; - } - - public DataObject ioctl(DataObject obj, Object... objects) { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java b/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java new file mode 100644 index 00000000000..b336ffa2db5 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java @@ -0,0 +1,71 @@ +/* + * 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.image.db; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.cloud.domain.DomainVO; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.template.VirtualMachineTemplate.TemplateFilter; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import com.cloud.utils.db.GenericDao; + +public interface ImageDataDao extends GenericDao { + public List listByPublic(); + public ImageDataVO findByName(String templateName); + public ImageDataVO findByTemplateName(String templateName); + + //public void update(ImageDataVO template); + + + public List listAllSystemVMTemplates(); + + public List listDefaultBuiltinTemplates(); + public String getRoutingTemplateUniqueName(); + public List findIsosByIdAndPath(Long domainId, Long accountId, String path); + public List listReadyTemplates(); + public List listByAccountId(long accountId); + public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, + List hypers, Boolean bootable, DomainVO domain, Long pageSize, Long startIndex, Long zoneId, + HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, + ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags); + + public Set> searchSwiftTemplates(String name, String keyword, TemplateFilter templateFilter, + boolean isIso, List hypers, Boolean bootable, DomainVO domain, Long pageSize, Long startIndex, + Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, Map tags); + + public long addTemplateToZone(ImageDataVO tmplt, long zoneId); + public List listAllInZone(long dataCenterId); + + public List listByHypervisorType(List hyperTypes); + public List publicIsoSearch(Boolean bootable, boolean listRemoved, Map tags); + public List userIsoSearch(boolean listRemoved); + ImageDataVO findSystemVMTemplate(long zoneId); + ImageDataVO findSystemVMTemplate(long zoneId, HypervisorType hType); + + ImageDataVO findRoutingTemplate(HypervisorType type); + List listPrivateTemplatesByHost(Long hostId); + public Long countTemplatesForAccount(long accountId); + +} + diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java b/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java new file mode 100644 index 00000000000..8ba557593b6 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java @@ -0,0 +1,925 @@ +/* + * 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.image.db; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.storage.image.format.ISO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.api.BaseCmd; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.storage.Storage; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.dao.VMTemplateDaoImpl; +import com.cloud.storage.dao.VMTemplateDetailsDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.tags.ResourceTagVO; +import com.cloud.tags.dao.ResourceTagsDaoImpl; +import com.cloud.template.VirtualMachineTemplate.TemplateFilter; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.component.Inject; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.exception.CloudRuntimeException; + +@Component +public class ImageDataDaoImpl extends GenericDaoBase implements ImageDataDao { + private static final Logger s_logger = Logger.getLogger(VMTemplateDaoImpl.class); + + @Inject + VMTemplateZoneDao _templateZoneDao; + @Inject + VMTemplateDetailsDao _templateDetailsDao; + + @Inject + ConfigurationDao _configDao; + @Inject + HostDao _hostDao; + @Inject + DomainDao _domainDao; + @Inject + DataCenterDao _dcDao; + private final String SELECT_TEMPLATE_HOST_REF = "SELECT t.id, h.data_center_id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " + + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; + + private final String SELECT_TEMPLATE_ZONE_REF = "SELECT t.id, tzr.zone_id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " + + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t INNER JOIN template_zone_ref tzr on (t.id = tzr.template_id) "; + + private final String SELECT_TEMPLATE_SWIFT_REF = "SELECT t.id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " + + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; + protected SearchBuilder TemplateNameSearch; + protected SearchBuilder UniqueNameSearch; + protected SearchBuilder tmpltTypeSearch; + protected SearchBuilder tmpltTypeHyperSearch; + protected SearchBuilder tmpltTypeHyperSearch2; + + protected SearchBuilder AccountIdSearch; + protected SearchBuilder NameSearch; + protected SearchBuilder TmpltsInZoneSearch; + private SearchBuilder PublicSearch; + private SearchBuilder NameAccountIdSearch; + private SearchBuilder PublicIsoSearch; + private SearchBuilder UserIsoSearch; + private GenericSearchBuilder CountTemplatesByAccount; + + ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); + + + private String routerTmpltName; + private String consoleProxyTmpltName; + + protected ImageDataDaoImpl() { + } + + @Override + public List listByPublic() { + SearchCriteria sc = PublicSearch.create(); + sc.setParameters("public", 1); + return listBy(sc); + } + + @Override + public ImageDataVO findByName(String templateName) { + SearchCriteria sc = UniqueNameSearch.create(); + sc.setParameters("uniqueName", templateName); + return findOneIncludingRemovedBy(sc); + } + + @Override + public ImageDataVO findByTemplateName(String templateName) { + SearchCriteria sc = NameSearch.create(); + sc.setParameters("name", templateName); + return findOneIncludingRemovedBy(sc); + } + + @Override + public List publicIsoSearch(Boolean bootable, boolean listRemoved, Map tags){ + + SearchBuilder sb = null; + if (tags == null || tags.isEmpty()) { + sb = PublicIsoSearch; + } else { + sb = createSearchBuilder(); + sb.and("public", sb.entity().isPublicTemplate(), SearchCriteria.Op.EQ); + sb.and("format", sb.entity().getFormat(), SearchCriteria.Op.EQ); + sb.and("type", sb.entity().getTemplateType(), SearchCriteria.Op.EQ); + sb.and("bootable", sb.entity().isBootable(), SearchCriteria.Op.EQ); + sb.and("removed", sb.entity().getRemoved(), SearchCriteria.Op.EQ); + + SearchBuilder tagSearch = _tagsDao.createSearchBuilder(); + for (int count=0; count < tags.size(); count++) { + tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); + tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); + tagSearch.cp(); + } + tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); + sb.groupBy(sb.entity().getId()); + sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); + } + + SearchCriteria sc = sb.create(); + + sc.setParameters("public", 1); + sc.setParameters("format", "ISO"); + sc.setParameters("type", TemplateType.PERHOST.toString()); + if (bootable != null) { + sc.setParameters("bootable", bootable); + } + + if (!listRemoved) { + sc.setParameters("removed", (Object)null); + } + + if (tags != null && !tags.isEmpty()) { + int count = 0; + sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.ISO.toString()); + for (String key : tags.keySet()) { + sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key); + sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key)); + count++; + } + } + + return listBy(sc); + } + + @Override + public List userIsoSearch(boolean listRemoved){ + + SearchBuilder sb = null; + sb = UserIsoSearch; + SearchCriteria sc = sb.create(); + + sc.setParameters("format", Storage.ImageFormat.ISO); + sc.setParameters("type", TemplateType.USER.toString()); + + if (!listRemoved) { + sc.setParameters("removed", (Object)null); + } + + return listBy(sc); + } + @Override + public List listAllSystemVMTemplates() { + SearchCriteria sc = tmpltTypeSearch.create(); + sc.setParameters("templateType", Storage.TemplateType.SYSTEM); + + Filter filter = new Filter(ImageDataVO.class, "id", false, null, null); + return listBy(sc, filter); + } + + @Override + public List listPrivateTemplatesByHost(Long hostId) { + + String sql = "select * from template_host_ref as thr INNER JOIN vm_template as t ON t.id=thr.template_id " + + "where thr.host_id=? and t.public=0 and t.featured=0 and t.type='USER' and t.removed is NULL"; + + List l = new ArrayList(); + + Transaction txn = Transaction.currentTxn(); + + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + pstmt.setLong(1, hostId); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + l.add(rs.getLong(1)); + } + } catch (SQLException e) { + } catch (Throwable e) { + } + return l; + } + + @Override + public List listReadyTemplates() { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("ready", SearchCriteria.Op.EQ, true); + sc.addAnd("format", SearchCriteria.Op.NEQ, Storage.ImageFormat.ISO); + return listIncludingRemovedBy(sc); + } + + @Override + public List findIsosByIdAndPath(Long domainId, Long accountId, String path) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("iso", SearchCriteria.Op.EQ, true); + if (domainId != null) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + if (path != null) { + sc.addAnd("path", SearchCriteria.Op.EQ, path); + } + return listIncludingRemovedBy(sc); + } + + @Override + public List listByAccountId(long accountId) { + SearchCriteria sc = AccountIdSearch.create(); + sc.setParameters("accountId", accountId); + return listBy(sc); + } + + @Override + public List listByHypervisorType(List hyperTypes) { + SearchCriteria sc = createSearchCriteria(); + hyperTypes.add(HypervisorType.None); + sc.addAnd("hypervisorType", SearchCriteria.Op.IN, hyperTypes.toArray()); + return listBy(sc); + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + boolean result = super.configure(name, params); + + PublicSearch = createSearchBuilder(); + PublicSearch.and("public", PublicSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); + + routerTmpltName = (String)params.get("routing.uniquename"); + + s_logger.debug("Found parameter routing unique name " + routerTmpltName); + if (routerTmpltName==null) { + routerTmpltName="routing"; + } + + consoleProxyTmpltName = (String)params.get("consoleproxy.uniquename"); + if(consoleProxyTmpltName == null) { + consoleProxyTmpltName = "routing"; + } + if(s_logger.isDebugEnabled()) { + s_logger.debug("Use console proxy template : " + consoleProxyTmpltName); + } + + UniqueNameSearch = createSearchBuilder(); + UniqueNameSearch.and("uniqueName", UniqueNameSearch.entity().getUniqueName(), SearchCriteria.Op.EQ); + NameSearch = createSearchBuilder(); + NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); + + NameAccountIdSearch = createSearchBuilder(); + NameAccountIdSearch.and("name", NameAccountIdSearch.entity().getName(), SearchCriteria.Op.EQ); + NameAccountIdSearch.and("accountId", NameAccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + + PublicIsoSearch = createSearchBuilder(); + PublicIsoSearch.and("public", PublicIsoSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); + PublicIsoSearch.and("format", PublicIsoSearch.entity().getFormat(), SearchCriteria.Op.EQ); + PublicIsoSearch.and("type", PublicIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); + PublicIsoSearch.and("bootable", PublicIsoSearch.entity().isBootable(), SearchCriteria.Op.EQ); + PublicIsoSearch.and("removed", PublicIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); + + UserIsoSearch = createSearchBuilder(); + UserIsoSearch.and("format", UserIsoSearch.entity().getFormat(), SearchCriteria.Op.EQ); + UserIsoSearch.and("type", UserIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); + UserIsoSearch.and("removed", UserIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); + + tmpltTypeHyperSearch = createSearchBuilder(); + tmpltTypeHyperSearch.and("templateType", tmpltTypeHyperSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); + SearchBuilder hostHyperSearch = _hostDao.createSearchBuilder(); + hostHyperSearch.and("type", hostHyperSearch.entity().getType(), SearchCriteria.Op.EQ); + hostHyperSearch.and("zoneId", hostHyperSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); + hostHyperSearch.groupBy(hostHyperSearch.entity().getHypervisorType()); + + tmpltTypeHyperSearch.join("tmplHyper", hostHyperSearch, hostHyperSearch.entity().getHypervisorType(), tmpltTypeHyperSearch.entity().getHypervisorType(), JoinBuilder.JoinType.INNER); + hostHyperSearch.done(); + tmpltTypeHyperSearch.done(); + + tmpltTypeHyperSearch2 = createSearchBuilder(); + tmpltTypeHyperSearch2.and("templateType", tmpltTypeHyperSearch2.entity().getTemplateType(), SearchCriteria.Op.EQ); + tmpltTypeHyperSearch2.and("hypervisorType", tmpltTypeHyperSearch2.entity().getHypervisorType(), SearchCriteria.Op.EQ); + + + tmpltTypeSearch = createSearchBuilder(); + tmpltTypeSearch.and("removed", tmpltTypeSearch.entity().getRemoved(), SearchCriteria.Op.NULL); + tmpltTypeSearch.and("templateType", tmpltTypeSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); + + AccountIdSearch = createSearchBuilder(); + AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountIdSearch.and("publicTemplate", AccountIdSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); + AccountIdSearch.done(); + + SearchBuilder tmpltZoneSearch = _templateZoneDao.createSearchBuilder(); + tmpltZoneSearch.and("removed", tmpltZoneSearch.entity().getRemoved(), SearchCriteria.Op.NULL); + tmpltZoneSearch.and("zoneId", tmpltZoneSearch.entity().getZoneId(), SearchCriteria.Op.EQ); + + TmpltsInZoneSearch = createSearchBuilder(); + TmpltsInZoneSearch.and("removed", TmpltsInZoneSearch.entity().getRemoved(), SearchCriteria.Op.NULL); + TmpltsInZoneSearch.and().op("avoidtype", TmpltsInZoneSearch.entity().getTemplateType(), SearchCriteria.Op.NEQ); + TmpltsInZoneSearch.or("templateType", TmpltsInZoneSearch.entity().getTemplateType(), SearchCriteria.Op.NULL); + TmpltsInZoneSearch.cp(); + TmpltsInZoneSearch.join("tmpltzone", tmpltZoneSearch, tmpltZoneSearch.entity().getTemplateId(), TmpltsInZoneSearch.entity().getId(), JoinBuilder.JoinType.INNER); + tmpltZoneSearch.done(); + TmpltsInZoneSearch.done(); + + CountTemplatesByAccount = createSearchBuilder(Long.class); + CountTemplatesByAccount.select(null, Func.COUNT, null); + CountTemplatesByAccount.and("account", CountTemplatesByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountTemplatesByAccount.and("removed", CountTemplatesByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); + CountTemplatesByAccount.done(); + + return result; + } + + @Override + public String getRoutingTemplateUniqueName() { + return routerTmpltName; + } + + @Override + public Set> searchSwiftTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, + Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, Map tags) { + + StringBuilder builder = new StringBuilder(); + if (!permittedAccounts.isEmpty()) { + for (Account permittedAccount : permittedAccounts) { + builder.append(permittedAccount.getAccountId() + ","); + } + } + + String permittedAccountsStr = builder.toString(); + + if (permittedAccountsStr.length() > 0) { + // chop the "," off + permittedAccountsStr = permittedAccountsStr.substring(0, permittedAccountsStr.length() - 1); + } + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + Set> templateZonePairList = new HashSet>(); + PreparedStatement pstmt = null; + ResultSet rs = null; + String sql = SELECT_TEMPLATE_SWIFT_REF; + try { + String joinClause = ""; + String whereClause = " WHERE t.removed IS NULL"; + + if (isIso) { + whereClause += " AND t.format = 'ISO'"; + if (!hyperType.equals(HypervisorType.None)) { + joinClause = " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) "; + whereClause += " AND goh.hypervisor_type = '" + hyperType.toString() + "'"; + } + } else { + whereClause += " AND t.format <> 'ISO'"; + if (hypers.isEmpty()) { + return templateZonePairList; + } else { + StringBuilder relatedHypers = new StringBuilder(); + for (HypervisorType hyper : hypers) { + relatedHypers.append("'"); + relatedHypers.append(hyper.toString()); + relatedHypers.append("'"); + relatedHypers.append(","); + } + relatedHypers.setLength(relatedHypers.length() - 1); + whereClause += " AND t.hypervisor_type IN (" + relatedHypers + ")"; + } + } + joinClause += " INNER JOIN template_swift_ref tsr on (t.id = tsr.template_id)"; + if (keyword != null) { + whereClause += " AND t.name LIKE \"%" + keyword + "%\""; + } else if (name != null) { + whereClause += " AND t.name LIKE \"%" + name + "%\""; + } + + if (bootable != null) { + whereClause += " AND t.bootable = " + bootable; + } + + if (!showDomr) { + whereClause += " AND t.type != '" + Storage.TemplateType.SYSTEM.toString() + "'"; + } + + if (templateFilter == TemplateFilter.featured) { + whereClause += " AND t.public = 1 AND t.featured = 1"; + } else if ((templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { + if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { + joinClause += " INNER JOIN account a on (t.account_id = a.id) INNER JOIN domain d on (a.domain_id = d.id)"; + whereClause += " AND d.path LIKE '" + domain.getPath() + "%'"; + } else { + whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; + } + } else if (templateFilter == TemplateFilter.sharedexecutable && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { + if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) { + joinClause += " LEFT JOIN launch_permission lp ON t.id = lp.template_id WHERE" + " (t.account_id IN (" + permittedAccountsStr + ") OR" + " lp.account_id IN (" + + permittedAccountsStr + "))"; + } else { + joinClause += " INNER JOIN account a on (t.account_id = a.id) "; + } + } else if (templateFilter == TemplateFilter.executable && !permittedAccounts.isEmpty()) { + whereClause += " AND (t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; + } else if (templateFilter == TemplateFilter.community) { + whereClause += " AND t.public = 1 AND t.featured = 0"; + } else if (templateFilter == TemplateFilter.all && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) { + } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { + return templateZonePairList; + } + + sql += joinClause + whereClause + getOrderByLimit(pageSize, startIndex); + pstmt = txn.prepareStatement(sql); + rs = pstmt.executeQuery(); + while (rs.next()) { + Pair templateZonePair = new Pair(rs.getLong(1), -1L); + templateZonePairList.add(templateZonePair); + } + + } catch (Exception e) { + s_logger.warn("Error listing templates", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + txn.commit(); + } catch (SQLException sqle) { + s_logger.warn("Error in cleaning up", sqle); + } + } + + return templateZonePairList; + } + + + @Override + public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, + boolean isIso, List hypers, Boolean bootable, DomainVO domain, Long pageSize, Long startIndex, + Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr,List permittedAccounts, + Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags) { + StringBuilder builder = new StringBuilder(); + if (!permittedAccounts.isEmpty()) { + for (Account permittedAccount : permittedAccounts) { + builder.append(permittedAccount.getAccountId() + ","); + } + } + + String permittedAccountsStr = builder.toString(); + + if (permittedAccountsStr.length() > 0) { + //chop the "," off + permittedAccountsStr = permittedAccountsStr.substring(0, permittedAccountsStr.length()-1); + } + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + /* Use LinkedHashSet here to guarantee iteration order */ + Set> templateZonePairList = new LinkedHashSet>(); + PreparedStatement pstmt = null; + ResultSet rs = null; + StringBuilder relatedDomainIds = new StringBuilder(); + String sql = SELECT_TEMPLATE_ZONE_REF; + String groupByClause = ""; + try { + //short accountType; + //String accountId = null; + String guestOSJoin = ""; + StringBuilder templateHostRefJoin = new StringBuilder(); + String dataCenterJoin = "", lpjoin = ""; + String tagsJoin = ""; + + if (isIso && !hyperType.equals(HypervisorType.None)) { + guestOSJoin = " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) "; + } + if (onlyReady){ + templateHostRefJoin.append(" INNER JOIN template_host_ref thr on (t.id = thr.template_id) INNER JOIN host h on (thr.host_id = h.id)"); + sql = SELECT_TEMPLATE_HOST_REF; + groupByClause = " GROUP BY t.id, h.data_center_id "; + } + if ((templateFilter == TemplateFilter.featured) || (templateFilter == TemplateFilter.community)) { + dataCenterJoin = " INNER JOIN data_center dc on (h.data_center_id = dc.id)"; + } + + if (templateFilter == TemplateFilter.sharedexecutable){ + lpjoin = " INNER JOIN launch_permission lp ON t.id = lp.template_id "; + } + + if (tags != null && !tags.isEmpty()) { + tagsJoin = " INNER JOIN resource_tags r ON t.id = r.resource_id "; + } + + sql += guestOSJoin + templateHostRefJoin + dataCenterJoin + lpjoin + tagsJoin; + String whereClause = ""; + + //All joins have to be made before we start setting the condition settings + if ((listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources + || (!permittedAccounts.isEmpty() && !(templateFilter == TemplateFilter.community || templateFilter == TemplateFilter.featured))) && + !(caller.getType() != Account.ACCOUNT_TYPE_NORMAL && templateFilter == TemplateFilter.all)) { + whereClause += " INNER JOIN account a on (t.account_id = a.id)"; + if ((templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)) { + whereClause += " INNER JOIN domain d on (a.domain_id = d.id) WHERE d.path LIKE '" + domain.getPath() + "%'"; + if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { + whereClause += " AND a.type != " + Account.ACCOUNT_TYPE_PROJECT; + } + } else + if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { + whereClause += " WHERE a.type != " + Account.ACCOUNT_TYPE_PROJECT; + } + } + + if (!permittedAccounts.isEmpty()) { + for (Account account : permittedAccounts) { + //accountType = account.getType(); + //accountId = Long.toString(account.getId()); + DomainVO accountDomain = _domainDao.findById(account.getDomainId()); + + // get all parent domain ID's all the way till root domain + DomainVO domainTreeNode = accountDomain; + while (true) { + relatedDomainIds.append(domainTreeNode.getId()); + relatedDomainIds.append(","); + if (domainTreeNode.getParent() != null) { + domainTreeNode = _domainDao.findById(domainTreeNode.getParent()); + } else { + break; + } + } + + // get all child domain ID's + if (isAdmin(account.getType()) ) { + List allChildDomains = _domainDao.findAllChildren(accountDomain.getPath(), accountDomain.getId()); + for (DomainVO childDomain : allChildDomains) { + relatedDomainIds.append(childDomain.getId()); + relatedDomainIds.append(","); + } + } + relatedDomainIds.setLength(relatedDomainIds.length()-1); + } + } + + String attr = " AND "; + if (whereClause.endsWith(" WHERE ")) { + attr += " WHERE "; + } + + if (!isIso) { + if ( hypers.isEmpty() ) { + return templateZonePairList; + } else { + StringBuilder relatedHypers = new StringBuilder(); + for (HypervisorType hyper : hypers ) { + relatedHypers.append("'"); + relatedHypers.append(hyper.toString()); + relatedHypers.append("'"); + relatedHypers.append(","); + } + relatedHypers.setLength(relatedHypers.length()-1); + whereClause += attr + " t.hypervisor_type IN (" + relatedHypers + ")"; + } + } + + if (!permittedAccounts.isEmpty() && !(templateFilter == TemplateFilter.featured || + templateFilter == TemplateFilter.community || templateFilter == TemplateFilter.executable) && !isAdmin(caller.getType()) ) { + whereClause += attr + "t.account_id IN (" + permittedAccountsStr + ")"; + } + + if (templateFilter == TemplateFilter.featured) { + whereClause += attr + "t.public = 1 AND t.featured = 1"; + if (!permittedAccounts.isEmpty()) { + whereClause += attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)"; + } + } else if (templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) { + whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; + } else if (templateFilter == TemplateFilter.sharedexecutable) { + whereClause += " AND " + + " (t.account_id IN (" + permittedAccountsStr + ") OR" + + " lp.account_id IN (" + permittedAccountsStr + "))"; + } else if (templateFilter == TemplateFilter.executable && !permittedAccounts.isEmpty()) { + whereClause += attr + "(t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; + } else if (templateFilter == TemplateFilter.community) { + whereClause += attr + "t.public = 1 AND t.featured = 0"; + if (!permittedAccounts.isEmpty()) { + whereClause += attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)"; + } + } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && !isIso) { + return templateZonePairList; + } + + if (tags != null && !tags.isEmpty()) { + whereClause += " AND ("; + boolean first = true; + for (String key : tags.keySet()) { + if (!first) { + whereClause += " OR "; + } + whereClause += "(r.key=\"" + key + "\" and r.value=\"" + tags.get(key) + "\")"; + first = false; + } + whereClause += ")"; + } + + if (whereClause.equals("")) { + whereClause += " WHERE "; + } else if (!whereClause.equals(" WHERE ")) { + whereClause += " AND "; + } + + sql += whereClause + getExtrasWhere(templateFilter, name, keyword, isIso, bootable, hyperType, zoneId, + onlyReady, showDomr) + groupByClause + getOrderByLimit(pageSize, startIndex); + + pstmt = txn.prepareStatement(sql); + rs = pstmt.executeQuery(); + + while (rs.next()) { + Pair templateZonePair = new Pair(rs.getLong(1), rs.getLong(2)); + templateZonePairList.add(templateZonePair); + } + //for now, defaulting pageSize to a large val if null; may need to revisit post 2.2RC2 + if(isIso && templateZonePairList.size() < (pageSize != null ? pageSize : 500) + && templateFilter != TemplateFilter.community + && !(templateFilter == TemplateFilter.self && !BaseCmd.isRootAdmin(caller.getType())) ){ //evaluates to true If root admin and filter=self + + List publicIsos = publicIsoSearch(bootable, false, tags); + List userIsos = userIsoSearch(false); + + //Listing the ISOs according to the page size.Restricting the total no. of ISOs on a page + //to be less than or equal to the pageSize parameter + + int i=0; + + if (startIndex > userIsos.size()) { + i=(int) (startIndex - userIsos.size()); + } + + for (; i < publicIsos.size(); i++) { + if(templateZonePairList.size() >= pageSize){ + break; + } else { + if (keyword != null && publicIsos.get(i).getName().contains(keyword)) { + templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); + continue; + } else if (name != null && publicIsos.get(i).getName().contains(name)) { + templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); + continue; + } else if (keyword == null && name == null){ + templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); + } + } + } + } + } catch (Exception e) { + s_logger.warn("Error listing templates", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + txn.commit(); + } catch( SQLException sqle) { + s_logger.warn("Error in cleaning up", sqle); + } + } + + return templateZonePairList; + } + + private String getExtrasWhere(TemplateFilter templateFilter, String name, String keyword, boolean isIso, Boolean bootable, HypervisorType hyperType, Long zoneId, boolean onlyReady, boolean showDomr) { + String sql = ""; + if (keyword != null) { + sql += " t.name LIKE \"%" + keyword + "%\" AND"; + } else if (name != null) { + sql += " t.name LIKE \"%" + name + "%\" AND"; + } + + if (isIso) { + sql += " t.format = 'ISO'"; + if (!hyperType.equals(HypervisorType.None)) { + sql += " AND goh.hypervisor_type = '" + hyperType.toString() + "'"; + } + } else { + sql += " t.format <> 'ISO'"; + if (!hyperType.equals(HypervisorType.None)) { + sql += " AND t.hypervisor_type = '" + hyperType.toString() + "'"; + } + } + + if (bootable != null) { + sql += " AND t.bootable = " + bootable; + } + + if (onlyReady){ + sql += " AND thr.download_state = '" +Status.DOWNLOADED.toString() + "'" + " AND thr.destroyed=0 "; + if (zoneId != null){ + sql += " AND h.data_center_id = " +zoneId; + } + }else if (zoneId != null){ + sql += " AND tzr.zone_id = " +zoneId+ " AND tzr.removed is null" ; + }else{ + sql += " AND tzr.removed is null "; + } + if (!showDomr){ + sql += " AND t.type != '" +Storage.TemplateType.SYSTEM.toString() + "'"; + } + + sql += " AND t.removed IS NULL"; + + return sql; + } + + private String getOrderByLimit(Long pageSize, Long startIndex) { + Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); + isAscending = (isAscending == null ? true : isAscending); + + String sql; + if (isAscending) { + sql = " ORDER BY t.sort_key ASC"; + } else { + sql = " ORDER BY t.sort_key DESC"; + } + + if ((pageSize != null) && (startIndex != null)) { + sql += " LIMIT " + startIndex.toString() + "," + pageSize.toString(); + } + return sql; + } + + @Override + @DB + public long addTemplateToZone(ImageDataVO tmplt, long zoneId) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + ImageDataVO tmplt2 = findById(tmplt.getId()); + if (tmplt2 == null){ + if (persist(tmplt) == null) { + throw new CloudRuntimeException("Failed to persist the template " + tmplt); + } + if(tmplt.getDetails() != null) { + _templateDetailsDao.persist(tmplt.getId(), tmplt.getDetails()); + } + } + VMTemplateZoneVO tmpltZoneVO = _templateZoneDao.findByZoneTemplate(zoneId, tmplt.getId()); + if (tmpltZoneVO == null ) { + tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date()); + _templateZoneDao.persist(tmpltZoneVO); + } else { + tmpltZoneVO.setRemoved(null); + tmpltZoneVO.setLastUpdated(new Date()); + _templateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO); + } + txn.commit(); + + return tmplt.getId(); + } + + @Override + @DB + public List listAllInZone(long dataCenterId) { + SearchCriteria sc = TmpltsInZoneSearch.create(); + sc.setParameters("avoidtype", TemplateType.PERHOST.toString()); + sc.setJoinParameters("tmpltzone", "zoneId", dataCenterId); + return listBy(sc); + } + + @Override + public List listDefaultBuiltinTemplates() { + SearchCriteria sc = tmpltTypeSearch.create(); + sc.setParameters("templateType", Storage.TemplateType.BUILTIN); + return listBy(sc); + } + + @Override + public ImageDataVO findSystemVMTemplate(long zoneId) { + SearchCriteria sc = tmpltTypeHyperSearch.create(); + sc.setParameters("templateType", Storage.TemplateType.SYSTEM); + sc.setJoinParameters("tmplHyper", "type", Host.Type.Routing); + sc.setJoinParameters("tmplHyper", "zoneId", zoneId); + + //order by descending order of id and select the first (this is going to be the latest) + List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, 1l)); + + if (tmplts.size() > 0) { + return tmplts.get(0); + } else { + return null; + } + } + + public ImageDataVO findSystemVMTemplate(long zoneId, HypervisorType hType) { + SearchCriteria sc = tmpltTypeHyperSearch.create(); + sc.setParameters("templateType", Storage.TemplateType.SYSTEM); + sc.setJoinParameters("tmplHyper", "type", Host.Type.Routing); + sc.setJoinParameters("tmplHyper", "zoneId", zoneId); + + //order by descending order of id + List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, null)); + + for (ImageDataVO tmplt: tmplts) { + if (tmplt.getHypervisorType() == hType) { + return tmplt; + } + } + if (tmplts.size() > 0 && hType == HypervisorType.Any) { + return tmplts.get(0); + } + return null; + } + + @Override + public ImageDataVO findRoutingTemplate(HypervisorType hType) { + SearchCriteria sc = tmpltTypeHyperSearch2.create(); + sc.setParameters("templateType", Storage.TemplateType.SYSTEM); + sc.setParameters("hypervisorType", hType); + + //order by descending order of id and select the first (this is going to be the latest) + List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, 1l)); + + if (tmplts.size() > 0) { + return tmplts.get(0); + } else { + return null; + } + } + + @Override + public Long countTemplatesForAccount(long accountId) { + SearchCriteria sc = CountTemplatesByAccount.create(); + sc.setParameters("account", accountId); + return customSearch(sc, null).get(0); + } + + @Override + @DB + public boolean remove(Long id) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + ImageDataVO template = createForUpdate(); + template.setRemoved(new Date()); + + ImageDataVO vo = findById(id); + if (vo != null) { + if (vo.getFormat().equalsIgnoreCase(new ISO().toString())) { + _tagsDao.removeByIdAndType(id, TaggedResourceType.ISO); + } else { + _tagsDao.removeByIdAndType(id, TaggedResourceType.Template); + } + } + + boolean result = update(id, template); + txn.commit(); + return result; + } + + private boolean isAdmin(short accountType) { + return ((accountType == Account.ACCOUNT_TYPE_ADMIN) || + (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) || + (accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || + (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)); + } + +} \ No newline at end of file diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java b/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java new file mode 100644 index 00000000000..d50be8867d1 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java @@ -0,0 +1,381 @@ +/* + * 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.image.db; + +import java.util.Date; +import java.util.Map; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.TableGenerator; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import com.cloud.api.Identity; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Storage; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Storage.TemplateType; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name="vm_template") +public class ImageDataVO implements Identity { + @Id + @TableGenerator(name="vm_template_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="vm_template_seq", allocationSize=1) + @Column(name="id", nullable = false) + private long id; + + @Column(name="format") + private String format; + + @Column(name="unique_name") + private String uniqueName; + + @Column(name="name") + private String name = null; + + @Column(name="public") + private boolean publicTemplate = true; + + @Column(name="featured") + private boolean featured; + + @Column(name="type") + private Storage.TemplateType templateType; + + @Column(name="url") + private String url = null; + + @Column(name="hvm") + private boolean requiresHvm; + + @Column(name="bits") + private int bits; + + @Temporal(value=TemporalType.TIMESTAMP) + @Column(name=GenericDao.CREATED_COLUMN) + private Date created = null; + + @Column(name=GenericDao.REMOVED) + @Temporal(TemporalType.TIMESTAMP) + private Date removed; + + @Column(name="account_id") + private long accountId; + + @Column(name="checksum") + private String checksum; + + @Column(name="display_text", length=4096) + private String displayText; + + @Column(name="enable_password") + private boolean enablePassword; + + @Column(name="guest_os_id") + private long guestOSId; + + @Column(name="bootable") + private boolean bootable = true; + + @Column(name="prepopulate") + private boolean prepopulate = false; + + @Column(name="cross_zones") + private boolean crossZones = false; + + @Column(name="hypervisor_type") + @Enumerated(value=EnumType.STRING) + private HypervisorType hypervisorType; + + @Column(name="extractable") + private boolean extractable = true; + + @Column(name="source_template_id") + private Long sourceTemplateId; + + @Column(name="template_tag") + private String templateTag; + + @Column(name="uuid") + private String uuid; + + @Column(name="sort_key") + private int sortKey; + + @Column(name="enable_sshkey") + private boolean enableSshKey; + + @Transient + Map details; + + + public String getUniqueName() { + return uniqueName; + } + + public void setUniqueName(String uniqueName) { + this.uniqueName = uniqueName; + } + + protected ImageDataVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public boolean getEnablePassword() { + return enablePassword; + } + + public String getFormat() { + return format; + } + + public void setEnablePassword(boolean enablePassword) { + this.enablePassword = enablePassword; + } + + public void setFormat(String format) { + this.format = format; + } + + public long getId() { + return id; + } + + public TemplateType getTemplateType() { + return templateType; + } + + public void setTemplateType(TemplateType type) { + this.templateType = type; + } + + public boolean requiresHvm() { + return requiresHvm; + } + + public int getBits() { + return bits; + } + + public void setBits(int bits) { + this.bits = bits; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getRemoved() { + return removed; + } + + public boolean isPublicTemplate() { + return publicTemplate; + } + + public void setPublicTemplate(boolean publicTemplate) { + this.publicTemplate = publicTemplate; + } + + public boolean isFeatured() { + return featured; + } + + public void setFeatured(boolean featured) { + this.featured = featured; + } + + public Date getCreated() { + return created; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public long getAccountId() { + return accountId; + } + + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } + + public String getDisplayText() { + return displayText; + } + + public void setDisplayText(String displayText) { + this.displayText = displayText; + } + + public long getGuestOSId() { + return guestOSId; + } + + public void setGuestOSId(long guestOSId) { + this.guestOSId = guestOSId; + } + + public boolean isBootable() { + return bootable; + } + + public void setBootable(boolean bootable) { + this.bootable = bootable; + } + + public void setPrepopulate(boolean prepopulate) { + this.prepopulate = prepopulate; + } + + public boolean isPrepopulate() { + return prepopulate; + } + + public void setCrossZones(boolean crossZones) { + this.crossZones = crossZones; + } + + public boolean isCrossZones() { + return crossZones; + } + + public HypervisorType getHypervisorType() { + return hypervisorType; + } + + public void setHypervisorType(HypervisorType hyperType) { + hypervisorType = hyperType; + } + + public boolean isExtractable() { + return extractable; + } + + public void setExtractable(boolean extractable) { + this.extractable = extractable; + } + + public Long getSourceTemplateId() { + return sourceTemplateId; + } + + public void setSourceTemplateId(Long sourceTemplateId) { + this.sourceTemplateId = sourceTemplateId; + } + + public String getTemplateTag() { + return templateTag; + } + + public void setTemplateTag(String templateTag) { + this.templateTag = templateTag; + } + + public long getDomainId() { + return -1; + } + + @Override + public String getUuid() { + return this.uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Map getDetails() { + return this.details; + } + + public void setDetails(Map details) { + this.details = details; + } + + @Override + public boolean equals(Object that) { + if (this == that ) { + return true; + } + if (!(that instanceof VMTemplateVO)){ + return false; + } + VMTemplateVO other = (VMTemplateVO)that; + + return ((this.getUniqueName().equals(other.getUniqueName()))); + } + + @Override + public int hashCode() { + return uniqueName.hashCode(); + } + + @Transient + String toString; + @Override + public String toString() { + if (toString == null) { + toString = new StringBuilder("Tmpl[").append(id).append("-").append(format).append("-").append(uniqueName).toString(); + } + return toString; + } + + public void setRemoved(Date removed) { + this.removed = removed; + } + + public void setSortKey(int key) { + sortKey = key; + } + + public int getSortKey() { + return sortKey; + } + + public boolean getEnableSshKey() { + return enableSshKey; + } + + public void setEnableSshKey(boolean enable) { + enableSshKey = enable; + } + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/BAREMETAL.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/BAREMETAL.java new file mode 100644 index 00000000000..c3de2f1a31d --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/BAREMETAL.java @@ -0,0 +1,31 @@ +/* + * 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.image.format; + +import org.apache.cloudstack.storage.BaseType; +import org.springframework.stereotype.Component; + +@Component +public class BAREMETAL extends BaseType implements ImageFormat { + private final String type = "BAREMETAL"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/ISO.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/ISO.java new file mode 100644 index 00000000000..f27d16b178a --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/ISO.java @@ -0,0 +1,31 @@ +/* + * 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.image.format; + +import org.apache.cloudstack.storage.BaseType; +import org.springframework.stereotype.Component; + +@Component +public class ISO extends BaseType implements ImageFormat { + private final String type = "ISO"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormat.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormat.java new file mode 100644 index 00000000000..f02694a7195 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormat.java @@ -0,0 +1,23 @@ +/* + * 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.image.format; + +public interface ImageFormat { + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormatHelper.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormatHelper.java new file mode 100644 index 00000000000..6ecb9b05d43 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/ImageFormatHelper.java @@ -0,0 +1,44 @@ +/* + * 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.image.format; + +import java.util.List; + +import javax.inject.Inject; + +import org.springframework.stereotype.Component; + +@Component +public class ImageFormatHelper { + private static List formats; + private static final ImageFormat defaultFormat = new Unknown(); + @Inject + public void setFormats(List formats) { + ImageFormatHelper.formats = formats; + } + + public static ImageFormat getFormat(String format) { + for(ImageFormat fm : formats) { + if (fm.equals(format)) { + return fm; + } + } + return ImageFormatHelper.defaultFormat; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/OVA.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/OVA.java new file mode 100644 index 00000000000..46f77a00be2 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/OVA.java @@ -0,0 +1,31 @@ +/* + * 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.image.format; + +import org.apache.cloudstack.storage.BaseType; +import org.springframework.stereotype.Component; + +@Component +public class OVA extends BaseType implements ImageFormat { + private final String type = "OVA"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/QCOW2.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/QCOW2.java new file mode 100644 index 00000000000..9e13ebb62c8 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/QCOW2.java @@ -0,0 +1,31 @@ +/* + * 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.image.format; + +import org.apache.cloudstack.storage.BaseType; +import org.springframework.stereotype.Component; + +@Component("imageformat_qcow2") +public class QCOW2 extends BaseType implements ImageFormat { + private final String type = "QCOW2"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/Unknown.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/Unknown.java new file mode 100644 index 00000000000..341be646b6b --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/Unknown.java @@ -0,0 +1,32 @@ +/* + * 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.image.format; + +import org.apache.cloudstack.storage.BaseType; +import org.springframework.stereotype.Component; + +@Component +public class Unknown extends BaseType implements ImageFormat { + private final String type = "Unknown"; + + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/format/VHD.java b/platform/storage/src/org/apache/cloudstack/storage/image/format/VHD.java new file mode 100644 index 00000000000..4a02e5fe893 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/format/VHD.java @@ -0,0 +1,29 @@ +/* + * 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.image.format; + +import org.apache.cloudstack.storage.BaseType; + +public class VHD extends BaseType implements ImageFormat { + private final String type = "VHD"; + @Override + public String toString() { + return type; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/provider/ImageDataStoreProvider.java b/platform/storage/src/org/apache/cloudstack/storage/image/provider/ImageDataStoreProvider.java new file mode 100644 index 00000000000..42933f440b9 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/provider/ImageDataStoreProvider.java @@ -0,0 +1,25 @@ +/* + * 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.image.provider; + +import org.apache.cloudstack.storage.image.store.ImageDataStore; + +public interface ImageDataStoreProvider { + ImageDataStore getImageDataStore(long imageStoreId); +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/image/store/ImageDataStore.java b/platform/storage/src/org/apache/cloudstack/storage/image/store/ImageDataStore.java new file mode 100644 index 00000000000..db7c2657aa2 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/image/store/ImageDataStore.java @@ -0,0 +1,23 @@ +/* + * 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.image.store; + +public interface ImageDataStore { + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/manager/PrimaryDataStoreManagerImpl.java b/platform/storage/src/org/apache/cloudstack/storage/manager/PrimaryDataStoreManagerImpl.java index 6faf6d7a16b..2cae6a8c7ac 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/manager/PrimaryDataStoreManagerImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/manager/PrimaryDataStoreManagerImpl.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.platform.subsystem.api.storage.DataStore; import org.apache.cloudstack.platform.subsystem.api.storage.DataStore.StoreType; import org.apache.cloudstack.platform.subsystem.api.storage.DataStoreLifeCycle; import org.apache.cloudstack.platform.subsystem.api.storage.StorageProvider; +import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; @@ -126,4 +127,16 @@ public class PrimaryDataStoreManagerImpl implements PrimaryDataStoreManager { return spool; } + @Override + public PrimaryDataStore addDataStore(long zoneId, long podId, long clusterId, long hostId, String URI, String storageType, String poolName, String storageProviderName, Map params) { + // TODO Auto-generated method stub + return null; + } + + @Override + public PrimaryDataStore getDataStore(String id) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java b/platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java index fb1c37d6580..35eaa3b9a16 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java @@ -2,19 +2,23 @@ package org.apache.cloudstack.storage.volume; import javax.inject.Inject; -import org.apache.cloudstack.platform.subsystem.api.storage.DataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; +import org.apache.cloudstack.storage.datastore.PrimaryDataStoreInfo; import org.apache.cloudstack.storage.volume.db.VolumeDao; import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.apache.cloudstack.storage.volume.disktype.VolumeDiskType; import org.apache.cloudstack.storage.volume.disktype.VolumeDiskTypeHelper; import org.apache.cloudstack.storage.volume.type.VolumeType; import org.apache.cloudstack.storage.volume.type.VolumeTypeHelper; +import org.apache.log4j.Logger; -import com.cloud.utils.fsm.StateObject; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; -public class Volume implements StateObject { +public class Volume { + private static final Logger s_logger = Logger.getLogger(Volume.class); protected VolumeVO volumeVO; + private StateMachine2 _volStateMachine; protected PrimaryDataStore dataStore; @Inject VolumeDiskTypeHelper diskTypeHelper; @@ -28,7 +32,30 @@ public class Volume implements StateObject { this.dataStore = dataStore; } - @Override + public String getUuid() { + return volumeVO.getUuid(); + } + + public void setUuid(String uuid) { + volumeVO.setUuid(uuid); + } + + public String getPath() { + return volumeVO.getPath(); + } + + public String getTemplateUuid() { + return null; + } + + public String getTemplatePath() { + return null; + } + + public PrimaryDataStoreInfo getDataStoreInfo() { + return dataStore.getDataStoreInfo(); + } + public VolumeState getState() { return volumeVO.getState(); } @@ -49,10 +76,24 @@ public class Volume implements StateObject { return volumeTypeHelper.getType(volumeVO.getVolumeType()); } + public long getVolumeId() { + return volumeVO.getId(); + } + public void setVolumeDiskType(VolumeDiskType type) { volumeVO.setDiskType(type.toString()); } + public boolean stateTransit(VolumeEvent event) { + boolean result = false; + try { + result = _volStateMachine.transitTo(volumeVO, event, null, volumeDao); + } catch (NoTransitionException e) { + s_logger.debug("Failed to transit volume: " + this.getVolumeId() + ", due to: " + e.toString()); + } + return result; + } + public void update() { volumeDao.update(volumeVO.getId(), volumeVO); volumeVO = volumeDao.findById(volumeVO.getId()); diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeInfo.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeInfo.java new file mode 100644 index 00000000000..0c6981a9401 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeInfo.java @@ -0,0 +1,76 @@ +/* + * 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.volume; + +import org.apache.cloudstack.storage.datastore.PrimaryDataStoreInfo; +import org.apache.cloudstack.storage.volume.disktype.VolumeDiskType; +import org.apache.cloudstack.storage.volume.type.VolumeType; + +public class VolumeInfo { + private long size; + private String uuid; + private String path; + private PrimaryDataStoreInfo dataStoreInfo; + private String baseTemplateUuid; + private String baseTemplatePath; + private VolumeType type; + private VolumeDiskType diskType; + + public VolumeInfo(Volume volume) { + this.size = volume.getSize(); + this.uuid = volume.getUuid(); + this.baseTemplatePath = volume.getTemplatePath(); + this.baseTemplateUuid = volume.getTemplateUuid(); + this.dataStoreInfo = volume.getDataStoreInfo(); + this.diskType = volume.getDiskType(); + this.type = volume.getType(); + } + + public long getSize() { + return this.size; + } + + public String getUuid() { + return this.uuid; + } + + public String getPath() { + return this.path; + } + + public PrimaryDataStoreInfo getDataStore() { + return this.dataStoreInfo; + } + + public String getTemplateUuid() { + return this.baseTemplateUuid; + } + + public String getTemplatePath() { + return this.baseTemplatePath; + } + + public VolumeType getType() { + return this.type; + } + + public VolumeDiskType getDiskType() { + return this.diskType; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java index 79aa6456151..63e247cc2a8 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java @@ -18,6 +18,7 @@ */ package org.apache.cloudstack.storage.volume; +import org.apache.cloudstack.storage.volume.disktype.VolumeDiskType; import org.apache.cloudstack.storage.volume.type.VolumeType; public interface VolumeService { @@ -34,7 +35,7 @@ public interface VolumeService { * * @return the volume object */ - Volume createVolume(long volumeId, long dataStoreId); + Volume createVolume(long volumeId, long dataStoreId, VolumeDiskType diskType); /** * Delete volume diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index a44f82d83c8..145813fda9b 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -20,7 +20,10 @@ package org.apache.cloudstack.storage.volume; import javax.inject.Inject; +import org.apache.cloudstack.storage.datastore.PrimaryDataStore; +import org.apache.cloudstack.storage.datastore.manager.PrimaryDataStoreManager; import org.apache.cloudstack.storage.volume.db.VolumeDao; +import org.apache.cloudstack.storage.volume.disktype.VolumeDiskType; import org.apache.cloudstack.storage.volume.type.VolumeType; import org.springframework.stereotype.Service; @@ -30,10 +33,12 @@ import com.cloud.utils.db.DB; public class VolumeServiceImpl implements VolumeService { @Inject VolumeDao volDao; + @Inject + PrimaryDataStoreManager dataStoreMgr; @Override - public Volume createVolume(long volumeId, long dataStoreId) { - // TODO Auto-generated method stub - return null; + public Volume createVolume(long volumeId, long dataStoreId, VolumeDiskType diskType) { + PrimaryDataStore dataStore = dataStoreMgr.getPrimaryDataStore(dataStoreId); + return dataStore.createVolume(volumeId, diskType); } @DB diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java index 6b81f007ea6..f2ebafa6690 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.storage.volume; +import org.apache.cloudstack.storage.volume.db.VolumeVO; + import com.cloud.utils.fsm.StateMachine2; public enum VolumeState { @@ -36,7 +38,7 @@ public enum VolumeState { _description = description; } - public static StateMachine2 getStateMachine() { + public static StateMachine2 getStateMachine() { return s_fsm; } @@ -44,7 +46,7 @@ public enum VolumeState { return _description; } - private final static StateMachine2 s_fsm = new StateMachine2(); + private final static StateMachine2 s_fsm = new StateMachine2(); static { s_fsm.addTransition(Allocated, VolumeEvent.CreateRequested, Creating); s_fsm.addTransition(Allocated, VolumeEvent.DestroyRequested, Destroy); diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java index 7f2cede9c29..48da123ceef 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java @@ -39,10 +39,11 @@ import com.cloud.api.Identity; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateObject; @Entity @Table(name = "volumes") -public class VolumeVO implements Identity { +public class VolumeVO implements Identity, StateObject{ @Id @TableGenerator(name = "volume_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "volume_seq", allocationSize = 1) @GeneratedValue(strategy = GenerationType.TABLE) diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/disktype/VolumeDiskTypeHelper.java b/platform/storage/src/org/apache/cloudstack/storage/volume/disktype/VolumeDiskTypeHelper.java index 666f89b901d..c51e25fcf84 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/disktype/VolumeDiskTypeHelper.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/disktype/VolumeDiskTypeHelper.java @@ -8,17 +8,22 @@ import org.springframework.stereotype.Component; @Component public class VolumeDiskTypeHelper { - @Inject - protected List diskTypes; - protected VolumeDiskType defaultType = new Unknown(); - public VolumeDiskType getDiskType(String type) { + static private List diskTypes; + static final private VolumeDiskType defaultType = new Unknown(); + + @Inject + public void setDiskTypes(List diskTypes) { + VolumeDiskTypeHelper.diskTypes = diskTypes; + } + + public static VolumeDiskType getDiskType(String type) { for (VolumeDiskType diskType : diskTypes) { if (diskType.equals(type)) { return diskType; } } - return defaultType; + return VolumeDiskTypeHelper.defaultType; } } diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeType.java b/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeType.java index 6f11b090db2..e423a5e62ef 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeType.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeType.java @@ -19,5 +19,4 @@ package org.apache.cloudstack.storage.volume.type; public interface VolumeType { - boolean equals(String type); } diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeBase.java b/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeBase.java index 3597517cbe6..830873cd2c2 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeBase.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeBase.java @@ -4,12 +4,23 @@ public class VolumeTypeBase implements VolumeType { protected String type = "Unknown"; @Override - public boolean equals(String type) { - if (this.type.equalsIgnoreCase(type)) { + public boolean equals(Object that) { + if (this == that) { return true; + } + if (that instanceof String) { + if (this.toString().equalsIgnoreCase((String)that)) { + return true; + } + } else if (that instanceof VolumeTypeBase) { + VolumeTypeBase th = (VolumeTypeBase)that; + if (this.toString().equalsIgnoreCase(th.toString())) { + return true; + } } else { return false; } + return false; } @Override diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeHelper.java b/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeHelper.java index 8f567589c7e..9443475e79a 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeHelper.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/type/VolumeTypeHelper.java @@ -8,17 +8,21 @@ import org.springframework.stereotype.Component; @Component public class VolumeTypeHelper { - @Inject - private List types; - private VolumeType defaultType = new Unknown(); + static private List types; + private static VolumeType defaultType = new Unknown(); - public VolumeType getType(String type) { + @Inject + public void setTypes(List types) { + VolumeTypeHelper.types = types; + } + + public static VolumeType getType(String type) { for (VolumeType ty : types) { if (ty.equals(type)) { return ty; } } - return defaultType; + return VolumeTypeHelper.defaultType; } } diff --git a/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index ca3a366687e..8771d02543e 100644 --- a/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -28,12 +28,20 @@ import javax.inject.Inject; import org.apache.cloudstack.storage.datastore.DefaultPrimaryDataStoreImpl; import org.apache.cloudstack.storage.datastore.provider.DefaultPrimaryDatastoreProviderImpl; import org.apache.cloudstack.storage.datastore.provider.PrimaryDataStoreProvider; +import org.apache.cloudstack.storage.image.format.ISO; +import org.apache.cloudstack.storage.image.format.ImageFormat; +import org.apache.cloudstack.storage.image.format.ImageFormatHelper; +import org.apache.cloudstack.storage.image.format.OVA; +import org.apache.cloudstack.storage.image.format.Unknown; import org.apache.cloudstack.storage.volume.VolumeMotionService; import org.apache.cloudstack.storage.volume.VolumeService; import org.apache.cloudstack.storage.volume.db.VolumeDao; +import org.apache.cloudstack.storage.volume.disktype.QCOW2; import org.apache.cloudstack.storage.volume.disktype.VHD; import org.apache.cloudstack.storage.volume.disktype.VMDK; +import org.apache.cloudstack.storage.volume.disktype.VolumeDiskType; import org.apache.cloudstack.storage.volume.disktype.VolumeDiskTypeHelper; +import org.apache.cloudstack.storage.volume.type.Iso; import org.apache.cloudstack.storage.volume.type.VolumeTypeHelper; import org.junit.Before; import org.junit.Test; @@ -60,10 +68,6 @@ public class volumeServiceTest { protected VolumeDao volumeDao; @Autowired protected VolumeMotionService vmotion; - @Autowired - protected VolumeTypeHelper volTypeHelper; - @Inject - protected VolumeDiskTypeHelper volDiskTypeHelper; @Before public void setUp() { Mockito.when(vmotion.copyVolume(null, null)).thenReturn(false); @@ -91,22 +95,34 @@ public class volumeServiceTest { @Test public void test1() { - System.out.println(volTypeHelper.getType("Root")); - System.out.println(volDiskTypeHelper.getDiskType("vmdk")); + System.out.println(VolumeTypeHelper.getType("Root")); + System.out.println(VolumeDiskTypeHelper.getDiskType("vmdk")); + System.out.println(ImageFormatHelper.getFormat("ova")); assertFalse(new VMDK().equals(new VHD())); VMDK vmdk = new VMDK(); assertTrue(vmdk.equals(vmdk)); VMDK newvmdk = new VMDK(); assertTrue(vmdk.equals(newvmdk)); + + ImageFormat ova = new OVA(); + ImageFormat iso = new ISO(); + assertTrue(ova.equals(new OVA())); + assertFalse(ova.equals(iso)); + assertTrue(ImageFormatHelper.getFormat("test").equals(new Unknown())); + + VolumeDiskType qcow2 = new QCOW2(); + ImageFormat qcow2format = new org.apache.cloudstack.storage.image.format.QCOW2(); + assertFalse(qcow2.equals(qcow2format)); + } - @Test + //@Test public void testStaticBean() { DefaultPrimaryDatastoreProviderImpl provider = ComponentInject.inject(DefaultPrimaryDatastoreProviderImpl.class); assertNotNull(provider.dataStoreDao); DefaultPrimaryDataStoreImpl dpdsi = new DefaultPrimaryDataStoreImpl(null, null, null); ComponentInject.inject(dpdsi); - assertNotNull(dpdsi.volumeDao); + //assertNotNull(dpdsi.volumeDao); } } diff --git a/server/src/com/cloud/host/dao/HostDao.java b/server/src/com/cloud/host/dao/HostDao.java index 58bd8be931a..4760035ec48 100755 --- a/server/src/com/cloud/host/dao/HostDao.java +++ b/server/src/com/cloud/host/dao/HostDao.java @@ -68,6 +68,7 @@ public interface HostDao extends GenericDao, StateDao findHypervisorHostInCluster(long clusterId); /** diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/server/src/com/cloud/host/dao/HostDaoImpl.java index ab1e77eb7f4..990aef8d729 100755 --- a/server/src/com/cloud/host/dao/HostDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDaoImpl.java @@ -73,6 +73,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao protected final SearchBuilder IdStatusSearch; protected final SearchBuilder TypeDcSearch; protected final SearchBuilder TypeDcStatusSearch; + protected final SearchBuilder TypeClusterStatusSearch; protected final SearchBuilder MsStatusSearch; protected final SearchBuilder DcPrivateIpAddressSearch; protected final SearchBuilder DcStorageIpAddressSearch; @@ -157,7 +158,14 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao TypeDcStatusSearch.and("status", TypeDcStatusSearch.entity().getStatus(), SearchCriteria.Op.EQ); TypeDcStatusSearch.and("resourceState", TypeDcStatusSearch.entity().getResourceState(), SearchCriteria.Op.EQ); TypeDcStatusSearch.done(); - + + TypeClusterStatusSearch = createSearchBuilder(); + TypeClusterStatusSearch.and("type", TypeClusterStatusSearch.entity().getType(), SearchCriteria.Op.EQ); + TypeClusterStatusSearch.and("cluster", TypeClusterStatusSearch.entity().getClusterId(), SearchCriteria.Op.EQ); + TypeClusterStatusSearch.and("status", TypeClusterStatusSearch.entity().getStatus(), SearchCriteria.Op.EQ); + TypeClusterStatusSearch.and("resourceState", TypeClusterStatusSearch.entity().getResourceState(), SearchCriteria.Op.EQ); + TypeClusterStatusSearch.done(); + IdStatusSearch = createSearchBuilder(); IdStatusSearch.and("id", IdStatusSearch.entity().getId(), SearchCriteria.Op.EQ); IdStatusSearch.and("states", IdStatusSearch.entity().getStatus(), SearchCriteria.Op.IN); @@ -764,4 +772,15 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao return findOneBy(sc); } + @Override + public List findHypervisorHostInCluster(long clusterId) { + SearchCriteria sc = TypeClusterStatusSearch.create(); + sc.setParameters("type", Host.Type.Routing); + sc.setParameters("cluster", clusterId); + sc.setParameters("status", Status.Up); + sc.setParameters("resourceState", ResourceState.Enabled); + + return listBy(sc); + } + }