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());
}
}
}