diff --git a/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/CacheController.java b/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/CacheController.java index 8ffaab2c8..41ffe111b 100644 --- a/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/CacheController.java +++ b/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/CacheController.java @@ -39,6 +39,7 @@ import java.util.stream.Stream; +@io.swagger.annotations.Api(tags = "Cache") @RestController @RequestMapping(path = "/cache", produces = Api.API_MIME_TYPE) @Slf4j diff --git a/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/ClientsController.java b/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/ClientsController.java index ddeece462..84bafcf9d 100644 --- a/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/ClientsController.java +++ b/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/api/ClientsController.java @@ -41,6 +41,7 @@ import java.util.Comparator; import java.util.stream.Stream; +@io.swagger.annotations.Api(tags = "Clients") @RestController @RequestMapping(path = "/clients", produces = Api.API_MIME_TYPE) @Slf4j diff --git a/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/config/SwaggerConfig.java b/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/config/SwaggerConfig.java index 97d9763e4..d3fd9ced2 100644 --- a/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/config/SwaggerConfig.java +++ b/rpki-rtr-server/src/main/java/net/ripe/rpki/rtr/config/SwaggerConfig.java @@ -40,6 +40,7 @@ import springfox.documentation.schema.AlternateTypeRule; import springfox.documentation.schema.AlternateTypeRules; import springfox.documentation.schema.WildcardType; +import springfox.documentation.service.Tag; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @@ -66,8 +67,12 @@ public Docket api() { .directModelSubstitute(URI.class, String.class) .directModelSubstitute(Links.class, Object.class) .genericModelSubstitutes(Optional.class) + .tags( + new Tag("Cache", "Cache status"), + new Tag("Clients", "Client status") + ) .select() - .apis(RequestHandlerSelectors.any()) + .apis(RequestHandlerSelectors.basePackage("net.ripe")) .paths(PathSelectors.any()) .build(); } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiError.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiError.java index e13afb7d2..762b93d72 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiError.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiError.java @@ -30,6 +30,7 @@ package net.ripe.rpki.validator3.api; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Builder; import lombok.Value; import org.springframework.http.HttpStatus; @@ -38,9 +39,12 @@ @Builder @ApiModel(value = "Error") public class ApiError { + @ApiModelProperty(value = "(HTTP) status code", example = "500", required = true) String status; String code; + @ApiModelProperty(value = "Reason for the error", example = "Internal Server Error", required = true) String title; + @ApiModelProperty(value = "More detailed description of the error", required = false) String detail; ApiErrorSource source; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiErrorHandler.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiErrorHandler.java index 6cfb5fdb7..e29ff3bc6 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiErrorHandler.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ApiErrorHandler.java @@ -58,7 +58,7 @@ public class ApiErrorHandler extends ResponseEntityExceptionHandler { @ExceptionHandler(value = DataRetrievalFailureException.class) protected ResponseEntity> handleDataRetrievalFailureException(DataRetrievalFailureException ex, WebRequest request) { HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.valueOf(Api.API_MIME_TYPE)); + headers.setContentType(MediaType.valueOf(ValidatorApi.API_MIME_TYPE)); return new ResponseEntity<>(ApiResponse.error(ApiError.of(HttpStatus.NOT_FOUND)), headers, HttpStatus.NOT_FOUND); } @@ -77,7 +77,7 @@ protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotV .build() ).collect(Collectors.toList()); return ResponseEntity.badRequest() - .contentType(MediaType.valueOf(Api.API_MIME_TYPE)) + .contentType(MediaType.valueOf(ValidatorApi.API_MIME_TYPE)) .body(ApiResponse.error(errors)); } @@ -102,7 +102,7 @@ protected ResponseEntity handleMethodArgumentNotValidException(MethodArg ) .build(); return ResponseEntity.badRequest() - .contentType(MediaType.valueOf(Api.API_MIME_TYPE)) + .contentType(MediaType.valueOf(ValidatorApi.API_MIME_TYPE)) .body(ApiResponse.error(error)); } } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/InternalApiCall.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/InternalApiCall.java new file mode 100644 index 000000000..53f2a2f77 --- /dev/null +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/InternalApiCall.java @@ -0,0 +1,38 @@ +/** + * The BSD License + * + * Copyright (c) 2010-2018 RIPE NCC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the RIPE NCC nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package net.ripe.rpki.validator3.api; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface InternalApiCall { +} diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ModelPropertyDescriptions.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ModelPropertyDescriptions.java new file mode 100644 index 000000000..120149345 --- /dev/null +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ModelPropertyDescriptions.java @@ -0,0 +1,63 @@ +/** + * The BSD License + * + * Copyright (c) 2010-2018 RIPE NCC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the RIPE NCC nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package net.ripe.rpki.validator3.api; + +public class ModelPropertyDescriptions { + public static final String ASN_EXAMPLE = "3333"; + public static final String ASN_PROPERTY = "ASN to match (without AS prefix)"; + + public static final String ASN_PREFIXED_PROPERTY = "ASN to match (with AS prefix)"; + public static final String ASN_PREFIXED_EXAMPLE = "AS3333"; + + public static final String ASN_LIST_PROPERTY = "List of ASNs (without prefix)"; + + public static final String ORIGIN_PROPERTY = "Origin AS (without AS prefix)"; + public static final String ORIGIN_PREFIXED_PROPERTY = "Origin AS (with AS prefix)"; + + public static final String PREFIX_EXAMPLE = "193.0.0.0/21"; + + /** + * The inputs for @see net.ripe.rpki.validator3.api.Sorting#parse + */ + public static final String SORT_DIRECTION_ALLOWABLE_VALUES = "asc, desc"; + public static final String SORT_BY_ALLOWABLE_VALUES = "prefix, asn, ta, key, location, status, validity, type, lastchecked, comment, maximumlength"; + + /** + * @see net.ripe.rpki.validator3.api.bgp.BgpPreviewService.Validity + */ + public static final String VALIDITY_ALLOWABLE_VALUES = "UNKNOWN, VALID, INVALID_ASN, INVALID_LENGTH"; + + public static final String SOURCE_TRUST_ANCHOR = "source (name of Trust Anchor)"; + + public static final String TRUST_ANCHOR = "Name of trust anchor"; + public static final String TRUST_ANCHOR_EXAMPLE = "RIPE NCC RPKI Root"; + + public static final String MAXLENGTH_PROPERTY = "Maxlength (>= prefix size)"; +} diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/PublicApiCall.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/PublicApiCall.java new file mode 100644 index 000000000..38fb667e5 --- /dev/null +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/PublicApiCall.java @@ -0,0 +1,38 @@ +/** + * The BSD License + * + * Copyright (c) 2010-2018 RIPE NCC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the RIPE NCC nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package net.ripe.rpki.validator3.api; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface PublicApiCall { +} diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/Api.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ValidatorApi.java similarity index 96% rename from rpki-validator/src/main/java/net/ripe/rpki/validator3/api/Api.java rename to rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ValidatorApi.java index c653f71ee..8aaac756f 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/Api.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ValidatorApi.java @@ -29,10 +29,10 @@ */ package net.ripe.rpki.validator3.api; -public class Api { +public class ValidatorApi { public static final String API_MIME_TYPE = "application/vnd.net.ripe.rpki.validator.v3+json; charset=UTF-8"; public static final long MINIMUM_VALID_ID = 1; - private Api() {} + private ValidatorApi() {} } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewController.java index 6a6719005..c4720db4e 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewController.java @@ -29,16 +29,13 @@ */ package net.ripe.rpki.validator3.api.bgp; +import io.swagger.annotations.*; import lombok.Value; import lombok.extern.slf4j.Slf4j; import net.ripe.ipresource.Asn; import net.ripe.ipresource.IpRange; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.*; import net.ripe.rpki.validator3.api.ApiResponse; -import net.ripe.rpki.validator3.api.Metadata; -import net.ripe.rpki.validator3.api.Paging; -import net.ripe.rpki.validator3.api.SearchTerm; -import net.ripe.rpki.validator3.api.Sorting; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; @@ -51,9 +48,15 @@ import java.util.function.Supplier; import java.util.stream.Stream; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.*; + +@PublicApiCall @RestController -@RequestMapping(path = "/api/bgp", produces = {Api.API_MIME_TYPE, "application/json"}) +@RequestMapping(path = "/api/bgp", produces = {ValidatorApi.API_MIME_TYPE, "application/json"}) @Slf4j +@Api( + tags ="BGP preview" +) public class BgpPreviewController { @Autowired @@ -64,7 +67,9 @@ public ResponseEntity>> list( @RequestParam(name = "startFrom", defaultValue = "0") long startFrom, @RequestParam(name = "pageSize", defaultValue = "20") long pageSize, @RequestParam(name = "search", defaultValue = "", required = false) String searchString, + @ApiParam(allowableValues = SORT_BY_ALLOWABLE_VALUES) @RequestParam(name = "sortBy", defaultValue = "prefix") String sortBy, + @ApiParam(allowableValues = SORT_DIRECTION_ALLOWABLE_VALUES) @RequestParam(name = "sortDirection", defaultValue = "asc") String sortDirection ) { final SearchTerm searchTerm = StringUtils.isNotBlank(searchString) ? new SearchTerm(searchString) : null; @@ -108,8 +113,10 @@ private static T arg(Supplier s) { @Value(staticConstructor = "of") public static class BgpPreview { + @ApiModelProperty(value = ASN_PREFIXED_PROPERTY, example = ASN_PREFIXED_EXAMPLE) private String asn; private String prefix; + @ApiModelProperty(allowableValues = VALIDITY_ALLOWABLE_VALUES) private String validity; } } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewService.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewService.java index 92968c625..0d1540ea7 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewService.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/bgp/BgpPreviewService.java @@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedSet; +import io.swagger.annotations.ApiModelProperty; import lombok.extern.slf4j.Slf4j; import net.ripe.ipresource.Asn; import net.ripe.ipresource.IpRange; @@ -74,6 +75,7 @@ import static java.util.Comparator.comparing; import static java.util.Comparator.comparingInt; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.*; @Service @Slf4j @@ -109,10 +111,13 @@ public static class BgpPreviewResult { @lombok.Value(staticConstructor = "of") public static class ValidatingRoa { + @ApiModelProperty(value = ORIGIN_PROPERTY, example = ASN_EXAMPLE) String origin; String prefix; + @ApiModelProperty(allowableValues = VALIDITY_ALLOWABLE_VALUES) String validity; Integer maxLength; + @ApiModelProperty(SOURCE_TRUST_ANCHOR) String source; String uri; Long roaPrefixAssertionId; @@ -121,16 +126,21 @@ public static class ValidatingRoa { @lombok.Value(staticConstructor = "of") public static class BgpValidity { + @ApiModelProperty(value = ORIGIN_PREFIXED_PROPERTY, example = ASN_PREFIXED_EXAMPLE) String origin; String prefix; + @ApiModelProperty(allowableValues = VALIDITY_ALLOWABLE_VALUES) String validity; List validatingRoas; } @lombok.Value(staticConstructor = "of") public static class BgpValidityWithFilteredResource { + @ApiModelProperty(value = ORIGIN_PREFIXED_PROPERTY, example = ASN_PREFIXED_EXAMPLE) String origin; + @ApiModelProperty(example = PREFIX_EXAMPLE) String prefix; + @ApiModelProperty(allowableValues = VALIDITY_ALLOWABLE_VALUES) String validity; List validatingRoas; List filteredRoas; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/health/HealthController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/health/HealthController.java index 3d4b4a043..19bbe5001 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/health/HealthController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/health/HealthController.java @@ -29,11 +29,13 @@ */ package net.ripe.rpki.validator3.api.health; +import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiResponse; +import net.ripe.rpki.validator3.api.InternalApiCall; import net.ripe.rpki.validator3.api.bgp.BgpPreviewService; import net.ripe.rpki.validator3.api.bgp.BgpRisDump; import net.ripe.rpki.validator3.api.trustanchors.TaStatus; @@ -52,14 +54,14 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalUnit; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +@InternalApiCall @RestController -@RequestMapping(path = "/api/healthcheck", produces = {Api.API_MIME_TYPE, "application/json"}) +@RequestMapping(path = "/api/healthcheck", produces = {ValidatorApi.API_MIME_TYPE, "application/json"}) @Slf4j public class HealthController { @@ -78,9 +80,9 @@ public class HealthController { @Autowired private Storage storage; + @ApiOperation("Get result of validator health checks") @GetMapping public ResponseEntity> health() { - try { final List trustAnchorReady = storage.readTx(tx -> trustAnchors.getStatuses(tx)) .stream() diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/AddIgnoreFilter.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/AddIgnoreFilter.java index cd4873f42..c2c6c06c2 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/AddIgnoreFilter.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/AddIgnoreFilter.java @@ -32,6 +32,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Builder; import lombok.Data; +import net.ripe.rpki.validator3.api.ModelPropertyDescriptions; import net.ripe.rpki.validator3.domain.constraints.ValidAddIgnoreFilter; import net.ripe.rpki.validator3.domain.constraints.ValidAsn; import net.ripe.rpki.validator3.domain.constraints.ValidPrefix; @@ -40,12 +41,11 @@ @Builder @ValidAddIgnoreFilter public class AddIgnoreFilter { - - @ApiModelProperty(position = 1) + @ApiModelProperty(position = 1, value = ModelPropertyDescriptions.ASN_PROPERTY, example = ModelPropertyDescriptions.ASN_EXAMPLE) @ValidAsn String asn; - @ApiModelProperty(position = 2) + @ApiModelProperty(position = 2, example = ModelPropertyDescriptions.PREFIX_EXAMPLE) @ValidPrefix String prefix; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/IgnoreFiltersController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/IgnoreFiltersController.java index 49b2a4198..bbacfad67 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/IgnoreFiltersController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/ignorefilters/IgnoreFiltersController.java @@ -29,14 +29,11 @@ */ package net.ripe.rpki.validator3.api.ignorefilters; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; -import net.ripe.rpki.validator3.api.ApiCommand; -import net.ripe.rpki.validator3.api.ApiResponse; -import net.ripe.rpki.validator3.api.Metadata; -import net.ripe.rpki.validator3.api.Paging; -import net.ripe.rpki.validator3.api.SearchTerm; -import net.ripe.rpki.validator3.api.Sorting; +import net.ripe.rpki.validator3.api.*; import net.ripe.rpki.validator3.api.roas.ObjectController; import net.ripe.rpki.validator3.domain.IgnoreFiltersPredicate; import net.ripe.rpki.validator3.domain.validation.ValidatedRpkiObjects; @@ -63,9 +60,11 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; +@PublicApiCall @RestController @Slf4j -@RequestMapping(path = "/api/ignore-filters", produces = { Api.API_MIME_TYPE, "application/json" }) +@Api(tags = "Ignore filters") +@RequestMapping(path = "/api/ignore-filters", produces = { ValidatorApi.API_MIME_TYPE, "application/json" }) public class IgnoreFiltersController { @Autowired @@ -74,12 +73,16 @@ public class IgnoreFiltersController { @Autowired private ValidatedRpkiObjects validatedRpkiObjects; + @ApiOperation("Get ignore filters (matching parameters)") @GetMapping public ResponseEntity>> list( @RequestParam(name = "startFrom", defaultValue = "0") long startFrom, @RequestParam(name = "pageSize", defaultValue = "20") long pageSize, + @ApiParam("query string") @RequestParam(name = "search", defaultValue = "", required = false) String searchString, + @ApiParam(allowableValues = ModelPropertyDescriptions.SORT_BY_ALLOWABLE_VALUES) @RequestParam(name = "sortBy", defaultValue = "prefix") String sortBy, + @ApiParam(allowableValues = ModelPropertyDescriptions.SORT_DIRECTION_ALLOWABLE_VALUES) @RequestParam(name = "sortDirection", defaultValue = "asc") String sortDirection) { final SearchTerm searchTerm = StringUtils.isNotBlank(searchString) ? new SearchTerm(searchString) : null; @@ -107,7 +110,8 @@ public ResponseEntity> get(@PathVariable long id) { return ResponseEntity.ok(ignoreFilterResource(ignoreFilterService.get(id))); } - @PostMapping(consumes = { Api.API_MIME_TYPE, "application/json" }) + @ApiOperation("Add ignore filter") + @PostMapping(consumes = { ValidatorApi.API_MIME_TYPE, "application/json" }) public ResponseEntity> add(@RequestBody @Valid ApiCommand command) throws Exception { final long id = ignoreFilterService.execute(command.getData()); final IgnoreFilter ignoreFilter = ignoreFilterService.get(id); diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/AddRoaPrefixAssertion.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/AddRoaPrefixAssertion.java index cf3deb042..224da75e9 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/AddRoaPrefixAssertion.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/AddRoaPrefixAssertion.java @@ -41,21 +41,23 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.*; + @Data(staticConstructor = "of") @Builder @ValidAddRoaPrefixAssertion public class AddRoaPrefixAssertion { - @ApiModelProperty(position = 1, required = true) + @ApiModelProperty(position = 1, required = true, value = ASN_PROPERTY, example = ASN_EXAMPLE) @NotNull @ValidAsn String asn; - @ApiModelProperty(position = 2, required = true) + @ApiModelProperty(position = 2, required = true, example = PREFIX_EXAMPLE) @NotNull @ValidPrefix String prefix; - @ApiModelProperty(position = 3) + @ApiModelProperty(position = 3, value = MAXLENGTH_PROPERTY) @Min(0) @Max(128) Integer maximumLength; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/RoaPrefixAssertionsController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/RoaPrefixAssertionsController.java index eb39ce77f..822eeb4e0 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/RoaPrefixAssertionsController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roaprefixassertions/RoaPrefixAssertionsController.java @@ -30,15 +30,11 @@ package net.ripe.rpki.validator3.api.roaprefixassertions; import com.google.common.collect.ImmutableList; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; -import net.ripe.ipresource.Asn; -import net.ripe.rpki.validator3.api.Api; -import net.ripe.rpki.validator3.api.ApiCommand; -import net.ripe.rpki.validator3.api.ApiResponse; -import net.ripe.rpki.validator3.api.Metadata; -import net.ripe.rpki.validator3.api.Paging; -import net.ripe.rpki.validator3.api.SearchTerm; -import net.ripe.rpki.validator3.api.Sorting; +import net.ripe.rpki.validator3.api.*; import net.ripe.rpki.validator3.api.bgp.BgpPreviewController; import net.ripe.rpki.validator3.api.bgp.BgpPreviewService; import org.apache.commons.lang.StringUtils; @@ -61,12 +57,16 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.SORT_BY_ALLOWABLE_VALUES; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.SORT_DIRECTION_ALLOWABLE_VALUES; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; +@PublicApiCall @RestController @Slf4j -@RequestMapping(path = "/api/roa-prefix-assertions", produces = { Api.API_MIME_TYPE, "application/json" }) +@Api(tags = "Whitelist") +@RequestMapping(path = "/api/roa-prefix-assertions", produces = { ValidatorApi.API_MIME_TYPE, "application/json" }) public class RoaPrefixAssertionsController { @Autowired @@ -75,12 +75,15 @@ public class RoaPrefixAssertionsController { @Autowired private BgpPreviewService bgpPreviewService; + @ApiOperation("Get current entries") @GetMapping public ResponseEntity>> list( @RequestParam(name = "startFrom", defaultValue = "0") long startFrom, @RequestParam(name = "pageSize", defaultValue = "20") long pageSize, @RequestParam(name = "search", defaultValue = "", required = false) String searchString, + @ApiParam(allowableValues = SORT_BY_ALLOWABLE_VALUES) @RequestParam(name = "sortBy", defaultValue = "prefix") String sortBy, + @ApiParam(allowableValues = SORT_DIRECTION_ALLOWABLE_VALUES) @RequestParam(name = "sortDirection", defaultValue = "asc") String sortDirection) { final SearchTerm searchTerm = StringUtils.isNotBlank(searchString) ? new SearchTerm(searchString) : null; @@ -109,7 +112,15 @@ public ResponseEntity> get(@PathVariable return ResponseEntity.ok(ApiResponse.data(toResource(roaPrefixAssertionsService.get(id)))); } - @PostMapping(consumes = { Api.API_MIME_TYPE, "application/json" }) + @ApiOperation(value = "Add whitelist entry", notes = + "By adding a whitelist entry you can manually authorise an ASN to originate a prefix, in addition to the " + + "validated ROAs from the repository.\n" + + "Please note that whitelist entries may invalidate announcements for this prefix from other ASNs (just like" + + " ROAs). This may be intentional (when you whitelist ASN A, which ASN B is hijacking), or not (when ASN B " + + "should also be authorised, or you made a mistake).\n" + + "When you modify the whitelist please validate its effects using `/api/roa-prefix-assertions` to find the number" + + " of prefixes validated and invalidated, and verify that there are no unintentional side-effects.") + @PostMapping(consumes = { ValidatorApi.API_MIME_TYPE, "application/json" }) public ResponseEntity> add(@RequestBody @Valid ApiCommand command) { final long id = roaPrefixAssertionsService.execute(command.getData()); final RoaPrefixAssertion ignoreFilter = roaPrefixAssertionsService.get(id); diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ExportsController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ExportsController.java index 2499da846..1228389a4 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ExportsController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ExportsController.java @@ -30,9 +30,12 @@ package net.ripe.rpki.validator3.api.roas; import au.com.bytecode.opencsv.CSVWriter; +import io.swagger.annotations.Api; import io.swagger.annotations.ApiModelProperty; +import io.swagger.annotations.ApiOperation; import lombok.Value; import lombok.extern.slf4j.Slf4j; +import net.ripe.rpki.validator3.api.PublicApiCall; import net.ripe.rpki.validator3.domain.validation.ValidatedRpkiObjects; import net.ripe.rpki.validator3.storage.Storage; import net.ripe.rpki.validator3.storage.stores.Settings; @@ -44,7 +47,7 @@ import java.io.IOException; import java.util.stream.Stream; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.*; /** * Controller to export validated ROA prefix information. @@ -52,6 +55,8 @@ * The API and data format is backwards compatible with the RPKI validator 2.x (see * https://github.com/RIPE-NCC/rpki-validator/blob/350d939d5e18858ee6cefc0c9a99e0c70b609b6d/rpki-validator-app/src/main/scala/net/ripe/rpki/validator/controllers/ExportController.scala#L41). */ +@Api(tags = "VRP export") +@PublicApiCall @RestController @Slf4j public class ExportsController { @@ -71,11 +76,11 @@ public ExportsController(ValidatedRpkiObjects validatedRpkiObjects, Settings set this.storage = storage; } - @GetMapping(path = "/api/export.json", produces = {JSON, APPLICATION_JSON_VALUE}) + @ApiOperation("export VRPs (json)") + @GetMapping(path = "/api/export.json") public JsonExport exportJson(HttpServletResponse response) { response.setContentType(JSON); - if (!storage.readTx(settings::isInitialValidationRunCompleted)) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return null; @@ -95,7 +100,8 @@ public JsonExport exportJson(HttpServletResponse response) { return new JsonExport(validatedPrefixes); } - @GetMapping(path = "/api/export.csv", produces = CSV) + @ApiOperation("export VRPs (CSV)") + @GetMapping(path = "/api/export.csv") public void exportCsv(HttpServletResponse response) throws IOException { response.setContentType(CSV); @@ -143,9 +149,12 @@ private static class JsonExport { @Value private static class JsonRoaPrefix { + @ApiModelProperty(value = ASN_PROPERTY, example = ASN_EXAMPLE) private String asn; + @ApiModelProperty(example = PREFIX_EXAMPLE) private String prefix; private int maxLength; + @ApiModelProperty(value = TRUST_ANCHOR, example = TRUST_ANCHOR_EXAMPLE) private String ta; } } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ObjectController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ObjectController.java index cd8ccf258..12a84fd57 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ObjectController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ObjectController.java @@ -29,10 +29,12 @@ */ package net.ripe.rpki.validator3.api.roas; +import io.swagger.annotations.Api; import io.swagger.annotations.ApiModelProperty; +import io.swagger.annotations.ApiOperation; import lombok.Value; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiResponse; import net.ripe.rpki.validator3.api.bgpsec.BgpSecAssertionsService; import net.ripe.rpki.validator3.api.bgpsec.BgpSecFilterService; @@ -61,8 +63,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.*; + @RestController -@RequestMapping(path = "/api/objects", produces = { Api.API_MIME_TYPE, "application/json" }) +@Api(tags = "Validated objects") +@RequestMapping(path = "/api/objects", produces = { ValidatorApi.API_MIME_TYPE, "application/json" }) @Slf4j public class ObjectController { @@ -93,6 +98,7 @@ public class ObjectController { @Autowired private Storage storage; + @ApiOperation("get all validated objects (used by rpki-rtr-server)") @GetMapping(path = "/validated") public ResponseEntity> list(Locale locale) { final List trustAnchorList = storage.readTx(tx -> trustAnchors.findAll(tx)); @@ -164,13 +170,16 @@ public static class ValidatedObjects { @Value public static class RoaPrefix { + @ApiModelProperty(value = ASN_PROPERTY, example = ASN_EXAMPLE) private String asn; + @ApiModelProperty(PREFIX_EXAMPLE) private String prefix; private int maxLength; } @Value public static class RouterCertificate { + @ApiModelProperty(ASN_LIST_PROPERTY) private List asn; private String subjectKeyIdentifier; private String subjectPublicKeyInfo; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ValidatedRoasController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ValidatedRoasController.java index 2ceb0100e..bdae83bf1 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ValidatedRoasController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/roas/ValidatedRoasController.java @@ -29,9 +29,11 @@ */ package net.ripe.rpki.validator3.api.roas; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.annotations.ApiParam; import lombok.Value; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiResponse; import net.ripe.rpki.validator3.api.Metadata; import net.ripe.rpki.validator3.api.Paging; @@ -49,10 +51,11 @@ import java.util.stream.Stream; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.*; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; @RestController -@RequestMapping(path = "/api/roas", produces = {Api.API_MIME_TYPE, "application/json"}) +@RequestMapping(path = "/api/roas", produces = {ValidatorApi.API_MIME_TYPE, "application/json"}) @Slf4j public class ValidatedRoasController { @Autowired @@ -63,7 +66,9 @@ public ResponseEntity>> list( @RequestParam(name = "startFrom", defaultValue = "0") long startFrom, @RequestParam(name = "pageSize", defaultValue = "20") long pageSize, @RequestParam(name = "search", defaultValue = "", required = false) String searchString, + @ApiParam(allowableValues = SORT_BY_ALLOWABLE_VALUES) @RequestParam(name = "sortBy", defaultValue = "prefix") String sortBy, + @ApiParam(allowableValues = SORT_DIRECTION_ALLOWABLE_VALUES) @RequestParam(name = "sortDirection", defaultValue = "asc") String sortDirection) { final SearchTerm searchTerm = StringUtils.isNotBlank(searchString) ? new SearchTerm(searchString) : null; @@ -94,9 +99,12 @@ public ResponseEntity>> list( @Value class RoaPrefix { + @ApiModelProperty(value = ASN_PROPERTY, example = ASN_EXAMPLE) private String asn; private String prefix; + @ApiModelProperty(MAXLENGTH_PROPERTY) private int length; + @ApiModelProperty(value = TRUST_ANCHOR, example = TRUST_ANCHOR_EXAMPLE) private String trustAnchor; private String uri; } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkiobjects/RpkiObjectController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkiobjects/RpkiObjectController.java index 0557402d6..93ee2ec21 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkiobjects/RpkiObjectController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkiobjects/RpkiObjectController.java @@ -33,6 +33,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.google.common.collect.Sets; +import io.swagger.annotations.Api; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Builder; @@ -52,8 +53,9 @@ import net.ripe.rpki.commons.crypto.x509cert.X509ResourceCertificate; import net.ripe.rpki.commons.crypto.x509cert.X509RouterCertificate; import net.ripe.rpki.commons.validation.ValidationResult; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiResponse; +import net.ripe.rpki.validator3.api.PublicApiCall; import net.ripe.rpki.validator3.storage.Tx; import net.ripe.rpki.validator3.storage.data.RpkiObject; import net.ripe.rpki.validator3.storage.data.TrustAnchor; @@ -95,8 +97,10 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; +@Api(tags = "RPKI objects") +@PublicApiCall @RestController -@RequestMapping(path = "/api/rpki-objects", produces = { Api.API_MIME_TYPE, "application/json" }) +@RequestMapping(path = "/api/rpki-objects", produces = { ValidatorApi.API_MIME_TYPE, "application/json" }) @Slf4j public class RpkiObjectController { diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoriesController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoriesController.java index 56481d126..6aa90d35f 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoriesController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoriesController.java @@ -29,13 +29,11 @@ */ package net.ripe.rpki.validator3.api.rpkirepositories; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; -import net.ripe.rpki.validator3.api.ApiResponse; -import net.ripe.rpki.validator3.api.Metadata; -import net.ripe.rpki.validator3.api.Paging; -import net.ripe.rpki.validator3.api.SearchTerm; -import net.ripe.rpki.validator3.api.Sorting; +import net.ripe.rpki.validator3.api.*; import net.ripe.rpki.validator3.storage.data.Key; import net.ripe.rpki.validator3.storage.data.RpkiRepository; import net.ripe.rpki.validator3.storage.Storage; @@ -56,10 +54,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.SORT_BY_ALLOWABLE_VALUES; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.SORT_DIRECTION_ALLOWABLE_VALUES; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; +@PublicApiCall @RestController -@RequestMapping(path = "/api/rpki-repositories", produces = {Api.API_MIME_TYPE, "application/json"}) +@Api(tags = "RPKI repositories") +@RequestMapping(path = "/api/rpki-repositories", produces = {ValidatorApi.API_MIME_TYPE, "application/json"}) @Slf4j public class RpkiRepositoriesController { @@ -72,14 +74,19 @@ public RpkiRepositoriesController(RpkiRepositories rpkiRepositories, Storage sto this.storage = storage; } + @ApiOperation("Get repositories (matching parameters)") @GetMapping public ResponseEntity>> list( + @ApiParam("Validation status") @RequestParam(name = "status", required = false) RpkiRepository.Status status, + @ApiParam("Trust anchor id") @RequestParam(name = "ta", required = false) Long taId, @RequestParam(name = "startFrom", defaultValue = "0") long startFrom, @RequestParam(name = "pageSize", defaultValue = "20") long pageSize, @RequestParam(name = "search", defaultValue = "", required = false) String searchString, + @ApiParam(allowableValues = SORT_BY_ALLOWABLE_VALUES) @RequestParam(name = "sortBy", defaultValue = "location") String sortBy, + @ApiParam(allowableValues = SORT_DIRECTION_ALLOWABLE_VALUES) @RequestParam(name = "sortDirection", defaultValue = "asc") String sortDirection, @RequestParam(name = "hideChildrenOfDownloadedParent", defaultValue = "true") boolean hideChildrenOfDownloadedParent ) { @@ -108,6 +115,7 @@ public ResponseEntity>> list( }); } + @ApiOperation("Get repository by id") @GetMapping(path = "/{id}") public ResponseEntity> get(@PathVariable long id) { return storage.readTx(tx -> rpkiRepositories.get(tx, Key.of(id))) @@ -115,6 +123,7 @@ public ResponseEntity> get(@PathVariable lon .orElse(ResponseEntity.notFound().build()); } + @ApiOperation("Repository status by trust anchor") @GetMapping(path = "/statuses/{taId}") public ApiResponse repositories( @PathVariable long taId, @@ -130,6 +139,7 @@ public ApiResponse repositories( )).build(); } + @ApiOperation("Delete repository by id") @DeleteMapping(path = "/{id}") public ResponseEntity delete(@PathVariable long id) { storage.writeTx0(tx -> rpkiRepositories.remove(tx, Key.of(id))); diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoryResource.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoryResource.java index ba5bea85b..c4785b13c 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoryResource.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/rpkirepositories/RpkiRepositoryResource.java @@ -31,7 +31,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.domain.constraints.ValidLocationURI; import net.ripe.rpki.validator3.storage.data.RpkiRepository; import org.springframework.hateoas.Links; @@ -48,7 +48,7 @@ public class RpkiRepositoryResource { @ApiModelProperty(allowableValues = RpkiRepository.TYPE, required = true, position = 1) final String type; - @ApiModelProperty(required = true, allowableValues = "range[" + Api.MINIMUM_VALID_ID + ",infinity]", example = "1", position = 2) + @ApiModelProperty(required = true, allowableValues = "range[" + ValidatorApi.MINIMUM_VALID_ID + ",infinity]", example = "1", position = 2) final long id; @NotNull diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/slurm/SlurmController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/slurm/SlurmController.java index ef0875671..87bb0f540 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/slurm/SlurmController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/slurm/SlurmController.java @@ -30,10 +30,12 @@ package net.ripe.rpki.validator3.api.slurm; import com.google.common.base.Charsets; +import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiError; import net.ripe.rpki.validator3.api.ApiResponse; +import net.ripe.rpki.validator3.api.PublicApiCall; import net.ripe.rpki.validator3.api.slurm.dtos.Slurm; import net.ripe.rpki.validator3.api.trustanchors.TrustAnchorResource; import net.ripe.rpki.validator3.storage.encoding.GsonCoder; @@ -50,8 +52,10 @@ import java.util.Locale; +@Api(tags = "SLURM") +@PublicApiCall @RestController -@RequestMapping(path = "/api/slurm", produces = {Api.API_MIME_TYPE, "application/json"}) +@RequestMapping(path = "/api/slurm", produces = {ValidatorApi.API_MIME_TYPE, "application/json"}) @Slf4j public class SlurmController { @@ -78,7 +82,7 @@ public ResponseEntity slurm() { } // FIXME Do something to force browser's save file prompt instead of rendering JSON - @GetMapping(path = "/download", produces = Api.API_MIME_TYPE) + @GetMapping(path = "/download", produces = ValidatorApi.API_MIME_TYPE) public StreamingResponseBody download() { return out -> slurmService.writeTo(out); } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/system/xodus/XodusController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/system/xodus/XodusController.java index 46ecc2437..db1bc38fd 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/system/xodus/XodusController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/system/xodus/XodusController.java @@ -30,7 +30,8 @@ package net.ripe.rpki.validator3.api.system.xodus; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; +import net.ripe.rpki.validator3.api.InternalApiCall; import net.ripe.rpki.validator3.domain.cleanup.ValidationRunCleanupService; import net.ripe.rpki.validator3.storage.xodus.Xodus; import org.springframework.beans.factory.annotation.Autowired; @@ -40,8 +41,9 @@ import java.util.Map; +@InternalApiCall @RestController -@RequestMapping(path = "/api/xodus", produces = {Api.API_MIME_TYPE, "application/json"}) +@RequestMapping(path = "/api/xodus", produces = {ValidatorApi.API_MIME_TYPE, "application/json"}) @Slf4j public class XodusController { diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorController.java index 67b0c3924..4644a8659 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorController.java @@ -29,15 +29,11 @@ */ package net.ripe.rpki.validator3.api.trustanchors; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; -import net.ripe.rpki.validator3.api.ApiCommand; -import net.ripe.rpki.validator3.api.ApiError; -import net.ripe.rpki.validator3.api.ApiResponse; -import net.ripe.rpki.validator3.api.Metadata; -import net.ripe.rpki.validator3.api.Paging; -import net.ripe.rpki.validator3.api.SearchTerm; -import net.ripe.rpki.validator3.api.Sorting; +import net.ripe.rpki.validator3.api.*; import net.ripe.rpki.validator3.api.validationruns.ValidationCheckResource; import net.ripe.rpki.validator3.api.validationruns.ValidationRunController; import net.ripe.rpki.validator3.api.validationruns.ValidationRunResource; @@ -78,11 +74,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.SORT_BY_ALLOWABLE_VALUES; +import static net.ripe.rpki.validator3.api.ModelPropertyDescriptions.SORT_DIRECTION_ALLOWABLE_VALUES; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; +@PublicApiCall @RestController -@RequestMapping(path = "/api/trust-anchors", produces = { Api.API_MIME_TYPE, "application/json" }) +@Api(tags = "Trust Anchors") +@RequestMapping(path = "/api/trust-anchors", produces = { ValidatorApi.API_MIME_TYPE, "application/json" }) @Slf4j public class TrustAnchorController { @@ -98,6 +98,7 @@ public class TrustAnchorController { @Autowired private Storage storage; + @ApiOperation("List the configured Trust Anchors") @GetMapping public ResponseEntity>> list(Locale locale) { return storage.readTx(tx -> ResponseEntity.ok(ApiResponse.data( @@ -109,7 +110,8 @@ public ResponseEntity>> list(Locale locale ))); } - @PostMapping(consumes = { Api.API_MIME_TYPE, "application/json" }) + @ApiOperation("Add a Trust Anchor using a JSON payload") + @PostMapping(consumes = { ValidatorApi.API_MIME_TYPE, "application/json" }) public ResponseEntity> add(@RequestBody @Valid ApiCommand command, Locale locale) { long id = trustAnchorService.execute(command.getData()); return storage.readTx(tx -> { @@ -119,6 +121,7 @@ public ResponseEntity> add(@RequestBody @Valid }); } + @ApiOperation("Add a Trust Anchor from a file") @PostMapping(path = "/upload", consumes = "multipart/form-data") public ResponseEntity> add(@RequestParam("file") MultipartFile trustAnchorLocator, Locale locale) { try { @@ -149,6 +152,7 @@ public ResponseEntity> add(@RequestParam("file" } } + @ApiOperation("Get a trust anchor by (numeric) identifier") @GetMapping(path = "/{id}") public ResponseEntity> get(@PathVariable long id, Locale locale) { return storage.readTx(tx -> @@ -171,13 +175,16 @@ public ResponseEntity> validationResults(@Pat return ResponseEntity.notFound().build(); } + @ApiOperation("Get validation issues") @GetMapping(path = "/{id}/validation-checks") public ResponseEntity>> validationChecks( @PathVariable long id, @RequestParam(name = "startFrom", defaultValue = "0") long startFrom, @RequestParam(name = "pageSize", defaultValue = "20") long pageSize, @RequestParam(name = "search", required = false) String searchString, + @ApiParam(allowableValues = SORT_BY_ALLOWABLE_VALUES) @RequestParam(name = "sortBy", defaultValue = "location") String sortBy, + @ApiParam(allowableValues = SORT_DIRECTION_ALLOWABLE_VALUES) @RequestParam(name = "sortDirection", defaultValue = "asc") String sortDirection, Locale locale ) { @@ -203,11 +210,13 @@ public ResponseEntity>> validationCh }); } + @ApiOperation("Get the statuses of all configured trust anchors") @GetMapping(path = "/statuses") public ApiResponse> statuses() { return storage.readTx(tx -> ApiResponse.>builder().data(trustAnchors.getStatuses(tx)).build()); } + @ApiOperation("Delete a trust anchor by id") @DeleteMapping(path = "/{id}") public ResponseEntity delete(@PathVariable long id) { trustAnchorService.remove(id); diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorResource.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorResource.java index 6cddf9ae5..da52a5cf8 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorResource.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorResource.java @@ -32,7 +32,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Value; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.storage.data.TrustAnchor; import org.springframework.hateoas.Links; @@ -47,7 +47,7 @@ public class TrustAnchorResource { @ApiModelProperty(allowableValues = TrustAnchor.TYPE, required = true, position = 1) String type; - @ApiModelProperty(required = true, allowableValues = "range[" + Api.MINIMUM_VALID_ID + ",infinity]", example = "1", position = 2) + @ApiModelProperty(required = true, allowableValues = "range[" + ValidatorApi.MINIMUM_VALID_ID + ",infinity]", example = "1", position = 2) long id; @ApiModelProperty(required = true, example = "RPKI CA", position = 3) String name; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/util/CommonValidationController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/util/CommonValidationController.java index 4c2ac1720..bbdd81f7c 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/util/CommonValidationController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/util/CommonValidationController.java @@ -29,11 +29,15 @@ */ package net.ripe.rpki.validator3.api.util; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import net.ripe.ipresource.IpRange; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiError; import net.ripe.rpki.validator3.api.ApiResponse; +import net.ripe.rpki.validator3.api.PublicApiCall; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -41,11 +45,14 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +@Api(tags = "Input validation") +@PublicApiCall @RestController -@RequestMapping(path = "/api/validate", produces = {Api.API_MIME_TYPE, "application/json"}) +@RequestMapping(path = "/api/validate", produces = {ValidatorApi.API_MIME_TYPE, "application/json"}) @Slf4j public class CommonValidationController { + @ApiOperation("Validate that value is a valid prefix") @GetMapping(path = "/prefix") public ResponseEntity> validatePrefix( @RequestParam(name = "p") String prefix) diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationCheckResource.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationCheckResource.java index 21adbe98c..713743e5c 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationCheckResource.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationCheckResource.java @@ -39,15 +39,15 @@ @Data(staticConstructor = "of") @ApiModel(value = "ValidationCheck") public class ValidationCheckResource { - @ApiModelProperty(required = true, position = 1) + @ApiModelProperty(required = true, position = 1, example = "rsync://rpki.cnnic.cn/rpki/A9162E3D0000/BBYptqnqt8sTJOo5ePA3lviJtUA.crl") final String location; - @ApiModelProperty(required = true, position = 2) + @ApiModelProperty(required = true, position = 2, example = "WARNING") final ValidationCheck.Status status; - @ApiModelProperty(required = true, position = 4) + @ApiModelProperty(required = true, position = 4, example = "crl.next.update.before.now") final String key; - @ApiModelProperty(required = true, position = 3) + @ApiModelProperty(required = true, position = 3, example = "[\"2020-01-09T23:15:45.000Z\"]") final List parameters; - @ApiModelProperty(required = false, position = 5) + @ApiModelProperty(required = false, position = 5, example = "CRL next update was expected on or before 2020-01-09T23:15:45.000Z") final String formattedMessage; public static ValidationCheckResource of(ValidationCheck check, String formattedMessage) { diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunController.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunController.java index e4cb2973b..7a3edb8e2 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunController.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunController.java @@ -29,9 +29,11 @@ */ package net.ripe.rpki.validator3.api.validationruns; +import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiResponse; +import net.ripe.rpki.validator3.api.PublicApiCall; import net.ripe.rpki.validator3.storage.data.validation.ValidationRun; import net.ripe.rpki.validator3.storage.Storage; import net.ripe.rpki.validator3.storage.stores.TrustAnchors; @@ -53,8 +55,10 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; +@Api(tags = "Validation runs") +@PublicApiCall @RestController -@RequestMapping(path = "/api/validation-runs", produces = Api.API_MIME_TYPE) +@RequestMapping(path = "/api/validation-runs", produces = ValidatorApi.API_MIME_TYPE) @Slf4j public class ValidationRunController { @@ -75,7 +79,7 @@ public ResponseEntity>> list(Locale loca return storage.readTx(tx -> ResponseEntity.ok(ApiResponse.data( new Links(linkTo(methodOn(ValidationRunController.class).list(locale)).withSelfRel()), - validationRuns.findAll(tx, ValidationRun.class) + validationRuns.findAll(tx) .stream() .map(validationRun -> ValidationRunResource.of(validationRun, vr -> validationRuns.getObjectCount(tx, vr), diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunResource.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunResource.java index e28311eb6..ff9dec09a 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunResource.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/api/validationruns/ValidationRunResource.java @@ -56,7 +56,10 @@ @Data @Builder -@ApiModel(value = "ValidationRun") +@ApiModel( + value = "ValidationRun", + description = "The result of a validation run (at a point in time) of the validator." +) public class ValidationRunResource { @ApiModelProperty( allowableValues = TrustAnchorValidationRun.TYPE + "," + @@ -70,6 +73,10 @@ public class ValidationRunResource { Instant completedAt; + @ApiModelProperty( + allowableValues = "RUNNING, SUCCEEDED, FAILED", + example = "SUCCEEDED" + ) String status; List validationChecks; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/background/ValidationScheduler.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/background/ValidationScheduler.java index b9af8c46b..0c31eaff8 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/background/ValidationScheduler.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/background/ValidationScheduler.java @@ -32,7 +32,7 @@ import com.google.common.base.Preconditions; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.storage.data.RpkiRepository; import net.ripe.rpki.validator3.storage.data.TrustAnchor; import org.quartz.JobKey; @@ -46,7 +46,6 @@ import org.springframework.stereotype.Component; import java.time.Duration; -import java.time.temporal.TemporalUnit; @Component @Slf4j @@ -72,7 +71,7 @@ public void addTrustAnchor(TrustAnchor trustAnchor) { return; } Preconditions.checkArgument( - trustAnchor.key().asLong() >= Api.MINIMUM_VALID_ID, + trustAnchor.key().asLong() >= ValidatorApi.MINIMUM_VALID_ID, "trustAnchor id %s is not valid", trustAnchor.key() ); @@ -126,7 +125,7 @@ public synchronized void addRrdpRpkiRepository(RpkiRepository rpkiRepository) { Preconditions.checkArgument(rpkiRepository.getType() == RpkiRepository.Type.RRDP); Preconditions.checkArgument( - rpkiRepository.key().asLong() >= Api.MINIMUM_VALID_ID, + rpkiRepository.key().asLong() >= ValidatorApi.MINIMUM_VALID_ID, "rpkiRepository id %s is not valid", rpkiRepository.key() ); diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/ApiConfig.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/ApiConfig.java index b7540aa6f..99935d135 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/ApiConfig.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/ApiConfig.java @@ -37,7 +37,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiLogger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; @@ -112,7 +112,7 @@ public void extendMessageConverters(List> converters) { public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer .favorPathExtension(false) - .defaultContentType(MediaType.valueOf(Api.API_MIME_TYPE)); + .defaultContentType(MediaType.valueOf(ValidatorApi.API_MIME_TYPE)); } @Override diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/SwaggerConfig.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/SwaggerConfig.java index 0c0222ce8..5f990af17 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/SwaggerConfig.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/config/SwaggerConfig.java @@ -30,6 +30,9 @@ package net.ripe.rpki.validator3.config; import com.fasterxml.classmate.TypeResolver; + +import net.ripe.rpki.validator3.api.InternalApiCall; +import net.ripe.rpki.validator3.api.PublicApiCall; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -41,9 +44,12 @@ import springfox.documentation.schema.AlternateTypeRules; import springfox.documentation.schema.WildcardType; import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.ApiSelectorBuilder; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; +import springfox.documentation.service.Tag; + import java.net.URI; import java.util.List; import java.util.Optional; @@ -53,22 +59,51 @@ @EnableSwagger2 @Import(value = BeanValidatorPluginsConfiguration.class) public class SwaggerConfig { - @Bean - public Docket api() { - TypeResolver typeResolver = new TypeResolver(); + private Docket docketBuilder() { + final TypeResolver typeResolver = new TypeResolver(); + return new Docket(DocumentationType.SWAGGER_2) - .alternateTypeRules(AlternateTypeRules.newRule(typeResolver.resolve(Optional.class, URI.class), String.class, AlternateTypeRule.HIGHEST_PRECEDENCE + 1000)) - .alternateTypeRules(AlternateTypeRules.newRule( - typeResolver.resolve(Stream.class, WildcardType.class), - typeResolver.resolve(List.class, WildcardType.class), - AlternateTypeRule.HIGHEST_PRECEDENCE + 1002 - )) - .directModelSubstitute(URI.class, String.class) - .directModelSubstitute(Links.class, Object.class) - .genericModelSubstitutes(Optional.class) - .select() - .apis(RequestHandlerSelectors.any()) - .paths(PathSelectors.any()) - .build(); + .alternateTypeRules(AlternateTypeRules.newRule(typeResolver.resolve(Optional.class, URI.class), String.class, AlternateTypeRule.HIGHEST_PRECEDENCE + 1000)) + .alternateTypeRules(AlternateTypeRules.newRule( + typeResolver.resolve(Stream.class, WildcardType.class), + typeResolver.resolve(List.class, WildcardType.class), + AlternateTypeRule.HIGHEST_PRECEDENCE + 1002 + )) + .directModelSubstitute(URI.class, String.class) + .directModelSubstitute(Links.class, Object.class) + .genericModelSubstitutes(Optional.class); + } + + @Bean + public Docket mainApi() { + return docketBuilder() + .tags( + new Tag("BGP preview", "Previews the likely RPKI validity of BGP announcements"), + new Tag("Ignore filters", "Ignore filters (filters that exclude ROAs)"), + new Tag("Input validation", "Validate that objects are valid inputs"), + new Tag("RPKI repositories", "RPKI repositories"), + new Tag("RPKI objects", "All valid RPKI objects"), + new Tag("SLURM", "Simplified Local Internet Number Resource Management with the RPKI"), + new Tag("Trust Anchors", "Trust Anchors"), + new Tag("Validated objects", "Validated objects (rpki-rtr-server API)"), + new Tag("Validation runs", "Validation runs"), + new Tag("VRP export", "Validated ROA Payload export"), + new Tag("Whitelist", "Whitelist entries") + ) + .groupName("Public APIs") + .select() + .apis(RequestHandlerSelectors.withClassAnnotation(PublicApiCall.class)) + .paths(PathSelectors.any()) + .build(); + } + + @Bean + public Docket internalApi() { + return docketBuilder() + .groupName("Status and health check APIs") + .select() + .apis(RequestHandlerSelectors.withClassAnnotation(InternalApiCall.class)) + .paths(PathSelectors.any()) + .build(); } } diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/jobs/JobExecutor.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/jobs/JobExecutor.java index 52b6fa319..d08127d10 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/jobs/JobExecutor.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/jobs/JobExecutor.java @@ -167,14 +167,14 @@ static class JobWrap { private Job job; } - @EqualsAndHashCode + @EqualsAndHashCode(callSuper = true) public static class Just extends JobWrap { public Just(Job job) { super(job); } } - @EqualsAndHashCode + @EqualsAndHashCode(callSuper = true) public static class Repeat extends JobWrap { private final Duration interval; diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/ValidationRuns.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/ValidationRuns.java index b2556973e..6db9db956 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/ValidationRuns.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/ValidationRuns.java @@ -53,6 +53,8 @@ public interface ValidationRuns { Optional get(Tx.Read tx, Class type, long id); + List findAll(Tx.Read tx); + List findAll(Tx.Read tx, Class type); List findLatestSuccessful(Tx.Read tx, Class type); diff --git a/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/impl/ValidationRunsStore.java b/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/impl/ValidationRunsStore.java index dc0cf5645..8904052b6 100644 --- a/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/impl/ValidationRunsStore.java +++ b/rpki-validator/src/main/java/net/ripe/rpki/validator3/storage/stores/impl/ValidationRunsStore.java @@ -181,6 +181,15 @@ public Optional get(Tx.Read tx, Class type, long .map(validationRun -> (T) validationRun.get()); } + @Override + public List findAll(Tx.Read tx) { + final List result = new ArrayList<>(); + maps.values().forEach(ixMap -> + ixMap.forEach(tx, (k, bb) -> + result.add((T) ixMap.toValue(bb)))); + return result; + } + @Override public List findAll(Tx.Read tx, Class type) { final List result = new ArrayList<>(); @@ -194,7 +203,7 @@ public List findAll(Tx.Read tx, Class type) { @SuppressWarnings("unchecked") public List findLatestSuccessful(Tx.Read tx, Class type) { final List result = new ArrayList<>(); - List> ixMaps = pickIxMaps(type); + List> ixMaps = pickIxMaps(type); ixMaps.forEach(ixMap -> ixMap.getByIdxDescendingWhere(BY_COMPLETED_AT_INDEX, tx, ValidationRun::isSucceeded) .forEach((k, v) -> result.add((T) v))); @@ -430,14 +439,13 @@ private IxMap pickIxMap(String vrType) { return (IxMap) ixMap; } - private List> pickIxMaps(Class c) { - List> ixMaps = new ArrayList<>(); - + private List> pickIxMaps(Class c) { + List> ixMaps = new ArrayList<>(); try { String validationRunType = FieldUtils.readDeclaredStaticField(c, "TYPE").toString(); ixMaps.add(pickIxMap(validationRunType)); - } catch (IllegalAccessException e) { - throw new RuntimeException("Validation run "+c.toGenericString()+" has not static TYPE field declared."); + } catch (IllegalAccessException | IllegalArgumentException e) { + ixMaps.addAll(maps.values()); } return ixMaps; } diff --git a/rpki-validator/src/main/resources/application.properties b/rpki-validator/src/main/resources/application.properties index 1137b48f6..4ed54d3ea 100644 --- a/rpki-validator/src/main/resources/application.properties +++ b/rpki-validator/src/main/resources/application.properties @@ -47,7 +47,7 @@ logging.level.org.quartz=OFF rpki.validator.data.path=/tmp/rpki-validator-3-data/ -rpki.validator.preconfigured.trust.anchors.directory=./rpki-validator/src/main/resources/packaging/generic/workdirs/preconfigured-tals +rpki.validator.preconfigured.trust.anchors.directory=./src/main/resources/packaging/generic/workdirs/preconfigured-tals rpki.validator.rsync.local.storage.directory=/tmp/rpki-validator-3 rpki.validator.bgp.ris.dump.urls=https://www.ris.ripe.net/dumps/riswhoisdump.IPv4.gz,https://www.ris.ripe.net/dumps/riswhoisdump.IPv6.gz diff --git a/rpki-validator/src/test/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorControllerTest.java b/rpki-validator/src/test/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorControllerTest.java index b0a3425e3..e13c91c5e 100644 --- a/rpki-validator/src/test/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorControllerTest.java +++ b/rpki-validator/src/test/java/net/ripe/rpki/validator3/api/trustanchors/TrustAnchorControllerTest.java @@ -32,7 +32,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import net.ripe.rpki.validator3.IntegrationTest; -import net.ripe.rpki.validator3.api.Api; +import net.ripe.rpki.validator3.api.ValidatorApi; import net.ripe.rpki.validator3.api.ApiCommand; import net.ripe.rpki.validator3.api.ApiResponse; import net.ripe.rpki.validator3.storage.data.TrustAnchor; @@ -83,8 +83,8 @@ public void setUp() { public void should_add_trust_anchor() throws Exception { ResultActions result = mvc.perform( post("/api/trust-anchors") - .accept(Api.API_MIME_TYPE) - .contentType(Api.API_MIME_TYPE) + .accept(ValidatorApi.API_MIME_TYPE) + .contentType(ValidatorApi.API_MIME_TYPE) .content(objectMapper.writeValueAsString(ApiCommand.of(AddTrustAnchor.builder() .type(TrustAnchor.TYPE) .name(TEST_CA_NAME) @@ -96,7 +96,7 @@ public void should_add_trust_anchor() throws Exception { result .andExpect(status().isCreated()) - .andExpect(content().contentType(Api.API_MIME_TYPE)); + .andExpect(content().contentType(ValidatorApi.API_MIME_TYPE)); ApiResponse response = addTrustAnchorResponse(result); assertThat(response.getData()).isNotNull(); @@ -106,10 +106,10 @@ public void should_add_trust_anchor() throws Exception { Link selfRel = resource.getLinks().getLink("self"); mvc.perform( get(selfRel.getHref()) - .accept(Api.API_MIME_TYPE) + .accept(ValidatorApi.API_MIME_TYPE) ) .andExpect(status().isOk()) - .andExpect(content().contentType(Api.API_MIME_TYPE)) + .andExpect(content().contentType(ValidatorApi.API_MIME_TYPE)) .andExpect(jsonPath("$.data.name").value(TEST_CA_NAME)); } @@ -117,8 +117,8 @@ public void should_add_trust_anchor() throws Exception { public void should_fail_on_invalid_request() throws Exception { ResultActions result = mvc.perform( post("/api/trust-anchors") - .accept(Api.API_MIME_TYPE) - .contentType(Api.API_MIME_TYPE) + .accept(ValidatorApi.API_MIME_TYPE) + .contentType(ValidatorApi.API_MIME_TYPE) .content(objectMapper.writeValueAsString(ApiCommand.of(AddTrustAnchor.builder() .type(TrustAnchor.TYPE) .name(TEST_CA_NAME) @@ -130,7 +130,7 @@ public void should_fail_on_invalid_request() throws Exception { result .andExpect(status().isBadRequest()) - .andExpect(content().contentType(Api.API_MIME_TYPE)); + .andExpect(content().contentType(ValidatorApi.API_MIME_TYPE)); ApiResponse response = addTrustAnchorResponse(result);