<commit_before>/**
 *  Copyright (C) 2010 Cloud.com, Inc.  All rights reserved.
 * 
 * This software is licensed under the GNU General Public License v3 or later.
 * 
 * It is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package com.cloud.storage.download;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;

import javax.ejb.Local;

import org.apache.log4j.Logger;

import com.cloud.agent.AgentManager;
import com.cloud.agent.Listener;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.storage.DeleteTemplateCommand;
import com.cloud.agent.api.storage.DownloadCommand;
import com.cloud.agent.api.storage.DownloadProgressCommand;
import com.cloud.agent.api.storage.ListTemplateAnswer;
import com.cloud.agent.api.storage.ListTemplateCommand;
import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType;
import com.cloud.alert.AlertManager;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventVO;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.StorageUnavailableException;
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.storage.Storage.ImageFormat;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateZoneVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateHostDao;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.storage.template.TemplateConstants;
import com.cloud.storage.template.TemplateInfo;
import com.cloud.user.Account;
import com.cloud.utils.component.Inject;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.SecondaryStorageVm;
import com.cloud.vm.SecondaryStorageVmVO;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.SecondaryStorageVmDao;



/**
 * @author chiradeep
 *
 */
@Local(value={DownloadMonitor.class})
public class DownloadMonitorImpl implements  DownloadMonitor {
    static final Logger s_logger = Logger.getLogger(DownloadMonitorImpl.class);
	
    @Inject 
    VMTemplateHostDao _vmTemplateHostDao;
    @Inject 
    VMTemplateZoneDao _vmTemplateZoneDao;
    @Inject
	VMTemplatePoolDao _vmTemplatePoolDao;
    @Inject
    StoragePoolHostDao _poolHostDao;
    @Inject
    SecondaryStorageVmDao _secStorageVmDao;
    @Inject
    AlertManager _alertMgr;
    
    @Inject
    private final DataCenterDao _dcDao = null;
    @Inject
    VMTemplateDao _templateDao =  null;
    @Inject
	private AgentManager _agentMgr;
    @Inject SecondaryStorageVmManager _secMgr;
    @Inject
    ConfigurationDao _configDao;
    @Inject
    UserVmManager _vmMgr;

    
    @Inject 
    private UsageEventDao _usageEventDao;
    
    @Inject
    private ClusterDao _clusterDao;
    @Inject
    private HostDao _hostDao;

	private String _name;
	private Boolean _sslCopy = new Boolean(false);
	private String _copyAuthPasswd;
    protected SearchBuilder<VMTemplateHostVO> ReadyTemplateStatesSearch;

	Timer _timer;

	final Map<VMTemplateHostVO, DownloadListener> _listenerMap = new ConcurrentHashMap<VMTemplateHostVO, DownloadListener>();


	public long send(Long hostId, Command cmd, Listener listener) {
		return _agentMgr.gatherStats(hostId, cmd, listener);
	}

	@Override
	public boolean configure(String name, Map<String, Object> params) {
		_name = name;
        final Map<String, String> configs = _configDao.getConfiguration("ManagementServer", params);
        _sslCopy = Boolean.parseBoolean(configs.get("secstorage.encrypt.copy"));
        
        String cert = configs.get("secstorage.ssl.cert.domain");
        if (!"realhostip.com".equalsIgnoreCase(cert)) {
        	s_logger.warn("Only realhostip.com ssl cert is supported, ignoring self-signed and other certs");
        }
        
        _copyAuthPasswd = configs.get("secstorage.copy.password");
        
        _agentMgr.registerForHostEvents(new DownloadListener(this), true, false, false);
        
        ReadyTemplateStatesSearch = _vmTemplateHostDao.createSearchBuilder();
        ReadyTemplateStatesSearch.and("download_state", ReadyTemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.EQ);
        ReadyTemplateStatesSearch.and("destroyed", ReadyTemplateStatesSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
        ReadyTemplateStatesSearch.and("host_id", ReadyTemplateStatesSearch.entity().getHostId(), SearchCriteria.Op.EQ);

        SearchBuilder<VMTemplateVO> TemplatesWithNoChecksumSearch = _templateDao.createSearchBuilder();
        TemplatesWithNoChecksumSearch.and("checksum", TemplatesWithNoChecksumSearch.entity().getChecksum(), SearchCriteria.Op.NULL);

        ReadyTemplateStatesSearch.join("vm_template", TemplatesWithNoChecksumSearch, TemplatesWithNoChecksumSearch.entity().getId(),
                ReadyTemplateStatesSearch.entity().getTemplateId(), JoinBuilder.JoinType.INNER);
        TemplatesWithNoChecksumSearch.done();
        ReadyTemplateStatesSearch.done();
               
		return true;
	}

	@Override
	public String getName() {
		return _name;
	}

	@Override
	public boolean start() {
		_timer = new Timer();
		return true;
	}

	@Override
	public boolean stop() {
		return true;
	}
	
	
	public boolean isTemplateUpdateable(Long templateId) {
		List<VMTemplateHostVO> downloadsInProgress =
			_vmTemplateHostDao.listByTemplateStatus(templateId, VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS);
		return (downloadsInProgress.size() == 0);
	}
	
	
	public boolean isTemplateUpdateable(Long templateId, Long datacenterId) {
		List<VMTemplateHostVO> downloadsInProgress =
			_vmTemplateHostDao.listByTemplateStatus(templateId, datacenterId, VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS);
		return (downloadsInProgress.size() == 0);
	}
	
	@Override
    public boolean copyTemplate(VMTemplateVO template, HostVO sourceServer, HostVO destServer) throws StorageUnavailableException{

		boolean downloadJobExists = false;
        VMTemplateHostVO destTmpltHost = null;
        VMTemplateHostVO srcTmpltHost = null;

        srcTmpltHost = _vmTemplateHostDao.findByHostTemplate(sourceServer.getId(), template.getId());
        if (srcTmpltHost == null) {
        	throw new InvalidParameterValueException("Template " + template.getName() + " not associated with " + sourceServer.getName());
        }
        if( !_secMgr.generateSetupCommand(sourceServer.getId()) ){
            return false;
        }       
        String url = generateCopyUrl(sourceServer, srcTmpltHost);
	    if (url == null) {
			s_logger.warn("Unable to start/resume copy of template " + template.getUniqueName() + " to " + destServer.getName() + ", no secondary storage vm in running state in source zone");
			throw new StorageUnavailableException("No secondary VM in running state in zone " + sourceServer.getDataCenterId(), srcTmpltHost.getPoolId());
	    }
        destTmpltHost = _vmTemplateHostDao.findByHostTemplate(destServer.getId(), template.getId());
        if (destTmpltHost == null) {
            destTmpltHost = new VMTemplateHostVO(destServer.getId(), template.getId(), new Date(), 0, VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, "jobid0000", null, url);
            destTmpltHost.setCopy(true);
            destTmpltHost.setPhysicalSize(srcTmpltHost.getPhysicalSize());
            _vmTemplateHostDao.persist(destTmpltHost);
        } else if ((destTmpltHost.getJobId() != null) && (destTmpltHost.getJobId().length() > 2)) {
            downloadJobExists = true;
        }

        Long maxTemplateSizeInBytes = getMaxTemplateSizeInBytes();
        
		if(destTmpltHost != null) {
		    start();
		    
			DownloadCommand dcmd =  
              new DownloadCommand(destServer.getStorageUrl(), url, template, TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd, maxTemplateSizeInBytes);
			if (downloadJobExists) {
				dcmd = new DownloadProgressCommand(dcmd, destTmpltHost.getJobId(), RequestType.GET_OR_RESTART);
	 		} 
            HostVO ssAhost = _agentMgr.getSSAgent(destServer);
            if( ssAhost == null ) {
                 s_logger.warn("There is no secondary storage VM for secondary storage host " + destServer.getName());
                 return false;
            }
            DownloadListener dl = new DownloadListener(ssAhost, destServer, template, _timer, _vmTemplateHostDao, destTmpltHost.getId(), this, dcmd);
            if (downloadJobExists) {
                dl.setCurrState(destTmpltHost.getDownloadState());
            }
			DownloadListener old = null;
			synchronized (_listenerMap) {
			    old = _listenerMap.put(destTmpltHost, dl);
			}
			if( old != null ) {
			    old.abandon();
			}
			
	        long result = send(ssAhost.getId(), dcmd, dl);
			if (result == -1) {
				s_logger.warn("Unable to start /resume COPY of template " + template.getUniqueName() + " to " + destServer.getName());
				dl.setDisconnected();
				dl.scheduleStatusCheck(RequestType.GET_OR_RESTART);
			} else {
			    return true;
			}
		}
		return false;
	}
	
	private String generateCopyUrl(String ipAddress, String dir, String path){
		String hostname = ipAddress;
		String scheme = "http";
		if (_sslCopy) {
			hostname = ipAddress.replace(".", "-");
			hostname = hostname + ".realhostip.com";
			scheme = "https";
		}
		return scheme + "://" + hostname + "/copy/SecStorage/" + dir + "/" + path; 
	}
	
	private String generateCopyUrl(HostVO sourceServer, VMTemplateHostVO srcTmpltHost) {
		List<SecondaryStorageVmVO> ssVms = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, sourceServer.getDataCenterId(), State.Running);
		if (ssVms.size() > 0) {
			SecondaryStorageVmVO ssVm = ssVms.get(0);
			if (ssVm.getPublicIpAddress() == null) {
				s_logger.warn("A running secondary storage vm has a null public ip?");
				return null;
			}
			return generateCopyUrl(ssVm.getPublicIpAddress(), sourceServer.getParent(), srcTmpltHost.getInstallPath());
		}
		
		VMTemplateVO tmplt = _templateDao.findById(srcTmpltHost.getTemplateId());
		HypervisorType hyperType = tmplt.getHypervisorType();
		/*No secondary storage vm yet*/
		if (hyperType != null && hyperType == HypervisorType.KVM) {
			return "file://" + sourceServer.getParent() + "/" + srcTmpltHost.getInstallPath();
		}
		return null;
	}

