Merge pull request #2044 from shapeblue/cleanup-unlinked-templates

CLOUDSTACK-9877 Cleanup unlinked templates
This commit is contained in:
dahn 2017-08-25 09:01:26 +02:00 committed by GitHub
commit 64e56a2159
13 changed files with 363 additions and 554 deletions

View File

@ -50,6 +50,8 @@ public interface StorageManager extends StorageService {
"Determines how long (in seconds) to wait before actually expunging destroyed volumes. The default value = the default value of storage.cleanup.interval.", false, ConfigKey.Scope.Global, null); "Determines how long (in seconds) to wait before actually expunging destroyed volumes. The default value = the default value of storage.cleanup.interval.", false, ConfigKey.Scope.Global, null);
static final ConfigKey<Boolean> StorageCleanupEnabled = new ConfigKey<Boolean>(Boolean.class, "storage.cleanup.enabled", "Advanced", "true", static final ConfigKey<Boolean> StorageCleanupEnabled = new ConfigKey<Boolean>(Boolean.class, "storage.cleanup.enabled", "Advanced", "true",
"Enables/disables the storage cleanup thread.", false, ConfigKey.Scope.Global, null); "Enables/disables the storage cleanup thread.", false, ConfigKey.Scope.Global, null);
static final ConfigKey<Boolean> TemplateCleanupEnabled = new ConfigKey<Boolean>(Boolean.class, "storage.template.cleanup.enabled", "Storage", "true",
"Enable/disable template cleanup activity, only take effect when overall storage cleanup is enabled", false, ConfigKey.Scope.Global, null);
/** /**
* Returns a comma separated list of tags for the specified storage pool * Returns a comma separated list of tags for the specified storage pool

View File

@ -270,7 +270,6 @@
<bean id="storagePoolTagsDaoImpl" class="com.cloud.storage.dao.StoragePoolTagsDaoImpl" /> <bean id="storagePoolTagsDaoImpl" class="com.cloud.storage.dao.StoragePoolTagsDaoImpl" />
<bean id="hostTagDaoImpl" class="com.cloud.api.query.dao.HostTagDaoImpl" /> <bean id="hostTagDaoImpl" class="com.cloud.api.query.dao.HostTagDaoImpl" />
<bean id="storagePoolWorkDaoImpl" class="com.cloud.storage.dao.StoragePoolWorkDaoImpl" /> <bean id="storagePoolWorkDaoImpl" class="com.cloud.storage.dao.StoragePoolWorkDaoImpl" />
<bean id="templatePrimaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.volume.db.TemplatePrimaryDataStoreDaoImpl" />
<bean id="uploadDaoImpl" class="com.cloud.storage.dao.UploadDaoImpl" /> <bean id="uploadDaoImpl" class="com.cloud.storage.dao.UploadDaoImpl" />
<bean id="usageDaoImpl" class="com.cloud.usage.dao.UsageDaoImpl" /> <bean id="usageDaoImpl" class="com.cloud.usage.dao.UsageDaoImpl" />
<bean id="usageEventDaoImpl" class="com.cloud.event.dao.UsageEventDaoImpl" /> <bean id="usageEventDaoImpl" class="com.cloud.event.dao.UsageEventDaoImpl" />

View File

@ -43,7 +43,6 @@
<bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" /> <bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" />
<bean id="primaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl" /> <bean id="primaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl" />
<bean id="primaryDataStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.volume.db.PrimaryDataStoreDetailsDaoImpl" /> <bean id="primaryDataStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.volume.db.PrimaryDataStoreDetailsDaoImpl" />
<bean id="templatePrimaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.volume.db.TemplatePrimaryDataStoreDaoImpl" />
<bean id="LocalStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.LocalStoragePoolAllocator"/> <bean id="LocalStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.LocalStoragePoolAllocator"/>
<bean id="clusterScopeStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ClusterScopeStoragePoolAllocator" /> <bean id="clusterScopeStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ClusterScopeStoragePoolAllocator" />
<bean id="zoneWideStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ZoneWideStoragePoolAllocator" /> <bean id="zoneWideStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ZoneWideStoragePoolAllocator" />

View File

@ -43,7 +43,6 @@
<bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" /> <bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" />
<bean id="primaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl" /> <bean id="primaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl" />
<bean id="primaryDataStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.volume.db.PrimaryDataStoreDetailsDaoImpl" /> <bean id="primaryDataStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.volume.db.PrimaryDataStoreDetailsDaoImpl" />
<bean id="templatePrimaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.volume.db.TemplatePrimaryDataStoreDaoImpl" />
<bean id="LocalStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.LocalStoragePoolAllocator"/> <bean id="LocalStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.LocalStoragePoolAllocator"/>
<bean id="clusterScopeStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ClusterScopeStoragePoolAllocator" /> <bean id="clusterScopeStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ClusterScopeStoragePoolAllocator" />
<bean id="zoneWideStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ZoneWideStoragePoolAllocator" /> <bean id="zoneWideStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ZoneWideStoragePoolAllocator" />

View File

@ -1,31 +0,0 @@
/*
* 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.db;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.fsm.StateDao;
public interface TemplatePrimaryDataStoreDao extends GenericDao<TemplatePrimaryDataStoreVO, Long>,
StateDao<ObjectInDataStoreStateMachine.State, ObjectInDataStoreStateMachine.Event, TemplatePrimaryDataStoreVO> {
public TemplatePrimaryDataStoreVO findByTemplateIdAndPoolId(long templateId, long poolId);
public TemplatePrimaryDataStoreVO findByTemplateIdAndPoolIdAndReady(long templateId, long poolId);
}

View File

@ -1,123 +0,0 @@
/*
* 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.db;
import java.util.Date;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.UpdateBuilder;
@Component
public class TemplatePrimaryDataStoreDaoImpl extends GenericDaoBase<TemplatePrimaryDataStoreVO, Long> implements TemplatePrimaryDataStoreDao {
private static final Logger s_logger = Logger.getLogger(TemplatePrimaryDataStoreDaoImpl.class);
protected final SearchBuilder<TemplatePrimaryDataStoreVO> updateSearchBuilder;
public TemplatePrimaryDataStoreDaoImpl() {
updateSearchBuilder = createSearchBuilder();
updateSearchBuilder.and("id", updateSearchBuilder.entity().getId(), Op.EQ);
updateSearchBuilder.and("state", updateSearchBuilder.entity().getState(), Op.EQ);
updateSearchBuilder.and("updatedCount", updateSearchBuilder.entity().getUpdatedCount(), Op.EQ);
updateSearchBuilder.done();
}
@Override
public TemplatePrimaryDataStoreVO findByTemplateIdAndPoolId(long templateId, long poolId) {
QueryBuilder<TemplatePrimaryDataStoreVO> sc = QueryBuilder.create(TemplatePrimaryDataStoreVO.class);
sc.and(sc.entity().getTemplateId(), Op.EQ, templateId);
sc.and(sc.entity().getPoolId(), Op.EQ, poolId);
return sc.find();
}
@Override
public TemplatePrimaryDataStoreVO findByTemplateIdAndPoolIdAndReady(long templateId, long poolId) {
QueryBuilder<TemplatePrimaryDataStoreVO> sc = QueryBuilder.create(TemplatePrimaryDataStoreVO.class);
sc.and(sc.entity().getTemplateId(), Op.EQ, templateId);
sc.and(sc.entity().getPoolId(), Op.EQ, poolId);
sc.and(sc.entity().getState(), Op.EQ, ObjectInDataStoreStateMachine.State.Ready);
return sc.find();
}
@Override
public boolean updateState(State currentState, Event event, State nextState, TemplatePrimaryDataStoreVO vo, Object data) {
Long oldUpdated = vo.getUpdatedCount();
Date oldUpdatedTime = vo.getLastUpdated();
SearchCriteria<TemplatePrimaryDataStoreVO> sc = updateSearchBuilder.create();
sc.setParameters("id", vo.getId());
sc.setParameters("state", currentState);
sc.setParameters("updatedCount", vo.getUpdatedCount());
vo.incrUpdatedCount();
UpdateBuilder builder = getUpdateBuilder(vo);
builder.set(vo, "state", nextState);
builder.set(vo, "lastUpdated", new Date());
int rows = update(vo, sc);
if (rows == 0 && s_logger.isDebugEnabled()) {
TemplatePrimaryDataStoreVO template = findByIdIncludingRemoved(vo.getId());
if (template != null) {
StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString());
str.append(": DB Data={id=")
.append(template.getId())
.append("; state=")
.append(template.getState())
.append("; updatecount=")
.append(template.getUpdatedCount())
.append(";updatedTime=")
.append(template.getLastUpdated());
str.append(": New Data={id=")
.append(vo.getId())
.append("; state=")
.append(nextState)
.append("; event=")
.append(event)
.append("; updatecount=")
.append(vo.getUpdatedCount())
.append("; updatedTime=")
.append(vo.getLastUpdated());
str.append(": stale Data={id=")
.append(vo.getId())
.append("; state=")
.append(currentState)
.append("; event=")
.append(event)
.append("; updatecount=")
.append(oldUpdated)
.append("; updatedTime=")
.append(oldUpdatedTime);
} else {
s_logger.debug("Unable to update template: id=" + vo.getId() + ", as there is no such template exists in the database anymore");
}
}
return rows > 0;
}
}

View File

@ -1,262 +0,0 @@
/*
* 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.db;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.fsm.StateObject;
@Entity
@Table(name = "template_spool_ref")
public class TemplatePrimaryDataStoreVO implements StateObject<ObjectInDataStoreStateMachine.State> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
long id;
@Column(name = "pool_id")
private long poolId;
@Column(name = "template_id")
long templateId;
@Column(name = GenericDaoBase.CREATED_COLUMN)
Date created = null;
@Column(name = "last_updated")
@Temporal(value = TemporalType.TIMESTAMP)
Date lastUpdated = null;
@Column(name = "download_pct")
int downloadPercent;
@Column(name = "download_state")
@Enumerated(EnumType.STRING)
Status downloadState;
@Column(name = "local_path")
String localDownloadPath;
@Column(name = "error_str")
String errorString;
@Column(name = "job_id")
String jobId;
@Column(name = "install_path")
String installPath;
@Column(name = "template_size")
long templateSize;
@Column(name = "marked_for_gc")
boolean markedForGC;
@Column(name = "state")
@Enumerated(EnumType.STRING)
ObjectInDataStoreStateMachine.State state;
@Column(name = "update_count", updatable = true, nullable = false)
protected long updatedCount;
public long getUpdatedCount() {
return this.updatedCount;
}
public void incrUpdatedCount() {
this.updatedCount++;
}
public void decrUpdatedCount() {
this.updatedCount--;
}
public String getInstallPath() {
return installPath;
}
public long getTemplateSize() {
return templateSize;
}
public long getPoolId() {
return poolId;
}
public void setpoolId(long poolId) {
this.poolId = poolId;
}
public long getTemplateId() {
return templateId;
}
public void setTemplateId(long templateId) {
this.templateId = templateId;
}
public int getDownloadPercent() {
return downloadPercent;
}
public void setDownloadPercent(int downloadPercent) {
this.downloadPercent = downloadPercent;
}
public void setDownloadState(Status downloadState) {
this.downloadState = downloadState;
}
public long getId() {
return id;
}
public Date getCreated() {
return created;
}
public Date getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Date date) {
lastUpdated = date;
}
public void setInstallPath(String installPath) {
this.installPath = installPath;
}
public Status getDownloadState() {
return downloadState;
}
public TemplatePrimaryDataStoreVO(long poolId, long templateId) {
super();
this.poolId = poolId;
this.templateId = templateId;
this.downloadState = Status.NOT_DOWNLOADED;
this.state = ObjectInDataStoreStateMachine.State.Allocated;
this.markedForGC = false;
}
public TemplatePrimaryDataStoreVO(long poolId, long templateId, Date lastUpdated, int downloadPercent, Status downloadState, String localDownloadPath,
String errorString, String jobId, String installPath, long templateSize) {
super();
this.poolId = poolId;
this.templateId = templateId;
this.lastUpdated = lastUpdated;
this.downloadPercent = downloadPercent;
this.downloadState = downloadState;
this.localDownloadPath = localDownloadPath;
this.errorString = errorString;
this.jobId = jobId;
this.installPath = installPath;
this.templateSize = templateSize;
}
protected TemplatePrimaryDataStoreVO() {
}
public void setLocalDownloadPath(String localPath) {
this.localDownloadPath = localPath;
}
public String getLocalDownloadPath() {
return localDownloadPath;
}
public void setErrorString(String errorString) {
this.errorString = errorString;
}
public String getErrorString() {
return errorString;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobId() {
return jobId;
}
public void setTemplateSize(long templateSize) {
this.templateSize = templateSize;
}
public boolean getMarkedForGC() {
return markedForGC;
}
public void setMarkedForGC(boolean markedForGC) {
this.markedForGC = markedForGC;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof TemplatePrimaryDataStoreVO) {
TemplatePrimaryDataStoreVO other = (TemplatePrimaryDataStoreVO)obj;
return (this.templateId == other.getTemplateId() && this.poolId == other.getPoolId());
}
return false;
}
@Override
public int hashCode() {
Long tid = new Long(templateId);
Long hid = new Long(poolId);
return tid.hashCode() + hid.hashCode();
}
@Override
public String toString() {
return new StringBuilder("TmplPool[").append(id)
.append("-")
.append(templateId)
.append("-")
.append("poolId")
.append("-")
.append(installPath)
.append("]")
.toString();
}
@Override
public ObjectInDataStoreStateMachine.State getState() {
return this.state;
}
}

View File

@ -0,0 +1,158 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.hypervisor.vmware.manager;
import com.cloud.api.query.dao.TemplateJoinDao;
import com.cloud.api.query.vo.TemplateJoinVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.HypervisorGuru;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.template.TemplateManager;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.vm.UserVmCloneSettingVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.UserVmCloneSettingDao;
import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.engine.orchestration.VolumeOrchestrator;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.log4j.Logger;
import java.util.List;
/**
* This Task marks templates that are only used as fully cloned templates and have been deleted from CloudStack for removal from primary stores.
*/
public class CleanupFullyClonedTemplatesTask extends ManagedContextRunnable {
private static final Logger s_logger = Logger.getLogger(CleanupFullyClonedTemplatesTask.class);
private PrimaryDataStoreDao primaryStorageDao;
private VMTemplatePoolDao templateDataStoreDao;
private TemplateJoinDao templateDao;
private VMInstanceDao vmInstanceDao;
private UserVmCloneSettingDao cloneSettingDao;
private TemplateManager templateManager;
private Thread mine;
CleanupFullyClonedTemplatesTask(PrimaryDataStoreDao primaryStorageDao,
VMTemplatePoolDao templateDataStoreDao,
TemplateJoinDao templateDao,
VMInstanceDao vmInstanceDao,
UserVmCloneSettingDao cloneSettingDao,
TemplateManager templateManager) {
this.primaryStorageDao = primaryStorageDao;
this.templateDataStoreDao = templateDataStoreDao;
this.templateDao = templateDao;
this.vmInstanceDao = vmInstanceDao;
this.cloneSettingDao = cloneSettingDao;
this.templateManager = templateManager;
if(s_logger.isDebugEnabled()) {
s_logger.debug("new task created: " + this);
}
}
@Override
public void runInContext() {
mine = Thread.currentThread();
s_logger.info("running job to mark fully cloned templates for gc in thread " + mine.getName());
if (HypervisorGuru.VmwareFullClone.value()) { // only run if full cloning is being used (might need to be more fine grained)
try {
queryAllPools();
} catch (Throwable t) {
s_logger.error("error during job to mark fully cloned templates for gc in thread " + mine.getName());
if(s_logger.isDebugEnabled()) {
s_logger.debug("running job to mark fully cloned templates for gc in thread " + mine.getName(),t);
}
}
}
}
private void queryAllPools() {
List<StoragePoolVO> storagePools = primaryStorageDao.listAll();
for (StoragePoolVO pool : storagePools) {
long zoneId = pool.getDataCenterId();
queryPoolForTemplates(pool, zoneId);
}
}
private void queryPoolForTemplates(StoragePoolVO pool, long zoneId) {
// we don't need those specific to other hypervisor types
if (pool.getHypervisor() == null || Hypervisor.HypervisorType.VMware.equals(pool.getHypervisor())) {
if(s_logger.isDebugEnabled()) {
s_logger.debug(mine.getName() + " is marking fully cloned templates in pool " + pool.getName());
}
List<VMTemplateStoragePoolVO> templatePrimaryDataStoreVOS = templateDataStoreDao.listByPoolId(pool.getId());
for (VMTemplateStoragePoolVO templateMapping : templatePrimaryDataStoreVOS) {
if (canRemoveTemplateFromZone(zoneId, templateMapping)) {
templateManager.evictTemplateFromStoragePool(templateMapping);
}
}
} else {
if(s_logger.isDebugEnabled()) {
s_logger.debug(mine.getName() + " is ignoring pool " + pool.getName() + " id == " + pool.getId());
}
}
}
private boolean canRemoveTemplateFromZone(long zoneId, VMTemplateStoragePoolVO templateMapping) {
if (!templateMapping.getMarkedForGC()) {
if(s_logger.isDebugEnabled()) {
s_logger.debug(mine.getName() + " is checking template with id " + templateMapping.getTemplateId() + " for deletion from pool with id " + templateMapping.getPoolId());
}
TemplateJoinVO templateJoinVO = templateDao.findByIdIncludingRemoved(templateMapping.getTemplateId());
// check if these are deleted (not removed is null)
if (VirtualMachineTemplate.State.Inactive.equals(templateJoinVO.getTemplateState())) { // meaning it is removed!
// see if we can find vms using it with user_vm_clone_setting != full
return markedForGc(templateMapping, zoneId);
}
}
return false;
}
private boolean markedForGc(VMTemplateStoragePoolVO templateMapping, long zoneId) {
boolean used = false;
List<VMInstanceVO> vms = vmInstanceDao.listNonExpungedByZoneAndTemplate(zoneId, templateMapping.getTemplateId());
for (VMInstanceVO vm : vms) {
try {
UserVmCloneSettingVO cloneSetting = cloneSettingDao.findByVmId(vm.getId());
// VolumeOrchestrator or UserVmManagerImpl depending on version
if (VolumeOrchestrator.UserVmCloneType.linked.equals(VolumeOrchestrator.UserVmCloneType.valueOf(cloneSetting.getCloneType()))) {
used = true;
break;
}
} catch (Exception e) {
s_logger.error("failed to retrieve vm clone setting for vm " + vm.toString());
if(s_logger.isDebugEnabled()) {
s_logger.debug("failed to retrieve vm clone setting for vm " + vm.toString(), e);
}
}
}
if (!used) {
s_logger.info(mine.getName() + " is marking template with id " + templateMapping.getTemplateId() + " for gc in pool with id " + templateMapping.getPoolId());
// else
// mark it for removal from primary store
templateMapping.setMarkedForGC(true);
}
return !used;
}
}

