diff options
Diffstat (limited to 'node-admin/src/main/java/com/yahoo')
5 files changed, 109 insertions, 8 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeAttributes.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeAttributes.java index 2379659f74b..e7c348bbbec 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeAttributes.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeAttributes.java @@ -4,11 +4,13 @@ package com.yahoo.vespa.hosted.node.admin.configserver.noderepository; import com.fasterxml.jackson.databind.JsonNode; import com.yahoo.component.Version; import com.yahoo.config.provision.DockerImage; +import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.bindings.NodeRepositoryNode; import java.time.Instant; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -29,6 +31,7 @@ public class NodeAttributes { private Optional<Version> vespaVersion = Optional.empty(); private Optional<Version> currentOsVersion = Optional.empty(); private Optional<Instant> currentFirmwareCheck = Optional.empty(); + private Set<TrustStoreItem> trustStore = Set.of(); /** The list of reports to patch. A null value is used to remove the report. */ private Map<String, JsonNode> reports = new TreeMap<>(); @@ -144,7 +147,17 @@ public class NodeAttributes { && Objects.equals(vespaVersion, other.vespaVersion) && Objects.equals(currentOsVersion, other.currentOsVersion) && Objects.equals(currentFirmwareCheck, other.currentFirmwareCheck) - && Objects.equals(reports, other.reports); + && Objects.equals(reports, other.reports) + && Objects.equals(trustStore, other.trustStore); + } + + public NodeAttributes withTrustStore(Set<TrustStoreItem> trustStore) { + this.trustStore = Set.copyOf(trustStore); + return this; + } + + public Set<TrustStoreItem> getTrustStore() { + return trustStore; } @Override @@ -156,7 +169,8 @@ public class NodeAttributes { vespaVersion.map(ver -> "vespaVersion=" + ver.toFullString()), currentOsVersion.map(ver -> "currentOsVersion=" + ver.toFullString()), currentFirmwareCheck.map(at -> "currentFirmwareCheck=" + at), - Optional.ofNullable(reports.isEmpty() ? null : "reports=" + reports)) + Optional.ofNullable(reports.isEmpty() ? null : "reports=" + reports), + Optional.of("trustStore:" + trustStore)) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.joining(", ", "{", "}")); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeSpec.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeSpec.java index e85d51ef992..96dc8cdd9fe 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeSpec.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeSpec.java @@ -68,6 +68,8 @@ public class NodeSpec { private final Optional<ApplicationId> exclusiveTo; + private final Set<TrustStoreItem> trustStore; + public NodeSpec( String hostname, Optional<String> id, @@ -98,7 +100,8 @@ public class NodeSpec { List<Event> events, Optional<String> parentHostname, Optional<URI> archiveUri, - Optional<ApplicationId> exclusiveTo) { + Optional<ApplicationId> exclusiveTo, + Set<TrustStoreItem> trustStore) { if (state == NodeState.active) { requireOptional(owner, "owner"); requireOptional(membership, "membership"); @@ -138,6 +141,7 @@ public class NodeSpec { this.parentHostname = Objects.requireNonNull(parentHostname); this.archiveUri = Objects.requireNonNull(archiveUri); this.exclusiveTo = Objects.requireNonNull(exclusiveTo); + this.trustStore = Objects.requireNonNull(trustStore); } public String hostname() { @@ -319,7 +323,8 @@ public class NodeSpec { Objects.equals(events, that.events) && Objects.equals(parentHostname, that.parentHostname) && Objects.equals(archiveUri, that.archiveUri) && - Objects.equals(exclusiveTo, that.exclusiveTo); + Objects.equals(exclusiveTo, that.exclusiveTo) && + Objects.equals(trustStore, that.trustStore); } @Override @@ -354,7 +359,8 @@ public class NodeSpec { events, parentHostname, archiveUri, - exclusiveTo); + exclusiveTo, + trustStore); } @Override @@ -390,6 +396,7 @@ public class NodeSpec { + " parentHostname=" + parentHostname + " archiveUri=" + archiveUri + " exclusiveTo=" + exclusiveTo + + " trustStore=" + trustStore + " }"; } @@ -424,6 +431,7 @@ public class NodeSpec { private Optional<String> parentHostname = Optional.empty(); private Optional<URI> archiveUri = Optional.empty(); private Optional<ApplicationId> exclusiveTo = Optional.empty(); + private Set<TrustStoreItem> trustStore = Set.of(); public Builder() {} @@ -456,6 +464,7 @@ public class NodeSpec { node.parentHostname.ifPresent(this::parentHostname); node.archiveUri.ifPresent(this::archiveUri); node.exclusiveTo.ifPresent(this::exclusiveTo); + trustStore(node.trustStore); } public Builder hostname(String hostname) { @@ -633,12 +642,19 @@ public class NodeSpec { return this; } + public Builder trustStore(Set<TrustStoreItem> trustStore) { + this.trustStore = Set.copyOf(trustStore); + return this; + } + public Builder updateFromNodeAttributes(NodeAttributes attributes) { attributes.getHostId().ifPresent(this::id); attributes.getDockerImage().ifPresent(this::currentDockerImage); attributes.getCurrentOsVersion().ifPresent(this::currentOsVersion); attributes.getRebootGeneration().ifPresent(this::currentRebootGeneration); attributes.getRestartGeneration().ifPresent(this::currentRestartGeneration); + // Always replace entire trust store + trustStore(attributes.getTrustStore()); this.reports.updateFromRawMap(attributes.getReports()); return this; @@ -752,7 +768,7 @@ public class NodeSpec { wantedRebootGeneration, currentRebootGeneration, wantedFirmwareCheck, currentFirmwareCheck, modelName, resources, realResources, ipAddresses, additionalIpAddresses, - reports, events, parentHostname, archiveUri, exclusiveTo); + reports, events, parentHostname, archiveUri, exclusiveTo, trustStore); } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/RealNodeRepository.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/RealNodeRepository.java index abc779d8a9a..d60a2f2e8ee 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/RealNodeRepository.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/RealNodeRepository.java @@ -155,6 +155,11 @@ public class RealNodeRepository implements NodeRepository { .map(event -> new Event(event.agent, event.event, Optional.ofNullable(event.at).map(Instant::ofEpochMilli).orElse(Instant.EPOCH))) .collect(Collectors.toUnmodifiableList()); + Set<TrustStoreItem> trustStore = Optional.ofNullable(node.trustStore).orElse(Set.of()).stream() + .map(item -> new TrustStoreItem(item.fingerprint, Instant.ofEpochMilli(item.expiry))) + .collect(Collectors.toSet()); + + return new NodeSpec( node.hostname, Optional.ofNullable(node.openStackId), @@ -185,7 +190,8 @@ public class RealNodeRepository implements NodeRepository { events, Optional.ofNullable(node.parentHostname), Optional.ofNullable(node.archiveUri).map(URI::create), - Optional.ofNullable(node.exclusiveTo).map(ApplicationId::fromSerializedForm)); + Optional.ofNullable(node.exclusiveTo).map(ApplicationId::fromSerializedForm), + trustStore); } private static NodeResources nodeResources(NodeRepositoryNode.NodeResources nodeResources) { @@ -270,7 +276,9 @@ public class RealNodeRepository implements NodeRepository { node.vespaVersion = nodeAttributes.getVespaVersion().map(Version::toFullString).orElse(null); node.currentOsVersion = nodeAttributes.getCurrentOsVersion().map(Version::toFullString).orElse(null); node.currentFirmwareCheck = nodeAttributes.getCurrentFirmwareCheck().map(Instant::toEpochMilli).orElse(null); - + node.trustStore = nodeAttributes.getTrustStore().stream() + .map(item -> new NodeRepositoryNode.TrustStoreItem(item.fingerprint(), item.expiry().toEpochMilli())) + .collect(Collectors.toSet()); Map<String, JsonNode> reports = nodeAttributes.getReports(); node.reports = reports == null || reports.isEmpty() ? null : new TreeMap<>(reports); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/TrustStoreItem.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/TrustStoreItem.java new file mode 100644 index 00000000000..d3e797bca24 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/TrustStoreItem.java @@ -0,0 +1,48 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.vespa.hosted.node.admin.configserver.noderepository; + +import java.time.Instant; +import java.util.Objects; + +/** + * @author mortent + */ +public class TrustStoreItem { + private final String fingerprint; + private final Instant expiry; + + public TrustStoreItem(String fingerprint, Instant expiry) { + this.fingerprint = fingerprint; + this.expiry = expiry; + } + + public String fingerprint() { + return fingerprint; + } + + public Instant expiry() { + return expiry; + } + + @Override + public String toString() { + return "TrustStoreItem{" + + "fingerprint='" + fingerprint + '\'' + + ", expiry=" + expiry + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TrustStoreItem that = (TrustStoreItem) o; + return Objects.equals(fingerprint, that.fingerprint) && Objects.equals(expiry, that.expiry); + } + + @Override + public int hashCode() { + return Objects.hash(fingerprint, expiry); + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/bindings/NodeRepositoryNode.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/bindings/NodeRepositoryNode.java index 4282c67b4cd..b07f7d8845f 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/bindings/NodeRepositoryNode.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/bindings/NodeRepositoryNode.java @@ -85,6 +85,8 @@ public class NodeRepositoryNode { public String exclusiveTo; @JsonProperty("history") public List<Event> history; + @JsonProperty("trustStore") + public Set<TrustStoreItem> trustStore; @JsonProperty("reports") public Map<String, JsonNode> reports = null; @@ -221,4 +223,17 @@ public class NodeRepositoryNode { '}'; } } + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class TrustStoreItem { + @JsonProperty ("fingerprint") + public String fingerprint; + @JsonProperty ("expiry") + public long expiry; + + public TrustStoreItem(@JsonProperty("fingerprint") String fingerprint, @JsonProperty("expiry") long expiry) { + this.fingerprint = fingerprint; + this.expiry = expiry; + } + } } |