This is an automated email from the ASF dual-hosted git repository.
markap14 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new ae61ebb5ed NIFI-12186 Add ability to export a versioned reporting task
snapshot (#7853)
ae61ebb5ed is described below
commit ae61ebb5eda7076c6a18ba0419b614b8516faf14
Author: Bryan Bende <[email protected]>
AuthorDate: Mon Oct 9 10:50:36 2023 -0400
NIFI-12186 Add ability to export a versioned reporting task snapshot (#7853)
* NIFI-12186 Add ability to export a versioned reporting task snapshot
- Add CLI commands and optional query param to specify specific reporting
task
---
.../nifi/flow/VersionedReportingTaskSnapshot.java | 48 +++++++
.../flow/mapping/NiFiRegistryFlowMapper.java | 3 +-
.../VersionedReportingTaskSnapshotMapper.java | 72 ++++++++++
.../org/apache/nifi/web/NiFiServiceFacade.java | 16 +++
.../apache/nifi/web/StandardNiFiServiceFacade.java | 49 +++++++
.../java/org/apache/nifi/web/api/FlowResource.java | 151 ++++++++++++++++-----
.../toolkit/cli/impl/client/nifi/FlowClient.java | 15 ++
.../impl/client/nifi/impl/JerseyFlowClient.java | 18 +++
.../cli/impl/command/nifi/NiFiCommandGroup.java | 4 +
.../command/nifi/flow/ExportReportingTask.java | 67 +++++++++
.../command/nifi/flow/ExportReportingTasks.java | 65 +++++++++
.../nifi/VersionedReportingTaskSnapshotResult.java | 63 +++++++++
12 files changed, 538 insertions(+), 33 deletions(-)
diff --git
a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTaskSnapshot.java
b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTaskSnapshot.java
new file mode 100644
index 0000000000..3da3f8c302
--- /dev/null
+++
b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTaskSnapshot.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.flow;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.List;
+
+@ApiModel
+public class VersionedReportingTaskSnapshot {
+
+ private List<VersionedReportingTask> reportingTasks;
+ private List<VersionedControllerService> controllerServices;
+
+ @ApiModelProperty(value = "The controller services")
+ public List<VersionedControllerService> getControllerServices() {
+ return controllerServices;
+ }
+
+ public void setControllerServices(List<VersionedControllerService>
controllerServices) {
+ this.controllerServices = controllerServices;
+ }
+
+ @ApiModelProperty(value = "The reporting tasks")
+ public List<VersionedReportingTask> getReportingTasks() {
+ return reportingTasks;
+ }
+
+ public void setReportingTasks(List<VersionedReportingTask> reportingTasks)
{
+ this.reportingTasks = reportingTasks;
+ }
+
+}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
index f1dfa857fb..b0ac1b8909 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
@@ -615,8 +615,9 @@ public class NiFiRegistryFlowMapper {
continue;
}
+ // if mapping a reporting task, serviceGroupId will be
null and we don't want to produce external service references
final String serviceGroupId =
serviceNode.getProcessGroupIdentifier();
- if (!includedGroupIds.contains(serviceGroupId)) {
+ if (serviceGroupId != null &&
!includedGroupIds.contains(serviceGroupId)) {
final String serviceId =
getId(serviceNode.getVersionedComponentId(), serviceNode.getIdentifier());
final ExternalControllerServiceReference
controllerServiceReference = new ExternalControllerServiceReference();
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedReportingTaskSnapshotMapper.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedReportingTaskSnapshotMapper.java
new file mode 100644
index 0000000000..fb00f48da6
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedReportingTaskSnapshotMapper.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.controller.serialization;
+
+import org.apache.nifi.controller.ReportingTaskNode;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.controller.service.ControllerServiceProvider;
+import org.apache.nifi.flow.VersionedControllerService;
+import org.apache.nifi.flow.VersionedReportingTask;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
+import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.registry.flow.mapping.NiFiRegistryFlowMapper;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class VersionedReportingTaskSnapshotMapper {
+
+ private final NiFiRegistryFlowMapper flowMapper;
+ private final ControllerServiceProvider controllerServiceProvider;
+
+ public VersionedReportingTaskSnapshotMapper(final ExtensionManager
extensionManager, final ControllerServiceProvider controllerServiceProvider) {
+ this.flowMapper = new NiFiRegistryFlowMapper(extensionManager);
+ this.controllerServiceProvider = controllerServiceProvider;
+ }
+
+ public VersionedReportingTaskSnapshot createMapping(final
Set<ReportingTaskNode> reportingTaskNodes, final Set<ControllerServiceNode>
controllerServiceNodes) {
+ final VersionedReportingTaskSnapshot versionedReportingTaskSnapshot =
new VersionedReportingTaskSnapshot();
+
versionedReportingTaskSnapshot.setReportingTasks(mapReportingTasks(reportingTaskNodes));
+
versionedReportingTaskSnapshot.setControllerServices(mapControllerServices(controllerServiceNodes));
+ return versionedReportingTaskSnapshot;
+ }
+
+ private List<VersionedReportingTask> mapReportingTasks(final
Set<ReportingTaskNode> reportingTaskNodes) {
+ final List<VersionedReportingTask> reportingTasks = new ArrayList<>();
+
+ for (final ReportingTaskNode taskNode : reportingTaskNodes) {
+ final VersionedReportingTask versionedReportingTask =
flowMapper.mapReportingTask(taskNode, controllerServiceProvider);
+ reportingTasks.add(versionedReportingTask);
+ }
+
+ return reportingTasks;
+ }
+
+ private List<VersionedControllerService> mapControllerServices(final
Set<ControllerServiceNode> controllerServiceNodes) {
+ final List<VersionedControllerService> controllerServices = new
ArrayList<>();
+
+ for (final ControllerServiceNode serviceNode : controllerServiceNodes)
{
+ final VersionedControllerService versionedControllerService =
flowMapper.mapControllerService(
+ serviceNode, controllerServiceProvider,
Collections.emptySet(), Collections.emptyMap());
+ controllerServices.add(versionedControllerService);
+ }
+
+ return controllerServices;
+ }
+}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
index 8387d3e71c..4904fdef4d 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
@@ -29,6 +29,7 @@ import
org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.diagnostics.DiagnosticLevel;
import org.apache.nifi.flow.ExternalControllerServiceReference;
import org.apache.nifi.flow.ParameterProviderReference;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
import org.apache.nifi.flow.VersionedParameterContext;
import org.apache.nifi.flow.VersionedProcessGroup;
import org.apache.nifi.groups.ProcessGroup;
@@ -317,6 +318,21 @@ public interface NiFiServiceFacade {
*/
ControllerConfigurationEntity getControllerConfiguration();
+ /**
+ * Gets the snapshot for the given reporting task.
+ *
+ * @param reportingTaskId the id of the reporting task to get the snapshot
for
+ * @return the reporting task snapshot
+ */
+ VersionedReportingTaskSnapshot getVersionedReportingTaskSnapshot(String
reportingTaskId);
+
+ /**
+ * Gets the snapshot of all reporting tasks.
+ *
+ * @return the reporting task snapshot
+ */
+ VersionedReportingTaskSnapshot getVersionedReportingTaskSnapshot();
+
/**
* Gets the controller level bulletins.
*
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index a09aff5dce..eba0110932 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -91,7 +91,9 @@ import
org.apache.nifi.controller.leader.election.LeaderElectionManager;
import org.apache.nifi.controller.repository.FlowFileEvent;
import org.apache.nifi.controller.repository.FlowFileEventRepository;
import org.apache.nifi.controller.repository.claim.ContentDirection;
+import
org.apache.nifi.controller.serialization.VersionedReportingTaskSnapshotMapper;
import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.controller.service.ControllerServiceProvider;
import org.apache.nifi.controller.service.ControllerServiceReference;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.controller.status.ProcessGroupStatus;
@@ -113,6 +115,7 @@ import org.apache.nifi.flow.VersionedExternalFlowMetadata;
import org.apache.nifi.flow.VersionedFlowCoordinates;
import org.apache.nifi.flow.VersionedParameterContext;
import org.apache.nifi.flow.VersionedProcessGroup;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.groups.ProcessGroupCounts;
import org.apache.nifi.groups.RemoteProcessGroup;
@@ -4150,6 +4153,52 @@ public class StandardNiFiServiceFacade implements
NiFiServiceFacade {
return entityFactory.createControllerConfigurationEntity(dto,
revision, permissions);
}
+ @Override
+ public VersionedReportingTaskSnapshot
getVersionedReportingTaskSnapshot(final String reportingTaskId) {
+ final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final ReportingTaskNode reportingTaskNode =
reportingTaskDAO.getReportingTask(reportingTaskId);
+ return
getVersionedReportingTaskSnapshot(Collections.singleton(reportingTaskNode),
user);
+ }
+
+ @Override
+ public VersionedReportingTaskSnapshot getVersionedReportingTaskSnapshot() {
+ final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Set<ReportingTaskNode> reportingTaskNodes =
reportingTaskDAO.getReportingTasks();
+ return getVersionedReportingTaskSnapshot(reportingTaskNodes, user);
+ }
+
+ private VersionedReportingTaskSnapshot
getVersionedReportingTaskSnapshot(final Set<ReportingTaskNode>
reportingTaskNodes, final NiFiUser user) {
+ final Set<ControllerServiceNode> serviceNodes = new HashSet<>();
+ reportingTaskNodes.forEach(reportingTaskNode -> {
+ reportingTaskNode.authorize(authorizer, RequestAction.READ, user);
+ findReferencedControllerServices(reportingTaskNode, serviceNodes,
user);
+ });
+
+ final ExtensionManager extensionManager =
controllerFacade.getExtensionManager();
+ final ControllerServiceProvider serviceProvider =
controllerFacade.getControllerServiceProvider();
+ final VersionedReportingTaskSnapshotMapper snapshotMapper = new
VersionedReportingTaskSnapshotMapper(extensionManager, serviceProvider);
+ return snapshotMapper.createMapping(reportingTaskNodes, serviceNodes);
+ }
+
+ private void findReferencedControllerServices(final ComponentNode
componentNode, final Set<ControllerServiceNode> serviceNodes, final NiFiUser
user) {
+ componentNode.getPropertyDescriptors().forEach(descriptor -> {
+ if (descriptor.getControllerServiceDefinition() != null) {
+ final String serviceId =
componentNode.getEffectivePropertyValue(descriptor);
+ if (serviceId != null) {
+ try {
+ final ControllerServiceNode serviceNode =
controllerServiceDAO.getControllerService(serviceId);
+ serviceNode.authorize(authorizer, RequestAction.READ,
user);
+ if (serviceNodes.add(serviceNode)) {
+ findReferencedControllerServices(serviceNode,
serviceNodes, user);
+ }
+ } catch (ResourceNotFoundException e) {
+ // ignore if the resource is not found, if the
referenced service was previously deleted, it should not stop this action
+ }
+ }
+ }
+ });
+ }
+
@Override
public ControllerBulletinsEntity getControllerBulletins() {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
index a0f3701a41..ddad726a14 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
@@ -26,38 +26,6 @@ import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Authorization;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.annotations.Tag;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.StreamingOutput;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
@@ -77,6 +45,7 @@ import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.service.ControllerServiceNode;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.flow.ExecutionEngine;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.nar.NarClassLoadersHolder;
import org.apache.nifi.registry.client.NiFiRegistryException;
@@ -159,6 +128,41 @@ import org.apache.nifi.web.api.request.FlowMetricsRegistry;
import org.apache.nifi.web.api.request.IntegerParameter;
import org.apache.nifi.web.api.request.LongParameter;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.text.Collator;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
import static
org.apache.nifi.web.api.entity.ScheduleComponentsEntity.STATE_DISABLED;
import static
org.apache.nifi.web.api.entity.ScheduleComponentsEntity.STATE_ENABLED;
@@ -178,6 +182,9 @@ public class FlowResource extends ApplicationResource {
private static final String NIFI_REGISTRY_TYPE =
"org.apache.nifi.registry.flow.NifiRegistryFlowRegistryClient";
private static final String RECURSIVE = "false";
+ private static final String
VERSIONED_REPORTING_TASK_SNAPSHOT_FILENAME_PATTERN =
"VersionedReportingTaskSnapshot-%s.json";
+ private static final String VERSIONED_REPORTING_TASK_SNAPSHOT_DATE_FORMAT
= "yyyyMMddHHmmss";
+
private NiFiServiceFacade serviceFacade;
private Authorizer authorizer;
@@ -680,6 +687,86 @@ public class FlowResource extends ApplicationResource {
return generateOkResponse(entity).build();
}
+ /**
+ * Gets a snapshot of reporting tasks.
+ */
+ @GET
+ @Consumes(MediaType.WILDCARD)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("reporting-tasks/snapshot")
+ @ApiOperation(
+ value = "Get a snapshot of the given reporting tasks and any
controller services they use",
+ response = VersionedReportingTaskSnapshot.class,
+ authorizations = {
+ @Authorization(value = "Read - /flow")
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = 401, message = "Client could not be
authenticated."),
+ @ApiResponse(code = 403, message = "Client is not
authorized to make this request."),
+ @ApiResponse(code = 409, message = "The request was valid
but NiFi was not in the appropriate state to process it. Retrying the same
request later may be successful.")
+ }
+ )
+ public Response getReportingTaskSnapshot(
+ @ApiParam(value = "Specifies a reporting task id to export. If not
specified, all reporting tasks will be exported.")
+ @QueryParam("reportingTaskId") final String reportingTaskId
+ ) {
+
+ authorizeFlow();
+
+ if (isReplicateRequest()) {
+ return replicate(HttpMethod.GET);
+ }
+
+ final VersionedReportingTaskSnapshot snapshot = reportingTaskId == null
+ ? serviceFacade.getVersionedReportingTaskSnapshot() :
+
serviceFacade.getVersionedReportingTaskSnapshot(reportingTaskId);
+
+ return generateOkResponse(snapshot).build();
+ }
+
+ /**
+ * Downloads a snapshot of reporting tasks.
+ */
+ @GET
+ @Consumes(MediaType.WILDCARD)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("reporting-tasks/download")
+ @ApiOperation(
+ value = "Download a snapshot of the given reporting tasks and any
controller services they use",
+ response = byte[].class,
+ authorizations = {
+ @Authorization(value = "Read - /flow")
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = 401, message = "Client could not be
authenticated."),
+ @ApiResponse(code = 403, message = "Client is not
authorized to make this request."),
+ @ApiResponse(code = 409, message = "The request was valid
but NiFi was not in the appropriate state to process it. Retrying the same
request later may be successful.")
+ }
+ )
+ public Response downloadReportingTaskSnapshot(
+ @ApiParam(value = "Specifies a reporting task id to export. If not
specified, all reporting tasks will be exported.")
+ @QueryParam("reportingTaskId") final String reportingTaskId
+ ) {
+
+ authorizeFlow();
+
+ if (isReplicateRequest()) {
+ return replicate(HttpMethod.GET);
+ }
+
+ final VersionedReportingTaskSnapshot snapshot = reportingTaskId == null
+ ? serviceFacade.getVersionedReportingTaskSnapshot() :
+
serviceFacade.getVersionedReportingTaskSnapshot(reportingTaskId);
+
+ final SimpleDateFormat dateFormat = new
SimpleDateFormat(VERSIONED_REPORTING_TASK_SNAPSHOT_DATE_FORMAT);
+ final String filename =
VERSIONED_REPORTING_TASK_SNAPSHOT_FILENAME_PATTERN.formatted(dateFormat.format(new
Date()));
+ return
generateOkResponse(snapshot).header(HttpHeaders.CONTENT_DISPOSITION,
String.format("attachment; filename=\"%s\"", filename)).build();
+ }
+
/**
* Updates the specified process group.
*
diff --git
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/FlowClient.java
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/FlowClient.java
index 2d1c41edb3..ef1231b15a 100644
---
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/FlowClient.java
+++
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/FlowClient.java
@@ -16,6 +16,7 @@
*/
package org.apache.nifi.toolkit.cli.impl.client.nifi;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
import org.apache.nifi.web.api.entity.ActivateControllerServicesEntity;
import org.apache.nifi.web.api.entity.ClusteSummaryEntity;
import org.apache.nifi.web.api.entity.ConnectionStatusEntity;
@@ -122,6 +123,20 @@ public interface FlowClient {
*/
ReportingTasksEntity getReportingTasks() throws NiFiClientException,
IOException;
+ /**
+ * Retrieves the snapshot of all reporting tasks and their respective
controller services.
+ *
+ * @return the snapshot
+ */
+ VersionedReportingTaskSnapshot getReportingTaskSnapshot() throws
NiFiClientException, IOException;
+
+ /**
+ * Retrieves the snapshot of the given reporting task and it's respective
controller services.
+ *
+ * @return the snapshot
+ */
+ VersionedReportingTaskSnapshot getReportingTaskSnapshot(String
reportingTaskId) throws NiFiClientException, IOException;
+
/**
* Retrieves the parameter providers.
*
diff --git
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/impl/JerseyFlowClient.java
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/impl/JerseyFlowClient.java
index 8c8ea36151..8065ed6cca 100644
---
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/impl/JerseyFlowClient.java
+++
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/impl/JerseyFlowClient.java
@@ -17,6 +17,7 @@
package org.apache.nifi.toolkit.cli.impl.client.nifi.impl;
import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
import org.apache.nifi.toolkit.cli.impl.client.nifi.FlowClient;
import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClientException;
import org.apache.nifi.toolkit.cli.impl.client.nifi.ProcessGroupBox;
@@ -246,6 +247,23 @@ public class JerseyFlowClient extends AbstractJerseyClient
implements FlowClient
});
}
+ @Override
+ public VersionedReportingTaskSnapshot getReportingTaskSnapshot() throws
NiFiClientException, IOException {
+ return executeAction("Error retrieving reporting tasks", () -> {
+ final WebTarget target =
flowTarget.path("reporting-tasks/snapshot");
+ return
getRequestBuilder(target).get(VersionedReportingTaskSnapshot.class);
+ });
+ }
+
+ @Override
+ public VersionedReportingTaskSnapshot getReportingTaskSnapshot(final
String reportingTaskId) throws NiFiClientException, IOException {
+ return executeAction("Error retrieving reporting task", () -> {
+ final WebTarget target =
flowTarget.path("reporting-tasks/snapshot")
+ .queryParam("reportingTaskId", reportingTaskId);
+ return
getRequestBuilder(target).get(VersionedReportingTaskSnapshot.class);
+ });
+ }
+
@Override
public ParameterProvidersEntity getParamProviders() throws
NiFiClientException, IOException {
return executeAction("Error retrieving parameter providers", () -> {
diff --git
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/NiFiCommandGroup.java
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/NiFiCommandGroup.java
index 168043a8e6..29feb8073d 100644
---
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/NiFiCommandGroup.java
+++
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/NiFiCommandGroup.java
@@ -29,6 +29,8 @@ import
org.apache.nifi.toolkit.cli.impl.command.nifi.cs.GetControllerServices;
import org.apache.nifi.toolkit.cli.impl.command.nifi.flow.ClusterSummary;
import org.apache.nifi.toolkit.cli.impl.command.nifi.flow.CreateReportingTask;
import org.apache.nifi.toolkit.cli.impl.command.nifi.flow.CurrentUser;
+import org.apache.nifi.toolkit.cli.impl.command.nifi.flow.ExportReportingTask;
+import org.apache.nifi.toolkit.cli.impl.command.nifi.flow.ExportReportingTasks;
import
org.apache.nifi.toolkit.cli.impl.command.nifi.flow.GetControllerConfiguration;
import org.apache.nifi.toolkit.cli.impl.command.nifi.flow.GetReportingTask;
import org.apache.nifi.toolkit.cli.impl.command.nifi.flow.GetReportingTasks;
@@ -150,6 +152,8 @@ public class NiFiCommandGroup extends AbstractCommandGroup {
commands.add(new DeleteReportingTask());
commands.add(new StartReportingTasks());
commands.add(new StopReportingTasks());
+ commands.add(new ExportReportingTasks());
+ commands.add(new ExportReportingTask());
commands.add(new ListUsers());
commands.add(new CreateUser());
commands.add(new ListUserGroups());
diff --git
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/flow/ExportReportingTask.java
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/flow/ExportReportingTask.java
new file mode 100644
index 0000000000..331438ae5e
--- /dev/null
+++
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/flow/ExportReportingTask.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.toolkit.cli.impl.command.nifi.flow;
+
+import org.apache.commons.cli.MissingOptionException;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
+import org.apache.nifi.toolkit.cli.api.CommandException;
+import org.apache.nifi.toolkit.cli.api.Context;
+import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClient;
+import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClientException;
+import org.apache.nifi.toolkit.cli.impl.command.CommandOption;
+import org.apache.nifi.toolkit.cli.impl.command.nifi.AbstractNiFiCommand;
+import
org.apache.nifi.toolkit.cli.impl.result.nifi.VersionedReportingTaskSnapshotResult;
+
+import java.io.IOException;
+import java.util.Properties;
+
+public class ExportReportingTask extends
AbstractNiFiCommand<VersionedReportingTaskSnapshotResult> {
+
+ public ExportReportingTask() {
+ super("export-reporting-task",
VersionedReportingTaskSnapshotResult.class);
+ }
+
+ @Override
+ public void doInitialize(final Context context) {
+ addOption(CommandOption.RT_ID.createOption());
+ addOption(CommandOption.OUTPUT_FILE.createOption());
+ }
+
+ @Override
+ public String getDescription() {
+ return "Exports a snapshot of the specified reporting task and any
management controller services used by the reporting task. " +
+ " The --" + CommandOption.OUTPUT_FILE.getLongName() + " can be
used to export to a file, " +
+ "otherwise the content will be written to terminal or standard
out.";
+ }
+
+ @Override
+ public VersionedReportingTaskSnapshotResult doExecute(final NiFiClient
client, final Properties properties) throws NiFiClientException, IOException,
MissingOptionException, CommandException {
+ final String reportingTaskId = getRequiredArg(properties,
CommandOption.RT_ID);
+ final VersionedReportingTaskSnapshot snapshot =
client.getFlowClient().getReportingTaskSnapshot(reportingTaskId);
+
+ // currently export doesn't use the ResultWriter concept, it always
writes JSON
+ // destination will be a file if outputFile is specified, otherwise it
will be the output stream of the CLI
+ final String outputFile;
+ if (properties.containsKey(CommandOption.OUTPUT_FILE.getLongName())) {
+ outputFile =
properties.getProperty(CommandOption.OUTPUT_FILE.getLongName());
+ } else {
+ outputFile = null;
+ }
+
+ return new VersionedReportingTaskSnapshotResult(snapshot, outputFile);
+ }
+}
diff --git
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/flow/ExportReportingTasks.java
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/flow/ExportReportingTasks.java
new file mode 100644
index 0000000000..7e5e5caffd
--- /dev/null
+++
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/nifi/flow/ExportReportingTasks.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.toolkit.cli.impl.command.nifi.flow;
+
+import org.apache.commons.cli.MissingOptionException;
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
+import org.apache.nifi.toolkit.cli.api.CommandException;
+import org.apache.nifi.toolkit.cli.api.Context;
+import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClient;
+import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClientException;
+import org.apache.nifi.toolkit.cli.impl.command.CommandOption;
+import org.apache.nifi.toolkit.cli.impl.command.nifi.AbstractNiFiCommand;
+import
org.apache.nifi.toolkit.cli.impl.result.nifi.VersionedReportingTaskSnapshotResult;
+
+import java.io.IOException;
+import java.util.Properties;
+
+public class ExportReportingTasks extends
AbstractNiFiCommand<VersionedReportingTaskSnapshotResult> {
+
+ public ExportReportingTasks() {
+ super("export-reporting-tasks",
VersionedReportingTaskSnapshotResult.class);
+ }
+
+ @Override
+ public void doInitialize(final Context context) {
+ addOption(CommandOption.OUTPUT_FILE.createOption());
+ }
+
+ @Override
+ public String getDescription() {
+ return "Exports a snapshot of all reporting tasks and any management
controller services used by the reporting tasks. " +
+ " The --" + CommandOption.OUTPUT_FILE.getLongName() + " can be
used to export to a file, " +
+ "otherwise the content will be written to terminal or standard
out.";
+ }
+
+ @Override
+ public VersionedReportingTaskSnapshotResult doExecute(final NiFiClient
client, final Properties properties) throws NiFiClientException, IOException,
MissingOptionException, CommandException {
+ final VersionedReportingTaskSnapshot snapshot =
client.getFlowClient().getReportingTaskSnapshot();
+
+ // currently export doesn't use the ResultWriter concept, it always
writes JSON
+ // destination will be a file if outputFile is specified, otherwise it
will be the output stream of the CLI
+ final String outputFile;
+ if (properties.containsKey(CommandOption.OUTPUT_FILE.getLongName())) {
+ outputFile =
properties.getProperty(CommandOption.OUTPUT_FILE.getLongName());
+ } else {
+ outputFile = null;
+ }
+
+ return new VersionedReportingTaskSnapshotResult(snapshot, outputFile);
+ }
+}
diff --git
a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/result/nifi/VersionedReportingTaskSnapshotResult.java
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/result/nifi/VersionedReportingTaskSnapshotResult.java
new file mode 100644
index 0000000000..e8dc911253
--- /dev/null
+++
b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/result/nifi/VersionedReportingTaskSnapshotResult.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.toolkit.cli.impl.result.nifi;
+
+import org.apache.nifi.flow.VersionedReportingTaskSnapshot;
+import org.apache.nifi.toolkit.cli.api.WritableResult;
+import org.apache.nifi.toolkit.cli.impl.util.JacksonUtils;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Objects;
+
+/**
+ * Result for a VersionedReportingTaskSnapshot.
+ *
+ * If this result was created with a non-null exportFileName, then the write
method will ignore
+ * the passed in PrintStream, and will write the serialized snapshot to the
give file.
+ *
+ * If this result was created with a null exportFileName, then the write
method will write the
+ * serialized snapshot to the given PrintStream.
+ */
+public class VersionedReportingTaskSnapshotResult implements
WritableResult<VersionedReportingTaskSnapshot> {
+
+ private final VersionedReportingTaskSnapshot
versionedReportingTaskSnapshot;
+ private final String exportFileName;
+
+ public VersionedReportingTaskSnapshotResult(final
VersionedReportingTaskSnapshot versionedReportingTaskSnapshot, final String
exportFileName) {
+ this.versionedReportingTaskSnapshot =
Objects.requireNonNull(versionedReportingTaskSnapshot);
+ this.exportFileName = exportFileName;
+ }
+
+ @Override
+ public VersionedReportingTaskSnapshot getResult() {
+ return versionedReportingTaskSnapshot;
+ }
+
+ @Override
+ public void write(final PrintStream output) throws IOException {
+ if (exportFileName != null) {
+ try (final OutputStream resultOut = new
FileOutputStream(exportFileName)) {
+ JacksonUtils.write(versionedReportingTaskSnapshot, resultOut);
+ }
+ } else {
+ JacksonUtils.write(versionedReportingTaskSnapshot, output);
+ }
+ }
+}