16 package org.openkilda.testing.service.traffexam;
18 import static java.util.Collections.unmodifiableMap;
41 import net.jodah.failsafe.Failsafe;
42 import net.jodah.failsafe.RetryPolicy;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.beans.factory.DisposableBean;
46 import org.springframework.beans.factory.annotation.Autowired;
47 import org.springframework.beans.factory.annotation.Qualifier;
48 import org.springframework.http.HttpStatus;
49 import org.springframework.stereotype.Service;
50 import org.springframework.web.client.HttpStatusCodeException;
51 import org.springframework.web.client.RestClientException;
52 import org.springframework.web.client.RestTemplate;
53 import org.springframework.web.util.UriBuilder;
54 import org.springframework.web.util.UriComponentsBuilder;
56 import java.net.Inet4Address;
58 import java.net.URISyntaxException;
59 import java.net.UnknownHostException;
60 import java.util.ArrayList;
61 import java.util.HashMap;
62 import java.util.InputMismatchException;
63 import java.util.LinkedList;
64 import java.util.List;
66 import java.util.UUID;
67 import java.util.concurrent.TimeUnit;
68 import javax.annotation.PostConstruct;
76 @Qualifier(
"traffExamRestTemplate")
77 private RestTemplate restTemplate;
82 private Map<UUID, Host> hostsPool;
85 private Map<UUID, Address> suppliedAddresses =
new HashMap<>();
86 private Map<UUID, HostResource> suppliedEndpoints =
new HashMap<>();
87 private List<HostResource> failedToRelease =
new LinkedList<>();
89 private final RetryPolicy retryPolicy =
new RetryPolicy()
90 .withDelay(1, TimeUnit.SECONDS)
94 void initializePools() {
95 hostsPool =
new HashMap<>();
97 for (TraffGen traffGen : topology.getActiveTraffGens()) {
100 controlEndpoint =
new URI(traffGen.getControlEndpoint());
101 }
catch (URISyntaxException e) {
102 throw new IllegalArgumentException(String.format(
103 "Invalid traffGen(%s) REST endpoint address \"%s\": %s",
104 traffGen.getName(), traffGen.getControlEndpoint(), e.getMessage()), e);
107 UUID
id = UUID.randomUUID();
108 Host host =
new Host(
id, traffGen.getIfaceName(), controlEndpoint, traffGen.getName());
111 restTemplate.headForHeaders(makeHostUri(
host).
path(
"endpoint").
build());
112 }
catch (RestClientException ex) {
113 throw new IllegalArgumentException(String.format(
114 "The traffGen(%s) REST endpoint address \"%s\" can't be reached: %s",
115 traffGen.getName(), traffGen.getControlEndpoint(), ex.getMessage()), ex);
118 hostsPool.put(
id,
host);
120 hostsPool = unmodifiableMap(hostsPool);
122 TraffGenConfig
config = topology.getTraffGenConfig();
126 (Inet4Address) Inet4Address.getByName(
config.getAddressPoolBase()),
127 config.getAddressPoolPrefixLen());
129 throw new InputMismatchException(String.format(
130 "Invalid traffGen address pool \"%s:%s\": %s",
131 config.getAddressPoolBase(),
config.getAddressPoolPrefixLen(), e));
138 return new ArrayList<>(hostsPool.values());
144 throw new IllegalArgumentException(
"Argument \"name\" must not be null");
148 for (
Host current : hostsPool.values()) {
149 if (!
name.equals(current.getName())) {
165 checkHostPresence(exam.getSource());
166 checkHostPresence(exam.getDest());
172 throw new OperationalException(
"Unable to allocate subnet for exam. There is no more addresses available.");
176 List<HostResource> supplied =
new ArrayList<>(4);
178 Address sourceAddress =
new Address(subnet.address(1), subnet.getPrefix(), exam.getSourceVlan());
179 sourceAddress = assignAddress(exam.getSource(), sourceAddress);
180 supplied.add(sourceAddress);
182 Address destAddress =
new Address(subnet.address(2), subnet.getPrefix(), exam.getDestVlan());
183 destAddress = assignAddress(exam.getDest(), destAddress);
184 supplied.add(destAddress);
190 sourceAddress.
getId(),
192 if (exam.getBandwidthLimit() != null) {
193 producer.setBandwidth(exam.getBandwidthLimit());
194 producer.setBurstPkt(exam.getBurstPkt());
196 if (exam.getTimeLimitSeconds() != null) {
197 producer.setTime(exam.getTimeLimitSeconds());
206 "Insufficient resources - not enough IP address in subnet. Check addressPool configuration.");
208 if (resources == null) {
209 extendFailedToRelease(releaseResources(supplied));
212 addressPool.free(subnet);
244 EndpointReport producerReport = fetchEndpointReport(resources.getProducer());
247 consumerReport = fetchEndpointReport(resources.getConsumer());
249 if (producerReport.getError() == null) {
252 consumerReport =
new EndpointReport(
"Don't wait for consumer report due to error on producer side");
255 return new ExamReport(exam, producerReport, consumerReport);
261 List<HostResource> releaseQueue =
new ArrayList<>(4);
263 releaseQueue.add(resources.getProducer());
264 releaseQueue.add(resources.getConsumer());
269 addressId = resources.getProducer().getBindAddressId();
270 if (addressId != null) {
271 address = suppliedAddresses.get(addressId);
272 checkHostRelation(address, suppliedAddresses);
273 releaseQueue.add(address);
275 addressId = resources.getConsumer().getBindAddressId();
276 if (addressId != null) {
277 address = suppliedAddresses.get(addressId);
278 checkHostRelation(address, suppliedAddresses);
279 releaseQueue.add(address);
282 List<HostResource> failed = releaseResources(releaseQueue);
285 retryResourceRelease();
287 extendFailedToRelease(failed);
293 List<HostResource> releaseQueue =
new LinkedList<>();
295 releaseQueue.addAll(suppliedEndpoints.values());
296 releaseQueue.addAll(suppliedAddresses.values());
298 releaseQueue = releaseResources(releaseQueue);
300 retryResourceRelease();
302 extendFailedToRelease(releaseQueue);
318 suppliedAddresses.put(address.
getId(), address);
323 private void releaseAddress(Address subject) {
325 makeHostUri(subject.getHost())
327 .path(subject.getId().toString()).
build());
329 suppliedAddresses.remove(subject.getId());
333 private <T extends Endpoint> T assignEndpoint(Host
host, T payload) {
334 EndpointResponse response = restTemplate.postForObject(
336 payload, EndpointResponse.class);
338 @SuppressWarnings(
"unchecked")
339 T endpoint = (T) response.endpoint;
340 endpoint.setHost(
host);
341 suppliedEndpoints.put(endpoint.getId(), endpoint);
346 private
void releaseEndpoint(Endpoint endpoint) {
348 makeHostUri(endpoint.getHost())
350 .path(endpoint.getId().toString())
353 suppliedEndpoints.remove(endpoint.getId());
356 private EndpointReport fetchEndpointReport(Endpoint endpoint)
357 throws NoResultsFoundException, ExamNotFinishedException {
358 checkHostRelation(endpoint, suppliedEndpoints);
360 ReportResponse report = restTemplate.getForObject(
361 makeHostUri(endpoint.getHost())
363 .path(endpoint.getId().toString())
364 .
path(
"/report").build(),
365 ReportResponse.class);
366 if (report.getStatus() == null) {
367 throw new ExamNotFinishedException();
370 return new EndpointReport(report);
373 private synchronized void retryResourceRelease() {
374 failedToRelease = releaseResources(failedToRelease);
377 private List<HostResource> releaseResources(List<HostResource> resources) {
378 List<HostResource> fail =
new LinkedList<>();
380 for (HostResource item : resources) {
382 if (item instanceof Address) {
383 releaseAddress((Address) item);
384 }
else if (item instanceof Endpoint) {
385 releaseEndpoint((Endpoint) item);
387 throw new RuntimeException(
"Unsupported resource");
389 }
catch (HttpStatusCodeException e) {
390 if (e.getStatusCode() != HttpStatus.NOT_FOUND) {
393 }
catch (RestClientException e) {
401 private synchronized void extendFailedToRelease(List<HostResource> resources) {
402 failedToRelease.addAll(resources);
405 private ExamResources retrieveExamResources(Exam exam)
throws NoResultsFoundException {
406 ExamResources resources = exam.getResources();
407 if (resources == null) {
408 throw new IllegalArgumentException(
"Exam resources are empty.");
410 checkExamRelation(resources);
415 private void checkExamRelation(ExamResources resources)
throws NoResultsFoundException {
416 checkHostRelation(resources.getProducer(), suppliedEndpoints);
417 checkHostRelation(resources.getConsumer(), suppliedEndpoints);
420 private void checkHostRelation(
421 HostResource
target, Map<UUID, ? extends HostResource> supplied)
422 throws NoResultsFoundException {
423 if (!supplied.containsKey(
target.getId())) {
424 throw new NoResultsFoundException(
425 "Object is not supplied by this service.");
427 if (
target.getHost() == null) {
428 throw new NoResultsFoundException(
429 "Object have no link to the host object.");
433 private void checkHostPresence(Host subject)
434 throws NoResultsFoundException {
435 if (!hostsPool.containsKey(subject.getId())) {
436 throw new NoResultsFoundException(String.format(
437 "There is no host with id \"%s\"", subject.getId()));
441 private UriBuilder makeHostUri(Host
host) {
442 return UriComponentsBuilder.fromUri(
host.getApiAddress());
ExamReport waitExam(Exam exam, boolean cleanup)
ExamResources startExam(Exam exam)
ExamReport waitExam(Exam exam)
Host hostByName(String name)
ExamReport fetchReport(Exam exam)