
本文详解 Rundeck 文件选项(type: file)的底层机制,指出直接拼接路径的常见误区,演示如何通过脚本步骤(Script Step)安全获取真实文件路径,并提供可运行的 Python 示例与完整 Job YAML 配置。
本文详解 rundeck 文件选项(`type: file`)的底层机制,指出直接拼接路径的常见误区,演示如何通过脚本步骤(script step)安全获取真实文件路径,并提供可运行的 python 示例与完整 job yaml 配置。
在 Rundeck 中使用 type: file 类型的作业选项时,一个普遍误解是:${file.optionName} 返回的是“文件路径”,而 ${file.optionName.fileName} 返回的是“文件名”,二者可直接拼接为完整路径(如 os.path.join(${file.opt}, ${file.opt.fileName}))。这是错误的——Rundeck 实际上传文件至服务端临时目录(如 /var/rundeck/var/upload/uuid),${file.optionName} 返回的正是该临时文件的绝对路径(已含文件名),而非仅目录;而 ${file.optionName.fileName} 仅返回原始上传时的文件名(不含路径),在多数场景下完全冗余。
因此,您无需拼接路径。只需将 ${file.history_path} 直接作为参数传入 Python 脚本,它已是可读取的有效文件路径。
✅ 正确做法:使用 Script Step + 参数透传
Rundeck 的 exec 命令(内联执行)对文件路径变量支持有限,且易受 shell 解析干扰;推荐改用 Script Step,它能更可靠地注入参数、自动处理路径转义,并支持 Python 解释器直调。
1. 简洁可靠的 Python 脚本(示例:main.py)
#!/usr/bin/env python3
import sys
import os
import pandas as pd
if len(sys.argv) < 2:
print("Error: Missing file path argument.")
sys.exit(1)
# 直接使用第一个参数 —— 它就是 Rundeck 上传后的完整文件路径
uploaded_file = sys.argv[1].strip()
print(f"Received file path: '{uploaded_file}'")
print(f"File exists: {os.path.isfile(uploaded_file)}")
print(f"File size: {os.path.getsize(uploaded_file)} bytes")
# ✅ 安全读取(以 Excel 为例,自动适配 CSV/JSON 等)
try:
if uploaded_file.endswith('.xlsx') or uploaded_file.endswith('.xls'):
df = pd.read_excel(uploaded_file)
elif uploaded_file.endswith('.csv'):
df = pd.read_csv(uploaded_file)
else:
print("Warning: Unsupported format. Skipping Pandas load.")
df = None
if df is not None:
print(f"Loaded DataFrame with {len(df)} rows and {len(df.columns)} columns.")
except Exception as e:
print(f"Failed to load file: {e}")
sys.exit(1)? 提示:脚本中无需 os.path.join 拼接,sys.argv[1] 即为真实路径(如 /var/rundeck/var/upload/9a6835df-f6fd-4f75-8d25-0964b6be6d40)。
立即学习“Python免费学习笔记(深入)”;
2. Rundeck Job YAML 配置(关键字段说明)
- name: Process Upload File
description: Reads an uploaded file (e.g., Excel/CSV) via Python script
options:
- name: history_path
label: History File
type: file
required: true
sequence:
commands:
# Step 1: 可选 —— 打印调试信息(确认变量解析正确)
- exec: echo "Debug: File path = ${file.history_path}"
# Step 2: ✅ 核心 —— Script Step 调用 Python
- args: ${file.history_path} # ← 仅需这一个参数!
scriptInterpreter: /opt/env/bin/python # 替换为您的 Python 解释器路径
scriptfile: /opt/script/main.py # 替换为您的脚本绝对路径
interpreterArgsQuoted: false
expandTokenInScriptFile: true
keepgoing: false
strategy: node-first✅ 关键配置说明:
- args: ${file.history_path}:唯一必需参数,Rundeck 自动将其解析为上传后的真实文件路径。
- scriptInterpreter:显式指定 Python 环境(推荐使用虚拟环境路径,避免系统 Python 版本冲突)。
- interpreterArgsQuoted: false:确保路径中空格等特殊字符被正确传递(Rundeck 默认已做转义)。
- expandTokenInScriptFile: true:若脚本内需引用 Rundeck 变量(如 ${job.name}),才启用;本例无需。
⚠️ 注意事项与最佳实践
- 不要使用 exec 内联调用带 ${file.xxx} 的 Python 命令:Shell 层可能截断路径、忽略空格或触发意外变量扩展,导致 FileNotFoundError。
- file_path 选项类型是陷阱:定义 type: file 的选项(如 history_path)本身即代表文件,不存在独立的“目录选项”;Rundeck 不提供用户可控的上传根目录。
- 临时文件生命周期:上传文件在作业执行结束后由 Rundeck 自动清理(默认保留数小时),请勿依赖长期存储;如需持久化,请在脚本内 shutil.copy() 到自定义目录。
- 权限检查:确保 Rundeck 执行用户(如 rundeck)对上传目录(/var/rundeck/var/upload/)和脚本路径有读取权限。
- Pandas 依赖:确保目标节点的 Python 环境已安装 pandas, openpyxl(Excel)或 xlrd(旧版 Excel)等必要包。
总结
Rundeck 的文件上传本质是服务端临时存储,${file.optionName} 已是“开箱即用”的完整路径。放弃手动拼接,拥抱 Script Step 的标准化参数传递,即可稳定、简洁、安全地将上传文件交由 Python 处理。调试时优先用 echo 验证变量值,再用 os.path.isfile() 在脚本内二次校验,双保险保障可靠性。