View File

@ -16,24 +16,25 @@
// under the License. // under the License.
package com.cloud.hypervisor.vmware.manager; package com.cloud.hypervisor.vmware.manager;
import java.io.File;
import java.util.List;
import java.util.Map;
import com.vmware.vim25.ManagedObjectReference;
import org.apache.cloudstack.framework.config.ConfigKey;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareContext;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.vmware.vim25.ManagedObjectReference;
import org.apache.cloudstack.framework.config.ConfigKey;
import java.io.File;
import java.util.List;
import java.util.Map;
public interface VmwareManager { public interface VmwareManager {
public final String CONTEXT_STOCK_NAME = "vmwareMgr"; public final String CONTEXT_STOCK_NAME = "vmwareMgr";
public static final ConfigKey<Long> s_vmwareNicHotplugWaitTimeout = new ConfigKey<Long>("Advanced", Long.class, "vmware.nic.hotplug.wait.timeout", "15000", public static final ConfigKey<Long> s_vmwareNicHotplugWaitTimeout = new ConfigKey<Long>("Advanced", Long.class, "vmware.nic.hotplug.wait.timeout", "15000",
"Wait timeout (milli seconds) for hot plugged NIC of VM to be detected by guest OS.", false, ConfigKey.Scope.Global); "Wait timeout (milli seconds) for hot plugged NIC of VM to be detected by guest OS.", false, ConfigKey.Scope.Global);
public static final ConfigKey<Long> templateCleanupInterval = new ConfigKey<Long>("Advanced", Long.class, "vmware.full.clone.template.cleanup.period", "0",
"period (in minutes) between the start of template cleanup jobs for vmware full cloned templates.", false, ConfigKey.Scope.Global);
public static final ConfigKey<Boolean> s_vmwareCleanOldWorderVMs = new ConfigKey<Boolean>("Advanced", Boolean.class, "vmware.clean.old.worker.vms", "false", public static final ConfigKey<Boolean> s_vmwareCleanOldWorderVMs = new ConfigKey<Boolean>("Advanced", Boolean.class, "vmware.clean.old.worker.vms", "false",
"If a worker vm is older then twice the 'job.expire.minutes' + 'job.cancel.threshold.minutes' , remove it.", true, ConfigKey.Scope.Global); "If a worker vm is older then twice the 'job.expire.minutes' + 'job.cancel.threshold.minutes' , remove it.", true, ConfigKey.Scope.Global);

View File

@ -16,43 +16,6 @@
// under the License. // under the License.
package com.cloud.hypervisor.vmware.manager; package com.cloud.hypervisor.vmware.manager;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.rmi.RemoteException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobManagerImpl;
import org.apache.log4j.Logger;
import com.vmware.vim25.AboutInfo;
import com.vmware.vim25.ManagedObjectReference;
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
import com.cloud.agent.Listener; import com.cloud.agent.Listener;
import com.cloud.agent.api.AgentControlAnswer; import com.cloud.agent.api.AgentControlAnswer;
@ -61,6 +24,7 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command; import com.cloud.agent.api.Command;
import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.api.query.dao.TemplateJoinDao;
import com.cloud.cluster.ClusterManager; import com.cloud.cluster.ClusterManager;
import com.cloud.cluster.ManagementServerHost; import com.cloud.cluster.ManagementServerHost;
import com.cloud.cluster.dao.ManagementServerHostPeerDao; import com.cloud.cluster.dao.ManagementServerHostPeerDao;
@ -103,9 +67,9 @@ import com.cloud.hypervisor.vmware.util.VmwareContext;
import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.hypervisor.vmware.util.VmwareHelper;
import com.cloud.network.CiscoNexusVSMDeviceVO; import com.cloud.network.CiscoNexusVSMDeviceVO;
import com.cloud.network.NetworkModel; import com.cloud.network.NetworkModel;
import com.cloud.network.VmwareTrafficLabel;
import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.TrafficType;
import com.cloud.network.VmwareTrafficLabel;
import com.cloud.network.dao.CiscoNexusVSMDeviceDao; import com.cloud.network.dao.CiscoNexusVSMDeviceDao;
import com.cloud.org.Cluster.ClusterType; import com.cloud.org.Cluster.ClusterType;
import com.cloud.secstorage.CommandExecLogDao; import com.cloud.secstorage.CommandExecLogDao;
@ -113,6 +77,9 @@ import com.cloud.server.ConfigurationServer;
import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.ImageStoreDetailsUtil;
import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.JavaStorageLayer;
import com.cloud.storage.StorageLayer; import com.cloud.storage.StorageLayer;
import com.cloud.storage.StorageManager;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.template.TemplateManager;
import com.cloud.utils.FileUtil; import com.cloud.utils.FileUtil;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
@ -127,14 +94,48 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script; import com.cloud.utils.script.Script;
import com.cloud.utils.ssh.SshHelper; import com.cloud.utils.ssh.SshHelper;
import com.cloud.vm.DomainRouterVO; import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.dao.UserVmCloneSettingDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.vmware.vim25.AboutInfo;
import com.vmware.vim25.ManagedObjectReference;
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobManagerImpl;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.rmi.RemoteException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService, Configurable { public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService, Configurable {
private static final Logger s_logger = Logger.getLogger(VmwareManagerImpl.class); private static final Logger s_logger = Logger.getLogger(VmwareManagerImpl.class);
private static final long SECONDS_PER_MINUTE = 60; private static final long SECONDS_PER_MINUTE = 60;
private static final int STARTUP_DELAY = 60000; // 60 seconds
private static final long DEFAULT_HOST_SCAN_INTERVAL = 600000; // every 10 minutes
private long _hostScanInterval = DEFAULT_HOST_SCAN_INTERVAL;
private int _timeout; private int _timeout;
private String _instance; private String _instance;
@ -175,6 +176,18 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
private ClusterManager _clusterMgr; private ClusterManager _clusterMgr;
@Inject @Inject
private ImageStoreDetailsUtil imageStoreDetailsUtil; private ImageStoreDetailsUtil imageStoreDetailsUtil;
@Inject
private PrimaryDataStoreDao primaryStorageDao;
@Inject
private VMTemplatePoolDao templateDataStoreDao;
@Inject
private TemplateJoinDao templateDao;
@Inject
private VMInstanceDao vmInstanceDao;
@Inject
private UserVmCloneSettingDao cloneSettingDao;
@Inject
private TemplateManager templateManager;
private String _mountParent; private String _mountParent;
private StorageLayer _storage; private StorageLayer _storage;
@ -196,15 +209,15 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
private final String _dataDiskController = DiskControllerType.osdefault.toString(); private final String _dataDiskController = DiskControllerType.osdefault.toString();
private final Map<String, String> _storageMounts = new HashMap<String, String>(); private final Map<String, String> _storageMounts = new HashMap<>();
private final Random _rand = new Random(System.currentTimeMillis()); private final Random _rand = new Random(System.currentTimeMillis());
private static ScheduledExecutorService templateCleanupScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-FullyClonedTemplateCheck"));;
private final VmwareStorageManager _storageMgr; private final VmwareStorageManager _storageMgr;
private final GlobalLock _exclusiveOpLock = GlobalLock.getInternLock("vmware.exclusive.op"); private final GlobalLock _exclusiveOpLock = GlobalLock.getInternLock("vmware.exclusive.op");
private final ScheduledExecutorService _hostScanScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-Host-Scan"));
public VmwareManagerImpl() { public VmwareManagerImpl() {
_storageMgr = new VmwareStorageManagerImpl(this); _storageMgr = new VmwareStorageManagerImpl(this);
} }
@ -216,7 +229,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override @Override
public ConfigKey<?>[] getConfigKeys() { public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {s_vmwareNicHotplugWaitTimeout, s_vmwareCleanOldWorderVMs}; return new ConfigKey<?>[] {s_vmwareNicHotplugWaitTimeout, s_vmwareCleanOldWorderVMs, templateCleanupInterval};
} }
@Override @Override
@ -313,10 +326,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
s_logger.info("Additional VNC port allocation range is settled at " + _additionalPortRangeStart + " to " + (_additionalPortRangeStart + _additionalPortRangeSize)); s_logger.info("Additional VNC port allocation range is settled at " + _additionalPortRangeStart + " to " + (_additionalPortRangeStart + _additionalPortRangeSize));
value = _configDao.getValue("vmware.host.scan.interval");
_hostScanInterval = NumbersUtil.parseLong(value, DEFAULT_HOST_SCAN_INTERVAL);
s_logger.info("VmwareManagerImpl config - vmware.host.scan.interval: " + _hostScanInterval);
((VmwareStorageManagerImpl)_storageMgr).configure(params); ((VmwareStorageManagerImpl)_storageMgr).configure(params);
_agentMgr.registerForHostEvents(this, true, true, true); _agentMgr.registerForHostEvents(this, true, true, true);
@ -327,21 +336,20 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override @Override
public boolean start() { public boolean start() {
_hostScanScheduler.scheduleAtFixedRate(getHostScanTask(), STARTUP_DELAY, _hostScanInterval, TimeUnit.MILLISECONDS); // Do not run empty task _hostScanScheduler.scheduleAtFixedRate(getHostScanTask(), STARTUP_DELAY, _hostScanInterval, TimeUnit.MILLISECONDS);
// but implement it first!
startTemplateCleanJobSchedule();
startupCleanup(_mountParent); startupCleanup(_mountParent);
s_logger.info("start done");
return true; return true;
} }
@Override @Override
public boolean stop() { public boolean stop() {
_hostScanScheduler.shutdownNow(); s_logger.info("shutting down scheduled tasks");
try { templateCleanupScheduler.shutdown();
_hostScanScheduler.awaitTermination(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
s_logger.debug("[ignored] interupted while stopping<:/.");
}
shutdownCleanup(); shutdownCleanup();
return true; return true;
} }
@ -670,19 +678,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return keyFile; return keyFile;
} }
private Runnable getHostScanTask() {
return new Runnable() {
@Override
public void run() {
// TODO scan vSphere for newly added hosts.
// we are going to both support adding host from CloudStack UI and
// adding host via vSphere server
//
// will implement host scanning later
}
};
}
@Override @Override
public String getMountPoint(String storageUrl, Integer nfsVersion) { public String getMountPoint(String storageUrl, Integer nfsVersion) {
String mountPoint = null; String mountPoint = null;
@ -1288,4 +1283,55 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} }
} }
private void startTemplateCleanJobSchedule() {
if(s_logger.isDebugEnabled()) {
s_logger.debug("checking to see if we should schedule a job to search for fully cloned templates to clean-up");
}
if(StorageManager.StorageCleanupEnabled.value() &&
StorageManager.TemplateCleanupEnabled.value() &&
templateCleanupInterval.value() > 0) {
try {
if (s_logger.isInfoEnabled()) {
s_logger.info("scheduling job to search for fully cloned templates to clean-up once per " + templateCleanupInterval.value() + " minutes.");
}
// futureTemplateCleanup =
Runnable task = getCleanupFullyClonedTemplatesTask();
templateCleanupScheduler.scheduleAtFixedRate(task,
templateCleanupInterval.value(),
templateCleanupInterval.value(),
TimeUnit.MINUTES);
if (s_logger.isTraceEnabled()) {
s_logger.trace("scheduled job to search for fully cloned templates to clean-up.");
}
} catch (RejectedExecutionException ree) {
s_logger.error("job to search for fully cloned templates cannot be scheduled");
s_logger.debug("job to search for fully cloned templates cannot be scheduled;", ree);
} catch (NullPointerException npe) {
s_logger.error("job to search for fully cloned templates is invalid");
s_logger.debug("job to search for fully cloned templates is invalid;", npe);
} catch (IllegalArgumentException iae) {
s_logger.error("job to search for fully cloned templates is scheduled at invalid intervals");
s_logger.debug("job to search for fully cloned templates is scheduled at invalid intervals;", iae);
} catch (Exception e) {
s_logger.error("job to search for fully cloned templates failed for unknown reasons");
s_logger.debug("job to search for fully cloned templates failed for unknown reasons;", e);
}
}
}
/**
* This task is to cleanup templates from primary storage that are otherwise not cleaned by the {@link com.cloud.storage.StorageManagerImpl.StorageGarbageCollector}.
* it is called at regular intervals when storage.template.cleanup.enabled == true
* It collect all templates that
* - are deleted from cloudstack
* - when vmware.create.full.clone == true and the entries for VMs having volumes on the primary storage in db table user_vm_clone_setting reads 'full'
*/
private Runnable getCleanupFullyClonedTemplatesTask() {
return new CleanupFullyClonedTemplatesTask(primaryStorageDao,
templateDataStoreDao,
templateDao,
vmInstanceDao,
cloneSettingDao,
templateManager);
}
} }

