Skip to content

Feat: Submit and status reporting for HTCondor - #35

Draft
Alexander-Auer wants to merge 79 commits into
DIRACGrid:mainfrom
Alexander-Auer:stack/htcondor-3-submit-status
Draft

Alexander-Auer wants to merge 79 commits into
DIRACGrid:mainfrom
Alexander-Auer:stack/htcondor-3-submit-status

Conversation

@Alexander-Auer

@Alexander-Auer Alexander-Auer commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

feat: HTCondorCEBackend with submit and status

Part of #23. PR 3 of 6 for the HTCondor-CE backend.

Important

Depends on #30 and #33 (stack/htcondor-1-core). Merge after both.
Until then, this diff also shows them. This PR's own change: 1,688 lines

A consumer can now get an HTCondor-CE backend from the registry (kind = "htcondor-ce"), submit to it and ask for status. Kill, purge and output follow in PRs 4 and 5. About half of this PR is tests.

Reading order (one commit each)

  1. Config: HTCondorCEConfig gets schedd. endpoint and schedd are validated when read, because both end up on a command line.
  2. Fix: an unreadable local input is a SpecificationRejectedError, now in the conformance suite and on the fake.
  3. Building blocks: process runs one tool, session holds one operation's credentials and tells a rejected token from an unreachable CE, and staging covers the working area and what a submission puts in it.
  4. Backend: submit, get_status and the registry entry.
  5. Tests.

Decisions to check

  • Credentials: a token lives in private files only while its operation runs. _CONDOR_SEC_CLIENT_AUTHENTICATION=REQUIRED stops HTCondor falling back to an anonymous connection after a rejected token.
  • Scopes follow the operation: compute.create for submit, compute.read for status.
  • Proxy: it rides in the job for VOMS accounting, with delegation off (HTCONDOR-2904).
  • Copies with different variable names go in separate clusters, because HTCondor merges each process's environment onto the previous one.
  • Partial failure: if a later cluster fails, the submitted copies are returned and the rest appear in failures. It only raises when nothing was submitted.
  • Handles: foreign or malformed handles never reach a command line, so an id cannot pass as an option.
  • Outputs and containers: outputs are listed by name (patterns need include_unlisted), and containers need a container_launcher.
  • No Diagnosable, on purpose.

Known issue, not fixed here

submit() raises a raw ValueError for a line break in an argument or environment value, a bad variable name, or a comma in an output name. It should be a SpecificationRejectedError. If the bad value is in a later group of copies, the first cluster is already submitted, so that job stays queued and the caller gets no handle for it.

Testing

65 new unit tests against simulated tools (FakeCondor, which answers as HTCondor 25 does), so no HTCondor is needed. Tests against a real CE arrive in PR 6.

alexander and others added 30 commits October 2, 2026 16:54
* feat: Models the core contract needs

* Feat: Protocols and Exceptions added for the core contract

* Feat: Private protocols for the BatchBackend

* feat: a fake backend to run unit tests against

* fix: some code cleanup in the helper functions

* feat: setup for the unit test suite

* chore: style fix

* chore: styling, unit test fixture

* chore: single letter var `h` refering to hanlde changed to `handle`

* fix: unused parameter in `test_injected_failure_is_reported_per_job()` removed

* feat: Models the core contract needs

* Feat: Protocols and Exceptions added for the core contract

* Feat: Private protocols for the BatchBackend

* feat: a fake backend to run unit tests against

* fix: some code cleanup in the helper functions

* feat: setup for the unit test suite

* chore: style fix

* chore: styling, unit test fixture

* chore: single letter var `h` refering to hanlde changed to `handle`

* fix: unused parameter in `test_injected_failure_is_reported_per_job()` removed

* fix: made the OutputSpec optional as it is not suppoerted by all and a consumer should choose to use it or not

---------

Co-authored-by: alexander <alexander.auer@cern.ch>
alexander added 27 commits October 26, 2026 09:53
- Google-style docstrings with Args, Returns and Raises for resolve() and every registry and configuration helper, and docstrings for the settings classes; ruff now checks docstrings against the Google convention.
- Remove vm_max_lifetime_s: removing VMs after a lifetime is the consumer's policy, not interCEde's.
- Import Callable from collections.abc, like the rest of the code.
A verb says that the call builds something, and get_backend() no longer reads like the backend itself.
ARCConfig, HTCondorCEConfig, CloudConfig, BatchLocalConfig and BatchSSHConfig
replace the flat BackendConfig, which is now their union, chosen by kind (and
by transport for batch). A consumer can still pass a plain mapping, such as a
TOML table.

