Skip to content

Commit

Permalink
RIPE NCC has merged fd1d936
Browse files Browse the repository at this point in the history
* Add forRemoval [a009bd1d]
* Sonarqube remarks [2418b438]
* Update dependency commons-codec:commons-codec to v1.17.1 [ffed33e3]
* Update dependency io.sentry:sentry-bom to v7.12.0 [42524de9]
* Update dependency gradle to v8.9 [2cad0a10]
* Add deprecation javadoc [58dc87b9]
* Add a test for no overlap [ccb5c541]
* Adjust error handling, fix tests [d224afff]
* Deprecate existing announcements end-point [f5606b9b]
* Add reasons for empty BGP announcements [f74cb67a]
* Take lastUpdated from the downloaded files, store it only in memory [da330df8]
* Fix Hibernate error [f7a43604]
* Make lastUpdate for RIS updates persistent [06e77007]
* Add simple lastUpdated to announcements. [4cd5e9cd]
* Update dependency org.wiremock:wiremock-jetty12 to v3.8.0 [bd776aba]
* Update dependency org.sonarqube:org.sonarqube.gradle.plugin to v5.1.0.4882 [080df6ab]
* Update dependency io.sentry:sentry-bom to v7.11.0 [18d6b90b]
* Update dependency net.jqwik:jqwik to v1.9.0 [4e7835c4]
* Update dependency org.wiremock:wiremock-jetty12 to v3.7.0 [20ad0c33]
* Update dependency org.eclipse.jgit:org.eclipse.jgit to v6.10.0.202406032230-r [504db2af]
* Update dependency io.sentry:sentry-bom to v7.10.0 [9a21fd80]
* Update dependency gradle to v8.8 [7283bdae]
* Update plugin com.google.cloud.tools.jib to v3.4.3 [fed00dbb]
* Log exception stacktraces [cf1a9544]
* typo [2cfacb90]
* Execute after-TA-response-processing actions in the background [9a6cb1ea]
  • Loading branch information
RPKI Team at RIPE NCC committed Jul 19, 2024
1 parent 030b964 commit a960ed6
Show file tree
Hide file tree
Showing 20 changed files with 207 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
default:
image: gradle:8.7-jdk17
image: gradle:8.9-jdk17

# Explicit version of the Mergerequests-Pipelines workflow, with the main branch
# added.
Expand Down
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
id 'org.springframework.boot' version "3.2.4"
id 'distribution'
id 'jacoco'
id "com.google.cloud.tools.jib" version "3.4.2"
id "com.google.cloud.tools.jib" version "3.4.3"
id "com.google.osdetector" version "1.7.3"
}

