Mark Payne created NIP-38:
-----------------------------
Summary: Pluggable Flow Persistence and Audit Storage
Key: NIP-38
URL: https://issues.apache.org/jira/browse/NIP-38
Project: NiFi Improvement Proposal
Issue Type: Improvement
Reporter: Mark Payne
h2. Motivation
Two parts of the NiFi framework are hardcoded to read and write local files,
with no way to redirect that storage elsewhere.
The first is the dataflow itself, which is always persisted to a local file as
GZIP-compressed JSON ({{{}flow.json.gz{}}}). Some deployments would benefit
from the ability to store the flow somewhere other than a local file, and there
is currently no extension point that lets the mechanism for loading and saving
the flow be replaced. This coupling also appears in components that only need
to read a small part of the flow. For example, {{FileAccessPolicyProvider}}
parses {{flow.json.gz}} directly to obtain the root process group identifier
when seeding initial access policies.
The second is the flow-change history (the audit trail of who changed what in
the flow), which is written to an embedded database under
{{{}nifi.database.directory{}}}. This history is stored by the
{{{}AuditService{}}}. An {{AuditService}} interface already exists, but the
framework constructs the {{EntityStoreAuditService}} implementation directly,
so there is no way to store this history anywhere other than the local embedded
database.
This NIP makes both storage mechanisms pluggable, using the same extension
pattern for each.
h2. Proposed Solution
h3. Flow Persistence Provider
Introduce a {{FlowPersistenceProvider}} extension point in
{{{}nifi-framework-api{}}}. A single provider is selected per instance and is
responsible for loading and saving the dataflow. The provider should operate on
{{{}VersionedDataflow{}}}; the encoding of the flow and the mechanism used to
store it are entirely the provider's concern.
{code:java}
/**
* Persists and restores the dataflow for a NiFi instance. A single provider is
selected per
* instance and is responsible for durably storing the flow so that it can be
recovered when
* NiFi restarts. The encoding of the flow and the mechanism used to store it
are entirely the
* provider's concern.
*/
public interface FlowPersistenceProvider {
/**
* Called once after instantiation to provide the provider with its
configuration.
*/
void initialize(FlowPersistenceProviderInitializationContext
initializationContext) throws IOException;
/**
* Loads the currently persisted flow, or an empty Optional when no flow
has been persisted.
*/
Optional<VersionedDataflow> loadFlow() throws IOException;
/**
* Persists the flow described by the given context, replacing any
previously persisted flow.
*/
void saveFlow(FlowPersistenceContext context) throws IOException;
}
{code}
{{saveFlow}} accepts a {{FlowPersistenceContext}} rather than a bare
{{VersionedDataflow}} so that additional detail about the save — for example a
human-readable description of what changed — can be added later without
breaking existing providers.
{{VersionedDataflow}} and {{VersionedFlowEncodingVersion}} move from
{{nifi-framework-core-api}} into {{nifi-framework-api}} so the extension point
can expose a typed API.
A default {{StandardFlowPersistenceProvider}} in {{nifi-framework-core}}
persists the flow as GZIP-compressed JSON to the configured flow configuration
file.
h3. Audit Service
Make the {{AuditService}} a selectable extension point. The interface moves
from {{nifi-administration}} into {{nifi-framework-api}} so that
implementations can be delivered in NARs, and it gains a default {{initialize}}
method that receives the implementation's configuration.
{code:java}
/**
* Called once after instantiation to provide the Audit Service with its
configuration. The
* default implementation does nothing so that existing implementations
continue to work
* unchanged.
*/
default void initialize(AuditServiceInitializationContext
initializationContext) throws IOException {
}
{code}
The implementation to use is selected in {{nifi.properties}} and defaults to
{{{}EntityStoreAuditService{}}}, which stores the flow-change history in the
existing embedded database. The directory the default implementation uses is
supplied through its initialization context, so the storage location is
configuration rather than a hardcoded file reference.
h2. Framework Changes
* New {{FlowPersistenceProvider}} extension point and supporting context types
in {{{}nifi-framework-api{}}}.
* {{VersionedDataflow}} and {{VersionedFlowEncodingVersion}} move from
{{nifi-framework-core-api}} to {{{}nifi-framework-api{}}}.
* Default {{StandardFlowPersistenceProvider}} plus its extension-discovery and
dependency-injection wiring in {{{}nifi-framework-core{}}}.
* Every point at which the framework saves the flow, and every point at which
it restores the flow, goes through the provider.
* {{FileAccessPolicyProvider}} obtains the root process group identifier from
the provider rather than reading {{flow.json.gz}} directly.
* The previous {{FlowConfigurationDAO}} / {{StandardFlowConfigurationDAO}} /
{{FlowParser}} / {{FlowInfo}} code path is removed.
* {{AuditService}} (and its supporting types {{{}History{}}},
{{{}HistoryQuery{}}}, {{{}PreviousValue{}}}) move from {{nifi-administration}}
to {{{}nifi-framework-api{}}}, and the interface gains a default {{initialize}}
method plus an {{{}AuditServiceInitializationContext{}}}.
* The {{AuditService}} implementation is created through extension-discovery
and dependency-injection wiring in {{nifi-framework-core}} instead of being
constructed directly.
* {{EntityStoreAuditService}} reads its storage directory from its
initialization context rather than from a hardcoded location.
h2. nifi.properties Configuration
* {{nifi.flow.persistence.provider.implementation}} — fully qualified class
name of the {{FlowPersistenceProvider}} to use. Default:
{{{}org.apache.nifi.controller.flow.StandardFlowPersistenceProvider{}}}.
* {{nifi.flow.persistence.provider.properties.<name>}} — provider-specific
configuration, passed to the provider through its initialization context.
* {{nifi.audit.service.implementation}} — fully qualified class name of the
{{AuditService}} to use. Default:
{{{}org.apache.nifi.admin.service.EntityStoreAuditService{}}}.
* {{nifi.audit.service.properties.<name>}} — implementation-specific
configuration, passed to the Audit Service through its initialization context.
The existing {{{}nifi.flow.configuration.file{}}},
{{{}nifi.flow.configuration.archive.*{}}}, and {{nifi.database.directory}}
properties are honored as fallbacks.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)