htcondor

package module
v0.20.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 48 Imported by: 0

README

golang-htcondor

A Go client library for HTCondor — collector queries, schedd submission and management, file transfer, sandbox handling, and pool metrics — plus two long-running servers built on top of it.

What's in this repo

  • Go library (github.com/bbockelm/golang-htcondor) — idiomatic Go bindings mirroring the HTCondor Python bindings. Submit jobs, query the schedd/collector, transfer files, build sandboxes, collect pool metrics. See docs/library.md.
  • htcondor-api — RESTful HTTP API server with a bundled SPA, OAuth2/OIDC support, API-key auth, an embedded IDP, admin UI, and an LLM-powered chat assistant. Runs standalone, under condor_master, or in Docker. See docs/server.md.
  • htcondor-mcp — Model Context Protocol server that exposes the same engine to LLM agents (Claude Code, etc.) over stdio. See docs/server.md.

Install

As a Go module:

go get github.com/bbockelm/golang-htcondor

As a server (pre-built container, multi-arch amd64/arm64):

docker run -p 8080:8080 ghcr.io/bbockelm/golang-htcondor:latest

Or build from source:

git clone https://github.com/bbockelm/golang-htcondor
cd golang-htcondor
make build

Quickstart

Library — query a collector:

collector := htcondor.NewCollector("collector.example.com:9618")
ads, _, err := collector.QueryAdsWithOptions(ctx, "ScheddAd", "",
    &htcondor.QueryOptions{Limit: 50})

More: docs/library.md.

HTTP server — start a demo (no HTCondor required):

./htcondor-api -demo

The SPA, admin UI, and chat assistant are served at https://localhost:8080. The first-time admin credentials are printed to stdout.

More: docs/server.md.

Documentation

Contributing

Patches welcome — see CONTRIBUTING.md for the local-development setup, pre-commit hooks, and CI expectations.

Building and testing locally
go build ./...
go test ./...
golangci-lint run

Integration tests need HTCondor installed; they run automatically in Docker via:

make docker-test-integration

The Docker dev environment (Rocky Linux 9, HTCondor pre-installed) works on Linux and Apple Silicon Macs. Open this repo in GitHub Codespaces for an instant cloud-based environment with HTCondor pre-installed.

License

Apache License 2.0. See LICENSE.

Documentation

Overview

Package htcondor provides a Go client library for HTCondor. This file adds helpers for locating a peer daemon by its address file.

Package htcondor provides HTCondor job submission functionality.

Index

Constants

View Source
const (
	// MaxAdvertiseBufferSize is the maximum buffer size for multiple ad advertisements (1MB)
	MaxAdvertiseBufferSize = 1024 * 1024

	// DefaultMyAddress is the default MyAddress value for ads without one set
	DefaultMyAddress = "<127.0.0.1:0>"

	// AvgBytesPerAttribute is the estimated average size per ClassAd attribute for buffer management
	AvgBytesPerAttribute = 100
)
View Source
const (
	StartdAdType     = "StartdAd"
	ScheddAdType     = "ScheddAd"
	MasterAdType     = "MasterAd"
	SubmitterAdType  = "SubmitterAd"
	LicenseAdType    = "LicenseAd"
	CollectorAdType  = "CollectorAd"
	NegotiatorAdType = "NegotiatorAd"
	AccountingAdType = "AccountingAd"
	StorageAdType    = "StorageAd"
	GridAdType       = "GridAd"
	HADAdType        = "HADAd"
	// StartdPrivateAdType is the startd's private ad (MyType
	// "MachinePrivate"), queried via QUERY_STARTD_PVT_ADS.
	StartdPrivateAdType = "StartdPrivateAd"
	// CkptServerAdType is the (legacy) checkpoint server ad. Standard
	// universe is gone, so this is rarely present, but the collector
	// query command still exists.
	CkptServerAdType = "CkptServerAd"
	// PlacementdAdType is the placementd's ad. Unlike the types above it is
	// the MyType the daemon publishes verbatim, because the collector stores
	// placementd ads as generic ads keyed by that name.
	PlacementdAdType = "PlacementD"
	// AnyAdType is a catch-all: it queries the collector for every ad type
	// (QUERY_ANY_ADS) rather than one specific kind.
	AnyAdType = "Any"
)

Ad type names accepted as the adType argument by the collector query methods (QueryAds, QueryAdsWithProjection, QueryAdsWithOptions, QueryAdsStream). Each names the ad a daemon advertises — a schedd advertises a ScheddAd, whose MyType is "Scheduler" — and selects the matching collector query. The daemon-type spellings (e.g. "Schedd") are also accepted, but prefer these constants.

They are plain string constants so they drop into the existing adType string parameters without a conversion.

View Source
const (
	// StoreCred is the main credential storage command (SCHED_VERS+79 = 479)
	// This is what store_cred_handler uses
	StoreCred       = 479   // SCHED_VERS+79
	CreddGetToken   = 81004 // CREDD_BASE+4
	CreddCheckCreds = 81030 // CREDD_BASE+30
)

Command codes for credd daemon (from condor_commands.h) HTCondor command codes

View Source
const (
	ModeMask           = 3
	GenericAdd         = 0
	GenericDelete      = 1
	GenericQuery       = 2
	StoreCredUserKrb   = 0x20
	StoreCredUserOAuth = 0x28
	StoreCredLegacy    = 0x40
	AddOAuthMode       = StoreCredUserOAuth | GenericAdd
	DeleteOAuthMode    = StoreCredUserOAuth | GenericDelete
	QueryOAuthMode     = StoreCredUserOAuth | GenericQuery
	AddKrbMode         = StoreCredUserKrb | GenericAdd
	DeleteKrbMode      = StoreCredUserKrb | GenericDelete
	QueryKrbMode       = StoreCredUserKrb | GenericQuery
)

Mode constants for StoreCred command (from store_cred.h)

View Source
const (
	Success            = 1
	Failure            = 0
	FailureBadPassword = 2
	FailureNotSecure   = 4
	FailureNotFound    = 5
	SuccessPending     = 6
	FailureNotAllowed  = 7
	FailureBadArgs     = 8
	FailureConfigError = 11
)

Return codes from store_cred operations (from store_cred.h)

View Source
const (
	// FailureNoImpersonate means user switching is not supported.
	FailureNoImpersonate = 3
	// FailureProtocolMismatch means client and server disagreed about
	// what should have been sent on the wire.
	FailureProtocolMismatch = 9
	// FailureCredmonTimeout means the credmon did not process the
	// credential within its timeout.
	FailureCredmonTimeout = 10
	// FailureJSONParse means the stored credential could not be parsed
	// as JSON. An OAuth service credential is a JSON document, and the
	// credd re-parses it when a query names a specific service -- so a
	// credential stored as something else is written without complaint
	// and then fails every read of it thereafter.
	FailureJSONParse = 12
	// FailureCredMismatch means a credential was found but did not match
	// the requested scopes or audience.
	FailureCredMismatch = 13
	// FailureUntrustedHost means the credential would require contacting
	// a host the credd does not trust.
	FailureUntrustedHost = 14
)

Return codes the credd sends back from a store or query, from HTCondor's store_cred.h. The ones this package already names (Success, FailureNotFound, ...) are declared in credd_client.go; these fill in the rest so an error can say what happened instead of quoting a number.

View Source
const (
	DCChildAlive = 60008 // DC_CHILDALIVE: child keepalive to parent
	DCSetReady   = 60043 // DC_SET_READY: daemon signals startup readiness
	DCQueryReady = 60044 // DC_QUERY_READY: master readiness query (reserved for future use)
)

DC command identifiers used by the master for daemon lifecycle signaling.

View Source
const (
	DCNopRead            = commands.DC_NOP_READ
	DCNopWrite           = commands.DC_NOP_WRITE
	DCNopNegotiator      = commands.DC_NOP_NEGOTIATOR
	DCNopAdministrator   = commands.DC_NOP_ADMINISTRATOR
	DCNopOwner           = commands.DC_NOP_OWNER
	DCNopConfig          = commands.DC_NOP_CONFIG
	DCNopDaemon          = commands.DC_NOP_DAEMON
	DCNopAdvertiseStartd = commands.DC_NOP_ADVERTISE_STARTD
	DCNopAdvertiseSchedd = commands.DC_NOP_ADVERTISE_SCHEDD
	DCNopAdvertiseMaster = commands.DC_NOP_ADVERTISE_MASTER
)

Permission levels for DC_SEC_QUERY authorization checking. These are sent as AuthCommand during the security handshake.

The values come from cedar's commands package rather than being written out here. They were previously hardcoded and every one from READ through ADMINISTRATOR was off by one — DC_NOP_OWNER (DC_BASE+24) was missing from the list, so DCNopRead asked the daemon about WRITE, DCNopWrite about NEGOTIATOR, and DCNopAdministrator about OWNER. The mistake was invisible because PingWithOptions never read the daemon's answer (see PingResult. Authorized), so nothing depended on asking the right question.

View Source
const (
	// PlacementUserLogin requests an IDToken for a foreign user identity.
	PlacementUserLogin = commands.SCHED_VERS + 155
	// PlacementQueryUsers lists the users the placementd knows about.
	PlacementQueryUsers = commands.SCHED_VERS + 156
	// PlacementQueryTokens lists the tokens the placementd has issued.
	PlacementQueryTokens = commands.SCHED_VERS + 157
	// PlacementQueryAuthorizations lists the authorizations the placementd
	// can grant, optionally narrowed to those a single user may request.
	PlacementQueryAuthorizations = commands.SCHED_VERS + 158
)

Command codes for the placement daemon (condor_placementd), from condor_commands.h. They are defined here rather than in cedar's commands package because the placementd is new enough that cedar has not enumerated them; the values are the stable wire numbers.

View Source
const (
	// PlacementErrNotEncrypted means the request arrived unencrypted. The
	// daemon refuses to mint a token over a channel that would expose it.
	PlacementErrNotEncrypted = 1
	// PlacementErrMissingUserName means the request carried no UserName.
	PlacementErrMissingUserName = 2
	// PlacementErrUserNotAuthorized means the user is absent from the
	// placementd's map file.
	PlacementErrUserNotAuthorized = 3
	// PlacementErrAuthorizationDenied means the user asked for an
	// authorization their map-file entry does not grant.
	PlacementErrAuthorizationDenied = 4
	// PlacementErrUserMappingExpired means the user's map-file entry has an
	// expiration in the past.
	PlacementErrUserMappingExpired = 6
	// PlacementErrRequesterUnknown means a login made on another user's
	// behalf named a requester absent from the map file.
	PlacementErrRequesterUnknown = 7
	// PlacementErrRequesterNotInstructor means the requester exists but
	// lacks the INSTRUCTOR authorization needed to act for someone else.
	PlacementErrRequesterNotInstructor = 8
	// PlacementErrRequesterMappingExpired means the requester's own
	// map-file entry has expired.
	PlacementErrRequesterMappingExpired = 9
	// PlacementErrProjectNotAuthorized means the user's map-file entry does
	// not list the requested project.
	PlacementErrProjectNotAuthorized = 10
	// PlacementErrDatabase means the placementd could not record the issued
	// token in its sqlite database. No token is returned in that case even
	// though one was minted.
	PlacementErrDatabase = 11
	// PlacementErrSchedd means the schedd leg of a login failed: the schedd
	// could not be located or queried, or the user or project record there
	// exists but is disabled.
	PlacementErrSchedd = 12
)

Error codes the placementd assigns to its own failures (placementd.cpp). The daemon also forwards CondorError codes from the schedd verbatim, so a code outside this set is a schedd-side error, not one of these.

View Source
const (
	AttrStartupLimitUUID           = "StartupLimitUUID"
	AttrStartupLimitTag            = "StartupLimitTag"
	AttrStartupLimitName           = "StartupLimitName"
	AttrStartupLimitExpr           = "StartupLimitExpression"
	AttrStartupLimitCostExpr       = "StartupLimitRateCost"
	AttrStartupLimitRateCount      = "StartupLimitRateCount"
	AttrStartupLimitRateWindow     = "StartupLimitRateWindow"
	AttrStartupLimitBurst          = "StartupLimitRateBurst"
	AttrStartupLimitMaxBurstCost   = "StartupLimitRateBurstMaxCost"
	AttrStartupLimitExpiration     = "StartupLimitExpiration"
	AttrStartupLimitStatus         = "StartupLimitStatus"
	AttrStartupLimitError          = "StartupLimitError"
	AttrStartupLimitJobsAllowed    = "StartupLimitJobsAllowed"
	AttrStartupLimitCostAllowed    = "StartupLimitCostAllowed"
	AttrStartupLimitJobsSkipped    = "StartupLimitJobsSkipped"
	AttrStartupLimitMatchesIgnored = "StartupLimitMatchesIgnored"
	AttrStartupLimitLastIgnored    = "StartupLimitLastIgnoredTime"
	AttrStartupLimitIgnoredUsers   = "StartupLimitIgnoredSources"
)

ClassAd attribute names for startup limits

View Source
const (
	CONDOR_NewCluster               = qmgmt.OpNewCluster
	CONDOR_NewProc                  = qmgmt.OpNewProc
	CONDOR_DestroyCluster           = qmgmt.OpDestroyCluster
	CONDOR_SetAttribute             = qmgmt.OpSetAttribute
	CONDOR_SetAttribute2            = qmgmt.OpSetAttribute2
	CONDOR_BeginTransaction         = qmgmt.OpBeginTransaction
	CONDOR_CommitTransactionNoFlags = qmgmt.OpCommitTransactionNoFlags
	CONDOR_CommitTransaction        = qmgmt.OpCommitTransaction
	CONDOR_AbortTransaction         = qmgmt.OpAbortTransaction
	CONDOR_SetEffectiveOwner        = qmgmt.OpSetEffectiveOwner
	CONDOR_GetCapabilities          = qmgmt.OpGetCapabilities
	CONDOR_CloseSocket              = qmgmt.OpCloseSocket
	QMGMT_WRITE_CMD                 = qmgmt.WriteCmd
)

QMGMT Protocol Commands. The canonical definitions now live in the qmgmt codec package (shared with the server); these names are kept for backward compatibility and match HTCondor's C++ naming convention.

View Source
const (
	UniverseMin       = 0
	UniverseStandard  = 1
	UniverseVanilla   = 5
	UniverseScheduler = 7
	UniverseGrid      = 9
	UniverseJava      = 10
	UniverseParallel  = 11
	UniverseLocal     = 12
	UniverseVM        = 13
)

Universe constants matching HTCondor

View Source
const DefaultCCBLearnedTTL = 15 * time.Minute

DefaultCCBLearnedTTL is how long a CCBDialer trusts what it learned about a broker. It is a compromise: long enough that a busy server is not re-measuring the same broker all day, short enough that a firewall change or a broker upgrade is picked up without a restart.

View Source
const DefaultCollectorRaceStagger = 150 * time.Millisecond

DefaultCollectorRaceStagger is the time between successive per-address connect attempts. 150 ms matches the inner v4/v6 happy-eyeballs cadence the user-facing dialer should be running.

View Source
const DefaultHistoryScanLimit = 10000

DefaultHistoryScanLimit is the ScanLimit a history query uses when the caller sets none: the daemon examines at most this many records, newest first, before it stops looking for matches.

View Source
const DefaultPeekMaxBytes = 64 * 1024

DefaultPeekMaxBytes is the per-call cap when the caller doesn't supply one. The C++ tool defaults to 1024 to be friendly on terminals; for a UI poll we want enough for a useful snapshot while still keeping each round-trip cheap.

View Source
const DefaultRescheduleInterval = 5 * time.Second

DefaultRescheduleInterval is the minimum wall-clock gap between successful Reschedule calls to the same schedd address.

Five seconds matches the typical NEGOTIATOR_INTERVAL operators configure for low-latency pools and stays well clear of the rate at which a busy submitter loop might fire-and-forget reschedule requests — sending one after every Submit in a tight loop should not amount to DoS pressure on the schedd.

View Source
const HarnessTrustDomain = "test.htcondor.org"

HarnessTrustDomain is the TRUST_DOMAIN the harness pins, and so the `iss` a daemon must mint tokens with to be trusted by this schedd. It is a fixed string rather than the hostname the default would produce, so a test can configure a daemon to match it without first asking the harness what its hostname resolved to.

Variables

View Source
var ErrCredentialNotFound = errors.New("credential not found")

ErrCredentialNotFound is returned when the requested credential does not exist.

View Source
var ErrInvalidTarEntry = errors.New("invalid tar entry name")

ErrInvalidTarEntry is returned (wrapped) by SpoolJobFilesFromTar when an entry's name is not a canonical path inside the sandbox. The upload is abandoned before that entry is sent and without the final command, so the schedd does not release the job.

View Source
var ErrNoJobsMatched = errors.New("no jobs matched")

ErrNoJobsMatched reports a job action whose constraint or IDs matched no job in the queue. Test for it with errors.Is; the error itself is a *JobActionRefusedError.

View Source
var ErrPaginationUnsupported = errors.New(
	"the schedd cannot paginate: its job queue is a hash table with no order to resume from " +
		"and no index to seek with, so each page would cost a full queue scan. " +
		"Raise the limit to read more at once, narrow the constraint, or query an htcondordb mirror")

ErrPaginationUnsupported is returned for a job query carrying a page token, because a schedd cannot be walked page by page.

Two independent reasons, either of which is enough:

There is no order to page by. QUERY_JOB_ADS walks the job queue's ClassAdLog, a HashTable, and LimitResults stops that walk early — so the jobs a page returns are an arbitrary subset of the matches, and a cursor taken from one either returns the same page forever or silently skips every job the page did not include. Imposing an order on this side means sorting every match, which is only possible by fetching every match.

And there is no index to make the next page cheap. filter_iterator (condor_utils/classad_log.h) runs that hash table from begin() to end() evaluating the constraint against every ad; matching jobs sit in whatever buckets they hash to, so no bound on ClusterId prunes anything. Every page costs a full queue walk, which means walking a queue in P pages costs the schedd P full walks where reading it once costs one. Pagination against a schedd is more load than the thing it exists to avoid.

Where pagination does work is an htcondordb mirror: it resumes from a storage cursor against a snapshot, with no scan and no reordering (see webapi/dbmirror). Callers with no mirror raise the limit, narrow the constraint, or use a server-side aggregate for counts.

Functions

func AddressFilePath added in v0.10.0

func AddressFilePath(cfg *config.Config, subsys string) string

AddressFilePath returns where subsys writes its address file: the <SUBSYS>_ADDRESS_FILE config value if set, otherwise $(LOG)/.<subsys>_address (the HTCondor default). It returns "" when neither is resolvable (no override and LOG unset). subsys is the upper-case subsystem name (e.g. "HTCONDORDB", "COLLECTOR").

A DaemonCore daemon writes its current contact address to this file as a single-line sinful string. That address is NOT stable: under shared port it carries a per-run socket token that changes every time condor_master restarts the daemon, so a client that caches the address once goes stale on restart. Pair this with FileAddressResolver so a reconnecting client re-reads the file and follows a restarted daemon automatically.

func DecodePageToken added in v0.0.4

func DecodePageToken(token string) (int64, int64, error)

DecodePageToken decodes a base64 page token to cluster and proc IDs Returns cluster ID, proc ID, and error if decoding fails

func DefaultCollectorProjection added in v0.0.4

func DefaultCollectorProjection() []string

DefaultCollectorProjection returns the default list of collector ad attributes

func DefaultEpochProjection added in v0.0.4

func DefaultEpochProjection() []string

DefaultEpochProjection returns the default list of attributes for job epoch history

func DefaultHistoryProjection added in v0.0.4

func DefaultHistoryProjection() []string

DefaultHistoryProjection returns the default list of attributes for job history

func DefaultJobProjection added in v0.0.4

func DefaultJobProjection() []string

DefaultJobProjection returns the default list of job attributes to include in query results

func DefaultTransferProjection added in v0.0.4

func DefaultTransferProjection() []string

DefaultTransferProjection returns the default list of attributes for transfer history

func DialSinful added in v0.2.0

func DialSinful(ctx context.Context, address string, secConfig *security.SecurityConfig, opts *DialOptions) (*client.HTCondorClient, error)