Expand Down Expand Up @@ -44,7 +44,7 @@ dependencies {
implementation "org.thymeleaf:thymeleaf:3.1.2.RELEASE"
implementation "org.thymeleaf:thymeleaf-spring6:3.1.2.RELEASE"

implementation platform('io.sentry:sentry-bom:7.9.0')
implementation platform('io.sentry:sentry-bom:7.12.0')
implementation 'io.sentry:sentry-spring-boot-starter'
implementation 'io.sentry:sentry-logback'

Expand All @@ -58,7 +58,7 @@ dependencies {

implementation 'com.google.code.gson:gson:2.11.0'
implementation 'com.jamesmurty.utils:java-xmlbuilder:1.3'
implementation 'commons-codec:commons-codec:1.17.0'
implementation 'commons-codec:commons-codec:1.17.1'
implementation 'commons-io:commons-io:2.16.1'
implementation 'ch.qos.logback.contrib:logback-json-classic:0.1.5'
implementation 'ch.qos.logback.contrib:logback-jackson:0.1.5'
Expand All @@ -72,8 +72,8 @@ dependencies {
exclude group: 'org.hamcrest', module: 'hamcrest-core'
}

testImplementation "org.wiremock:wiremock-jetty12:3.6.0"
testImplementation 'net.jqwik:jqwik:1.8.5'
testImplementation "org.wiremock:wiremock-jetty12:3.8.0"
testImplementation 'net.jqwik:jqwik:1.9.0'
testImplementation "net.ripe.rpki:rpki-commons:$rpki_commons_version:tests"
testImplementation 'org.assertj:assertj-core'

Expand Down
4 changes: 2 additions & 2 deletions buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ dependencies {
implementation('com.gorylenko.gradle-git-properties:com.gorylenko.gradle-git-properties.gradle.plugin:2.4.2') {
exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit'
}
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.9.0.202403050737-r'
implementation 'org.sonarqube:org.sonarqube.gradle.plugin:5.0.0.4638'
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.10.0.202406032230-r'
implementation 'org.sonarqube:org.sonarqube.gradle.plugin:5.1.0.4882'
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
2 changes: 1 addition & 1 deletion gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.ripe.rpki.bgpris;

import lombok.Getter;
import lombok.Setter;
import net.ripe.ipresource.IpAddress;
import net.ripe.ipresource.IpRange;
import net.ripe.ipresource.IpResource;
Expand All @@ -11,6 +13,7 @@
import net.ripe.rpki.server.api.services.read.BgpRisEntryViewService;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -19,7 +22,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Component
public class BgpRisEntryRepositoryBean implements BgpRisEntryViewService {
Expand All @@ -31,6 +33,10 @@ public class BgpRisEntryRepositoryBean implements BgpRisEntryViewService {
*/
private final AtomicReference<IntervalMap<IpRange, ArrayList<BgpRisEntry>>> entries = new AtomicReference<>(emptyEntries());

@Getter
@Setter
private Instant lastUpdated;

@Override
public boolean isEmpty() {
return entries.get().isEmpty();
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/net/ripe/rpki/bgpris/riswhois/RisWhoisFetcher.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.ripe.rpki.bgpris.riswhois;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateTimeConstants;
import org.springframework.stereotype.Component;

Expand All @@ -16,16 +17,17 @@ public class RisWhoisFetcher {

private static final int HTTP_TIMEOUT = 30 * DateTimeConstants.MILLIS_PER_SECOND;

public String fetch(String url) throws IOException {
try (InputStream unzipped = new GZIPInputStream(getContent(url))) {
return IOUtils.toString(unzipped, StandardCharsets.UTF_8);
public Pair<String, Long> fetch(String url) throws IOException {
var content = getContent(url);
try (InputStream unzipped = new GZIPInputStream(content.getLeft())) {
return Pair.of(IOUtils.toString(unzipped, StandardCharsets.UTF_8), content.getRight());
}
}

protected InputStream getContent(String url) throws IOException {
protected Pair<InputStream, Long> getContent(String url) throws IOException {
URLConnection connection = new URL(url).openConnection();
connection.setConnectTimeout(HTTP_TIMEOUT);
connection.setReadTimeout(HTTP_TIMEOUT);
return connection.getInputStream();
return Pair.of(connection.getInputStream(), connection.getLastModified());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,5 @@ public interface PropertyEntityRepository extends Repository<PropertyEntity> {

PropertyEntity findByKey(String key);

PropertyEntity getByKey(String key);

void createOrUpdate(String key, String value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void visitIncomingCertificateUpdatedEvent(IncomingCertificateUpdatedEvent

private void updateRoaConfigurationsForResources(ManagedCertificateAuthority ca, ImmutableResourceSet nowCurrentResources, CommandContext context) {
final Optional<RoaConfiguration> maybeConfig = roaConfigurationRepository.findByCertificateAuthority(ca);
if (!maybeConfig.isPresent()) {
if (maybeConfig.isEmpty()) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.ripe.rpki.rest.service;

import jakarta.annotation.PostConstruct;
import lombok.Getter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import net.ripe.ipresource.ImmutableResourceSet;
Expand Down Expand Up @@ -135,10 +136,10 @@ enum PrefixValidationResult {
OWNERSHIP_ERROR("ownership", "You are not a holder of the prefix %s"),
OK("ok", "");

@Getter
private final String type;
private final String message;


PrefixValidationResult(String type, String message) {
this.type = type;
this.message = message;
Expand All @@ -147,10 +148,6 @@ enum PrefixValidationResult {
public String getMessage(String resource) {
return String.format(message, resource);
}

public String getType() {
return type;
}
}

private static class CaNameFormatter implements Formatter<CaName> {
Expand Down
48 changes: 44 additions & 4 deletions src/main/java/net/ripe/rpki/rest/service/AnnouncementService.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -68,11 +69,30 @@ public AnnouncementService(BgpRisEntryViewService bgpRisEntryViewService,
this.roaAlertConfigurationViewService = roaAlertConfigurationViewService;
}

/**
* @deprecated This end-point only exists for the current RPKI dashboard. Remove this call as soon as either it's
* not used from ripe-portal anymore or the whole ripe-portal-based RPKI dashboard is not used anymore.
*/
@GetMapping
@Operation(summary = "Get all announcements, as well as not-announced ignored announcements for the CA")
public ResponseEntity<List<BgpAnnouncement>> getResourcesForCa(@PathVariable("caName") final CaName caName) {
@Operation(summary = "Get all announcements, as well as not-announced ignored announcements for the CA", deprecated = true)
@Deprecated(since = "2024-07-17", forRemoval = true)
public ResponseEntity<?> getResourcesForCa(@PathVariable("caName") final CaName caName) {
log.info("Getting resources for CA: {}", caName);
var response = getAnnouncements(caName);
if (response instanceof AnnouncementResponse.Announcements as) {
return ok(as.announcements);
}
return ok(new AnnouncementResponse.Announcements(Collections.emptyList(), null));
}

@GetMapping("extended")
@Operation(summary = "Get all announcements, metadata for them and not-announced ignored announcements for the CA")
public ResponseEntity<AnnouncementResponse> getResourcesForCaWithMetadata(@PathVariable("caName") final CaName caName) {
log.info("Getting resources for CA: {}", caName);
return ok(getAnnouncements(caName));
}

private AnnouncementResponse getAnnouncements(CaName caName) {
final HostedCertificateAuthorityData ca = getCa(HostedCertificateAuthorityData.class, caName);
final ImmutableResourceSet certifiedResources = ca.getResources();
final Map<Boolean, Collection<BgpRisEntry>> announcements = bgpRisEntryViewService.findMostSpecificContainedAndNotContained(certifiedResources);
Expand All @@ -93,7 +113,17 @@ public ResponseEntity<List<BgpAnnouncement>> getResourcesForCa(@PathVariable("ca
true)
).toList();

return ok(Stream.concat(announcedAnnouncements.stream(), notSeenAnnouncements.stream()).toList());
Instant risLastUpdated = bgpRisEntryViewService.getLastUpdated();
if (certifiedResources.isEmpty())
return new AnnouncementResponse.Problem(NO_CA_RESOURCES);
else if (risLastUpdated == null)
return new AnnouncementResponse.Problem(NO_RIS_UPDATES);
else if (!announcements.isEmpty() &&
announcements.values().stream().allMatch(Collection::isEmpty))
return new AnnouncementResponse.Problem(NO_OVERLAP_WITH_RIS);

var announcement = Stream.concat(announcedAnnouncements.stream(), notSeenAnnouncements.stream()).toList();
return new AnnouncementResponse.Announcements(announcement, risLastUpdated);
}

private Set<AnnouncedRoute> bgpRisMapToAnnouncedRoutes(Map<Boolean, Collection<BgpRisEntry>> announcements) {
Expand All @@ -103,7 +133,6 @@ private Set<AnnouncedRoute> bgpRisMapToAnnouncedRoutes(Map<Boolean, Collection<B
.collect(Collectors.toSet());
}


@PostMapping("/affected")
@Operation(summary = "Get all announcements affected by the given ROA configuration of a CA")
public ResponseEntity<List<BgpAnnouncement>> getAffectedAnnouncementsForCaAndRoa(@PathVariable("caName") final CaName caName, @RequestBody final ApiRoaPrefix roa) {
Expand Down Expand Up @@ -156,4 +185,15 @@ public ResponseEntity<List<BgpAnnouncement>> getAffectedAnnouncementsForCaAndRoa
return ok(knownAnnouncements);
}

public static final String NO_CA_RESOURCES = "no-ca-resources";
public static final String NO_RIS_UPDATES = "no-ris-updates";
public static final String NO_OVERLAP_WITH_RIS = "no-overlap-with-ris";

public interface AnnouncementResponse {
record Problem(String emptyAnnouncementsReason) implements AnnouncementResponse {}

record Announcements(List<BgpAnnouncement> announcements,
Instant lastUpdated) implements AnnouncementResponse { }
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ private void populateWith(Map<CaName, ImmutableResourceSet> certifiableResources
private void registerUpdateCompleted() {
propertyEntityRepository.createOrUpdate(RESOURCE_CACHE_UPDATE_KEY, Instant.now().toString());
}

public void updateEntry(CaName caName, ImmutableResourceSet resources) {
entityManager.createNativeQuery(
"insert into resource_cache (name, resources) values (:name, :resources)\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import net.ripe.ipresource.ImmutableResourceSet;
import net.ripe.rpki.server.api.dto.BgpRisEntry;

import java.time.Instant;
import java.util.Collection;
import java.util.Map;


public interface BgpRisEntryViewService {

boolean isEmpty();
Expand All @@ -20,6 +20,7 @@ public interface BgpRisEntryViewService {

/**
* findMostSpecificContainedAndNotContained
*
* @param resources
* @return all matching BGP RIS entries that do not have a more specific matching entry,
* split into two collections: those fully covered (contained) by the given resource set
Expand All @@ -28,4 +29,8 @@ public interface BgpRisEntryViewService {
Map<Boolean, Collection<BgpRisEntry>> findMostSpecificContainedAndNotContained(ImmutableResourceSet resources);

void resetEntries(Collection<BgpRisEntry> entries);

Instant getLastUpdated();

void setLastUpdated(Instant lastUpdated);
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,17 @@ public boolean isActive() {
protected void runService(Map<String, String> parameters) {
List<BgpRisEntry> entries = new ArrayList<>();

AtomicLong lastUpdated = new AtomicLong(0);
for (String filename : FILENAMES) {
String url = risWhoisBaseUrl + "/" + filename;
try {
log.info("fetching RIS whois entries from {}", url);

String text = fetcher.fetch(url);
final Collection<BgpRisEntry> currentEntries = RisWhoisParser.parse(text);
var result = fetcher.fetch(url);
final Collection<BgpRisEntry> currentEntries = RisWhoisParser.parse(result.getLeft());
updateMetrics(url, currentEntries);

entries.addAll(currentEntries);
lastUpdated.updateAndGet(i -> Long.max(result.getRight(), i));
} catch (IOException | NullPointerException e) {
log.error(String.format("Exception while handling RIS dump from %s - aborting update", url), e);
}
Expand All @@ -87,6 +88,7 @@ protected void runService(Map<String, String> parameters) {
if (entries.size() >= MINIMUM_EXPECTED_UPDATES) {
log.info("fetched {} RIS whois entries.", entries.size());
repository.resetEntries(entries);
repository.setLastUpdated(Instant.ofEpochMilli(lastUpdated.get()));
} else {
log.error("Found an unusually small number of RIS whois entries, please check files at: {}", risWhoisBaseUrl);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@ public PropertyEntity findByKey(String key) {
}
}

@Override
public PropertyEntity getByKey(String key) {
PropertyEntity entity = findByKey(key);
Preconditions.checkNotNull(entity, "Could not find property by key: " + key);
return entity;
}

@Override
public synchronized void createOrUpdate(String key, String value) {
PropertyEntity entity = findByKey(key);
Expand Down
Loading

0 comments on commit a960ed6

Please sign in to comment.