	private void downloadTemplateToStorage(VMTemplateVO template, HostVO sserver) {
		boolean downloadJobExists = false;
        VMTemplateHostVO vmTemplateHost = null;

        vmTemplateHost = _vmTemplateHostDao.findByHostTemplate(sserver.getId(), template.getId());
        if (vmTemplateHost == null) {
            vmTemplateHost = new VMTemplateHostVO(sserver.getId(), template.getId(), new Date(), 0, VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, "jobid0000", null, template.getUrl());
            _vmTemplateHostDao.persist(vmTemplateHost);
        } else if ((vmTemplateHost.getJobId() != null) && (vmTemplateHost.getJobId().length() > 2)) {
            downloadJobExists = true;
        }
                
        Long maxTemplateSizeInBytes = getMaxTemplateSizeInBytes();
        String secUrl = sserver.getStorageUrl();
		if(vmTemplateHost != null) {
		    start();
			DownloadCommand dcmd =
             new DownloadCommand(secUrl, template, maxTemplateSizeInBytes);
	        if (downloadJobExists) {
	            dcmd = new DownloadProgressCommand(dcmd, vmTemplateHost.getJobId(), RequestType.GET_OR_RESTART);
	        }
			if (vmTemplateHost.isCopy()) {
				dcmd.setCreds(TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd);
			}
			HostVO ssAhost = _agentMgr.getSSAgent(sserver);
			if( ssAhost == null ) {
	             s_logger.warn("There is no secondary storage VM for secondary storage host " + sserver.getName());
	             return;
			}
			DownloadListener dl = new DownloadListener(ssAhost, sserver, template, _timer, _vmTemplateHostDao, vmTemplateHost.getId(), this, dcmd);
			if (downloadJobExists) {
				dl.setCurrState(vmTemplateHost.getDownloadState());
	 		}
            DownloadListener old = null;
            synchronized (_listenerMap) {
                old = _listenerMap.put(vmTemplateHost, dl);
            }
            if( old != null ) {
                old.abandon();
            }

			long result = send(ssAhost.getId(), dcmd, dl);
			if (result == -1) {
				s_logger.warn("Unable to start /resume download of template " + template.getUniqueName() + " to " + sserver.getName());
				dl.setDisconnected();
				dl.scheduleStatusCheck(RequestType.GET_OR_RESTART);
			}
		}
	}



	@Override
	public boolean downloadTemplateToStorage(Long templateId, Long zoneId) {
        List<DataCenterVO> dcs = new ArrayList<DataCenterVO>();       
        if (zoneId == null) {
            dcs.addAll(_dcDao.listAll());
        } else {
            dcs.add(_dcDao.findById(zoneId));
        }
        for ( DataCenterVO dc : dcs ) {
    	    List<HostVO> ssHosts = _hostDao.listAllSecondaryStorageHosts(dc.getId());
    	    for ( HostVO ssHost : ssHosts ) {
        		if (isTemplateUpdateable(ssHost.getId(), templateId)) {
         
       				initiateTemplateDownload(templateId, ssHost);
        		}
    	    }
	    }
	    return true;
	}

	private void initiateTemplateDownload(Long templateId, HostVO ssHost) {
		VMTemplateVO template = _templateDao.findById(templateId);
		if (template != null && (template.getUrl() != null)) {
			//find all storage hosts and tell them to initiate download
    		downloadTemplateToStorage(template, ssHost);
		}
		
	}

