Connect workloads
To gate a licensed job, have it make three requests to LicOps: admit when it is submitted, dispatch when it starts, and release when it ends. LicOps only gates the jobs that ask it, so something in your environment has to make the requests. Pick the integration that matches where your jobs run:
| Your jobs run on | Use | Who makes the requests |
|---|---|---|
| Slurm | Slurm adapters | An sbatch wrapper on the submit nodes, and controller prolog and epilog hooks. |
| IBM Spectrum LSF | LSF adapters | An esub on the submit hosts, and queue PRE_EXEC and POST_EXEC hooks. |
| Kubernetes | Kubernetes workloads | The admission webhook for annotated pods, or the job itself. |
| Anything else | Call the admission API | Your own wrapper, script, or service. |
OpenLM supplies the Slurm and LSF adapters, and an integration kit with a wrapper script, a Python client, an OpenAPI description of the API and Kubernetes examples. Contact OpenLM to get them.
For other schedulers, call the admission API from your submit hook. See Call the admission API.
Before you connect anything
Before you connect a workload, find the LicOps address, get the license names right, and decide what happens when LicOps is unreachable.
Find the LicOps address
Every integration needs one address: the LicOps admission API on port 8100. The following table lists the address for each caller:
| Caller | Address |
|---|---|
| Slurm or LSF adapters | http://<licops-host>:8100/api/v1/admission-controller |
| A workload in the same Kubernetes cluster | http://openlm-router-api.<namespace>.svc:8100 |
| Your own tools | http://<licops-host>:8100, with the paths in API reference |
To confirm the address, run this command from the host that will make the calls, not from your own workstation:
curl -s -o /dev/null -w '%{http_code}\n' http://<licops-host>:8100/api/v1/status
200 means the address is right. Port 30001 is not the API: it speaks the FlexLM protocol, so an HTTP request there stops responding or fails.
Use the exact license names
Every request names a pool by its vendor daemon and feature, such as MLM and MATLAB. The names must match the pool exactly, including case: a request for mlm or Matlab matches nothing and is denied as NoServerAvailable, which looks like an outage rather than a typo. Copy the names from GET /api/v1/stats, as described in Configure OpenLM LicOps.
Some features contain spaces, such as Acrobat Pro. Send them with a real space in the API. The Slurm license map writes the space as %20, because the map itself is separated by spaces. The adapter turns it back into a space before it calls LicOps.
Release on every ending
A job's seat stays counted until its release arrives, or until its session times out. A job that fails, is canceled, or times out must release as surely as one that succeeds, or the seat stays taken while nobody uses it and other jobs are denied. The scheduler adapters release from hooks the scheduler runs whatever happens to the job. If you write your own integration, release from a finally block, a trap, or a hook that always runs.
Decide what happens when LicOps is unreachable
If LicOps is down or slow, the adapters cannot ask for a seat. You choose what they do, separately for admit and for dispatch. The following table compares the two choices:
| Aspect | Fail open: run the job anyway | Fail closed: hold or refuse the job |
|---|---|---|
| While LicOps is down | Jobs keep flowing. | Jobs stop. |
| The risk | More jobs start than the seats allow, and some fail at checkout. | The cluster idles until LicOps is back. |
| Suits | Dispatch, where the seat was already admitted, and widely licensed tools | Admit, for licenses where compliance matters more than throughput |
The Slurm and LSF adapters read OL_FAIL_MODE_ADMIT and OL_FAIL_MODE_DISPATCH, each open or closed. Both default to open. The integration kit's wrapper script has its own setting, OL_FAIL_MODE, which defaults to closed. They also give up on a request after OL_TIMEOUT seconds, 2 by default, and then apply the fail mode, so a slow LicOps never holds up submission for long. Decide deliberately and write down which you chose.
Decide whether LicOps also chooses the server
LicOps always decides whether a job may start. Whether the job then checks out from the server LicOps chose depends on how its checkout reaches the license server. The following table lists where the application checks out for each integration:
| Integration | Where the application checks out |
|---|---|
| Slurm or LSF adapters, by default | From the servers in the application's own license settings. LicOps gates the job but does not steer its checkout, so rules that choose a server, such as Cascade across servers in priority order, do not change where it checks out. |
| Slurm or LSF adapters, with checkout routing | Through the LicOps listen port, 30001, which passes the checkout to the server LicOps chose for that job. |
| The Kubernetes admission webhook | Through a sidecar in the pod, which passes it to LicOps the same way. |
| A Kubernetes job or your own integration calling the API | From the server dispatch names, when you set LM_LICENSE_FILE to the licenseFile that dispatch returns. |
Admission only is the simpler place to start, and already stops jobs from starting without a seat. Add checkout routing when you want the placement rules to apply to the checkouts themselves.
With checkout routing, LicOps recognizes each checkout by the IP address of the node it comes from. The compute nodes must reach the LicOps host directly, without address translation in between. The node's existing license setting stays in place behind the LicOps entry, so if LicOps is unreachable, the application falls back to its usual server.
The documentation team might draft this page using a large language model. A technical writer reviews every page and verifies it against the product before publishing it. A human makes the final decision.