package com.sungardas.enhancedsnapshots.service.impl; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.annotation.PostConstruct; import com.amazonaws.regions.Region; import com.amazonaws.regions.Regions; import com.amazonaws.services.ec2.AmazonEC2; import com.sungardas.enhancedsnapshots.aws.dynamodb.model.BackupEntry; import com.sungardas.enhancedsnapshots.aws.dynamodb.repository.BackupRepository; import com.sungardas.enhancedsnapshots.components.ConfigurationMediator; import com.sungardas.enhancedsnapshots.dto.VolumeDto; import com.sungardas.enhancedsnapshots.dto.converter.VolumeDtoConverter; import com.sungardas.enhancedsnapshots.exception.DataAccessException; import com.sungardas.enhancedsnapshots.service.SchedulerService; import com.sungardas.enhancedsnapshots.service.Task; import com.sungardas.enhancedsnapshots.service.VolumeService; import org.apache.commons.collections.IteratorUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class VolumeServiceImpl implements VolumeService { private static final Logger LOG = LogManager.getLogger(VolumeServiceImpl.class); private static final String REMOVED_VOLUME_STATE = "removed"; private static final String EMPTY = ""; private static final VolumeDtoComparator volumeDtoComparator = new VolumeDtoComparator(); @Autowired private AmazonEC2 amazonEC2; @Autowired private BackupRepository backupRepository; @Autowired private SchedulerService schedulerService; @Autowired private ConfigurationMediator configurationMediator; private Set<VolumeDto> cache; @PostConstruct private void init() { schedulerService.addTask(new Task() { @Override public String getId() { return getClass().getName(); } @Override public void run() { expireCache(); } }, "* * * * *"); } @Override public Set<VolumeDto> getVolumes() { LOG.debug("Getting volume list ..."); amazonEC2.setRegion(Region.getRegion(Regions.fromName(configurationMediator.getRegion()))); return getVolumes(amazonEC2); } @Override public Set<VolumeDto> getExistingVolumes() { return VolumeDtoConverter.convert(amazonEC2.describeVolumes().getVolumes()); } private Set<VolumeDto> getVolumes(AmazonEC2 amazonEC2) { if (cache != null) { return cache; } else { try { Set<VolumeDto> result = new TreeSet<>(volumeDtoComparator); result.addAll(VolumeDtoConverter.convert(amazonEC2.describeVolumes().getVolumes())); result.addAll(getHistoryVolumes()); result = setSchedules(result); LOG.debug("Volume list: [{}]", result); cache = result; return result; } catch (RuntimeException e) { LOG.error("Failed to get volume list.", e); throw new DataAccessException("Failed to get volume list.", e); } } } @Override public void expireCache() { cache = null; } @Override public Set<VolumeDto> getVolumesByRegion(Region region) { LOG.debug("Getting volume list for region [{}]", region); amazonEC2.setRegion(region); Set<VolumeDto> volumes = getVolumes(amazonEC2); return volumes; } @Override public boolean volumeExists(String volumeId) { for (VolumeDto dto : getExistingVolumes()) { if (dto.getVolumeId().equals(volumeId)) { return true; } } return false; } private Set<VolumeDto> setSchedules(Set<VolumeDto> result) { Set<String> volumeWithSchedule = schedulerService.getVolumeIdsWithSchedule(); for (VolumeDto volumeDto : result) { if (volumeWithSchedule.contains(volumeDto.getVolumeId())) { volumeDto.setScheduled(true); } } return result; } private Set<VolumeDto> getHistoryVolumes() { return convert(backupRepository.findAll()); } private Set<VolumeDto> convert(Iterable<BackupEntry> entries) { List<BackupEntry> backupList = IteratorUtils.toList(entries.iterator()); Comparator<BackupEntry> cmp = Comparator.comparingLong(backup-> Long.parseLong(backup.getTimeCreated())); Collections.sort(backupList, cmp.reversed()); Map<String, VolumeDto> dtos = new HashMap<>(); for (BackupEntry entry : backupList) { VolumeDto dto = new VolumeDto(); dto.setVolumeId(entry.getVolumeId()); dto.setSize(0); dto.setInstanceID(EMPTY); dto.setVolumeName(entry.getVolumeName()); dto.setTags(Collections.EMPTY_LIST); dto.setAvailabilityZone(EMPTY); dto.setSnapshotId(EMPTY); dto.setState(REMOVED_VOLUME_STATE); if(!dtos.containsKey(dto.getVolumeId())) { dtos.put(dto.getVolumeId(), dto); } } return new HashSet<>(dtos.values()); } private static final class VolumeDtoComparator implements Comparator<VolumeDto> { @Override public int compare(VolumeDto o1, VolumeDto o2) { return o1.getVolumeId().compareTo(o2.getVolumeId()); } } }