	public void handleDownloadEvent(HostVO host, VMTemplateVO template, Status dnldStatus) {
		if ((dnldStatus == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) || (dnldStatus==Status.ABANDONED)){
			VMTemplateHostVO vmTemplateHost = new VMTemplateHostVO(host.getId(), template.getId());
	        synchronized (_listenerMap) {
	            _listenerMap.remove(vmTemplateHost);
	        }
		}
		
		VMTemplateHostVO vmTemplateHost = _vmTemplateHostDao.findByHostTemplate(host.getId(), template.getId());
		
        if (dnldStatus == Status.DOWNLOADED) {
            long size = -1;
            if(vmTemplateHost!=null){
            	size = vmTemplateHost.getPhysicalSize();
            }
            else{
            	s_logger.warn("Failed to get size for template" + template.getName());
            }
			String eventType = EventTypes.EVENT_TEMPLATE_CREATE;
            if((template.getFormat()).equals(ImageFormat.ISO)){
                eventType = EventTypes.EVENT_ISO_CREATE;
            }
            if(template.getAccountId() != Account.ACCOUNT_ID_SYSTEM){
                UsageEventVO usageEvent = new UsageEventVO(eventType, template.getAccountId(), host.getDataCenterId(), template.getId(), template.getName(), null, template.getSourceTemplateId() , size);
                _usageEventDao.persist(usageEvent);
            }
        } 
        
		if (vmTemplateHost != null) {
			Long poolId = vmTemplateHost.getPoolId();
			if (poolId != null) {
				VMTemplateStoragePoolVO vmTemplatePool = _vmTemplatePoolDao.findByPoolTemplate(poolId, template.getId());
				StoragePoolHostVO poolHost = _poolHostDao.findByPoolHost(poolId, host.getId());
				if (vmTemplatePool != null && poolHost != null) {
					vmTemplatePool.setDownloadPercent(vmTemplateHost.getDownloadPercent());
					vmTemplatePool.setDownloadState(vmTemplateHost.getDownloadState());
					vmTemplatePool.setErrorString(vmTemplateHost.getErrorString());
					String localPath = poolHost.getLocalPath();
					String installPath = vmTemplateHost.getInstallPath();
					if (installPath != null) {
						if (!installPath.startsWith("/")) {
							installPath = "/" + installPath;
						}
						if (!(localPath == null) && !installPath.startsWith(localPath)) {
							localPath = localPath.replaceAll("/\\p{Alnum}+/*$", ""); //remove instance if necessary
						}
						if (!(localPath == null) && installPath.startsWith(localPath)) {
							installPath = installPath.substring(localPath.length());
						}
					}
					vmTemplatePool.setInstallPath(installPath);
					vmTemplatePool.setLastUpdated(vmTemplateHost.getLastUpdated());
					vmTemplatePool.setJobId(vmTemplateHost.getJobId());
					vmTemplatePool.setLocalDownloadPath(vmTemplateHost.getLocalDownloadPath());
					_vmTemplatePoolDao.update(vmTemplatePool.getId(),vmTemplatePool);
				}
			}
		}

	}
	
	@Override
    public void handleSysTemplateDownload(HostVO host) {
	    List<HypervisorType> hypers = _hostDao.getAvailHypervisorInZone(host.getId(), host.getDataCenterId());
	    HypervisorType hostHyper = host.getHypervisorType();
	    if (hypers.contains(hostHyper)) {
	        return;
	    }

	    Set<VMTemplateVO> toBeDownloaded = new HashSet<VMTemplateVO>();
	    List<HostVO> ssHosts = _hostDao.listBy(Host.Type.SecondaryStorage, host.getDataCenterId());
	    if (ssHosts == null || ssHosts.isEmpty()) {
	        return;
	    }
	    /*Download all the templates in zone with the same hypervisortype*/
        for ( HostVO ssHost : ssHosts) {
    	    List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
    	    List<VMTemplateVO> defaultBuiltin = _templateDao.listDefaultBuiltinTemplates();
    
    
    	    for (VMTemplateVO rtngTmplt : rtngTmplts) {
    	        if (rtngTmplt.getHypervisorType() == hostHyper) {
    	            toBeDownloaded.add(rtngTmplt);
    	        }
    	    }
    
    	    for (VMTemplateVO builtinTmplt : defaultBuiltin) {
    	        if (builtinTmplt.getHypervisorType() == hostHyper) {
    	            toBeDownloaded.add(builtinTmplt);
    	        }
    	    }
    
    	    for (VMTemplateVO template: toBeDownloaded) {
    	        VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(ssHost.getId(), template.getId());
    	        if (tmpltHost == null || tmpltHost.getDownloadState() != Status.DOWNLOADED) {
    	            downloadTemplateToStorage(template, ssHost);
    	        }
    	    }
        }
	}
    
    @Override	
	public void addSystemVMTemplatesToHost(HostVO host, Map<String, TemplateInfo> templateInfos){
	    if ( templateInfos == null ) {
	        return;
	    }
	    Long hostId = host.getId();
	    List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
	    for ( VMTemplateVO tmplt : rtngTmplts ) {
	        TemplateInfo tmpltInfo = templateInfos.get(tmplt.getUniqueName());
	        if ( tmpltInfo == null ) {
	            continue;
	        }
	        VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(hostId, tmplt.getId());
	        if ( tmpltHost == null ) {
                tmpltHost = new VMTemplateHostVO(hostId, tmplt.getId(), new Date(), 100, Status.DOWNLOADED, null, null, null, tmpltInfo.getInstallPath(), tmplt.getUrl());
	            tmpltHost.setSize(tmpltInfo.getSize());
	            tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
	            _vmTemplateHostDao.persist(tmpltHost);
	        }
	    }
	}
	
    @Override
    public void handleTemplateSync(long dcId) {
        List<HostVO> ssHosts = _hostDao.listSecondaryStorageHosts(dcId);
        for ( HostVO ssHost : ssHosts ) {
            handleTemplateSync(ssHost);
        }
    }
    
    private Map<String, TemplateInfo> listTemplate(HostVO ssHost) {
        ListTemplateCommand cmd = new ListTemplateCommand(ssHost.getStorageUrl());
        Answer answer = _agentMgr.sendToSecStorage(ssHost, cmd);
        if (answer != null && answer.getResult()) {
            ListTemplateAnswer tanswer = (ListTemplateAnswer)answer;
            return tanswer.getTemplateInfo();
        } else {
            if (s_logger.isDebugEnabled()) {
                s_logger.debug("can not list template for secondary storage host " + ssHost.getId());
            }
        } 
        
        return null;
    }
    
    private List<VMTemplateVO> listAllInZone(long dcId){
        List<VMTemplateVO> tmplts = _templateDao.listAllInZone(dcId);
        Iterator<VMTemplateVO> iter = tmplts.iterator();
        while ( iter.hasNext() ) {
            VMTemplateVO tmplt = iter.next();
            if( tmplt.isPublicTemplate() || tmplt.isFeatured() ) {
                continue;
            }
            List<VMTemplateHostVO> tmpltHosts = _vmTemplateHostDao.listByZoneTemplate(dcId, tmplt.getId(), false);
            for ( VMTemplateHostVO tmpltHost : tmpltHosts ) {
               if ( tmpltHost.getDownloadState() == Status.DOWNLOADED || tmpltHost.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) {
                   iter.remove();
                   break;
               }
            }
        }
        return tmplts;       
    }
	
