Merge pull request #1257 from navi-infra/INFRA-3970
INFRA-3970 | Dhruv | Adds support for CR in outbound
This commit is contained in:
2
kutegen
2
kutegen
Submodule kutegen updated: 0bb5b971c9...7e3941e08a
@@ -0,0 +1,11 @@
|
||||
package com.navi.infra.portal.domain.manifest;
|
||||
|
||||
public interface ManifestInfo {
|
||||
|
||||
|
||||
String getName();
|
||||
|
||||
String getEnvironment();
|
||||
|
||||
String getTeam();
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.navi.infra.portal.repository;
|
||||
|
||||
import com.navi.infra.portal.domain.manifest.Manifest;
|
||||
import com.navi.infra.portal.domain.manifest.ManifestInfo;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
@@ -35,7 +37,10 @@ public interface ManifestRepository extends JpaRepository<Manifest, Long> {
|
||||
+ "JOIN manifest m ON e.manifest_id = m.id "
|
||||
+ "WHERE jsonb_extract_path_text(CAST(e.data AS jsonb), 'database', 'instanceName') = :instanceName and m.environment = :environment",
|
||||
nativeQuery = true)
|
||||
Optional<Long> findIdByInstanceName(@Param("instanceName") String instanceName, @Param("environment") String environment);
|
||||
Optional<Long> findIdByInstanceName(
|
||||
@Param("instanceName") String instanceName,
|
||||
@Param("environment") String environment
|
||||
);
|
||||
|
||||
@Query(value = "SELECT * "
|
||||
+ "FROM manifest m "
|
||||
@@ -68,4 +73,7 @@ public interface ManifestRepository extends JpaRepository<Manifest, Long> {
|
||||
@Param("privileges") List<String> privileges,
|
||||
Pageable pageable
|
||||
);
|
||||
|
||||
@Query(value = "SELECT m.name, m.environment, m.data -> 'team' ->> 'name' as team from manifest m", nativeQuery = true)
|
||||
Set<ManifestInfo> getManifestInfo();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.navi.infra.portal.domain.manifest.ExtraResources;
|
||||
import com.navi.infra.portal.domain.manifest.LoadBalancer;
|
||||
import com.navi.infra.portal.domain.manifest.Manifest;
|
||||
import com.navi.infra.portal.domain.manifest.ManifestAudit;
|
||||
import com.navi.infra.portal.domain.manifest.ManifestInfo;
|
||||
import com.navi.infra.portal.domain.manifest.SecretConfig;
|
||||
import com.navi.infra.portal.domain.manifest.StatusMarker;
|
||||
import com.navi.infra.portal.domain.user.User;
|
||||
@@ -891,7 +892,7 @@ public class ManifestService {
|
||||
|
||||
public Map<String, Object> exportManifestByIdAndVersion(Long id, Long version) {
|
||||
final Set<String> keysToExclude = Set.of("version", "id", "infraVertical", "cluster",
|
||||
"groupName", "kmsKeyId", "product", "internalCommonApiGatewayUrl",
|
||||
"groupName", "kmsKeyId", "product", "internalCommonApiGatewayUrl", "hashedIdentifier",
|
||||
"commonApiGatewayUrl");
|
||||
final Map keysToReplace = Map.of("isDeployed", false, "ids", emptyList());
|
||||
var manifest = version == null ? fetchById(id) : fetchByIdAndVersion(id, version);
|
||||
@@ -931,6 +932,10 @@ public class ManifestService {
|
||||
|
||||
}
|
||||
|
||||
public Set<ManifestInfo> fetchManifestInfo() {
|
||||
return manifestRepository.getManifestInfo();
|
||||
}
|
||||
|
||||
public List<Manifest> fetchAllManifests() {
|
||||
return manifestRepository.findAll();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,19 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class MapUtil {
|
||||
|
||||
public static final String INSERT_IN_END_IDENTIFIER = "*";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static String getHashedIdentifierValue(Object obj) {
|
||||
return (String) ((Map<String, Object>) obj).get("hashedIdentifier");
|
||||
}
|
||||
|
||||
private static boolean isNewEntry(List<Object> list, Object value) {
|
||||
String hashedIdentifier = getHashedIdentifierValue(value);
|
||||
return list.stream().noneMatch(
|
||||
obj -> hashedIdentifier.equals(getHashedIdentifierValue(obj)));
|
||||
}
|
||||
|
||||
private static boolean isInteger(String s) {
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
@@ -104,7 +117,10 @@ public class MapUtil {
|
||||
}
|
||||
if (tmpMap.get(s) instanceof List) {
|
||||
final var tmpList = (List<Object>) tmpMap.get(s);
|
||||
final int index = Integer.valueOf(splitPath[++i], 10);
|
||||
if (splitPath[++i].equals(INSERT_IN_END_IDENTIFIER)) {
|
||||
throw new IndexOutOfBoundsException("New entry is being added to the list");
|
||||
}
|
||||
final int index = Integer.valueOf(splitPath[i], 10);
|
||||
if (i == splitPath.length - 1) {
|
||||
return tmpList.get(index);
|
||||
}
|
||||
@@ -165,6 +181,14 @@ public class MapUtil {
|
||||
try {
|
||||
idx = Integer.parseInt(paths.get(0));
|
||||
} catch (NumberFormatException e) {
|
||||
if (INSERT_IN_END_IDENTIFIER.equals(paths.get(0))) {
|
||||
if (isNewEntry(list, value)) {
|
||||
populateList(list, list.size());
|
||||
return list.set(list.size() - 1, value);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(format("Failed json path is wrong: %s", join(", ", paths)),
|
||||
e);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.navi.infra.portal.util.manifest;
|
||||
|
||||
import static com.navi.infra.portal.util.EncoderDecoderUtil.base64Encode;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.navi.infra.portal.v2.changerequest.entity.ChangeRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -10,6 +13,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.IntStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -18,6 +23,18 @@ import org.springframework.stereotype.Component;
|
||||
public class ChangeRequestUtils {
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private static final Map<String, Function<Map<String, Object>, String>> identifierPopulatorForlimitPath =
|
||||
Map.of(
|
||||
"/deployment/allowEndpoint", ChangeRequestUtils::getIdentifierForAllowEndpoint
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static String getIdentifierForAllowEndpoint(Map<String, Object> value) {
|
||||
var endpointValue = (Map<String, String>) value.get("value");
|
||||
var decodedIdentifier = String.format("%s:%s", endpointValue.get("host"),
|
||||
endpointValue.get("port"));
|
||||
return base64Encode(decodedIdentifier);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Object safeMapAccess(Object obj, String key) {
|
||||
@@ -42,6 +59,17 @@ public class ChangeRequestUtils {
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Object safeListAccess(Object obj, String uniqueIdentifier) {
|
||||
if (!(obj instanceof List)) {
|
||||
return null;
|
||||
}
|
||||
return Optional.of(obj).flatMap(list -> ((List<Object>) list).stream()
|
||||
.filter(map -> ((Map<String, Object>) map).containsValue(uniqueIdentifier))
|
||||
.findAny())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public static boolean isMap(Object obj) {
|
||||
return obj instanceof Map;
|
||||
}
|
||||
@@ -165,7 +193,7 @@ public class ChangeRequestUtils {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return currentWeight != null && (previousWeight == null || currentWeight > previousWeight);
|
||||
}
|
||||
|
||||
@@ -238,17 +266,8 @@ public class ChangeRequestUtils {
|
||||
var curPreManifestObj = safeMapAccess(preManifestObject, key);
|
||||
if (isTarget(currentLimitObj) && isMap(currentLimitObj)) {
|
||||
var mapCurrentLimitObject = (Map<String, Object>) currentLimitObj;
|
||||
if (mapCurrentLimitObject.get("forEach") != null && currentManifestObj != null) {
|
||||
var listCurrentManifestValue = (List<Map<String, Object>>) currentManifestObj;
|
||||
for (var i = 0; i < listCurrentManifestValue.size(); i++) {
|
||||
if (hasBreachedAndIsDifferent(
|
||||
(Map<String, Object>) mapCurrentLimitObject.get("forEach"),
|
||||
listCurrentManifestValue.get(i), safeListAccess(curPreManifestObj, i),
|
||||
manifestEnv)) {
|
||||
keysCausingChangeRequest.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
handleForEach(mapCurrentLimitObject, currentManifestObj, curPreManifestObj, key,
|
||||
manifestEnv, keysCausingChangeRequest);
|
||||
if (hasBreachedAndIsDifferent(mapCurrentLimitObject, currentManifestObj,
|
||||
curPreManifestObj, manifestEnv)) {
|
||||
keysCausingChangeRequest.add(key);
|
||||
@@ -258,6 +277,37 @@ public class ChangeRequestUtils {
|
||||
curPreManifestObj, manifestEnv, keysCausingChangeRequest);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void handleForEach(
|
||||
Map<String, Object> mapCurrentLimitObject, Object currentManifestObj,
|
||||
Object curPreManifestObj, String key, String manifestEnv,
|
||||
List<String> keysCausingChangeRequest
|
||||
) {
|
||||
if (mapCurrentLimitObject.get("forEach") != null && currentManifestObj != null) {
|
||||
var listCurrentManifestValue = (List<Map<String, Object>>) currentManifestObj;
|
||||
IntStream.range(0, listCurrentManifestValue.size()).forEach(i -> {
|
||||
var currentManifestValue = listCurrentManifestValue.get(i);
|
||||
Object preManifestValue = null;
|
||||
if (Boolean.TRUE.equals(mapCurrentLimitObject.get("hasHashedIdentifier"))) {
|
||||
var hashedIdentifier = (String) currentManifestValue.get("hashedIdentifier");
|
||||
if (hashedIdentifier == null) {
|
||||
keysCausingChangeRequest.add(String.format("%s[%d]", key, i));
|
||||
return;
|
||||
}
|
||||
preManifestValue = safeListAccess(curPreManifestObj, hashedIdentifier);
|
||||
} else {
|
||||
preManifestValue = safeListAccess(curPreManifestObj, i);
|
||||
}
|
||||
|
||||
if (hasBreachedAndIsDifferent(
|
||||
(Map<String, Object>) mapCurrentLimitObject.get("forEach"),
|
||||
currentManifestValue, preManifestValue, manifestEnv)) {
|
||||
keysCausingChangeRequest.add(String.format("%s[%d]", key, i));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> checkTriggersChangeRequest(
|
||||
Map<String, Object> limitObject,
|
||||
Map<String, Object> manifestObject,
|
||||
@@ -411,4 +461,16 @@ public class ChangeRequestUtils {
|
||||
return previousValue == null && ((List<?>) limit.get("environments")).contains(manifestEnv);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ChangeRequest populateIdentifier(ChangeRequest changeRequest) {
|
||||
changeRequest.getDiff().forEach(diff -> {
|
||||
var limitPath = (String) diff.get("limitPath");
|
||||
if (identifierPopulatorForlimitPath.containsKey(limitPath)) {
|
||||
var identifierValue = identifierPopulatorForlimitPath.get(limitPath).apply(diff);
|
||||
((Map<String, Object>) diff.get("value")).put("hashedIdentifier", identifierValue);
|
||||
}
|
||||
});
|
||||
return changeRequest;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import static java.util.stream.Collectors.toUnmodifiableSet;
|
||||
|
||||
import com.navi.infra.portal.domain.manifest.Manifest;
|
||||
import com.navi.infra.portal.domain.user.Team;
|
||||
import com.navi.infra.portal.repository.ManifestRepository;
|
||||
import com.navi.infra.portal.service.manifest.ManifestService;
|
||||
import com.navi.infra.portal.service.user.PrivilegeUtilService;
|
||||
import com.navi.infra.portal.service.user.UserService;
|
||||
import com.navi.infra.portal.util.MapUtil;
|
||||
@@ -24,6 +24,7 @@ import com.navi.infra.portal.v2.approvalflow.entity.ApprovalRequest;
|
||||
import com.navi.infra.portal.v2.approvalflow.entity.ApprovalRequestBuilder;
|
||||
import com.navi.infra.portal.v2.approvalflow.entity.RequestType;
|
||||
import com.navi.infra.portal.v2.approvalflow.repository.ApprovalRequestRepository;
|
||||
import com.navi.infra.portal.v2.approvalflow.util.ApprovalRequestUtil;
|
||||
import com.navi.infra.portal.v2.changerequest.entity.ChangeRequest;
|
||||
import com.navi.infra.portal.v2.changerequest.service.ChangeRequestService;
|
||||
import com.navi.infra.portal.v2.changerequest.service.ManifestLimitService;
|
||||
@@ -55,35 +56,37 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
private final ApprovalRequestRepository repository;
|
||||
private final TeamService teamService;
|
||||
private final UserService userService;
|
||||
// todo: use manifest service after the initial merge
|
||||
private final ManifestRepository manifestRepository;
|
||||
private final ManifestService manifestService;
|
||||
private final ManifestLimitService manifestLimitService;
|
||||
private final ChangeRequestService changeRequestService;
|
||||
private final TokenRequestService tokenRequestService;
|
||||
private final PrivilegeUtilService privilegeUtilService;
|
||||
private final ChangeRequestSlackService changeRequestSlackService;
|
||||
private final ApprovalRequestUtil approvalRequestUtil;
|
||||
private final MapUtil mapUtil;
|
||||
|
||||
public ApprovalRequestServiceImpl(
|
||||
ApprovalRequestRepository repository,
|
||||
TeamService teamService,
|
||||
UserService userService,
|
||||
ManifestRepository manifestRepository,
|
||||
ManifestService manifestService,
|
||||
ManifestLimitService manifestLimitService,
|
||||
@Lazy ChangeRequestService changeRequestService,
|
||||
@Lazy TokenRequestService tokenRequestService, PrivilegeUtilService privilegeUtilService,
|
||||
@Lazy ChangeRequestSlackService changeRequestSlackService,
|
||||
ApprovalRequestUtil approvalRequestUtil,
|
||||
MapUtil mapUtil
|
||||
) {
|
||||
this.repository = repository;
|
||||
this.teamService = teamService;
|
||||
this.userService = userService;
|
||||
this.manifestRepository = manifestRepository;
|
||||
this.manifestService = manifestService;
|
||||
this.manifestLimitService = manifestLimitService;
|
||||
this.changeRequestService = changeRequestService;
|
||||
this.tokenRequestService = tokenRequestService;
|
||||
this.privilegeUtilService = privilegeUtilService;
|
||||
this.changeRequestSlackService = changeRequestSlackService;
|
||||
this.approvalRequestUtil = approvalRequestUtil;
|
||||
this.mapUtil = mapUtil;
|
||||
}
|
||||
|
||||
@@ -129,7 +132,7 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Transactional
|
||||
public Iterable<ApprovalRequest> createApprovals(ChangeRequest changeRequest) {
|
||||
final var manifest = findManifestById(changeRequest.getManifestId());
|
||||
final var manifest = manifestService.fetchById(changeRequest.getManifestId());
|
||||
|
||||
final var oldApprovalList = repository.findByRequestIdAndType(changeRequest.getId(),
|
||||
CHANGE_REQUEST.code);
|
||||
@@ -153,7 +156,7 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
var additionalApprovals = new ArrayList<>(approvalList);
|
||||
additionalApprovals.removeAll(oldApprovalList);
|
||||
try {
|
||||
|
||||
|
||||
changeRequestSlackService.updateApprovalStatusesInBulk(PENDING.code, extractedData);
|
||||
if (!oldApprovalList.isEmpty()) {
|
||||
log.info(
|
||||
@@ -180,7 +183,7 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
format("No manifest id is found in this token request: %d", tokenRequest.getId())));
|
||||
|
||||
final var manifest = findManifestById(manifestId);
|
||||
final var manifest = manifestService.fetchById(manifestId);
|
||||
final var approverTeamSet = new HashSet<String>();
|
||||
approverTeamSet.add(
|
||||
(String) ((HashMap<String, Object>) manifest.getData().get("team")).get("name"));
|
||||
@@ -330,10 +333,10 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
format("No manifest is associated with this Token Request: %d", requestId)));
|
||||
}
|
||||
|
||||
return Optional.ofNullable(manifestId)
|
||||
.map(manifestRepository::findById)
|
||||
return Optional.ofNullable(Optional.ofNullable(manifestId)
|
||||
.map(manifestService::fetchById)
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
format("No manifest is associated with this request: %d", requestId)));
|
||||
format("No manifest is associated with this request: %d", requestId))));
|
||||
}
|
||||
|
||||
private boolean userHasSameTeamAsApprovalRequest(Long teamId, Long userId) {
|
||||
@@ -349,12 +352,6 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
return allPendingByCrId.isEmpty();
|
||||
}
|
||||
|
||||
private Manifest findManifestById(Long manifestId) {
|
||||
return manifestRepository.findById(manifestId).orElseThrow(
|
||||
() -> new NotFoundException("Manifest not found for CR, id: " + manifestId)
|
||||
);
|
||||
}
|
||||
|
||||
private List<ApprovalRequest> getRequiredApprovalList(
|
||||
ChangeRequest changeRequest,
|
||||
String env,
|
||||
@@ -367,7 +364,7 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
.map(diffMap -> (String) diffMap.get("limitPath"))
|
||||
.collect(toUnmodifiableList());
|
||||
final var approverTeams = Stream.of(
|
||||
getApproverTeamsByPaths(limitMap, pathsOfChangedComponents),
|
||||
getApproverTeamsByPaths(changeRequest.getDiff(), limitMap, pathsOfChangedComponents),
|
||||
singletonList(manifestTeam)
|
||||
).flatMap(List::stream)
|
||||
.collect(toUnmodifiableSet());
|
||||
@@ -391,10 +388,16 @@ public class ApprovalRequestServiceImpl implements ApprovalRequestService {
|
||||
.collect(toUnmodifiableList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<String> getApproverTeamsByPaths(Map<String, Object> limitMap, List<String> paths) {
|
||||
private List<String> getApproverTeamsByPaths(
|
||||
List<Map<String, Object>> diff, Map<String, Object> limitMap, List<String> paths
|
||||
) {
|
||||
var pathDiffMap = diff.stream().collect(
|
||||
Collectors.groupingBy(
|
||||
breach -> (String) breach.get("limitPath")
|
||||
)
|
||||
);
|
||||
return paths.stream()
|
||||
.map(path -> (List<String>) mapUtil.getValueAtPath(limitMap, path, "approvalFrom"))
|
||||
.map(path -> approvalRequestUtil.getApprovers(pathDiffMap.get(path), limitMap, path))
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(toUnmodifiableList());
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.navi.infra.portal.v2.approvalflow.util;
|
||||
|
||||
import com.navi.infra.portal.v2.egress.Egress;
|
||||
import com.navi.infra.portal.v2.egress.EgressService;
|
||||
import com.navi.infra.portal.v2.team.TeamService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AdditionalApproverTeam {
|
||||
|
||||
private final TeamService teamService;
|
||||
private final EgressService egressService;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getAllowEndpointAdditionalTeam(
|
||||
List<Map<String, Object>> allowEndpointBreachData
|
||||
) {
|
||||
log.info("Allowing endpoint additional team");
|
||||
return allowEndpointBreachData.stream()
|
||||
.flatMap(egressData -> {
|
||||
var endpointData = (Map<String, String>) egressData.get("value");
|
||||
return egressService.getEgress(
|
||||
endpointData.get("host"), endpointData.get("port"))
|
||||
.stream().map(Egress::getTeam)
|
||||
.filter(team -> teamService.findByName(team).getName() != null);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.navi.infra.portal.v2.approvalflow.util;
|
||||
|
||||
import com.navi.infra.portal.util.MapUtil;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ApprovalRequestUtil {
|
||||
|
||||
private final AdditionalApproverTeam additionalApproverTeam;
|
||||
private final MapUtil mapUtil;
|
||||
private final Map<String, Pair<String, Function<Object, List<String>>>> pathAdditionalApprover;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ApprovalRequestUtil(
|
||||
AdditionalApproverTeam additionalApproverTeam,
|
||||
MapUtil mapUtil
|
||||
) {
|
||||
this.additionalApproverTeam = additionalApproverTeam;
|
||||
this.mapUtil = mapUtil;
|
||||
this.pathAdditionalApprover = Map.of("/deployment/allowEndpoint",
|
||||
Pair.of("ENDPOINT_OWNER_TEAM",
|
||||
obj -> this.additionalApproverTeam.getAllowEndpointAdditionalTeam(
|
||||
(List<Map<String, Object>>) obj))
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getApprovers(
|
||||
List<Map<String, Object>> pathDiff,
|
||||
Map<String, Object> limitMap,
|
||||
String path
|
||||
) {
|
||||
var teams = (List<String>) mapUtil.getValueAtPath(limitMap, path, "approvalFrom");
|
||||
return teams.stream()
|
||||
.flatMap(team -> {
|
||||
if (pathAdditionalApprover.containsKey(path)
|
||||
&& team.equals(pathAdditionalApprover.get(path).getFirst())) {
|
||||
return pathAdditionalApprover.get(path).getSecond().apply(pathDiff).stream();
|
||||
}
|
||||
return Stream.of(team);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.navi.infra.portal.v2.changerequest.service;
|
||||
|
||||
import static com.navi.infra.portal.util.MapUtil.INSERT_IN_END_IDENTIFIER;
|
||||
import static com.navi.infra.portal.v2.changerequest.entity.RequestStatus.APPROVED;
|
||||
import static com.navi.infra.portal.v2.changerequest.entity.RequestStatus.CLOSED;
|
||||
import static com.navi.infra.portal.v2.changerequest.entity.RequestStatus.PENDING;
|
||||
@@ -23,6 +24,7 @@ import com.navi.infra.portal.security.authorization.AuthorizationContext;
|
||||
import com.navi.infra.portal.service.manifest.ManifestService;
|
||||
import com.navi.infra.portal.service.user.UserService;
|
||||
import com.navi.infra.portal.util.MapUtil;
|
||||
import com.navi.infra.portal.util.manifest.ChangeRequestUtils;
|
||||
import com.navi.infra.portal.v2.approvalflow.dto.ApprovalRequestDto;
|
||||
import com.navi.infra.portal.v2.approvalflow.entity.ApprovalRequest;
|
||||
import com.navi.infra.portal.v2.approvalflow.entity.ApprovalRequestBuilder;
|
||||
@@ -93,9 +95,10 @@ public class ChangeRequestServiceImpl implements ChangeRequestService {
|
||||
@Override
|
||||
@Transactional
|
||||
public ChangeRequest create(final ChangeRequest newCr) {
|
||||
final var oldCr = repository.findFirstPendingByManifestId(newCr.getManifestId())
|
||||
final var identifierPopulatedCr = ChangeRequestUtils.populateIdentifier(newCr);
|
||||
final var oldCr = repository.findFirstPendingByManifestId(identifierPopulatedCr.getManifestId())
|
||||
.orElse(null);
|
||||
final var finalCr = mergeCr(newCr, oldCr);
|
||||
final var finalCr = mergeCr(identifierPopulatedCr, oldCr);
|
||||
|
||||
final ChangeRequest savedCr;
|
||||
try {
|
||||
@@ -401,9 +404,12 @@ public class ChangeRequestServiceImpl implements ChangeRequestService {
|
||||
final var list = new ArrayList<>(oldDiffList);
|
||||
|
||||
for (final var newDiff : newDiffList) {
|
||||
var newPath = newDiff.get("path");
|
||||
var newPath = (String) newDiff.get("path");
|
||||
if (newPath.endsWith(INSERT_IN_END_IDENTIFIER)) {
|
||||
list.add(newDiff);
|
||||
continue;
|
||||
}
|
||||
var isFound = false;
|
||||
|
||||
for (final var oldDiff : list) {
|
||||
var oldPath = oldDiff.get("path");
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
@@ -16,9 +18,11 @@ import lombok.Setter;
|
||||
@Entity
|
||||
@Setter
|
||||
@Getter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Table(name = "egress")
|
||||
class Egress extends BaseEntity {
|
||||
public class Egress extends BaseEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@@ -27,6 +31,23 @@ class Egress extends BaseEntity {
|
||||
private String host;
|
||||
private String port;
|
||||
private String cluster;
|
||||
private String vertical;
|
||||
private String team;
|
||||
private String manifestName;
|
||||
private String manifestEnvironment;
|
||||
|
||||
public Egress(
|
||||
String host, String port, String cluster, String vertical, String team,
|
||||
String manifestName, String manifestEnvironment
|
||||
) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.cluster = cluster;
|
||||
this.vertical = vertical;
|
||||
this.team = team;
|
||||
this.manifestName = manifestName;
|
||||
this.manifestEnvironment = manifestEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
@@ -42,6 +63,23 @@ class Egress extends BaseEntity {
|
||||
&& Objects.equals(cluster, egress.cluster);
|
||||
}
|
||||
|
||||
public boolean equalsAllFields(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Egress egress = (Egress) o;
|
||||
return port.equals(egress.port)
|
||||
&& host.equals(egress.host)
|
||||
&& cluster.equals(egress.cluster)
|
||||
&& vertical.equals(egress.vertical)
|
||||
&& team.equals(egress.team)
|
||||
&& manifestName.equals(egress.manifestName)
|
||||
&& manifestEnvironment.equals(egress.manifestEnvironment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(host, port, cluster);
|
||||
@@ -49,6 +87,8 @@ class Egress extends BaseEntity {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return cluster + ":" + host + ":" + port;
|
||||
return String.format("Egress{host='%s', port='%s', cluster='%s', vertical='%s', team='%s', "
|
||||
+ "manifestName='%s', manifestEnvironment='%s'}",
|
||||
host, port, cluster, vertical, team, manifestName, manifestEnvironment);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@Validated
|
||||
@RequestMapping("/api/egress")
|
||||
class EgressController {
|
||||
|
||||
private final EgressService egressService;
|
||||
|
||||
@GetMapping()
|
||||
@@ -38,8 +39,10 @@ class EgressController {
|
||||
}
|
||||
|
||||
@PostMapping()
|
||||
public ResponseEntity<EgressUpdateResponse> updateEgress(@RequestParam Boolean dryRun,
|
||||
@RequestBody @Valid EgressUpdateRequest egressUpdateRequest) {
|
||||
public ResponseEntity<EgressUpdateResponse> updateEgress(
|
||||
@RequestParam Boolean dryRun,
|
||||
@RequestBody @Valid EgressUpdateRequest egressUpdateRequest
|
||||
) {
|
||||
try {
|
||||
log.info("Request received to update egresses with dryRun: {}",
|
||||
dryRun);
|
||||
@@ -57,4 +60,24 @@ class EgressController {
|
||||
return ResponseEntity.status(INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/validate-tags")
|
||||
public ResponseEntity<EgressTagValidationResponse> validateTags(
|
||||
@RequestBody @Valid EgressTagValidationDto egressTagInfo
|
||||
) {
|
||||
try {
|
||||
log.info("Request received to validate egress tags");
|
||||
final EgressTagValidationResponse tagValidationResponse = egressService.validateTags(
|
||||
egressTagInfo.getEgressTagData());
|
||||
if (tagValidationResponse.getConflictingTags().isEmpty()) {
|
||||
return ResponseEntity.ok(tagValidationResponse);
|
||||
} else {
|
||||
log.info("Egress have outdated or deleted manifest tags");
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(tagValidationResponse);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to validate egress tags", e);
|
||||
return ResponseEntity.status(INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.navi.infra.portal.v2.egress;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -10,8 +12,11 @@ import lombok.Setter;
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
class EgressDto {
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class EgressDto extends EgressTagDto {
|
||||
|
||||
@NotNull
|
||||
@Pattern(regexp = "(^([-a-zA-Z0-9_*]+[.]?)+$)|"
|
||||
+ "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|"
|
||||
@@ -28,4 +33,22 @@ class EgressDto {
|
||||
private String host;
|
||||
@NotNull
|
||||
private String port;
|
||||
|
||||
public EgressDto(Egress egress) {
|
||||
this.host = egress.getHost();
|
||||
this.port = egress.getPort();
|
||||
}
|
||||
|
||||
public EgressDto(
|
||||
String host,
|
||||
String port,
|
||||
String team,
|
||||
String vertical,
|
||||
String manifestEnvironment,
|
||||
String manifestName
|
||||
) {
|
||||
super(team, manifestName, vertical, manifestEnvironment);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
}
|
||||
@@ -10,20 +10,7 @@ import org.springframework.stereotype.Repository;
|
||||
@Repository
|
||||
interface EgressRepository extends JpaRepository<Egress, Long> {
|
||||
|
||||
@Query(value = "SELECT e.host, e.port FROM Egress e where e.cluster = :cluster",
|
||||
nativeQuery = true)
|
||||
List<Object[]> findByClusterName(String cluster);
|
||||
List<Egress> findByCluster(String cluster);
|
||||
|
||||
default List<EgressDto> findByCluster(String cluster) {
|
||||
var objs = findByClusterName(cluster);
|
||||
return objs
|
||||
.stream()
|
||||
.map(obj -> {
|
||||
var egress = new EgressDto();
|
||||
egress.setHost((String) obj[0]);
|
||||
egress.setPort((String) obj[1]);
|
||||
return egress;
|
||||
})
|
||||
.collect(toList());
|
||||
}
|
||||
List<Egress> findByHostAndPort(String host, String zone);
|
||||
}
|
||||
@@ -2,8 +2,14 @@ package com.navi.infra.portal.v2.egress;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface EgressService {
|
||||
public interface EgressService {
|
||||
|
||||
List<EgressDto> getEgresses(String cluster);
|
||||
|
||||
List<Egress> getEgress(String host, String zone);
|
||||
|
||||
EgressUpdateResponse updateEgresses(List<EgressUpdateRequestData> egresses, Boolean dryRun);
|
||||
|
||||
EgressTagValidationResponse validateTags(List<EgressTagDto> egressTags);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.navi.infra.portal.service.manifest.ManifestService;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -21,48 +22,97 @@ import org.springframework.stereotype.Service;
|
||||
@Slf4j
|
||||
@Service
|
||||
class EgressServiceImpl implements EgressService {
|
||||
|
||||
private final EgressRepository egressRepository;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final ManifestService manifestService;
|
||||
|
||||
public EgressServiceImpl(EgressRepository egressRepository,
|
||||
ManifestService manifestService, ObjectMapper objectMapper) {
|
||||
public EgressServiceImpl(
|
||||
EgressRepository egressRepository,
|
||||
ManifestService manifestService, ObjectMapper objectMapper
|
||||
) {
|
||||
this.egressRepository = egressRepository;
|
||||
this.manifestService = manifestService;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public List<Egress> getEgress(String host, String zone) {
|
||||
return egressRepository.findByHostAndPort(host, zone);
|
||||
}
|
||||
|
||||
public List<EgressDto> getEgresses(String cluster) {
|
||||
return egressRepository.findByCluster(cluster);
|
||||
return egressRepository.findByCluster(cluster)
|
||||
.stream()
|
||||
.map(EgressDto::new)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
private List<Egress> flattenEgresses(List<EgressUpdateRequestData> egressUpdateRequests) {
|
||||
return egressUpdateRequests.stream()
|
||||
.flatMap(clusterData -> clusterData.getEgressData().stream()
|
||||
.map(egressDto -> {
|
||||
Egress egress = new Egress();
|
||||
egress.setHost(egressDto.getHost());
|
||||
egress.setPort(egressDto.getPort());
|
||||
egress.setCluster(clusterData.getCluster());
|
||||
return egress;
|
||||
return Egress.builder()
|
||||
.team(egressDto.getTeam())
|
||||
.vertical(egressDto.getVertical())
|
||||
.manifestEnvironment(egressDto.getManifestEnvironment())
|
||||
.manifestName(egressDto.getManifestName())
|
||||
.host(egressDto.getHost())
|
||||
.port(egressDto.getPort())
|
||||
.cluster(clusterData.getCluster())
|
||||
.build();
|
||||
}))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
public EgressUpdateResponse updateEgresses(List<EgressUpdateRequestData> egresses,
|
||||
Boolean dryRun) {
|
||||
private Set<Egress> getUpdatedEgresses(
|
||||
Set<Egress> existingEgresses,
|
||||
List<Egress> flattenedEgresses
|
||||
) {
|
||||
Map<String, Egress> flattenedEgressMap = flattenedEgresses.stream()
|
||||
.collect(Collectors.toMap(
|
||||
egress -> egress.getHost() + ":" + egress.getPort() + ":" + egress.getCluster(),
|
||||
egress -> egress
|
||||
));
|
||||
return existingEgresses.stream()
|
||||
.map(egress -> {
|
||||
String key = egress.getHost() + ":" + egress.getPort() + ":" + egress.getCluster();
|
||||
Egress flattenedEgress = flattenedEgressMap.get(key);
|
||||
if (flattenedEgress != null && !flattenedEgress.equalsAllFields(egress)) {
|
||||
return Egress.builder()
|
||||
.id(egress.getId())
|
||||
.host(flattenedEgress.getHost())
|
||||
.port(flattenedEgress.getPort())
|
||||
.cluster(flattenedEgress.getCluster())
|
||||
.team(flattenedEgress.getTeam())
|
||||
.vertical(flattenedEgress.getVertical())
|
||||
.manifestEnvironment(flattenedEgress.getManifestEnvironment())
|
||||
.manifestName(flattenedEgress.getManifestName())
|
||||
.build();
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public EgressUpdateResponse updateEgresses(
|
||||
List<EgressUpdateRequestData> egresses,
|
||||
Boolean dryRun
|
||||
) {
|
||||
log.info("Updating egresses with dryRun: {}", dryRun);
|
||||
|
||||
List<Egress> flattenedEgresses = flattenEgresses(egresses);
|
||||
Set<Egress> existingEgresses = new HashSet<>(egressRepository.findAll());
|
||||
|
||||
Set<Egress> updatedEgresses = getUpdatedEgresses(existingEgresses, flattenedEgresses);
|
||||
|
||||
Set<Egress> newEgresses = flattenedEgresses.stream()
|
||||
.filter(egress -> !existingEgresses.contains(egress)).collect(toSet());
|
||||
Set<Egress> removedEgresses = existingEgresses.stream()
|
||||
.filter(egress -> !flattenedEgresses.contains(egress)).collect(toSet());
|
||||
|
||||
log.info("Egresses to be updated: {}",
|
||||
updatedEgresses.stream().map(Egress::toString).collect(toList()));
|
||||
log.info("New Egress to be added egresses: {}",
|
||||
newEgresses.stream().map(Egress::toString).collect(toList()));
|
||||
|
||||
@@ -74,6 +124,7 @@ class EgressServiceImpl implements EgressService {
|
||||
|
||||
if (!dryRun) {
|
||||
egressRepository.saveAll(newEgresses);
|
||||
egressRepository.saveAll(updatedEgresses);
|
||||
egressRepository.deleteAll(removedEgresses);
|
||||
} else {
|
||||
log.info("Dry run enabled, Skipping adding new egresses and "
|
||||
@@ -85,6 +136,21 @@ class EgressServiceImpl implements EgressService {
|
||||
return new EgressUpdateResponse(Map.of(), updatedEgress, dryRun);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EgressTagValidationResponse validateTags(List<EgressTagDto> egressTags) {
|
||||
var manifestInfo = manifestService.fetchManifestInfo();
|
||||
var manifestInfoSet = manifestInfo.stream().map(
|
||||
manifest -> String.format("%s:%s:%s", manifest.getName(), manifest.getTeam(),
|
||||
manifest.getEnvironment())).collect(toSet());
|
||||
var missingEgressTags = egressTags.stream().filter(
|
||||
egressTag -> {
|
||||
var manifestKey = String.format("%s:%s:%s", egressTag.getManifestName(),
|
||||
egressTag.getTeam(), egressTag.getManifestEnvironment());
|
||||
return !manifestInfoSet.contains(manifestKey);
|
||||
}).distinct().collect(toList());
|
||||
return new EgressTagValidationResponse(missingEgressTags);
|
||||
}
|
||||
|
||||
private Map<String, List<Egress>> validateDeleteEgress(Set<Egress> removedEgresses) {
|
||||
log.info("Validating egress list to be deleted: {}",
|
||||
removedEgresses.stream().map(Egress::toString).collect(toList()));
|
||||
@@ -98,7 +164,8 @@ class EgressServiceImpl implements EgressService {
|
||||
|
||||
private Map.Entry<String, List<Egress>> filterConflictingEgresses(
|
||||
Map.Entry<String, List<Egress>> manifestWithEgressList,
|
||||
Set<Egress> removedEgresses) {
|
||||
Set<Egress> removedEgresses
|
||||
) {
|
||||
List<Egress> conflictingEgresses = manifestWithEgressList.getValue().stream()
|
||||
.filter(removedEgresses::contains)
|
||||
.collect(toList());
|
||||
@@ -106,16 +173,17 @@ class EgressServiceImpl implements EgressService {
|
||||
}
|
||||
|
||||
private Map<String, List<Egress>> fetchConflictingManifestsWithEgressHostList(
|
||||
Map<String, List<Egress>> manifestWithEgressMap, Set<Egress> removedEgresses) {
|
||||
Map<String, List<Egress>> manifestWithEgressMap, Set<Egress> removedEgresses
|
||||
) {
|
||||
log.info("Fetching conflicting manifests with egress");
|
||||
return manifestWithEgressMap
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(manifestWithEgressList ->
|
||||
.map(manifestWithEgressList ->
|
||||
filterConflictingEgresses(manifestWithEgressList, removedEgresses))
|
||||
.filter(entry -> !entry.getValue().isEmpty())
|
||||
.peek(entry -> log.info("Manifest: {} contains following egress which are being "
|
||||
+ "deleted: {}", entry.getKey(), entry.getValue().stream().map(Egress::toString)
|
||||
+ "deleted: {}", entry.getKey(), entry.getValue().stream().map(Egress::toString)
|
||||
.collect(Collectors.toList())))
|
||||
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
@@ -129,13 +197,14 @@ class EgressServiceImpl implements EgressService {
|
||||
Manifest::fullName,
|
||||
manifest -> {
|
||||
EgressUpdateRequestData egressUpdateRequestData = new EgressUpdateRequestData();
|
||||
egressUpdateRequestData.setEgressData(convertEgressObjectToEgressDtoList(manifest.getEgress()));
|
||||
egressUpdateRequestData.setEgressData(
|
||||
convertEgressObjectToEgressDtoList(manifest.getEgress()));
|
||||
egressUpdateRequestData.setCluster(manifest.getCluster());
|
||||
return flattenEgresses(List.of(egressUpdateRequestData));
|
||||
}));
|
||||
}
|
||||
|
||||
private List<EgressDto> convertEgressObjectToEgressDtoList(Object egressList) {
|
||||
return objectMapper.convertValue(egressList, new TypeReference<List<EgressDto>>(){});
|
||||
return objectMapper.convertValue(egressList, new TypeReference<List<EgressDto>>() {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.navi.infra.portal.v2.egress;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
public class EgressTagDto {
|
||||
|
||||
@JsonProperty("owner_team")
|
||||
@NotNull
|
||||
private String team;
|
||||
|
||||
@JsonProperty("owner_manifest_name")
|
||||
@NotNull
|
||||
private String manifestName;
|
||||
|
||||
@JsonProperty("owner_vertical")
|
||||
@NotNull
|
||||
private String vertical;
|
||||
|
||||
@JsonProperty("owner_environment")
|
||||
@NotNull
|
||||
private String manifestEnvironment;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.navi.infra.portal.v2.egress;
|
||||
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
public class EgressTagValidationDto {
|
||||
|
||||
@NotNull
|
||||
private List<EgressTagDto> egressTagData;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.navi.infra.portal.v2.egress;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
public class EgressTagValidationResponse {
|
||||
|
||||
private List<EgressTagDto> conflictingTags;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public interface JitRequestsRepository extends JpaRepository<JitRequest, Long> {
|
||||
+ "AND (resource_type NOT IN ('AWS','GOCD','KUBERNETES') OR vertical = :vertical) "
|
||||
+ "AND team_id = :teamId "
|
||||
+ "AND ( (aws_resource_type is NULL AND :awsResourceType is NULL) OR aws_resource_type = CAST(:awsResourceType AS VARCHAR)) "
|
||||
+ "AND :grantAt BETWEEN grant_at AND grant_at + interval '1 hour' * grant_window "
|
||||
+ "AND ( :grantAt BETWEEN grant_at AND grant_at + interval '1 hour' * grant_window ) "
|
||||
+ "AND status IN ('PENDING','APPROVED')",
|
||||
nativeQuery = true)
|
||||
List<JitRequest> getDuplicateRequestsByUser(
|
||||
|
||||
@@ -5,6 +5,12 @@ metadata:
|
||||
values:
|
||||
- tier-0
|
||||
deployment:
|
||||
allowEndpoint:
|
||||
approvalFrom:
|
||||
- ENDPOINT_OWNER_TEAM
|
||||
forEach: {}
|
||||
hasHashedIdentifier: true
|
||||
|
||||
isVpaEnabled:
|
||||
approvalFrom: []
|
||||
values:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE egress ADD COLUMN IF NOT EXISTS vertical VARCHAR(255) NOT NULL DEFAULT 'NA';
|
||||
ALTER TABLE egress ADD COLUMN IF NOT EXISTS team VARCHAR(255) NOT NULL DEFAULT 'Shared';
|
||||
ALTER TABLE egress ADD COLUMN IF NOT EXISTS manifest_name VARCHAR(255) NOT NULL DEFAULT 'NA';
|
||||
ALTER TABLE egress ADD COLUMN IF NOT EXISTS manifest_environment VARCHAR(255) NOT NULL DEFAULT 'NA';
|
||||
@@ -1,13 +1,17 @@
|
||||
package com.navi.infra.portal.util;
|
||||
|
||||
import static com.navi.infra.portal.util.ListEqualIgnoringOrder.listEqualIgnoringOrder;
|
||||
import static com.navi.infra.portal.v2.changerequest.entity.RequestStatus.PENDING;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import com.navi.infra.portal.domain.user.User;
|
||||
import com.navi.infra.portal.util.manifest.ChangeRequestUtils;
|
||||
import com.navi.infra.portal.v2.changerequest.entity.ChangeRequestBuilder;
|
||||
import com.navi.infra.portal.v2.changerequest.service.ManifestLimitService;
|
||||
import com.navi.infra.portal.v2.changerequest.service.ManifestLimitServiceImpl;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
@@ -61,7 +65,7 @@ class ChangeRequestUtilTest {
|
||||
List<String> breachedList = ChangeRequestUtils.getChangeRequestTriggers(limitMap, null,
|
||||
mapWithAlreadyExceededLimits);
|
||||
var expectedViolations = List.of("maxAllocatedStorageInGb", "sizeInGb",
|
||||
"storageType", "iops", "multiAZDisabled", "loadBalancers", "database", "minCPU",
|
||||
"storageType", "iops", "multiAZDisabled", "loadBalancers[0]", "database", "minCPU",
|
||||
"isVpaEnabled", "minMemory", "maxReplicas", "minReplicas", "awsInstanceClass",
|
||||
"awsInstanceClass");
|
||||
MatcherAssert.assertThat(breachedList, listEqualIgnoringOrder(expectedViolations));
|
||||
@@ -84,7 +88,40 @@ class ChangeRequestUtilTest {
|
||||
mapWithNonBreaching,
|
||||
mapWithChangedLoadBalancerType);
|
||||
assertEquals(1, breachedList.size());
|
||||
assertEquals("loadBalancers", breachedList.get(0));
|
||||
assertEquals("loadBalancers[0]", breachedList.get(0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
@DisplayName("Should populate hashedIdentifier")
|
||||
void shouldPopulateHashedIdentifier() {
|
||||
Map<String, Object> diff = new HashMap<>();
|
||||
diff.put("path", "/deployment/allowEndpoint/*");
|
||||
diff.put("op", "op");
|
||||
diff.put("limitPath", "/deployment/allowEndpoint");
|
||||
Map<String, Object> valueMap = new HashMap<>();
|
||||
valueMap.put("host", "endpoint.one");
|
||||
valueMap.put("port", "4321");
|
||||
diff.put("value", valueMap);
|
||||
|
||||
final User user1 = new User();
|
||||
user1.setId(1L);
|
||||
user1.setName("foo");
|
||||
user1.setEmail("foo@bar.com");
|
||||
final var changeRequest = new ChangeRequestBuilder()
|
||||
.setId(1L)
|
||||
.setManifestId(1L)
|
||||
.setStatus(PENDING)
|
||||
.setCreatedBy(user1.getId())
|
||||
.setUpdatedBy(user1.getId())
|
||||
.setDiff(List.of(diff))
|
||||
.createChangeRequest();
|
||||
var result = ChangeRequestUtils.populateIdentifier(changeRequest);
|
||||
var populatedDiffValue = (Map<String, Object>) result.getDiff().get(0).get("value");
|
||||
var expectedIdentifier = "ZW5kcG9pbnQub25lOjQzMjE=";
|
||||
assertEquals(populatedDiffValue.get("hashedIdentifier"),
|
||||
expectedIdentifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import com.navi.infra.portal.domain.manifest.Manifest;
|
||||
import com.navi.infra.portal.domain.user.Team;
|
||||
import com.navi.infra.portal.domain.user.User;
|
||||
import com.navi.infra.portal.repository.ManifestRepository;
|
||||
import com.navi.infra.portal.service.manifest.ManifestService;
|
||||
import com.navi.infra.portal.service.user.PrivilegeUtilService;
|
||||
import com.navi.infra.portal.service.user.UserService;
|
||||
import com.navi.infra.portal.util.MapUtil;
|
||||
@@ -26,6 +26,8 @@ import com.navi.infra.portal.v2.approvalflow.entity.RequestType;
|
||||
import com.navi.infra.portal.v2.approvalflow.repository.ApprovalRequestRepository;
|
||||
import com.navi.infra.portal.v2.approvalflow.service.ApprovalRequestService;
|
||||
import com.navi.infra.portal.v2.approvalflow.service.ApprovalRequestServiceImpl;
|
||||
import com.navi.infra.portal.v2.approvalflow.util.AdditionalApproverTeam;
|
||||
import com.navi.infra.portal.v2.approvalflow.util.ApprovalRequestUtil;
|
||||
import com.navi.infra.portal.v2.changerequest.entity.ChangeRequestBuilder;
|
||||
import com.navi.infra.portal.v2.exception.NotFoundException;
|
||||
import com.navi.infra.portal.v2.jit.service.ChangeRequestSlackService;
|
||||
@@ -65,19 +67,21 @@ public class ApprovalRequestServiceImplTest {
|
||||
@Mock
|
||||
private TeamService teamService;
|
||||
@Mock
|
||||
private AdditionalApproverTeam additionalApproverTeam;
|
||||
private final ApprovalRequestUtil approvalRequestUtil = new ApprovalRequestUtil(
|
||||
additionalApproverTeam, mapUtil);
|
||||
@Mock
|
||||
private UserService userService;
|
||||
@Mock
|
||||
private ManifestService manifestService;
|
||||
@Mock
|
||||
private ApprovalRequestRepository repo;
|
||||
@Mock
|
||||
private PrivilegeUtilService privilegeUtilService;
|
||||
@Mock
|
||||
private ManifestLimitService manifestLimitService;
|
||||
@Mock
|
||||
private ManifestRepository manifestRepository;
|
||||
|
||||
@Mock
|
||||
private ChangeRequestService changeRequestService;
|
||||
|
||||
@Mock
|
||||
private TokenRequestService tokenRequestService;
|
||||
|
||||
@@ -109,8 +113,9 @@ public class ApprovalRequestServiceImplTest {
|
||||
.setRequestType(RequestType.CHANGE_REQUEST).setTeamId(team2.getId())
|
||||
.createApprovalRequest();
|
||||
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService, userService, manifestRepository, null, changeRequestService, null,
|
||||
privilegeUtilService, changeRequestSlackService,null);
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService, userService, manifestService,
|
||||
null, changeRequestService, null,
|
||||
privilegeUtilService, changeRequestSlackService, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -118,8 +123,9 @@ public class ApprovalRequestServiceImplTest {
|
||||
void approvalShouldFailIfAllApprovalsAreAlreadyDone() {
|
||||
when(repo.findPendingByRequestId(crId1)).thenReturn(Optional.empty());
|
||||
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService, userService, null, null, null, null,
|
||||
privilegeUtilService, changeRequestSlackService, null);
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService, userService, null, null, null,
|
||||
null,
|
||||
privilegeUtilService, changeRequestSlackService, null, null);
|
||||
|
||||
final var exception = assertThrows(NotFoundException.class,
|
||||
() -> service.allowApproveRequest(arId1, user1.getId()));
|
||||
@@ -147,11 +153,13 @@ public class ApprovalRequestServiceImplTest {
|
||||
when(repo.save(toBeSavedRequestApproval)).thenReturn(toBeSavedRequestApproval);
|
||||
when(repo.findAllPendingByRequestTypeAndRequestId(RequestType.CHANGE_REQUEST.code,
|
||||
requestApproval.getRequestId())).thenReturn(singletonList(new ApprovalRequest()));
|
||||
when(manifestRepository.findById(1L)).thenReturn(Optional.of(manifest));
|
||||
when(manifestService.fetchById(1L)).thenReturn(manifest);
|
||||
when(changeRequestService.findById(1L)).thenReturn(Optional.of(changeRequest));
|
||||
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService,userService, manifestRepository, null,
|
||||
changeRequestService, tokenRequestService, privilegeUtilService, changeRequestSlackService, null);
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService, userService, manifestService,
|
||||
null,
|
||||
changeRequestService, tokenRequestService, privilegeUtilService,
|
||||
changeRequestSlackService, null, null);
|
||||
|
||||
final var approvedRequest = service.allowApproveRequest(requestApproval.getId(),
|
||||
user1.getId());
|
||||
@@ -187,10 +195,10 @@ public class ApprovalRequestServiceImplTest {
|
||||
Optional.of(requestApproval1));
|
||||
when(changeRequestService.findById(requestApproval1.getId())).thenReturn(
|
||||
Optional.of(changeRequest));
|
||||
when(manifestRepository.findById(changeRequest.getManifestId())).thenReturn(
|
||||
Optional.of(manifest));
|
||||
when(changeRequestService.reject(requestApproval1.getRequestId())).thenReturn(changeRequest);
|
||||
when(manifestRepository.findById(1L)).thenReturn(Optional.of(manifest));
|
||||
when(manifestService.fetchById(changeRequest.getManifestId())).thenReturn(manifest);
|
||||
when(changeRequestService.reject(requestApproval1.getRequestId())).thenReturn(
|
||||
changeRequest);
|
||||
when(manifestService.fetchById(1L)).thenReturn(manifest);
|
||||
when(changeRequestService.findById(1L)).thenReturn(Optional.of(changeRequest));
|
||||
final var rejectedRequest = service.reject(requestApproval1.getId(),
|
||||
user1.getId());
|
||||
@@ -223,7 +231,6 @@ public class ApprovalRequestServiceImplTest {
|
||||
|
||||
final var oldApprovals = List.of(existingApprovalRequest1, existingApprovalRequest2);
|
||||
|
||||
|
||||
final var newApprovalRequest2 = new ApprovalRequestBuilder().from(ar1).setId(null)
|
||||
.setTeamId(team2.getId()).setRequestType(RequestType.CHANGE_REQUEST)
|
||||
.createApprovalRequest();
|
||||
@@ -231,16 +238,15 @@ public class ApprovalRequestServiceImplTest {
|
||||
final var savedNewApprovalRequest2 = new ApprovalRequestBuilder().from(newApprovalRequest2)
|
||||
.setId(3L).createApprovalRequest();
|
||||
|
||||
when(repo.findByRequestIdAndType(changeRequest.getId(), RequestType.CHANGE_REQUEST.code)).thenReturn(oldApprovals);
|
||||
when(repo.findByRequestIdAndType(changeRequest.getId(),
|
||||
RequestType.CHANGE_REQUEST.code)).thenReturn(oldApprovals);
|
||||
when(teamService.findByNames(argThat(
|
||||
listMatches(List.of(team1.getName(), team2.getName(), team3.getName()))))).thenReturn(
|
||||
List.of(team1, team2, team3));
|
||||
|
||||
when(manifestRepository.findById(changeRequest.getManifestId())).thenReturn(
|
||||
Optional.of(manifest));
|
||||
when(manifestService.fetchById(changeRequest.getManifestId())).thenReturn(manifest);
|
||||
|
||||
when(manifestRepository.findById(changeRequest.getManifestId())).thenReturn(
|
||||
Optional.of(manifest));
|
||||
when(manifestService.fetchById(changeRequest.getManifestId())).thenReturn(manifest);
|
||||
//noinspection unchecked
|
||||
when(manifestLimitService.getLimit(manifest.getEnvironment())).thenReturn(limitMap);
|
||||
|
||||
@@ -249,15 +255,16 @@ public class ApprovalRequestServiceImplTest {
|
||||
newApprovalRequest2))))).thenReturn(
|
||||
List.of(existingApprovalRequest1, existingApprovalRequest2, savedNewApprovalRequest2));
|
||||
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService,userService, manifestRepository,
|
||||
manifestLimitService, null, null, privilegeUtilService, changeRequestSlackService, mapUtil);
|
||||
service = new ApprovalRequestServiceImpl(repo, teamService, userService, manifestService,
|
||||
manifestLimitService, null, null, privilegeUtilService, changeRequestSlackService,
|
||||
approvalRequestUtil, mapUtil);
|
||||
|
||||
service.createApprovals(changeRequest);
|
||||
|
||||
verify(repo).findByRequestIdAndType(changeRequest.getId(), RequestType.CHANGE_REQUEST.code);
|
||||
verify(teamService).findByNames(argThat(
|
||||
listMatches(List.of(team1.getName(), team2.getName(), team3.getName()))));
|
||||
verify(manifestRepository).findById(changeRequest.getManifestId());
|
||||
verify(manifestService).fetchById(changeRequest.getManifestId());
|
||||
verify(manifestLimitService).getLimit(manifest.getEnvironment());
|
||||
verify(repo).saveAll(
|
||||
argThat(listMatches(List.of(existingApprovalRequest1, existingApprovalRequest2,
|
||||
@@ -265,6 +272,7 @@ public class ApprovalRequestServiceImplTest {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Custom argument matcher to check if the lists have the same content, disregarding order
|
||||
private <T> ArgumentMatcher<List<T>> listMatches(List<T> expectedList) {
|
||||
return actualList -> expectedList.containsAll(actualList) && actualList.containsAll(
|
||||
|
||||
@@ -197,10 +197,14 @@ class ChangeRequestServiceImplTest {
|
||||
approval2ChangeRequest2
|
||||
);
|
||||
|
||||
final var approvalDto1 = new ApprovalRequestDto(1L, "teamname", user1.getEmail(), new Date(), 1L, PENDING);
|
||||
final var approvalDto2 = new ApprovalRequestDto(2L, "teamname", user1.getEmail(), new Date(), 1L, APPROVED);
|
||||
final var approvalDto3 = new ApprovalRequestDto(3L, "teamname", user2.getEmail(), new Date(), 2L, PENDING);
|
||||
final var approvalDto4 = new ApprovalRequestDto(4L, "teamname", user2.getEmail(), new Date(), 2L, PENDING);
|
||||
final var approvalDto1 = new ApprovalRequestDto(1L, "teamname", user1.getEmail(),
|
||||
new Date(), 1L, PENDING);
|
||||
final var approvalDto2 = new ApprovalRequestDto(2L, "teamname", user1.getEmail(),
|
||||
new Date(), 1L, APPROVED);
|
||||
final var approvalDto3 = new ApprovalRequestDto(3L, "teamname", user2.getEmail(),
|
||||
new Date(), 2L, PENDING);
|
||||
final var approvalDto4 = new ApprovalRequestDto(4L, "teamname", user2.getEmail(),
|
||||
new Date(), 2L, PENDING);
|
||||
final var approvalDtoList = List.of(
|
||||
approvalDto1,
|
||||
approvalDto2,
|
||||
@@ -215,7 +219,8 @@ class ChangeRequestServiceImplTest {
|
||||
manifest2.setId(2L);
|
||||
manifest2.setData(data);
|
||||
|
||||
when(approvalRequestService.findAllByRequestTypeAndTeamIds(RequestType.CHANGE_REQUEST,teamIds)).thenReturn(List.of(
|
||||
when(approvalRequestService.findAllByRequestTypeAndTeamIds(RequestType.CHANGE_REQUEST,
|
||||
teamIds)).thenReturn(List.of(
|
||||
approvedApproval,
|
||||
approval1ChangeRequest1,
|
||||
approval2ChangeRequest1,
|
||||
@@ -224,7 +229,8 @@ class ChangeRequestServiceImplTest {
|
||||
));
|
||||
when(repo.findPendingByIds(changeRequestList)).thenReturn(
|
||||
List.of(changeRequest1, changeRequest2));
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,changeRequestList)).thenReturn(
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,
|
||||
changeRequestList)).thenReturn(
|
||||
approvalList);
|
||||
when(manifestService.fetchById(changeRequest1.getManifestId())).thenReturn(manifest1);
|
||||
when(manifestService.fetchById(changeRequest2.getManifestId())).thenReturn(manifest2);
|
||||
@@ -294,10 +300,14 @@ class ChangeRequestServiceImplTest {
|
||||
approval2ChangeRequest2
|
||||
);
|
||||
|
||||
final var approvalDto1 = new ApprovalRequestDto(1L, "teamname", user1.getEmail(), new Date(),1L, PENDING);
|
||||
final var approvalDto2 = new ApprovalRequestDto(2L, "teamname",user1.getEmail(), new Date(), 1L, APPROVED);
|
||||
final var approvalDto3 = new ApprovalRequestDto(3L, "teamname", user2.getEmail(), new Date(),2L, PENDING);
|
||||
final var approvalDto4 = new ApprovalRequestDto(4L, "teamname", user2.getEmail(), new Date(),2L, PENDING);
|
||||
final var approvalDto1 = new ApprovalRequestDto(1L, "teamname", user1.getEmail(),
|
||||
new Date(), 1L, PENDING);
|
||||
final var approvalDto2 = new ApprovalRequestDto(2L, "teamname", user1.getEmail(),
|
||||
new Date(), 1L, APPROVED);
|
||||
final var approvalDto3 = new ApprovalRequestDto(3L, "teamname", user2.getEmail(),
|
||||
new Date(), 2L, PENDING);
|
||||
final var approvalDto4 = new ApprovalRequestDto(4L, "teamname", user2.getEmail(),
|
||||
new Date(), 2L, PENDING);
|
||||
final var approvalDtoList = List.of(
|
||||
approvalDto1,
|
||||
approvalDto2,
|
||||
@@ -315,7 +325,8 @@ class ChangeRequestServiceImplTest {
|
||||
when(repo.findById(sampleCrId)).thenReturn(Optional.of(sampleChangeRequest1));
|
||||
when(repo.findById(changeRequest1.getId())).thenReturn(Optional.of(changeRequest1));
|
||||
when(repo.findById(changeRequest2.getId())).thenReturn(Optional.of(changeRequest2));
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,changeRequestList)).thenReturn(
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,
|
||||
changeRequestList)).thenReturn(
|
||||
approvalList);
|
||||
when(manifestService.fetchById(changeRequest1.getManifestId())).thenReturn(manifest1);
|
||||
when(manifestService.fetchById(changeRequest2.getManifestId())).thenReturn(manifest2);
|
||||
@@ -355,7 +366,8 @@ class ChangeRequestServiceImplTest {
|
||||
.setUpdatedBy(user1.getId())
|
||||
.setDiff(List.of(diff))
|
||||
.createChangeRequest();
|
||||
final var changeRequestList = List.of(changeRequestApproved.getId(), changeRequest1.getId());
|
||||
final var changeRequestList = List.of(changeRequestApproved.getId(),
|
||||
changeRequest1.getId());
|
||||
final var approvedApproval = new ApprovalRequestBuilder()
|
||||
.setId(0L)
|
||||
.setStatus(APPROVED)
|
||||
@@ -388,12 +400,14 @@ class ChangeRequestServiceImplTest {
|
||||
manifest2.setId(2L);
|
||||
manifest2.setData(data);
|
||||
|
||||
when(approvalRequestService.findAllByRequestTypeAndTeamIds(RequestType.CHANGE_REQUEST,teamIds)).thenReturn(List.of(
|
||||
when(approvalRequestService.findAllByRequestTypeAndTeamIds(RequestType.CHANGE_REQUEST,
|
||||
teamIds)).thenReturn(List.of(
|
||||
approvedApproval,
|
||||
approval1ChangeRequest1,
|
||||
approval2ChangeRequest1
|
||||
));
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,changeRequestList)).thenReturn(
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,
|
||||
changeRequestList)).thenReturn(
|
||||
approvalList);
|
||||
when(securityContext.getAuthentication()).thenReturn(authentication);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
@@ -469,10 +483,14 @@ class ChangeRequestServiceImplTest {
|
||||
approval2ChangeRequest2
|
||||
);
|
||||
|
||||
final var approvalDto1 = new ApprovalRequestDto(1L, "teamname", user1.getEmail(), new Date(), 1L, PENDING);
|
||||
final var approvalDto2 = new ApprovalRequestDto(2L, "teamname", user1.getEmail(), new Date(), 1L, APPROVED);
|
||||
final var approvalDto3 = new ApprovalRequestDto(3L, "teamname", user2.getEmail(), new Date(), 2L, PENDING);
|
||||
final var approvalDto4 = new ApprovalRequestDto(4L, "teamname", user2.getEmail(), new Date(), 2L, PENDING);
|
||||
final var approvalDto1 = new ApprovalRequestDto(1L, "teamname", user1.getEmail(),
|
||||
new Date(), 1L, PENDING);
|
||||
final var approvalDto2 = new ApprovalRequestDto(2L, "teamname", user1.getEmail(),
|
||||
new Date(), 1L, APPROVED);
|
||||
final var approvalDto3 = new ApprovalRequestDto(3L, "teamname", user2.getEmail(),
|
||||
new Date(), 2L, PENDING);
|
||||
final var approvalDto4 = new ApprovalRequestDto(4L, "teamname", user2.getEmail(),
|
||||
new Date(), 2L, PENDING);
|
||||
final var approvalDtoList = List.of(
|
||||
approvalDto1,
|
||||
approvalDto2,
|
||||
@@ -487,7 +505,8 @@ class ChangeRequestServiceImplTest {
|
||||
manifest2.setId(2L);
|
||||
manifest2.setData(data);
|
||||
|
||||
when(approvalRequestService.findAllByRequestTypeAndTeamIds(RequestType.CHANGE_REQUEST,teamIds)).thenReturn(List.of(
|
||||
when(approvalRequestService.findAllByRequestTypeAndTeamIds(RequestType.CHANGE_REQUEST,
|
||||
teamIds)).thenReturn(List.of(
|
||||
approvedApproval,
|
||||
approval1ChangeRequest1,
|
||||
approval2ChangeRequest1,
|
||||
@@ -496,7 +515,8 @@ class ChangeRequestServiceImplTest {
|
||||
));
|
||||
when(repo.findPendingByIds(changeRequestList)).thenReturn(
|
||||
List.of(changeRequest1, changeRequest2));
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,changeRequestList)).thenReturn(
|
||||
when(approvalRequestService.findAllByRequestTypeAndRequestIds(RequestType.CHANGE_REQUEST,
|
||||
changeRequestList)).thenReturn(
|
||||
approvalList);
|
||||
when(manifestService.fetchById(changeRequest1.getManifestId())).thenReturn(manifest1);
|
||||
when(manifestService.fetchById(changeRequest2.getManifestId())).thenThrow(
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EgressControllerTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Mock
|
||||
@@ -38,32 +39,66 @@ class EgressControllerTest {
|
||||
return egressDto;
|
||||
}
|
||||
|
||||
private static EgressUpdateRequestData getEgressUpdateRequestData(String cluster,
|
||||
List<EgressDto> egressData) {
|
||||
private static EgressDto getEgressDto(
|
||||
String host, String port, String team,
|
||||
String vertical, String manifestEnvironment, String manifestName
|
||||
) {
|
||||
return new EgressDto(
|
||||
host, port, team, vertical, manifestEnvironment, manifestName);
|
||||
}
|
||||
|
||||
private static EgressUpdateRequestData getEgressUpdateRequestData(
|
||||
String cluster,
|
||||
List<EgressDto> egressData
|
||||
) {
|
||||
EgressUpdateRequestData egressUpdateRequestData = new EgressUpdateRequestData();
|
||||
egressUpdateRequestData.setCluster(cluster);
|
||||
egressUpdateRequestData.setEgressData(egressData);
|
||||
return egressUpdateRequestData;
|
||||
}
|
||||
|
||||
private static List<EgressDto> getEgressDtoList() {
|
||||
private static List<EgressDto> getRequestEgressDtoList() {
|
||||
return List.of(getEgressDto("test1.com", "8080", "team1", "vertical1", "env1",
|
||||
"manifest1"),
|
||||
getEgressDto("test2.com", "8081", "team2", "vertical2", "evn2",
|
||||
"manifest2"),
|
||||
getEgressDto("test3.com", "8082", "team3", "vertical3", "env3",
|
||||
"manifest3"));
|
||||
}
|
||||
|
||||
|
||||
private static List<EgressDto> getResponseEgressDtoList() {
|
||||
return List.of(getEgressDto("test1.com", "8080"),
|
||||
getEgressDto("test2.com", "8081"),
|
||||
getEgressDto("test3.com", "8082"));
|
||||
}
|
||||
|
||||
private static Egress getEgress(String host, String port, String cluster) {
|
||||
private static Egress getEgress(
|
||||
String host, String port, String cluster, String team,
|
||||
String vertical, String manifestEnvironment, String manifestName
|
||||
) {
|
||||
Egress egress = new Egress();
|
||||
egress.setHost(host);
|
||||
egress.setPort(port);
|
||||
egress.setCluster(cluster);
|
||||
egress.setTeam(team);
|
||||
egress.setVertical(vertical);
|
||||
egress.setManifestEnvironment(manifestEnvironment);
|
||||
egress.setManifestName(manifestName);
|
||||
return egress;
|
||||
}
|
||||
|
||||
private static List<Egress> getEgressList() {
|
||||
return List.of(getEgress("test1.com", "8080", "spike.np.navi-tech.in"),
|
||||
getEgress("test2.com", "8081", "spike.np.navi-tech.in"),
|
||||
getEgress("test3.com", "8082", "spike.np.navi-tech.in"));
|
||||
private static List<Egress> getEgressList() {
|
||||
return List.of(
|
||||
getEgress("test1.com", "8080", "spike.np.navi-tech.in",
|
||||
"team1", "vertical1", "env1",
|
||||
"manifest1"),
|
||||
getEgress("test2.com", "8081", "prod.cmd.navi-tech.in",
|
||||
"team2", "vertical2", "evn2",
|
||||
"manifest2"),
|
||||
getEgress("test3.com", "8082", "aps1.prod.navi-tech.in",
|
||||
"team3", "vertical3", "env3",
|
||||
"manifest3"));
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@@ -78,10 +113,11 @@ class EgressControllerTest {
|
||||
@Nested
|
||||
@DisplayName("GET /api/egress")
|
||||
class GetEgressTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("GET /api/egress - 200")
|
||||
void shouldGetEgress() throws Exception {
|
||||
List<EgressDto> egresses = getEgressDtoList();
|
||||
List<EgressDto> egresses = getResponseEgressDtoList();
|
||||
String expectedJson = objectMapper.writeValueAsString(egresses);
|
||||
final String cluster = "test-cluster";
|
||||
when(egressService.getEgresses("test-cluster")).thenReturn(egresses);
|
||||
@@ -113,7 +149,7 @@ class EgressControllerTest {
|
||||
@Test
|
||||
@DisplayName("POST /api/egress - 200")
|
||||
void shouldUpdateEgress() throws Exception {
|
||||
List<EgressDto> egresses = getEgressDtoList();
|
||||
List<EgressDto> egresses = getRequestEgressDtoList();
|
||||
EgressUpdateRequest egressUpdateRequest = new EgressUpdateRequest();
|
||||
List<EgressUpdateRequestData> egressUpdateRequestData =
|
||||
List.of(getEgressUpdateRequestData("spike.np.navi-tech.in", egresses));
|
||||
@@ -136,7 +172,7 @@ class EgressControllerTest {
|
||||
@Test
|
||||
@DisplayName("POST /api/egress - 400 Bad Request Reason: Invalid cluster name")
|
||||
void shouldThrowBadRequestOnInvalidCluster() throws Exception {
|
||||
List<EgressDto> egresses = getEgressDtoList();
|
||||
List<EgressDto> egresses = getRequestEgressDtoList();
|
||||
List<EgressUpdateRequestData> egressUpdateRequestData =
|
||||
List.of(getEgressUpdateRequestData("spke.np.navi-tech.in", egresses));
|
||||
EgressUpdateRequest egressUpdateRequest = new EgressUpdateRequest();
|
||||
@@ -165,7 +201,7 @@ class EgressControllerTest {
|
||||
@Test
|
||||
@DisplayName("POST /api/egress - 500 Internal Server Error")
|
||||
void shouldUpdateEgressInterServerError() throws Exception {
|
||||
List<EgressDto> egresses = getEgressDtoList();
|
||||
List<EgressDto> egresses = getRequestEgressDtoList();
|
||||
List<EgressUpdateRequestData> egressUpdateRequestData =
|
||||
List.of(getEgressUpdateRequestData("spike.np.navi-tech.in", egresses));
|
||||
EgressUpdateRequest egressUpdateRequest = new EgressUpdateRequest();
|
||||
@@ -173,8 +209,6 @@ class EgressControllerTest {
|
||||
boolean dryRun = true;
|
||||
when(egressService.updateEgresses(egressUpdateRequestData, dryRun))
|
||||
.thenThrow(new RuntimeException());
|
||||
String expectedJson = objectMapper.writeValueAsString(egressUpdateRequest);
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/api/egress?dryRun=" + dryRun)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(egressUpdateRequest)))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.navi.infra.portal.v2.egress;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -9,10 +8,12 @@ import static org.mockito.Mockito.when;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.navi.infra.portal.service.manifest.ManifestService;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -34,41 +35,58 @@ class EgressServiceImplTest {
|
||||
|
||||
private EgressService egressService;
|
||||
|
||||
private static EgressDto getEgressDto(String host, String port) {
|
||||
EgressDto egressDto = new EgressDto();
|
||||
egressDto.setHost(host);
|
||||
egressDto.setPort(port);
|
||||
return egressDto;
|
||||
|
||||
private static EgressDto getEgressDto(
|
||||
String host, String port, String team,
|
||||
String vertical, String manifestEnvironment, String manifestName
|
||||
) {
|
||||
return new EgressDto(
|
||||
host, port, team, vertical, manifestEnvironment, manifestName);
|
||||
}
|
||||
|
||||
private static EgressUpdateRequestData getEgressUpdateRequestData(String cluster,
|
||||
List<EgressDto> egressData) {
|
||||
private static EgressUpdateRequestData getEgressUpdateRequestData(
|
||||
String cluster,
|
||||
List<EgressDto> egressData
|
||||
) {
|
||||
EgressUpdateRequestData egressUpdateRequestData = new EgressUpdateRequestData();
|
||||
egressUpdateRequestData.setCluster(cluster);
|
||||
egressUpdateRequestData.setEgressData(egressData);
|
||||
return egressUpdateRequestData;
|
||||
}
|
||||
|
||||
private static List<EgressDto> getEgressDtoList() {
|
||||
return List.of(getEgressDto("test1.com", "8080"),
|
||||
getEgressDto("test2.com", "8081"),
|
||||
getEgressDto("test3.com", "8082"));
|
||||
}
|
||||
|
||||
private static Egress getEgress(String host, String port, String cluster) {
|
||||
private static Egress getEgress(
|
||||
String host, String port, String cluster, String team,
|
||||
String vertical, String manifestEnvironment, String manifestName
|
||||
) {
|
||||
Egress egress = new Egress();
|
||||
egress.setHost(host);
|
||||
egress.setPort(port);
|
||||
egress.setCluster(cluster);
|
||||
egress.setTeam(team);
|
||||
egress.setVertical(vertical);
|
||||
egress.setManifestEnvironment(manifestEnvironment);
|
||||
egress.setManifestName(manifestName);
|
||||
return egress;
|
||||
}
|
||||
|
||||
private static List<Egress> getEgressList() {
|
||||
return List.of(getEgress("test1.com", "8080", "spike.np.navi-tech.in"),
|
||||
getEgress("test2.com", "8081", "prod.cmd.navi-tech.in"),
|
||||
getEgress("test3.com", "8082", "aps1.prod.navi-tech.in"));
|
||||
private static List<Egress> getEgressList() {
|
||||
return List.of(
|
||||
getEgress("test1.com", "8080", "spike.np.navi-tech.in",
|
||||
"team1", "vertical1", "env1",
|
||||
"manifest1"),
|
||||
getEgress("test2.com", "8081", "prod.cmd.navi-tech.in",
|
||||
"team2", "vertical2", "evn2",
|
||||
"manifest2"),
|
||||
getEgress("test3.com", "8082", "aps1.prod.navi-tech.in",
|
||||
"team3", "vertical3", "env3",
|
||||
"manifest3"));
|
||||
}
|
||||
|
||||
private static Egress getEgress(EgressDto egressDto, String cluster) {
|
||||
return new Egress(egressDto.getHost(), egressDto.getPort(), cluster,
|
||||
egressDto.getVertical(), egressDto.getTeam(), egressDto.getManifestName(),
|
||||
egressDto.getManifestEnvironment());
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
@@ -79,13 +97,12 @@ class EgressServiceImplTest {
|
||||
@DisplayName("should get egresses")
|
||||
void shouldGetEgresses() {
|
||||
String cluster = "test-cluster";
|
||||
List<EgressDto> egresses = List.of(getEgressDto("test1.com", "8080"),
|
||||
getEgressDto("test2.com", "8081"),
|
||||
getEgressDto("test3.com", "8082"));
|
||||
var egresses = getEgressList();
|
||||
var egressDtos = egresses.stream().map(EgressDto::new).collect(Collectors.toList());
|
||||
when(egressRepository.findByCluster(cluster)).thenReturn(egresses);
|
||||
List<EgressDto> result = egressService.getEgresses(cluster);
|
||||
verify(egressRepository, times(1)).findByCluster(cluster);
|
||||
assertEquals(egresses, result);
|
||||
assertEquals(egressDtos, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,11 +110,14 @@ class EgressServiceImplTest {
|
||||
void shouldAddEgresses() {
|
||||
List<EgressUpdateRequestData> egressUpdateRequestData = new ArrayList<>();
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("spike.np.navi-tech.in",
|
||||
List.of(getEgressDto("test1.com", "8080"))));
|
||||
List.of(getEgressDto("test1.com", "8080", "team1", "vertical1", "env1",
|
||||
"manifest1"))));
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("prod.cmd.navi-tech.in",
|
||||
List.of(getEgressDto("test2.com", "8081"))));
|
||||
List.of(getEgressDto("test2.com", "8081", "team2", "vertical2", "evn2",
|
||||
"manifest2"))));
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("aps1.prod.navi-tech.in",
|
||||
List.of(getEgressDto("test3.com", "8082"))));
|
||||
List.of(getEgressDto("test3.com", "8082", "team3", "vertical3", "env3",
|
||||
"manifest3"))));
|
||||
List<Egress> egresses = getEgressList();
|
||||
Set<Egress> newEgresses = new HashSet<>(egresses);
|
||||
boolean dryRun = false;
|
||||
@@ -106,7 +126,8 @@ class EgressServiceImplTest {
|
||||
verify(egressRepository, times(1)).saveAll(newEgresses);
|
||||
verify(egressRepository, times(1)).deleteAll(Set.of());
|
||||
verify(egressRepository, times(2)).findAll();
|
||||
EgressUpdateResponse egressUpdateResponse = new EgressUpdateResponse(Map.of(), egresses, dryRun);
|
||||
EgressUpdateResponse egressUpdateResponse = new EgressUpdateResponse(Map.of(), egresses,
|
||||
dryRun);
|
||||
assertEquals(egressUpdateResponse, result);
|
||||
}
|
||||
|
||||
@@ -115,11 +136,14 @@ class EgressServiceImplTest {
|
||||
void shouldNotUpdateRepositoryWhenDryRunIsTrue() {
|
||||
List<EgressUpdateRequestData> egressUpdateRequestData = new ArrayList<>();
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("spike.np.navi-tech.in",
|
||||
List.of(getEgressDto("test1.com", "8080"))));
|
||||
List.of(getEgressDto("test1.com", "8080", "team1", "vertical1", "env1",
|
||||
"manifest1"))));
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("prod.cmd.navi-tech.in",
|
||||
List.of(getEgressDto("test2.com", "8081"))));
|
||||
List.of(getEgressDto("test2.com", "8081", "team2", "vertical2", "evn2",
|
||||
"manifest2"))));
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("aps1.prod.navi-tech.in",
|
||||
List.of(getEgressDto("test3.com", "8082"))));
|
||||
List.of(getEgressDto("test3.com", "8082", "team3", "vertical3", "env3",
|
||||
"manifest3"))));
|
||||
List<Egress> egresses = getEgressList();
|
||||
Set<Egress> newEgresses = new HashSet<>(egresses);
|
||||
boolean dryRun = true;
|
||||
@@ -128,7 +152,43 @@ class EgressServiceImplTest {
|
||||
verify(egressRepository, times(0)).saveAll(newEgresses);
|
||||
verify(egressRepository, times(0)).deleteAll(Set.of());
|
||||
verify(egressRepository, times(1)).findAll();
|
||||
EgressUpdateResponse egressUpdateResponse = new EgressUpdateResponse(Map.of(), List.of(), dryRun);
|
||||
EgressUpdateResponse egressUpdateResponse = new EgressUpdateResponse(Map.of(), List.of(),
|
||||
dryRun);
|
||||
assertEquals(egressUpdateResponse, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should update egress which differs in fields other than host, port, cluster")
|
||||
void shouldUpdateEgressWhichDiffersInFieldsOtherThanHostPortCluster() {
|
||||
List<EgressUpdateRequestData> egressUpdateRequestData = new ArrayList<>();
|
||||
var updatedEgressDto1 = getEgressDto("test1.com", "8080", "team4", "vertical1", "env1",
|
||||
"manifest1");
|
||||
var updatedEgressDto2 = getEgressDto("test2.com", "8081", "team6", "vertical2", "evn2",
|
||||
"manifest6");
|
||||
var updatedEgressDto3 = getEgressDto("test3.com", "8082", "team7", "vertical3", "env3",
|
||||
"manifest7");
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("spike.np.navi-tech.in",
|
||||
List.of(updatedEgressDto1)));
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("prod.cmd.navi-tech.in",
|
||||
List.of(updatedEgressDto2)));
|
||||
egressUpdateRequestData.add(getEgressUpdateRequestData("aps1.prod.navi-tech.in",
|
||||
List.of(updatedEgressDto3)));
|
||||
Set<Egress> newEgresses = new HashSet<>(List.of(
|
||||
getEgress(updatedEgressDto1, "spike.np.navi-tech.in"),
|
||||
getEgress(updatedEgressDto2, "prod.cmd.navi-tech.in"),
|
||||
getEgress(updatedEgressDto3, "aps1.prod.navi-tech.in")
|
||||
));
|
||||
List<Egress> egresses = getEgressList();
|
||||
|
||||
boolean dryRun = false;
|
||||
when(egressRepository.findAll()).thenReturn(egresses);
|
||||
EgressUpdateResponse result = egressService.updateEgresses(egressUpdateRequestData, dryRun);
|
||||
verify(egressRepository, times(1)).saveAll(Collections.emptySet());
|
||||
verify(egressRepository, times(1)).saveAll(newEgresses);
|
||||
verify(egressRepository, times(1)).deleteAll(Set.of());
|
||||
verify(egressRepository, times(2)).findAll();
|
||||
EgressUpdateResponse egressUpdateResponse = new EgressUpdateResponse(Map.of(), egresses,
|
||||
dryRun);
|
||||
assertEquals(egressUpdateResponse, result);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,11 @@ deployment:
|
||||
- Infra
|
||||
values:
|
||||
- false
|
||||
allowEndpoint:
|
||||
approvalFrom:
|
||||
- ENDPOINT_OWNER_TEAM
|
||||
forEach: {}
|
||||
hasHashedIdentifier: true
|
||||
instance:
|
||||
minCPU:
|
||||
approvalFrom:
|
||||
|
||||
@@ -4,6 +4,11 @@ deployment:
|
||||
- Infra
|
||||
values:
|
||||
- false
|
||||
allowEndpoint:
|
||||
approvalFrom:
|
||||
- ENDPOINT_OWNER_TEAM
|
||||
forEach: {}
|
||||
hasHashedIdentifier: true
|
||||
instance:
|
||||
minCPU:
|
||||
approvalFrom:
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"op": "op",
|
||||
"path": "/deployment/allowEndpoint/*",
|
||||
"limitPath": "/deployment/allowEndpoint",
|
||||
"value": {
|
||||
"host": "endpoint.one",
|
||||
"port": "4321"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -15,3 +15,8 @@ deployment:
|
||||
- team2
|
||||
values:
|
||||
- 0.0.0.0/0
|
||||
allowEndpoint:
|
||||
approvalFrom:
|
||||
- ENDPOINT_OWNER_TEAM
|
||||
forEach: { }
|
||||
hasHashedIdentifier: true
|
||||
|
||||
Reference in New Issue
Block a user