From 1d7ec8dba84ab7a62b96b894ef5847560bea8f70 Mon Sep 17 00:00:00 2001 From: mayurinehate <33225191+mayurinehate@users.noreply.github.com> Date: Thu, 9 Dec 2021 04:26:31 +0530 Subject: [PATCH] feat(ingest): add nifi source (#3681) --- .github/workflows/metadata-ingestion-slow.yml | 49 + metadata-ingestion/README.md | 1 + metadata-ingestion/build.gradle | 9 +- metadata-ingestion/developing.md | 5 +- .../examples/recipes/file_to_datahub_rest.yml | 4 +- metadata-ingestion/setup.cfg | 1 + metadata-ingestion/setup.py | 4 + metadata-ingestion/source_docs/nifi.md | 74 ++ .../src/datahub/ingestion/source/nifi.py | 1024 +++++++++++++++++ .../tests/integration/nifi/docker-compose.yml | 126 ++ .../nifi/nifi_mces_golden_cluster.json | 353 ++++++ .../nifi/nifi_mces_golden_standalone.json | 119 ++ .../integration/nifi/setup/conf/flow.xml.gz | Bin 0 -> 62007 bytes .../nifi/setup/conf_clustered/flow.xml.gz | Bin 0 -> 61643 bytes .../integration/nifi/setup/sftp_files/baz.csv | 2 + .../setup/sftp_files/temperature/2021_11.csv | 2 + .../setup/sftp_files/temperature/2021_12.csv | 2 + .../tests/integration/nifi/test_nifi.py | 125 ++ metadata-ingestion/tox.ini | 2 +- 19 files changed, 1896 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/metadata-ingestion-slow.yml create mode 100644 metadata-ingestion/source_docs/nifi.md create mode 100644 metadata-ingestion/src/datahub/ingestion/source/nifi.py create mode 100644 metadata-ingestion/tests/integration/nifi/docker-compose.yml create mode 100644 metadata-ingestion/tests/integration/nifi/nifi_mces_golden_cluster.json create mode 100644 metadata-ingestion/tests/integration/nifi/nifi_mces_golden_standalone.json create mode 100644 metadata-ingestion/tests/integration/nifi/setup/conf/flow.xml.gz create mode 100644 metadata-ingestion/tests/integration/nifi/setup/conf_clustered/flow.xml.gz create mode 100644 metadata-ingestion/tests/integration/nifi/setup/sftp_files/baz.csv create mode 100644 metadata-ingestion/tests/integration/nifi/setup/sftp_files/temperature/2021_11.csv create mode 100644 metadata-ingestion/tests/integration/nifi/setup/sftp_files/temperature/2021_12.csv create mode 100644 metadata-ingestion/tests/integration/nifi/test_nifi.py diff --git a/.github/workflows/metadata-ingestion-slow.yml b/.github/workflows/metadata-ingestion-slow.yml new file mode 100644 index 0000000000..041bb5037d --- /dev/null +++ b/.github/workflows/metadata-ingestion-slow.yml @@ -0,0 +1,49 @@ +name: metadata ingestion slow integration tests +on: + push: + branches: + - master + paths-ignore: + - "docs/**" + - "**.md" + pull_request: + branches: + - master + paths: + - "**/nifi/**" + - "**/nifi.py" + release: + types: [published, edited] + +jobs: + metadata-ingestion-slow-integration: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.9"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: ./metadata-ingestion/scripts/install_deps.sh + - name: Run metadata-ingestion slow integration tests + run: ./gradlew :metadata-ingestion:testSlowIntegration + - uses: actions/upload-artifact@v2 + if: always() + with: + name: Test Results (metadata ingestion slow integration tests) + path: | + **/build/reports/tests/test/** + **/build/test-results/test/** + **/junit.*.xml + + event-file: + runs-on: ubuntu-latest + steps: + - name: Upload + uses: actions/upload-artifact@v2 + with: + name: Event File + path: ${{ github.event_path }} diff --git a/metadata-ingestion/README.md b/metadata-ingestion/README.md index 894ccb87c4..b191abdc6a 100644 --- a/metadata-ingestion/README.md +++ b/metadata-ingestion/README.md @@ -66,6 +66,7 @@ Sources: | [superset](./source_docs/superset.md) | `pip install 'acryl-datahub[superset]'` | Superset source | | [trino](./source_docs/trino.md) | `pip install 'acryl-datahub[trino]` | Trino source | | [starburst-trino-usage](./source_docs/trino.md) | `pip install 'acryl-datahub[starburst-trino-usage]'` | Starburst Trino usage statistics source | +| [nifi](./source_docs/nifi.md) | `pip install 'acryl-datahub[nifi]' | Nifi source | Sinks diff --git a/metadata-ingestion/build.gradle b/metadata-ingestion/build.gradle index f809e89b00..576a59e92b 100644 --- a/metadata-ingestion/build.gradle +++ b/metadata-ingestion/build.gradle @@ -78,7 +78,7 @@ task testQuick(type: Exec, dependsOn: installDev) { inputs.files(project.fileTree(dir: "tests/")) outputs.dir("${venv_name}") commandLine 'bash', '-x', '-c', - "source ${venv_name}/bin/activate && pytest -m 'not integration' -vv --continue-on-collection-errors --junit-xml=junit.quick.xml" + "source ${venv_name}/bin/activate && pytest -m 'not integration and not slow_integration' -vv --continue-on-collection-errors --junit-xml=junit.quick.xml" } task installDevTest(type: Exec, dependsOn: [installDev]) { @@ -105,7 +105,12 @@ task testSingle(dependsOn: [installDevTest]) { task testFull(type: Exec, dependsOn: [testQuick, installDevTest]) { commandLine 'bash', '-x', '-c', - "source ${venv_name}/bin/activate && pytest -vv --continue-on-collection-errors --junit-xml=junit.full.xml" + "source ${venv_name}/bin/activate && pytest -m 'not slow_integration' -vv --continue-on-collection-errors --junit-xml=junit.full.xml" +} + +task testSlowIntegration(type: Exec, dependsOn: [testQuick, installDevTest]) { + commandLine 'bash', '-x', '-c', + "source ${venv_name}/bin/activate && pytest -m 'slow_integration' -vv --continue-on-collection-errors --junit-xml=junit.full.xml" } task cleanPythonCache(type: Exec) { diff --git a/metadata-ingestion/developing.md b/metadata-ingestion/developing.md index 58b7e6cd60..c508e75237 100644 --- a/metadata-ingestion/developing.md +++ b/metadata-ingestion/developing.md @@ -97,10 +97,13 @@ pip install -e '.[dev]' pip install -e '.[integration-tests]' # Run unit tests. -pytest -m 'not integration' +pytest -m 'not integration and not slow_integration' # Run Docker-based integration tests. pytest -m 'integration' + +# Run Docker-based slow integration tests. +pytest -m 'slow_integration' ``` ### Sanity check code before committing diff --git a/metadata-ingestion/examples/recipes/file_to_datahub_rest.yml b/metadata-ingestion/examples/recipes/file_to_datahub_rest.yml index 453a8421d4..617c54e981 100644 --- a/metadata-ingestion/examples/recipes/file_to_datahub_rest.yml +++ b/metadata-ingestion/examples/recipes/file_to_datahub_rest.yml @@ -1,9 +1,9 @@ ---- +run_id: test_cluster # see https://datahubproject.io/docs/metadata-ingestion/source_docs/file for complete documentation source: type: "file" config: - filename: "./examples/mce_files/bootstrap_mce.json" + filename: "./tests/integration/nifi/nifi_mces_golden_cluster.json" # see https://datahubproject.io/docs/metadata-ingestion/sink_docs/datahub for complete documentation sink: diff --git a/metadata-ingestion/setup.cfg b/metadata-ingestion/setup.cfg index 3f3c45f800..c241fd5de0 100644 --- a/metadata-ingestion/setup.cfg +++ b/metadata-ingestion/setup.cfg @@ -54,6 +54,7 @@ disallow_untyped_defs = yes addopts = --cov=src --cov-report term-missing --cov-config setup.cfg --strict-markers markers = integration: marks tests to only run in integration (deselect with '-m "not integration"') + slow_integration: marks tests that are too slow to even run in integration (deselect with '-m "not slow_integration") testpaths = tests/unit tests/integration diff --git a/metadata-ingestion/setup.py b/metadata-ingestion/setup.py index 00d7de9682..522f424743 100644 --- a/metadata-ingestion/setup.py +++ b/metadata-ingestion/setup.py @@ -144,6 +144,8 @@ plugins: Dict[str, Set[str]] = { # PR is from same author as that of sqlalchemy-trino library below. "sqlalchemy-trino" }, + "nifi": {"requests"}, + } all_exclude_plugins: Set[str] = { @@ -296,6 +298,8 @@ entry_points = { "openapi = datahub.ingestion.source.openapi:OpenApiSource", "trino = datahub.ingestion.source.sql.trino:TrinoSource", "starburst-trino-usage = datahub.ingestion.source.usage.starburst_trino_usage:TrinoUsageSource", + "nifi = datahub.ingestion.source.nifi:NifiSource", + ], "datahub.ingestion.sink.plugins": [ "file = datahub.ingestion.sink.file:FileSink", diff --git a/metadata-ingestion/source_docs/nifi.md b/metadata-ingestion/source_docs/nifi.md new file mode 100644 index 0000000000..93bd259566 --- /dev/null +++ b/metadata-ingestion/source_docs/nifi.md @@ -0,0 +1,74 @@ +# Nifi + +For context on getting started with ingestion, check out our [metadata ingestion guide](../README.md). + +## Setup + +To install this plugin, run `pip install 'acryl-datahub[nifi]'`. + +## Capabilities + +This plugin extracts the following: + +- Nifi flow as `DataFlow` entity +- Ingress, egress processors, remote input and output ports as `DataJob` entity +- Input and output ports receiving remote connections as `Dataset` entity +- Lineage information between external datasets and ingress/egress processors by analyzing provenance events + +Current limitations: + +- Limited ingress/egress processors are supported + - S3: `ListS3`, `FetchS3Object`, `PutS3Object` + - SFTP: `ListSFTP`, `FetchSFTP`, `GetSFTP`, `PutSFTP` + +## Quickstart recipe + +Check out the following recipe to get started with ingestion! See [below](#config-details) for full configuration options. + +For general pointers on writing and running a recipe, see our [main recipe guide](../README.md#recipes). + +```yml +source: + type: "nifi" + config: + # Coordinates + site_url: "https://localhost:8443/nifi/" + + # Credentials + auth: SINGLE_USER + username: admin + password: password + +sink: + # sink configs +``` + +## Config details + +Note that a `.` is used to denote nested fields in the YAML recipe. + +| Field | Required | Default | Description | +| -------------------------- | -------- | -------------------------- | ------------------------------------------------------- | +| `site_url` | ✅ | `"https://localhost:8443/nifi/"` | URI to connect to. | +| `site_name` | | `"default"` | Site name to identify this site with, useful when using input and output ports receiving remote connections | +| `auth` | | `"NO_AUTH"` | Nifi authentication. must be one of : NO_AUTH, SINGLE_USER, CLIENT_CERT | +| `username` | | | Nifi username, must be set for `auth` = `"SINGLE_USER"` | +| `password` | | | Nifi password, must be set for `auth` = `"SINGLE_USER"` | +| `client_cert_file` | | | Path to PEM file containing the public certificates for the user/client identity, must be set for `auth` = `"CLIENT_CERT"` | +| `client_key_file` | | | Path to PEM file containing the client’s secret key | +| `client_key_password` | | | The password to decrypt the client_key_file | +| `ca_file` | | | Path to PEM file containing certs for the root CA(s) for the NiFi | +| `provenance_days` | | | time window to analyze provenance events for external datasets | +| `site_url_to_site_name` | | | Lookup to find site_name for site_url, required if using remote process groups in nifi flow | +|`process_group_pattern.allow`| | | List of regex patterns for process groups to include in ingestion. | +| `process_group_pattern.deny`| | | List of regex patterns for process groups to exclude from ingestion. | +| `process_group_pattern.ignoreCase` | | `True` | Whether to ignore case sensitivity during pattern matching. | +| `env` | | `"PROD"` | Environment to use in namespace when constructing URNs. | + +## Compatibility + +Coming soon! + +## Questions + +If you've got any questions on configuring this source, feel free to ping us on [our Slack](https://slack.datahubproject.io/)! diff --git a/metadata-ingestion/src/datahub/ingestion/source/nifi.py b/metadata-ingestion/src/datahub/ingestion/source/nifi.py new file mode 100644 index 0000000000..4f652e5a1f --- /dev/null +++ b/metadata-ingestion/src/datahub/ingestion/source/nifi.py @@ -0,0 +1,1024 @@ +import json +import logging +import ssl +import time +from dataclasses import dataclass, field +from datetime import datetime, timedelta, timezone +from enum import Enum +from typing import Callable, Dict, Iterable, List, Optional, Tuple +from urllib.parse import urljoin + +import requests +from dateutil import parser +from requests.adapters import HTTPAdapter + +import datahub.emitter.mce_builder as builder +from datahub.configuration.common import AllowDenyPattern, ConfigModel +from datahub.emitter.mcp import MetadataChangeProposalWrapper +from datahub.ingestion.api.common import PipelineContext +from datahub.ingestion.api.source import Source, SourceReport +from datahub.ingestion.api.workunit import MetadataWorkUnit +from datahub.metadata.schema_classes import ( + ChangeTypeClass, + DataFlowInfoClass, + DataJobInfoClass, + DataJobInputOutputClass, + DataPlatformInstanceClass, + DatasetPropertiesClass, +) + +logger = logging.getLogger(__name__) +NIFI = "nifi" + + +# Python requests does not support passing password for key file, +# The same can be achieved by mounting ssl context +# as described here - https://github.com/psf/requests/issues/2519 +# and here - https://github.com/psf/requests/issues/1573 +class SSLAdapter(HTTPAdapter): + def __init__(self, certfile, keyfile, password=None): + self.context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + self.context.load_cert_chain( + certfile=certfile, keyfile=keyfile, password=password + ) + super().__init__() + + def init_poolmanager(self, *args, **kwargs): + kwargs["ssl_context"] = self.context + return super().init_poolmanager(*args, **kwargs) + + +class NifiAuthType(Enum): + NO_AUTH = "NO_AUTH" + SINGLE_USER = "SINGLE_USER" + CLIENT_CERT = "CLIENT_CERT" + + +class NifiSourceConfig(ConfigModel): + site_url: str + + auth: NifiAuthType = NifiAuthType.NO_AUTH + + provenance_days: int = 7 # Fetch provenance events for past 1 week + process_group_pattern: AllowDenyPattern = AllowDenyPattern.allow_all() + + # Required for nifi deployments using Remote Process Groups + site_name: str = "default" + site_url_to_site_name: Dict[str, str] = {} + + # Required to be set if auth is of type SINGLE_USER + username: Optional[str] + password: Optional[str] + + # Required to be set if auth is of type CLIENT_CERT + client_cert_file: Optional[str] + client_key_file: Optional[str] + client_key_password: Optional[str] + + # Required to be set if nifi server certificate is not signed by + # root CA trusted by client system, e.g. self-signed certificates + ca_file: Optional[str] + + +TOKEN_ENDPOINT = "/nifi-api/access/token" +CLUSTER_ENDPOINT = "/nifi-api/flow/cluster/summary" +PG_ENDPOINT = "/nifi-api/flow/process-groups/" +PROVENANCE_ENDPOINT = "/nifi-api/provenance/" + + +class NifiType(Enum): + PROCESSOR = "PROCESSOR" + FUNNEL = "FUNNEL" + INPUT_PORT = "INPUT_PORT" + OUTPUT_PORT = "OUTPUT_PORT" + REMOTE_INPUT_PORT = "REMOTE_INPUT_PORT" + REMOTE_OUTPUT_PORT = "REMOTE_OUTPUT_PORT" + + +class NifiEventType: + CREATE = "CREATE" + FETCH = "FETCH" + SEND = "SEND" + RECEIVE = "RECEIVE" + + +class NifiProcessorType: + ListS3 = "org.apache.nifi.processors.aws.s3.ListS3" + FetchS3Object = "org.apache.nifi.processors.aws.s3.FetchS3Object" + PutS3Object = "org.apache.nifi.processors.aws.s3.PutS3Object" + ListSFTP = "org.apache.nifi.processors.standard.ListSFTP" + FetchSFTP = "org.apache.nifi.processors.standard.FetchSFTP" + GetSFTP = "org.apache.nifi.processors.standard.GetSFTP" + PutSFTP = "org.apache.nifi.processors.standard.PutSFTP" + + +# To support new processor type, +# 1. add an entry in KNOWN_INGRESS_EGRESS_PROCESORS +# 2. Implement provenance event analyzer to find external dataset and +# map it in provenance_event_to_lineage_map +class NifiProcessorProvenanceEventAnalyzer: + + KNOWN_INGRESS_EGRESS_PROCESORS = { + NifiProcessorType.ListS3: NifiEventType.CREATE, + NifiProcessorType.FetchS3Object: NifiEventType.FETCH, + NifiProcessorType.PutS3Object: NifiEventType.SEND, + NifiProcessorType.ListSFTP: NifiEventType.CREATE, + NifiProcessorType.FetchSFTP: NifiEventType.FETCH, + NifiProcessorType.GetSFTP: NifiEventType.RECEIVE, + NifiProcessorType.PutSFTP: NifiEventType.SEND, + } + + def __init__(self) -> None: + # Map of Nifi processor type to the provenance event analyzer to find lineage + self.provenance_event_to_lineage_map: Dict[ + str, Callable[[Dict], ExternalDataset] + ] = { + NifiProcessorType.ListS3: self.process_s3_provenance_event, + NifiProcessorType.FetchS3Object: self.process_s3_provenance_event, + NifiProcessorType.PutS3Object: self.process_s3_provenance_event, + NifiProcessorType.ListSFTP: self.process_sftp_provenance_event, + NifiProcessorType.FetchSFTP: self.process_sftp_provenance_event, + NifiProcessorType.GetSFTP: self.process_sftp_provenance_event, + NifiProcessorType.PutSFTP: self.process_sftp_provenance_event, + } + + def process_s3_provenance_event(self, event): + attributes = event.get("attributes", []) + s3_bucket = get_attribute_value(attributes, "s3.bucket") + s3_key = get_attribute_value(attributes, "s3.key") + if not s3_key: + s3_key = get_attribute_value(attributes, "filename") + + s3_url = f"s3://{s3_bucket}/{s3_key}" + s3_url = s3_url[: s3_url.rindex("/")] + dataset_name = s3_url.replace("s3://", "").replace("/", ".") + platform = "urn:li:dataPlatform:s3" + dataset_urn = builder.make_dataset_urn(platform, dataset_name) + return ExternalDataset( + platform, + dataset_name, + dict(s3_uri=s3_url), + dataset_urn, + ) + + def process_sftp_provenance_event(self, event): + attributes = event.get("attributes", []) + remote_host = get_attribute_value(attributes, "sftp.remote.host") + path = get_attribute_value(attributes, "path") + filename = get_attribute_value(attributes, "filename") + absolute_path = f"sftp://{remote_host}/{path}/{filename}" + if remote_host is None or path is None or filename is None: + absolute_path = event.get("transitUri") + + absolute_path = absolute_path.replace("/./", "/") + if absolute_path.endswith("/."): + absolute_path = absolute_path[:-2] + absolute_path = absolute_path[: absolute_path.rindex("/")] + dataset_name = absolute_path.replace("sftp://", "").replace("/", ".") + platform = "file" + dataset_urn = builder.make_dataset_urn(platform, dataset_name) + return ExternalDataset( + platform, + dataset_name, + dict(uri=absolute_path), + dataset_urn, + ) + + +@dataclass +class ExternalDataset: + platform: str + dataset_name: str + dataset_properties: Dict[str, str] + dataset_urn: str + + +@dataclass +class NifiComponent: + id: str + name: str + type: str + parent_group_id: str + nifi_type: NifiType + comments: Optional[str] = None + status: Optional[str] = None + + # present only for nifi remote ports and processors + inlets: Dict[str, ExternalDataset] = field(default_factory=dict) + outlets: Dict[str, ExternalDataset] = field(default_factory=dict) + + # present only for processors + config: Optional[Dict] = None + + # present only for nifi remote ports + target_uris: Optional[str] = None + parent_rpg_id: Optional[str] = None + + # Last successful event time + last_event_time: Optional[str] = None + + +@dataclass +class NifiProcessGroup: + id: str + name: str + parent_group_id: Optional[str] + + +@dataclass +class NifiRemoteProcessGroup: + id: str + name: str + parent_group_id: str + remote_ports: Dict[str, NifiComponent] + + +@dataclass +class NifiFlow: + clustered: Optional[bool] + root_process_group: NifiProcessGroup + components: Dict[str, NifiComponent] = field(default_factory=dict) + remotely_accessible_ports: Dict[str, NifiComponent] = field(default_factory=dict) + connections: List[Tuple[str, str]] = field(default_factory=list) + processGroups: Dict[str, NifiProcessGroup] = field(default_factory=dict) + remoteProcessGroups: Dict[str, NifiRemoteProcessGroup] = field(default_factory=dict) + remote_ports: Dict[str, NifiComponent] = field(default_factory=dict) + + +def get_attribute_value(attr_lst: List[dict], attr_name: str) -> Optional[str]: + match = [entry for entry in attr_lst if entry["name"] == attr_name] + if len(match) > 0: + return match[0]["value"] + return None + + +@dataclass +class NifiSourceReport(SourceReport): + filtered: List[str] = field(default_factory=list) + + def report_dropped(self, ent_name: str) -> None: + self.filtered.append(ent_name) + + +# allowRemoteAccess +class NifiSource(Source): + config: NifiSourceConfig + report: NifiSourceReport + + def __init__(self, config: NifiSourceConfig, ctx: PipelineContext) -> None: + super().__init__(ctx) + self.config = config + self.report = NifiSourceReport() + self.session = requests.Session() + + if self.config.ca_file is not None: + self.session.verify = self.config.ca_file + + if self.config.site_url_to_site_name is None: + self.config.site_url_to_site_name = {} + if ( + not urljoin(self.config.site_url, "/nifi/") + in self.config.site_url_to_site_name + ): + self.config.site_url_to_site_name[ + urljoin(self.config.site_url, "/nifi/") + ] = self.config.site_name + + if self.config.auth is NifiAuthType.CLIENT_CERT: + logger.debug("Setting client certificates in requests ssl context") + assert ( + self.config.client_cert_file is not None + ), "Config client_cert_file is required for CLIENT_CERT auth" + self.session.mount( + urljoin(self.config.site_url, "/nifi-api/"), + SSLAdapter( + certfile=self.config.client_cert_file, + keyfile=self.config.client_key_file, + password=self.config.client_key_password, + ), + ) + if self.config.auth is NifiAuthType.SINGLE_USER: + assert ( + self.config.username is not None + ), "Config username is required for SINGLE_USER auth" + assert ( + self.config.password is not None + ), "Config password is required for SINGLE_USER auth" + token_response = self.session.post( + url=urljoin(self.config.site_url, TOKEN_ENDPOINT), + data={"username": self.config.username, "password": "admin@datahub"}, + ) + if not token_response.ok: + logger.error("Failed to get token") + self.report.report_failure(self.config.site_url, "Failed to get token") + + self.session.headers.update( + { + "Authorization": "Bearer " + token_response.text, + # "Accept": "application/json", + "Content-Type": "application/json", + } + ) + else: + self.session.headers.update( + { + # "Accept": "application/json", + "Content-Type": "application/json", + } + ) + + @classmethod + def create(cls, config_dict: dict, ctx: PipelineContext) -> "Source": + config = NifiSourceConfig.parse_obj(config_dict) + return cls(config, ctx) + + def get_report(self) -> SourceReport: + return self.report + + def update_flow(self, pg_flow_dto: Dict) -> None: # noqa: C901 + breadcrumb_dto = pg_flow_dto.get("breadcrumb", {}).get("breadcrumb", {}) + nifi_pg = NifiProcessGroup( + breadcrumb_dto.get("id"), + breadcrumb_dto.get("name"), + pg_flow_dto.get("parentGroupId"), + ) + self.nifi_flow.processGroups[nifi_pg.id] = nifi_pg + if not self.config.process_group_pattern.allowed(nifi_pg.name): + self.report.report_dropped(f"{nifi_pg.name}.*") + return + + flow_dto = pg_flow_dto.get("flow", {}) + + for processor in flow_dto.get("processors", []): + component = processor.get("component") + self.nifi_flow.components[component.get("id")] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + component.get("parentGroupId"), + NifiType.PROCESSOR, + config=component.get("config"), + comments=component.get("config", {}).get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + for funnel in flow_dto.get("funnels", []): + component = funnel.get("component") + self.nifi_flow.components[component.get("id")] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + component.get("parentGroupId"), + NifiType.FUNNEL, + comments=component.get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + logger.debug(f"Adding funnel {component.get('id')}") + + for connection in flow_dto.get("connections", []): + # Exclude self - recursive relationships + if connection.get("sourceId") != connection.get("destinationId"): + self.nifi_flow.connections.append( + (connection.get("sourceId"), connection.get("destinationId")) + ) + + for inputPort in flow_dto.get("inputPorts", []): + component = inputPort.get("component") + if inputPort.get("allowRemoteAccess"): + self.nifi_flow.remotely_accessible_ports[ + component.get("id") + ] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + component.get("parentGroupId"), + NifiType.INPUT_PORT, + comments=component.get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + logger.debug(f"Adding remotely accessible port {component.get('id')}") + else: + self.nifi_flow.components[component.get("id")] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + component.get("parentGroupId"), + NifiType.INPUT_PORT, + comments=component.get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + logger.debug(f"Adding port {component.get('id')}") + + for outputPort in flow_dto.get("outputPorts", []): + component = outputPort.get("component") + if outputPort.get("allowRemoteAccess"): + self.nifi_flow.remotely_accessible_ports[ + component.get("id") + ] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + component.get("parentGroupId"), + NifiType.OUTPUT_PORT, + comments=component.get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + logger.debug(f"Adding remotely accessible port {component.get('id')}") + else: + self.nifi_flow.components[component.get("id")] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + component.get("parentGroupId"), + NifiType.OUTPUT_PORT, + comments=component.get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + logger.debug(f"Adding report port {component.get('id')}") + + for rpg in flow_dto.get("remoteProcessGroups", []): + rpg_component = rpg.get("component", {}) + remote_ports = {} + + contents = rpg_component.get("contents", {}) + for component in contents.get("outputPorts", []): + if component.get("connected", False): + remote_ports[component.get("id")] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + rpg_component.get("parentGroupId"), + NifiType.REMOTE_OUTPUT_PORT, + target_uris=rpg_component.get("targetUris"), + parent_rpg_id=rpg_component.get("id"), + comments=component.get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + logger.debug(f"Adding remote output port {component.get('id')}") + + for component in contents.get("inputPorts", []): + if component.get("connected", False): + remote_ports[component.get("id")] = NifiComponent( + component.get("id"), + component.get("name"), + component.get("type"), + rpg_component.get("parentGroupId"), + NifiType.REMOTE_INPUT_PORT, + target_uris=rpg_component.get("targetUris"), + parent_rpg_id=rpg_component.get("id"), + comments=component.get("comments"), + status=component.get("status", {}).get("runStatus"), + ) + logger.debug(f"Adding remote input port {component.get('id')}") + + nifi_rpg = NifiRemoteProcessGroup( + rpg_component.get("id"), + rpg_component.get("name"), + component.get("parentGroupId"), + remote_ports, + ) + logger.debug(f"Adding remote process group {rpg_component.get('id')}") + self.nifi_flow.components.update(remote_ports) + self.nifi_flow.remoteProcessGroups[nifi_rpg.id] = nifi_rpg + + for pg in flow_dto.get("processGroups", []): + pg_response = self.session.get( + url=urljoin(self.config.site_url, PG_ENDPOINT) + pg.get("id") + ) + + if not pg_response.ok: + self.report_warning( + self.config.site_url, + "Failed to get process group flow " + pg.get("id"), + ) + continue + + pg_flow_dto = pg_response.json().get("processGroupFlow", {}) + + self.update_flow(pg_flow_dto) + + def update_flow_keep_only_ingress_egress(self): + components_to_del: List[NifiComponent] = [] + for component in self.nifi_flow.components.values(): + if ( + component.nifi_type is NifiType.PROCESSOR + and component.type + not in NifiProcessorProvenanceEventAnalyzer.KNOWN_INGRESS_EGRESS_PROCESORS.keys() + ) or component.nifi_type not in [ + NifiType.PROCESSOR, + NifiType.REMOTE_INPUT_PORT, + NifiType.REMOTE_OUTPUT_PORT, + ]: + components_to_del.append(component) + incoming = list( + filter(lambda x: x[1] == component.id, self.nifi_flow.connections) + ) + outgoing = list( + filter(lambda x: x[0] == component.id, self.nifi_flow.connections) + ) + # Create new connections from incoming to outgoing + for i in incoming: + for j in outgoing: + self.nifi_flow.connections.append((i[0], j[1])) + + # Remove older connections, as we already created + # new connections bypassing component to be deleted + + for i in incoming: + self.nifi_flow.connections.remove(i) + for j in outgoing: + self.nifi_flow.connections.remove(j) + + for c in components_to_del: + if c.nifi_type is NifiType.PROCESSOR and ( + c.name.startswith("Get") + or c.name.startswith("List") + or c.name.startswith("Fetch") + or c.name.startswith("Put") + ): + self.report_warning( + self.config.site_url, + f"Dropping Nifi Processor of type {c.type}, id {c.id}, name {c.name} from lineage view. \ + This is likely an Ingress or Egress node which may be reading to/writing from external datasets \ + However not currently supported in datahub", + ) + else: + logger.debug( + f"Dropping Nifi Component of type {c.type}, id {c.id}, name {c.name} from lineage view." + ) + + del self.nifi_flow.components[c.id] + + def create_nifi_flow(self): + cluster_response = self.session.get( + url=urljoin(self.config.site_url, CLUSTER_ENDPOINT) + ) + clustered: Optional[bool] = None + if cluster_response.ok: + clustered = ( + cluster_response.json().get("clusterSummary", {}).get("clustered") + ) + else: + logger.warn("Failed to fetch cluster summary for flow") + pg_response = self.session.get( + url=urljoin(self.config.site_url, PG_ENDPOINT) + "root" + ) + + if not pg_response.ok: + logger.error("Failed to get root process group flow") + self.report.report_failure( + self.config.site_url, "Failed to get of root process group flow" + ) + + pg_flow_dto = pg_response.json().get("processGroupFlow", {}) + breadcrumb_dto = pg_flow_dto.get("breadcrumb", {}).get("breadcrumb", {}) + self.nifi_flow = NifiFlow( + clustered=clustered, + root_process_group=NifiProcessGroup( + breadcrumb_dto.get("id"), + breadcrumb_dto.get("name"), + pg_flow_dto.get("parentGroupId"), + ), + ) + self.update_flow(pg_flow_dto) + self.update_flow_keep_only_ingress_egress() + + def fetch_provenance_events( + self, + processor: NifiComponent, + eventType: str, + startDate: datetime, + endDate: Optional[datetime] = None, + ) -> Iterable[Dict]: + + logger.debug( + f"Fetching {eventType} provenance events for {processor.id}\ + of processor type {processor.type}, Start date: {startDate}, End date: {endDate}" + ) + + payload = json.dumps( + { + "provenance": { + "request": { + "maxResults": 1000, + "summarize": False, + "searchTerms": { + "ProcessorID": {"value": processor.id}, + "EventType": {"value": eventType}, + }, + "startDate": startDate.strftime("%m/%d/%Y %H:%M:%S %Z"), + "endDate": ( + endDate.strftime("%m/%d/%Y %H:%M:%S %Z") + if endDate + else None + ), + } + } + } + ) + logger.debug(payload) + provenance_response = self.session.post( + url=urljoin(self.config.site_url, PROVENANCE_ENDPOINT), data=payload + ) + + if provenance_response.ok: + provenance = provenance_response.json().get("provenance", {}) + provenance_uri = provenance.get("uri") + + provenance_response = self.session.get(provenance_uri) + if provenance_response.ok: + provenance = provenance_response.json().get("provenance", {}) + + attempts = 5 # wait for at most 5 attempts 5*1= 5 seconds + while (not provenance.get("finished", False)) and attempts > 0: + logger.warn( + f"Provenance query not completed, attempts left : {attempts}" + ) + # wait until the uri returns percentcomplete 100 + time.sleep(1) + provenance_response = self.session.get(provenance_uri) + attempts -= 1 + if provenance_response.ok: + provenance = provenance_response.json().get("provenance", {}) + + events = provenance.get("results", {}).get("provenanceEvents", []) + last_event_time: Optional[datetime] = None + oldest_event_time: Optional[datetime] = None + + for event in events: + event_time = parser.parse(event.get("eventTime")) + # datetime.strptime( + # event.get("eventTime"), "%m/%d/%Y %H:%M:%S.%f %Z" + # ) + if not last_event_time or event_time > last_event_time: + last_event_time = event_time + + if not oldest_event_time or event_time < oldest_event_time: + oldest_event_time = event_time + + yield event + + processor.last_event_time = str(last_event_time) + self.delete_provenance(provenance_uri) + + total = provenance.get("results", {}).get("total") + totalCount = provenance.get("results", {}).get("totalCount") + if total != str(totalCount): + yield from self.fetch_provenance_events( + processor, eventType, startDate, oldest_event_time + ) + else: + self.report_warning( + self.config.site_url, + f"provenance events could not be fetched for processor \ + {processor.id} of type {processor.name}", + ) + logger.warn(provenance_response.text) + return + + def report_warning(self, key: str, reason: str) -> None: + logger.warning(f"{key}: {reason}") + self.report.report_warning(key, reason) + + def delete_provenance(self, provenance_uri): + delete_response = self.session.delete(provenance_uri) + if not delete_response.ok: + logger.error("failed to delete provenance ", provenance_uri) + + def construct_workunits(self) -> Iterable[MetadataWorkUnit]: # noqa: C901 + + rootpg = self.nifi_flow.root_process_group + flow_name = rootpg.name # self.config.site_name + flow_urn = builder.make_data_flow_urn(orchestrator=NIFI, flow_id=rootpg.id) + flow_properties = dict() + if self.nifi_flow.clustered is not None: + flow_properties["clustered"] = str(self.nifi_flow.clustered) + yield from self.construct_flow_workunits( + flow_urn, flow_name, self.make_external_url(rootpg.id), flow_properties + ) + + for component in self.nifi_flow.components.values(): + job_name = component.name + job_urn = builder.make_data_job_urn_with_flow(flow_urn, component.id) + + incoming = list( + filter(lambda x: x[1] == component.id, self.nifi_flow.connections) + ) + outgoing = list( + filter(lambda x: x[0] == component.id, self.nifi_flow.connections) + ) + inputJobs = [] + jobProperties = None + + if component.nifi_type is NifiType.PROCESSOR: + jobProperties = { + k: str(v) + for k, v in component.config.items() # type: ignore + if k + in [ + "schedulingPeriod", + "schedulingStrategy", + "executionNode", + "concurrentlySchedulableTaskCount", + ] + } + jobProperties["properties"] = json.dumps( + component.config.get("properties") # type: ignore + ) + if component.last_event_time is not None: + jobProperties["last_event_time"] = component.last_event_time + + for dataset in component.inlets.values(): + yield from self.construct_dataset_workunits( + dataset.platform, + dataset.dataset_name, + dataset.dataset_urn, + datasetProperties=dataset.dataset_properties, + ) + + for dataset in component.outlets.values(): + yield from self.construct_dataset_workunits( + dataset.platform, + dataset.dataset_name, + dataset.dataset_urn, + datasetProperties=dataset.dataset_properties, + ) + + for edge in incoming: + incoming_from = edge[0] + if incoming_from in self.nifi_flow.remotely_accessible_ports.keys(): + dataset_name = f"{self.config.site_name}.{self.nifi_flow.remotely_accessible_ports[incoming_from].name}" + dataset_urn = builder.make_dataset_urn( + NIFI, + dataset_name, + ) + component.inlets[dataset_urn] = ExternalDataset( + NIFI, + dataset_name, + dict(nifi_uri=self.config.site_url), + dataset_urn, + ) + else: + inputJobs.append( + builder.make_data_job_urn_with_flow(flow_urn, incoming_from) + ) + + for edge in outgoing: + outgoing_to = edge[1] + if outgoing_to in self.nifi_flow.remotely_accessible_ports.keys(): + dataset_name = f"{self.config.site_name}.{self.nifi_flow.remotely_accessible_ports[outgoing_to].name}" + dataset_urn = builder.make_dataset_urn(NIFI, dataset_name) + component.outlets[dataset_urn] = ExternalDataset( + NIFI, + dataset_name, + dict(nifi_uri=self.config.site_url), + dataset_urn, + ) + + if component.nifi_type is NifiType.REMOTE_INPUT_PORT: + # TODO - if target_uris is not set, but http proxy is used in RPG + site_urls = component.target_uris.split(",") # type: ignore + for site_url in site_urls: + if site_url not in self.config.site_url_to_site_name: + self.report_warning( + site_url, + f"Site with url {site_url} is being used in flow but\ + corresponding site name is not configured via site_url_to_site_name.\ + This may result in broken lineage.", + ) + else: + site_name = self.config.site_url_to_site_name[site_url] + dataset_name = f"{site_name}.{component.name}" + dataset_urn = builder.make_dataset_urn( + NIFI, + dataset_name, + ) + component.outlets[dataset_urn] = ExternalDataset( + NIFI, dataset_name, dict(nifi_uri=site_url), dataset_urn + ) + break + + if component.nifi_type is NifiType.REMOTE_OUTPUT_PORT: + site_urls = component.target_uris.split(",") # type: ignore + for site_url in site_urls: + if site_url not in self.config.site_url_to_site_name: + self.report_warning( + self.config.site_url, + f"Site with url {site_url} is being used in flow but\ + corresponding site name is not configured via site_url_to_site_name.\ + This may result in broken lineage.", + ) + else: + site_name = self.config.site_url_to_site_name[site_url] + + dataset_name = f"{site_name}.{component.name}" + dataset_urn = builder.make_dataset_urn( + NIFI, + dataset_name, + ) + component.inlets[dataset_urn] = ExternalDataset( + NIFI, dataset_name, dict(nifi_uri=site_url), dataset_urn + ) + break + + yield from self.construct_job_workunits( + job_urn, + job_name, + external_url=self.make_external_url( + component.parent_group_id, component.id, component.parent_rpg_id + ), + job_type=NIFI.upper() + "_" + component.nifi_type.value, + description=component.comments, + job_properties=jobProperties, + inlets=list(component.inlets.keys()), + outlets=list(component.outlets.keys()), + inputJobs=inputJobs, + status=component.status, + ) + + for port in self.nifi_flow.remotely_accessible_ports.values(): + dataset_name = f"{self.config.site_name}.{port.name}" + dataset_platform = NIFI + yield from self.construct_dataset_workunits( + dataset_platform, + dataset_name, + external_url=self.make_external_url(port.parent_group_id, port.id), + ) + + def process_provenance_events(self): + + startDate = datetime.now(timezone.utc) - timedelta( + days=self.config.provenance_days + ) + + eventAnalyzer = NifiProcessorProvenanceEventAnalyzer() + + for component in self.nifi_flow.components.values(): + if component.nifi_type is NifiType.PROCESSOR: + eventType = eventAnalyzer.KNOWN_INGRESS_EGRESS_PROCESORS[component.type] + events = self.fetch_provenance_events(component, eventType, startDate) + for event in events: + dataset = eventAnalyzer.provenance_event_to_lineage_map[ + component.type + ](event) + if eventType in [ + NifiEventType.CREATE, + NifiEventType.FETCH, + NifiEventType.RECEIVE, + ]: + component.inlets[dataset.dataset_urn] = dataset + else: + component.outlets[dataset.dataset_urn] = dataset + + def get_workunits(self) -> Iterable[MetadataWorkUnit]: + + # Creates nifi_flow by invoking /flow rest api and saves as self.nifi_flow + self.create_nifi_flow() + + # Updates inlets and outlets of nifi_flow.components by invoking /provenance rest api + self.process_provenance_events() + + # Reads and translates entities from self.nifi_flow into mcps + yield from self.construct_workunits() + + def make_external_url( + self, + parent_group_id: str, + component_id: Optional[str] = "", + parent_rpg_id: Optional[str] = None, + ) -> str: + if parent_rpg_id is not None: + component_id = parent_rpg_id + return urljoin( + self.config.site_url, + f"/nifi/?processGroupId={parent_group_id}&componentIds={component_id}", + ) + + def construct_flow_workunits( + self, + flow_urn: str, + flow_name: str, + external_url: str, + flow_properties: Optional[Dict[str, str]] = None, + ) -> Iterable[MetadataWorkUnit]: + mcp = MetadataChangeProposalWrapper( + entityType="dataFlow", + entityUrn=flow_urn, + changeType=ChangeTypeClass.UPSERT, + aspectName="dataFlowInfo", + aspect=DataFlowInfoClass( + name=flow_name, + customProperties=flow_properties, + externalUrl=external_url, + ), + ) + for proposal in [mcp]: + wu = MetadataWorkUnit( + id=f"{NIFI}.{flow_name}.{proposal.aspectName}", mcp=proposal + ) + self.report.report_workunit(wu) + yield wu + + def construct_job_workunits( + self, + job_urn: str, + job_name: str, + external_url: str, + job_type: str, + description: Optional[str], + job_properties: Optional[Dict[str, str]] = None, + inlets: List[str] = [], + outlets: List[str] = [], + inputJobs: List[str] = [], + status: Optional[str] = None, + ) -> Iterable[MetadataWorkUnit]: + if job_properties: + job_properties = {k: v for k, v in job_properties.items() if v is not None} + + mcp = MetadataChangeProposalWrapper( + entityType="dataJob", + entityUrn=job_urn, + changeType=ChangeTypeClass.UPSERT, + aspectName="dataJobInfo", + aspect=DataJobInfoClass( + name=job_name, + type=job_type, + description=description, + customProperties=job_properties, + externalUrl=external_url, + status=status, + ), + ) + + wu = MetadataWorkUnit( + id=f"{NIFI}.{job_name}.{mcp.aspectName}", + mcp=mcp, + ) + self.report.report_workunit(wu) + yield wu + + inlets.sort() + outlets.sort() + inputJobs.sort() + + mcp = MetadataChangeProposalWrapper( + entityType="dataJob", + entityUrn=job_urn, + changeType=ChangeTypeClass.UPSERT, + aspectName="dataJobInputOutput", + aspect=DataJobInputOutputClass( + inputDatasets=inlets, outputDatasets=outlets, inputDatajobs=inputJobs + ), + ) + + wu = MetadataWorkUnit( + id=f"{NIFI}.{job_name}.{mcp.aspectName}", + mcp=mcp, + ) + self.report.report_workunit(wu) + yield wu + + def construct_dataset_workunits( + self, + dataset_platform: str, + dataset_name: str, + dataset_urn: Optional[str] = None, + external_url: Optional[str] = None, + datasetProperties: Optional[Dict[str, str]] = None, + ) -> Iterable[MetadataWorkUnit]: + + if not dataset_urn: + dataset_urn = builder.make_dataset_urn(dataset_platform, dataset_name) + + mcp = MetadataChangeProposalWrapper( + entityType="dataset", + entityUrn=dataset_urn, + changeType=ChangeTypeClass.UPSERT, + aspectName="dataPlatformInstance", + aspect=DataPlatformInstanceClass( + platform=builder.make_data_platform_urn(dataset_platform) + ), + ) + platform = ( + dataset_platform[dataset_platform.rindex(":") + 1 :] + if dataset_platform.startswith("urn:") + else dataset_platform + ) + wu = MetadataWorkUnit(id=f"{platform}.{dataset_name}.{mcp.aspectName}", mcp=mcp) + if wu.id not in self.report.workunit_ids: + self.report.report_workunit(wu) + yield wu + + mcp = MetadataChangeProposalWrapper( + entityType="dataset", + entityUrn=dataset_urn, + changeType=ChangeTypeClass.UPSERT, + aspectName="datasetProperties", + aspect=DatasetPropertiesClass( + externalUrl=external_url, customProperties=datasetProperties + ), + ) + + wu = MetadataWorkUnit(id=f"{platform}.{dataset_name}.{mcp.aspectName}", mcp=mcp) + if wu.id not in self.report.workunit_ids: + self.report.report_workunit(wu) + yield wu diff --git a/metadata-ingestion/tests/integration/nifi/docker-compose.yml b/metadata-ingestion/tests/integration/nifi/docker-compose.yml new file mode 100644 index 0000000000..02b9f11a9e --- /dev/null +++ b/metadata-ingestion/tests/integration/nifi/docker-compose.yml @@ -0,0 +1,126 @@ +services: + nifi1: + image: apache/nifi:1.15.0 + container_name: nifi1 + hostname: nifi1 + environment: + #AUTH: tls + NIFI_REMOTE_INPUT_HOST: nifi1 + NIFI_SENSITIVE_PROPS_KEY: admin@datahub + #SINGLE_USER_CREDENTIALS_USERNAME: admin + #SINGLE_USER_CREDENTIALS_PASSWORD: admin@datahub + #KEYSTORE_PATH: /opt/certs/server_keystore.jks + #KEYSTORE_TYPE: JKS + #KEYSTORE_PASSWORD: datahub + #TRUSTSTORE_PATH: /opt/certs/server_truststore.jks + #TRUSTSTORE_PASSWORD: datahub + #TRUSTSTORE_TYPE: JKS + #INITIAL_ADMIN_IDENTITY: 'CN=DatahubUser, C=US' + NIFI_WEB_HTTP_PORT: 9443 + volumes: + - ./setup/conf:/opt/nifi/tmp:ro + #- ./setup/ssl_files:/opt/certs + entrypoint: + - bash + - -c + - | + echo "Copying Flow" + # + cp /opt/nifi/tmp/flow.xml.gz /opt/nifi/nifi-current/conf/flow.xml.gz + # + echo "Starting Nifi" + # + /opt/nifi/scripts/start.sh & + # + sleep infinity + ports: + - 9443:9443 + + + nifi_zookeeper: + hostname: nifi_zookeeper + container_name: nifi_zookeeper + image: 'bitnami/zookeeper:latest' + environment: + - ALLOW_ANONYMOUS_LOGIN=yes + - ZOO_PORT_NUMBER=52181 + ports: + - 52181:52181 + + nifi01: + image: apache/nifi:1.15.0 + container_name: nifi01 + hostname: nifi01 + depends_on: + - nifi_zookeeper + ports: + - 9080:9080 + volumes: + - ./setup/conf_clustered:/opt/nifi/tmp:ro + entrypoint: + - bash + - -c + - | + echo "Copying Flow" + # + cp /opt/nifi/tmp/flow.xml.gz /opt/nifi/nifi-current/conf/flow.xml.gz + # + echo "Starting Nifi" + # + /opt/nifi/scripts/start.sh & + # + sleep infinity + environment: + - NIFI_WEB_HTTP_PORT=9080 + - NIFI_CLUSTER_IS_NODE=true + - NIFI_CLUSTER_NODE_PROTOCOL_PORT=7080 + - NIFI_ZK_CONNECT_STRING=nifi_zookeeper:52181 + - NIFI_ELECTION_MAX_WAIT=1 min + - NIFI_SENSITIVE_PROPS_KEY=admin@datahub + + + nifi02: + image: apache/nifi:1.15.0 + container_name: nifi02 + hostname: nifi02 + depends_on: + - nifi_zookeeper + ports: + - 9081:9081 + volumes: + - ./setup/conf/awscreds.properties:/opt/nifi/nifi-current/conf/awscreds.properties + environment: + - NIFI_WEB_HTTP_PORT=9081 + - NIFI_CLUSTER_IS_NODE=true + - NIFI_CLUSTER_NODE_PROTOCOL_PORT=7080 + - NIFI_ZK_CONNECT_STRING=nifi_zookeeper:52181 + - NIFI_ELECTION_MAX_WAIT=1 min + - NIFI_SENSITIVE_PROPS_KEY=admin@datahub + + nifi03: + image: apache/nifi:1.15.0 + container_name: nifi03 + hostname: nifi03 + depends_on: + - nifi_zookeeper + ports: + - 9082:9082 + volumes: + - ./setup/conf/awscreds.properties:/opt/nifi/nifi-current/conf/awscreds.properties + environment: + - NIFI_WEB_HTTP_PORT=9082 + - NIFI_CLUSTER_IS_NODE=true + - NIFI_CLUSTER_NODE_PROTOCOL_PORT=7080 + - NIFI_ZK_CONNECT_STRING=nifi_zookeeper:52181 + - NIFI_ELECTION_MAX_WAIT=1 min + - NIFI_SENSITIVE_PROPS_KEY=admin@datahub + + sftp_public_host: + image: atmoz/sftp + container_name: sftp_public_host + hostname: sftp_public_host + volumes: + - ./setup/sftp_files:/home/foo + ports: + - "2222:22" + command: "foo:pass:::" \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/nifi/nifi_mces_golden_cluster.json b/metadata-ingestion/tests/integration/nifi/nifi_mces_golden_cluster.json new file mode 100644 index 0000000000..939ba157a6 --- /dev/null +++ b/metadata-ingestion/tests/integration/nifi/nifi_mces_golden_cluster.json @@ -0,0 +1,353 @@ +[ + { + "auditHeader": null, + "entityType": "dataFlow", + "entityUrn": "urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataFlowInfo", + "aspect": { + "value": "{\"customProperties\": {\"clustered\": \"True\"}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=80820b2f-017d-1000-85cf-05f56cde9185&componentIds=\", \"name\": \"Cluster Flow\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),fed5914b-937b-37dd-89c0-b34ffbae9cf4)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"ALL\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Object Key\\\": \\\"tropical_data/${filename}\\\", \\\"Bucket\\\": \\\"${s3.destbucket}\\\", \\\"Content Type\\\": null, \\\"Content Disposition\\\": null, \\\"Cache Control\\\": null, \\\"Access Key\\\": null, \\\"Secret Key\\\": null, \\\"Credentials File\\\": null, \\\"AWS Credentials Provider service\\\": \\\"69fc8d86-2f01-3f07-910f-2b14edc81779\\\", \\\"s3-object-tags-prefix\\\": null, \\\"s3-object-remove-tags-prefix\\\": \\\"false\\\", \\\"Storage Class\\\": \\\"Standard\\\", \\\"Region\\\": \\\"us-east-1\\\", \\\"Communications Timeout\\\": \\\"30 secs\\\", \\\"Expiration Time Rule\\\": null, \\\"FullControl User List\\\": \\\"${s3.permissions.full.users}\\\", \\\"Read Permission User List\\\": \\\"${s3.permissions.read.users}\\\", \\\"Write Permission User List\\\": \\\"${s3.permissions.write.users}\\\", \\\"Read ACL User List\\\": \\\"${s3.permissions.readacl.users}\\\", \\\"Write ACL User List\\\": \\\"${s3.permissions.writeacl.users}\\\", \\\"Owner\\\": \\\"${s3.owner}\\\", \\\"canned-acl\\\": \\\"${s3.permissions.cannedacl}\\\", \\\"SSL Context Service\\\": null, \\\"Endpoint Override URL\\\": null, \\\"Signer Override\\\": \\\"Default Signature\\\", \\\"Multipart Threshold\\\": \\\"5 GB\\\", \\\"Multipart Part Size\\\": \\\"5 GB\\\", \\\"Multipart Upload AgeOff Interval\\\": \\\"60 min\\\", \\\"Multipart Upload Max Age Threshold\\\": \\\"7 days\\\", \\\"s3-temporary-directory-multipart\\\": \\\"${java.io.tmpdir}\\\", \\\"server-side-encryption\\\": \\\"None\\\", \\\"encryption-service\\\": null, \\\"use-chunked-encoding\\\": \\\"true\\\", \\\"use-path-style-access\\\": \\\"false\\\", \\\"proxy-configuration-service\\\": null, \\\"Proxy Host\\\": null, \\\"Proxy Host Port\\\": null, \\\"proxy-user-name\\\": null, \\\"proxy-user-password\\\": null}\", \"last_event_time\": \"None\"}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=1c61a8d9-3462-387f-8145-09e6e7785e5c&componentIds=fed5914b-937b-37dd-89c0-b34ffbae9cf4\", \"name\": \"PutS3Object\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),fed5914b-937b-37dd-89c0-b34ffbae9cf4)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:nifi,default.s3_data,PROD)\"], \"outputDatasets\": [], \"inputDatajobs\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataPlatformInstance", + "aspect": { + "value": "{\"platform\": \"urn:li:dataPlatform:s3\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "datasetProperties", + "aspect": { + "value": "{\"customProperties\": {\"s3_uri\": \"s3://enriched-topical-chat\"}, \"tags\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),c5f6fc66-ffbb-3f60-9564-f2466ae32493)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"ALL\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Bucket\\\": \\\"enriched-topical-chat\\\", \\\"Object Key\\\": \\\"${filename}\\\", \\\"Region\\\": \\\"us-west-2\\\", \\\"Access Key\\\": null, \\\"Secret Key\\\": null, \\\"Credentials File\\\": null, \\\"AWS Credentials Provider service\\\": null, \\\"Communications Timeout\\\": \\\"30 secs\\\", \\\"Version\\\": null, \\\"SSL Context Service\\\": null, \\\"Endpoint Override URL\\\": null, \\\"Signer Override\\\": \\\"Default Signature\\\", \\\"encryption-service\\\": null, \\\"proxy-configuration-service\\\": null, \\\"Proxy Host\\\": null, \\\"Proxy Host Port\\\": null, \\\"proxy-user-name\\\": null, \\\"proxy-user-password\\\": null, \\\"requester-pays\\\": \\\"false\\\", \\\"range-start\\\": null, \\\"range-length\\\": null}\", \"last_event_time\": \"2021-12-08 14:23:21.702000+00:00\"}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=1c61a8d9-3462-387f-8145-09e6e7785e5c&componentIds=c5f6fc66-ffbb-3f60-9564-f2466ae32493\", \"name\": \"FetchS3Object\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),c5f6fc66-ffbb-3f60-9564-f2466ae32493)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)\"], \"outputDatasets\": [], \"inputDatajobs\": [\"urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8a218b6e-e6a0-36b6-bc4b-79d202a80167)\"]}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8a218b6e-e6a0-36b6-bc4b-79d202a80167)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"PRIMARY\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Bucket\\\": \\\"enriched-topical-chat\\\", \\\"Region\\\": \\\"us-west-2\\\", \\\"Access Key\\\": null, \\\"Secret Key\\\": null, \\\"record-writer\\\": null, \\\"min-age\\\": \\\"0 sec\\\", \\\"Listing Batch Size\\\": \\\"100\\\", \\\"write-s3-object-tags\\\": \\\"false\\\", \\\"write-s3-user-metadata\\\": \\\"false\\\", \\\"Credentials File\\\": null, \\\"AWS Credentials Provider service\\\": null, \\\"Communications Timeout\\\": \\\"30 secs\\\", \\\"SSL Context Service\\\": null, \\\"Endpoint Override URL\\\": null, \\\"Signer Override\\\": \\\"Default Signature\\\", \\\"proxy-configuration-service\\\": null, \\\"Proxy Host\\\": null, \\\"Proxy Host Port\\\": null, \\\"proxy-user-name\\\": null, \\\"proxy-user-password\\\": null, \\\"delimiter\\\": null, \\\"prefix\\\": null, \\\"use-versions\\\": \\\"false\\\", \\\"list-type\\\": \\\"1\\\", \\\"requester-pays\\\": \\\"false\\\"}\", \"last_event_time\": \"2021-12-08 14:23:07.204000+00:00\"}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=1c61a8d9-3462-387f-8145-09e6e7785e5c&componentIds=8a218b6e-e6a0-36b6-bc4b-79d202a80167\", \"name\": \"ListS3\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8a218b6e-e6a0-36b6-bc4b-79d202a80167)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)\"], \"outputDatasets\": [], \"inputDatajobs\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),71bc17ed-a3bc-339a-a100-ebad434717d4)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=1c61a8d9-3462-387f-8145-09e6e7785e5c&componentIds=8efa023d-017d-1000-0000-0000479b764f\", \"name\": \"s3_data\", \"description\": \"\", \"type\": {\"string\": \"NIFI_REMOTE_INPUT_PORT\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),71bc17ed-a3bc-339a-a100-ebad434717d4)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [], \"outputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:nifi,default.s3_data,PROD)\"], \"inputDatajobs\": [\"urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),c5f6fc66-ffbb-3f60-9564-f2466ae32493)\"]}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataPlatformInstance", + "aspect": { + "value": "{\"platform\": \"urn:li:dataPlatform:file\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "datasetProperties", + "aspect": { + "value": "{\"customProperties\": {\"uri\": \"sftp://sftp_public_host\"}, \"tags\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host.temperature,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataPlatformInstance", + "aspect": { + "value": "{\"platform\": \"urn:li:dataPlatform:file\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host.temperature,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "datasetProperties", + "aspect": { + "value": "{\"customProperties\": {\"uri\": \"sftp://sftp_public_host/temperature\"}, \"tags\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8eb5263d-017d-1000-ffff-ffff911b23aa)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"PRIMARY\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"listing-strategy\\\": \\\"timestamps\\\", \\\"Hostname\\\": \\\"${sftp.host}\\\", \\\"Port\\\": \\\"22\\\", \\\"Username\\\": \\\"${sftp.username}\\\", \\\"Password\\\": \\\"********\\\", \\\"Private Key Path\\\": null, \\\"Private Key Passphrase\\\": null, \\\"Remote Path\\\": \\\".\\\", \\\"record-writer\\\": null, \\\"Distributed Cache Service\\\": null, \\\"Search Recursively\\\": \\\"true\\\", \\\"follow-symlink\\\": \\\"false\\\", \\\"File Filter Regex\\\": null, \\\"Path Filter Regex\\\": null, \\\"Ignore Dotted Files\\\": \\\"true\\\", \\\"Strict Host Key Checking\\\": \\\"false\\\", \\\"Host Key File\\\": null, \\\"Connection Timeout\\\": \\\"30 sec\\\", \\\"Data Timeout\\\": \\\"30 sec\\\", \\\"Send Keep Alive On Timeout\\\": \\\"true\\\", \\\"target-system-timestamp-precision\\\": \\\"auto-detect\\\", \\\"proxy-configuration-service\\\": null, \\\"Proxy Type\\\": \\\"DIRECT\\\", \\\"Proxy Host\\\": null, \\\"Proxy Port\\\": null, \\\"Http Proxy Username\\\": null, \\\"Http Proxy Password\\\": null, \\\"et-state-cache\\\": null, \\\"et-time-window\\\": \\\"3 hours\\\", \\\"et-initial-listing-target\\\": \\\"all\\\", \\\"Minimum File Age\\\": \\\"0 sec\\\", \\\"Maximum File Age\\\": null, \\\"Minimum File Size\\\": \\\"0 B\\\", \\\"Maximum File Size\\\": null, \\\"Ciphers Allowed\\\": null, \\\"Key Algorithms Allowed\\\": null, \\\"Key Exchange Algorithms Allowed\\\": null, \\\"Message Authentication Codes Allowed\\\": null}\", \"last_event_time\": \"2021-12-08 14:23:02.805000+00:00\"}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=8eb4f034-017d-1000-ffff-ffffccebd06c&componentIds=8eb5263d-017d-1000-ffff-ffff911b23aa\", \"name\": \"ListSFTP\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8eb5263d-017d-1000-ffff-ffff911b23aa)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host,PROD)\", \"urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host.temperature,PROD)\"], \"outputDatasets\": [], \"inputDatajobs\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),c8c73d4c-ebdd-1bee-9b46-629672cd11a0)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"ALL\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Object Key\\\": \\\"sftp_data/${filename}\\\", \\\"Bucket\\\": \\\"${s3.destbucket}\\\", \\\"Content Type\\\": null, \\\"Content Disposition\\\": null, \\\"Cache Control\\\": null, \\\"Access Key\\\": null, \\\"Secret Key\\\": null, \\\"Credentials File\\\": null, \\\"AWS Credentials Provider service\\\": \\\"c8c73d64-ebdd-1bee-0000-000020079e12\\\", \\\"s3-object-tags-prefix\\\": null, \\\"s3-object-remove-tags-prefix\\\": \\\"false\\\", \\\"Storage Class\\\": \\\"Standard\\\", \\\"Region\\\": \\\"us-east-1\\\", \\\"Communications Timeout\\\": \\\"30 secs\\\", \\\"Expiration Time Rule\\\": null, \\\"FullControl User List\\\": \\\"${s3.permissions.full.users}\\\", \\\"Read Permission User List\\\": \\\"${s3.permissions.read.users}\\\", \\\"Write Permission User List\\\": \\\"${s3.permissions.write.users}\\\", \\\"Read ACL User List\\\": \\\"${s3.permissions.readacl.users}\\\", \\\"Write ACL User List\\\": \\\"${s3.permissions.writeacl.users}\\\", \\\"Owner\\\": \\\"${s3.owner}\\\", \\\"canned-acl\\\": \\\"${s3.permissions.cannedacl}\\\", \\\"SSL Context Service\\\": null, \\\"Endpoint Override URL\\\": null, \\\"Signer Override\\\": \\\"Default Signature\\\", \\\"Multipart Threshold\\\": \\\"5 GB\\\", \\\"Multipart Part Size\\\": \\\"5 GB\\\", \\\"Multipart Upload AgeOff Interval\\\": \\\"60 min\\\", \\\"Multipart Upload Max Age Threshold\\\": \\\"7 days\\\", \\\"s3-temporary-directory-multipart\\\": \\\"${java.io.tmpdir}\\\", \\\"server-side-encryption\\\": \\\"None\\\", \\\"encryption-service\\\": null, \\\"use-chunked-encoding\\\": \\\"true\\\", \\\"use-path-style-access\\\": \\\"false\\\", \\\"proxy-configuration-service\\\": null, \\\"Proxy Host\\\": null, \\\"Proxy Host Port\\\": null, \\\"proxy-user-name\\\": null, \\\"proxy-user-password\\\": null}\", \"last_event_time\": \"None\"}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=8eb4f034-017d-1000-ffff-ffffccebd06c&componentIds=c8c73d4c-ebdd-1bee-9b46-629672cd11a0\", \"name\": \"PutS3Object\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),c8c73d4c-ebdd-1bee-9b46-629672cd11a0)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [], \"outputDatasets\": [], \"inputDatajobs\": [\"urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),3ec2acd6-a0d4-3198-9066-a59fb757bc05)\"]}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8eb55aeb-017d-1000-ffff-fffff475768d)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"ALL\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Hostname\\\": \\\"${sftp.host}\\\", \\\"Port\\\": \\\"22\\\", \\\"Username\\\": \\\"${sftp.username}\\\", \\\"Password\\\": \\\"********\\\", \\\"Private Key Path\\\": null, \\\"Private Key Passphrase\\\": null, \\\"Remote File\\\": \\\"${path}/${filename}\\\", \\\"Completion Strategy\\\": \\\"None\\\", \\\"Move Destination Directory\\\": null, \\\"Create Directory\\\": \\\"false\\\", \\\"Disable Directory Listing\\\": \\\"false\\\", \\\"Connection Timeout\\\": \\\"30 sec\\\", \\\"Data Timeout\\\": \\\"30 sec\\\", \\\"Send Keep Alive On Timeout\\\": \\\"true\\\", \\\"Host Key File\\\": null, \\\"Strict Host Key Checking\\\": \\\"false\\\", \\\"Use Compression\\\": \\\"false\\\", \\\"proxy-configuration-service\\\": null, \\\"Proxy Type\\\": \\\"DIRECT\\\", \\\"Proxy Host\\\": null, \\\"Proxy Port\\\": null, \\\"Http Proxy Username\\\": null, \\\"Http Proxy Password\\\": null, \\\"fetchfiletransfer-notfound-loglevel\\\": \\\"ERROR\\\", \\\"Ciphers Allowed\\\": null, \\\"Key Algorithms Allowed\\\": null, \\\"Key Exchange Algorithms Allowed\\\": null, \\\"Message Authentication Codes Allowed\\\": null}\", \"last_event_time\": \"2021-12-08 14:23:04.318000+00:00\"}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=8eb4f034-017d-1000-ffff-ffffccebd06c&componentIds=8eb55aeb-017d-1000-ffff-fffff475768d\", \"name\": \"FetchSFTP\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8eb55aeb-017d-1000-ffff-fffff475768d)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host,PROD)\", \"urn:li:dataset:(urn:li:dataPlatform:file,sftp_public_host.temperature,PROD)\"], \"outputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:nifi,default.sftp_files_out,PROD)\"], \"inputDatajobs\": [\"urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),8eb5263d-017d-1000-ffff-ffff911b23aa)\"]}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),3ec2acd6-a0d4-3198-9066-a59fb757bc05)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=8eb4f034-017d-1000-ffff-ffffccebd06c&componentIds=8eb70d94-017d-1000-ffff-ffffc94c12ce\", \"name\": \"sftp_files_out\", \"description\": \"\", \"type\": {\"string\": \"NIFI_REMOTE_OUTPUT_PORT\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,80820b2f-017d-1000-85cf-05f56cde9185,prod),3ec2acd6-a0d4-3198-9066-a59fb757bc05)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:nifi,default.sftp_files_out,PROD)\"], \"outputDatasets\": [], \"inputDatajobs\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:nifi,default.s3_data,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataPlatformInstance", + "aspect": { + "value": "{\"platform\": \"urn:li:dataPlatform:nifi\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:nifi,default.s3_data,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "datasetProperties", + "aspect": { + "value": "{\"customProperties\": {}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=1c61a8d9-3462-387f-8145-09e6e7785e5c&componentIds=8ef96dcf-017d-1000-ffff-ffff8f7528f0\", \"tags\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:nifi,default.sftp_files_out,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataPlatformInstance", + "aspect": { + "value": "{\"platform\": \"urn:li:dataPlatform:nifi\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:nifi,default.sftp_files_out,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "datasetProperties", + "aspect": { + "value": "{\"customProperties\": {}, \"externalUrl\": \"http://localhost:9080/nifi/?processGroupId=8eb4f034-017d-1000-ffff-ffffccebd06c&componentIds=8eb66675-017d-1000-ffff-ffffa56e2758\", \"tags\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + } + ] \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/nifi/nifi_mces_golden_standalone.json b/metadata-ingestion/tests/integration/nifi/nifi_mces_golden_standalone.json new file mode 100644 index 0000000000..ac8e9fdc5e --- /dev/null +++ b/metadata-ingestion/tests/integration/nifi/nifi_mces_golden_standalone.json @@ -0,0 +1,119 @@ +[ + { + "auditHeader": null, + "entityType": "dataFlow", + "entityUrn": "urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataFlowInfo", + "aspect": { + "value": "{\"customProperties\": {\"clustered\": \"False\"}, \"externalUrl\": \"http://localhost:9443/nifi/?processGroupId=803ebb92-017d-1000-2961-4bdaa27a3ba0&componentIds=\", \"name\": \"Standalone Flow\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),aed63edf-e660-3f29-b56b-192cf6286889)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"ALL\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Object Key\\\": \\\"tropical_data/${filename}\\\", \\\"Bucket\\\": \\\"${s3.destbucket}\\\", \\\"Content Type\\\": null, \\\"Content Disposition\\\": null, \\\"Cache Control\\\": null, \\\"Access Key\\\": null, \\\"Secret Key\\\": null, \\\"Credentials File\\\": null, \\\"AWS Credentials Provider service\\\": \\\"80436b00-017d-1000-54c8-ff854b5c8990\\\", \\\"s3-object-tags-prefix\\\": null, \\\"s3-object-remove-tags-prefix\\\": \\\"false\\\", \\\"Storage Class\\\": \\\"Standard\\\", \\\"Region\\\": \\\"us-east-1\\\", \\\"Communications Timeout\\\": \\\"30 secs\\\", \\\"Expiration Time Rule\\\": null, \\\"FullControl User List\\\": \\\"${s3.permissions.full.users}\\\", \\\"Read Permission User List\\\": \\\"${s3.permissions.read.users}\\\", \\\"Write Permission User List\\\": \\\"${s3.permissions.write.users}\\\", \\\"Read ACL User List\\\": \\\"${s3.permissions.readacl.users}\\\", \\\"Write ACL User List\\\": \\\"${s3.permissions.writeacl.users}\\\", \\\"Owner\\\": \\\"${s3.owner}\\\", \\\"canned-acl\\\": \\\"${s3.permissions.cannedacl}\\\", \\\"SSL Context Service\\\": null, \\\"Endpoint Override URL\\\": null, \\\"Signer Override\\\": \\\"Default Signature\\\", \\\"Multipart Threshold\\\": \\\"5 GB\\\", \\\"Multipart Part Size\\\": \\\"5 GB\\\", \\\"Multipart Upload AgeOff Interval\\\": \\\"60 min\\\", \\\"Multipart Upload Max Age Threshold\\\": \\\"7 days\\\", \\\"s3-temporary-directory-multipart\\\": \\\"${java.io.tmpdir}\\\", \\\"server-side-encryption\\\": \\\"None\\\", \\\"encryption-service\\\": null, \\\"use-chunked-encoding\\\": \\\"true\\\", \\\"use-path-style-access\\\": \\\"false\\\", \\\"proxy-configuration-service\\\": null, \\\"Proxy Host\\\": null, \\\"Proxy Host Port\\\": null, \\\"proxy-user-name\\\": null, \\\"proxy-user-password\\\": null}\", \"last_event_time\": \"None\"}, \"externalUrl\": \"http://localhost:9443/nifi/?processGroupId=80404c81-017d-1000-e8e8-af7420af06c1&componentIds=aed63edf-e660-3f29-b56b-192cf6286889\", \"name\": \"PutS3Object\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),aed63edf-e660-3f29-b56b-192cf6286889)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [], \"outputDatasets\": [], \"inputDatajobs\": [\"urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),91d59f03-1c2b-3f3f-48bc-f89296a328bd)\"]}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataPlatformInstance", + "aspect": { + "value": "{\"platform\": \"urn:li:dataPlatform:s3\"}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataset", + "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "datasetProperties", + "aspect": { + "value": "{\"customProperties\": {\"s3_uri\": \"s3://enriched-topical-chat\"}, \"tags\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),91d59f03-1c2b-3f3f-48bc-f89296a328bd)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"ALL\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Bucket\\\": \\\"enriched-topical-chat\\\", \\\"Object Key\\\": \\\"${filename}\\\", \\\"Region\\\": \\\"us-west-2\\\", \\\"Access Key\\\": null, \\\"Secret Key\\\": null, \\\"Credentials File\\\": null, \\\"AWS Credentials Provider service\\\": null, \\\"Communications Timeout\\\": \\\"30 secs\\\", \\\"Version\\\": null, \\\"SSL Context Service\\\": null, \\\"Endpoint Override URL\\\": null, \\\"Signer Override\\\": \\\"Default Signature\\\", \\\"encryption-service\\\": null, \\\"proxy-configuration-service\\\": null, \\\"Proxy Host\\\": null, \\\"Proxy Host Port\\\": null, \\\"proxy-user-name\\\": null, \\\"proxy-user-password\\\": null, \\\"requester-pays\\\": \\\"false\\\", \\\"range-start\\\": null, \\\"range-length\\\": null}\", \"last_event_time\": \"2021-12-08 14:01:14.043000+00:00\"}, \"externalUrl\": \"http://localhost:9443/nifi/?processGroupId=80404c81-017d-1000-e8e8-af7420af06c1&componentIds=91d59f03-1c2b-3f3f-48bc-f89296a328bd\", \"name\": \"FetchS3Object\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),91d59f03-1c2b-3f3f-48bc-f89296a328bd)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)\"], \"outputDatasets\": [], \"inputDatajobs\": [\"urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),cb7693ed-f93b-3340-3776-fe80e6283ddc)\"]}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),cb7693ed-f93b-3340-3776-fe80e6283ddc)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInfo", + "aspect": { + "value": "{\"customProperties\": {\"schedulingPeriod\": \"0 sec\", \"schedulingStrategy\": \"TIMER_DRIVEN\", \"executionNode\": \"PRIMARY\", \"concurrentlySchedulableTaskCount\": \"1\", \"properties\": \"{\\\"Bucket\\\": \\\"enriched-topical-chat\\\", \\\"Region\\\": \\\"us-west-2\\\", \\\"Access Key\\\": null, \\\"Secret Key\\\": null, \\\"record-writer\\\": null, \\\"min-age\\\": \\\"0 sec\\\", \\\"Listing Batch Size\\\": \\\"100\\\", \\\"write-s3-object-tags\\\": \\\"false\\\", \\\"write-s3-user-metadata\\\": \\\"false\\\", \\\"Credentials File\\\": null, \\\"AWS Credentials Provider service\\\": null, \\\"Communications Timeout\\\": \\\"30 secs\\\", \\\"SSL Context Service\\\": null, \\\"Endpoint Override URL\\\": null, \\\"Signer Override\\\": \\\"Default Signature\\\", \\\"proxy-configuration-service\\\": null, \\\"Proxy Host\\\": null, \\\"Proxy Host Port\\\": null, \\\"proxy-user-name\\\": null, \\\"proxy-user-password\\\": null, \\\"delimiter\\\": null, \\\"prefix\\\": null, \\\"use-versions\\\": \\\"false\\\", \\\"list-type\\\": \\\"1\\\", \\\"requester-pays\\\": \\\"false\\\"}\", \"last_event_time\": \"2021-12-08 14:00:58.978000+00:00\"}, \"externalUrl\": \"http://localhost:9443/nifi/?processGroupId=80404c81-017d-1000-e8e8-af7420af06c1&componentIds=cb7693ed-f93b-3340-3776-fe80e6283ddc\", \"name\": \"ListS3\", \"description\": \"\", \"type\": {\"string\": \"NIFI_PROCESSOR\"}}", + "contentType": "application/json" + }, + "systemMetadata": null + }, + { + "auditHeader": null, + "entityType": "dataJob", + "entityUrn": "urn:li:dataJob:(urn:li:dataFlow:(nifi,803ebb92-017d-1000-2961-4bdaa27a3ba0,prod),cb7693ed-f93b-3340-3776-fe80e6283ddc)", + "entityKeyAspect": null, + "changeType": "UPSERT", + "aspectName": "dataJobInputOutput", + "aspect": { + "value": "{\"inputDatasets\": [\"urn:li:dataset:(urn:li:dataPlatform:s3,enriched-topical-chat,PROD)\"], \"outputDatasets\": [], \"inputDatajobs\": []}", + "contentType": "application/json" + }, + "systemMetadata": null + } +] \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/nifi/setup/conf/flow.xml.gz b/metadata-ingestion/tests/integration/nifi/setup/conf/flow.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..fb098eb99b20cb2726ef28ec1f60bcd9554914d0 GIT binary patch literal 62007 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 literal 0 HcmV?d00001 diff --git a/metadata-ingestion/tests/integration/nifi/setup/conf_clustered/flow.xml.gz b/metadata-ingestion/tests/integration/nifi/setup/conf_clustered/flow.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..5b684d598f04422f3ebb9ccf1344bc943df58120 GIT binary patch literal 61643 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

-69@ZOzPVEtVX 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

5^l2(uPY;fQL-_s`{RvnZR;$KyJ3^v*Li}#C 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