	@Override
	public void handleTemplateSync(HostVO ssHost) {
	    Long sserverId = ssHost.getId();
		if (ssHost == null) {
			s_logger.warn("Huh? Agent id " + sserverId + " does not correspond to a row in hosts table?");
			return;
		}
		if ( !(ssHost.getType() == Host.Type.SecondaryStorage || ssHost.getType() == Host.Type.LocalSecondaryStorage) ) {
	        s_logger.warn("Huh? Agent id " + sserverId + " is not secondary storage host");
		    return;
		}
		Map<String, TemplateInfo> templateInfos = listTemplate(ssHost);
		if( templateInfos == null ) {
		    return;
		}
		long zoneId = ssHost.getDataCenterId();

		Set<VMTemplateVO> toBeDownloaded = new HashSet<VMTemplateVO>();
		List<VMTemplateVO> allTemplates = listAllInZone(ssHost.getDataCenterId());
		List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
		List<VMTemplateVO> defaultBuiltin = _templateDao.listDefaultBuiltinTemplates();
		
		if (rtngTmplts != null) {
		    for (VMTemplateVO rtngTmplt : rtngTmplts) {
		        if (!allTemplates.contains(rtngTmplt)) {
		            allTemplates.add(rtngTmplt);
		        }
		    }
		}

		if (defaultBuiltin != null) {
		    for (VMTemplateVO builtinTmplt : defaultBuiltin) {
		        if (!allTemplates.contains(builtinTmplt)) {
		            allTemplates.add(builtinTmplt);
		        }
		    }
		}

        toBeDownloaded.addAll(allTemplates);
        
		for (VMTemplateVO tmplt: allTemplates) {
			String uniqueName = tmplt.getUniqueName();
			VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(sserverId, tmplt.getId());
			if (templateInfos.containsKey(uniqueName)) {
			    TemplateInfo tmpltInfo = templateInfos.remove(uniqueName);
				toBeDownloaded.remove(tmplt);
				if (tmpltHost != null) {
					s_logger.info("Template Sync found " + uniqueName + " already in the template host table");
                    if (tmpltHost.getDownloadState() != Status.DOWNLOADED) {
                    	tmpltHost.setErrorString("");
                    }
                    if( tmpltInfo.isCorrupted() ) {
                        tmpltHost.setDownloadState(Status.DOWNLOAD_ERROR);
                        tmpltHost.setErrorString("This template is corrupted");
                        toBeDownloaded.add(tmplt);
                        s_logger.info("Template (" + tmplt +") is corrupted");
                        if( tmplt.getUrl() == null) {
                            String msg = "Private Template (" + tmplt +") with install path "  + tmpltInfo.getInstallPath() + 
                            "is corrupted, please check in secondary storage: " + tmpltHost.getHostId();
                            s_logger.warn(msg);
                        } else {
                            toBeDownloaded.add(tmplt);
                        }

                    } else {
                        tmpltHost.setDownloadPercent(100);
                        tmpltHost.setDownloadState(Status.DOWNLOADED);
                        tmpltHost.setInstallPath(tmpltInfo.getInstallPath());
                        tmpltHost.setSize(tmpltInfo.getSize());
                        tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
                        tmpltHost.setLastUpdated(new Date());
                    }
					_vmTemplateHostDao.update(tmpltHost.getId(), tmpltHost);
				} else {
				    tmpltHost = new VMTemplateHostVO(sserverId, tmplt.getId(), new Date(), 100, Status.DOWNLOADED, null, null, null, tmpltInfo.getInstallPath(), tmplt.getUrl());
					tmpltHost.setSize(tmpltInfo.getSize());
                    tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
					_vmTemplateHostDao.persist(tmpltHost);
					VMTemplateZoneVO tmpltZoneVO = _vmTemplateZoneDao.findByZoneTemplate(zoneId, tmplt.getId());
					if (tmpltZoneVO == null){
					    tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date());
					    _vmTemplateZoneDao.persist(tmpltZoneVO);
					} else {
					    tmpltZoneVO.setLastUpdated(new Date());
					    _vmTemplateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO);
					}

				}

				continue;
			}
			if (tmpltHost != null && tmpltHost.getDownloadState() != Status.DOWNLOADED) {
				s_logger.info("Template Sync did not find " + uniqueName + " ready on server " + sserverId + ", will request download to start/resume shortly");

			} else if (tmpltHost == null) {
				s_logger.info("Template Sync did not find " + uniqueName + " on the server " + sserverId + ", will request download shortly");
				VMTemplateHostVO templtHost = new VMTemplateHostVO(sserverId, tmplt.getId(), new Date(), 0, Status.NOT_DOWNLOADED, null, null, null, null, tmplt.getUrl());
				_vmTemplateHostDao.persist(templtHost);
				VMTemplateZoneVO tmpltZoneVO = _vmTemplateZoneDao.findByZoneTemplate(zoneId, tmplt.getId());
				if (tmpltZoneVO == null){
				    tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date());
				    _vmTemplateZoneDao.persist(tmpltZoneVO);
				} else {
				    tmpltZoneVO.setLastUpdated(new Date());
				    _vmTemplateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO);
				}
			}

		}
		
		if (toBeDownloaded.size() > 0) {
			/*Only download templates whose hypervirsor type is in the zone*/
			List<HypervisorType> availHypers = _clusterDao.getAvailableHypervisorInZone(ssHost.getDataCenterId());
			if (availHypers.isEmpty()) {
			    /*This is for cloudzone, local secondary storage resource started before cluster created*/
			    availHypers.add(HypervisorType.KVM);
			}
			/* Baremetal need not to download any template */
			availHypers.remove(HypervisorType.BareMetal);
			availHypers.add(HypervisorType.None); //bug 9809: resume ISO download.
			for (VMTemplateVO tmplt: toBeDownloaded) {
				
				if (tmplt.getUrl() == null){ // If url is null we cant initiate the download so mark it as an error.
					VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(ssHost.getId(), tmplt.getId());
					if(tmpltHost != null){
						tmpltHost.setDownloadState(Status.DOWNLOAD_ERROR);
						tmpltHost.setDownloadPercent(0);
						tmpltHost.setErrorString("Cannot initiate the download as url is null.");
						_vmTemplateHostDao.update(tmpltHost.getId(), tmpltHost);
					}
					continue;
				}
				
			    if (availHypers.contains(tmplt.getHypervisorType())) {
			        s_logger.debug("Template " + tmplt.getName() + " needs to be downloaded to " + ssHost.getName());
			        downloadTemplateToStorage(tmplt, ssHost);
			    }
			}
		}
		
		for (String uniqueName: templateInfos.keySet()) {
			TemplateInfo tInfo = templateInfos.get(uniqueName);
			DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(ssHost.getStorageUrl(), tInfo.getInstallPath());
			long result = _agentMgr.sendToSecStorage(ssHost, dtCommand, null);
			if (result == -1 ){
				String description = "Failed to delete " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " which isn't in the database";
				s_logger.error(description);
				return;
			}
			String description = "Deleted template " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " since it isn't in the database, result=" + result;
			s_logger.info(description);
		}
		
		//This code is mostly for migration purposes so that we have checksum for all the templates
		if (ssHost.getType() == Host.Type.SecondaryStorage)
		    checksumSync(sserverId);
		

	}<commit_msg>bug 10511:<commit_after>/**
 *  Copyright (C) 2010 Cloud.com, Inc.  All rights reserved.
 * 
 * This software is licensed under the GNU General Public License v3 or later.
 * 
 * It is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package com.cloud.storage.download;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;

import javax.ejb.Local;

import org.apache.log4j.Logger;

import com.cloud.agent.AgentManager;
import com.cloud.agent.Listener;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.storage.DeleteTemplateCommand;
import com.cloud.agent.api.storage.DownloadCommand;
import com.cloud.agent.api.storage.DownloadProgressCommand;
import com.cloud.agent.api.storage.ListTemplateAnswer;
import com.cloud.agent.api.storage.ListTemplateCommand;
import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType;
import com.cloud.alert.AlertManager;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventVO;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.StorageUnavailableException;
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.storage.Storage.ImageFormat;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateZoneVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateHostDao;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.storage.template.TemplateConstants;
import com.cloud.storage.template.TemplateInfo;
import com.cloud.user.Account;
import com.cloud.utils.component.Inject;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.SecondaryStorageVm;
import com.cloud.vm.SecondaryStorageVmVO;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.SecondaryStorageVmDao;



/**
 * @author chiradeep
 *
 */
