Terraform · Arazzo Workflow

Terraform Find and Cancel a Stuck Run

Version 1.0.0

Locate an in-flight run on a workspace, cancel it, and unlock the workspace.

1 workflow 1 source API 1 provider
View Spec View on GitHub Infrastructure As CodeCloud InfrastructureDevOpsOpen SourceHashiCorpArazzoWorkflows

Provider

terraform

Workflows

cancel-stuck-run
Cancel an in-progress run on a workspace and release the workspace lock.
Lists the workspace's runs filtered to an in-flight status, reads the newest match, cancels it, waits for the cancellation to settle, and unlocks the workspace.
5 steps inputs: cancelComment, runStatusFilter, workspaceId outputs: cancelledRunId, finalStatus, workspaceLocked
1
findInFlightRun
ListWorkspaceRuns
List the workspace's runs filtered to the supplied in-flight status, newest first, taking only the most recent match.
2
readRun
GetRun
Read the matched run to confirm it is genuinely still in flight and has not settled on its own since the list call.
3
cancelRun
CancelRun
Cancel the in-progress run, recording why it was cancelled so the run history explains the intervention.
4
pollCancellation
GetRun
Poll the run until the cancellation is reflected in its status, repeating while the run is still winding down.
5
unlockWorkspace
UnlockWorkspace
Unlock the workspace so the next run can be queued, since a cancelled run can leave the workspace locked behind it.

Source API Descriptions

Arazzo Workflow Specification

Raw ↑
arazzo: 1.0.1
info:
  title: Terraform Find and Cancel a Stuck Run
  summary: Locate an in-flight run on a workspace, cancel it, and unlock the workspace.
  description: >-
    An operations runbook for the most common HCP Terraform incident: a run wedged
    in planning or applying that is holding a workspace hostage. The workflow finds
    the in-flight run on the workspace, reads it to confirm it is genuinely still
    running, cancels it, polls until the cancellation lands, and unlocks the
    workspace so the next run can proceed. Every step spells out its request inline
    so the flow can be read and executed without opening the underlying OpenAPI
    description.
  version: 1.0.0
sourceDescriptions:
- name: hcpTerraformApi
  url: ../openapi/hcp-terraform-openapi.yml
  type: openapi
workflows:
- workflowId: cancel-stuck-run
  summary: Cancel an in-progress run on a workspace and release the workspace lock.
  description: >-
    Lists the workspace's runs filtered to an in-flight status, reads the newest
    match, cancels it, waits for the cancellation to settle, and unlocks the
    workspace.
  inputs:
    type: object
    required:
    - workspaceId
    - runStatusFilter
    properties:
      workspaceId:
        type: string
        description: The workspace identifier holding the stuck run.
      runStatusFilter:
        type: string
        description: The run status to hunt for (e.g. "planning", "applying", "pending").
      cancelComment:
        type: string
        description: The comment recorded against the cancellation for the audit trail.
  steps:
  - stepId: findInFlightRun
    description: >-
      List the workspace's runs filtered to the supplied in-flight status, newest
      first, taking only the most recent match.
    operationId: ListWorkspaceRuns
    parameters:
    - name: workspace_id
      in: path
      value: $inputs.workspaceId
    - name: filter[status]
      in: query
      value: $inputs.runStatusFilter
    - name: page[number]
      in: query
      value: 1
    - name: page[size]
      in: query
      value: 1
    successCriteria:
    - condition: $statusCode == 200
    outputs:
      stuckRunId: $response.body#/data/0/id
    onSuccess:
    - name: foundStuckRun
      type: goto
      stepId: readRun
      criteria:
      - context: $response.body
        condition: $.data.length > 0
        type: jsonpath
    - name: nothingStuck
      type: end
      criteria:
      - context: $response.body
        condition: $.data.length == 0
        type: jsonpath
  - stepId: readRun
    description: >-
      Read the matched run to confirm it is genuinely still in flight and has not
      settled on its own since the list call.
    operationId: GetRun
    parameters:
    - name: run_id
      in: path
      value: $steps.findInFlightRun.outputs.stuckRunId
    successCriteria:
    - condition: $statusCode == 200
    outputs:
      runId: $response.body#/data/id
      status: $response.body#/data/attributes/status
      message: $response.body#/data/attributes/message
  - stepId: cancelRun
    description: >-
      Cancel the in-progress run, recording why it was cancelled so the run history
      explains the intervention.
    operationId: CancelRun
    parameters:
    - name: run_id
      in: path
      value: $steps.readRun.outputs.runId
    requestBody:
      contentType: application/vnd.api+json
      payload:
        comment: $inputs.cancelComment
    successCriteria:
    - condition: $statusCode == 202
  - stepId: pollCancellation
    description: >-
      Poll the run until the cancellation is reflected in its status, repeating
      while the run is still winding down.
    operationId: GetRun
    parameters:
    - name: run_id
      in: path
      value: $steps.readRun.outputs.runId
    successCriteria:
    - condition: $statusCode == 200
    outputs:
      finalStatus: $response.body#/data/attributes/status
    onSuccess:
    - name: cancelled
      type: goto
      stepId: unlockWorkspace
      criteria:
      - context: $response.body
        condition: $.data.attributes.status in ["canceled", "force_canceled", "discarded"]
        type: jsonpath
    - name: stillCancelling
      type: retry
      stepId: pollCancellation
      retryAfter: 5
      retryLimit: 60
      criteria:
      - context: $response.body
        condition: $.data.attributes.status in ["pending", "fetching", "planning", "applying"]
        type: jsonpath
  - stepId: unlockWorkspace
    description: >-
      Unlock the workspace so the next run can be queued, since a cancelled run can
      leave the workspace locked behind it.
    operationId: UnlockWorkspace
    parameters:
    - name: workspace_id
      in: path
      value: $inputs.workspaceId
    successCriteria:
    - condition: $statusCode == 200
    outputs:
      locked: $response.body#/data/attributes/locked
  outputs:
    cancelledRunId: $steps.readRun.outputs.runId
    finalStatus: $steps.pollCancellation.outputs.finalStatus
    workspaceLocked: $steps.unlockWorkspace.outputs.locked