DialSinful establishes an authenticated connection to an HTCondor daemon named by a sinful string, transparently following the appropriate transport: direct TCP, a shared-port daemon, or — when the sinful carries a ccbid — the Condor Connection Broker.

CCB has two modes, and the default is wrong for a caller that cannot accept inbound connections. Standard mode has the private daemon dial back to the caller, so the caller must be reachable from it; streaming mode has the broker relay both directions over the request socket, so it need not be. A caller in a container or behind NAT wants opts.CCBRequireStreaming.

secConfig should be built with the existing helpers (e.g. GetSecurityConfig) for the intended command. The returned client's stream is ready for the command payload.

func EncodePageToken added in v0.0.4

func EncodePageToken(clusterID, procID int64) string

EncodePageToken encodes a cluster.proc identifier as a base64 page token

func FileAddressResolver added in v0.10.0

func FileAddressResolver(path string) func() (string, error)

FileAddressResolver returns a function that re-reads path (via ReadAddressFile) on every call. Give it to a client that reconnects -- e.g. a connection pool that re-dials on failure -- so each reconnect picks up the daemon's current address instead of a cached, possibly-restarted-away one. A transient read failure surfaces to the caller (which should back off and retry) rather than yielding a stale address.

func GetAuthenticatedUserFromContext added in v0.0.3

func GetAuthenticatedUserFromContext(ctx context.Context) string

GetAuthenticatedUserFromContext retrieves the authenticated username from the context Returns empty string if not found, which will be treated as "unauthenticated"

func GetCommandCodes

func GetCommandCodes() struct {
	Upload   int
	Download int
}

GetCommandCodes returns the CEDAR command codes for file transfer operations. These are defined in cedar/commands package.

func GetDefaultConfig added in v0.0.11

func GetDefaultConfig() *config.Config

GetDefaultConfig returns the global default HTCondor configuration, loading it from CONDOR_CONFIG on first access. Returns nil if no config is reachable (which happens in unit tests and any process that runs outside an HTCondor install).

Exposed so callers in other packages (notably httpserver) can build SecurityConfigs that respect SEC_CLIENT_AUTHENTICATION_METHODS, AUTH_SSL_CLIENT_CERTFILE, etc., without re-implementing the loader.

func GetSecurityConfig

func GetSecurityConfig(cfg *config.Config, command int, context string) (*security.SecurityConfig, error)

GetSecurityConfig creates a SecurityConfig from HTCondor configuration. It reads security-related parameters like SEC_CLIENT_AUTHENTICATION, SEC_DEFAULT_AUTHENTICATION, SEC_CLIENT_AUTHENTICATION_METHODS, etc., and maps them to the cedar SecurityConfig struct.

The function follows HTCondor's security configuration pattern:

  • SEC_<context>_<feature> where context is CLIENT, READ, WRITE, etc.
  • Each setting falls back along the context's chain to SEC_DEFAULT_*, as HTCondor's SecMan::getSecSetting: an ADVERTISE_* context takes SEC_DAEMON_* first (and DAEMON takes SEC_WRITE_* under LEGACY_ALLOW_SEMANTICS)
  • Supports REQUIRED, PREFERRED, OPTIONAL, NEVER security levels
  • Supports multiple authentication methods (SSL, KERBEROS, TOKEN, etc.)
  • Supports multiple encryption methods (AES, BLOWFISH, 3DES)

Parameters:

  • cfg: HTCondor configuration object
  • command: The command to be executed (from cedar/commands package)
  • context: Security context ("CLIENT", "READ", "WRITE", "ADMINISTRATOR", etc.)

Returns:

  • *security.SecurityConfig: Cedar security configuration
  • error: Any configuration error encountered

Deficiencies (to be addressed in follow-up):

  • Authorization settings (ALLOW_READ, DENY_WRITE, etc.) are separate from SecurityConfig
  • NEGOTIATION security level not yet mapped

func GetSecurityConfigFromContext

func GetSecurityConfigFromContext(ctx context.Context) (security.SecurityConfig, bool)

GetSecurityConfigFromContext retrieves the security configuration from the context

func GetSecurityConfigOrDefault added in v0.0.3

func GetSecurityConfigOrDefault(ctx context.Context, cfg *config.Config, command int, secContext string, peerName string) (*security.SecurityConfig, error)

GetSecurityConfigOrDefault retrieves SecurityConfig from context if available, otherwise attempts to load from HTCondor configuration, and falls back to defaults.

This function provides consistent SecurityConfig creation across the module:

  1. Check context for existing SecurityConfig
  2. If not in context, use provided config or fall back to global default config
  3. If config available, load from HTCondor configuration
  4. Fall back to sensible defaults if config is not available

Parameters:

  • ctx: Context that may contain SecurityConfig
  • cfg: HTCondor configuration (can be nil, will use global default if available)
  • command: The command code for the operation
  • context: Security context ("CLIENT", "READ", "WRITE", etc.)
  • peerName: Peer name for session cache (e.g., schedd address)

Returns:

  • *security.SecurityConfig: Cedar security configuration
  • error: Any configuration error encountered

func GetServerSecurityConfig added in v0.2.0

func GetServerSecurityConfig(cfg *config.Config, command int, secContext string) (*security.SecurityConfig, error)

