Skip to content

feat: annotate resources withSchemaVersion #244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 25, 2024
Merged
Changes from all 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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -32,4 +32,7 @@ website/vendor
!command/test-fixtures/**/.terraform/

# Keep windows files with windows line endings
*.winfile eol=crlf
*.winfile eol=crlf

# Binary
terraform-provider-coder
2 changes: 2 additions & 0 deletions integration/integration_test.go
Original file line number Diff line number Diff line change
@@ -164,7 +164,9 @@ func setup(ctx context.Context, t *testing.T, name string) string {
"CODER_ACCESS_URL=" + localURL, // Set explicitly to avoid creating try.coder.app URLs.
"CODER_IN_MEMORY=true", // We don't necessarily care about real persistence here.
"CODER_TELEMETRY_ENABLE=false", // Avoid creating noise.
"CODER_VERBOSE=TRUE", // Debug logging.
"TF_CLI_CONFIG_FILE=/tmp/integration.tfrc", // Our custom tfrc from above.
"TF_LOG=DEBUG", // Debug logging in Terraform provider
},
Labels: map[string]string{},
}, &container.HostConfig{
7 changes: 5 additions & 2 deletions provider/agent.go
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@ package provider
import (
"context"
"fmt"
"os"
"reflect"
"strings"

@@ -12,10 +11,14 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"golang.org/x/xerrors"

"github.com/coder/terraform-provider-coder/provider/helpers"
)

func agentResource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this resource to associate an agent.",
CreateContext: func(_ context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
// This should be a real authentication token!
@@ -363,7 +366,7 @@ func updateInitScript(resourceData *schema.ResourceData, i interface{}) diag.Dia
if err != nil {
return diag.Errorf("parse access url: %s", err)
}
script := os.Getenv(fmt.Sprintf("CODER_AGENT_SCRIPT_%s_%s", operatingSystem, arch))
script := helpers.OptionalEnv(fmt.Sprintf("CODER_AGENT_SCRIPT_%s_%s", operatingSystem, arch))
if script != "" {
script = strings.ReplaceAll(script, "${ACCESS_URL}", accessURL.String())
script = strings.ReplaceAll(script, "${AUTH_TYPE}", auth)
2 changes: 2 additions & 0 deletions provider/app.go
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@ var (

func appResource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this resource to define shortcuts to access applications in a workspace.",
CreateContext: func(c context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
resourceData.SetId(uuid.NewString())
2 changes: 2 additions & 0 deletions provider/env.go
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@ import (

func envResource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: `Use this resource to set an environment variable in a workspace. Note that this resource cannot be used to overwrite existing environment variables set on the "coder_agent" resource.`,
CreateContext: func(_ context.Context, rd *schema.ResourceData, _ interface{}) diag.Diagnostics {
rd.SetId(uuid.NewString())
7 changes: 5 additions & 2 deletions provider/externalauth.go
Original file line number Diff line number Diff line change
@@ -3,15 +3,18 @@ package provider
import (
"context"
"fmt"
"os"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/coder/terraform-provider-coder/provider/helpers"
)

// externalAuthDataSource returns a schema for an external authentication data source.
func externalAuthDataSource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this data source to require users to authenticate with an external service prior to workspace creation. This can be used to pre-authenticate external services in a workspace. (e.g. gcloud, gh, docker, etc)",
ReadContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
id, ok := rd.Get("id").(string)
@@ -20,7 +23,7 @@ func externalAuthDataSource() *schema.Resource {
}
rd.SetId(id)

accessToken := os.Getenv(ExternalAuthAccessTokenEnvironmentVariable(id))
accessToken := helpers.OptionalEnv(ExternalAuthAccessTokenEnvironmentVariable(id))
rd.Set("access_token", accessToken)
return nil
},
7 changes: 5 additions & 2 deletions provider/gitauth.go
Original file line number Diff line number Diff line change
@@ -3,15 +3,18 @@ package provider
import (
"context"
"fmt"
"os"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/coder/terraform-provider-coder/provider/helpers"
)

// gitAuthDataSource returns a schema for a Git authentication data source.
func gitAuthDataSource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

DeprecationMessage: "Use the `coder_external_auth` data source instead.",
Description: "Use this data source to require users to authenticate with a Git provider prior to workspace creation. This can be used to perform an authenticated `git clone` in startup scripts.",
ReadContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
@@ -25,7 +28,7 @@ func gitAuthDataSource() *schema.Resource {
}
rd.SetId(id)

accessToken := os.Getenv(GitAuthAccessTokenEnvironmentVariable(id))
accessToken := helpers.OptionalEnv(GitAuthAccessTokenEnvironmentVariable(id))
rd.Set("access_token", accessToken)

return nil
31 changes: 31 additions & 0 deletions provider/helpers/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package helpers

import (
"fmt"
"os"
)

// RequireEnv requires environment variable to be present.
func RequireEnv(name string) (string, error) {
val := os.Getenv(name)
if val == "" {
return "", fmt.Errorf("%s is required", name)
}
return val, nil
}

// OptionalEnv returns the value for environment variable if it exists,
// otherwise returns an empty string.
func OptionalEnv(name string) string {
return OptionalEnvOrDefault(name, "")
}

// OptionalEnvOrDefault returns the value for environment variable if it exists,
// otherwise returns the default value.
func OptionalEnvOrDefault(name, defaultValue string) string {
val := os.Getenv(name)
if val == "" {
return defaultValue
}
return val
}
2 changes: 2 additions & 0 deletions provider/metadata.go
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@ import (

func metadataResource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this resource to attach metadata to a resource. They will be " +
"displayed in the Coder dashboard.",
CreateContext: func(c context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
2 changes: 2 additions & 0 deletions provider/parameter.go
Original file line number Diff line number Diff line change
@@ -63,6 +63,8 @@ type Parameter struct {

func parameterDataSource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this data source to configure editable options for workspaces.",
ReadContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
rd.SetId(uuid.NewString())
2 changes: 2 additions & 0 deletions provider/provisioner.go
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@ import (

func provisionerDataSource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this data source to get information about the Coder provisioner.",
ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
rd.SetId(uuid.NewString())
2 changes: 2 additions & 0 deletions provider/script.go
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ var ScriptCRONParser = cron.NewParser(cron.Second | cron.Minute | cron.Hour | cr

func scriptResource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this resource to run a script from an agent.",
CreateContext: func(_ context.Context, rd *schema.ResourceData, _ interface{}) diag.Diagnostics {
rd.SetId(uuid.NewString())
54 changes: 18 additions & 36 deletions provider/workspace.go
Original file line number Diff line number Diff line change
@@ -3,44 +3,38 @@ package provider
import (
"context"
"encoding/json"
"os"
"reflect"
"strconv"

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

"github.com/coder/terraform-provider-coder/provider/helpers"
)

func workspaceDataSource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this data source to get information for the active workspace build.",
ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
transition := os.Getenv("CODER_WORKSPACE_TRANSITION")
if transition == "" {
// Default to start!
transition = "start"
}
transition := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_TRANSITION", "start") // Default to start!
_ = rd.Set("transition", transition)

count := 0
if transition == "start" {
count = 1
}
_ = rd.Set("start_count", count)

owner := os.Getenv("CODER_WORKSPACE_OWNER")
if owner == "" {
owner = "default"
}
owner := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER", "default")
_ = rd.Set("owner", owner)

ownerEmail := os.Getenv("CODER_WORKSPACE_OWNER_EMAIL")
if ownerEmail == "" {
ownerEmail = "[email protected]"
}
ownerEmail := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER_EMAIL", "[email protected]")
_ = rd.Set("owner_email", ownerEmail)

ownerGroupsText := os.Getenv("CODER_WORKSPACE_OWNER_GROUPS")
ownerGroupsText := helpers.OptionalEnv("CODER_WORKSPACE_OWNER_GROUPS")
var ownerGroups []string
if ownerGroupsText != "" {
err := json.Unmarshal([]byte(ownerGroupsText), &ownerGroups)
@@ -50,43 +44,31 @@ func workspaceDataSource() *schema.Resource {
}
_ = rd.Set("owner_groups", ownerGroups)

ownerName := os.Getenv("CODER_WORKSPACE_OWNER_NAME")
if ownerName == "" {
ownerName = "default"
}
ownerName := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER_NAME", "default")
_ = rd.Set("owner_name", ownerName)

ownerID := os.Getenv("CODER_WORKSPACE_OWNER_ID")
if ownerID == "" {
ownerID = uuid.Nil.String()
}
ownerID := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER_ID", uuid.Nil.String())
_ = rd.Set("owner_id", ownerID)

ownerOIDCAccessToken := os.Getenv("CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN")
ownerOIDCAccessToken := helpers.OptionalEnv("CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN")
_ = rd.Set("owner_oidc_access_token", ownerOIDCAccessToken)

name := os.Getenv("CODER_WORKSPACE_NAME")
if name == "" {
name = "default"
}
name := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_NAME", "default")
rd.Set("name", name)

sessionToken := os.Getenv("CODER_WORKSPACE_OWNER_SESSION_TOKEN")
sessionToken := helpers.OptionalEnv("CODER_WORKSPACE_OWNER_SESSION_TOKEN")
_ = rd.Set("owner_session_token", sessionToken)

id := os.Getenv("CODER_WORKSPACE_ID")
if id == "" {
id = uuid.NewString()
}
id := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_ID", uuid.NewString())
rd.SetId(id)

templateID := os.Getenv("CODER_WORKSPACE_TEMPLATE_ID")
templateID := helpers.OptionalEnv("CODER_WORKSPACE_TEMPLATE_ID") // FIXME switch to `helpers.RequireEnv(...)`
_ = rd.Set("template_id", templateID)

templateName := os.Getenv("CODER_WORKSPACE_TEMPLATE_NAME")
templateName := helpers.OptionalEnv("CODER_WORKSPACE_TEMPLATE_NAME") // FIXME switch to `helpers.RequireEnv(...)`
_ = rd.Set("template_name", templateName)

templateVersion := os.Getenv("CODER_WORKSPACE_TEMPLATE_VERSION")
templateVersion := helpers.OptionalEnv("CODER_WORKSPACE_TEMPLATE_VERSION") // FIXME switch to `helpers.RequireEnv(...)`
_ = rd.Set("template_version", templateVersion)

config, valid := i.(config)
2 changes: 2 additions & 0 deletions provider/workspace_tags.go
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@ type WorkspaceTags struct {

func workspaceTagDataSource() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,

Description: "Use this data source to configure workspace tags to select provisioners.",
ReadContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
rd.SetId(uuid.NewString())