@Local(value={DownloadMonitor.class})
public class DownloadMonitorImpl implements  DownloadMonitor {
    static final Logger s_logger = Logger.getLogger(DownloadMonitorImpl.class);
	
    @Inject 
    VMTemplateHostDao _vmTemplateHostDao;
    @Inject 
    VMTemplateZoneDao _vmTemplateZoneDao;
    @Inject
	VMTemplatePoolDao _vmTemplatePoolDao;
    @Inject
    StoragePoolHostDao _poolHostDao;
    @Inject
    SecondaryStorageVmDao _secStorageVmDao;
    @Inject
    AlertManager _alertMgr;
    
    @Inject
    private final DataCenterDao _dcDao = null;
    @Inject
    VMTemplateDao _templateDao =  null;
    @Inject
	private AgentManager _agentMgr;
    @Inject SecondaryStorageVmManager _secMgr;
    @Inject
    ConfigurationDao _configDao;
    @Inject
    UserVmManager _vmMgr;

    
    @Inject 
    private UsageEventDao _usageEventDao;
    
    @Inject
    private ClusterDao _clusterDao;
    @Inject
    private HostDao _hostDao;

	private String _name;
	private Boolean _sslCopy = new Boolean(false);
	private String _copyAuthPasswd;
    protected SearchBuilder<VMTemplateHostVO> ReadyTemplateStatesSearch;

	Timer _timer;

	final Map<VMTemplateHostVO, DownloadListener> _listenerMap = new ConcurrentHashMap<VMTemplateHostVO, DownloadListener>();


	public long send(Long hostId, Command cmd, Listener listener) {
		return _agentMgr.gatherStats(hostId, cmd, listener);
	}

	@Override
	public boolean configure(String name, Map<String, Object> params) {
		_name = name;
        final Map<String, String> configs = _configDao.getConfiguration("ManagementServer", params);
        _sslCopy = Boolean.parseBoolean(configs.get("secstorage.encrypt.copy"));
        
        String cert = configs.get("secstorage.ssl.cert.domain");
        if (!"realhostip.com".equalsIgnoreCase(cert)) {
        	s_logger.warn("Only realhostip.com ssl cert is supported, ignoring self-signed and other certs");
        }
        
        _copyAuthPasswd = configs.get("secstorage.copy.password");
        
        _agentMgr.registerForHostEvents(new DownloadListener(this), true, false, false);
        
        ReadyTemplateStatesSearch = _vmTemplateHostDao.createSearchBuilder();
        ReadyTemplateStatesSearch.and("download_state", ReadyTemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.EQ);
        ReadyTemplateStatesSearch.and("destroyed", ReadyTemplateStatesSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
        ReadyTemplateStatesSearch.and("host_id", ReadyTemplateStatesSearch.entity().getHostId(), SearchCriteria.Op.EQ);

        SearchBuilder<VMTemplateVO> TemplatesWithNoChecksumSearch = _templateDao.createSearchBuilder();
        TemplatesWithNoChecksumSearch.and("checksum", TemplatesWithNoChecksumSearch.entity().getChecksum(), SearchCriteria.Op.NULL);

        ReadyTemplateStatesSearch.join("vm_template", TemplatesWithNoChecksumSearch, TemplatesWithNoChecksumSearch.entity().getId(),
                ReadyTemplateStatesSearch.entity().getTemplateId(), JoinBuilder.JoinType.INNER);
        TemplatesWithNoChecksumSearch.done();
        ReadyTemplateStatesSearch.done();
               
		return true;
	}

	@Override
	public String getName() {
		return _name;
	}

	@Override
	public boolean start() {
		_timer = new Timer();
		return true;
	}

	@Override
	public boolean stop() {
		return true;
	}
	
	
	public boolean isTemplateUpdateable(Long templateId) {
		List<VMTemplateHostVO> downloadsInProgress =
			_vmTemplateHostDao.listByTemplateStatus(templateId, VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS);
		return (downloadsInProgress.size() == 0);
	}
	
	
	public boolean isTemplateUpdateable(Long templateId, Long datacenterId) {
		List<VMTemplateHostVO> downloadsInProgress =
			_vmTemplateHostDao.listByTemplateStatus(templateId, datacenterId, VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS);
		return (downloadsInProgress.size() == 0);
	}
	
	@Override
    public boolean copyTemplate(VMTemplateVO template, HostVO sourceServer, HostVO destServer) throws StorageUnavailableException{

		boolean downloadJobExists = false;
        VMTemplateHostVO destTmpltHost = null;
        VMTemplateHostVO srcTmpltHost = null;

        srcTmpltHost = _vmTemplateHostDao.findByHostTemplate(sourceServer.getId(), template.getId());
        if (srcTmpltHost == null) {
        	throw new InvalidParameterValueException("Template " + template.getName() + " not associated with " + sourceServer.getName());
        }
        if( !_secMgr.generateSetupCommand(sourceServer.getId()) ){
            return false;
        }       
        String url = generateCopyUrl(sourceServer, srcTmpltHost);
	    if (url == null) {
			s_logger.warn("Unable to start/resume copy of template " + template.getUniqueName() + " to " + destServer.getName() + ", no secondary storage vm in running state in source zone");
			throw new StorageUnavailableException("No secondary VM in running state in zone " + sourceServer.getDataCenterId(), srcTmpltHost.getPoolId());
	    }
        destTmpltHost = _vmTemplateHostDao.findByHostTemplate(destServer.getId(), template.getId());
        if (destTmpltHost == null) {
            destTmpltHost = new VMTemplateHostVO(destServer.getId(), template.getId(), new Date(), 0, VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, "jobid0000", null, url);
            destTmpltHost.setCopy(true);
            destTmpltHost.setPhysicalSize(srcTmpltHost.getPhysicalSize());
            _vmTemplateHostDao.persist(destTmpltHost);
        } else if ((destTmpltHost.getJobId() != null) && (destTmpltHost.getJobId().length() > 2)) {
            downloadJobExists = true;
        }

        Long maxTemplateSizeInBytes = getMaxTemplateSizeInBytes();
        
		if(destTmpltHost != null) {
		    start();
		    
			DownloadCommand dcmd =  
              new DownloadCommand(destServer.getStorageUrl(), url, template, TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd, maxTemplateSizeInBytes);
			if (downloadJobExists) {
				dcmd = new DownloadProgressCommand(dcmd, destTmpltHost.getJobId(), RequestType.GET_OR_RESTART);
	 		} 
            HostVO ssAhost = _agentMgr.getSSAgent(destServer);
            if( ssAhost == null ) {
                 s_logger.warn("There is no secondary storage VM for secondary storage host " + destServer.getName());
                 return false;
            }
            DownloadListener dl = new DownloadListener(ssAhost, destServer, template, _timer, _vmTemplateHostDao, destTmpltHost.getId(), this, dcmd);
            if (downloadJobExists) {
                dl.setCurrState(destTmpltHost.getDownloadState());
            }
			DownloadListener old = null;
			synchronized (_listenerMap) {
			    old = _listenerMap.put(destTmpltHost, dl);
			}
			if( old != null ) {
			    old.abandon();
			}
			
	        long result = send(ssAhost.getId(), dcmd, dl);
			if (result == -1) {
				s_logger.warn("Unable to start /resume COPY of template " + template.getUniqueName() + " to " + destServer.getName());
				dl.setDisconnected();
				dl.scheduleStatusCheck(RequestType.GET_OR_RESTART);
			} else {
			    return true;
			}
		}
		return false;
	}
	
	private String generateCopyUrl(String ipAddress, String dir, String path){
		String hostname = ipAddress;
		String scheme = "http";
		if (_sslCopy) {
			hostname = ipAddress.replace(".", "-");
			hostname = hostname + ".realhostip.com";
			scheme = "https";
		}
		return scheme + "://" + hostname + "/copy/SecStorage/" + dir + "/" + path; 
	}
	
	private String generateCopyUrl(HostVO sourceServer, VMTemplateHostVO srcTmpltHost) {
		List<SecondaryStorageVmVO> ssVms = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, sourceServer.getDataCenterId(), State.Running);
		if (ssVms.size() > 0) {
			SecondaryStorageVmVO ssVm = ssVms.get(0);
			if (ssVm.getPublicIpAddress() == null) {
				s_logger.warn("A running secondary storage vm has a null public ip?");
				return null;
			}
			return generateCopyUrl(ssVm.getPublicIpAddress(), sourceServer.getParent(), srcTmpltHost.getInstallPath());
		}
		
		VMTemplateVO tmplt = _templateDao.findById(srcTmpltHost.getTemplateId());
		HypervisorType hyperType = tmplt.getHypervisorType();
		/*No secondary storage vm yet*/
		if (hyperType != null && hyperType == HypervisorType.KVM) {
			return "file://" + sourceServer.getParent() + "/" + srcTmpltHost.getInstallPath();
		}
		return null;
	}