- Every field is declared once, on the model of its kind: the internal
  settings classes, the hand-kept field lists and resolve() are gone, so a
  configuration is validated once instead of twice.
- validate_config() checks a configuration and returns its model;
  registry.get_backend() uses it. A model is checked again, so one changed
  with model_copy() cannot carry fields of another transport to a backend.
- Errors never repeat a value they were given, since it may be a secret, and
  name the expected fields when a field does not belong to the kind.
- The configuration tests use the public API only.

The SSH auth mode is now one value (auth = "key") instead of a list.
griffe-pydantic renders every field of each configuration model, inherited
ones included, with its type, default and description, so the reference cannot
drift from the code like the hand-written table could.
The merge of stack/registry kept a helper and a section header from the old test_config.py; the helper referred to resolve() and BackendConfig.model_validate(), which no longer exist.
Brings in the per-kind configuration models of stack/registry, and moves the
credential code onto them:

- credential_requirements(config, scopes) in _backends/credentials.py replaces
  the methods on the removed internal settings classes, with the same rules:
  a CE asks for its endpoint with the configured token and/or proxy, SSH for
  user@host:port unless an SSH agent holds the key, and a local batch system
  for nothing.
- registry.get_backend(config, credentials) checks the provider and passes it
  to the parts that authenticate: single-class backends and transports.
- The credential requirement tests move from test_config.py to
  test_credentials.py and build their configurations through validate_config().
Two tests had moved without changing, which only made the diff harder to read.
# Conflicts:
#	src/intercede/_backends/fake.py
#	src/intercede/registry.py
#	tests/unit/conftest.py
#	tests/unit/test_registry.py
A value given by mistake, such as a misspelled field or plain data in a
CredentialSet, may be the secret itself. Validation errors now hide their
input, as the configuration models already do.
The message comes from the consumer's code and may hold a token or a
secret URL. The AuthenticationError names only its type; the exception
itself is still available as __cause__.
The fields were described in comments, which the generated reference does
not show. They now use attribute docstrings, as the configuration models do.
Name every argument and the return value, and drop the blank lines
before closing quotes.
Moves test_fake_backend.py to tests/unit/backends/fake/, ready for the
HTCondor tests that follow. The tests themselves do not change.

Part of DIRACGrid#23.
Renders a submit description from a plan: one process per copy, per-copy
values indexed by ProcId, quoting, and refusing what a description cannot
hold. It sets no policy on the job except keeping finished jobs until they
are purged, so output can be collected again.

Shared with the HTCondor scheduler to come (DIRACGrid#21), so it knows nothing about
any backend. Expected values were checked against HTCondor 25.

Part of DIRACGrid#23.
Builds the tools' command lines and reads what they print: condor_submit
-terse, condor_rm, and the job ads of condor_q and condor_history, mapped
to the common JobStatus.

A finished job's result comes from its exit, a removed job keeps the result
it had, and any hold that interCEde did not cause counts as aborted.

Part of DIRACGrid#23.
For one of several CEs on a host, or a CE behind a forwarded address. The
endpoint and schedd end up on the tools' command lines, so they are checked
when the configuration is read: neither can pass as an option.

Part of DIRACGrid#23.
The contract says inputs are read before submit returns, so an unreadable
one is a SpecificationRejectedError, not a raw OSError. The conformance suite
now asks for it, and the fake does it.

Part of DIRACGrid#23.
- process: runs one tool, killing it on a timeout
- session: one operation's credentials in private files that exist only
  while it runs, the tools' environment, and telling a rejected token from
  an unreachable CE
- staging: the private working area, and what a submission puts in it

Nothing uses these yet. The backend follows in the next commit.

Part of DIRACGrid#23.
Spooled submission to a remote schedd, token authentication, and an optional
X.509 proxy for sites that account on VOMS attributes. Copies whose variable
names differ get separate clusters, because HTCondor merges each process's
environment onto the previous one.

Registered as `htcondor-ce`. Kill, purge and output follow in their own
branches.

Part of DIRACGrid#23.
FakeCondor answers the way HTCondor 25 does (checked against a live schedd),
so these run without HTCondor installed: credentials, error classification,
staging, secrets, containers and the working area.

Part of DIRACGrid#23.
@Alexander-Auer Alexander-Auer changed the title Stack/htcondor 3 submit status Feat: Submit and status reporting for HTCondor Nov 3, 2026
This was referenced Nov 3, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant