Skip to content
Snippets Groups Projects
Commit a8cc73c9 authored by kbeyro's avatar kbeyro
Browse files

Merge remote-tracking branch 'origin/develop' into develop

parents b76b2c03 293da2fd
No related branches found
No related tags found
2 merge requests!273Release 1.8.0 update,!203Resolve "Add option to select target remote cluster for instance deployment"
Pipeline #94270 passed
Showing
with 244 additions and 10 deletions
......@@ -88,7 +88,6 @@ dependencies {
implementation('org.springframework.boot:spring-boot-starter-mail')
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.springframework.boot:spring-boot-starter-actuator')
implementation('org.springframework.boot:spring-boot-devtools')
implementation('org.springframework.boot:spring-boot-starter-quartz')
implementation('org.springframework.boot:spring-boot-starter-validation')
implementation 'org.springframework.boot:spring-boot-starter-cache'
......
package net.geant.nmaas.orchestration.jobs;
import lombok.extern.slf4j.Slf4j;
import net.geant.nmaas.orchestration.exceptions.WebServiceCommunicationException;
import net.geant.nmaas.portal.api.domain.DomainGroupView;
import net.geant.nmaas.portal.api.domain.DomainGroupWebhookDto;
import net.geant.nmaas.portal.api.domain.WebhookEventDto;
import net.geant.nmaas.portal.api.exception.MissingElementException;
import net.geant.nmaas.portal.persistent.entity.WebhookEventType;
import net.geant.nmaas.portal.service.WebhookEventService;
import org.modelmapper.ModelMapper;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import java.security.GeneralSecurityException;
@Slf4j
@Component
public class DomainGroupJob extends WebhookJob {
@Autowired
public DomainGroupJob(RestClient restClient, WebhookEventService webhookEventService, ModelMapper modelMapper) {
super(restClient, webhookEventService, modelMapper);
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
Long webhookId = dataMap.getLong("webhookId");
String action = dataMap.getString("action");
DomainGroupView domainGroup = (DomainGroupView) dataMap.get("domainGroup");
try {
WebhookEventDto webhook = webhookEventService.getById(webhookId);
if (!WebhookEventType.DOMAIN_GROUP_CHANGE.equals(webhook.getEventType())) {
log.warn("Webhook's event type with id {} has been updated. DomainGroupJob is abandoned", webhookId);
return;
}
DomainGroupWebhookDto view = new DomainGroupWebhookDto(domainGroup, action);
callWebhook(webhook, view);
} catch (GeneralSecurityException e) {
log.error("Failed to decrypt webhook with id {}", webhookId);
throw new JobExecutionException("Failed webhook decryption");
} catch (MissingElementException e) {
log.warn("Webhook does not exist. DomainGroupJob is abandoned");
} catch (WebServiceCommunicationException e) {
log.error("Failed to communicate with external system for the webhoook of domain group with id {}", domainGroup.getId());
throw new JobExecutionException("Failed communication with external system");
}
}
}
......@@ -3,9 +3,11 @@ package net.geant.nmaas.portal.api.domain;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
public class ApplicationStatePerDomainView {
public class ApplicationStatePerDomainView implements Serializable {
Long applicationBaseId;
String applicationBaseName;
boolean enabled;
......
......@@ -4,10 +4,12 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@NoArgsConstructor
public class DomainBase {
public class DomainBase implements Serializable {
Long id;
String name;
......
......@@ -6,6 +6,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
......@@ -13,7 +14,7 @@ import java.util.List;
@NoArgsConstructor
@Getter
@Setter
public class DomainGroupView {
public class DomainGroupView implements Serializable {
@NotNull
private Long id;
......
package net.geant.nmaas.portal.api.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
@Getter
@Setter
public class DomainGroupWebhookDto {
private DomainGroupView domainGroup;
private String action;
}
......@@ -67,7 +67,7 @@ public class DomainGroup implements Serializable {
public DomainGroup(String name, String codename) {
super();
this.name = name;
this.codename = name;
this.codename = codename;
}
public DomainGroup(Long id, String name, String codename) {
......
......@@ -2,6 +2,8 @@ package net.geant.nmaas.portal.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.geant.nmaas.orchestration.jobs.DomainCreationJob;
import net.geant.nmaas.orchestration.jobs.DomainGroupJob;
import net.geant.nmaas.portal.api.domain.ApplicationStatePerDomainView;
import net.geant.nmaas.portal.api.domain.DomainGroupView;
import net.geant.nmaas.portal.api.exception.MissingElementException;
......@@ -11,16 +13,21 @@ import net.geant.nmaas.portal.persistent.entity.ApplicationStatePerDomain;
import net.geant.nmaas.portal.persistent.entity.Domain;
import net.geant.nmaas.portal.persistent.entity.DomainGroup;
import net.geant.nmaas.portal.persistent.entity.User;
import net.geant.nmaas.portal.persistent.entity.WebhookEventType;
import net.geant.nmaas.portal.persistent.repositories.DomainGroupRepository;
import net.geant.nmaas.portal.persistent.repositories.WebhookEventRepository;
import net.geant.nmaas.portal.service.ApplicationStatePerDomainService;
import net.geant.nmaas.portal.service.DomainGroupService;
import net.geant.nmaas.scheduling.ScheduleManager;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
......@@ -31,6 +38,8 @@ public class DomainGroupServiceImpl implements DomainGroupService {
private final DomainGroupRepository domainGroupRepository;
private final ApplicationStatePerDomainService applicationStatePerDomainService;
private final WebhookEventRepository webhookEventRepository;
private final ScheduleManager scheduleManager;
private final ModelMapper modelMapper;
......@@ -55,6 +64,10 @@ public class DomainGroupServiceImpl implements DomainGroupService {
DomainGroup domainGroupEntity = modelMapper.map(domainGroup, DomainGroup.class);
domainGroupEntity.setApplicationStatePerDomain(applicationStatePerDomainList);
domainGroupEntity = domainGroupRepository.save(domainGroupEntity);
//call existing webhooks
DomainGroupView domainGroupView = modelMapper.map(domainGroupEntity, DomainGroupView.class);
webhookEventRepository.findIdByEventType(WebhookEventType.DOMAIN_GROUP_CHANGE).forEach(id -> scheduleManager.createOneTimeJob(DomainGroupJob.class, "DomainGroup_" + id + "_" + domainGroupView.getId()+ "_" + LocalDateTime.now(), Map.of("webhookId", id, "action", "create","domainGroup",domainGroupView)));
return modelMapper.map(domainGroupEntity, DomainGroupView.class);
}
......@@ -81,6 +94,7 @@ public class DomainGroupServiceImpl implements DomainGroupService {
@Override
public void deleteDomainGroup(Long domainGroupId) {
DomainGroup domainGroup = domainGroupRepository.findById(domainGroupId).orElseThrow();
DomainGroupView domainGroupView = modelMapper.map(domainGroup, DomainGroupView.class);
List<Domain> toRemove = new ArrayList<>(domainGroup.getDomains());
Iterator<Domain> iterator = toRemove.iterator();
while (iterator.hasNext()) {
......@@ -90,6 +104,8 @@ public class DomainGroupServiceImpl implements DomainGroupService {
iterator.remove();
}
domainGroupRepository.deleteById(domainGroupId);
//call existing webhooks
webhookEventRepository.findIdByEventType(WebhookEventType.DOMAIN_GROUP_CHANGE).forEach(id -> scheduleManager.createOneTimeJob(DomainGroupJob.class, "DomainGroup_" + id + "_" + domainGroup.getId()+ "_" + LocalDateTime.now(), Map.of("webhookId", id, "action", "delete","domainGroup",domainGroupView)));
}
@Override
......@@ -128,7 +144,11 @@ public class DomainGroupServiceImpl implements DomainGroupService {
}
domainGroupRepository.save(domainGroup);
return modelMapper.map(domainGroup, DomainGroupView.class);
//call existing webhooks
DomainGroupView domainGroupView = modelMapper.map(domainGroup, DomainGroupView.class);
webhookEventRepository.findIdByEventType(WebhookEventType.DOMAIN_GROUP_CHANGE).forEach(id -> scheduleManager.createOneTimeJob(DomainGroupJob.class, "DomainGroup_" + id + "_" + domainGroupView.getId()+ "_" + LocalDateTime.now(), Map.of("webhookId", id, "action", "update","domainGroup",domainGroupView)));
return domainGroupView;
}
protected void checkParam(DomainGroupView domainGroup) {
......
package net.geant.nmaas.portal.service.impl;
import net.geant.nmaas.orchestration.jobs.DomainGroupJob;
import net.geant.nmaas.portal.api.domain.DomainGroupView;
import net.geant.nmaas.portal.persistent.entity.DomainGroup;
import net.geant.nmaas.portal.persistent.entity.WebhookEvent;
import net.geant.nmaas.portal.persistent.entity.WebhookEventType;
import net.geant.nmaas.portal.persistent.repositories.DomainGroupRepository;
import net.geant.nmaas.portal.persistent.repositories.WebhookEventRepository;
import net.geant.nmaas.portal.service.ApplicationStatePerDomainService;
import net.geant.nmaas.portal.service.DomainGroupService;
import net.geant.nmaas.scheduling.ScheduleManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.modelmapper.ModelMapper;
import org.quartz.JobListener;
import org.quartz.ListenerManager;
import org.quartz.Matcher;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import java.util.Optional;
import java.util.stream.Stream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class DomainGroupServiceTest {
DomainGroupRepository domainGroupRepository = mock(DomainGroupRepository.class);
ApplicationStatePerDomainService applicationStatePerDomainService = mock(ApplicationStatePerDomainService.class);
WebhookEventRepository webhookEventRepository = mock(WebhookEventRepository.class);
Scheduler scheduler = mock(Scheduler.class);
ListenerManager listenerManager = mock(ListenerManager.class);
ScheduleManager scheduleManager;
ModelMapper modelMapper = new ModelMapper();
DomainGroupService domainGroupService;
@BeforeEach
void setup() {
scheduleManager = new ScheduleManager(scheduler);
domainGroupService = new DomainGroupServiceImpl(domainGroupRepository, applicationStatePerDomainService, webhookEventRepository, scheduleManager, modelMapper);
}
@Test
void shouldCreateDomainGroup() throws SchedulerException {
// Setup webhook event
WebhookEvent webhookEvent = new WebhookEvent(1L, "webhook", "https://example.com/webhook", WebhookEventType.DOMAIN_GROUP_CHANGE, null, null);
when(webhookEventRepository.findIdByEventType(WebhookEventType.DOMAIN_GROUP_CHANGE))
.thenReturn(Stream.of(1L));
when(webhookEventRepository.findById(1L))
.thenReturn(Optional.of(webhookEvent));
// Setup domain group
String name = "testgroup";
String codename = "testgrp";
DomainGroup domainGroup = new DomainGroup(name, codename);
domainGroup.setId(10L);
when(domainGroupRepository.save(any(DomainGroup.class))).thenReturn(domainGroup);
when(domainGroupRepository.findById(10L)).thenReturn(Optional.of(domainGroup));
when(scheduler.getListenerManager()).thenReturn(listenerManager);
doNothing().when(listenerManager).addJobListener(any(JobListener.class), any(Matcher.class));
// Create domain group
DomainGroupView domainGroupView = new DomainGroupView();
domainGroupView.setName(name);
domainGroupView.setCodename(codename);
DomainGroupView result = this.domainGroupService.createDomainGroup(domainGroupView);
// Verify webhook job was scheduled with correct parameters for creation
verify(scheduler, times(1)).scheduleJob(
argThat(jobDetail ->
jobDetail.getKey().getName().startsWith("DomainGroup_1_10_") &&
jobDetail.getJobClass().equals(DomainGroupJob.class)
),
argThat(trigger ->
trigger.getKey().getName().startsWith("DomainGroup_1_10_")
)
);
// Verify domain group was created correctly
assertThat("Codenames are not the same", result.getCodename().equals(codename));
assertThat("Names are not the same", result.getName().equals(name));
// Update domain group
when(webhookEventRepository.findIdByEventType(WebhookEventType.DOMAIN_GROUP_CHANGE))
.thenReturn(Stream.of(1L));
when(webhookEventRepository.findById(1L))
.thenReturn(Optional.of(webhookEvent));
domainGroupView.setCodename(codename + "2");
domainGroupView.setId(10L);
result = this.domainGroupService.updateDomainGroup(10L, domainGroupView);
// Verify webhook job was scheduled with correct parameters for update
verify(scheduler, times(2)).scheduleJob(
argThat(jobDetail ->
jobDetail.getKey().getName().startsWith("DomainGroup_1_10_") &&
jobDetail.getJobClass().equals(DomainGroupJob.class)
),
argThat(trigger ->
trigger.getKey().getName().startsWith("DomainGroup_1_10_")
)
);
// Verify domain group was updated correctly
assertThat("Updated codenames are not the same", result.getCodename().equals(codename + "2"));
assertThat("Names are not the same after update", result.getName().equals(name));
}
@Test
void shouldDeleteDomainGroup() throws SchedulerException {
// Setup webhook event
WebhookEvent webhookEvent = new WebhookEvent(1L, "webhook", "https://example.com/webhook", WebhookEventType.DOMAIN_GROUP_CHANGE, null, null);
when(webhookEventRepository.findIdByEventType(WebhookEventType.DOMAIN_GROUP_CHANGE))
.thenReturn(Stream.of(1L));
when(webhookEventRepository.findById(1L))
.thenReturn(Optional.of(webhookEvent));
DomainGroup domainGroup = new DomainGroup("testgroup", "testgrp");
domainGroup.setId(10L);
when(domainGroupRepository.findById(10L)).thenReturn(Optional.of(domainGroup));
when(scheduler.getListenerManager()).thenReturn(listenerManager);
doNothing().when(listenerManager).addJobListener(any(JobListener.class), any(Matcher.class));
this.domainGroupService.deleteDomainGroup(10L);
verify(domainGroupRepository, times(1)).deleteById(10L);
verify(scheduler, times(1)).scheduleJob(
argThat(jobDetail ->
jobDetail.getKey().getName().startsWith("DomainGroup_1_10_") &&
jobDetail.getJobClass().equals(DomainGroupJob.class)
),
argThat(trigger ->
trigger.getKey().getName().startsWith("DomainGroup_1_10_")
)
);
}
}
......@@ -94,8 +94,6 @@ class DomainServiceTest {
Scheduler scheduler = mock(Scheduler.class);
ListenerManager listenerManager = mock(ListenerManager.class);
ScheduleManager scheduleManager;
EncryptionService encryptionService = mock(EncryptionService.class);
WebhookEventService webhookEventService;
DomainService domainService;
......@@ -103,15 +101,14 @@ class DomainServiceTest {
void setup() {
validator = new DefaultCodenameValidator("[a-z-]{2,12}");
namespaceValidator = new DefaultCodenameValidator("[a-z-]{0,64}");
domainGroupService = new DomainGroupServiceImpl(domainGroupRepository, applicationStatePerDomainService, modelMapper);
scheduleManager = new ScheduleManager( scheduler);
domainGroupService = new DomainGroupServiceImpl(domainGroupRepository, applicationStatePerDomainService, webhookEventRepository, scheduleManager, modelMapper);
domainService = new DomainServiceImpl(validator,
namespaceValidator, domainRepository,
domainDcnDetailsRepository, domainTechDetailsRepository, userService,
userRoleRepo, dcnRepositoryManager,
modelMapper, applicationStatePerDomainService, domainGroupService, eventPublisher, domainAnnotationsRepository, webhookEventRepository, scheduleManager);
((DomainServiceImpl) domainService).globalDomain = "GLOBAL";
webhookEventService = new WebhookEventService(webhookEventRepository, encryptionService, modelMapper);
}
@Test
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment