diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f9c6701..a5e951f 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -19,7 +19,8 @@ RUN wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz && tar -xvf go${G mv go /usr/local && rm go${GO_VERSION}.linux-amd64.tar.gz ENV PATH=$PATH:/usr/local/go/bin:/home/vscode/go/bin -RUN git clone https://github.com/flux-framework/flux-sched /opt/flux-sched +# RUN git clone https://github.com/flux-framework/flux-sched /opt/flux-sched +RUN git clone -b alloc-grow https://github.com/milroy/flux-sched /opt/flux-sched # Add the group and user that match our ids RUN groupadd -g ${USER_GID} ${USERNAME} && \ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 2e62816..83b84b6 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -23,8 +23,8 @@ jobs: # container base and lib prefix test: [["fluxrm/flux-sched:noble", "/usr/lib"], ["fluxrm/flux-sched:fedora40", "/usr/lib64"], - ["fluxrm/flux-sched:bookworm-amd64", "/usr/lib"], - ["fluxrm/flux-sched:el9", "/usr/lib64"]] + ["fluxrm/flux-sched:bookworm-amd64", "/usr/lib"]] +# ["fluxrm/flux-sched:el9", "/usr/lib64"]] container: image: ${{ matrix.test[0] }} @@ -37,12 +37,12 @@ jobs: go-version: ^1.22 - name: flux-sched build - run: git clone https://github.com/flux-framework/flux-sched /opt/flux-sched -# - name: build flux-sched -# run: | -# here=$(pwd) -# cd /opt/flux-sched -# mkdir build && cd build && cmake ../ && make -j && sudo make install -# cd $here + run: git clone -b alloc-grow https://github.com/milroy/flux-sched /opt/flux-sched + - name: build flux-sched + run: | + here=$(pwd) + cd /opt/flux-sched + mkdir build && cd build && cmake ../ && make -j && sudo make install + cd $here - name: Test run: LIB_PREFIX=${{ matrix.test[1] }} make test-v diff --git a/Makefile b/Makefile index 6f4d6cd..b23144c 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ test: .PHONY: test-v test-v: -# $(COMMONENVVAR) $(BUILDENVVAR) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) go test -count 1 -run TestCancel -v -ldflags '-w' ./pkg/fluxcli ./pkg/types +# $(COMMONENVVAR) $(BUILDENVVAR) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) go test -count 1 -run TestGrowAllocate -v -ldflags '-w' ./pkg/fluxcli ./pkg/types $(COMMONENVVAR) $(BUILDENVVAR) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) go test -v -ldflags '-w' ./pkg/fluxcli ./pkg/types .PHONY: $(LOCALBIN) diff --git a/pkg/fluxcli/data/grow-allocation/node-test.json b/pkg/fluxcli/data/grow-allocation/node-test.json new file mode 100644 index 0000000..bc78b6d --- /dev/null +++ b/pkg/fluxcli/data/grow-allocation/node-test.json @@ -0,0 +1,985 @@ +{ + "graph": { + "nodes": [ + { + "id": "221", + "metadata": { + "type": "core", + "basename": "core", + "name": "core0", + "id": 0, + "uniq_id": 221, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core0" + } + } + }, + { + "id": "222", + "metadata": { + "type": "core", + "basename": "core", + "name": "core1", + "id": 1, + "uniq_id": 222, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core1" + } + } + }, + { + "id": "223", + "metadata": { + "type": "core", + "basename": "core", + "name": "core2", + "id": 2, + "uniq_id": 223, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core2" + } + } + }, + { + "id": "224", + "metadata": { + "type": "core", + "basename": "core", + "name": "core3", + "id": 3, + "uniq_id": 224, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core3" + } + } + }, + { + "id": "225", + "metadata": { + "type": "core", + "basename": "core", + "name": "core4", + "id": 4, + "uniq_id": 225, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core4" + } + } + }, + { + "id": "226", + "metadata": { + "type": "core", + "basename": "core", + "name": "core5", + "id": 5, + "uniq_id": 226, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core5" + } + } + }, + { + "id": "227", + "metadata": { + "type": "core", + "basename": "core", + "name": "core6", + "id": 6, + "uniq_id": 227, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core6" + } + } + }, + { + "id": "228", + "metadata": { + "type": "core", + "basename": "core", + "name": "core7", + "id": 7, + "uniq_id": 228, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core7" + } + } + }, + { + "id": "229", + "metadata": { + "type": "core", + "basename": "core", + "name": "core8", + "id": 8, + "uniq_id": 229, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core8" + } + } + }, + { + "id": "230", + "metadata": { + "type": "core", + "basename": "core", + "name": "core9", + "id": 9, + "uniq_id": 230, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core9" + } + } + }, + { + "id": "231", + "metadata": { + "type": "core", + "basename": "core", + "name": "core10", + "id": 10, + "uniq_id": 231, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core10" + } + } + }, + { + "id": "232", + "metadata": { + "type": "core", + "basename": "core", + "name": "core11", + "id": 11, + "uniq_id": 232, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core11" + } + } + }, + { + "id": "233", + "metadata": { + "type": "core", + "basename": "core", + "name": "core12", + "id": 12, + "uniq_id": 233, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core12" + } + } + }, + { + "id": "234", + "metadata": { + "type": "core", + "basename": "core", + "name": "core13", + "id": 13, + "uniq_id": 234, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core13" + } + } + }, + { + "id": "235", + "metadata": { + "type": "core", + "basename": "core", + "name": "core14", + "id": 14, + "uniq_id": 235, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core14" + } + } + }, + { + "id": "236", + "metadata": { + "type": "core", + "basename": "core", + "name": "core15", + "id": 15, + "uniq_id": 236, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core15" + } + } + }, + { + "id": "237", + "metadata": { + "type": "core", + "basename": "core", + "name": "core16", + "id": 16, + "uniq_id": 237, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core16" + } + } + }, + { + "id": "238", + "metadata": { + "type": "core", + "basename": "core", + "name": "core17", + "id": 17, + "uniq_id": 238, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0/core17" + } + } + }, + { + "id": "77", + "metadata": { + "type": "socket", + "basename": "socket", + "name": "socket0", + "id": 0, + "uniq_id": 77, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket0" + } + } + }, + { + "id": "239", + "metadata": { + "type": "core", + "basename": "core", + "name": "core18", + "id": 18, + "uniq_id": 239, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core18" + } + } + }, + { + "id": "240", + "metadata": { + "type": "core", + "basename": "core", + "name": "core19", + "id": 19, + "uniq_id": 240, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core19" + } + } + }, + { + "id": "241", + "metadata": { + "type": "core", + "basename": "core", + "name": "core20", + "id": 20, + "uniq_id": 241, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core20" + } + } + }, + { + "id": "242", + "metadata": { + "type": "core", + "basename": "core", + "name": "core21", + "id": 21, + "uniq_id": 242, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core21" + } + } + }, + { + "id": "243", + "metadata": { + "type": "core", + "basename": "core", + "name": "core22", + "id": 22, + "uniq_id": 243, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core22" + } + } + }, + { + "id": "244", + "metadata": { + "type": "core", + "basename": "core", + "name": "core23", + "id": 23, + "uniq_id": 244, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core23" + } + } + }, + { + "id": "245", + "metadata": { + "type": "core", + "basename": "core", + "name": "core24", + "id": 24, + "uniq_id": 245, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core24" + } + } + }, + { + "id": "246", + "metadata": { + "type": "core", + "basename": "core", + "name": "core25", + "id": 25, + "uniq_id": 246, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core25" + } + } + }, + { + "id": "247", + "metadata": { + "type": "core", + "basename": "core", + "name": "core26", + "id": 26, + "uniq_id": 247, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core26" + } + } + }, + { + "id": "248", + "metadata": { + "type": "core", + "basename": "core", + "name": "core27", + "id": 27, + "uniq_id": 248, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core27" + } + } + }, + { + "id": "249", + "metadata": { + "type": "core", + "basename": "core", + "name": "core28", + "id": 28, + "uniq_id": 249, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core28" + } + } + }, + { + "id": "250", + "metadata": { + "type": "core", + "basename": "core", + "name": "core29", + "id": 29, + "uniq_id": 250, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core29" + } + } + }, + { + "id": "251", + "metadata": { + "type": "core", + "basename": "core", + "name": "core30", + "id": 30, + "uniq_id": 251, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core30" + } + } + }, + { + "id": "252", + "metadata": { + "type": "core", + "basename": "core", + "name": "core31", + "id": 31, + "uniq_id": 252, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core31" + } + } + }, + { + "id": "253", + "metadata": { + "type": "core", + "basename": "core", + "name": "core32", + "id": 32, + "uniq_id": 253, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core32" + } + } + }, + { + "id": "254", + "metadata": { + "type": "core", + "basename": "core", + "name": "core33", + "id": 33, + "uniq_id": 254, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core33" + } + } + }, + { + "id": "255", + "metadata": { + "type": "core", + "basename": "core", + "name": "core34", + "id": 34, + "uniq_id": 255, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core34" + } + } + }, + { + "id": "256", + "metadata": { + "type": "core", + "basename": "core", + "name": "core35", + "id": 35, + "uniq_id": 256, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1/core35" + } + } + }, + { + "id": "78", + "metadata": { + "type": "socket", + "basename": "socket", + "name": "socket1", + "id": 1, + "uniq_id": 78, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0/socket1" + } + } + }, + { + "id": "5", + "metadata": { + "type": "node", + "basename": "node", + "name": "node0", + "id": 0, + "uniq_id": 5, + "rank": -1, + "exclusive": true, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0/node0" + } + } + }, + { + "id": "1", + "metadata": { + "type": "rack", + "basename": "rack", + "name": "rack0", + "id": 0, + "uniq_id": 1, + "rank": -1, + "exclusive": false, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0/rack0" + } + } + }, + { + "id": "0", + "metadata": { + "type": "cluster", + "basename": "medium", + "name": "medium0", + "id": 0, + "uniq_id": 0, + "rank": -1, + "exclusive": false, + "unit": "", + "size": 1, + "paths": { + "containment": "/medium0" + } + } + } + ], + "edges": [ + { + "source": "77", + "target": "221", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "222", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "223", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "224", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "225", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "226", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "227", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "228", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "229", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "230", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "231", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "232", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "233", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "234", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "235", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "236", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "237", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "77", + "target": "238", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "5", + "target": "77", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "239", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "240", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "241", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "242", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "243", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "244", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "245", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "246", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "247", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "248", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "249", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "250", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "251", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "252", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "253", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "254", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "255", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "78", + "target": "256", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "5", + "target": "78", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "1", + "target": "5", + "metadata": { + "subsystem": "containment" + } + }, + { + "source": "0", + "target": "1", + "metadata": { + "subsystem": "containment" + } + } + ] + } +} \ No newline at end of file diff --git a/pkg/fluxcli/data/grow-allocation/test006.yaml b/pkg/fluxcli/data/grow-allocation/test006.yaml new file mode 100644 index 0000000..080ee95 --- /dev/null +++ b/pkg/fluxcli/data/grow-allocation/test006.yaml @@ -0,0 +1,30 @@ +version: 9999 +resources: + - type: cluster + count: 1 + with: + - type: rack + count: 1 + with: + - type: node + count: 1 + with: + - type: slot + count: 1 + label: default + with: + - type: socket + count: 1 + with: + - type: core + count: 18 +# a comment +attributes: + system: + duration: 3600 +tasks: + - command: [ "app" ] + slot: default + count: + per_slot: 1 + diff --git a/pkg/fluxcli/reapi_cli.go b/pkg/fluxcli/reapi_cli.go index 8dec4f1..3a92049 100644 --- a/pkg/fluxcli/reapi_cli.go +++ b/pkg/fluxcli/reapi_cli.go @@ -104,10 +104,21 @@ func (cli *ReapiClient) InitContext(jgf string, options string) (err error) { func (cli *ReapiClient) Match( match_op types.MatchType, jobspec string, -) (reserved bool, allocated string, at int64, overhead float64, jobid int64, err error) { + jobid int64, +) (bool, string, int64, float64, int64, error) { + + // Variables we are preparing to return + var reserved bool + var at int64 + var overhead float64 + var err error + + // C variables we need for request - "R" and the jobspec var r = C.CString("") spec := C.CString(jobspec) - var jobidPassed uint64 + + // We assume the job is not negative (signed) + jobidPassed := uint64(jobid) fluxerr := (int)(C.reapi_cli_match((*C.struct_reapi_cli_ctx)(cli.ctx), C.match_op_t(match_op), @@ -118,7 +129,8 @@ func (cli *ReapiClient) Match( (*C.long)(&at), (*C.double)(&overhead))) - allocated = C.GoString(r) + allocated := C.GoString(r) + fmt.Printf("After job id %d", jobidPassed) defer C.free(unsafe.Pointer(r)) defer C.free(unsafe.Pointer(spec)) @@ -129,7 +141,6 @@ func (cli *ReapiClient) Match( } jobid, err = strconv.ParseInt(fmt.Sprintf("%d", jobidPassed), 10, 64) return reserved, allocated, at, overhead, jobid, err - } // MatchAllocate matches a jobspec to the "best" resources and either allocate @@ -155,7 +166,7 @@ func (cli *ReapiClient) Match( func (cli *ReapiClient) MatchAllocate( orelse_reserve bool, jobspec string, -) (reserved bool, allocated string, at int64, overhead float64, jobid int64, err error) { +) (bool, string, int64, float64, int64, error) { var match_op types.MatchType if orelse_reserve { @@ -163,7 +174,16 @@ func (cli *ReapiClient) MatchAllocate( } else { match_op = types.MatchAllocate } - return cli.Match(match_op, jobspec) + // MatchAllocate we provide an empty (unset) jobid + return cli.Match(match_op, jobspec, int64(0)) +} + +// MatchGrowAllocate calls Match and requests to Grow +func (cli *ReapiClient) MatchGrowAllocate( + jobspec string, + jobid int64, +) (bool, string, int64, float64, int64, error) { + return cli.Match(types.MatchGrowAllocation, jobspec, jobid) } // MatchSatisfy runs satisfiability check on jobspec. diff --git a/pkg/fluxcli/reapi_cli_test.go b/pkg/fluxcli/reapi_cli_test.go index 025edc9..39fcd67 100644 --- a/pkg/fluxcli/reapi_cli_test.go +++ b/pkg/fluxcli/reapi_cli_test.go @@ -27,6 +27,84 @@ func NewClient(jgf string) (*ReapiClient, error) { return cli, err } +/* + +cmds010="${cmd_dir}/cmds10.in" +test010_desc="grow existing job to occupy all resources; can't occupy more than exist" +test_expect_success "${test010_desc}" ' + sed "s~@TEST_SRCDIR@~${SHARNESS_TEST_SRCDIR}~g" ${cmds010} > cmds010 && + ${query} -L ${jgf} -F jgf -f jgf -S CA -P low -t 010.R.out \ + < cmds010 && + test_cmp 010.R.out ${exp_dir}/010.R.out +' + +cmds011="${cmd_dir}/cmds11.in" +test011_desc="grow existing job four times, grow graph and grow allocation onto new resources; can't occupy more than exist" +test_expect_success "${test010_desc}" ' + sed "s~@TEST_SRCDIR@~${SHARNESS_TEST_SRCDIR}~g" ${cmds011} > cmds011 && + ${query} -L ${jgf} -F jgf -f jgf -S CA -P low -t 011.R.out \ + < cmds011 && + test_cmp 011.R.out ${exp_dir}/011.R.out +' +*/ + +func TestGrowAllocate(t *testing.T) { + + // This graph has 1 node, 2 sockets, each with 18 cores + jgf, err := os.ReadFile("./data/grow-allocation/node-test.json") + if err != nil { + t.Errorf("Error reading JGF file: %s", err) + } + cli, err := NewClient(string(jgf)) + if err != nil { + t.Errorf("creating new client %v\n", err) + } + + // This job asks for half the entire graph - 1 node, 18 cores + jobspec, err := os.ReadFile("./data/grow-allocation/test006.yaml") + if err != nil { + t.Log("Error reading grow-allocate initial jobspec file") + } + // Allocate the initial job (described above) + t.Log("allocate initial job to take up half of graph") + reserved, allocated, at, _, jobid, err := cli.MatchAllocate(false, string(jobspec)) + if err != nil { + t.Logf("Fluxion errors %s\n", cli.GetErrMsg()) + t.Errorf("matchAllocate without reservations failed %v\n", err) + } + printOutput(reserved, allocated, at, jobid, err) + + t.Log("request to grow allocate first time should succeed") + reserved, allocated, at, _, jobid, err = cli.MatchGrowAllocate(string(jobspec), jobid) + if err != nil { + t.Logf("Fluxion errors %s\n", cli.GetErrMsg()) + t.Errorf("matchGrowAllocate failed %v\n", err) + } + printOutput(reserved, allocated, at, jobid, err) + + t.Log("request to grow allocate second time should alert resources are not available") + reserved, allocated, at, _, jobid, err = cli.MatchGrowAllocate(string(jobspec), jobid) + if err != nil { + t.Logf("Fluxion errors %s\n", cli.GetErrMsg()) + t.Errorf("matchGrowAllocate failed %v\n", err) + } + printOutput(reserved, allocated, at, jobid, err) + if allocated != "" { + t.Error("second group should not work without resources") + t.Error("initial allocation failed (is empty)") + } + + // Cancel should work of the initial job + t.Log("cancel for partially cancelled job") + err = cli.Cancel(jobid, false) + + if err != nil { + t.Logf("Fluxion errors %s\n", cli.GetErrMsg()) + t.Errorf("cancel for grown job: %v\n", err) + } + +} + func TestCancel(t *testing.T) { // This job takes up the entire graph @@ -130,7 +208,6 @@ func TestCancel(t *testing.T) { if allocated == "" { t.Errorf("matchAllocate should not have failed, we have two nodes again.") } - } func TestMatchAllocate(t *testing.T) { @@ -169,7 +246,7 @@ func TestMatchAllocate(t *testing.T) { printOutput(reserved, allocated, at, jobid, err) // Same call, but directly to Match specifying the match operator type - reserved, allocated, at, overhead, jobid, err = cli.Match(types.MatchAllocate, string(jobspec)) + reserved, allocated, at, overhead, jobid, err = cli.Match(types.MatchAllocate, string(jobspec), int64(0)) if err != nil { t.Logf("Fluxion errors %s\n", cli.GetErrMsg()) t.Errorf("match with match_op MatchAllocate %v\n", err) @@ -177,7 +254,7 @@ func TestMatchAllocate(t *testing.T) { printOutput(reserved, allocated, at, jobid, err) // Same, but with match_op match allocate or else reserve - reserved, allocated, at, overhead, jobid, err = cli.Match(types.MatchAllocateOrElseReserve, string(jobspec)) + reserved, allocated, at, overhead, jobid, err = cli.Match(types.MatchAllocateOrElseReserve, string(jobspec), int64(0)) if err != nil { t.Logf("Fluxion errors %s\n", cli.GetErrMsg()) t.Errorf("match with match_op MatchAllocateElseReserve %v\n", err) @@ -185,7 +262,7 @@ func TestMatchAllocate(t *testing.T) { printOutput(reserved, allocated, at, jobid, err) // Same, but with satisfy - reserved, allocated, at, overhead, jobid, err = cli.Match(types.MatchAllocateWithSatisfiability, string(jobspec)) + reserved, allocated, at, overhead, jobid, err = cli.Match(types.MatchAllocateWithSatisfiability, string(jobspec), int64(0)) if err != nil { t.Logf("Fluxion errors %s\n", cli.GetErrMsg()) t.Errorf("Error in ReapiClient MatchAllocate: %v\n", err) @@ -218,8 +295,7 @@ func TestMatchAllocate(t *testing.T) { func printOutput(reserved bool, allocated string, at int64, jobid int64, err error) { fmt.Println("\n\t----Match Allocate output---") - isAllocated := allocated != "" - fmt.Printf("jobid: %d\nreserved: %t\nallocated: %v\nat: %d\nerror: %v\n", jobid, reserved, isAllocated, at, err) + fmt.Printf("jobid: %d\nreserved: %t\nallocated: %s\nat: %d\nerror: %v\n", jobid, reserved, allocated, at, err) } func printSatOutput(sat bool, err error) { diff --git a/pkg/types/types.go b/pkg/types/types.go index da265b6..254bb2e 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -28,6 +28,7 @@ const ( MatchAllocate // allocate MatchAllocateWithSatisfiability // allocate with satisfiability MatchAllocateOrElseReserve // allocate or else reserve + MatchGrowAllocation // grow allocate MatchSatisfiability // satisfiability ) @@ -37,11 +38,13 @@ func (m MatchType) String() string { case MatchAllocate: return "allocate" case MatchAllocateOrElseReserve: - return "allocate or else reserve" + return "allocate_orelse_reserve" case MatchAllocateWithSatisfiability: - return "allocate with satisfiability" + return "allocate_with_satisfiability" case MatchSatisfiability: return "satisfiability" + case MatchGrowAllocation: + return "grow_allocate" } return "unknown" } diff --git a/pkg/types/types_test.go b/pkg/types/types_test.go index f665d88..5c26c3a 100644 --- a/pkg/types/types_test.go +++ b/pkg/types/types_test.go @@ -14,15 +14,6 @@ import ( "testing" ) -// List of match types, purposefully out of order -var matchTypes = []MatchType{ - MatchAllocateWithSatisfiability, - MatchAllocateOrElseReserve, - MatchAllocate, - MatchSatisfiability, - MatchUnknown, -} - func TestToString(t *testing.T) { type test struct { description string @@ -34,8 +25,9 @@ func TestToString(t *testing.T) { {description: "unknown", input: MatchUnknown, expected: "unknown"}, {description: "allocate", input: MatchAllocate, expected: "allocate"}, {description: "satisfiability", input: MatchSatisfiability, expected: "satisfiability"}, - {description: "allocate or else reserve", input: MatchAllocateOrElseReserve, expected: "allocate or else reserve"}, - {description: "allocate with satisfiability", input: MatchAllocateWithSatisfiability, expected: "allocate with satisfiability"}, + {description: "allocate_orelse_reserve", input: MatchAllocateOrElseReserve, expected: "allocate_orelse_reserve"}, + {description: "allocate_with_satisfiability", input: MatchAllocateWithSatisfiability, expected: "allocate_with_satisfiability"}, + {description: "grow_allocate", input: MatchGrowAllocation, expected: "grow_allocate"}, } for _, item := range tests { t.Run(item.description, func(t *testing.T) { @@ -58,9 +50,10 @@ func TestAsInt(t *testing.T) { tests := []test{ {description: "unknown", input: MatchUnknown, expected: 0}, {description: "allocate", input: MatchAllocate, expected: 1}, - {description: "satisfiability", input: MatchSatisfiability, expected: 4}, - {description: "allocate or else reserve", input: MatchAllocateOrElseReserve, expected: 3}, - {description: "allocate with satisfiability", input: MatchAllocateWithSatisfiability, expected: 2}, + {description: "satisfiability", input: MatchSatisfiability, expected: 5}, + {description: "allocate_orelse_reserve", input: MatchAllocateOrElseReserve, expected: 3}, + {description: "allocate_with_satisfiability", input: MatchAllocateWithSatisfiability, expected: 2}, + {description: "grow_allocate", input: MatchGrowAllocation, expected: 4}, } for _, item := range tests { t.Run(item.description, func(t *testing.T) {