	private void downloadTemplateToStorage(VMTemplateVO template, HostVO sserver) {
		boolean downloadJobExists = false;
        VMTemplateHostVO vmTemplateHost = null;

        vmTemplateHost = _vmTemplateHostDao.findByHostTemplate(sserver.getId(), template.getId());
        if (vmTemplateHost == null) {
            vmTemplateHost = new VMTemplateHostVO(sserver.getId(), template.getId(), new Date(), 0, VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, "jobid0000", null, template.getUrl());
            _vmTemplateHostDao.persist(vmTemplateHost);
        } else if ((vmTemplateHost.getJobId() != null) && (vmTemplateHost.getJobId().length() > 2)) {
            downloadJobExists = true;
        }
                
        Long maxTemplateSizeInBytes = getMaxTemplateSizeInBytes();
        String secUrl = sserver.getStorageUrl();
		if(vmTemplateHost != null) {
		    start();
			DownloadCommand dcmd =
             new DownloadCommand(secUrl, template, maxTemplateSizeInBytes);
	        if (downloadJobExists) {
	            dcmd = new DownloadProgressCommand(dcmd, vmTemplateHost.getJobId(), RequestType.GET_OR_RESTART);
	        }
			if (vmTemplateHost.isCopy()) {
				dcmd.setCreds(TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd);
			}
			HostVO ssAhost = _agentMgr.getSSAgent(sserver);
			if( ssAhost == null ) {
	             s_logger.warn("There is no secondary storage VM for secondary storage host " + sserver.getName());
	             return;
			}
			DownloadListener dl = new DownloadListener(ssAhost, sserver, template, _timer, _vmTemplateHostDao, vmTemplateHost.getId(), this, dcmd);
			if (downloadJobExists) {
				dl.setCurrState(vmTemplateHost.getDownloadState());
	 		}
            DownloadListener old = null;
            synchronized (_listenerMap) {
                old = _listenerMap.put(vmTemplateHost, dl);
            }
            if( old != null ) {
                old.abandon();
            }

			long result = send(ssAhost.getId(), dcmd, dl);
			if (result == -1) {
				s_logger.warn("Unable to start /resume download of template " + template.getUniqueName() + " to " + sserver.getName());
				dl.setDisconnected();
				dl.scheduleStatusCheck(RequestType.GET_OR_RESTART);
			}
		}
	}



	@Override
	public boolean downloadTemplateToStorage(Long templateId, Long zoneId) {
        List<DataCenterVO> dcs = new ArrayList<DataCenterVO>();       
        if (zoneId == null) {
            dcs.addAll(_dcDao.listAll());
        } else {
            dcs.add(_dcDao.findById(zoneId));
        }
        for ( DataCenterVO dc : dcs ) {
    	    List<HostVO> ssHosts = _hostDao.listAllSecondaryStorageHosts(dc.getId());
    	    for ( HostVO ssHost : ssHosts ) {
        		if (isTemplateUpdateable(ssHost.getId(), templateId)) {
         
       				initiateTemplateDownload(templateId, ssHost);
        		}
    	    }
	    }
	    return true;
	}

	private void initiateTemplateDownload(Long templateId, HostVO ssHost) {
		VMTemplateVO template = _templateDao.findById(templateId);
		if (template != null && (template.getUrl() != null)) {
			//find all storage hosts and tell them to initiate download
    		downloadTemplateToStorage(template, ssHost);
		}
		
	}