GetServerSecurityConfig builds a *server-side* SecurityConfig from the HTCondor configuration. It takes the same auth/crypto methods and security levels as GetSecurityConfig (so the server enforces the pool's SEC_* policy), and additionally loads the credentials a server needs to *verify* incoming authentications rather than to present its own:

  • SSL: the server certificate/key/CA (AUTH_SSL_SERVER_CERTFILE / KEYFILE / CAFILE) instead of the client ones.
  • TOKEN/IDTOKENS: the signing keys used to validate presented tokens (SEC_TOKEN_POOL_SIGNING_KEY_FILE for the pool key, SEC_PASSWORD_DIRECTORY for named issuer keys), the trust domain (TRUST_DOMAIN, defaulting to UID_DOMAIN), and the maximum token age (SEC_TOKEN_MAX_AGE).

secContext is the authorization level whose SEC_<level>_* policy applies; each setting falls back as GetSecurityConfig describes, so an unset SEC_ADVERTISE_STARTD_AUTHENTICATION takes SEC_DAEMON_AUTHENTICATION before SEC_DEFAULT_AUTHENTICATION. A daemon negotiates each command under the policy of the level it is registered at with daemon.Daemon.InstallSecurityLevels.

UID_DOMAIN (set by GetSecurityConfig) is the domain of an FS peer's identity, user@UID_DOMAIN. A daemon behind a shared port should build its configs with daemon.Daemon.ServerSecurityConfig, which also sets the shared-port id.

This is what a Go HTCondor daemon (e.g. a CCB server) should use so it authenticates clients with the same policy and keys as the C++ daemons.

func IsDaemonFallbackRefused added in v0.20.0

func IsDaemonFallbackRefused(err error) bool

IsDaemonFallbackRefused reports whether err is a refusal of the daemon fallback.

Exported so a transport can answer with the status the refusal actually means. It is an authentication failure -- the caller presented nothing this server could use -- so it maps to 401, not to the 500 that a security-config error otherwise reads as.

func LoadSigningKeys added in v0.2.0

func LoadSigningKeys(cfg *config.Config) (map[string][]byte, error)

LoadSigningKeys reads the HTCondor pool signing keys from SEC_PASSWORD_DIRECTORY, returning a map of key name (e.g. "POOL") to its raw (unscrambled) key bytes. These keys are used as key-encryption keys for at-rest encryption of derived secrets (e.g. the persisted CCB session cache).

It returns (nil, nil) when SEC_PASSWORD_DIRECTORY is unset (no keys available). Unreadable individual key files are skipped (a key the daemon cannot read is not one it can use); a missing directory is reported as an error so a misconfiguration is visible.

SEC_PASSWORD_DIRECTORY and its key files are root-owned (0700/0600), so the directory listing and each file are read as root via droppriv — matching HTCondor's set_priv(PRIV_ROOT) — letting a daemon that has dropped to the condor account still load them (a no-op re-elevation when already root).

func LocalDaemonAddress added in v0.10.0

func LocalDaemonAddress(cfg *config.Config, subsys string) (func() (string, error), string, error)

LocalDaemonAddress resolves subsys's address for a peer using the standard knobs, and returns a resolver plus a one-line description of the source (for logging). On each call the resolver prefers the daemon's address file (AddressFilePath) when that file is present and readable -- so a co-located daemon is followed across restarts -- and otherwise falls back to the static <SUBSYS>_HOST knob (e.g. a daemon on another host with no local address file). It errors at construction only when neither a file path nor a host is configured; a per-call file-read error still falls back to <SUBSYS>_HOST if one is set, else surfaces so the caller can retry.

A caller with its own knob names (e.g. a collector using COLLECTOR_DB_HOST / COLLECTOR_DB_ADDRESS_FILE rather than the <SUBSYS>_* convention) should instead compose AddressFilePath / FileAddressResolver directly with its own precedence.

func LookupSSLClientCredentials added in v0.0.11

func LookupSSLClientCredentials() (certFile, keyFile, caFile string, ok bool)

LookupSSLClientCredentials reads the AUTH_SSL_CLIENT_CERTFILE, AUTH_SSL_CLIENT_KEYFILE, and AUTH_SSL_CLIENT_CAFILE settings from the global HTCondor configuration. Returns ok=true only when both cert and key paths are configured (CA may legitimately be empty when the system trust store is used).

Intended for callers that want to add SSL as a secondary auth method to a hand-built SecurityConfig without going through the full GetSecurityConfig path (which only loads SSL credentials when the configured AuthenticationMethods list already names SSL).

func LookupSSLClientCredentialsWithConfig added in v0.20.0

func LookupSSLClientCredentialsWithConfig(cfg *config.Config) (certFile, keyFile, caFile string, ok bool)

LookupSSLClientCredentialsWithConfig is LookupSSLClientCredentials reading cfg instead of the process-wide default configuration. A nil cfg is exactly LookupSSLClientCredentials.

func NewClientSecurityConfig added in v0.0.11

func NewClientSecurityConfig(
	ctx context.Context,
	token string,
	peerName string,
	command int,
	secContext string,
	sessionCache *security.SessionCache,
) (*security.SecurityConfig, error)

NewClientSecurityConfig builds a SecurityConfig for a client→daemon connection, starting from the configured SEC_<context>_AUTHENTICATION_METHODS (or SEC_DEFAULT_*) in the loaded HTCondor configuration and overlaying the supplied token, peer name, and session cache. This is the preferred constructor for any daemon-side path that needs to talk to another condor daemon — call sites that hand-build a SecurityConfig literal will lock themselves into a specific auth-method list and silently override what the operator configured.

Method-list construction:

  • Starts from the configured SEC_<context>_AUTHENTICATION_METHODS (falling back to SEC_DEFAULT_*, then to a sensible compiled-in fallback that includes SSL alongside TOKEN/FS). Read through loadClientSecurityDefaults when a token was supplied, and through GetSecurityConfigOrDefault -- which may instead return a credential the context already carries -- when none was.
  • When a non-empty token is supplied, guarantees TOKEN appears in the method list — prepended if absent — so the supplied token is actually offered to the peer, and drops every method that would identify this process instead (FS, KERBEROS, PASSWORD) or no one (ANONYMOUS). AuthIDTokens already counts as TOKEN at the wire level, so we don't duplicate.

Field overlays:

  • Token: set when token != "". TokenFile, TokenDir, CertFile and KeyFile are then cleared and Authentication is REQUIRED, so the token is the only credential the connection can present.
  • SessionCache: set when sessionCache != nil; otherwise cedar uses its global cache.
  • PeerName: populated from the argument, used for session-cache lookups and SSL hostname verification.

Other security parameters (CryptoMethods, Authentication/Encryption/ Integrity levels, SSL credentials when SSL is configured) come from GetSecurityConfig — same code path that condor_config_val sees.

command is the cedar/commands constant for the RPC the caller is about to dispatch. Used for session-cache lookups via LookupByCommand; stored on the resulting SecurityConfig.

secContext should be one of "CLIENT", "READ", "WRITE", "ADMINISTRATOR", "DAEMON", "NEGOTIATOR" — the same context strings HTCondor uses for SEC_<context>_* knob lookup. Empty defaults to "CLIENT".

func NewClientSecurityConfigWithConfig added in v0.20.0

func NewClientSecurityConfigWithConfig(
	ctx context.Context,
	cfg *config.Config,
	token string,
	peerName string,
	command int,
	secContext string,
	sessionCache *security.SessionCache,
) (*security.SecurityConfig, error)

NewClientSecurityConfigWithConfig is NewClientSecurityConfig reading the SEC_* settings from cfg instead of the process-wide default configuration. A nil cfg is exactly NewClientSecurityConfig. cfg decides only where the configuration comes from; which credential is presented is decided the same way for either.

func ParseAdvertiseCommand added in v0.0.4

func ParseAdvertiseCommand(cmd string) (commands.CommandType, bool)

ParseAdvertiseCommand parses an UPDATE command string to CommandType This is a shared utility used by both HTTP handlers and MCP handlers

func ParseJobID added in v0.0.11

func ParseJobID(s string) (int, int, error)

ParseJobID parses "cluster.proc" into a (cluster, proc) pair. Used by httpserver routes; lives here so it has a single owner.

func ReadAddressFile added in v0.10.0

func ReadAddressFile(path string) (string, error)

ReadAddressFile returns the first non-empty line of an HTCondor address file: a sinful string, possibly angle-bracket wrapped (cedar's addresses.ParseSinful accepts either form, and ConnectAndAuthenticate takes it as-is).

func ReloadDefaultConfig added in v0.0.3

func ReloadDefaultConfig()

ReloadDefaultConfig reloads the global default HTCondor configuration. This is useful when configuration files change and need to be re-read. If loading fails, the global config is set to nil.

func ResetRescheduleLimiter added in v0.1.0

func ResetRescheduleLimiter()

ResetRescheduleLimiter clears the per-process reschedule rate limiter state. Intended for tests; production callers shouldn't need it.

func SSHToJobHarnessConfig added in v0.14.3

func SSHToJobHarnessConfig() (string, bool)

SSHToJobHarnessConfig returns the extra condor_config lines a test harness needs so jobs in it accept condor_ssh_to_job, plus ok=false when this host cannot support it.

func SSHToJobPrereqs added in v0.14.3

func SSHToJobPrereqs() (sshd string, configTemplate string, ok bool)

SSHToJobPrereqs locates what condor_ssh_to_job needs on this host: the system sshd the starter spawns inside the sandbox, and the sshd_config template HTCondor hands it.

Both are found by searching, not by a fixed list of paths, because the fixed list is how an integration test quietly stops running. A developer whose HTCondor lives in a build tree (release_dir/lib/...) rather than in /usr/lib had every ssh-to-job test skip on their machine — which looks identical, in CI output and at a glance, to the tests passing.

Returns ok=false when either piece is missing, which is a genuine "this host cannot run condor_ssh_to_job" and a legitimate skip.

func SetUnmarkedOriginPolicy added in v0.20.0

func SetUnmarkedOriginPolicy(p UnmarkedOriginPolicy)

SetUnmarkedOriginPolicy sets the process-wide policy for unclassified contexts. The zero value, in force until something calls this, is UnmarkedAllow.

func SetUnmarkedOriginReporter added in v0.20.0

func SetUnmarkedOriginReporter(fn func(command int, secContext, peerName string))

SetUnmarkedOriginReporter installs the function UnmarkedWarn calls for each unclassified daemon fallback. Passing nil removes it.

A hook rather than a log call: this package deliberately does not depend on the logging package (a daemon hands its own logger in), and the caller that turns Warn on is the same one that knows where its logs go.

func SpoolInputAllowSet added in v0.17.0

func SpoolInputAllowSet(ad *classad.ClassAd) []string

SpoolInputAllowSet returns, sorted, the filenames the schedd will accept into this job's input spool. Any name outside the set is dropped in silence on its way through sendJobFilesFromTar, so a caller who uploads by that name gets a clean success and a job that runs without the file.

Exported for the share-URL mint path: the person redeeming an upload URL is often not the person who wrote the submit file, and has no other way to learn which names are expected before spending an upload on the wrong one.

The ad must carry jobInputSpoolProjection's attributes with the cluster ad overlaid, or the set comes back missing the executable -- see fetchProcAdForSpool.

func ValidateAttributeForEdit

func ValidateAttributeForEdit(attrName string, opts *EditJobOptions) error

ValidateAttributeForEdit checks if an attribute can be edited Returns an error if the attribute is immutable or protected (when not allowed)

func ValidateOAuthCredential added in v0.13.0

func ValidateOAuthCredential(service string, cred []byte) error

ValidateOAuthCredential reports whether a credential's bytes are storable as an OAuth service credential, and explains the problem when they are not.

An OAuth service credential has to be a JSON document. The credd will not tell you that at store time: it accepts whatever bytes it is given, and only parses them when a request carries scopes or an audience. It re-parses them, though, whenever a query names a specific service -- so storing a bare token string succeeds, and then get_credential_status fails ever after with FAILURE_JSON_PARSE while list_service_credentials, which never names a service, keeps reporting the credential as present.

Two read paths disagreeing about the same credential is a miserable thing to debug, and the evidence points away from the cause: the store said OK. So every path that stores one should refuse at the door instead.

Lives here, next to PutServiceCred, because it is a fact about the credd rather than about any particular API in front of it -- there is more than one, and they were not agreeing.

An empty credential is deliberately allowed, and is not the same thing as a malformed one. A credmon that mints tokens locally -- see the localcredmon module -- watches for the stored .top file and never reads its contents, so storing nothing is how you ask for a token rather than supply one. That is the normal path for OAuth services a server-side job transform added.

func WithAuthenticatedUser added in v0.0.3

func WithAuthenticatedUser(ctx context.Context, username string) context.Context

WithAuthenticatedUser creates a context that includes the authenticated username This is used for rate limiting purposes

func WithDaemonCredential added in v0.20.0

func WithDaemonCredential(ctx context.Context, reason string) context.Context

WithDaemonCredential marks ctx as this daemon's own work, which is what makes authenticating as this daemon legitimate.

It also detaches any caller credential, because the two always belong together: the reason a piece of plumbing is daemon work is that the peer is infrastructure with no reason to trust the caller's token, and offering it one anyway asks a third party to accept a credential meant for somebody else. Doing both here means a context derived from a request cannot be half-converted.

func WithRenewableSecurityConfig added in v0.20.0

func WithRenewableSecurityConfig(ctx context.Context, secConfig *security.SecurityConfig, renew SecurityConfigRenewer) context.Context

WithRenewableSecurityConfig is WithSecurityConfig for a credential minted for the caller: when the token secConfig carries is about to expire, GetSecurityConfigOrDefault replaces it with what renew returns. renew may refuse -- the grant behind the credential has ended -- and the connection then fails rather than presenting the expired token.

func WithSecurityConfig

func WithSecurityConfig(ctx context.Context, secConfig *security.SecurityConfig) context.Context

WithSecurityConfig creates a context that includes security configuration This allows passing authentication information (like tokens) from HTTP handlers to Schedd methods

func WithUserRequest added in v0.20.0

func WithUserRequest(ctx context.Context, reason string) context.Context

WithUserRequest marks ctx as acting for somebody other than this daemon, so that reaching the daemon fallback under it is an error rather than a silent promotion.

Mark at the transport, not at the authentication branch. The branches are precisely the code that forgets: one returns the context unchanged when it has no signing key, another hands back a context whose credential could not be minted, a third is a route that nobody wrapped in the gate. Marking where the request enters the process means a route added tomorrow inherits it, and a branch that fails to attach a credential produces a context that is refused instead of one that authenticates as a superuser.

reason names the surface, and is carried into the refusal message: an operator reading the log line needs to know which door the context came in through, because the fix is at that door.

func WithoutSecurityConfig added in v0.14.0

func WithoutSecurityConfig(ctx context.Context) context.Context

WithoutSecurityConfig returns ctx with any caller credential detached, so the connection built from it authenticates as this daemon rather than as whoever made the request.

A request context carries the caller's own SecurityConfig, and GetSecurityConfigOrDefault prefers it over the daemon's configuration. That is right for anything done *on behalf of* the caller. It is wrong for the plumbing underneath: a connection to a broker, a relay, or any other piece of infrastructure is this daemon talking, and offering the caller's credential there asks a third party to trust a token it has no reason to recognise.

Cancellation and deadlines are preserved -- only the credential is dropped.

Detaching the credential is also a statement about who the connection is, so this classifies the context as daemon work (see CredentialOrigin). Without that, a plumbing context derived from a request would keep the request's own classification and be refused for having no credential -- which is the correct treatment of an accident and the wrong treatment of this, where the daemon's credential is the one the peer recognises.

Types

type ActionResult

type ActionResult int

ActionResult represents the result of an action on a single job

const (
	AR_ERROR             ActionResult = iota // 0: Error occurred (no longer generated by the schedd as of 2025)
	AR_SUCCESS                               // 1: Action succeeded
	AR_NOT_FOUND                             // 2: Job not found
	AR_BAD_STATUS                            // 3: Job in wrong status for action
	AR_ALREADY_DONE                          // 4: Action already performed
	AR_PERMISSION_DENIED                     // 5: Permission denied
	AR_LIMIT_EXCEEDED                        // 6: Per-user job/action limit exceeded
)

Action result constants.

These index the result ad's per-result attributes (result_total_<N> for AR_TOTALS, job_<c>_<p>/cluster_<c> = <N> for AR_LONG). MUST match the C++ action_result_t enum (src/condor_daemon_client/dc_schedd.h:52-60).

type ActionResultType

type ActionResultType int

ActionResultType specifies what kind of result information to return

const (
	AR_NONE   ActionResultType = iota // 0: don't care / don't yet know
	AR_LONG                           // 1: Return detailed per-job results
	AR_TOTALS                         // 2: Return only totals (default)
)

Action result type constants.

Placed on the wire as ATTR_ACTION_RESULT_TYPE. MUST match the C++ action_result_type_t enum (src/condor_daemon_client/dc_schedd.h:63-67):

AR_NONE = 0  // don't care / don't yet know
AR_LONG = 1  // want info per job (job_<c>_<p> / cluster_<c> = result)
AR_TOTALS = 2 // want totals for each possible result (result_total_<N>)

The schedd only special-cases AR_LONG; anything else is treated as AR_TOTALS (src/condor_schedd.V6/schedd.cpp:7571-7574). The earlier Go values had AR_TOTALS=0, which happened to work but did not match the C++ enum.

type AdResult added in v0.0.4

type AdResult struct {
	Ad  *classad.ClassAd
	Err error
}

AdResult represents a single ad or error from a streaming query

type AdvertiseError added in v0.14.1

type AdvertiseError struct {
	// Succeeded lists the collectors that took the ad, sorted.
	Succeeded []string
	// Failed maps a collector address to why it did not.
	Failed map[string]error
}

AdvertiseError reports an advertisement that did not reach every configured collector.

It is returned whenever at least one collector failed, including when others succeeded -- partial success is a real outcome and the caller should be able to see it rather than have it collapsed into "ok" or "failed". Use AllFailed to tell "the ad is nowhere" from "the ad is in some collectors but not all", which is the distinction that decides whether a daemon is invisible or merely under-advertised.

func (*AdvertiseError) AllFailed added in v0.14.1

func (e *AdvertiseError) AllFailed() bool

AllFailed reports whether no collector took the ad.

func (*AdvertiseError) Error added in v0.14.1

func (e *AdvertiseError) Error() string

func (*AdvertiseError) Unwrap added in v0.14.1

func (e *AdvertiseError) Unwrap() []error

Unwrap exposes the per-collector errors to errors.Is and errors.As.

type AdvertiseOptions added in v0.0.4

type AdvertiseOptions struct {
	// Command specifies the UPDATE command to use (e.g., UPDATE_SCHEDD_AD).
	//
	// The zero value means "derive the command from the ad's MyType"
	// (getCommandForAdvertise), which is the intended default and yields the
	// correct command for every standard ad type. NOTE: because UPDATE_STARTD_AD
	// is itself 0, an explicit Command: UPDATE_STARTD_AD is indistinguishable from
	// the unset zero value and is also derived from MyType -- identical for a
	// Machine/StartD ad, so this matters only for the nonsensical case of forcing a
	// startd update on an ad whose MyType is absent or non-startd (which would
	// instead derive UPDATE_AD_GENERIC). To force any other command, set it here
	// (all other UPDATE_* commands are non-zero and are honored exactly).
	Command commands.CommandType
	// WithAck requests acknowledgment from the collector (forces TCP)
	WithAck bool
	// UseTCP forces TCP connection (default: true)
	UseTCP bool
	// PrivateAd is an optional companion "private" ad sent immediately after the
	// public ad on the SAME CEDAR message (public ad, then private ad, then a
	// single end_of_message), mirroring the C++ startd's UPDATE_STARTD_AD wire
	// (dc_collector.cpp): putClassAd(public) then putClassAd(private).
	//
	// This carries the STARTD_PVT ad -- the private half of the public+private
	// Machine ad pair the negotiator requires, holding the slot's ClaimId. The
	// collector matches the private ad to its public ad by Name and MyAddress,
	// so a private ad should carry those; Advertise copies "MyAddress" from the
	// public ad into the private ad if the public ad has it and the private ad
	// does not, matching dc_collector.cpp.
	//
	// The private ad is serialized WITH private (secret) attributes included
	// (PutClassAdIncludePrivate) so its ClaimId survives the trip; the public ad
	// is serialized normally, which redacts any secret attributes.
	//
	// Optional: a nil PrivateAd sends only the public ad (a missing private ad is
	// tolerated by the collector). Only honored by Advertise; AdvertiseMultiple
	// returns an error if PrivateAd is set (see AdvertiseMultiple).
	PrivateAd *classad.ClassAd
}

AdvertiseOptions configures advertisement behavior

type AggregateRow added in v0.13.0

type AggregateRow struct {
	// Group holds the group-by attribute values, in the order the
	// attributes were requested. Empty for an ungrouped total.
	Group []string
	// Count is the number of jobs in the group.
	Count int64
}

AggregateRow is one group returned by an aggregate query: the values of the group-by attributes, and how many jobs fell into that group.

type CCBDialer added in v0.18.0

type CCBDialer struct {
	// contains filtered or unexported fields
}

CCBDialer reaches daemons behind a Condor Connection Broker, choosing between connection reversal and broker relaying, and remembering what worked.

The choice cannot be made ahead of time. Which broker a dial goes through is decided by the execute node, in the sinful it advertised, so this process does not know until it holds the address -- and even then the two things that determine the answer are not things it can ask about. Whether the execute node can reach us is a fact about the network between two hosts that are not this one; whether the broker can relay is a fact about a version we only see once we have authenticated to it. So both are learned by trying, and the result is cached per broker so a server that has learned the answer does not pay for it on every exec.

The zero value is not usable; call NewCCBDialer. A nil *CCBDialer is valid and dials exactly as DialSinful does with no CCB options -- the behavior of a caller that never configured any of this.

func NewCCBDialer added in v0.18.0

func NewCCBDialer(cfg CCBDialerConfig) *CCBDialer

NewCCBDialer builds a CCBDialer from cfg.

func (*CCBDialer) Dial added in v0.18.0

func (d *CCBDialer) Dial(ctx context.Context, address string, secConfig *security.SecurityConfig, opts *DialOptions) (*client.HTCondorClient, error)

Dial establishes an authenticated connection to address, choosing how to traverse CCB if the address needs it. Non-CCB addresses are dialed unchanged.

opts supplies everything but the CCB mode (notably Timeout); the CCB fields on it are ignored, since choosing them is this method's job.

func (*CCBDialer) HasRouter added in v0.18.0

func (d *CCBDialer) HasRouter() bool

HasRouter reports whether an inbound path is configured, for callers that log or report their configuration.

func (*CCBDialer) Streaming added in v0.18.0

func (d *CCBDialer) Streaming() bool

Streaming reports whether broker relaying is permitted.

type CCBDialerConfig added in v0.18.0

type CCBDialerConfig struct {
	// Router, when set, gives this process an inbound path, which makes
	// connection reversal possible and is preferred over streaming: it works
	// with every broker version, while streaming does not, and the broker for
	// a given dial is chosen by the execute node.
	Router CCBReverseRouter

	// Streaming permits the broker-relayed mode. With no Router it is the only
	// thing that works from a host the execute nodes cannot reach; with one it
	// is the fallback for when they turn out not to reach us anyway.
	Streaming bool

	// LearnedTTL bounds how long what we learned about a broker is trusted
	// (default DefaultCCBLearnedTTL).
	LearnedTTL time.Duration

	// PrivateNetworkName is this client's PRIVATE_NETWORK_NAME. When it
	// equals a target's PrivNet, the target is dialed directly instead of
	// through its broker. Empty disables the behaviour entirely.
	PrivateNetworkName string

	// Logger receives one line per mode change. Defaults to slog.Default().
	Logger *slog.Logger
}

CCBDialerConfig configures a CCBDialer.

type CCBReverseRouter added in v0.18.0

type CCBReverseRouter interface {
	// Register claims one inbound path. The caller closes the listener when
	// the dial is done, which releases the registration.
	Register() (net.Listener, string, error)
}

CCBReverseRouter hands out inbound paths for CCB connection reversal: a listener the execute node's connection back to us will arrive on, and the HTCondor sinful to advertise as the address it should dial.

The implementation is an in-process shared-port router (see webapi/sharedportrouter), which multiplexes any number of concurrent reversals over one inbound TCP port. It is an interface here so the core library does not require one, and so tests can supply a trivial one.

type CallerCredential added in v0.20.0

type CallerCredential struct {
	// contains filtered or unexported fields
}

CallerCredential is a caller's credential detached from the request that carried it, for work that outlives the request.

func CallerCredentialFromContext added in v0.20.0

func CallerCredentialFromContext(ctx context.Context) (CallerCredential, bool)

CallerCredentialFromContext copies the caller's credential off ctx, with the renewer that was attached alongside it, if any. The copy is the holder's own: nothing the request does afterwards changes it.

func (CallerCredential) Attach added in v0.20.0

Attach returns ctx carrying the credential, renewable as it was on the request it came from.

func (CallerCredential) Renew added in v0.20.0

Renew mints the credential again now, whatever its token's expiry.

func (CallerCredential) Renewable added in v0.20.0

func (c CallerCredential) Renewable() bool

Renewable reports whether the credential can be re-minted. One that cannot -- a token the caller presented themselves -- lasts exactly as long as that token.

func (CallerCredential) Token added in v0.20.0

func (c CallerCredential) Token() string

Token is the token the credential presents.

type CedarCredd added in v0.0.6

type CedarCredd struct {
	// contains filtered or unexported fields
}

CedarCredd provides a CEDAR-based credd client implementation

func NewCedarCredd added in v0.0.6

func NewCedarCredd(address string) *CedarCredd

NewCedarCredd creates a new CEDAR-based credd client

func (*CedarCredd) CheckCreds added in v0.20.0

func (c *CedarCredd) CheckCreds(ctx context.Context, requests []CredRequest) (string, error)

CheckCreds implements CREDD_CHECK_CREDS, the request condor_submit makes before submitting (do_check_oauth_creds in store_cred.cpp): a count, one ad per requested service, then a single string in reply.

The credd may hold the reply while a local credmon writes a token it has just asked for, up to about 20 seconds, so ctx should allow for that.

func (*CedarCredd) DeleteServiceCred added in v0.0.6

func (c *CedarCredd) DeleteServiceCred(ctx context.Context, credType CredType, service string, handle string, user string) error

DeleteServiceCred removes a service credential

func (*CedarCredd) DeleteUserCred added in v0.0.6

func (c *CedarCredd) DeleteUserCred(ctx context.Context, credType CredType, user string) error

DeleteUserCred removes a user credential

func (*CedarCredd) GetCredential added in v0.0.6

func (c *CedarCredd) GetCredential(ctx context.Context, credType CredType, service string, handle string, user string) ([]byte, error)

GetCredential returns the stored credential payload

func (*CedarCredd) GetServiceCredStatus added in v0.0.6

func (c *CedarCredd) GetServiceCredStatus(ctx context.Context, credType CredType, service string, handle string, user string) (CredentialStatus, error)

GetServiceCredStatus reports status for a stored service credential.

It asks the credd for every credential file the user holds rather than naming the service. A query that names a service makes the credd re-read the service's .top file as JSON to compare scopes, and a local credmon's .top is not JSON -- it holds only the user's name -- so naming the service fails with FAILURE_JSON_PARSE on a credential that works. The listing reads no file contents.

A service with no files at all is reported as ErrCredentialNotFound.

func (*CedarCredd) GetUserCredStatus added in v0.0.6

func (c *CedarCredd) GetUserCredStatus(ctx context.Context, credType CredType, user string) (CredentialStatus, error)

GetUserCredStatus reports credential status

func (*CedarCredd) ListServiceCreds added in v0.0.6

func (c *CedarCredd) ListServiceCreds(ctx context.Context, credType CredType, user string) ([]ServiceStatus, error)

ListServiceCreds returns all service credentials for the user. A user with none gets an empty list: the credd answers that query with "not found", which is an answer, not a failure.

func (*CedarCredd) PutServiceCred added in v0.0.6

func (c *CedarCredd) PutServiceCred(ctx context.Context, credType CredType, credential []byte, service string, handle string, user string, refresh *bool) error

PutServiceCred stores an OAuth service credential

func (*CedarCredd) PutUserCred added in v0.0.6

func (c *CedarCredd) PutUserCred(ctx context.Context, credType CredType, credential []byte, user string) error

PutUserCred stores a user credential (Kerberos)

func (*CedarCredd) WithConfig added in v0.20.0

func (c *CedarCredd) WithConfig(cfg *config.Config) *CedarCredd

WithConfig sets the HTCondor configuration this credd client uses; see the note above.

type CheckCredsRefusal added in v0.20.0

type CheckCredsRefusal struct {
	Reason string
}

CheckCredsRefusal is the credd answering CREDD_CHECK_CREDS with a reason it cannot supply the credentials, as distinct from failing to reach it. Asking again gets the same answer until something on the access point changes.

func (*CheckCredsRefusal) Error added in v0.20.0

func (e *CheckCredsRefusal) Error() string

type Collector

type Collector struct {
	// contains filtered or unexported fields
}

Collector represents an HTCondor collector daemon.

The configured address may be a single host:port / sinful string or a comma-separated list ("host1,host2" or "host1:9618,host2:9618") matching the HTCondor COLLECTOR_HOST convention. With a list, every operation races against the entries with a small stagger so a stalled primary collector falls over to the secondary quickly. See collector_race.go for the protocol; `raceStagger == 0` (the default) means DefaultCollectorRaceStagger.

Address ordering inside a list follows two principles, matching the C++ HTCondor client:

  1. At construction, the address list is shuffled. A fleet of identically-configured clients would otherwise pile onto the same primary collector; shuffling spreads load.
  2. After a successful dial, the winning address becomes "sticky" and is moved to position 0 for subsequent dials. Sustained traffic from one client therefore lands on a single collector until that collector fails, at which point the race naturally promotes whichever address won the failover.

func NewCollector

func NewCollector(address string) *Collector

NewCollector creates a new Collector instance. address may be a single hostname, host:port (or sinful string), or a comma-separated list:

NewCollector("cm-1.ospool.osg-htc.org,cm-2.ospool.osg-htc.org")

Entries without a port number are given the default HTCondor collector port (9618). With a list, attempts are raced with a 150 ms stagger and the first that returns an authenticated CEDAR stream wins. The list is shuffled at construction; see the Collector type comment for the ordering policy.

func (*Collector) Address added in v0.0.11

func (c *Collector) Address() string

Address returns the address the collector is configured against. Useful for logging and diagnostics; never returns the empty string for a Collector constructed via NewCollector. For a comma-separated list, returns the raw list string the caller passed in.

func (*Collector) Addresses added in v0.1.0

func (c *Collector) Addresses() []string

Addresses returns the parsed list of collector addresses in the Collector's current dial-order: the last-successful address (if any) first, then the post-shuffle remainder. For a single- collector setup this returns a one-element slice. Never returns nil for a Collector built via NewCollector with a non-empty address.

The returned slice is a defensive copy; mutating it has no effect on the Collector.

func (*Collector) Advertise

func (c *Collector) Advertise(ctx context.Context, ad *classad.ClassAd, opts *AdvertiseOptions) error

Advertise sends an advertisement to the collector The command type is determined from the ad's MyType attribute if not specified in opts Returns error if advertisement fails

func (*Collector) AdvertiseMultiple added in v0.0.4

func (c *Collector) AdvertiseMultiple(ctx context.Context, ads []*classad.ClassAd, opts *AdvertiseOptions) []error

AdvertiseMultiple sends many advertisements over as few connections as possible using HTCondor's persistent command-socket protocol: one authenticated connection carries a run of updates, the first riding the connection's negotiated command and each follow-on prefixed with its own command integer. Matching the C++ condor_collector (and DaemonCore), the command integer and the ad are two separate CEDAR messages -- [cmd + EOM] then [ad + EOM] -- which is exactly how a C++ daemon streams a schedd ad plus submitter ads down one stashed socket.

This amortizes the per-ad TCP connect + authenticate cost that otherwise dominates advertising (a fresh connection per ad). On a send error the connection is torn down and re-established, and the remaining ads continue on the new one. Returns one error per ad (nil entries where the ad succeeded), or nil if the batch was empty.

func (*Collector) LocateDaemon

func (c *Collector) LocateDaemon(ctx context.Context, daemonType DaemonType, name string) (*DaemonLocation, error)

LocateDaemon locates a daemon by querying the collector.

daemonType is the kind of daemon to locate — one of the DaemonType constants (DaemonSchedd, DaemonStartd, DaemonMaster, DaemonCollector, DaemonNegotiator). It is translated to the corresponding collector-query ad type internally, so callers pass a daemon type (DaemonSchedd), not an ad type ("ScheddAd").

name is the name of the daemon to locate (optional, pass empty string to find any).

func (*Collector) Ping added in v0.0.4

func (c *Collector) Ping(ctx context.Context) (*PingResult, error)

Ping performs a ping operation against the collector daemon This is similar to condor_ping and provides information about authentication and authorization. It's useful for health checks and debugging security settings.

func (*Collector) PingWithOptions added in v0.0.4

func (c *Collector) PingWithOptions(ctx context.Context, opts *PingOptions) (*PingResult, error)

PingWithOptions performs a ping operation with optional permission checking

func (*Collector) QueryAds deprecated

func (c *Collector) QueryAds(ctx context.Context, adType string, constraint string) ([]*classad.ClassAd, error)

QueryAds queries the collector for daemon advertisements adType selects the ad type to query — one of the *AdType constants (e.g. ScheddAdType), or a daemon-type name like "Schedd" constraint is a ClassAd constraint expression string (pass empty string for no constraint)

Deprecated: Use QueryAdsWithOptions for pagination and default limits/projections

func (*Collector) QueryAdsStream added in v0.0.4

func (c *Collector) QueryAdsStream(ctx context.Context, adType string, constraint string, projection []string, limit int, streamOpts *StreamOptions) (<-chan AdResult, error)

QueryAdsStream queries the collector and streams results through a channel Returns a channel and an error. If the error is non-nil, it indicates a problem before the request was sent (e.g., invalid parameters, connection failure). The channel will be closed when all ads have been sent or an error occurs during streaming. If cumulative time blocking on channel writes exceeds StreamOptions.WriteTimeout, an error is sent through the channel. The limit parameter controls the maximum number of ads to return (-1 for unlimited).

func (*Collector) QueryAdsWithOptions added in v0.0.4

func (c *Collector) QueryAdsWithOptions(ctx context.Context, adType string, constraint string, opts *QueryOptions) ([]*classad.ClassAd, *PageInfo, error)

QueryAdsWithOptions queries the collector for daemon advertisements with pagination and limits opts specifies query options including limit, projection, and pagination Returns the matching ads and pagination info

func (*Collector) QueryAdsWithProjection deprecated added in v0.0.3

func (c *Collector) QueryAdsWithProjection(ctx context.Context, adType string, constraint string, projection []string) ([]*classad.ClassAd, error)

QueryAdsWithProjection queries the collector for daemon advertisements with optional projection adType selects the ad type to query — one of the *AdType constants (e.g. ScheddAdType), or a daemon-type name like "Schedd" constraint is a ClassAd constraint expression string (pass empty string for no constraint) projection is an optional list of attribute names to return (pass nil for all attributes)

Deprecated: Use QueryAdsWithOptions for pagination and default limits/projections

func (*Collector) WatchAds added in v0.5.0

func (c *Collector) WatchAds(ctx context.Context, adType, constraint string, cursor []byte) (<-chan WatchEvent, error)

WatchAds subscribes to changes for adType (e.g. "StartdAd", "Machine", "ScheddAd") at the collector and returns a channel of events. constraint, if non-empty, is a ClassAd match expression (e.g. `DAGManJobId == 42`) so only events for matching ads are delivered -- an ad that stops matching arrives as a Delete. Pass a nil cursor for a full replay, or a cursor from a prior Synced/live event to resume incrementally.

The channel is closed when ctx is cancelled or the stream ends (the server went away or the connection dropped); a GoingAway event, if delivered, arrives just before the close. The caller should range over the channel and, on GoingAway/Resync or an unexpected close, reconnect with its last cursor. The underlying connection is closed automatically when the stream ends.

func (*Collector) WithConfig added in v0.20.0

func (c *Collector) WithConfig(cfg *config.Config) *Collector

WithConfig sets the HTCondor configuration this Collector uses; see the note above.

func (*Collector) WithRaceStagger added in v0.1.0

func (c *Collector) WithRaceStagger(stagger time.Duration) *Collector

WithRaceStagger returns a Collector with the inter-attempt delay overridden. Setting stagger == 0 disables the stagger (every address attempts in parallel from t=0). Negative values are clamped to the default.

This is a fluent-style modifier so it composes with NewCollector:

c := htcondor.NewCollector(addrs).WithRaceStagger(200 * time.Millisecond)

type CondorTestHarness added in v0.0.4

type CondorTestHarness struct {
	// contains filtered or unexported fields
}

CondorTestHarness manages a mini HTCondor instance for integration testing

func SetupCondorHarness added in v0.0.4

func SetupCondorHarness(t TestingT) *CondorTestHarness

SetupCondorHarness creates and starts a mini HTCondor instance

func SetupCondorHarnessWithConfig added in v0.0.4

func SetupCondorHarnessWithConfig(t TestingT, extraConfig string) *CondorTestHarness

SetupCondorHarnessWithConfig is like SetupCondorHarness but appends extra configuration to the generated condor_config. This allows tests to register custom daemons or tweak logging without duplicating harness logic.

func (*CondorTestHarness) GetCollectorAddr added in v0.0.4

func (h *CondorTestHarness) GetCollectorAddr() string

GetCollectorAddr returns the collector address

func (*CondorTestHarness) GetConfig added in v0.0.4

func (h *CondorTestHarness) GetConfig() (*config.Config, error)

GetConfig returns a Config instance configured for this harness

func (*CondorTestHarness) GetConfigFile added in v0.0.11

func (h *CondorTestHarness) GetConfigFile() string

GetConfigFile returns the path of the on-disk condor_config file the harness wrote. Tests that spawn extra processes pointed at the same HTCondor instance need this so they can set CONDOR_CONFIG.

func (*CondorTestHarness) GetLockDir added in v0.0.11

func (h *CondorTestHarness) GetLockDir() string

GetLockDir returns the lock directory path for this harness — useful for tests that read the shared_port_ad file the shared_port daemon drops there to discover its dynamically-assigned port.

func (*CondorTestHarness) GetLogDir added in v0.0.4

func (h *CondorTestHarness) GetLogDir() string

GetLogDir returns the log directory path for this harness

func (*CondorTestHarness) GetPasswordDir added in v0.13.0

func (h *CondorTestHarness) GetPasswordDir() string

GetPasswordDir returns the SEC_PASSWORD_DIRECTORY this harness pins, which is where its daemons look for token signing keys.

func (*CondorTestHarness) GetScheddName added in v0.0.4

func (h *CondorTestHarness) GetScheddName() string

GetScheddName returns the schedd name for this harness

func (*CondorTestHarness) GetSigningKeyPath added in v0.13.0

func (h *CondorTestHarness) GetSigningKeyPath() string

GetSigningKeyPath returns the POOL signing key this harness created. Pass it as a daemon's SIGNING_KEY_PATH: a token signed with it and issued for GetTrustDomain is one this harness's schedd will accept, so the daemon authenticates as the token's subject rather than falling through to FS and being recorded as its own OS user.

func (*CondorTestHarness) GetSpoolDir added in v0.0.4

func (h *CondorTestHarness) GetSpoolDir() string

GetSpoolDir returns the spool directory path for this harness

func (*CondorTestHarness) GetTrustDomain added in v0.13.0

func (h *CondorTestHarness) GetTrustDomain() string

GetTrustDomain returns the trust domain this harness's daemons accept tokens from. Pass it as a daemon's TRUST_DOMAIN.

func (*CondorTestHarness) PrintCollectorLog added in v0.18.0

func (h *CondorTestHarness) PrintCollectorLog()

PrintCollectorLog prints the collector log contents for debugging. The collector also hosts the pool's built-in CCB server, so this is where a failed connection reversal explains itself.

func (*CondorTestHarness) PrintScheddLog added in v0.0.4

func (h *CondorTestHarness) PrintScheddLog()

PrintScheddLog prints the schedd log contents for debugging

func (*CondorTestHarness) PrintShadowLog added in v0.0.7

func (h *CondorTestHarness) PrintShadowLog()

PrintShadowLog is the exported version for test access

func (*CondorTestHarness) PrintStartdLog added in v0.18.0

func (h *CondorTestHarness) PrintStartdLog()

PrintStartdLog prints the startd log contents for debugging.

func (*CondorTestHarness) PrintStarterLogs added in v0.0.7

func (h *CondorTestHarness) PrintStarterLogs()

PrintStarterLogs is the exported version for test access

func (*CondorTestHarness) Shutdown added in v0.0.4

func (h *CondorTestHarness) Shutdown()

Shutdown stops the HTCondor instance

func (*CondorTestHarness) WaitForDaemons added in v0.0.4

func (h *CondorTestHarness) WaitForDaemons() error

WaitForDaemons waits for the HTCondor daemons to start and become responsive

func (*CondorTestHarness) WaitForSchedd added in v0.12.8

func (h *CondorTestHarness) WaitForSchedd(timeout time.Duration) error

WaitForSchedd waits for the schedd to advertise to the collector, which is what makes it locatable by the tests. Separate from the address file the schedd writes: a test reaches the schedd through the collector, so the ad is the readiness signal that matters.

func (*CondorTestHarness) WaitForStartd added in v0.0.4

func (h *CondorTestHarness) WaitForStartd(timeout time.Duration) error

WaitForStartd waits for the startd daemon to advertise to the collector. This is useful because the startd may take longer to start up and advertise than the collector and schedd, especially on slower systems.

type CredRequest added in v0.20.0

type CredRequest struct {
	Service  string
	Handle   string
	Scopes   string
	Audience string
}

CredRequest names one OAuth service credential a job needs, as sent to CheckCreds.

type CredType added in v0.0.6

type CredType string

CredType enumerates the credential types supported by the credd. Mirrors the Python bindings CredType enum (Kerberos, OAuth).

const (
	// CredTypeKerberos stores Kerberos credentials.
	CredTypeKerberos CredType = "Kerberos"
	// CredTypeOAuth stores OAuth2 credentials.
	CredTypeOAuth CredType = "OAuth"
)

type CreddClient added in v0.0.6

type CreddClient interface {
	PutUserCred(ctx context.Context, credType CredType, credential []byte, user string) error
	DeleteUserCred(ctx context.Context, credType CredType, user string) error
	GetUserCredStatus(ctx context.Context, credType CredType, user string) (CredentialStatus, error)

	PutServiceCred(ctx context.Context, credType CredType, credential []byte, service string, handle string, user string, refresh *bool) error
	DeleteServiceCred(ctx context.Context, credType CredType, service string, handle string, user string) error
	GetServiceCredStatus(ctx context.Context, credType CredType, service string, handle string, user string) (CredentialStatus, error)
	ListServiceCreds(ctx context.Context, credType CredType, user string) ([]ServiceStatus, error)

	GetCredential(ctx context.Context, credType CredType, service string, handle string, user string) ([]byte, error)

	// CheckCreds makes the request condor_submit makes before it submits a
	// job: it asks the credd to make sure the caller holds every OAuth
	// credential in requests, and the credd adds the services its own
	// local credmons provide (SUBMIT_ADD_LOCAL_CREDMON_PROVIDERS, on by
	// default). For a local credmon's service a missing credential is
	// created on the spot, which is how an access point that requires one
	// on every job gets it -- so an empty request list is meaningful.
	//
	// It returns "" when everything is in place, or a URL the user must
	// visit to grant a credential the credd cannot create itself.
	CheckCreds(ctx context.Context, requests []CredRequest) (string, error)
}

CreddClient defines the operations exposed by the credd (credential daemon). The methods mirror the Python bindings htcondor2.Credd API but omit Windows password support.

type CredentialCache added in v0.2.0

type CredentialCache struct {
	// contains filtered or unexported fields
}

CredentialCache reads credential files (the SSL server key/cert, token signing keys) for a daemon that has dropped privileges to a service account. It reads through droppriv as root — matching HTCondor's set_priv(PRIV_ROOT) — so root-owned 0600 credentials remain readable after the drop, and caches the bytes so steady-state handshakes do not pay a privilege transition and file read each time.

It satisfies cedar's security.CredentialReader (assign it to SecurityConfig.Credentials). Reload clears the cache so the next read picks up rotated signing keys or a renewed certificate; wire it to the daemon's SIGHUP reconfigure so credential reloads follow HTCondor's reconfig convention.

func NewCredentialCache added in v0.2.0

func NewCredentialCache() *CredentialCache

NewCredentialCache returns an empty credential cache.

func (*CredentialCache) ListCredentialDir added in v0.11.0

func (c *CredentialCache) ListCredentialDir(path string) ([]os.DirEntry, error)

ListCredentialDir lists the entries of a credential directory as root (via droppriv), so a daemon that has dropped privileges can still enumerate a root-only, mode-0700 token directory such as SEC_TOKEN_SYSTEM_DIRECTORY (/etc/condor/tokens.d). It satisfies cedar's security.CredentialDirLister.

Unlike ReadCredential the listing is not cached: a token directory's contents change as tokens are added, rotated, or removed, and the scan happens at most once per handshake, so a stale cached listing would cost more than it saves.

func (*CredentialCache) ReadCredential added in v0.2.0

func (c *CredentialCache) ReadCredential(path string) ([]byte, error)

ReadCredential returns the bytes of the credential file at path, reading it as root (via droppriv) on a cache miss and caching the result.

func (*CredentialCache) Reload added in v0.2.0

func (c *CredentialCache) Reload()

Reload drops all cached credentials so subsequent reads re-fetch the current on-disk bytes. Call it on reconfigure (SIGHUP) to honor rotated keys/certs.

type CredentialOrigin added in v0.20.0

type CredentialOrigin int

CredentialOrigin records who a context is acting for.

It exists because a context carrying no *security.SecurityConfig was ambiguous in the one way that matters. "Nobody attached a credential because this is the daemon's own queue mirroring" and "nobody attached a credential because the code that should have done so returned early" look identical at the point where the connection is built, and GetSecurityConfigOrDefault resolved both of them the same way: fall through to this daemon's own configuration. On an access point the daemon is a queue superuser, so a missing credential did not fail closed -- it escalated. A request whose authentication went wrong ended up with MORE authority than one whose went right.

The classification therefore has to come from somewhere that cannot be skipped by the failure it is meant to catch, which means the transport that accepted the request rather than the branch that authenticates it. See WithUserRequest.

const (
	// OriginUnset is a context nobody has classified. What happens when one
	// reaches the daemon fallback is the process-wide policy's decision;
	// see SetUnmarkedOriginPolicy.
	OriginUnset CredentialOrigin = iota
	// OriginUser is a context acting for somebody who is not this daemon.
	// The daemon fallback is never right for one of these: the worst
	// acceptable outcome is an unauthenticated connection the peer refuses,
	// not an authenticated one the peer trusts completely.
	OriginUser
	// OriginDaemon is this daemon's own work -- queue mirroring, collector
	// advertising, a CCB relay, a health ping. Here the daemon credential is
	// the point rather than an accident.
	OriginDaemon
)

func CredentialOriginFromContext added in v0.20.0

func CredentialOriginFromContext(ctx context.Context) (CredentialOrigin, string)

CredentialOriginFromContext reports how ctx was classified, and why.

func (CredentialOrigin) String added in v0.20.0

func (o CredentialOrigin) String() string

type CredentialReloader added in v0.2.0

type CredentialReloader interface {
	Reload()
}

CredentialReloader is implemented by a SecurityConfig.Credentials value (e.g. *CredentialCache) that can drop cached credentials so the next read picks up rotated keys / renewed certs. A daemon wires this to its SIGHUP reconfigure.

type CredentialStatus added in v0.0.6

type CredentialStatus struct {
	Exists    bool       `json:"exists"`
	UpdatedAt *time.Time `json:"updated_at,omitempty"`
	// Pending reports a credential that has been requested or stored but
	// is not usable yet: the credd holds its request (.top) file and a
	// credmon has not written the token (.use) from it. Exists is false
	// while this is true.
	Pending bool `json:"pending,omitempty"`
}

CredentialStatus describes whether a credential exists and when it was last updated.

type DaemonLocation

type DaemonLocation struct {
	Name    string
	Address string
	Pool    string
}

DaemonLocation represents the location information for a daemon

type DaemonType added in v0.8.0

type DaemonType string

DaemonType identifies a kind of HTCondor daemon for LocateDaemon. It mirrors the daemon types used by the HTCondor Python bindings' Collector.locate().

A daemon type is distinct from the collector-query ad type: a schedd, for example, is DaemonSchedd but advertises a "Scheduler" ad queried as the "ScheddAd" ad type. LocateDaemon does that translation for you (see adType).

const (
	DaemonSchedd     DaemonType = "Schedd"
	DaemonStartd     DaemonType = "Startd"
	DaemonMaster     DaemonType = "Master"
	DaemonCollector  DaemonType = "Collector"
	DaemonNegotiator DaemonType = "Negotiator"
	// DaemonPlacementd is condor_placementd. It advertises a generic ad
	// whose MyType is "PlacementD", so it is located through the generic-ad
	// query path rather than a dedicated QUERY_*_ADS command.
	DaemonPlacementd DaemonType = "PlacementD"
)

Daemon types accepted by LocateDaemon.

type DialOptions added in v0.2.0

type DialOptions struct {
	// Timeout bounds connection establishment (default 30s).
	Timeout time.Duration

	// CCBReturnAddr enables streaming/proxy mode when the address is a CCB
	// sinful: it is this client's own CCB sinful (carrying a ccbid), used when
	// the client itself is private and cannot accept a direct reverse
	// connection. Leave empty for the common case (a publicly reachable tool
	// dialing into a private daemon).
	CCBReturnAddr string

	// CCBRequireStreaming makes streaming mode mandatory: if the broker does
	// not support it, DialSinful fails fast rather than attempting a direct
	// reverse connection.
	//
	// Setting this alone is enough to select streaming; CCBReturnAddr is
	// filled in for you. See DialSinful.
	CCBRequireStreaming bool

	// CCBReverseListener supplies the inbound path for a standard-mode CCB
	// dial instead of a private TCP socket, letting a caller with no port of
	// its own still accept connection reversal -- see
	// ccb.DialOptions.ReverseListener and CCBDialer, which is what normally
	// sets this.
	//
	// Ignored when CCBRequireStreaming or CCBReturnAddr select streaming: in
	// streaming mode nothing reverses.
	CCBReverseListener ccb.ReverseListenerFunc
}

DialOptions configures DialSinful, principally for reaching daemons behind a Condor Connection Broker (CCB).

type EditJobOptions

type EditJobOptions struct {
	// AllowProtectedAttrs allows editing of protected attributes (requires superuser privileges)
	AllowProtectedAttrs bool

	// Force allows editing even if some validations fail (use with caution)
	Force bool
}

EditJobOptions contains options for editing jobs

type ErrDaemonFallbackRefused added in v0.20.0

type ErrDaemonFallbackRefused struct {
	// Origin is how the context was classified: OriginUser for a refused
	// caller, OriginUnset when the policy refuses unclassified contexts.
	Origin CredentialOrigin
	// Reason is the surface the classification was made at.
	Reason string
	// Command, Context and PeerName describe the connection that was about
	// to be built, so a log line identifies which call was refused.
	Command  int
	Context  string
	PeerName string
}

ErrDaemonFallbackRefused is returned when a context that is not this daemon's own work reaches the point where the daemon's credential would have been used.

It always means a bug in this server: some code path reached CEDAR without attaching the caller's credential (htcondor.WithSecurityConfig), or did the daemon's own work without saying so (htcondor.WithDaemonCredential). That advice is for whoever fixes the code, so it lives here rather than in the message, which reaches log readers and, through the HTTP handlers, users.

func (*ErrDaemonFallbackRefused) Error added in v0.20.0

func (e *ErrDaemonFallbackRefused) Error() string

type FileTransferClient

type FileTransferClient struct {
	// contains filtered or unexported fields
}

FileTransferClient handles client-side file transfers. Supports uploading files to schedd and downloading from schedd.

func NewFileTransferClient

func NewFileTransferClient(daemonAddr string, daemonPort int, transKey string) *FileTransferClient

NewFileTransferClient creates a new file transfer client.

func (*FileTransferClient) DownloadFile

func (ftc *FileTransferClient) DownloadFile(ctx context.Context, remotePath string, localPath string) error

DownloadFile downloads a single file from the schedd.

This implements the client side of the FILETRANS_DOWNLOAD protocol:

  1. Connect to daemon
  2. Perform security handshake
  3. Send FILETRANS_DOWNLOAD command
  4. Send transfer key (using Stream.PutSecret)
  5. Send file path request
  6. Receive file metadata
  7. Receive file data (using Stream.GetFile)
  8. Verify checksum if provided

Parameters:

  • ctx: Context for cancellation
  • remotePath: Path on schedd
  • localPath: Where to save the file locally

Returns error if transfer fails.

NOTE: This implementation uses cedar v0.0.2+ APIs:

  • Stream.PutSecret() for transfer key transmission
  • Stream.GetFile() for efficient file streaming

TODO: Still missing Daemon.StartCommand() - currently must manually send command code.

func (*FileTransferClient) UploadFile

func (ftc *FileTransferClient) UploadFile(ctx context.Context, item FileTransferItem) error

UploadFile uploads a single file to the schedd.

This implements the client side of the FILETRANS_UPLOAD protocol:

  1. Gather file metadata (size, permissions, checksum)
  2. Connect to daemon
  3. Perform security handshake
  4. Send FILETRANS_UPLOAD command
  5. Send transfer key (using Stream.PutSecret)
  6. Send file metadata
  7. Send CommandXferFile
  8. Send file data (using Stream.PutFile)
  9. Send CommandFinished

Parameters:

  • ctx: Context for cancellation
  • item: File metadata and paths

Returns error if transfer fails.

NOTE: This implementation uses cedar v0.0.2+ APIs:

  • Stream.PutSecret() for transfer key transmission
  • Stream.PutFile() for efficient file streaming

TODO: Still missing Daemon.StartCommand() - currently must manually send command code.

type FileTransferItem

type FileTransferItem struct {
	// SrcPath is the source file path (local for upload, remote for download)
	SrcPath string

	// DestPath is the destination file path
	DestPath string

	// FileSize is the size of the file in bytes
	FileSize int64

	// FileMode is the Unix file permissions (e.g., 0644, 0755)
	FileMode uint32

	// Checksum is optional SHA256 checksum for verification
	Checksum string

	// ChecksumType is the type of checksum (e.g., "SHA256")
	ChecksumType string
}

FileTransferItem represents a single file to transfer. Contains metadata needed for the transfer protocol.

type FileTransferServer

type FileTransferServer struct {
	// contains filtered or unexported fields
}

FileTransferServer handles server-side file transfers. This would be implemented by schedd to handle incoming transfer requests.

NOTE: Server-side implementation requires command registration API from CEDAR which is not yet available. This is a placeholder for future implementation.

func NewFileTransferServer

func NewFileTransferServer(transKey string, baseDir string) *FileTransferServer

NewFileTransferServer creates a new file transfer server handler.

func (*FileTransferServer) HandleDownload

func (fts *FileTransferServer) HandleDownload(_ context.Context, _ *stream.Stream) error

HandleDownload sends files to a client.

This would be registered as a command handler for FILETRANS_DOWNLOAD. The schedd calls this when a client requests a download.

Protocol:

  1. Receive transfer key and file request
  2. Send file metadata
  3. Send file data
  4. Send CommandFinished

NOTE: Command registration API not yet available in CEDAR Go library.

func (*FileTransferServer) HandleUpload

func (fts *FileTransferServer) HandleUpload(_ context.Context, _ *stream.Stream) error

HandleUpload receives files from a client.

This would be registered as a command handler for FILETRANS_UPLOAD. The schedd calls this when a client initiates an upload.

Protocol:

  1. Receive transfer key (already authenticated)
  2. Receive file metadata
  3. Receive file data
  4. Write to disk
  5. Wait for CommandFinished

NOTE: Command registration API not yet available in CEDAR Go library.

type HistoryAdResult added in v0.0.4

type HistoryAdResult struct {
	Ad  *classad.ClassAd
	Err error
}

HistoryAdResult represents a single history ad or error from a streaming query

type HistoryQueryOptions added in v0.0.4

type HistoryQueryOptions struct {
	// Source specifies the history record source to query
	// Default is HistorySourceJobHistory
	Source HistoryRecordSource

	// Limit specifies the maximum number of results to return.
	// Use 0 or negative value for unlimited results.
	// Default is 50 if not specified.
	Limit int

	// ScanLimit specifies the maximum number of ads to scan.
	// Use a negative value for unlimited scanning.
	// Default (0) is DefaultHistoryScanLimit, to prevent timeouts on large
	// pools. Set Stats to learn whether a query stopped at this limit.
	ScanLimit int

	// Projection is a list of attributes to include in results.
	// Use nil or empty slice for default projections.
	// Use []string{"*"} to include all attributes.
	Projection []string

	// Backwards controls the order of results.
	// If true, returns results in reverse chronological order (newest first).
	// If false, returns results in chronological order (oldest first).
	// Default is true (backwards).
	Backwards bool

	// StreamResults requests that the server stream results as they are found
	// rather than buffering all results before sending.
	// Default is true for streaming.
	StreamResults bool

	// Since can be a job ID (e.g., "123.0") or a constraint expression
	// to stop scanning when matched. Only used when Backwards is true.
	Since string

	// TransferTypes specifies which transfer types to include when
	// Source is HistorySourceTransfer. Empty means all types.
	TransferTypes []TransferType

	// AdTypeFilter filters ads by their type (not MyType).
	// Only applies to some history sources.
	AdTypeFilter []string

	// ReadFromDirectory requests reading from per-job epoch directory
	// instead of aggregate history file. Only applies to epoch history.
	ReadFromDirectory bool

	// DaemonSubsystem specifies which daemon subsystem to query
	// when Source is HistorySourceDaemon (e.g., "SCHEDD").
	DaemonSubsystem string

	// Stats, when non-nil, is filled in from the daemon's closing ad once
	// the query completes successfully: how many records it examined and
	// whether it stopped because of ScanLimit. It is not sent to the
	// daemon. For a streaming query it is written before the result
	// channel is closed, so it is safe to read after draining the channel.
	Stats *HistoryScanStats
}

HistoryQueryOptions contains options for querying history records

func (*HistoryQueryOptions) ApplyDefaults added in v0.0.4

func (opts *HistoryQueryOptions) ApplyDefaults() HistoryQueryOptions

ApplyDefaults applies default values to HistoryQueryOptions

func (*HistoryQueryOptions) GetEffectiveProjection added in v0.0.4

func (opts *HistoryQueryOptions) GetEffectiveProjection() []string

GetEffectiveProjection returns the projection to use based on the source type

func (*HistoryQueryOptions) IsUnlimited added in v0.0.4

func (opts *HistoryQueryOptions) IsUnlimited() bool

IsUnlimited returns true if the query should return unlimited results

func (*HistoryQueryOptions) ShouldUseAllAttributes added in v0.0.4

func (opts *HistoryQueryOptions) ShouldUseAllAttributes() bool

ShouldUseAllAttributes returns true if all attributes should be returned

func (*HistoryQueryOptions) ShouldUseDefaultProjection added in v0.0.4

func (opts *HistoryQueryOptions) ShouldUseDefaultProjection() bool

ShouldUseDefaultProjection returns true if default projection should be used

type HistoryRecordSource added in v0.0.4

type HistoryRecordSource string

HistoryRecordSource specifies what type of history records to query

const (
	// HistorySourceJobHistory queries standard job history (completed jobs)
	HistorySourceJobHistory HistoryRecordSource = "HISTORY"

	// HistorySourceJobEpoch queries job epoch history (per job run instance)
	// This includes records for each execution attempt of a job
	HistorySourceJobEpoch HistoryRecordSource = "JOB_EPOCH"

	// HistorySourceTransfer queries transfer history from job epochs
	// This includes file transfer events (input, output, checkpoint)
	HistorySourceTransfer HistoryRecordSource = "TRANSFER"

	// HistorySourceStartd queries startd history (from compute nodes)
	HistorySourceStartd HistoryRecordSource = "STARTD"

	// HistorySourceDaemon queries daemon history (historical daemon ads)
	HistorySourceDaemon HistoryRecordSource = "DAEMON"
)

type HistoryScanStats added in v0.20.1

type HistoryScanStats struct {
	// Reported is true when the daemon's closing ad carried AdCount.
	// Without it the other counts are zero and ScanLimitReached is false
	// because nothing can be concluded, not because the scan finished.
	Reported bool
	// RecordsScanned is the number of history records the daemon examined
	// (AdCount).
	RecordsScanned int
	// Matches is the number of records that matched (NumMatches).
	Matches int
	// MalformedAds is the number of matching records the daemon could not
	// send.
	MalformedAds int
	// ScanLimit is the scan limit the query was sent with; 0 means none.
	ScanLimit int
	// ScanLimitReached reports that the daemon stopped because it had
	// examined ScanLimit records before finding Limit matches: older
	// records were not searched, and more matches may exist there.
	ScanLimitReached bool
}

HistoryScanStats is the daemon's own account of a history query, taken from the closing ad of the response. A query whose matches lie further back than the scan limit returns fewer records than asked for -- often none -- and this is the only place that says the search was cut short rather than exhausted.

type InMemoryCredd added in v0.0.6

type InMemoryCredd struct {
	// contains filtered or unexported fields
}

InMemoryCredd provides a lightweight, non-persistent credd implementation useful for testing and demo environments. It is not intended for production credential storage.

func NewInMemoryCredd added in v0.0.6

func NewInMemoryCredd() *InMemoryCredd

NewInMemoryCredd constructs a new in-memory credd client.

func (*InMemoryCredd) CheckCreds added in v0.20.0

func (c *InMemoryCredd) CheckCreds(ctx context.Context, requests []CredRequest) (string, error)

CheckCreds reports whether every requested service credential is stored. There is no credmon here to create a missing one, so a missing credential is an error, as the credd reports a service it has no credmon for.

func (*InMemoryCredd) DeleteServiceCred added in v0.0.6

func (c *InMemoryCredd) DeleteServiceCred(ctx context.Context, credType CredType, service string, handle string, user string) error

DeleteServiceCred removes a service credential for a user.

func (*InMemoryCredd) DeleteUserCred added in v0.0.6

func (c *InMemoryCredd) DeleteUserCred(ctx context.Context, credType CredType, user string) error

DeleteUserCred removes a user credential of the specified type.

func (*InMemoryCredd) GetCredential added in v0.0.6

func (c *InMemoryCredd) GetCredential(ctx context.Context, credType CredType, service string, handle string, user string) ([]byte, error)

GetCredential returns the stored credential payload for service/handle.

func (*InMemoryCredd) GetServiceCredStatus added in v0.0.6

func (c *InMemoryCredd) GetServiceCredStatus(ctx context.Context, credType CredType, service string, handle string, user string) (CredentialStatus, error)

GetServiceCredStatus reports status for a stored service credential.

func (*InMemoryCredd) GetUserCredStatus added in v0.0.6

func (c *InMemoryCredd) GetUserCredStatus(ctx context.Context, credType CredType, user string) (CredentialStatus, error)

GetUserCredStatus reports credential status for the specified user credential type.

func (*InMemoryCredd) ListServiceCreds added in v0.0.6

func (c *InMemoryCredd) ListServiceCreds(ctx context.Context, credType CredType, user string) ([]ServiceStatus, error)

ListServiceCreds returns all service credentials for the user and credType.

func (*InMemoryCredd) PutServiceCred added in v0.0.6

func (c *InMemoryCredd) PutServiceCred(ctx context.Context, credType CredType, credential []byte, service string, handle string, user string, refresh *bool) error

PutServiceCred stores an OAuth service credential for a user.

func (*InMemoryCredd) PutUserCred added in v0.0.6

func (c *InMemoryCredd) PutUserCred(ctx context.Context, credType CredType, credential []byte, user string) error

PutUserCred stores a user credential of the given type (Kerberos).

type JobAction

type JobAction int

JobAction represents an action to perform on jobs

const (
	JA_ERROR                    JobAction = iota // 0: Error/invalid action
	JA_HOLD_JOBS                                 // 1: Hold jobs
	JA_RELEASE_JOBS                              // 2: Release held jobs
	JA_REMOVE_JOBS                               // 3: Remove jobs
	JA_REMOVE_X_JOBS                             // 4: Remove jobs with force (X = extended/force)
	JA_VACATE_JOBS                               // 5: Vacate jobs (gentle)
	JA_VACATE_FAST_JOBS                          // 6: Vacate jobs (fast/hard kill)
	JA_CLEAR_DIRTY_JOB_ATTRS                     // 7: Clear dirty job attributes
	JA_SUSPEND_JOBS                              // 8: Suspend jobs
	JA_CONTINUE_JOBS                             // 9: Continue suspended jobs
	JA_TRANSFER_AND_REMOVE_JOBS                  // 10: Spool then remove jobs
)

Job action constants based on HTCondor's JobAction enum.

These values are placed on the wire as ATTR_JOB_ACTION and MUST match the C++ enum exactly (src/condor_utils/enum_utils.h:106-116):

JA_ERROR = 0, JA_HOLD_JOBS, JA_RELEASE_JOBS, JA_REMOVE_JOBS,
JA_REMOVE_X_JOBS, JA_VACATE_JOBS, JA_VACATE_FAST_JOBS,
JA_CLEAR_DIRTY_JOB_ATTRS, JA_SUSPEND_JOBS, JA_CONTINUE_JOBS,
JA_TRANSFER_AND_REMOVE_JOBS

(An earlier version of this file omitted JA_CLEAR_DIRTY_JOB_ATTRS, which silently shifted JA_SUSPEND_JOBS/JA_CONTINUE_JOBS off by one relative to the schedd's switch in Scheduler::actOnJobs, src/condor_schedd.V6/schedd.cpp:7517.)

type JobActionRefusedError added in v0.20.0

type JobActionRefusedError struct {
	Results *JobActionResults
}

JobActionRefusedError is a job action the schedd carried out on none of the jobs it was aimed at. It is an answer, not a failure to get one: Results says why, job by job -- nothing matched, the jobs were already in that state, permission was denied. Callers usually want to report that reason rather than a server error.

func (*JobActionRefusedError) Error added in v0.20.0

func (e *JobActionRefusedError) Error() string

func (*JobActionRefusedError) Is added in v0.20.0

func (e *JobActionRefusedError) Is(target error) bool

Is makes errors.Is(err, ErrNoJobsMatched) true when nothing matched.

type JobActionResults

type JobActionResults struct {
	// Total count of each result type
	TotalJobs        int
	Success          int
	NotFound         int
	PermissionDenied int
	BadStatus        int
	AlreadyDone      int
	LimitExceeded    int
	Error            int

	// The result ClassAd from the schedd (may contain per-job details)
	ResultAd *classad.ClassAd
}

JobActionResults contains the results of a job action

func (*JobActionResults) Attempted added in v0.20.0

func (r *JobActionResults) Attempted() int

Attempted is the number of jobs the action reached: every one has exactly one outcome, so it is the sum of the outcome counts. Zero means nothing matched.

func (*JobActionResults) Summary added in v0.20.0

func (r *JobActionResults) Summary() string

Summary describes the outcomes other than success, e.g. "2 already in that state, 1 permission denied". Empty when every job succeeded.

type JobAdResult added in v0.0.4

type JobAdResult struct {
	Ad  *classad.ClassAd
	Err error
}

JobAdResult represents a single job ad or error from a streaming query

type JobConnectInfo added in v0.0.11

type JobConnectInfo struct {
	StarterAddr    string // sinful string of the starter
	ClaimID        string // claim id for the schedd-minted starter session
	StarterVersion string // starter's HTCondor version banner
	RemoteHost     string // slot name (cosmetic only, useful for logs)
	// contains filtered or unexported fields
}

JobConnectInfo is the result of a GET_JOB_CONNECT_INFO call against the schedd. It is everything you need to talk to the starter on behalf of the user without going through the schedd again.

func (*JobConnectInfo) OpenSSH added in v0.0.11

func (info *JobConnectInfo) OpenSSH(ctx context.Context, opts *JobShellOptions) (*ssh.Client, error)

OpenSSH performs the START_SSHD step + crypto/ssh handshake against an already-located starter. This is the seam for tests and for advanced callers that want to look at the slot/version metadata first.

type JobID

type JobID struct {
	Cluster int
	Proc    int
}

JobID represents a cluster/proc pair

type JobShellOptions added in v0.0.11

type JobShellOptions struct {
	// HandshakeTimeout caps the SSH handshake (NewClientConn). Default 30s.
	HandshakeTimeout time.Duration

	// CCB decides how to reach a starter that sits behind a Condor Connection
	// Broker: on an inbound path of our own, or by having the broker relay.
	//
	// It matters because the default -- having the execute node dial back to
	// us -- needs this process to be reachable from that node, which is not
	// true of an API server in a container or behind NAT. The broker then
	// tells the starter to connect to an address nothing routes to and the
	// attempt times out with nothing to show for it. A nil CCB keeps that
	// default, which is right for a tool running on a pool host. It costs
	// nothing when the starter is not behind CCB -- the address decides
	// whether CCB is involved at all.
	CCB *CCBDialer
}

JobShellOptions tunes the SSH session. Zero values are fine for typical use.

type KeepAliveOptions added in v0.0.4

type KeepAliveOptions struct {
	// HangTimeout is the grace period the master should allow before considering the daemon hung.
	HangTimeout time.Duration
	// Interval is how frequently to send keepalives. If zero, it is derived from HangTimeout.
	Interval time.Duration
	// DprintfLockDelay optionally reports the log lock hold time; omitted when zero.
	DprintfLockDelay time.Duration
}

KeepAliveOptions controls keepalive payload and timing.

type Master added in v0.0.4

type Master struct {
	// contains filtered or unexported fields
}

Master provides child-to-master control plane helpers for daemons launched by condor_master. It can send keepalive heartbeats and readiness notifications.

func MasterFromEnv added in v0.0.4

func MasterFromEnv() (*Master, error)

MasterFromEnv builds a Master using HTCondor's CONDOR_INHERIT metadata. It expects the CONDOR_INHERIT environment variable to contain the parent PID followed by the master's command sinful string (e.g., "1234 <127.0.0.1:9618>").

As a side effect, this also primes the global cedar SessionCache by touching it once: GetSessionCache() lazily imports inherited sessions from CONDOR_PRIVATE_INHERIT, and we want that import to happen at daemon startup rather than the first time we send DC_CHILDALIVE. Without the priming, a transient init race could cause our first keepalive to do a fresh handshake when an inherited family session was available all along — the master would then log `vscode@<host>` for that one DC_CHILDALIVE instead of `condor@child`, which is benign but makes audit logs noisier.

func NewMaster added in v0.0.4

func NewMaster(address string) *Master

NewMaster constructs a Master pointed at a specific command address.

func (*Master) Address added in v0.0.4

func (m *Master) Address() string

Address returns the master's command address.

func (*Master) DaemonName added in v0.0.4

func (m *Master) DaemonName() string

DaemonName returns the configured daemon name (if provided).

func (*Master) ParentPID added in v0.0.4

func (m *Master) ParentPID() int

ParentPID returns the parent PID parsed from CONDOR_INHERIT when available.

func (*Master) SendKeepAlive added in v0.0.4

func (m *Master) SendKeepAlive(ctx context.Context, opts *KeepAliveOptions) error

SendKeepAlive transmits a DC_CHILDALIVE heartbeat to condor_master.

func (*Master) SendReady added in v0.0.4

func (m *Master) SendReady(ctx context.Context, opts *ReadyOptions) error

SendReady transmits a DC_SET_READY notification indicating the daemon successfully initialized and is ready to serve work.

func (*Master) SetDaemonName added in v0.9.4

func (m *Master) SetDaemonName(name string)

SetDaemonName sets the name reported to the master in DC_SET_READY (the "DaemonName" attribute the master logs as "Setting ready state ... for <name>"). The master identifies the daemon by PID, so this is for its logging/bookkeeping; callers use it to supply the subsystem name when _CONDOR_DAEMON_NAME is unset.

func (*Master) StartKeepAlive added in v0.0.4

func (m *Master) StartKeepAlive(ctx context.Context, opts *KeepAliveOptions) (stop func(), errs <-chan error, err error)

StartKeepAlive launches a background keepalive loop. It sends an initial heartbeat immediately, then repeats at the configured interval until the context is cancelled or Stop is invoked.

The returned stop function cancels the loop. The error channel is closed once the loop exits; non-nil errors are delivered through it.

func (*Master) WithConfig added in v0.20.0

func (m *Master) WithConfig(cfg *config.Config) *Master

WithConfig sets the HTCondor configuration the Master's CEDAR sender uses for keepalives and readiness; see the note above.

type OutputRemap added in v0.0.4

type OutputRemap struct {
	Source      string // Original filename from the job sandbox
	Destination string // Remapped destination path or URL
	IsURL       bool   // True if destination is a URL (should be skipped in tarball)
}

OutputRemap represents a single output file remap entry

type PageInfo added in v0.0.4

type PageInfo struct {
	// NextPageToken is the token to use for fetching the next page of results.
	// Empty string if there are no more results.
	NextPageToken string

	// HasMoreResults indicates whether there are more results available
	HasMoreResults bool

	// TotalReturned is the number of results in the current response
	TotalReturned int
}

PageInfo contains pagination metadata

type PeekRequest added in v0.0.12

type PeekRequest struct {
	Stdout       bool
	StdoutOffset int64
	Stderr       bool
	StderrOffset int64
	// MaxBytes is the total cap shared across the requested
	// streams. The starter splits it across files internally.
	// Zero or negative falls back to DefaultPeekMaxBytes.
	MaxBytes int64

	// CCB decides how to reach a starter behind a Condor Connection Broker --
	// see JobShellOptions.CCB, which is the same choice for the same reason on
	// the shell path.
	CCB *CCBDialer
}

PeekRequest controls a single STARTER_PEEK call.

An offset of -1 asks the starter to "tail" — return the last MaxBytes of the file. After a successful call the response carries the new absolute offset; pass that back in on the next call to stream incremental chunks (the same trick the condor_tail -follow loop uses).

type PeekResult added in v0.0.12

type PeekResult struct {
	Stdout *PeekedStream
	Stderr *PeekedStream
}

PeekResult carries whichever streams the caller asked for. Each pointer is non-nil iff the matching request flag was set AND the starter returned a payload for it.

type PeekedStream added in v0.0.12

type PeekedStream struct {
	Bytes  []byte
	Offset int64 // absolute byte offset at the *end* of Bytes
}

PeekedStream is what came back for one of the requested streams.

type PingOptions added in v0.0.4

type PingOptions struct {
	// CheckPermission specifies a permission level to check authorization for.
	// If 0, only authentication is performed (DC_NOP).
	// If set to one of DC_NOP_* constants, authorization is checked (DC_SEC_QUERY).
	CheckPermission int

	// Command, when set, is the DC_NOP_* command the ping sends in place of
	// DC_NOP. DaemonCore registers DC_NOP at ALLOW, so a plain ping succeeds
	// for any identity the daemon can authenticate; each DC_NOP_<LEVEL> is
	// registered at its level, so the daemon refuses the handshake (post-auth
	// ReturnCode DENIED) unless the identity is authorized there. The ping
	// then fails rather than reporting a User.
	//
	// Unlike CheckPermission, which asks the daemon a question and reads its
	// answer, this makes the ping itself an operation at that level. Mutually
	// exclusive with CheckPermission.
	Command int
}

PingOptions configures the ping operation

type PingResult added in v0.0.4

type PingResult struct {
	// AuthMethod is the authentication method that was negotiated
	AuthMethod string
	// User is the authenticated username
	User string
	// SessionID is the session identifier
	SessionID string
	// ValidCommands is a string describing which commands are authorized
	ValidCommands string
	// Encryption indicates whether encryption was negotiated
	Encryption bool
	// Authentication indicates whether authentication was performed
	Authentication bool
	// Authorized reports the daemon's answer to the DC_SEC_QUERY probe:
	// whether the authenticated identity would be permitted to run a
	// command at the requested level. Only meaningful when
	// PingOptions.CheckPermission was set; false otherwise. A daemon that
	// refuses the level answers DENIED in the handshake itself (C++
	// DaemonCore and cedar alike); that is reported here as false, with
	// Reason, rather than as an error.
	//
	// Note this is an authorization answer, not an identity one. It says
	// the daemon's ACLs admit whatever identity the connection presented;
	// it says nothing about whether that identity still exists wherever it
	// originated.
	Authorized bool
	// Permission is the permission level that was checked (e.g., "READ", "WRITE")
	// Only set when CheckPermission is specified
	Permission string
	// Reason says why Authorized is false after a CheckPermission query:
	// the daemon refused the level, or registers no command at it.
	Reason string
	// CommandNotFound reports that the daemon registers no command at the
	// level CheckPermission queried (it answered CMD_NOT_FOUND), so it
	// could not say whether the identity is authorized there. Authorized
	// is false.
	CommandNotFound bool
}

PingResult contains the result of a ping operation

type PlacementAuthorization added in v0.13.0

type PlacementAuthorization struct {
	// Name is the authorization as it appears in a token's bounding set.
	Name string
	// Label is the human-readable name to show instead of Name.
	Label string
	// Color is the operator's suggested display color for the badge. It is
	// whatever the map file says -- a CSS color name, a hex triplet, or a
	// token meaningful only to a particular UI -- so treat it as a hint and
	// have a fallback.
	Color string
	// Description is a sentence explaining what the authorization permits.
	Description string
}

PlacementAuthorization is one authorization the placementd can grant, with the display metadata its authorizations map file carries so a UI can render the same labels and colors the reference portal does.

type PlacementError added in v0.13.0

type PlacementError struct {
	Code    int
	Message string
}

PlacementError is an error the placementd reported in its reply ad, carrying the daemon's own ErrorCode/ErrorString rather than a transport failure. Callers that need to distinguish, say, "this user may not have that authorization" from "the schedd is down" should errors.As to this type and switch on Code against the PlacementErr* constants.

func (*PlacementError) Error added in v0.13.0

func (e *PlacementError) Error() string

type PlacementLoginRequest added in v0.13.0

type PlacementLoginRequest struct {
	// UserName is the foreign identity to log in -- the left-hand column of
	// the placementd map file, not the local AP account. Required.
	UserName string
	// Authorizations narrows the token's bounding set to these
	// authorizations. Every entry must be one the user's map-file line
	// grants, or the login is refused entirely (the daemon does not silently
	// drop the ones it cannot grant). Empty means "everything this user is
	// entitled to".
	Authorizations []string
	// Project ties the token, and so the jobs submitted with it, to an AP
	// project. It must appear in the user's map-file project list. Empty
	// means the token carries no project claim.
	Project string
	// Requester is the foreign identity of whoever is asking, when that is
	// not the user being logged in -- an instructor minting a token for a
	// student, say. The requester must itself be mapped and hold the
	// INSTRUCTOR authorization. Empty means the user is requesting for
	// themselves.
	Requester string
}

PlacementLoginRequest asks the placementd to mint an IDToken.

type PlacementLoginResult added in v0.13.0

type PlacementLoginResult struct {
	// Token is the signed IDToken. Treat it as a secret: it is a bearer
	// credential for the AP identity it names.
	Token string
	// Ad is the daemon's full reply ad, so callers can read attributes this
	// struct does not model yet.
	Ad *classad.ClassAd
}

PlacementLoginResult is a successful login.

type PlacementToken added in v0.13.0

type PlacementToken struct {
	// Requester is the foreign identity that asked for the token, which
	// differs from UserName only for instructor-issued tokens.
	Requester string
	// UserName is the foreign identity the token was issued for.
	UserName string
	// APUserID is the local AP account named in the token's subject.
	APUserID string
	// Authorizations is the token's bounding set.
	Authorizations []string
	// TokenID is the token's jti claim, the handle for talking about one
	// specific token.
	TokenID string
	// Expiration is the token's exp claim.
	Expiration time.Time
	// Project is the project claim, empty when the token carries none.
	Project string
}

PlacementToken is one issued token as recorded in the placementd database. The token itself is not stored, only its identity and claims.

type PlacementTokenQuery added in v0.13.0

type PlacementTokenQuery struct {
	// UserName restricts the result to tokens issued for one foreign
	// identity.
	UserName string
	// TokenID restricts the result to the single token with this jti. It
	// takes precedence over the other two fields: the daemon applies it
	// alone.
	TokenID string
	// ValidOnly drops tokens that have already expired.
	ValidOnly bool
}

PlacementTokenQuery narrows QueryTokens. A zero query returns every token the daemon has ever issued, expired ones included.

type PlacementUser added in v0.13.0

type PlacementUser struct {
	// UserName is the foreign identity.
	UserName string
	// APUserID is the local AP account the identity maps to (the token's
	// subject).
	APUserID string
	// TokenExpiration is when the newest unexpired token for this user runs
	// out; the zero time means no live token.
	TokenExpiration time.Time
	// MappingExpiration is when the map-file entry itself stops being
	// honored; the zero time means it never does.
	MappingExpiration time.Time
	// Projects are the AP projects this identity may bind a token to.
	Projects []string
	// Authorizations are the authorizations the map file grants.
	Authorizations []string
	// Authorized reports whether the identity is still in the map file. A
	// user with live tokens but no map-file entry comes back with
	// Authorized false: their tokens work until they expire, but they can no
	// longer log in.
	Authorized bool
}

PlacementUser is one row of the placementd's user view: the map-file entry for a foreign identity, merged with the newest unexpired token issued to it.

type Placementd added in v0.13.0

type Placementd struct {
	// contains filtered or unexported fields
}

Placementd is a CEDAR client for condor_placementd.

Every command the daemon registers requires ADMINISTRATOR authorization and forced authentication, and the login command additionally refuses to run on an unencrypted channel (it would otherwise hand a bearer token to anyone on the path). This client therefore demands authentication and encryption on every connection rather than letting configuration weaken them.

func NewPlacementd added in v0.13.0

func NewPlacementd(address string) *Placementd

NewPlacementd returns a client for the placementd at address, a sinful string. Use Collector.LocateDaemon with DaemonPlacementd to find one.

func (*Placementd) Address added in v0.13.0

func (p *Placementd) Address() string

Address returns the sinful string this client talks to.

func (*Placementd) Login added in v0.13.0

Login mints an IDToken for a foreign identity. See PlacementLoginRequest for what the daemon does with each field.

A login has a side effect beyond the token: the placementd creates the AP user record -- and the project record, when the request names a project -- in the schedd if they do not already exist. A login against a disabled user or project fails with PlacementErrSchedd rather than re-enabling it.

func (*Placementd) QueryAuthorizations added in v0.13.0

func (p *Placementd) QueryAuthorizations(ctx context.Context, userName string) ([]PlacementAuthorization, error)

QueryAuthorizations lists the authorizations the placementd can grant, with the display metadata from its authorizations map file. An empty userName lists every defined authorization; a non-empty one narrows the list to those that user may request, and fails with PlacementErrUserNotAuthorized if the user is not mapped.

func (*Placementd) QueryTokens added in v0.13.0

func (p *Placementd) QueryTokens(ctx context.Context, query PlacementTokenQuery) ([]PlacementToken, error)

QueryTokens lists tokens the placementd has issued. Tokens are never removed from its database, so an unfiltered query returns expired ones too; set PlacementTokenQuery.ValidOnly to see only live tokens.

func (*Placementd) QueryUsers added in v0.13.0

func (p *Placementd) QueryUsers(ctx context.Context, userName string) ([]PlacementUser, error)

QueryUsers lists the users the placementd knows about: everyone in its map file, plus anyone holding an unexpired token even if their mapping is gone (those come back with Authorized false). An empty userName lists all of them; a userName that is neither mapped nor holds a live token yields an empty result, not an error.

func (*Placementd) WithConfig added in v0.20.0

func (p *Placementd) WithConfig(cfg *config.Config) *Placementd

WithConfig sets the HTCondor configuration this placementd client uses; see the note above. The client's authentication and encryption requirements are not configurable either way.

type PlacementdClient added in v0.13.0

type PlacementdClient interface {
	// Login mints an IDToken for a foreign identity.
	Login(ctx context.Context, req PlacementLoginRequest) (*PlacementLoginResult, error)
	// QueryUsers lists known users; an empty userName lists all of them.
	QueryUsers(ctx context.Context, userName string) ([]PlacementUser, error)
	// QueryTokens lists issued tokens.
	QueryTokens(ctx context.Context, query PlacementTokenQuery) ([]PlacementToken, error)
	// QueryAuthorizations lists grantable authorizations; a non-empty
	// userName narrows the list to what that user may request.
	QueryAuthorizations(ctx context.Context, userName string) ([]PlacementAuthorization, error)
}

PlacementdClient is the placementd operations, as an interface so callers (notably the web API) can substitute a fake in tests.

type QmgmtConnection

type QmgmtConnection struct {
	// contains filtered or unexported fields
}

QmgmtConnection represents an active connection to the schedd for queue management operations Implements HTCondor's QMGMT (Queue Management) protocol for job submission

Protocol Flow:

  1. TCP connection to schedd
  2. DC_AUTHENTICATE handshake
  3. QMGMT_WRITE_CMD (1112) to enter queue management mode
  4. GetCapabilities (10036) to query schedd capabilities
  5. BeginTransaction (10023)
  6. NewCluster (10002) → cluster ID
  7. NewProc (10003) → proc ID
  8. SetAttribute (10006) for each attribute
  9. CommitTransaction (10007)
  10. CloseSocket (10028)

func NewQmgmtConnection

func NewQmgmtConnection(ctx context.Context, address string) (*QmgmtConnection, error)

NewQmgmtConnection establishes a queue management connection to the schedd Uses FS authentication from cedar package address can be a hostname:port or a sinful string like "<IP:PORT?addrs=...>"

func (*QmgmtConnection) AbortTransaction

func (q *QmgmtConnection) AbortTransaction(ctx context.Context) error

AbortTransaction aborts a queue management transaction

func (*QmgmtConnection) BeginTransaction

func (q *QmgmtConnection) BeginTransaction(ctx context.Context) error

BeginTransaction starts a queue management transaction

func (*QmgmtConnection) Close

func (q *QmgmtConnection) Close() error

Close disconnects from the schedd queue

func (*QmgmtConnection) CommitTransaction

func (q *QmgmtConnection) CommitTransaction(ctx context.Context) error

CommitTransaction commits a queue management transaction

func (*QmgmtConnection) DestroyCluster

func (q *QmgmtConnection) DestroyCluster(ctx context.Context, clusterID int) error

DestroyCluster removes a cluster and all its procs

func (*QmgmtConnection) NewCluster

func (q *QmgmtConnection) NewCluster(ctx context.Context) (int, error)

NewCluster allocates a new cluster ID

func (*QmgmtConnection) NewProc

func (q *QmgmtConnection) NewProc(ctx context.Context, clusterID int) (int, error)

NewProc allocates a new proc ID within a cluster

func (*QmgmtConnection) SendJobAttributes

func (q *QmgmtConnection) SendJobAttributes(ctx context.Context, clusterID, procID int, ad *classad.ClassAd) error

SendJobAttributes sends all attributes from a ClassAd to the schedd for a specific job This iterates through the ClassAd and calls SetAttribute for each attribute

func (*QmgmtConnection) SetAttribute

func (q *QmgmtConnection) SetAttribute(ctx context.Context, clusterID, procID int, attrName, attrValue string, flags SetAttributeFlags) error

SetAttribute sets an attribute on a job (cluster.proc) or cluster (cluster.-1)

func (*QmgmtConnection) SetAttributeInt

func (q *QmgmtConnection) SetAttributeInt(ctx context.Context, clusterID, procID int, attrName string, value int, flags SetAttributeFlags) error

SetAttributeInt is a convenience method to set an integer attribute

func (*QmgmtConnection) SetEffectiveOwner

func (q *QmgmtConnection) SetEffectiveOwner(ctx context.Context, owner string) error

SetEffectiveOwner sets the effective owner for subsequent job operations This must be called before setting job attributes as it determines the owner of the jobs

type QueryFetchOpts added in v0.0.4

type QueryFetchOpts int

QueryFetchOpts specifies what types of ads to fetch in a job query

const (
	// FetchNormal fetches normal job ads (default)
	FetchNormal QueryFetchOpts = 0

	// FetchMyJobs filters to only jobs owned by the authenticated user
	// Requires Owner to be set in QueryOptions
	FetchMyJobs QueryFetchOpts = 1 << 0

	// FetchSummaryOnly returns summary information instead of individual job ads
	FetchSummaryOnly QueryFetchOpts = 1 << 1

	// FetchIncludeClusterAd includes cluster ads in addition to proc ads
	FetchIncludeClusterAd QueryFetchOpts = 1 << 2

	// FetchIncludeJobsetAds includes jobset ads in the query results
	FetchIncludeJobsetAds QueryFetchOpts = 1 << 3

	// FetchNoProcAds excludes proc ads, only returning cluster/jobset ads
	FetchNoProcAds QueryFetchOpts = 1 << 4
)

type QueryOptions added in v0.0.4

type QueryOptions struct {
	// Limit specifies the maximum number of results to return.
	// Use 0 or negative value for unlimited results (opt-in with "*" in API).
	// Default is 50 if not specified.
	Limit int

	// Projection is a list of attributes to include in results.
	// Use nil or empty slice for default projections.
	// Use []string{"*"} to include all attributes.
	Projection []string

	// PageToken is used for pagination. Empty string for first page.
	// The token identifies where to continue fetching results.
	PageToken string

	// FetchOpts specifies query fetch options (MyJobs, SummaryOnly, etc.)
	// Default is FetchNormal (0) which fetches all job ads
	FetchOpts QueryFetchOpts

	// Owner specifies the job owner for FetchMyJobs queries
	// If empty and FetchMyJobs is set, uses authenticated username from context
	Owner string
}

QueryOptions contains options for querying jobs and collector ads

func (*QueryOptions) ApplyDefaults added in v0.0.4

func (opts *QueryOptions) ApplyDefaults() QueryOptions

ApplyDefaults applies default values to QueryOptions.

It copies EVERY field. It used to rebuild the struct from Limit, Projection and PageToken alone, which silently dropped FetchOpts and Owner — so a caller asking to see only its own jobs got a query with no owner filter at all, on both the streaming and buffered paths. Adding a field to QueryOptions means adding it here too.

func (*QueryOptions) GetEffectiveProjection added in v0.0.4

func (opts *QueryOptions) GetEffectiveProjection(defaultProj []string) []string

GetEffectiveProjection returns the projection to use, applying defaults if needed

func (*QueryOptions) IsUnlimited added in v0.0.4

func (opts *QueryOptions) IsUnlimited() bool

IsUnlimited returns true if the query should return unlimited results

func (*QueryOptions) ShouldUseAllAttributes added in v0.0.4

func (opts *QueryOptions) ShouldUseAllAttributes() bool

ShouldUseAllAttributes returns true if all attributes should be returned

func (*QueryOptions) ShouldUseDefaultProjection added in v0.0.4

func (opts *QueryOptions) ShouldUseDefaultProjection() bool

ShouldUseDefaultProjection returns true if default projection should be used

type ReadyOptions added in v0.0.4

type ReadyOptions struct {
	// State is a human-readable daemon state. Defaults to "Ready".
	State string
	// Name overrides the daemon name. If empty, Master.daemonName is used.
	Name string
	// Attributes adds custom ClassAd attributes to the readiness ping.
	Attributes map[string]any
}

ReadyOptions customizes the ready-state notification.

type RescheduleOptions added in v0.1.0

type RescheduleOptions struct {
	// MinInterval is the minimum gap between successful reschedule
	// requests to this schedd. Zero disables the limiter for this
	// call. Negative is treated as zero. If unset (zero value),
	// DefaultRescheduleInterval applies.
	MinInterval time.Duration

	// Force, when true, sends the reschedule even if the limiter
	// would otherwise skip it. Equivalent to MinInterval = 0 but
	// reads better at call sites that want the limiter to *protect
	// the schedd from us* most of the time and *not* protect it
	// during, say, an end-to-end test setup.
	Force bool
}

RescheduleOptions tunes Reschedule's behavior for a single call.

type Schedd

type Schedd struct {
	// contains filtered or unexported fields
}

Schedd represents an HTCondor schedd daemon

func NewSchedd

func NewSchedd(name string, address string) *Schedd

NewSchedd creates a new Schedd instance address can be a hostname:port or a sinful string like "<IP:PORT?addrs=...>"

func (*Schedd) Address added in v0.0.3

func (s *Schedd) Address() string

Address returns the schedd's address

func (*Schedd) AggregateJobs added in v0.13.0

func (s *Schedd) AggregateJobs(ctx context.Context, constraint string, groupBy []string, opts *QueryOptions) ([]AggregateRow, error)

AggregateJobs counts jobs matching constraint, grouped by the given attributes. An empty groupBy returns a single total.

The counting happens on the schedd; the wire carries one row per group rather than one ad per job.

func (*Schedd) ConfigVal added in v0.13.0

func (s *Schedd) ConfigVal(ctx context.Context, name string) (value string, ok bool, err error)

ConfigVal asks a daemon for the value of one configuration parameter, the way `condor_config_val -<daemon>` does.

This reads the DAEMON's view of its configuration, which is the point: the answer can differ from what this process would compute locally, because the daemon may run on another host, have been started with a different CONDOR_CONFIG, or simply not have been reconfigured since the file changed. For anything used to make an authorization decision, the daemon's own answer is the only one that means anything.

The command is registered at READ authorization on the daemon side, so this needs no special privilege.

A parameter with no value returns ("", false, nil) — an unset knob is a normal answer, not a failure.

func (*Schedd) CreateStartupLimit added in v0.0.6

func (s *Schedd) CreateStartupLimit(ctx context.Context, req *StartupLimitRequest) (string, error)

CreateStartupLimit creates or updates a startup rate limit in the schedd

Parameters:

  • ctx: Context for the operation (can include security config via WithSecurityConfig)
  • req: Startup limit parameters

Returns:

  • UUID of the created/updated limit
  • Error if the operation fails

Example:

req := &htcondor.StartupLimitRequest{
    Tag:        "gpu_limit",
    Name:       "GPU Job Rate Limit",
    Expression: "RequestGpus > 0",
    RateCount:  10,
    RateWindow: 60,  // 10 GPU jobs per minute
    Expiration: 3600, // expires in 1 hour
}
uuid, err := schedd.CreateStartupLimit(ctx, req)

func (*Schedd) EditJob

func (s *Schedd) EditJob(ctx context.Context, clusterID, procID int, attributes map[string]string, opts *EditJobOptions) error

EditJob edits attributes of an existing job This opens a QMGMT connection, edits the specified attributes, and commits the changes

func (*Schedd) EditJobAttributes

func (s *Schedd) EditJobAttributes(ctx context.Context, clusterID, procID int, attributes *classad.ClassAd, opts *EditJobOptions) error

EditJobAttributes edits attributes using ClassAd values instead of strings This is useful when you need to set complex ClassAd expressions or values

func (*Schedd) EditJobByID

func (s *Schedd) EditJobByID(ctx context.Context, jobID string, attributes map[string]string, opts *EditJobOptions) error

EditJobByID is a convenience method that parses a job ID string (e.g., "123.0") and calls EditJob

func (*Schedd) EditJobs

func (s *Schedd) EditJobs(ctx context.Context, constraint string, attributes map[string]string, opts *EditJobOptions) (int, error)

EditJobs edits attributes for multiple jobs matching a constraint This is more efficient than calling EditJob multiple times as it uses a single transaction

func (*Schedd) GetJobConnectInfo added in v0.0.11

func (s *Schedd) GetJobConnectInfo(ctx context.Context, clusterID, procID int) (*JobConnectInfo, error)

GetJobConnectInfo invokes the schedd's GET_JOB_CONNECT_INFO RPC for ClusterId.ProcId and returns the address of the starter and the claim id for an on-demand session. The schedd authenticates the caller and verifies they own the job before minting the session.

func (*Schedd) GetUserRecord added in v0.13.0

func (s *Schedd) GetUserRecord(ctx context.Context, user string) (*UserRecord, error)

GetUserRecord returns the record for one fully-qualified user, or nil when the schedd has no record of them.

A nil record is NOT a denial. The schedd creates records lazily on first submit, so a user who has only ever queried — or who is new — has no record at all. Callers gating access must treat nil as "no information".

func (*Schedd) HoldJobs

func (s *Schedd) HoldJobs(ctx context.Context, constraint string, reason string) (*JobActionResults, error)

HoldJobs holds jobs matching the constraint

func (*Schedd) Name added in v0.0.3

func (s *Schedd) Name() string

Name returns the schedd's name

func (*Schedd) OpenJobShell added in v0.0.11

func (s *Schedd) OpenJobShell(ctx context.Context, clusterID, procID int, opts *JobShellOptions) (*ssh.Client, error)

OpenJobShell is the end-to-end convenience: GET_JOB_CONNECT_INFO + START_SSHD + crypto/ssh handshake. Returns a live *ssh.Client. The caller owns it and must Close() to release the underlying TCP connection.

Briefly transient errors at the schedd are retried (up to ~30 s) — the same race the C++ condor_ssh_to_job tool retries through after a job first hits Running but before the startd has registered the starter address.

func (*Schedd) PeekJobOutput added in v0.0.12

func (s *Schedd) PeekJobOutput(ctx context.Context, cluster, proc int, req PeekRequest) (*PeekResult, error)

PeekJobOutput is the public entry point. It looks up the running job's starter, resumes the schedd-minted session, runs one STARTER_PEEK round, and returns whichever streams were requested.

func (*Schedd) Ping added in v0.0.4

func (s *Schedd) Ping(ctx context.Context) (*PingResult, error)

Ping performs a ping operation against the schedd daemon This is similar to condor_ping and provides information about authentication and authorization. It's useful for health checks and debugging security settings.

func (*Schedd) PingWithOptions added in v0.0.4

func (s *Schedd) PingWithOptions(ctx context.Context, opts *PingOptions) (*PingResult, error)

PingWithOptions performs a ping operation with optional permission checking

func (*Schedd) Query deprecated

func (s *Schedd) Query(ctx context.Context, constraint string, projection []string) ([]*classad.ClassAd, error)

Query queries the schedd for job advertisements constraint is a ClassAd constraint expression (use "true" to get all jobs) projection is a list of attributes to return (use nil to get all attributes)

Deprecated: Use QueryWithOptions for pagination and default limits/projections

func (*Schedd) QueryHistory added in v0.0.4

func (s *Schedd) QueryHistory(ctx context.Context, constraint string, projection []string) ([]*classad.ClassAd, error)

QueryHistory queries the schedd for job history records constraint is a ClassAd constraint expression (use "true" to get all records) projection is a list of attributes to return (use nil to get all attributes)

This method queries standard job history (completed jobs) by default. For epoch or transfer history, use QueryHistoryWithOptions.

func (*Schedd) QueryHistoryStream added in v0.0.4

func (s *Schedd) QueryHistoryStream(ctx context.Context, constraint string, opts *HistoryQueryOptions, streamOpts *StreamOptions) (<-chan HistoryAdResult, error)

QueryHistoryStream queries the schedd for history and streams ads through a channel Returns a channel and an error. If the error is non-nil, it indicates a problem before the request was sent (e.g., invalid parameters, connection failure). The channel will be closed when all ads have been sent or an error occurs during streaming.

func (*Schedd) QueryHistoryWithOptions added in v0.0.4

func (s *Schedd) QueryHistoryWithOptions(ctx context.Context, constraint string, opts *HistoryQueryOptions) ([]*classad.ClassAd, error)

QueryHistoryWithOptions queries the schedd for history records with options opts specifies query options including source type, limit, and projection Returns the matching history ads

func (*Schedd) QueryStartupLimits added in v0.0.6

func (s *Schedd) QueryStartupLimits(ctx context.Context, uuid, tag string) ([]*StartupLimit, error)

QueryStartupLimits queries startup rate limits from the schedd

Parameters:

  • ctx: Context for the operation (can include security config via WithSecurityConfig)
  • uuid: Optional UUID to filter results (empty string = all limits)
  • tag: Optional tag to filter results (empty string = all limits)

Returns:

  • Slice of startup limits matching the query
  • Error if the operation fails

Example:

// Get all limits
limits, err := schedd.QueryStartupLimits(ctx, "", "")

// Get specific limit by UUID
limits, err := schedd.QueryStartupLimits(ctx, "abc123", "")

// Get all limits with tag
limits, err := schedd.QueryStartupLimits(ctx, "", "gpu_limit")

func (*Schedd) QueryStream deprecated added in v0.0.4

func (s *Schedd) QueryStream(ctx context.Context, constraint string, projection []string, streamOpts *StreamOptions) (<-chan JobAdResult, error)

QueryStream queries the schedd and streams job ads through a channel Returns a channel and an error. If the error is non-nil, it indicates a problem before the request was sent (e.g., invalid parameters, connection failure). The channel will be closed when all ads have been sent or an error occurs during streaming. If cumulative time blocking on channel writes exceeds StreamOptions.WriteTimeout, an error is sent through the channel.

Deprecated: Use QueryStreamWithOptions for pagination and limit support

func (*Schedd) QueryStreamWithOptions added in v0.0.4

func (s *Schedd) QueryStreamWithOptions(ctx context.Context, constraint string, opts *QueryOptions, streamOpts *StreamOptions) (<-chan JobAdResult, error)

QueryStreamWithOptions queries the schedd with QueryOptions and streams job ads through a channel Returns a channel and an error. If the error is non-nil, it indicates a problem before the request was sent (e.g., invalid parameters, rate limit exceeded). This method supports server-side limits for better performance

func (*Schedd) QueryUserRecords added in v0.13.0

func (s *Schedd) QueryUserRecords(ctx context.Context, opts *UserRecordQueryOptions) (records []UserRecord, err error)

QueryUserRecords returns the schedd's user records matching opts.

The command is registered at READ authorization on the schedd side, so this needs no special privilege beyond what any query requires — in contrast to ENABLE_USERREC / DISABLE_USERREC, which are ADMINISTRATOR. That split is what makes these records usable as a revocation signal by an unprivileged service: an admin disables a user, and everything else can only observe it.

func (*Schedd) QueryWithOptions added in v0.0.4

func (s *Schedd) QueryWithOptions(ctx context.Context, constraint string, opts *QueryOptions) ([]*classad.ClassAd, *PageInfo, error)

QueryWithOptions queries the schedd for job advertisements with pagination and limits opts specifies query options including limit, projection, and pagination Returns the matching job ads and pagination info

func (*Schedd) QueueSuperUsers added in v0.13.0

func (s *Schedd) QueueSuperUsers(ctx context.Context) ([]string, error)

QueueSuperUsers returns the schedd's effective QUEUE_SUPER_USERS set, in the identity form the schedd compares against: each configured name is returned both bare and qualified with the schedd's UID_DOMAIN.

The qualification mirrors what the schedd does when it builds its own set (see the "Backward compatibility hack" in qmgmt.cpp): QUEUE_SUPER_USERS historically named OS users, while authenticated identities are "user@domain", so a configured "condor" also makes "condor@$(UID_DOMAIN)" a superuser. A caller comparing an authenticated identity against this set would otherwise never match.

This does NOT reproduce every alternate identity the schedd accepts — condor@child, condor@parent and condor@password are session-internal identities that no web caller will ever present, and PERSONAL_CONDOR_IS_ SUPER_USER adds the process owner in a way that is only observable inside the daemon. The set returned here is therefore a SUBSET of what the schedd will accept: a caller may conclude "not a superuser" for an identity the schedd would in fact allow. That direction is the safe one — it costs a fallback to a less specific identity, never an unearned privilege.

func (*Schedd) ReceiveJobSandbox

func (s *Schedd) ReceiveJobSandbox(ctx context.Context, constraint string, w io.Writer) <-chan error

ReceiveJobSandbox downloads job output files (sandbox) from the schedd for jobs matching the constraint. The files are written to a tar archive via the provided writer. This method starts the transfer in a goroutine and returns immediately. The caller should read from the returned channel to get the final result.

Protocol (based on DCSchedd::receiveJobSandbox in reference/dc_schedd.cpp):

  1. Connect to schedd and send TRANSFER_DATA_WITH_PERMS command
  2. Perform DC_AUTHENTICATE handshake
  3. Send version string (CondorVersion())
  4. Send constraint expression
  5. EOM
  6. Receive number of matching jobs (int)
  7. EOM
  8. For each job: a. Receive job ClassAd b. EOM c. Initialize FileTransfer with job ad d. Call FileTransfer.DownloadFiles() to receive files e. Files are sent using HTCondor's file transfer protocol
  9. Send OK reply (int = 0)
  10. EOM

constraint: ClassAd constraint expression to select jobs (e.g., "ClusterId == 123") w: Writer where the tar archive will be written Returns: A channel that will receive the error result (nil on success)

func (*Schedd) ReleaseJobs

func (s *Schedd) ReleaseJobs(ctx context.Context, constraint string, reason string) (*JobActionResults, error)

ReleaseJobs releases held jobs matching the constraint

func (*Schedd) RemoveJobs

func (s *Schedd) RemoveJobs(ctx context.Context, constraint string, reason string) (*JobActionResults, error)

RemoveJobs removes jobs matching the constraint constraint is a ClassAd constraint expression reason is an optional reason for the removal (can be empty string)

func (*Schedd) RemoveJobsByID

func (s *Schedd) RemoveJobsByID(ctx context.Context, ids []string, reason string) (*JobActionResults, error)

RemoveJobsByID removes specific jobs by their cluster.proc IDs ids is a slice of job IDs in "cluster.proc" format (e.g., []string{"123.0", "123.1"}) reason is an optional reason for the removal (can be empty string)

func (*Schedd) Reschedule added in v0.1.0

func (s *Schedd) Reschedule(ctx context.Context) error

Reschedule asks the schedd to push a fresh submitter ad to the collector and kick off a negotiation cycle. This is the wire-level equivalent of `condor_reschedule <schedd>`.

Why call this: after Schedd.Submit, the schedd doesn't immediately advertise a SubmitterAd; it waits SCHEDD_INTERVAL (default 300s) before its next collector update. The negotiator can't match the new job until a SubmitterAd arrives, so without Reschedule a fresh pool may take minutes to start the first job. condor_submit fires a reschedule itself; library callers must do the same.

Rate limiting: this client deliberately throttles successful reschedule requests to one every DefaultRescheduleInterval per schedd address (process-wide). The schedd treats reschedules as advisory anyway — it coalesces close-together requests — so dropping the duplicate on the client side is purely a courtesy. To bypass the limiter use RescheduleWithOptions with MinInterval = 0.

Errors: returns a non-nil error only when the connect/auth itself fails. A rate-limited skip returns nil; callers should treat Reschedule as advisory regardless. The context's deadline applies to the connect/auth attempt.

func (*Schedd) RescheduleWithOptions added in v0.1.0

func (s *Schedd) RescheduleWithOptions(ctx context.Context, opts *RescheduleOptions) error

RescheduleWithOptions is the configurable form of Reschedule. See the Reschedule doc for behavior; opts controls the rate limiter.

func (*Schedd) SpoolJobFilesFromFS

func (s *Schedd) SpoolJobFilesFromFS(ctx context.Context, jobAds []*classad.ClassAd, fsys fs.FS) error

SpoolJobFilesFromFS uploads input files to the schedd for the specified jobs. Files are read from the provided filesystem.

The input files to transfer are determined from each job ad's TransferInput attribute. If TransferInput is not present, an error is returned.

Protocol (based on DCSchedd::spoolJobFiles in reference/dc_schedd.cpp):

  1. Connect to schedd and send SPOOL_JOB_FILES_WITH_PERMS command
  2. Perform DC_AUTHENTICATE handshake
  3. Send version string (CondorVersion())
  4. Send number of jobs (int)
  5. EOM
  6. For each job, send PROC_ID structure (cluster, proc)
  7. EOM
  8. For each job: a. Initialize FileTransfer with job ad b. Call FileTransfer.UploadFiles() to send files c. Files are sent using HTCondor's file transfer protocol
  9. EOM
  10. Receive reply (int, 1 = success, 0 = failure)
  11. EOM

jobAds: Array of job ClassAds containing ClusterId, ProcId, and TransferInput fsys: Filesystem containing the files to upload Returns: error if the upload fails

func (*Schedd) SpoolJobFilesFromTar

func (s *Schedd) SpoolJobFilesFromTar(ctx context.Context, jobAds []*classad.ClassAd, r io.Reader) error

SpoolJobFilesFromTar uploads input files to the schedd for the specified jobs. Files are read from a tar archive.

Protocol: Same as SpoolJobFilesFromFS

The tar archive should be organized as:

  • For single job: files directly at root (no cluster.proc prefix)
  • For multiple jobs: cluster.proc/filename (e.g., "123.0/input.txt")

Files are spooled in the order they appear in the tar archive. Only files listed in the job's TransferInput are spooled. Files for jobs not in jobAds are ignored.

jobAds: Array of job ClassAds containing ClusterId, ProcId, and file transfer attributes r: Reader providing the tar archive Returns: error if the upload fails

func (*Schedd) Submit

func (s *Schedd) Submit(ctx context.Context, submitFileContent string) (string, error)

Submit submits a job to the schedd using an HTCondor submit file submitFileContent is the content of an HTCondor submit file Returns the cluster ID as a string

func (*Schedd) SubmitRemote

func (s *Schedd) SubmitRemote(ctx context.Context, submitFileContent string) (clusterID int, procAds []*classad.ClassAd, err error)

SubmitRemote submits jobs to the schedd with remote submission semantics. This method is designed for remote job submission with file spooling support.

Remote submission behavior: 1. Parses the submit file 2. Ensures ShouldTransferFiles is set to YES 3. Jobs start in HELD status with SpoolingInput hold reason (code 16) 4. Sets LeaveJobInQueue to keep completed jobs for 10 days for output retrieval 5. Submits the job to the schedd 6. Returns the cluster ID and proc ads for subsequent file spooling

The caller should then use SpoolJobFilesFromFS or SpoolJobFilesFromTar to upload input files.

func (*Schedd) WithConfig added in v0.20.0

func (s *Schedd) WithConfig(cfg *config.Config) *Schedd

WithConfig sets the HTCondor configuration this Schedd uses; see the note above. It also applies to the JobConnectInfo it returns.

func (*Schedd) WithRateLimitKey added in v0.20.1

func (s *Schedd) WithRateLimitKey(key string) *Schedd

WithRateLimitKey gives this client its own partition of the schedd query rate limiter: a global budget of its own and per-user budgets of its own, at the configured rates, instead of the budget every client sharing its configuration draws on. A server talking to many schedds keys each by the schedd's name, so one busy schedd cannot starve the others. Empty (the default) is the shared budget.

type ScheddTarget added in v0.12.8

type ScheddTarget struct {
	// Name is the schedd's name when SCHEDD_HOST was written as
	// name@hostname, otherwise empty.
	Name string
	// Host is the machine the schedd runs on. May carry a ":port"
	// suffix, in which case Address reports it as a directly dialable
	// address and no collector lookup is needed.
	Host string
}

ScheddTarget is what a SCHEDD_HOST setting points at. HTCondor documents the knob as "the host name of the machine where the condor_schedd is running for your pool", with the name included as name@hostname when that host sets SCHEDD_NAME or MASTER_NAME. It is undefined in most pools, so a defined value is a deliberate instruction to talk to that schedd rather than whichever one happens to be local or first in the collector.

func ParseScheddHost added in v0.12.8

func ParseScheddHost(value string) ScheddTarget

ParseScheddHost splits a SCHEDD_HOST value into its parts. An empty or whitespace-only value yields the zero ScheddTarget, whose IsSet reports false.

func (ScheddTarget) Address added in v0.12.8

func (t ScheddTarget) Address() string

Address returns a directly dialable address when SCHEDD_HOST included a port, and "" when the target still has to be looked up in the collector.

func (ScheddTarget) CollectorConstraint added in v0.12.8

func (t ScheddTarget) CollectorConstraint() string

CollectorConstraint returns the ClassAd constraint that selects this target's ScheddAd in the collector, or "" when the target names nothing to constrain on.

func (ScheddTarget) IsSet added in v0.12.8

func (t ScheddTarget) IsSet() bool

IsSet reports whether the target names anything.

type SecurityConfigRenewer added in v0.20.0

type SecurityConfigRenewer func(ctx context.Context) (*security.SecurityConfig, error)

SecurityConfigRenewer re-creates a caller's credential: a SecurityConfig like the one it was attached with, carrying a newly minted token.

It exists because the credential a server mints for a caller is meant for one request -- a minute or five -- while some of what a request starts outlives it: a stream that keeps polling, a watch shared by several viewers, a lease that removes a job when it runs out. Copying the request's token into those hands them a credential that expires under them. Copying the renewer instead lets them mint the caller's credential again, from the identity and authorization the original was minted for.

type ServiceStatus added in v0.0.6

type ServiceStatus struct {
	Service   string     `json:"service"`
	Handle    string     `json:"handle,omitempty"`
	Exists    bool       `json:"exists"`
	UpdatedAt *time.Time `json:"updated_at,omitempty"`
}

ServiceStatus describes the state of a service credential.

type SetAttributeFlags

type SetAttributeFlags = qmgmt.SetAttributeFlags

SetAttributeFlags controls behavior when setting job attributes. It aliases the shared codec type in the qmgmt package.

const (
	// SetAttributeNoAck indicates not to wait for acknowledgment when setting
	// attributes (SetAttribute_NoAck, bit 1<<1 in condor_qmgr.h).
	SetAttributeNoAck SetAttributeFlags = qmgmt.SetNoAck
)

type Startd added in v0.20.0

type Startd struct {
	// contains filtered or unexported fields
}

Startd is a client for one execution point's condor_startd. Today it speaks only the startd's remote-history protocol (GET_HISTORY, HTCondor 8.9.7+), which serves the per-job records the startd appends to its STARTD_HISTORY file as each job finishes on that machine. That file is the execution point's own view of what ran there -- it exists even for jobs whose submitting schedd is not ours, and it survives the schedd forgetting the job.

func NewStartd added in v0.20.0

func NewStartd(name string, address string) *Startd

NewStartd creates a new Startd instance. address can be a hostname:port or a sinful string like "<IP:PORT?addrs=...>".

func (*Startd) Address added in v0.20.0

func (s *Startd) Address() string

Address returns the startd's address.

func (*Startd) Name added in v0.20.0

func (s *Startd) Name() string

Name returns the startd's name.

func (*Startd) QueryHistory added in v0.20.0

func (s *Startd) QueryHistory(ctx context.Context, constraint string, projection []string) ([]*classad.ClassAd, error)

QueryHistory queries the startd for the job history records it wrote as jobs finished on that machine. constraint is a ClassAd constraint expression (use "true" or "" for all records); projection is the attributes to return (nil for condor_history's default set, []string{"*"} for every attribute).

func (*Startd) QueryHistoryStream added in v0.20.0

func (s *Startd) QueryHistoryStream(ctx context.Context, constraint string, opts *HistoryQueryOptions, streamOpts *StreamOptions) (<-chan HistoryAdResult, error)

QueryHistoryStream queries the startd's history and streams the records through a channel, which is closed when the query finishes or fails. A non-nil error means the query never started.

func (*Startd) QueryHistoryWithOptions added in v0.20.0

func (s *Startd) QueryHistoryWithOptions(ctx context.Context, constraint string, opts *HistoryQueryOptions) ([]*classad.ClassAd, error)

QueryHistoryWithOptions queries the startd's history with options. opts.Source is ignored -- the startd serves startd history and nothing else.

func (*Startd) WithConfig added in v0.20.0

func (s *Startd) WithConfig(cfg *config.Config) *Startd

WithConfig sets the HTCondor configuration this Startd uses; see the note above.

type StartupLimit added in v0.0.6

type StartupLimit struct {
	UUID           string  `json:"uuid"`
	Tag            string  `json:"tag"`
	Name           string  `json:"name,omitempty"`
	Expression     string  `json:"expression"`
	CostExpression string  `json:"cost_expression,omitempty"`
	RateCount      int     `json:"rate_count"`
	RateWindow     int     `json:"rate_window"` // seconds
	Burst          int     `json:"burst,omitempty"`
	MaxBurstCost   int     `json:"max_burst_cost,omitempty"`
	Expiration     int     `json:"expiration,omitempty"`      // seconds from creation
	ExpiresAt      int64   `json:"expires_at,omitempty"`      // Unix timestamp
	JobsAllowed    int64   `json:"jobs_allowed,omitempty"`    // Stats: jobs allowed
	CostAllowed    float64 `json:"cost_allowed,omitempty"`    // Stats: cost allowed
	JobsSkipped    int64   `json:"jobs_skipped,omitempty"`    // Stats: jobs skipped
	MatchesIgnored int64   `json:"matches_ignored,omitempty"` // Stats: matches ignored
	LastIgnored    int64   `json:"last_ignored,omitempty"`    // Stats: last time match ignored
	IgnoredUsers   string  `json:"ignored_users,omitempty"`   // Stats: comma-separated list
}

StartupLimit represents a startup rate limit in the schedd

type StartupLimitRequest added in v0.0.6

type StartupLimitRequest struct {
	UUID           string `json:"uuid,omitempty"`            // If provided, updates existing limit
	Tag            string `json:"tag"`                       // Required: unique tag identifier
	Name           string `json:"name,omitempty"`            // Optional: human-friendly name
	Expression     string `json:"expression"`                // Required: ClassAd expression to match jobs
	CostExpression string `json:"cost_expression,omitempty"` // Optional: expression for variable cost (default: 1)
	RateCount      int    `json:"rate_count"`                // Required: max jobs per window (0 = unlimited monitoring)
	RateWindow     int    `json:"rate_window"`               // Required: time window in seconds
	Burst          int    `json:"burst,omitempty"`           // Optional: extra capacity below zero
	MaxBurstCost   int    `json:"max_burst_cost,omitempty"`  // Optional: cap on single cost
	Expiration     int    `json:"expiration,omitempty"`      // Optional: expiration in seconds
}

StartupLimitRequest represents parameters for creating a startup limit

type StartupLimitResponse added in v0.0.6

type StartupLimitResponse struct {
	Status int    `json:"status"`          // 0 = success, -1 = error
	UUID   string `json:"uuid,omitempty"`  // UUID of created/updated limit
	Error  string `json:"error,omitempty"` // Error message if status != 0
}

StartupLimitResponse represents the response from creating a startup limit

type StreamOptions added in v0.0.4

type StreamOptions struct {
	// BufferSize is the number of ads to buffer in the channel (default: 100)
	BufferSize int
	// WriteTimeout is the maximum cumulative time spent blocking on channel writes (default: 5s)
	WriteTimeout time.Duration
}

StreamOptions configures streaming query behavior

func (*StreamOptions) ApplyStreamDefaults added in v0.0.4

func (o *StreamOptions) ApplyStreamDefaults() StreamOptions

ApplyStreamDefaults returns StreamOptions with defaults applied

type SubmitFile

type SubmitFile struct {
	// contains filtered or unexported fields
}

SubmitFile represents a parsed HTCondor submit file

func ParseSubmitFile

func ParseSubmitFile(r io.Reader) (*SubmitFile, error)

ParseSubmitFile parses a submit file from a reader. The parse cannot reach the local host: see SubmitParseOptions.AllowLocalAccess and ParseSubmitFileWithOptions for a parse on behalf of the local user.

func ParseSubmitFileWithOptions added in v0.12.8

func ParseSubmitFileWithOptions(r io.Reader, opts SubmitParseOptions) (*SubmitFile, error)

ParseSubmitFileWithOptions parses a submit file from a reader with explicit parse options.

func (*SubmitFile) MakeClusterAd

func (sf *SubmitFile) MakeClusterAd(clusterID int) (*classad.ClassAd, error)

MakeClusterAd creates a cluster ad with common attributes for all jobs This is part of late materialization - the cluster ad serves as a template

func (*SubmitFile) MakeJobAd

func (sf *SubmitFile) MakeJobAd(jobID JobID, queueVars map[string]string) (*classad.ClassAd, error)

MakeJobAd creates a ClassAd for a single job This is the main transformation from submit file to job ClassAd queueVars contains variable substitutions from the queue statement

func (*SubmitFile) MakeProcAd

func (sf *SubmitFile) MakeProcAd(clusterID int, procID int, queueVars map[string]string) (*classad.ClassAd, error)

MakeProcAd creates a proc-specific ad given a cluster ad template This is used in late materialization to create individual proc ads efficiently

func (*SubmitFile) Submit

func (sf *SubmitFile) Submit(clusterID int) (*SubmitResult, error)

Submit submits the jobs from this submit file Returns the cluster ID and number of procs created

func (*SubmitFile) SubmitLate

func (sf *SubmitFile) SubmitLate(clusterID int) (*SubmitResult, error)

SubmitLate performs late materialization submission This creates a cluster ad template and individual proc ads with only differing attributes This is more efficient for large job submissions

type SubmitIterator

type SubmitIterator interface {
	// Next advances to the next item and returns true if successful
	Next() bool
	// Values returns the current row's variable values
	Values() map[string]string
	// Count returns the total number of items
	Count() int
}

SubmitIterator provides iteration over queue items

type SubmitParseOptions added in v0.12.8

type SubmitParseOptions struct {
	// AllowLocalAccess lets the parse reach the host it runs on:
	// `include` and `include command` directives (the latter runs a
	// shell command), the $ENV() macro function, `queue ... from
	// <itemdata file>` and `queue ... matching <glob>`.
	//
	// Off by default, which is the setting a daemon parsing a submit
	// file it received over the network wants: none of these should
	// run with the daemon's identity on a remote caller's behalf —
	// `include command` alone would be command execution as the daemon
	// user. Set it for a submit file the local user wrote and that the
	// parse runs on that user's behalf, which is how condor_submit
	// reads one.
	AllowLocalAccess bool
}

SubmitParseOptions controls what a submit-file parse is allowed to do besides reading the text it was handed.

type SubmitResult

type SubmitResult struct {
	ClusterID int
	NumProcs  int
	ClusterAd *classad.ClassAd
	ProcAds   []*classad.ClassAd
}

SubmitResult contains the results of submitting jobs

type TestingT added in v0.0.4

type TestingT interface {
	Helper()
	Skip(...interface{})
	Skipf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
	Logf(format string, args ...interface{})
	Log(...interface{})
	TempDir() string
	Cleanup(func())
}

TestingT is an interface that matches the testing.T methods used by the test harness. This allows the harness to be used without directly depending on the testing package.

type TransferCommand

type TransferCommand int32

TransferCommand represents file transfer protocol commands. These match the HTCondor C++ TransferCommand enum from file_transfer.cpp.

const (
	// CommandFinished indicates transfer complete
	CommandFinished TransferCommand = 0

	// CommandXferFile transfers a file
	CommandXferFile TransferCommand = 1

	// CommandEnableEncryption enables encryption for subsequent transfers
	CommandEnableEncryption TransferCommand = 2

	// CommandDisableEncryption disables encryption for subsequent transfers
	CommandDisableEncryption TransferCommand = 3

	// CommandXferX509 transfers X.509 credential
	CommandXferX509 TransferCommand = 4

	// CommandDownloadURL downloads from URL
	CommandDownloadURL TransferCommand = 5

	// CommandMkdir creates directory
	CommandMkdir TransferCommand = 6

	// CommandOther represents plugin-specific commands
	CommandOther TransferCommand = 999
)

type TransferType added in v0.0.4

type TransferType string

TransferType specifies the type of file transfer to query

const (
	// TransferTypeInput queries input file transfers
	TransferTypeInput TransferType = "INPUT"

	// TransferTypeOutput queries output file transfers
	TransferTypeOutput TransferType = "OUTPUT"

	// TransferTypeCheckpoint queries checkpoint file transfers
	TransferTypeCheckpoint TransferType = "CHECKPOINT"
)

type UnmarkedOriginPolicy added in v0.20.0

type UnmarkedOriginPolicy int32

UnmarkedOriginPolicy says what an unclassified context may do when it reaches the daemon fallback.

It is the dial that stages the migration. Every context in a daemon this large cannot be classified in one change, and a gate that refused the unclassified ones on day one would refuse the daemon's own background work along with the requests it is aimed at. So: Allow is today's behaviour and the default, Warn is the same plus a report per unmarked fallback naming the call, and Deny is the fail-closed end state where forgetting to classify a context breaks loudly rather than quietly running as a queue superuser.

const (
	// UnmarkedAllow lets an unclassified context fall back to the daemon's
	// own configuration, as it always has.
	UnmarkedAllow UnmarkedOriginPolicy = iota
	// UnmarkedWarn allows the fallback and reports it, so the remaining
	// unclassified call sites can be enumerated from a running system
	// rather than guessed at from the source.
	UnmarkedWarn
	// UnmarkedDeny refuses an unclassified context the same way a
	// user-marked one is refused.
	UnmarkedDeny
)

type UserRecord added in v0.13.0

type UserRecord struct {
	// User is the fully-qualified user name, e.g. "alice@example.org".
	User string
	// Enabled reports whether the schedd will accept work from this user.
	//
	// It is a pointer because "the record does not say" is a distinct and
	// common answer from "false": the attribute is written when an admin
	// acts on the record (condor_qusers -enable/-disable), so an
	// auto-created record that nobody has touched may not carry it at all.
	// The schedd's own default for an unset value is enabled — its
	// JobQueueUserRec initializes `enabled=true`, and placementd reads the
	// attribute into a variable pre-set to 1 — so nil must be read as
	// "not disabled", never as a denial.
	Enabled *bool
	// DisableReason is the note an admin attached with
	// `condor_qusers -disable <user> -reason "..."`, when there is one.
	DisableReason string
	// Ad is the full record, for callers that want attributes beyond the
	// few lifted out above.
	Ad *classad.ClassAd
}

UserRecord is one of the schedd's per-user records, as returned by QUERY_USERREC_ADS. condor_qusers reads and writes the same records.

The schedd creates a record the first time a user submits, so the set of records is "users this schedd has seen", not "users who exist". A user with no record has simply never submitted here; that is not a statement about their standing. See Enabled.

func (*UserRecord) IsDisabled added in v0.13.0

func (u *UserRecord) IsDisabled() bool

IsDisabled reports whether the record affirmatively says this user is disabled. A record that does not mention Enabled returns false: absence of a statement is not a denial.

type UserRecordQueryOptions added in v0.13.0

type UserRecordQueryOptions struct {
	// Constraint is a ClassAd expression evaluated against each record,
	// e.g. `User == "alice@example.org"`.
	Constraint string
	// Projection limits the attributes returned. Empty returns everything.
	// Note that a projection which omits Enabled makes every record look
	// un-disabled, so include it whenever the answer matters.
	Projection []string
	// Limit caps the number of records returned. Zero or negative means
	// no limit.
	Limit int
}

UserRecordQueryOptions narrows a user-record query.

type WatchEvent added in v0.5.0

type WatchEvent struct {
	Kind   watch.Kind
	Key    string
	Ad     *classad.ClassAd
	Cursor []byte
}

WatchEvent is one item in a collector watch stream (see Collector.WatchAds). Its Kind mirrors the collections engine's event kinds, plus GoingAway:

Upsert  - Ad is the added/updated ad for Key
Delete  - Key was removed (Ad is nil)
Reset   - discard local state; an authoritative snapshot of Upserts follows
Synced  - end of the initial snapshot/catch-up; now live. Cursor is durable
Resync  - the live stream fell behind; reconnect with the last cursor
GoingAway - the server is shutting down; reconnect (with the last cursor),
          possibly to another collector

Cursor, when non-nil (Synced and live events), is an opaque token to persist and pass back to WatchAds to resume without a full replay.

Directories

Path Synopsis
Package authz implements HTCondor's host/user authorization: the ALLOW_<PERM>/DENY_<PERM> policy enforced by the C++ IpVerify class.
Package authz implements HTCondor's host/user authorization: the ALLOW_<PERM>/DENY_<PERM> policy enforced by the C++ IpVerify class.
Package classadlog provides functionality for reading and parsing HTCondor job_queue.log files.
Package classadlog provides functionality for reading and parsing HTCondor job_queue.log files.
Package config implements HTCondor configuration file parsing and management.
Package config implements HTCondor configuration file parsing and management.
Package daemon provides the common bootstrap for an HTCondor daemon written in Go: configuration + HTCondor-compatible logging, condor_master integration (DC_SET_READY readiness and the DC_CHILDALIVE keepalive loop), shared-port listener adoption from CONDOR_INHERIT, and a graceful run loop driven by SIGTERM/SIGINT (terminate) and SIGHUP (reconfigure).
Package daemon provides the common bootstrap for an HTCondor daemon written in Go: configuration + HTCondor-compatible logging, condor_master integration (DC_SET_READY readiness and the DC_CHILDALIVE keepalive loop), shared-port listener adoption from CONDOR_INHERIT, and a graceful run loop driven by SIGTERM/SIGINT (terminate) and SIGHUP (reconfigure).
Package droppriv provides privilege dropping functionality for Unix-like systems.
Package droppriv provides privilege dropping functionality for Unix-like systems.
Example demonstrating metricsd streaming API usage with background collection
Example demonstrating metricsd streaming API usage with background collection
classadlog_reader command
Package main provides an example of using the classadlog package to monitor HTCondor job queue logs.
Package main provides an example of using the classadlog package to monitor HTCondor job queue logs.
metrics_demo command
Package main demonstrates using the metricsd package to collect and export HTCondor metrics
Package main demonstrates using the metricsd package to collect and export HTCondor metrics
Package filetransfer implements the direction-neutral core of HTCondor's CEDAR file-transfer wire protocol (FileTransfer::DoUpload / DoDownload in src/condor_utils/file_transfer.cpp), factored out so that both the tool-side spool/receive paths (github.com/bbockelm/golang-htcondor Schedd methods) and the shadow-side transfer server (golang-ap internal/shadow) drive the exact same bytes.
Package filetransfer implements the direction-neutral core of HTCondor's CEDAR file-transfer wire protocol (FileTransfer::DoUpload / DoDownload in src/condor_utils/file_transfer.cpp), factored out so that both the tool-side spool/receive paths (github.com/bbockelm/golang-htcondor Schedd methods) and the shadow-side transfer server (golang-ap internal/shadow) drive the exact same bytes.
fuzz
config
Package fuzzconfig holds the differential fuzz harness comparing the native Go config parser (github.com/bbockelm/golang-htcondor/config) against HTCondor's reference C++ parser (libcondor_utils, via the oracle subpackage).
Package fuzzconfig holds the differential fuzz harness comparing the native Go config parser (github.com/bbockelm/golang-htcondor/config) against HTCondor's reference C++ parser (libcondor_utils, via the oracle subpackage).
config/oracle
Package oracle (stub build): without the `libcondor_utils` tag the C++ oracle is not linked, so the package still compiles (and `go vet ./...`, editors, and non-fuzz CI work) but ParseExpand is unavailable.
Package oracle (stub build): without the `libcondor_utils` tag the C++ oracle is not linked, so the package still compiles (and `go vet ./...`, editors, and non-fuzz CI work) but ParseExpand is unavailable.
Package idmap resolves an identity asserted by an OIDC provider to a local Unix account, by matching the token's subject against accounts' GECOS fields.
Package idmap resolves an identity asserted by an OIDC provider to a local Unix account, by matching the token's subject against accounts' GECOS fields.
internal
nullfile
Package nullfile identifies HTCondor's null file: the name a job ad carries for a standard stream that is not a real file.
Package nullfile identifies HTCondor's null file: the name a job ad carries for a standard stream that is not a real file.
privatefile
Package privatefile creates and tightens files that other local users must not read, such as the SQLite databases the daemons and the HTTP API server keep session state and keys in.
Package privatefile creates and tightens files that other local users must not read, such as the SQLite databases the daemons and the HTTP API server keep session state and keys in.
testdaemon command
Command testdaemon is a minimal HTCondor daemon built on the daemon framework, used by the daemon-under-condor_master integration test.
Command testdaemon is a minimal HTCondor daemon built on the daemon framework, used by the daemon-under-condor_master integration test.
Package jobid is the one place a job's identity becomes text and text becomes a job's identity.
Package jobid is the one place a job's identity becomes text and text becomes a job's identity.
Package jobqueue mirrors a schedd's job_queue.log into a watch-enabled collections.Collection, so job ads can be watched -- resumable, constraint filtered, coalesced -- with the same subscription model as the collector's ad watch.
Package jobqueue mirrors a schedd's job_queue.log into a watch-enabled collections.Collection, so job ads can be watched -- resumable, constraint filtered, coalesced -- with the same subscription model as the collector's ad watch.
localcredmon module
Package logging provides structured logging functionality for HTCondor applications.
Package logging provides structured logging functionality for HTCondor applications.
Package metricsd provides metrics collection for HTCondor daemons This is inspired by condor_gangliad but designed for more general metric export
Package metricsd provides metrics collection for HTCondor daemons This is inspired by condor_gangliad but designed for more general metric export
Package qmgmt holds the shared codec for HTCondor's QMGMT (queue management) wire protocol: the operation constants, the SetAttribute flag bits, and the reply framing convention.
Package qmgmt holds the shared codec for HTCondor's QMGMT (queue management) wire protocol: the operation constants, the SetAttribute flag bits, and the reply framing convention.
Package ratelimit provides rate limiting capabilities for HTCondor queries.
Package ratelimit provides rate limiting capabilities for HTCondor queries.
Package sandbox provides utilities for creating and extracting HTCondor job sandboxes.
Package sandbox provides utilities for creating and extracting HTCondor job sandboxes.
Package sessioncache persists a daemon's CEDAR security session cache so that clients can resume sessions across a restart instead of all re-authenticating at once.
Package sessioncache persists a daemon's CEDAR security session cache so that clients can resume sessions across a restart instead of all re-authenticating at once.
sqlite
Package sqlite provides an encrypted-at-rest SQLite implementation of sessioncache.SessionStore.
Package sqlite provides an encrypted-at-rest SQLite implementation of sessioncache.SessionStore.
Package sharedport implements the endpoint side of HTCondor's shared_port HTTP/HTTPS forwarding protocol.
Package sharedport implements the endpoint side of HTCondor's shared_port HTTP/HTTPS forwarding protocol.
Package startd implements the schedd->startd claim protocol: the CEDAR command exchange a schedd uses to REQUEST_CLAIM a slot, RELEASE_CLAIM it, and DEACTIVATE_CLAIM a running job on it.
Package startd implements the schedd->startd claim protocol: the CEDAR command exchange a schedd uses to REQUEST_CLAIM a slot, RELEASE_CLAIM it, and DEACTIVATE_CLAIM a running job on it.
Package syscalls implements the STARTER-side (client) senders for HTCondor's shadow<->starter remote-syscall protocol.
Package syscalls implements the STARTER-side (client) senders for HTCondor's shadow<->starter remote-syscall protocol.
Package userlog parses HTCondor user-log files (the file pointed at by `log = ...` in a submit description).
Package userlog parses HTCondor user-log files (the file pointed at by `log = ...` in a submit description).
Package version exposes build-time version information for the golang-htcondor binaries.
Package version exposes build-time version information for the golang-htcondor binaries.
webapi module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL