diff --git a/clicommand/lock_acquire.go b/clicommand/lock_acquire.go index 58a13a3aad..e515ea80f9 100644 --- a/clicommand/lock_acquire.go +++ b/clicommand/lock_acquire.go @@ -20,6 +20,12 @@ Description: forever) until it can acquire the lock, if the lock is already held by another process. If multiple processes are waiting for the same lock, there is no ordering guarantee of which one will be given the lock next. + + To prevent separate processes unlocking each other, the output from ′lock + acquire′ should be stored, and passed to ′lock release′. + + Note that this subcommand is only available when an agent has been started + with the ′agent-api′ experiment enabled. Examples: diff --git a/clicommand/lock_do.go b/clicommand/lock_do.go index aaff25b0cf..5c0811eae5 100644 --- a/clicommand/lock_do.go +++ b/clicommand/lock_do.go @@ -20,6 +20,9 @@ Description: wait for completion of some shared work, where only one process should do the work. + Note that this subcommand is only available when an agent has been started + with the ′agent-api′ experiment enabled. + ′lock do′ will do one of two things: - Print 'do'. The calling process should proceed to do the work and then diff --git a/clicommand/lock_done.go b/clicommand/lock_done.go index 83286ccb46..08c7c0335d 100644 --- a/clicommand/lock_done.go +++ b/clicommand/lock_done.go @@ -17,6 +17,9 @@ const lockDoneHelpDescription = `Usage: Description: Completes a do-once lock. This should only be used by the process performing the work. + + Note that this subcommand is only available when an agent has been started + with the ′agent-api′ experiment enabled. Examples: diff --git a/clicommand/lock_get.go b/clicommand/lock_get.go index fbd4dfb162..a15d5467c9 100644 --- a/clicommand/lock_get.go +++ b/clicommand/lock_get.go @@ -12,12 +12,15 @@ import ( const lockGetHelpDescription = `Usage: - buildkite-agent lock get [key] + buildkite-agent lock get [key] Description: Retrieves the value of a lock key. Any key not in use returns an empty string. + Note that this subcommand is only available when an agent has been started + with the ′agent-api′ experiment enabled. + ′lock get′ is generally only useful for inspecting lock state, as the value can change concurrently. To acquire or release a lock, use ′lock acquire′ and ′lock release′. diff --git a/clicommand/lock_release.go b/clicommand/lock_release.go index 99abf9f0c1..24cea89b60 100644 --- a/clicommand/lock_release.go +++ b/clicommand/lock_release.go @@ -12,11 +12,16 @@ import ( const lockReleaseHelpDescription = `Usage: - buildkite-agent lock release [key] + buildkite-agent lock release [key] [token] Description: Releases the lock for the given key. This should only be called by the - process that acquired the lock. + process that acquired the lock. To help prevent different processes unlocking + each other unintentionally, the output from ′lock acquire′ is required as the + second argument. + + Note that this subcommand is only available when an agent has been started + with the ′agent-api′ experiment enabled. Examples: diff --git a/lock/lock.go b/lock/lock.go index 922918d6e7..7ccbd389f2 100644 --- a/lock/lock.go +++ b/lock/lock.go @@ -55,6 +55,10 @@ func (c *Client) Locker(key string) sync.Locker { // token or an error. The token must be passed to Unlock in order to unlock the // lock later on. func (c *Client) Lock(ctx context.Context, key string) (string, error) { + // The token generation only has to avoid making the same token twice to + // prevent separate processes unlocking each other. + // Using crypto/rand to generate 16 bytes is possibly overkill - it's not a + // goal to be cryptographically secure - but ensures the result. otp := make([]byte, 16) if _, err := rand.Read(otp); err != nil { return "", err