New to Kestra?
Use blueprints to kickstart your first workflows.
Fire on new NFS file arrivals, alert Slack or auto-quarantine non-compliant files, and log the result for data platform teams.
A shared NFS drop directory that many systems can write to eventually gets something that does not belong: an executable where only CSVs were expected, a stray temp file, a wrong export format from a misconfigured upstream job. Nothing about NFS itself enforces what kind of file a directory is supposed to receive; by the time a downstream job trips over it, the file could have been sitting there for hours. This blueprint watches a directory in real time, checks every new arrival against an approved extension pattern, and can quarantine the ones that fail once you have explicitly said this flow is allowed to.
This blueprint was created by Mohit Jeswani.
watch_directory (io.kestra.plugin.fs.nfs.Trigger) polls the watched directory and
fires with every newly created file's name, URI, and metadata in trigger.files.evaluate (io.kestra.plugin.core.output.OutputValues) counts and lists the files whose
name does not match allowed_extensions_regex with a jq filter, and classifies the
fire as ALL_COMPLIANT, NONCOMPLIANT_AUTO_QUARANTINE, or
NONCOMPLIANT_NEEDS_HUMAN, folding confirm_quarantine into the non-compliant
classification itself.route (io.kestra.plugin.core.flow.Switch):ForEachs every file this fire delivered, moves only
the non-compliant ones into quarantine_directory with
io.kestra.plugin.fs.nfs.Move (the safe remediation, since moving a file within the
same NFS mount deletes nothing), then posts a Slack notice.summary logs the non-compliant count and severity, closing the governance cycle.errors alerts Slack if the flow itself fails, for example an unmounted NFS path.confirm_quarantine to allow it.nfs.Trigger
and nfs.Move used together as an event-driven compliance gate, distinct from this repo's
existing NFS blueprint, which runs a nightly scheduled sweep deleting stale scratch files
by age rather than reacting to a new arrival's file type in real time.NFS has no concept of an allowed file-type policy and no way to react the moment a
non-compliant file lands. Kestra keeps allowed_extensions_regex, quarantine_directory,
and confirm_quarantine as flow inputs, turns a trigger's file batch into a policy
decision, and keeps a full execution history of every arrival this flow has seen and what it
did about it.
A local NFS server can be run via an open-source Docker image such as itsthenetwork/nfs-server-alpine,
mounted into the Kestra worker container, for a fully local end-to-end test, no managed
service required.
SLACK_WEBHOOK_URL: used by both Slack alert cases and the errors block. In Kestra OSS,
provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.| Input | Default | Purpose |
|---|---|---|
allowed_extensions_regex |
.*\\.(csv|json|parquet)$ |
Pattern a filename must fully match to be compliant |
quarantine_directory |
/mnt/nfs/quarantine |
Where non-compliant files are moved when authorized |
confirm_quarantine |
false |
Authorizes this flow to quarantine non-compliant files itself |
The watched directory is set directly on the watch_directory trigger's from, not as a
flow input; see Pitfalls.
{{ trigger.files }}: every new or updated file this fire detected (name, uri, size,
isDirectory, isHidden, creationTime, lastModifiedTime, changeType), as
nfs.Trigger reports them.{{ outputs.evaluate.values.noncompliant_count }} / .noncompliant_names: how many files
failed the pattern and their names, semicolon-joined.{{ outputs.evaluate.values.severity }}: ALL_COMPLIANT, NONCOMPLIANT_AUTO_QUARANTINE,
or NONCOMPLIANT_NEEDS_HUMAN.from, interval, on, recursive, and maxFiles are trigger-level configuration, not
flow inputs; a polling trigger has no per-execution input overrides the way a Schedule
trigger does, so watching a different directory means editing the trigger block directly.nfs.Trigger caps a single fire at maxFiles (default 25); a directory that receives a
larger burst than that in one poll interval has the excess files picked up on the next
poll instead, not dropped.nfs.Move's destination directory is created automatically if it does not exist, and an
existing file at the destination path is overwritten; two different source files sharing a
filename quarantined in the same run will collide, with the second overwriting the first.SLACK_WEBHOOK_URL secret.watch_directory's from at a real incoming directory.report.csv), and confirm
log_all_compliant fires.malware.exe) with confirm_quarantine: false; confirm
alert_noncompliant fires.confirm_quarantine: true, write another non-compliant file, and confirm
move_to_quarantine relocates it and alert_auto_quarantined fires.watch_directory trigger
configuration, one per drop zone your team owns.