Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions HOWTO/JOB_DIRECTIVES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Job Script Directives

Job scripts in Sky Port use special directives prefixed with `#SWM` to specify job requirements and configuration.

## Available Directives

### Resource Requirements

#### nodes
Specify the number of nodes to allocate for the job.
```bash
#SWM nodes <count>
```
**Example:**
```bash
#SWM nodes 3
```
This will request a partition with 3 compute nodes. The nodes will be named:
- `swm-<jobid>-main` (primary/manager node)
- `swm-<jobid>-node0` (first extra compute node)
- `swm-<jobid>-node1` (second extra compute node)

**Default:** 1 node

**Note:** Multi-node job support requires the gate to support the multi-node partition feature (available in swm-cloud-gate branch `feature/multi-node-jobs`).

#### flavor
Specify the cloud instance flavor/size.
```bash
#SWM flavor <flavor_name>
```

#### gpus
Request GPU resources.
```bash
#SWM gpus <count>
```

### Image Configuration

#### cloud-image
Specify the cloud VM image to use.
```bash
#SWM cloud-image <image_name>
```

#### container-image
Specify the Docker container image to run the job in.
```bash
#SWM container-image <image:tag>
```

### Job Metadata

#### name
Set a human-readable name for the job.
```bash
#SWM name <job_name>
```

#### comment
Add a description/comment for the job.
```bash
#SWM comment <description>
```

#### account
Specify the account to use for billing.
```bash
#SWM account <account_name>
```

### Input/Output

#### stdin
Specify the standard input file.
```bash
#SWM stdin <file_path>
```

#### stdout
Specify where to redirect standard output.
```bash
#SWM stdout <file_path>
```

#### stderr
Specify where to redirect standard error.
```bash
#SWM stderr <file_path>
```

#### workdir
Set the working directory for the job.
```bash
#SWM workdir <directory_path>
```

#### input-files
Specify input files to be transferred to the job.
```bash
#SWM input-files <file1> <file2> ...
```

#### output-files
Specify output files to be transferred back after job completion.
```bash
#SWM output-files <file1> <file2> ...
```

### Networking

#### ports
Specify ports to forward from the remote node.
```bash
#SWM ports <port1>,<port2>,...
```

#### submission-address
Specify the submission address.
```bash
#SWM submission-address <address>
```

### Job Behavior

#### relocatable
Mark the job as relocatable (can be migrated between nodes).
```bash
#SWM relocatable
```

## Complete Multi-Node Example

```bash
#!/bin/bash

#SWM name Multi-Node MPI Job
#SWM nodes 4
#SWM flavor Standard_D4s_v3
#SWM cloud-image ubuntu22.04
#SWM container-image mpi/ubuntu:latest
#SWM relocatable
#SWM comment Distributed MPI computation across 4 nodes

echo "Starting multi-node job on $(hostname)"
echo "Job ID: $SWM_JOBID"

# Your MPI or distributed application code here
mpirun -n 16 ./my_parallel_app

echo "Job completed"
```
21 changes: 21 additions & 0 deletions priv/examples/jobscripts/multi-node.job
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

#SWM name Multi-Node Job Example
#SWM nodes 3
#SWM relocatable
#SWM comment Example job script demonstrating multi-node job submission

# This job requests 3 nodes from the cloud provider
# The nodes will be named: swm-<jobid>-node0, swm-<jobid>-node1, swm-<jobid>-node2
# where swm-<jobid>-node0 is the main/master node

echo "Hello from multi-node job $SWM_JOBID"
echo "Running on node: $(hostname)"
date

# Your multi-node application code here
# For example, MPI applications, distributed computing tasks, etc.

sleep 60

echo "Multi-node job completed"
30 changes: 30 additions & 0 deletions src/srv/user/wm_jobscript.erl
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ parse_line(Ws, Job) when hd(Ws) == "flavor", length(Ws) > 1 ->
add_requested_resource("flavor", lists:flatten(tl(Ws)), Job);
parse_line(Ws, Job) when hd(Ws) == "gpus", length(Ws) > 1 ->
add_requested_resource("gpus", list_to_integer(lists:flatten(tl(Ws))), [], Job);
parse_line(Ws, Job) when hd(Ws) == "nodes", length(Ws) > 1 ->
add_requested_resource("node", list_to_integer(lists:flatten(tl(Ws))), [], Job);
parse_line(Ws, Job) when hd(Ws) == "account", length(Ws) > 1 ->
wm_entity:set({account_id, get_account_id(lists:flatten(tl(Ws)))}, Job);
parse_line(Ws, Job) when hd(Ws) == "name", length(Ws) > 1 ->
Expand Down Expand Up @@ -135,3 +137,31 @@ parse_line(Ws, Job) ->
get_account_id(AccountName) ->
{ok, Account} = wm_conf:select(account, {name, AccountName}),
wm_entity:get(id, Account).

%% ============================================================================
%% Tests
%% ============================================================================

-ifdef(EUNIT).

-include_lib("eunit/include/eunit.hrl").

% ./rebar3 eunit --module=wm_jobscript
-spec parse_nodes_directive_test() -> ok.
parse_nodes_directive_test() ->
JobScript = "#!/bin/bash\n#SWM nodes 3\necho hello",
Job = parse(JobScript),
Resources = wm_entity:get(request, Job),
NodeResource = lists:keyfind("node", 2, Resources),
?assertMatch(#resource{name = "node", count = 3}, NodeResource).

-spec parse_single_node_default_test() -> ok.
parse_single_node_default_test() ->
JobScript = "#!/bin/bash\necho hello",
Job = parse(JobScript),
Resources = wm_entity:get(request, Job),
% When no nodes directive is present, default should be added elsewhere
% This test just ensures parsing doesn't crash
?assertEqual([], Resources).

-endif.
Loading