Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/data-sources/script_order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "coder_script_order Data Source - terraform-provider-coder"
subcategory: ""
description: |-
Use this data source to declare ordering constraints between coder_script resources on the same agent. It does not run scripts. Every script selected by run waits for every script selected by after.
Selectors are Terraform address strings (coder_script.name, coder_script.name[0], coder_script.name["key"], module.name), resolved by Coder relative to the module that declares the data source. Terraform and terraform validate do not check them; Coder reports unknown or unsupported selectors when the template is imported. All values must be known at plan time, and the data source needs no depends_on.
-> This data source is only available in Coder v2.39 and later. Older versions ignore it and run scripts concurrently.
---

# coder_script_order (Data Source)

Use this data source to declare ordering constraints between `coder_script` resources on the same agent. It does not run scripts. Every script selected by `run` waits for every script selected by `after`.

Selectors are Terraform address strings (`coder_script.name`, `coder_script.name[0]`, `coder_script.name["key"]`, `module.name`), resolved by Coder relative to the module that declares the data source. Terraform and `terraform validate` do not check them; Coder reports unknown or unsupported selectors when the template is imported. All values must be known at plan time, and the data source needs no `depends_on`.

-> This data source is only available in Coder v2.39 and later. Older versions ignore it and run scripts concurrently.

## Example Usage

