diff options
author | Ola Aunrønning <olaa@yahooinc.com> | 2023-06-28 09:50:12 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-28 09:50:12 +0200 |
commit | 60805d1274eed4c7cff037deb55255fea6b3f867 (patch) | |
tree | 162b0bb5963afaae27b9b6ccdf0fceaccdc2b344 | |
parent | 8dd76a44947424b2f6162c64395e5ffd0a352936 (diff) | |
parent | a256c020150f4327dcc276f1c82cde09e0227c90 (diff) |
Merge pull request #27554 from vespa-engine/olaa/cmr-category
Store CMR categories and forward to node reports
14 files changed, 56 insertions, 104 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java index e5b3422b79b..0c43a3704df 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java @@ -10,78 +10,13 @@ import static com.yahoo.vespa.hosted.controller.api.integration.vcmr.ChangeReque /** * @author olaa */ -public class ChangeRequestSource { - - private final String system; - private final String id; - private final Status status; - private final String url; - private final ZonedDateTime plannedStartTime; - private final ZonedDateTime plannedEndTime; - - - public ChangeRequestSource(String system, String id, String url, Status status, ZonedDateTime plannedStartTime, ZonedDateTime plannedEndTime) { - this.system = Objects.requireNonNull(system); - this.id = Objects.requireNonNull(id); - this.url = Objects.requireNonNull(url); - this.status = Objects.requireNonNull(status); - this.plannedStartTime = Objects.requireNonNull(plannedStartTime); - this.plannedEndTime = Objects.requireNonNull(plannedEndTime); - } - - public String getSystem() { - return system; - } - - public String getId() { - return id; - } - - public Status getStatus() { - return status; - } - - public String getUrl() { - return url; - } - - public ZonedDateTime getPlannedStartTime() { - return plannedStartTime; - } - - public ZonedDateTime getPlannedEndTime() { - return plannedEndTime; - } - - @Override - public String toString() { - return "ChangeRequestSource{" + - "system='" + system + '\'' + - ", id='" + id + '\'' + - ", status=" + status + - ", url='" + url + '\'' + - ", plannedStartTime=" + plannedStartTime + - ", plannedEndTime=" + plannedEndTime + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ChangeRequestSource that = (ChangeRequestSource) o; - return Objects.equals(system, that.system) && - Objects.equals(id, that.id) && - status == that.status && - Objects.equals(url, that.url) && - Objects.equals(plannedStartTime, that.plannedStartTime) && - Objects.equals(plannedEndTime, that.plannedEndTime); - } - - @Override - public int hashCode() { - return Objects.hash(system, id, status, url, plannedStartTime, plannedEndTime); - } +public record ChangeRequestSource(String system, + String id, + String url, + Status status, + ZonedDateTime plannedStartTime, + ZonedDateTime plannedEndTime, + String category) { public boolean isClosed() { return List.of(CLOSED, CANCELED, COMPLETE).contains(status); @@ -105,6 +40,7 @@ public class ChangeRequestSource { private Status status; private ZonedDateTime plannedStartTime; private ZonedDateTime plannedEndTime; + private String category; public Builder system(String system) { this.system = system; @@ -136,8 +72,13 @@ public class ChangeRequestSource { return this; } + public Builder category(String category) { + this.category = category; + return this; + } + public ChangeRequestSource build() { - return new ChangeRequestSource(system, id, url, status, plannedStartTime, plannedEndTime); + return new ChangeRequestSource(system, id, url, status, plannedStartTime, plannedEndTime, category); } } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VcmrReport.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VcmrReport.java index 660f3c50556..89cf6f4b28d 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VcmrReport.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VcmrReport.java @@ -47,12 +47,12 @@ public class VcmrReport { * @return true if list of VCMRs is changed */ public boolean addVcmr(ChangeRequestSource source) { - var vcmr = new Vcmr(source.getId(), source.getStatus().name(), source.getPlannedStartTime(), source.getPlannedEndTime()); + var vcmr = new Vcmr(source.id(), source.status().name(), source.plannedStartTime(), source.plannedEndTime(), source.category()); if (vcmrs.contains(vcmr)) return false; // Remove to catch any changes in start/end time - removeVcmr(source.getId()); + removeVcmr(source.id()); return vcmrs.add(vcmr); } @@ -95,6 +95,7 @@ public class VcmrReport { public record Vcmr (@JsonProperty("id") String id, @JsonProperty("status") String status, @JsonProperty("plannedStartTime") ZonedDateTime plannedStartTime, - @JsonProperty("plannedEndTime") ZonedDateTime plannedEndTime) {} + @JsonProperty("plannedEndTime") ZonedDateTime plannedEndTime, + @JsonProperty("category") String category) {} } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.java index e0f867b97be..2771520e7fc 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.java @@ -3,7 +3,6 @@ package com.yahoo.vespa.hosted.controller.api.integration.vcmr; import com.yahoo.config.provision.zone.ZoneId; -import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainer.java index e16d52703e9..320f15a8b18 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainer.java @@ -121,7 +121,7 @@ public class ChangeRequestMaintainer extends ControllerMaintainer { private boolean shouldDeleteChangeRequest(ChangeRequestSource source) { return source.isClosed() && - source.getPlannedStartTime() + source.plannedStartTime() .plus(Duration.ofDays(7)) .isBefore(ZonedDateTime.now()); } @@ -129,7 +129,7 @@ public class ChangeRequestMaintainer extends ControllerMaintainer { private void approveChangeRequest(ChangeRequest changeRequest) { if (system.equals(SystemName.main) && changeRequest.getApproval() == ChangeRequest.Approval.REQUESTED) { - logger.info("Approving " + changeRequest.getChangeRequestSource().getId()); + logger.info("Approving " + changeRequest.getChangeRequestSource().id()); changeRequestClient.approveChangeRequest(changeRequest); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java index d4c4b4efda7..df6e89fb5ef 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java @@ -170,7 +170,7 @@ public class VcmrMaintainer extends ControllerMaintainer { .orElse(new HostAction(node.hostname().value(), State.NONE, Instant.now())); if (changeRequest.getChangeRequestSource().isClosed()) { - LOG.fine(() -> changeRequest.getChangeRequestSource().getId() + " is closed, recycling " + node.hostname()); + LOG.fine(() -> changeRequest.getChangeRequestSource().id() + " is closed, recycling " + node.hostname()); recycleNode(zoneId, node, hostAction); removeReport(zoneId, changeRequest, node); return hostAction.withState(State.COMPLETE); @@ -179,14 +179,14 @@ public class VcmrMaintainer extends ControllerMaintainer { if (isLowImpact(changeRequest)) return hostAction; - if (shouldAddReport(node, changeRequest.getChangeRequestSource().getId(), hostAction)) + if (shouldAddReport(node, changeRequest.getChangeRequestSource().id(), hostAction)) addReport(zoneId, changeRequest, node); if (isOutOfSync(node, hostAction)) return hostAction.withState(State.OUT_OF_SYNC); if (isPostponed(changeRequest, hostAction)) { - LOG.fine(() -> changeRequest.getChangeRequestSource().getId() + " is postponed, recycling " + node.hostname()); + LOG.fine(() -> changeRequest.getChangeRequestSource().id() + " is postponed, recycling " + node.hostname()); recycleNode(zoneId, node, hostAction); return hostAction.withState(State.PENDING_RETIREMENT); } @@ -203,7 +203,7 @@ public class VcmrMaintainer extends ControllerMaintainer { if (shouldRetire(changeRequest, hostAction)) { if (!wantToRetireRecursive(zoneId, node)) { - LOG.info(Text.format("Retiring %s due to %s", node.hostname().value(), changeRequest.getChangeRequestSource().getId())); + LOG.info(Text.format("Retiring %s due to %s", node.hostname().value(), changeRequest.getChangeRequestSource().id())); // TODO: Remove try/catch once retirement is stabilized try { setWantToRetire(zoneId, node, true); @@ -256,14 +256,14 @@ public class VcmrMaintainer extends ControllerMaintainer { private boolean isPostponed(VespaChangeRequest changeRequest, HostAction action) { return List.of(State.RETIRED, State.RETIRING).contains(action.getState()) && - changeRequest.getChangeRequestSource().getPlannedStartTime() + changeRequest.getChangeRequestSource().plannedStartTime() .minus(ALLOWED_POSTPONEMENT_TIME) .isAfter(ZonedDateTime.now()); } private boolean shouldRetire(VespaChangeRequest changeRequest, HostAction action) { return action.getState() == State.PENDING_RETIREMENT && - getRetirementStartTime(changeRequest.getChangeRequestSource().getPlannedStartTime()) + getRetirementStartTime(changeRequest.getChangeRequestSource().plannedStartTime()) .isBefore(ZonedDateTime.now()); } @@ -348,14 +348,14 @@ public class VcmrMaintainer extends ControllerMaintainer { if (changeRequest.getApproval() != ChangeRequest.Approval.REQUESTED) return; - LOG.info("Approving " + changeRequest.getChangeRequestSource().getId()); + LOG.info("Approving " + changeRequest.getChangeRequestSource().id()); changeRequestClient.approveChangeRequest(changeRequest); } private void removeReport(ZoneId zoneId, VespaChangeRequest changeRequest, Node node) { var report = VcmrReport.fromReports(node.reports()); - if (report.removeVcmr(changeRequest.getChangeRequestSource().getId())) { + if (report.removeVcmr(changeRequest.getChangeRequestSource().id())) { updateReport(zoneId, node, report); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializer.java index dbf14f4df87..ba11ad1756f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializer.java @@ -45,6 +45,7 @@ public class ChangeRequestSerializer { private static final String ACTION_STATE_FIELD = "state"; private static final String LAST_UPDATED_FIELD = "lastUpdated"; private static final String HOSTS_FIELD = "hosts"; + private static final String CATEGORY_FIELD = "category"; public static VespaChangeRequest fromSlime(Slime slime) { @@ -56,6 +57,8 @@ public class ChangeRequestSerializer { var status = VespaChangeRequest.Status.valueOf(inspector.field(STATUS_FIELD).asString()); var impact = ChangeRequest.Impact.valueOf(inspector.field(IMPACT_FIELD).asString()); var approval = ChangeRequest.Approval.valueOf(inspector.field(APPROVAL_FIELD).asString()); + var category = inspector.field(CATEGORY_FIELD).valid() ? + inspector.field(CATEGORY_FIELD).asString() : "Unknown"; var impactedHosts = new ArrayList<String>(); inspector.field(IMPACTED_HOSTS_FIELD) @@ -111,22 +114,26 @@ public class ChangeRequestSerializer { } private static void writeChangeRequestSource(Cursor cursor, ChangeRequestSource source) { - cursor.setString(SOURCE_SYSTEM_FIELD, source.getSystem()); - cursor.setString(ID_FIELD, source.getId()); - cursor.setString(URL_FIELD, source.getUrl()); - cursor.setString(START_TIME_FIELD, source.getPlannedStartTime().toString()); - cursor.setString(END_TIME_FIELD, source.getPlannedEndTime().toString()); - cursor.setString(STATUS_FIELD, source.getStatus().name()); + cursor.setString(SOURCE_SYSTEM_FIELD, source.system()); + cursor.setString(ID_FIELD, source.id()); + cursor.setString(URL_FIELD, source.url()); + cursor.setString(START_TIME_FIELD, source.plannedStartTime().toString()); + cursor.setString(END_TIME_FIELD, source.plannedEndTime().toString()); + cursor.setString(STATUS_FIELD, source.status().name()); + cursor.setString(CATEGORY_FIELD, source.category()); } public static ChangeRequestSource readChangeRequestSource(Inspector inspector) { + var category = inspector.field(CATEGORY_FIELD).valid() ? + inspector.field(CATEGORY_FIELD).asString() : "Unknown"; return new ChangeRequestSource( inspector.field(SOURCE_SYSTEM_FIELD).asString(), inspector.field(ID_FIELD).asString(), inspector.field(URL_FIELD).asString(), ChangeRequestSource.Status.valueOf(inspector.field(STATUS_FIELD).asString()), ZonedDateTime.parse(inspector.field(START_TIME_FIELD).asString()), - ZonedDateTime.parse(inspector.field(END_TIME_FIELD).asString()) + ZonedDateTime.parse(inspector.field(END_TIME_FIELD).asString()), + category ); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java index a72e0fdfe52..f0c851f50ef 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java @@ -106,7 +106,7 @@ public class ChangeManagementApiHandler extends AuditLoggingRequestHandler { private HttpResponse changeRequestAssessment(String changeRequestId) { var optionalChangeRequest = controller.curator().readChangeRequests() .stream() - .filter(request -> changeRequestId.equals(request.getChangeRequestSource().getId())) + .filter(request -> changeRequestId.equals(request.getChangeRequestSource().id())) .findFirst(); if (optionalChangeRequest.isEmpty()) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainerTest.java index a20a2e26d22..a25304ee297 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeRequestMaintainerTest.java @@ -36,9 +36,9 @@ public class ChangeRequestMaintainerTest { changeRequestMaintainer.maintain(); persistedChangeRequest = tester.curator().readChangeRequest("some-id").get(); - assertEquals(Status.CANCELED, persistedChangeRequest.getChangeRequestSource().getStatus()); + assertEquals(Status.CANCELED, persistedChangeRequest.getChangeRequestSource().status()); assertEquals(ChangeRequest.Approval.APPROVED, persistedChangeRequest.getApproval()); - assertEquals(time, persistedChangeRequest.getChangeRequestSource().getPlannedStartTime()); + assertEquals(time, persistedChangeRequest.getChangeRequestSource().plannedStartTime()); assertEquals(0, changeRequestClient.getApprovedChangeRequests().size()); } @@ -99,6 +99,7 @@ public class ChangeRequestMaintainerTest { .url("some-url") .system("some-system") .status(status) + .category("some-category") .build()) .build(); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java index 39bf61df9ed..cba916df52a 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java @@ -58,7 +58,7 @@ public class VcmrMaintainerTest { @Test void recycle_hosts_after_completion() { var vcmrReport = new VcmrReport(); - vcmrReport.addVcmr(new ChangeRequestSource("aws", "id123", "url", ChangeRequestSource.Status.WAITING_FOR_APPROVAL , ZonedDateTime.now(), ZonedDateTime.now())); + vcmrReport.addVcmr(new ChangeRequestSource("aws", "id123", "url", ChangeRequestSource.Status.WAITING_FOR_APPROVAL , ZonedDateTime.now(), ZonedDateTime.now(), "N/A")); var parkedNode = createNode(host1, NodeType.host, Node.State.parked, true); var failedNode = createNode(host2, NodeType.host, Node.State.failed, false); var reports = vcmrReport.toNodeReports(); @@ -285,7 +285,7 @@ public class VcmrMaintainerTest { private VespaChangeRequest newChangeRequest(ChangeRequestSource.Status sourceStatus, State state1, State state2, ZonedDateTime startTime) { - var source = new ChangeRequestSource("aws", changeRequestId, "url", sourceStatus , startTime, ZonedDateTime.now()); + var source = new ChangeRequestSource("aws", changeRequestId, "url", sourceStatus , startTime, ZonedDateTime.now(), "N/A"); var actionPlan = List.of( new HostAction(host1.value(), state1, Instant.now()), new HostAction(host2.value(), state2, Instant.now()) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializerTest.java index 77686467336..a429e9090cc 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ChangeRequestSerializerTest.java @@ -21,7 +21,7 @@ public class ChangeRequestSerializerTest { @Test void reserialization_equality() { - var source = new ChangeRequestSource("aws", "id321", "url", ChangeRequestSource.Status.STARTED, ZonedDateTime.now(), ZonedDateTime.now()); + var source = new ChangeRequestSource("aws", "id321", "url", ChangeRequestSource.Status.STARTED, ZonedDateTime.now(), ZonedDateTime.now(), "Some category"); var actionPlan = List.of( new HostAction("host1", HostAction.State.RETIRING, Instant.now()), new HostAction("host2", HostAction.State.RETIRED, Instant.now()) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java index de2bf70997a..8a915d72b25 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java @@ -86,7 +86,7 @@ public class ChangeManagementApiHandlerTest extends ControllerContainerTest { private VespaChangeRequest createChangeRequest() { var instant = Instant.ofEpochMilli(9001); var date = ZonedDateTime.ofInstant(instant, java.time.ZoneId.of("UTC")); - var source = new ChangeRequestSource("aws", "id321", "url", ChangeRequestSource.Status.STARTED, date, date); + var source = new ChangeRequestSource("aws", "id321", "url", ChangeRequestSource.Status.STARTED, date, date, "N/A"); var actionPlan = List.of( new HostAction("host1", HostAction.State.RETIRING, instant), new HostAction("host2", HostAction.State.RETIRED, instant) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/patched-vcmr.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/patched-vcmr.json index 3db8b226b21..b05a299bc4d 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/patched-vcmr.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/patched-vcmr.json @@ -10,7 +10,8 @@ "url": "url", "plannedStartTime": "1970-01-01T00:00:09.001Z[UTC]", "plannedEndTime": "1970-01-01T00:00:09.001Z[UTC]", - "status": "STARTED" + "status": "STARTED", + "category": "N/A" }, "actionPlan": { "hosts": [ diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmr.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmr.json index 545fe289be8..531a182cad6 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmr.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmr.json @@ -10,7 +10,8 @@ "url": "url", "plannedStartTime": "1970-01-01T00:00:09.001Z[UTC]", "plannedEndTime": "1970-01-01T00:00:09.001Z[UTC]", - "status": "STARTED" + "status": "STARTED", + "category": "N/A" }, "actionPlan": { "hosts": [ diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmrs.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmrs.json index 4ae079ebfb4..3a456d09bc5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmrs.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/vcmrs.json @@ -12,7 +12,8 @@ "url": "url", "plannedStartTime": "1970-01-01T00:00:09.001Z[UTC]", "plannedEndTime": "1970-01-01T00:00:09.001Z[UTC]", - "status": "STARTED" + "status": "STARTED", + "category": "N/A" }, "actionPlan": { "hosts": [ |