	public void handleDownloadEvent(HostVO host, VMTemplateVO template, Status dnldStatus) {
		if ((dnldStatus == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) || (dnldStatus==Status.ABANDONED)){
			VMTemplateHostVO vmTemplateHost = new VMTemplateHostVO(host.getId(), template.getId());
	        synchronized (_listenerMap) {
	            _listenerMap.remove(vmTemplateHost);
	        }
		}
		
		VMTemplateHostVO vmTemplateHost = _vmTemplateHostDao.findByHostTemplate(host.getId(), template.getId());
		
        if (dnldStatus == Status.DOWNLOADED) {
            long size = -1;
            if(vmTemplateHost!=null){
            	size = vmTemplateHost.getPhysicalSize();
            }
            else{
            	s_logger.warn("Failed to get size for template" + template.getName());
            }
			String eventType = EventTypes.EVENT_TEMPLATE_CREATE;
            if((template.getFormat()).equals(ImageFormat.ISO)){
                eventType = EventTypes.EVENT_ISO_CREATE;
            }
            if(template.getAccountId() != Account.ACCOUNT_ID_SYSTEM){
                UsageEventVO usageEvent = new UsageEventVO(eventType, template.getAccountId(), host.getDataCenterId(), template.getId(), template.getName(), null, template.getSourceTemplateId() , size);
                _usageEventDao.persist(usageEvent);
            }
        } 
        
		if (vmTemplateHost != null) {
			Long poolId = vmTemplateHost.getPoolId();
			if (poolId != null) {
				VMTemplateStoragePoolVO vmTemplatePool = _vmTemplatePoolDao.findByPoolTemplate(poolId, template.getId());
				StoragePoolHostVO poolHost = _poolHostDao.findByPoolHost(poolId, host.getId());
				if (vmTemplatePool != null && poolHost != null) {
					vmTemplatePool.setDownloadPercent(vmTemplateHost.getDownloadPercent());
					vmTemplatePool.setDownloadState(vmTemplateHost.getDownloadState());
					vmTemplatePool.setErrorString(vmTemplateHost.getErrorString());
					String localPath = poolHost.getLocalPath();
					String installPath = vmTemplateHost.getInstallPath();
					if (installPath != null) {
						if (!installPath.startsWith("/")) {
							installPath = "/" + installPath;
						}
						if (!(localPath == null) && !installPath.startsWith(localPath)) {
							localPath = localPath.replaceAll("/\\p{Alnum}+/*$", ""); //remove instance if necessary
						}
						if (!(localPath == null) && installPath.startsWith(localPath)) {
							installPath = installPath.substring(localPath.length());
						}
					}
					vmTemplatePool.setInstallPath(installPath);
					vmTemplatePool.setLastUpdated(vmTemplateHost.getLastUpdated());
					vmTemplatePool.setJobId(vmTemplateHost.getJobId());
					vmTemplatePool.setLocalDownloadPath(vmTemplateHost.getLocalDownloadPath());
					_vmTemplatePoolDao.update(vmTemplatePool.getId(),vmTemplatePool);
				}
			}
		}

	}
	
	@Override
    public void handleSysTemplateDownload(HostVO host) {
	    List<HypervisorType> hypers = _hostDao.getAvailHypervisorInZone(host.getId(), host.getDataCenterId());
	    HypervisorType hostHyper = host.getHypervisorType();
	    if (hypers.contains(hostHyper)) {
	        return;
	    }

	    Set<VMTemplateVO> toBeDownloaded = new HashSet<VMTemplateVO>();
	    List<HostVO> ssHosts = _hostDao.listBy(Host.Type.SecondaryStorage, host.getDataCenterId());
	    if (ssHosts == null || ssHosts.isEmpty()) {
	        return;
	    }
	    /*Download all the templates in zone with the same hypervisortype*/
        for ( HostVO ssHost : ssHosts) {
    	    List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
    	    List<VMTemplateVO> defaultBuiltin = _templateDao.listDefaultBuiltinTemplates();
    
    
    	    for (VMTemplateVO rtngTmplt : rtngTmplts) {
    	        if (rtngTmplt.getHypervisorType() == hostHyper) {
    	            toBeDownloaded.add(rtngTmplt);
    	        }
    	    }
    
    	    for (VMTemplateVO builtinTmplt : defaultBuiltin) {
    	        if (builtinTmplt.getHypervisorType() == hostHyper) {
    	            toBeDownloaded.add(builtinTmplt);
    	        }
    	    }
    
    	    for (VMTemplateVO template: toBeDownloaded) {
    	        VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(ssHost.getId(), template.getId());
    	        if (tmpltHost == null || tmpltHost.getDownloadState() != Status.DOWNLOADED) {
    	            downloadTemplateToStorage(template, ssHost);
    	        }
    	    }
        }
	}
    
    @Override	
	public void addSystemVMTemplatesToHost(HostVO host, Map<String, TemplateInfo> templateInfos){
	    if ( templateInfos == null ) {
	        return;
	    }
	    Long hostId = host.getId();
	    List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
	    for ( VMTemplateVO tmplt : rtngTmplts ) {
	        TemplateInfo tmpltInfo = templateInfos.get(tmplt.getUniqueName());
	        if ( tmpltInfo == null ) {
	            continue;
	        }
	        VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(hostId, tmplt.getId());
	        if ( tmpltHost == null ) {
                tmpltHost = new VMTemplateHostVO(hostId, tmplt.getId(), new Date(), 100, Status.DOWNLOADED, null, null, null, tmpltInfo.getInstallPath(), tmplt.getUrl());
	            tmpltHost.setSize(tmpltInfo.getSize());
	            tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
	            _vmTemplateHostDao.persist(tmpltHost);
	        }
	    }
	}
	
    @Override
    public void handleTemplateSync(long dcId) {
        List<HostVO> ssHosts = _hostDao.listSecondaryStorageHosts(dcId);
        for ( HostVO ssHost : ssHosts ) {
            handleTemplateSync(ssHost);
        }
    }
    