View File

@ -17,48 +17,8 @@
package com.cloud.hypervisor.vmware; package com.cloud.hypervisor.vmware;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import com.cloud.user.User;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
import org.apache.cloudstack.test.utils.SpringUtils;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
import com.cloud.api.query.dao.TemplateJoinDao;
import com.cloud.cluster.ClusterManager; import com.cloud.cluster.ClusterManager;
import com.cloud.cluster.dao.ManagementServerHostPeerDao; import com.cloud.cluster.dao.ManagementServerHostPeerDao;
import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsDao;
@ -89,15 +49,58 @@ import com.cloud.org.Managed.ManagedState;
import com.cloud.secstorage.CommandExecLogDao; import com.cloud.secstorage.CommandExecLogDao;
import com.cloud.server.ConfigurationServer; import com.cloud.server.ConfigurationServer;
import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.ImageStoreDetailsUtil;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.template.TemplateManager;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.user.AccountService; import com.cloud.user.AccountService;
import com.cloud.user.AccountVO; import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserVO; import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.AccountDao;
import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.dao.UserVmCloneSettingDao;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.test.utils.SpringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import javax.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static org.mockito.Mockito.when;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@ -447,6 +450,36 @@ public class VmwareDatacenterApiUnitTest {
return Mockito.mock(ImageStoreDetailsDao.class); return Mockito.mock(ImageStoreDetailsDao.class);
} }
@Bean
public VMTemplatePoolDao templateDataStoreDao() {
return Mockito.mock(VMTemplatePoolDao.class);
}
@Bean
public TemplateJoinDao templateDao() {
return Mockito.mock(TemplateJoinDao.class);
}
@Bean
public VMInstanceDao vmInstanceDao() {
return Mockito.mock(VMInstanceDao.class);
}
@Bean
public UserVmCloneSettingDao cloneSettingDao() {
return Mockito.mock(UserVmCloneSettingDao.class);
}
@Bean
public PrimaryDataStoreDao primaryStorageDao() {
return Mockito.mock(PrimaryDataStoreDao.class);
}
@Bean
public TemplateManager templateManager() {
return Mockito.mock(TemplateManager.class);
}
public static class Library implements TypeFilter { public static class Library implements TypeFilter {
@Override @Override

View File

@ -182,14 +182,6 @@ public enum Config {
"3600", "3600",
"Timeout (in seconds) to synchronize storage pool operations.", "Timeout (in seconds) to synchronize storage pool operations.",
null), null),
StorageTemplateCleanupEnabled(
"Storage",
ManagementServer.class,
Boolean.class,
"storage.template.cleanup.enabled",
"true",
"Enable/disable template cleanup activity, only take effect when overall storage cleanup is enabled",
null),
PrimaryStorageDownloadWait( PrimaryStorageDownloadWait(
"Storage", "Storage",
TemplateManager.class, TemplateManager.class,

View File

@ -314,7 +314,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
protected SearchBuilder<StoragePoolVO> LocalStorageSearch; protected SearchBuilder<StoragePoolVO> LocalStorageSearch;
ScheduledExecutorService _executor = null; ScheduledExecutorService _executor = null;
boolean _templateCleanupEnabled = true;
int _storagePoolAcquisitionWaitSeconds = 1800; // 30 minutes int _storagePoolAcquisitionWaitSeconds = 1800; // 30 minutes
int _downloadUrlCleanupInterval; int _downloadUrlCleanupInterval;
int _downloadUrlExpirationInterval; int _downloadUrlExpirationInterval;
@ -477,11 +476,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
_agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao, _dataStoreProviderMgr), true, false, true); _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao, _dataStoreProviderMgr), true, false, true);
String value = _configDao.getValue(Config.StorageTemplateCleanupEnabled.key());
_templateCleanupEnabled = (value == null ? true : Boolean.parseBoolean(value));
s_logger.info("Storage cleanup enabled: " + StorageCleanupEnabled.value() + ", interval: " + StorageCleanupInterval.value() + ", delay: " + StorageCleanupDelay.value() + s_logger.info("Storage cleanup enabled: " + StorageCleanupEnabled.value() + ", interval: " + StorageCleanupInterval.value() + ", delay: " + StorageCleanupDelay.value() +
", template cleanup enabled: " + _templateCleanupEnabled); ", template cleanup enabled: " + TemplateCleanupEnabled.value());
String cleanupInterval = configs.get("extract.url.cleanup.interval"); String cleanupInterval = configs.get("extract.url.cleanup.interval");
_downloadUrlCleanupInterval = NumbersUtil.parseInt(cleanupInterval, 7200); _downloadUrlCleanupInterval = NumbersUtil.parseInt(cleanupInterval, 7200);
@ -1065,7 +1061,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
if (scanLock.lock(3)) { if (scanLock.lock(3)) {
try { try {
// Cleanup primary storage pools // Cleanup primary storage pools
if (_templateCleanupEnabled) { if (TemplateCleanupEnabled.value()) {
List<StoragePoolVO> storagePools = _storagePoolDao.listAll(); List<StoragePoolVO> storagePools = _storagePoolDao.listAll();
for (StoragePoolVO pool : storagePools) { for (StoragePoolVO pool : storagePools) {
try { try {
@ -2426,7 +2422,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
@Override @Override
public ConfigKey<?>[] getConfigKeys() { public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {StorageCleanupInterval, StorageCleanupDelay, StorageCleanupEnabled}; return new ConfigKey<?>[] {StorageCleanupInterval, StorageCleanupDelay, StorageCleanupEnabled, TemplateCleanupEnabled};
} }
@Override @Override