Skip to content

Commit

Permalink
fix(concourse): recursively parse plan for resources (#813)
Browse files Browse the repository at this point in the history
* fix(concourse): recursively parse plan for resources

Concourse build plan json is a recursive structure, not well-suited for pojo-mapping. This changes Plan.getResources() to a recursive parser for objects of shape {id, get/put:{name, type}}

Addresses issue: spinnaker/spinnaker#5895

* updates from code review

Co-authored-by: Jared Stehler <jared.stehler@edgenuity.com>
  • Loading branch information
jaredstehler and jared-stehler committed Jul 28, 2020
1 parent 84997c1 commit 3a8739d
Show file tree
Hide file tree
Showing 3 changed files with 472 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,76 +16,55 @@

package com.netflix.spinnaker.igor.concourse.client.model;

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import java.util.Map.Entry;
import java.util.stream.StreamSupport;
import lombok.Data;
import lombok.Setter;

@Data
public class Plan {
private InnerPlan plan;
private ObjectNode plan;

@Data
public static class InnerPlan {
@JsonAlias("do")
private List<Op> does;

@Nullable private OnFailure onFailure;
public List<Resource> getResources() {
return getResources(plan);
}

@Setter
public static class Op {
private String id;
private List<Resource> getResources(ObjectNode o) {
if (o.hasNonNull("id")) {
if (o.hasNonNull("get")) {
return Collections.singletonList(parseResource(o.get("id").asText(), o.get("get")));
}
if (o.hasNonNull("put")) {
return Collections.singletonList(parseResource(o.get("id").asText(), o.get("put")));
}
}

@Nullable private ResourceShape get;
List<Resource> res = new ArrayList<>();

@Nullable private ResourceShape put;
Iterator<Entry<String, JsonNode>> fields = o.fields();
while (fields.hasNext()) {
Entry<String, JsonNode> f = fields.next();

@Nullable private OnSuccess onSuccess;
if (f.getValue().isArray()) {
StreamSupport.stream(f.getValue().spliterator(), false)
.filter(JsonNode::isObject)
.map(jsonNode -> getResources((ObjectNode) jsonNode))
.forEach(res::addAll);

@Nullable
public Resource getResource() {
String resourceId = id;
ResourceShape shape = get;
if (shape == null && onSuccess != null) {
shape = onSuccess.getStep().put;
resourceId = onSuccess.getStep().id;
}
if (shape == null) {
return null;
} else if (f.getValue().isObject()) {
res.addAll(getResources((ObjectNode) f.getValue()));
}
return new Resource(resourceId, shape.getName(), shape.getType());
}
}

@Data
private static class ResourceShape {
private String type;
private String name;
}

@Data
private static class OnSuccess {
private Op step;
return res;
}

@Data
private static class OnFailure {
private InnerPlan step;
}

public List<Resource> getResources() {
return Optional.ofNullable(plan.getOnFailure())
.map(OnFailure::getStep)
.map(InnerPlan::getDoes)
.orElse(plan.getDoes())
.stream()
.map(Op::getResource)
.filter(Objects::nonNull)
.collect(Collectors.toList());
private Resource parseResource(String id, JsonNode res) {
return new Resource(id, res.get("name").asText(), res.get("type").asText());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ private Collection<Resource> getResources(String buildId) {

if (!resources.isEmpty()) {
setResourceMetadata(buildId, resources);
} else {
log.warn("No resources retrieved for buildId: {}", buildId);
}

return resources.values();
Expand Down
Loading

0 comments on commit 3a8739d

Please sign in to comment.