diff --git a/README.md b/README.md index cbec7099..151a7299 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,39 @@ # terraform-provider-coder -See [Coder](https://github.com/coder/coder). +Terraform provider for [Coder](https://github.com/coder/coder). + +### Developing + +Follow the instructions outlined in the [Terraform documentation](https://developer.hashicorp.com/terraform/cli/config/config-file#development-overrides-for-provider-developers) +to setup your local Terraform to use your local version rather than the registry version. + +1. Create a file named `.terraformrc` in your `$HOME` directory +2. Add the following content: + ```hcl + provider_installation { + # Override the coder/coder provider to use your local version + dev_overrides { + "coder/coder" = "/path/to/terraform-provider-coder" + } + + # For all other providers, install them directly from their origin provider + # registries as normal. If you omit this, Terraform will _only_ use + # the dev_overrides block, and so no other providers will be available. + direct {} + } + ``` +3. (optional, but recommended) Validate your configuration: + 1. Create a new `main.tf` file and include: + ```hcl + terraform { + required_providers { + coder = { + source = "coder/coder" + } + } + } + ``` + 2. Run `terraform init` and observe a warning like `Warning: Provider development overrides are in effect` +4. Run `go build -o terraform-provider-coder` to build the provider binary, which Terraform will try locate and execute +5. All local Terraform runs will now use your local provider! +6. _**NOTE**: we vendor in this provider into `github.com/coder/coder`, so if you're testing with a local clone then you should also run `go mod edit -replace github.com/coder/terraform-provider-coder=/path/to/terraform-provider-coder` in your clone._ \ No newline at end of file diff --git a/examples/resources/coder_parameter/resource.tf b/examples/resources/coder_parameter/resource.tf index 3c674f1c..4efc3320 100644 --- a/examples/resources/coder_parameter/resource.tf +++ b/examples/resources/coder_parameter/resource.tf @@ -84,4 +84,34 @@ data "coder_parameter" "users" { display_name = "System users" type = "list(string)" default = jsonencode(["root", "user1", "user2"]) +} + +data "coder_parameter" "home_volume_size" { + name = "Home Volume Size" + description = <<-EOF + How large should your home volume be? + EOF + type = "number" + default = 30 + mutable = true + order = 3 + + option { + name = "30GB" + value = 30 + } + + option { + name = "60GB" + value = 60 + } + + option { + name = "100GB" + value = 100 + } + + validation { + monotonic = "increasing" + } } \ No newline at end of file diff --git a/provider/parameter.go b/provider/parameter.go index f4a31b7f..12dbc019 100644 --- a/provider/parameter.go +++ b/provider/parameter.go @@ -231,12 +231,11 @@ func parameterDataSource() *schema.Resource { }, }, "option": { - Type: schema.TypeList, - Description: "Each \"option\" block defines a value for a user to select from.", - ForceNew: true, - Optional: true, - MaxItems: 64, - ConflictsWith: []string{"validation"}, + Type: schema.TypeList, + Description: "Each \"option\" block defines a value for a user to select from.", + ForceNew: true, + Optional: true, + MaxItems: 64, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { @@ -276,11 +275,10 @@ func parameterDataSource() *schema.Resource { }, }, "validation": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "Validate the input of a parameter.", - ConflictsWith: []string{"option"}, + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Validate the input of a parameter.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "min": { @@ -410,6 +408,9 @@ func (v *Validation) Valid(typ, value string) error { if !v.MaxDisabled { return fmt.Errorf("a max cannot be specified for a %s type", typ) } + if v.Monotonic != "" { + return fmt.Errorf("monotonic validation can only be specified for number types, not %s types", typ) + } } if typ != "string" && v.Regex != "" { return fmt.Errorf("a regex cannot be specified for a %s type", typ) diff --git a/provider/parameter_test.go b/provider/parameter_test.go index e60c96f7..05d3604b 100644 --- a/provider/parameter_test.go +++ b/provider/parameter_test.go @@ -73,7 +73,7 @@ func TestParameter(t *testing.T) { } }, }, { - Name: "ValidationWithOptions", + Name: "RegexValidationWithOptions", Config: ` data "coder_parameter" "region" { name = "Region" @@ -88,7 +88,23 @@ func TestParameter(t *testing.T) { } } `, - ExpectError: regexp.MustCompile("conflicts with option"), + ExpectError: regexp.MustCompile("a regex cannot be specified for a number type"), + }, { + Name: "MonotonicValidationWithNonNumberType", + Config: ` + data "coder_parameter" "region" { + name = "Region" + type = "string" + option { + name = "1" + value = "1" + } + validation { + monotonic = "increasing" + } + } + `, + ExpectError: regexp.MustCompile("monotonic validation can only be specified for number types, not string types"), }, { Name: "ValidationRegexMissingError", Config: ` @@ -424,6 +440,54 @@ data "coder_parameter" "region" { require.Equal(t, expected, state.Primary.Attributes[key]) } }, + }, { + Name: "NumberValidation_MonotonicWithOptions", + Config: ` + data "coder_parameter" "region" { + name = "Region" + type = "number" + description = <<-EOF + Always pick a larger region. + EOF + default = 1 + + option { + name = "Small" + value = 1 + } + + option { + name = "Medium" + value = 2 + } + + option { + name = "Large" + value = 3 + } + + validation { + monotonic = "increasing" + } + } + `, + Check: func(state *terraform.ResourceState) { + for key, expected := range map[string]any{ + "name": "Region", + "type": "number", + "validation.#": "1", + "option.0.name": "Small", + "option.0.value": "1", + "option.1.name": "Medium", + "option.1.value": "2", + "option.2.name": "Large", + "option.2.value": "3", + "default": "1", + "validation.0.monotonic": "increasing", + } { + require.Equal(t, expected, state.Primary.Attributes[key]) + } + }, }, { Name: "NumberValidation_Min", Config: `