FortiNAC-F
FortiNAC-F is a zero-trust network access solution that provides users with enhanced visibility into the Internet of Things (IoT) devices on their enterprise networks. For legacy FortiNAC articles prior to FortiNAC-F 7.2, see FortiNAC.
Sx11
Staff
Staff
Article Id 340179
Description This article describes how to leverage Bash scripts to run Python or other scripts in the FortiNAC scheduler tool
Scope FortiNAC-F, FortiNAC.
Solution

In FortiNAC it is possible to set Scheduled Activities and one of the actions that can be used is a Custom Script. This is done in System -> Scheduler.

Scripts must be stored in FortiNAC path /home/cm/scripts and have to execute permissions which is done manually through FortiNAC CLI:

 

execute enter-shell

chmod +x /home/cm/scripts/test.py

 

ls -la /home/cm/scripts/test.py
-rwxrwx--x 1 nac cmdb 398 Sep 9 16:50 /home/cm/scripts/test.py

 

test.py is a Python script that pings 3 times one Device whose IP address we input as an argument. After that, it prints the date when actions were performed and returns 0 in case each action(ping and date) was successful. The script requires as input an argument which is the "ip" of the device to be pinged. It will then print statistics and the date of that action.

 

test.py script content:

 

#!/usr/bin python3
import subprocess
import argparse
import sys
def IP_address(ip):
  return(str(ip))
ip=sys.argv[1]
result=subprocess.run(['ping','-c','3','-n',ip], stdout=subprocess.PIPE, encoding='utf-8')
date=subprocess.run(['date'], stdout=subprocess.PIPE, encoding='utf-8')
sys.stderr.close()
print(result.stdout)
print(result.returncode)
print(date.stdout)
print(date.returncode)

 

If the python script is directly put in the Scheduler Activity it will fail. This is due to the scheduler function being unable to detect what type of script it is being executed and does not run the script using the interpreter program as follows:

 

python3 /home/cm/scripts/test.py <ip>

 

Troubleshoot Scheduler Activities and Custom script failures:

To troubleshoot scheduler tasks, enable following debugs in FortiNAC:

 

execute enter-shell

diagnose debug plugin enable SchedulerInterface

diagnose tail -F output.master

 

At this point,  manually run the script from Scheduler View and verify the output.

 

Figure 1. Create a Scheduled activity with Custom Script action type and run it manually.Figure 1. Create a Scheduled activity with Custom Script action type and run it manually.

 

Example 1:

  • The Python script is used directly in Scheduled Activity Action.
  • The input argument is the FortiGate IP: 10.10.10.1
  • FortiNAC event logs will show the following when Filtering for an element: 'FortiNAC': 

 

Figure 2. Verify CLI task results in Event logs.Figure 2. Verify CLI task results in Event logs.

 

In FortiNAC CLI output messages the following will be visible:

 

yams.SchedulerInterface FINER :: 2024-09-10 11:16:23:428 :: #400 :: SchedulerServer: ScheduledSystemObject Ping_stats - Running starting task
yams INFO :: 2024-09-10 11:16:23:430 :: #400 :: Error in ScheduledSystemObject.performScheduledTask java.io.IOException: Cannot run program "/home/cm/scripts/test.py": error=13, Permission denied
yams INFO :: 2024-09-10 11:16:23:430 :: #400 :: Command was: /home/cm/scripts/test.py 10.10.10.1
yams.SchedulerInterface FINER :: 2024-09-10 11:16:23:430 :: #400 :: SchedulerServer: ScheduledSystemObject Ping_stats - Running finished task

 

If the script is manually executed in the CLI, it will only work as follows:

 

naclab1:~$ python3 /home/cm/scripts/test.py 10.10.10.1
PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data.
64 bytes from 10.10.10.1: icmp_seq=1 ttl=255 time=0.463 ms
64 bytes from 10.10.10.1: icmp_seq=2 ttl=255 time=0.654 ms
64 bytes from 10.10.10.1: icmp_seq=3 ttl=255 time=0.238 ms

--- 10.10.10.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2083ms
rtt min/avg/max/mdev = 0.238/0.451/0.654/0.170 ms

0
Tue Sep 10 11:24:40 CEST 2024

0
naclab1:~$

 

Meanwhile, as visible in the scheduler log message it is attempting directly with '/home/cm/scripts/test.py 10.10.10.1'.

To prevent this it is possible to use a bash script that simply takes the argument as input and passes it to the pythong script.

 

Example 2. Using a Bash script to execute the Python script.

 

In this case, a Bash script named 'bash_pyth.sh' has been created with following content:

 

#!/bin/bash
python3 /home/cm/scripts/test.py $1 | grep "statistics" -A 6 >> /home/cm/scripts/Scriptoutput.txt

 

This script still takes an input argument which is the 'ip' and passed it to the pythong script.

The output is then filtered for 6 lines after the 'statistics' string. This will give only the ping stats and the date command output executed afterward.

 

This output is then appended to a text file saved in /home/cm/scripts/.  

In the scheduled Activity the 'bash_pyth.sh' will be selected as the Custrom script entry and use '10.10.10.1' in the Arguments entry.

Event logs will show the following:

 

Figure 3. Script success results in Event logs.Figure 3. Script success results in Event logs.

 

 Output.master logs results:

 

yams.SchedulerInterface FINER :: 2024-09-10 11:46:33:776 :: #1404 :: new object = ScheduledSystemObject:
ID = 14
Landscape = 91769544454 00:15:5D:E4:1F:06
State = Initial
Name = Ping_stats - Running
Task Tag = SYSTEM_COMMAND
EventTag = SYSTEM_COMMAND
Description = ConfigurationScheduledObjectDesc:
actionLabel = com.bsc.ui.scheduler.SchedulerViewer.SYSTEM_COMMAND.ActionLabel
actionValue = com.bsc.ui.scheduler.SchedulerViewer.SYSTEM_COMMAND.ActionValue
commandLabel = com.bsc.ui.scheduler.SchedulerViewer.SYSTEM_COMMAND.CommandLabel
commandValue = /home/cm/scripts/bash_pyth.sh
description =
null
targets =
10.10.10.1

Type = SystemCommand
Scheduled Time = Sun Sep 10 11:46:33 CEST 2023
previousScheduledTime Time = null
Delta = 0
Command = null

com.bsc.plugin.scheduler.SchedulerServer$ObjectListener 10.10.10.6 matches operation 1yams.SchedulerInterface FINER :: 2024-09-10 11:46:33:776 :: #1404 :: satisfiesFilter called for com.bsc.plugin.scheduler.SchedulerServer$ObjectListener 10.10.10.6, result=true

 

Each time the script is executed (manually or by the scheduler) it will append the results in the /home/cm/scripts/Scriptoutput.txt file

 

naclab1:~$ tail -n 16 /home/cm/scripts/Scriptoutput.txt
Tue Sep 10 11:46:35 CEST 2024

--- 10.10.10.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2070ms
rtt min/avg/max/mdev = 0.226/0.481/0.834/0.257 ms

0
Tue Sep 10 11:49:04 CEST 2024

--- 10.10.10.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2040ms
rtt min/avg/max/mdev = 0.316/0.384/0.485/0.072 ms

0
Tue Sep 10 11:52:04 CEST 2024

naclab1:~$

 

This is a simple example where the script checks for ping statistics from an inventory device and prints the date for each time there are results. Advanced users can use more complex Python scripts to fulfill their needs and automate processes.

The scope of this article is to show how to use such scripts and how to troubleshoot scripts when calling them through  the scheduler.

 

Related documents:

Add task in Scheduler

Send Alarm to Custom Script

Contributors