Batch_connect app with permission denied in generated slurm script while generating connect.yml file

Hello Team,

I want to ask your help to understand/fix the following error.

I’m setting up a batch_connect app to configure and start a vLLM + OpenHands session in our local cluster.

The error happens during the slurm script execution on the compute node. I can see the host portion of the `connection.yml` is populated, and then the permission denied showing in the output.log:

Script starting...
Generating connection YAML file...
/var/spool/slurm/d/job33111772/slurm_script: line 144: /gpfs/home/myuser/ondemand/data/sys/dashboard/batch_connect/dev/ood-vllm/output/0a37d2a6-6208-4c3a-95a8-7ca95943b3dc/script.sh: Permission denied

When I open the `connection.yml` file I can see only the host is there:
```
host: hpcgpu020
port:
password:
```
The template script.sh uses Python socket library to find a free port for vLLM. I’m guessing that is the problem, but I cannot understand/explain exactly why.

Here is how that script looks:

#!/usr/bin/env bash

set -euo pipefail
cd "${HOME}"

CONDA_BASE_FALLBACK="/gpfs/hpc_fs/scratch/conda"
VLLM_CONDA_ENV="vllm-serve"
OPENHANDS_CONDA_ENV="openhands-ai"

# Shared HuggingFace model cache on GPFS.
HF_HOME_SHARED="/gpfs/hpc_fs/scratch/hf-cache"

# Outbound HTTP proxy used by compute nodes.
PROXY_HOST="hpclogin01"
PROXY_PORT="3128"

# =============================================================================
# 1. ENVIRONMENT
# =============================================================================
module purge 2>/dev/null || true

module load miniforge3 2>/dev/null || true
CONDA_BASE=$(conda info --base 2>/dev/null || echo "${CONDA_BASE_FALLBACK}")
echo "[conda] base environment: ${CONDA_BASE}"

_HOST=$(hostname)
_HOST_IP=$(hostname -i 2>/dev/null | awk '{print $1}' || echo "127.0.0.1")

# =============================================================================
# 2. PORT DISCOVERY
# Two ports: one for vLLM, one reserved for OpenHands.
# =============================================================================
_free_port() {
    python3 -c \
        'import socket; s=socket.socket(); s.bind(("",0)); p=s.getsockname()[1]; s.close(); print(p)'
}
VLLM_PORT=$(_free_port)
OPENHANDS_PORT=$(_free_port)

# =============================================================================
# 3. WRITE connection.yml
# OOD reads this YAML file and makes every key available as a local variable
# in view.html.erb.  Starting with vllm_ready=false; the health-check loop
# flips that flag to "true" once /health responds.
# =============================================================================
STAGED_ROOT="/gpfs/hpc_fs/home/hpcuser/ondemand/data/sys/dashboard/batch_connect/dev/ood-vllm/output/0a37d2a6-6208-4c3a-95a8-7ca95943b3dc"
CONNECTION_YML="${STAGED_ROOT}/connection.yml"

cat > "${CONNECTION_YML}" << EOL
---
host: ${_HOST}
port: ${VLLM_PORT}
vllm_port: ${VLLM_PORT}
openhands_port: ${OPENHANDS_PORT}
model_repo_id: "${MODEL_REPO_ID}"
model_served_name: "${MODEL_SERVED_NAME}"
hardware_pool: "${HARDWARE_POOL}"
gpu_count: "${GPU_COUNT}"
enable_openhands: "${ENABLE_OPENHANDS}"
vllm_ready: "false"
EOL
echo "[ood]   connection.yml initialised at ${CONNECTION_YML}"

It could actually be that template/script.sh.erb isn’t 755 or executable at all. Line 144 of job_script_content.sh is trying to execute .../0a37d2a6-6208-4c3a-95a8-7ca95943b3dc/script.sh right?

Thanks @jeff.ohrstrom! You nailed it as usual.. :ok_hand:

And thank you as well for reminding me, the job script should also have read permissions set for all. I tend to only do a chmod +x ... every time and that will probably create other issues down the road. :bomb:

I have a question regarding the ERB templates. Why is that the OOD team choose Ruby as an script language for those. Do you guys have plans to also support Python. And is there any linter or syntax checking tool that you can recommend using for the submit.yml.erb and view.html.erb files?

I currently use this idiom:

$ erb -T - -x submit.yml.erb | ruby -c
Syntax OK

But I have the impression there might be a better tool for that.

Thanks again for saving me a few hours of headache. :folded_hands:

The dashboard application is Ruby on Rails, so that’s why it’s Ruby. We don’t have any plans to support python.

I think that that’s likely your best option, though I don’t know of any others.