package core.aws.resource.ec2;
import com.amazonaws.services.ec2.model.IpPermission;
import com.amazonaws.services.ec2.model.IpRange;
import com.amazonaws.services.ec2.model.UserIdGroupPair;
import core.aws.util.Lists;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author neo
*/
class SecurityGroupRuleHelper {
private final Map<Protocol, List<SecurityGroup.Source>> localIngressRules;
private final List<IpPermission> remoteIngressRules;
SecurityGroupRuleHelper(Map<Protocol, List<SecurityGroup.Source>> localIngressRules, List<IpPermission> remoteIngressRules) {
this.localIngressRules = localIngressRules;
this.remoteIngressRules = remoteIngressRules;
}
Map<Protocol, List<SecurityGroup.Source>> findAddedIngressRules() {
Map<Protocol, List<SecurityGroup.Source>> addedRules = new HashMap<>();
localIngressRules.forEach((protocol, sources) -> sources.forEach(source -> {
if (!remoteIngressRulesContains(protocol, source)) {
addedRules.computeIfAbsent(protocol, key -> Lists.newArrayList()).add(source);
}
}));
return addedRules;
}
List<IpPermission> findDeletedIngressRules() {
List<IpPermission> deletedRules = new ArrayList<>();
for (IpPermission permission : remoteIngressRules) {
// delete all traffic rules
if ("-1".equals(permission.getIpProtocol())) {
deletedRules.add(permission);
continue;
}
Protocol protocol = new Protocol(permission.getIpProtocol(), permission.getFromPort(), permission.getToPort());
List<SecurityGroup.Source> sources = localIngressRules.get(protocol);
if (sources == null) {
deletedRules.add(permission);
continue;
}
List<IpRange> deletedIpRanges = permission.getIpv4Ranges().stream()
.filter(ipRange -> !containsIpRange(sources, ipRange))
.collect(Collectors.toList());
List<UserIdGroupPair> deletedSecurityGroupIds = new ArrayList<>();
deletedSecurityGroupIds.addAll(permission.getUserIdGroupPairs().stream()
.filter(userGroup -> !containsSourceUserGroup(sources, userGroup))
.map(userGroup -> new UserIdGroupPair().withUserId(userGroup.getUserId()).withGroupId(userGroup.getGroupId()))
.collect(Collectors.toList()));
if (!deletedIpRanges.isEmpty() || !deletedSecurityGroupIds.isEmpty()) {
IpPermission rule = new IpPermission()
.withIpProtocol(permission.getIpProtocol())
.withFromPort(permission.getFromPort())
.withToPort(permission.getToPort())
.withIpv4Ranges(deletedIpRanges)
.withUserIdGroupPairs(deletedSecurityGroupIds);
deletedRules.add(rule);
}
}
return deletedRules;
}
private boolean containsSourceUserGroup(Collection<SecurityGroup.Source> sources, final UserIdGroupPair sourceUserGroup) {
return sources.stream().anyMatch(source -> source.securityGroup != null && source.securityGroup.remoteSecurityGroup != null
&& sourceUserGroup.getGroupId().equals(source.securityGroup.remoteSecurityGroup.getGroupId()));
}
private boolean containsIpRange(Collection<SecurityGroup.Source> sources, final IpRange ipRange) {
return sources.stream().anyMatch(source -> source.ipRange != null && source.ipRange.equals(ipRange));
}
private boolean remoteIngressRulesContains(Protocol protocol, SecurityGroup.Source source) {
for (IpPermission rule : remoteIngressRules) {
if (rule.getIpProtocol().equals(protocol.ipProtocol)
&& rule.getFromPort() == protocol.fromPort
&& rule.getToPort() == protocol.toPort) {
if (source.ipRange != null && rule.getIpv4Ranges().contains(source.ipRange)) return true;
if (remoteIngressRuleContainsSource(rule, source)) return true;
}
}
return false;
}
private boolean remoteIngressRuleContainsSource(IpPermission rule, SecurityGroup.Source source) {
if (source.securityGroup != null && source.securityGroup.remoteSecurityGroup != null) {
for (UserIdGroupPair userGroup : rule.getUserIdGroupPairs()) {
if (userGroup.getGroupId().equals(source.securityGroup.remoteSecurityGroup.getGroupId()))
return true;
}
}
return false;
}
}