ecFlow 远程执行任务

目录

ecflow 官方网站上远程执行任务的例子是假定远程服务器与 ecflow server 所在的服务器共享磁盘(例如使用 NAS)。但实际中远程服务器的文件系统往往独立于任务控制服务器,因此需要编写额外的脚本来远程执行任务。
远程执行任务注意下面几点:
1. 任务脚本
2. 执行命令
3. 与 ecflow 的通讯
任务脚本是在 ecflow server 所在的服务器生成的,需要拷贝到远程服务器上执行。
远程执行命令可以通过 ssh 调用远程服务器上的命令实现。
ecflow_client 提供与远程 ecflow 服务通讯的功能,需要设置 ECF_NODE 和 ECF_PORT 变量。要确保任务执行的环境能访问到 ECF_NODE 节点上的 ECF_PORT 端口。
为了实现远程执行任务,需要对 suite 定义、脚本环境变量、提交作业的命令等部分进行修改。

suite 定义

为了使用 ssh 连接,需要定义远程服务器的用户名 ip 地址(端口号可以省略)。

suite.add_variable("REMOTE_USER", self.remote_user)
suite.add_variable("REMOTE_HOST", self.remote_host)

定义拷贝作业脚本的根路径,对应本地的作业脚本根路径 ECF_HOME。拷贝文件时将 ECF_HOME 替换为 REMOTE_ECF_HOME,得到的就是远程服务器上文件的路径。

suite.add_variable("ECF_HOME", self.ecf_home)
suite.add_variable("REMOTE_ECF_HOME", self.remote_ecf_home)

ecflow server 节点自带的 ECF_NODE 变量值可能是服务器的 hostname,远程服务器往往无法识别。所以最好使用 IP 地址定义一个记录 ecflow server 节点的变量,例如 REMOTE_ECF_NODE。

suite.add_variable("ECF_PORT", self.ecf_port)
suite.add_variable("REMOTE_ECF_NODE", self.ecf_node)

设定 ECF_JOB_CMD,使用一个脚本实现远程提交作业。

node.add_variable(
    "ECF_JOB_CMD",
    ("submit_to_aix.sh %ECF_JOB% "
     "%ECF_HOME% %REMOTE_ECF_HOME% "
     "%REMOTE_USER% %REMOTE_HOST% "
     "'bash -lc \"remote_llsubmit4_for_ecflow %ECF_NAME% %ECF_JOB% %ECF_HOME% %REMOTE_ECF_HOME% %ECF_TRIES% %ECF_TRYNO% %REMOTE_ECF_NODE% %ECF_PORT%\"'")
)

提交作业脚本后续会介绍。

脚本环境变量

ecflow_client 使用环境变量 ECF_NODE 和 ECF_PORT 与 ecflow server 通讯,在脚本中需要将这两个变量设为远程 ecflow server 的地址。

export ECF_PORT=%ECF_PORT%
export ECF_NODE=%REMOTE_ECF_NODE%

提交作业脚本

提交作业的脚本分为两部分:ecflow server 上的脚本和远程服务器上的脚本。
ecflow server 上的脚本用于将作业拷贝到远程服务器并调用远程服务器上的命令提交作业。
一个简单的示例如下,脚本 submit_to_aix.sh

#!/usr/bin/env bash
# Usage:
#   ./submit_to_aix job_script ecf_home remote_ecf_home remote_user remote_host remote_command
set -x
job_script=$1
ecf_home=$2
remote_ecf_home=$3
remote_user=$4
remote_host=$5
remote_command=$6
remote_path=$(echo ${job_script} | sed "s:${ecf_home}:${remote_ecf_home}:g")
remote_dir=$(dirname ${remote_path})
ssh ${remote_user}@${remote_host} "mkdir -p ${remote_dir}"
scp ${job_script} ${remote_user}@${remote_host}:${remote_path}
ssh ${remote_user}@${remote_host} "${remote_command}"
set +x

远程服务器上的脚本用于提交作业,并将作业号发送给 ecflow server。
一个简单例子如下:

task_name=$1
job_script=$2
ecf_home=$3
remote_ecf_home=$4
ecf_tries=$5
ecf_tryno=$6
ecf_host=$7
ecf_port=$8

local_job_script=$(echo ${job_script} | sed "s:${ecf_home}:${remote_ecf_home}:g")

name=$(llsubmit ${local_job_script} 2>>$SUBMITLOG | tail -n 1)
rid=$(echo $name | cut -d '"' -f 2)
if [ -n "$rid" ]; then
        ecflow_client --host=${ecf_host} --port=${ecf_port} \
                --alter add variable ECF_RID ${rid} ${task_name}
fi

存在的问题

如果执行任务的节点无法访问 ecflow server,上述方法就会失效。比如 HPC 的并行节点没有对外网络,队列中的并行任务就调用 ecflow_client 就会超时退出。
一种可行的方法是在可以连接外网的节点上调用 ecflow_client,并行任务采用诸如 RPC 等方式通过该节点执行 ecflow_client 操作。因为 ecflow_client 不同的子命令使用不同的环境变量,必须考虑如何传递需要的环境变量。该方法比较繁琐,尚未实现,后面有时间我会尝试下。