```terraform
provider "coder" {}

data "coder_script_order" "startup_dependencies" {
rule {
run = ["coder_script.install_tools"]
after = ["coder_script.clone_repo"]
}

rule {
run = ["coder_script.configure_workspace"]
after = ["module.bootstrap"]
requires = "completion"
}

# module.cleanup has both start and stop scripts. phase keeps only the
# stop scripts and suppresses the inferred-phase warning.
rule {
run = ["coder_script.archive_logs"]
after = ["module.cleanup"]
phase = "stop"
}
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `rule` (Block List, Min: 1) One or more ordering rules. Rules from every `coder_script_order` in the template are merged into one graph per agent. (see [below for nested schema](#nestedblock--rule))

### Read-Only

- `id` (String) The ID of this resource.

<a id="nestedblock--rule"></a>
### Nested Schema for `rule`

Required:

- `after` (List of String) Selectors for the scripts that must finish before any `run` script starts.
- `run` (List of String) Selectors for the scripts that wait for every `after` script.

Optional:

- `phase` (String) Which lifecycle the rule applies to: `start` or `stop`. When omitted, Coder infers the phase from any `coder_script` selector in the rule and filters `module` selectors to that phase with a warning. If the rule has only `module` selectors and they expand to both start and stop scripts, Coder cannot infer the phase and rejects the rule at template import, so set `phase` explicitly in that case.
- `requires` (String) The outcome required from every `after` script before a `run` script starts. `success` (the default) skips the `run` scripts if any `after` script fails, times out or is skipped. `completion` runs them once every `after` script has finished, whatever the outcome.
7 changes: 5 additions & 2 deletions docs/resources/script.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
page_title: "coder_script Resource - terraform-provider-coder"
subcategory: ""
description: |-
Use this resource to run a script from an agent. When multiple scripts are assigned to the same agent, they are executed in parallel.
Use this resource to run a script on a workspace agent (coder_agent). When multiple scripts are assigned to the same workspace agent, they are executed in parallel unless a coder_script_order data source orders them.
-> Ordering with coder_script_order is only available in Coder v2.39 and later.
---

# coder_script (Resource)

Use this resource to run a script from an agent. When multiple scripts are assigned to the same agent, they are executed in parallel.
Use this resource to run a script on a workspace agent (`coder_agent`). When multiple scripts are assigned to the same workspace agent, they are executed in parallel unless a `coder_script_order` data source orders them.

-> Ordering with `coder_script_order` is only available in Coder v2.39 and later.

## Example Usage

Expand Down
22 changes: 22 additions & 0 deletions examples/data-sources/coder_script_order/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
provider "coder" {}

data "coder_script_order" "startup_dependencies" {
rule {
run = ["coder_script.install_tools"]
after = ["coder_script.clone_repo"]
}

rule {
run = ["coder_script.configure_workspace"]
after = ["module.bootstrap"]
requires = "completion"
}

# module.cleanup has both start and stop scripts. phase keeps only the
# stop scripts and suppresses the inferred-phase warning.
rule {
run = ["coder_script.archive_logs"]
after = ["module.cleanup"]
phase = "stop"
}
}
1 change: 1 addition & 0 deletions provider/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func TestExamples(t *testing.T) {

for _, testDir := range []string{
"coder_parameter",
"coder_script_order",
"coder_workspace_tags",
"coder_resources_monitoring",
} {
Expand Down
1 change: 1 addition & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func New() *schema.Provider {
"coder_workspace_owner": workspaceOwnerDataSource(),
"coder_workspace_preset": workspacePresetDataSource(),
"coder_task": taskDatasource(),
"coder_script_order": scriptOrderDataSource(),
},
ResourcesMap: map[string]*schema.Resource{
"coder_agent": agentResource(),
Expand Down
2 changes: 1 addition & 1 deletion provider/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func scriptResource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this resource to run a script from an agent. When multiple scripts are assigned to the same agent, they are executed in parallel.",
Description: "Use this resource to run a script on a workspace agent (`coder_agent`). When multiple scripts are assigned to the same workspace agent, they are executed in parallel unless a `coder_script_order` data source orders them.\n\n-> Ordering with `coder_script_order` is only available in Coder v2.39 and later.",
CreateContext: func(_ context.Context, rd *schema.ResourceData, _ interface{}) diag.Diagnostics {
rd.SetId(uuid.NewString())
runOnStart, _ := rd.Get("run_on_start").(bool)
Expand Down
104 changes: 104 additions & 0 deletions provider/script_order.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package provider

import (
"context"

"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

// Coder's provisioner accepts the same values. The provider and Coder
// share no Go types, so the plan JSON is the contract between them.
const (
scriptOrderRequiresSuccess = "success"
scriptOrderRequiresCompletion = "completion"

scriptOrderPhaseStart = "start"
scriptOrderPhaseStop = "stop"
)

func scriptOrderDataSource() *schema.Resource {
// Selector syntax is not checked here. Coder resolves selectors
// against the whole plan and reports unknown or unsupported ones at
// template import. A stricter check here could reject selectors that
// Coder accepts.
selectorSchema := func(description string) *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Description: description,
Required: true,
MinItems: 1,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
}
}

return &schema.Resource{
SchemaVersion: 0,

Description: "Use this data source to declare ordering constraints between `coder_script` " +
"resources on the same agent. It does not run scripts. Every script selected by " +
"`run` waits for every script selected by `after`.\n\n" +
"Selectors are Terraform address strings (`coder_script.name`, " +
"`coder_script.name[0]`, `coder_script.name[\"key\"]`, `module.name`), resolved " +
"by Coder relative to the module that declares the data source. Terraform and " +
"`terraform validate` do not check them; Coder reports unknown or unsupported " +
"selectors when the template is imported. All values must be known at plan time, " +
Comment thread
BobbyHo marked this conversation as resolved.
Outdated
"and the data source needs no `depends_on`.\n\n" +
"-> This data source is only available in Coder v2.39 and later. Older versions " +
"ignore it and run scripts concurrently.",
ReadContext: func(_ context.Context, rd *schema.ResourceData, _ any) diag.Diagnostics {
rd.SetId(uuid.NewString())
return nil
},
Schema: map[string]*schema.Schema{
"rule": {
Type: schema.TypeList,
Description: "One or more ordering rules. Rules from every `coder_script_order` in the template are merged into one graph per agent.",
Required: true,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"run": selectorSchema("Selectors for the scripts that wait for every `after` script."),
"after": selectorSchema("Selectors for the scripts that must finish before any `run` script starts."),
"requires": {
Type: schema.TypeString,
Description: "The outcome required from every `after` script before a `run` script starts. " +
"`success` (the default) skips the `run` scripts if any `after` script fails, times out or is skipped. " +
"`completion` runs them once every `after` script has finished, whatever the outcome.",
Optional: true,
Default: scriptOrderRequiresSuccess,
ValidateFunc: validation.StringInSlice([]string{
scriptOrderRequiresSuccess,
scriptOrderRequiresCompletion,
}, false),
},
"phase": {
Type: schema.TypeString,
Description: "Which lifecycle the rule applies to: `start` or `stop`. " +
Comment thread
BobbyHo marked this conversation as resolved.
"When omitted, Coder infers the phase from any `coder_script` selector in the rule " +
"and filters `module` selectors to that phase with a warning. " +
"If the rule has only `module` selectors and they expand to both start and stop " +
"scripts, Coder cannot infer the phase and rejects the rule at template import, " +
"so set `phase` explicitly in that case.",
Optional: true,
// No default on purpose. Coder infers the phase when
// this is unset, warns when inference filtered a
// module selector, and rejects a module-only rule
// that spans both phases. A default would hide all
// three.
ValidateFunc: validation.StringInSlice([]string{
scriptOrderPhaseStart,
scriptOrderPhaseStop,
}, false),
},
},
},
},
},
}
}
Loading
Loading