    private Map<String, TemplateInfo> listTemplate(HostVO ssHost) {
        ListTemplateCommand cmd = new ListTemplateCommand(ssHost.getStorageUrl());
        Answer answer = _agentMgr.sendToSecStorage(ssHost, cmd);
        if (answer != null && answer.getResult()) {
            ListTemplateAnswer tanswer = (ListTemplateAnswer)answer;
            return tanswer.getTemplateInfo();
        } else {
            if (s_logger.isDebugEnabled()) {
                s_logger.debug("can not list template for secondary storage host " + ssHost.getId());
            }
        } 
        
        return null;
    }
    
	
	@Override
    public void handleTemplateSync(HostVO ssHost) {
        if (ssHost == null) {
            s_logger.warn("Huh? ssHost is null");
            return;
        }
        long sserverId = ssHost.getId();
        long zoneId = ssHost.getDataCenterId();
        if (!(ssHost.getType() == Host.Type.SecondaryStorage || ssHost.getType() == Host.Type.LocalSecondaryStorage)) {
            s_logger.warn("Huh? Agent id " + sserverId + " is not secondary storage host");
            return;
        }
        Map<String, TemplateInfo> templateInfos = listTemplate(ssHost);
        if (templateInfos == null) {
            return;
        }

        Set<VMTemplateVO> toBeDownloaded = new HashSet<VMTemplateVO>();
        List<VMTemplateVO> allTemplates = _templateDao.listAllInZone(zoneId);
        List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
        List<VMTemplateVO> defaultBuiltin = _templateDao.listDefaultBuiltinTemplates();

        if (rtngTmplts != null) {
            for (VMTemplateVO rtngTmplt : rtngTmplts) {
                if (!allTemplates.contains(rtngTmplt)) {
                    allTemplates.add(rtngTmplt);
                }
            }
        }

        if (defaultBuiltin != null) {
            for (VMTemplateVO builtinTmplt : defaultBuiltin) {
                if (!allTemplates.contains(builtinTmplt)) {
                    allTemplates.add(builtinTmplt);
                }
            }
        }

        toBeDownloaded.addAll(allTemplates);

        for (VMTemplateVO tmplt : allTemplates) {
            String uniqueName = tmplt.getUniqueName();
            VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(sserverId, tmplt.getId());
            if (templateInfos.containsKey(uniqueName)) {
                TemplateInfo tmpltInfo = templateInfos.remove(uniqueName);
                toBeDownloaded.remove(tmplt);
                if (tmpltHost != null) {
                    s_logger.info("Template Sync found " + uniqueName + " already in the template host table");
                    if (tmpltHost.getDownloadState() != Status.DOWNLOADED) {
                        tmpltHost.setErrorString("");
                    }
                    if (tmpltInfo.isCorrupted()) {
                        tmpltHost.setDownloadState(Status.DOWNLOAD_ERROR);
                        String msg = "Template " + tmplt.getName() + ":" + tmplt.getId() + " is corrupted on secondary storage " + tmpltHost.getId();
                        tmpltHost.setErrorString(msg);
                        s_logger.info("msg");
                        if (tmplt.getUrl() == null) {
                            msg = "Private Template (" + tmplt + ") with install path " + tmpltInfo.getInstallPath() + "is corrupted, please check in secondary storage: " + tmpltHost.getHostId();
                            s_logger.warn(msg);
                        } else {
                            toBeDownloaded.add(tmplt);
                        }

                    } else {
                        tmpltHost.setDownloadPercent(100);
                        tmpltHost.setDownloadState(Status.DOWNLOADED);
                        tmpltHost.setInstallPath(tmpltInfo.getInstallPath());
                        tmpltHost.setSize(tmpltInfo.getSize());
                        tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
                        tmpltHost.setLastUpdated(new Date());
                    }
                    _vmTemplateHostDao.update(tmpltHost.getId(), tmpltHost);
                } else {
                    tmpltHost = new VMTemplateHostVO(sserverId, tmplt.getId(), new Date(), 100, Status.DOWNLOADED, null, null, null, tmpltInfo.getInstallPath(), tmplt.getUrl());
                    tmpltHost.setSize(tmpltInfo.getSize());
                    tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
                    _vmTemplateHostDao.persist(tmpltHost);
                    VMTemplateZoneVO tmpltZoneVO = _vmTemplateZoneDao.findByZoneTemplate(zoneId, tmplt.getId());
                    if (tmpltZoneVO == null) {
                        tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date());
                        _vmTemplateZoneDao.persist(tmpltZoneVO);
                    } else {
                        tmpltZoneVO.setLastUpdated(new Date());
                        _vmTemplateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO);
                    }

                }

                continue;
            }
            if (tmpltHost != null && tmpltHost.getDownloadState() != Status.DOWNLOADED) {
                s_logger.info("Template Sync did not find " + uniqueName + " ready on server " + sserverId + ", will request download to start/resume shortly");

            } else if (tmpltHost == null) {
                s_logger.info("Template Sync did not find " + uniqueName + " on the server " + sserverId + ", will request download shortly");
                VMTemplateHostVO templtHost = new VMTemplateHostVO(sserverId, tmplt.getId(), new Date(), 0, Status.NOT_DOWNLOADED, null, null, null, null, tmplt.getUrl());
                _vmTemplateHostDao.persist(templtHost);
                VMTemplateZoneVO tmpltZoneVO = _vmTemplateZoneDao.findByZoneTemplate(zoneId, tmplt.getId());
                if (tmpltZoneVO == null) {
                    tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date());
                    _vmTemplateZoneDao.persist(tmpltZoneVO);
                } else {
                    tmpltZoneVO.setLastUpdated(new Date());
                    _vmTemplateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO);
                }
            }

        }

        if (toBeDownloaded.size() > 0) {
            /* Only download templates whose hypervirsor type is in the zone */
            List<HypervisorType> availHypers = _clusterDao.getAvailableHypervisorInZone(zoneId);
            if (availHypers.isEmpty()) {
                /*
                 * This is for cloudzone, local secondary storage resource
                 * started before cluster created
                 */
                availHypers.add(HypervisorType.KVM);
            }
            /* Baremetal need not to download any template */
            availHypers.remove(HypervisorType.BareMetal);
            availHypers.add(HypervisorType.None); // bug 9809: resume ISO
                                                  // download.
            for (VMTemplateVO tmplt : toBeDownloaded) {
                if (tmplt.getUrl() == null) { // If url is null we can't
                                              // initiate the download
                    continue;
                }
                // if this is private template, and there is no record for this
                // template in this sHost, skip
                if (!tmplt.isPublicTemplate() && !tmplt.isFeatured()) {
                    VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(sserverId, tmplt.getId());
                    if (tmpltHost == null) {
                        continue;
                    }
                }
                if (availHypers.contains(tmplt.getHypervisorType())) {
                    s_logger.debug("Template " + tmplt.getName() + " needs to be downloaded to " + ssHost.getName());
                    downloadTemplateToStorage(tmplt, ssHost);
                }
            }
        }

        for (String uniqueName : templateInfos.keySet()) {
            TemplateInfo tInfo = templateInfos.get(uniqueName);
            DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(ssHost.getStorageUrl(), tInfo.getInstallPath());
            long result = _agentMgr.sendToSecStorage(ssHost, dtCommand, null);
            if (result == -1) {
                String description = "Failed to delete " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " which isn't in the database";
                s_logger.error(description);
                return;
            }
            String description = "Deleted template " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " since it isn't in the database, result=" + result;
            s_logger.info(description);
        }

        // This code is mostly for migration purposes so that we have checksum
        // for all the templates
        if (ssHost.getType() == Host.Type.SecondaryStorage) {
            checksumSync(sserverId);
        }
    }
{'fraction_non_alphanumeric': 0.10372897385665068, 'fraction_numerical': 0.0015199621698304398, 'mean_word_length': 2.972427210519254, 'pattern_counts': {'":': 3, '<': 67, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 170, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2651882', 'n_tokens_mistral': 18432, 'n_tokens_neox': 17440, 'n_words': 3392}