From 1a49822fc9cdb5b613a46408a644b41e1d73ca4e Mon Sep 17 00:00:00 2001
From: Mathias Fredriksson <mafredri@gmail.com>
Date: Mon, 22 Jul 2024 13:42:57 +0300
Subject: [PATCH] Envbuilder
---
.gitignore | 2 +
CHANGELOG.md | 3 -
GNUmakefile | 13 ++
README.md | 32 +--
docs/data-sources/cached_image.md | 52 +++++
docs/data-sources/example.md | 30 ---
docs/functions/example.md | 26 ---
docs/index.md | 12 +-
docs/resources/example.md | 31 ---
.../envbuilder_cached_image/data-source.tf | 13 ++
.../scaffolding_example/data-source.tf | 3 -
examples/provider/provider.tf | 4 +-
.../resources/scaffolding_example/resource.tf | 3 -
go.mod | 4 +-
internal/provider/cached_image_data_source.go | 182 +++++++++++++++++
.../provider/cached_image_data_source_test.go | 48 +++++
internal/provider/example_data_source.go | 105 ----------
internal/provider/example_data_source_test.go | 32 ---
internal/provider/example_function.go | 50 -----
internal/provider/example_function_test.go | 78 --------
internal/provider/example_resource.go | 187 ------------------
internal/provider/example_resource_test.go | 56 ------
internal/provider/provider.go | 54 +++--
internal/provider/provider_test.go | 2 +-
main.go | 19 +-
25 files changed, 350 insertions(+), 691 deletions(-)
delete mode 100644 CHANGELOG.md
create mode 100644 docs/data-sources/cached_image.md
delete mode 100644 docs/data-sources/example.md
delete mode 100644 docs/functions/example.md
delete mode 100644 docs/resources/example.md
create mode 100644 examples/data-sources/envbuilder_cached_image/data-source.tf
delete mode 100644 examples/data-sources/scaffolding_example/data-source.tf
delete mode 100644 examples/resources/scaffolding_example/resource.tf
create mode 100644 internal/provider/cached_image_data_source.go
create mode 100644 internal/provider/cached_image_data_source_test.go
delete mode 100644 internal/provider/example_data_source.go
delete mode 100644 internal/provider/example_data_source_test.go
delete mode 100644 internal/provider/example_function.go
delete mode 100644 internal/provider/example_function_test.go
delete mode 100644 internal/provider/example_resource.go
delete mode 100644 internal/provider/example_resource_test.go
diff --git a/.gitignore b/.gitignore
index fd3ad8e..e6071d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,5 @@ website/vendor
# Keep windows files with windows line endings
*.winfile eol=crlf
+
+terraform-provider-envbuilder
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index b76e247..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.1.0 (Unreleased)
-
-FEATURES:
diff --git a/GNUmakefile b/GNUmakefile
index 7771cd6..e4da196 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,6 +1,19 @@
default: testacc
+test: testacc
+
# Run acceptance tests
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
+
+fmt: examples/*/*.tf
+ terraform fmt -recursive
+
+gen:
+ go generate
+
+build: terraform-provider-envbuilder
+
+terraform-provider-envbuilder: internal/provider/*.go main.go
+ CGO_ENABLED=0 go build .
diff --git a/README.md b/README.md
index 9759acd..7cbcc50 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,11 @@
-# Terraform Provider Scaffolding (Terraform Plugin Framework)
+# terraform-provider-envbuilder
-_This template repository is built on the [Terraform Plugin Framework](https://github.com/hashicorp/terraform-plugin-framework). The template repository built on the [Terraform Plugin SDK](https://github.com/hashicorp/terraform-plugin-sdk) can be found at [terraform-provider-scaffolding](https://github.com/hashicorp/terraform-provider-scaffolding). See [Which SDK Should I Use?](https://developer.hashicorp.com/terraform/plugin/framework-benefits) in the Terraform documentation for additional information._
-
-This repository is a *template* for a [Terraform](https://www.terraform.io) provider. It is intended as a starting point for creating Terraform providers, containing:
-
-- A resource and a data source (`internal/provider/`),
-- Examples (`examples/`) and generated documentation (`docs/`),
-- Miscellaneous meta files.
-
-These files contain boilerplate code that you will need to edit to create your own Terraform provider. Tutorials for creating Terraform providers can be found on the [HashiCorp Developer](https://developer.hashicorp.com/terraform/tutorials/providers-plugin-framework) platform. _Terraform Plugin Framework specific guides are titled accordingly._
-
-Please see the [GitHub template repository documentation](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template) for how to create a new repository from this template on GitHub.
-
-Once you've written your provider, you'll want to [publish it on the Terraform Registry](https://developer.hashicorp.com/terraform/registry/providers/publishing) so that others can use it.
+The `terraform-provider-envbuilder` is a Terraform provider that acts as a helper for setting up [`envbuilder`](https://envbuilder.sh) environments.
## Requirements
- [Terraform](https://developer.hashicorp.com/terraform/downloads) >= 1.0
-- [Go](https://golang.org/doc/install) >= 1.21
+- [Go](https://golang.org/doc/install) >= 1.22
## Building The Provider
@@ -29,20 +17,6 @@ Once you've written your provider, you'll want to [publish it on the Terraform R
go install
```
-## Adding Dependencies
-
-This provider uses [Go modules](https://github.com/golang/go/wiki/Modules).
-Please see the Go documentation for the most up to date information about using Go modules.
-
-To add a new dependency `github.com/author/dependency` to your Terraform provider:
-
-```shell
-go get github.com/author/dependency
-go mod tidy
-```
-
-Then commit the changes to `go.mod` and `go.sum`.
-
## Using the provider
Fill this in for each provider
diff --git a/docs/data-sources/cached_image.md b/docs/data-sources/cached_image.md
new file mode 100644
index 0000000..e491d00
--- /dev/null
+++ b/docs/data-sources/cached_image.md
@@ -0,0 +1,52 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "envbuilder_cached_image Data Source - envbuilder"
+subcategory: ""
+description: |-
+ The cached image data source can be used to retrieve a cached image produced by envbuilder.
+---
+
+# envbuilder_cached_image (Data Source)
+
+The cached image data source can be used to retrieve a cached image produced by envbuilder.
+
+## Example Usage
+
+```terraform
+data "envbuilder_cached_image" "example" {
+ builder_image = "ghcr.io/coder/envbuilder:latest"
+ git_url = "https://github.com/coder/envbuilder-starter-devcontainer"
+ cache_repo = "localhost:5000/local/test-cache"
+ extra_env = {
+ "ENVBUILDER_VERBOSE" : "true"
+ }
+}
+
+resource "docker_container" "container" {
+ image = envbuilder_cached_image.example.image
+ env = data.envbuilder_image.cached.env
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `builder_image` (String) The builder image URL to use if the cache does not exist.
+- `cache_repo` (String) The name of the container registry to fetch the cache image from.
+- `git_url` (String) The URL of a Git repository containing a Devcontainer or Docker image to clone.
+
+### Optional
+
+- `cache_ttl_days` (Number) The number of days to use cached layers before expiring them. Defaults to 7 days.
+- `extra_env` (Map of String) Extra environment variables to set for the container. This may include evbuilder options.
+- `git_password` (String, Sensitive) The password to use for Git authentication. This is optional.
+- `git_username` (String) The username to use for Git authentication. This is optional.
+
+### Read-Only
+
+- `env` (List of String) Computed envbuilder configuration to be set for the container.
+- `exists` (Boolean) Whether the cached image was exists or not for the given config.
+- `id` (String) Cached image identifier
+- `image` (String) Outputs the cached image URL if it exists, otherwise the builder image URL is output instead.
diff --git a/docs/data-sources/example.md b/docs/data-sources/example.md
deleted file mode 100644
index b19c8a0..0000000
--- a/docs/data-sources/example.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "scaffolding_example Data Source - scaffolding"
-subcategory: ""
-description: |-
- Example data source
----
-
-# scaffolding_example (Data Source)
-
-Example data source
-
-## Example Usage
-
-```terraform
-data "scaffolding_example" "example" {
- configurable_attribute = "some-value"
-}
-```
-
-<!-- schema generated by tfplugindocs -->
-## Schema
-
-### Optional
-
-- `configurable_attribute` (String) Example configurable attribute
-
-### Read-Only
-
-- `id` (String) Example identifier
diff --git a/docs/functions/example.md b/docs/functions/example.md
deleted file mode 100644
index c65087d..0000000
--- a/docs/functions/example.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "example function - scaffolding"
-subcategory: ""
-description: |-
- Example function
----
-
-# function: example
-
-Echoes given argument as result
-
-
-
-## Signature
-
-<!-- signature generated by tfplugindocs -->
-```text
-example(input string) string
-```
-
-## Arguments
-
-<!-- arguments generated by tfplugindocs -->
-1. `input` (String) String to echo
-
diff --git a/docs/index.md b/docs/index.md
index 7458d6d..5ff0897 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,26 +1,20 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "scaffolding Provider"
+page_title: "envbuilder Provider"
subcategory: ""
description: |-
---
-# scaffolding Provider
+# envbuilder Provider
## Example Usage
```terraform
-provider "scaffolding" {
- # example configuration here
-}
+provider "envbuilder" {}
```
<!-- schema generated by tfplugindocs -->
## Schema
-
-### Optional
-
-- `endpoint` (String) Example provider attribute
diff --git a/docs/resources/example.md b/docs/resources/example.md
deleted file mode 100644
index 5f3d5ca..0000000
--- a/docs/resources/example.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "scaffolding_example Resource - scaffolding"
-subcategory: ""
-description: |-
- Example resource
----
-
-# scaffolding_example (Resource)
-
-Example resource
-
-## Example Usage
-
-```terraform
-resource "scaffolding_example" "example" {
- configurable_attribute = "some-value"
-}
-```
-
-<!-- schema generated by tfplugindocs -->
-## Schema
-
-### Optional
-
-- `configurable_attribute` (String) Example configurable attribute
-- `defaulted` (String) Example configurable attribute with default value
-
-### Read-Only
-
-- `id` (String) Example identifier
diff --git a/examples/data-sources/envbuilder_cached_image/data-source.tf b/examples/data-sources/envbuilder_cached_image/data-source.tf
new file mode 100644
index 0000000..5169ce1
--- /dev/null
+++ b/examples/data-sources/envbuilder_cached_image/data-source.tf
@@ -0,0 +1,13 @@
+data "envbuilder_cached_image" "example" {
+ builder_image = "ghcr.io/coder/envbuilder:latest"
+ git_url = "https://github.com/coder/envbuilder-starter-devcontainer"
+ cache_repo = "localhost:5000/local/test-cache"
+ extra_env = {
+ "ENVBUILDER_VERBOSE" : "true"
+ }
+}
+
+resource "docker_container" "container" {
+ image = envbuilder_cached_image.example.image
+ env = data.envbuilder_image.cached.env
+}
\ No newline at end of file
diff --git a/examples/data-sources/scaffolding_example/data-source.tf b/examples/data-sources/scaffolding_example/data-source.tf
deleted file mode 100644
index a852489..0000000
--- a/examples/data-sources/scaffolding_example/data-source.tf
+++ /dev/null
@@ -1,3 +0,0 @@
-data "scaffolding_example" "example" {
- configurable_attribute = "some-value"
-}
diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf
index 942db45..7edcce7 100644
--- a/examples/provider/provider.tf
+++ b/examples/provider/provider.tf
@@ -1,3 +1 @@
-provider "scaffolding" {
- # example configuration here
-}
+provider "envbuilder" {}
diff --git a/examples/resources/scaffolding_example/resource.tf b/examples/resources/scaffolding_example/resource.tf
deleted file mode 100644
index 9ae3f57..0000000
--- a/examples/resources/scaffolding_example/resource.tf
+++ /dev/null
@@ -1,3 +0,0 @@
-resource "scaffolding_example" "example" {
- configurable_attribute = "some-value"
-}
diff --git a/go.mod b/go.mod
index 48c9e8f..3bca642 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
-module github.com/hashicorp/terraform-provider-scaffolding-framework
+module github.com/mafredri/terraform-provider-envbuilder
-go 1.21
+go 1.22
require (
github.com/hashicorp/terraform-plugin-docs v0.19.4
diff --git a/internal/provider/cached_image_data_source.go b/internal/provider/cached_image_data_source.go
new file mode 100644
index 0000000..1bb4809
--- /dev/null
+++ b/internal/provider/cached_image_data_source.go
@@ -0,0 +1,182 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+)
+
+// Ensure provider defined types fully satisfy framework interfaces.
+var _ datasource.DataSource = &CachedImageDataSource{}
+
+func NewCachedImageDataSource() datasource.DataSource {
+ return &CachedImageDataSource{}
+}
+
+// CachedImageDataSource defines the data source implementation.
+type CachedImageDataSource struct {
+ client *http.Client
+}
+
+// CachedImageDataSourceModel describes the data source data model.
+type CachedImageDataSourceModel struct {
+ BuilderImage types.String `tfsdk:"builder_image"`
+ CacheRepo types.String `tfsdk:"cache_repo"`
+ CacheTTLDays types.Number `tfsdk:"cache_ttl_days"`
+ Env types.List `tfsdk:"env"`
+ Exists types.Bool `tfsdk:"exists"`
+ ExtraEnv types.Map `tfsdk:"extra_env"`
+ GitPassword types.String `tfsdk:"git_password"`
+ GitURL types.String `tfsdk:"git_url"`
+ GitUsername types.String `tfsdk:"git_username"`
+ ID types.String `tfsdk:"id"`
+ Image types.String `tfsdk:"image"`
+}
+
+func (d *CachedImageDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_cached_image"
+}
+
+func (d *CachedImageDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ // This description is used by the documentation generator and the language server.
+ MarkdownDescription: "The cached image data source can be used to retrieve a cached image produced by envbuilder.",
+
+ Attributes: map[string]schema.Attribute{
+ "builder_image": schema.StringAttribute{
+ MarkdownDescription: "The builder image URL to use if the cache does not exist.",
+ Required: true,
+ },
+ "git_url": schema.StringAttribute{
+ MarkdownDescription: "The URL of a Git repository containing a Devcontainer or Docker image to clone.",
+ Required: true,
+ },
+ "git_username": schema.StringAttribute{
+ MarkdownDescription: "The username to use for Git authentication. This is optional.",
+ Optional: true,
+ },
+ "git_password": schema.StringAttribute{
+ MarkdownDescription: "The password to use for Git authentication. This is optional.",
+ Sensitive: true,
+ Optional: true,
+ },
+ "cache_repo": schema.StringAttribute{
+ MarkdownDescription: "The name of the container registry to fetch the cache image from.",
+ Required: true,
+ },
+ "cache_ttl_days": schema.NumberAttribute{
+ MarkdownDescription: "The number of days to use cached layers before expiring them. Defaults to 7 days.",
+ Optional: true,
+ },
+ // TODO(mafredri): Map vs List? Support both?
+ "extra_env": schema.MapAttribute{
+ MarkdownDescription: "Extra environment variables to set for the container. This may include evbuilder options.",
+ ElementType: types.StringType,
+ Optional: true,
+ },
+ "id": schema.StringAttribute{
+ MarkdownDescription: "Cached image identifier",
+ Computed: true,
+ },
+ "exists": schema.BoolAttribute{
+ MarkdownDescription: "Whether the cached image was exists or not for the given config.",
+ Computed: true,
+ },
+ "image": schema.StringAttribute{
+ MarkdownDescription: "Outputs the cached image URL if it exists, otherwise the builder image URL is output instead.",
+ Computed: true,
+ },
+ // TODO(mafredri): Map vs List? Support both?
+ "env": schema.ListAttribute{
+ MarkdownDescription: "Computed envbuilder configuration to be set for the container.",
+ ElementType: types.StringType,
+ Computed: true,
+ },
+ },
+ }
+}
+
+func (d *CachedImageDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ // Prevent panic if the provider has not been configured.
+ if req.ProviderData == nil {
+ return
+ }
+
+ client, ok := req.ProviderData.(*http.Client)
+
+ if !ok {
+ resp.Diagnostics.AddError(
+ "Unexpected Data Source Configure Type",
+ fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+ )
+
+ return
+ }
+
+ d.client = client
+}
+
+func (d *CachedImageDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var data CachedImageDataSourceModel
+
+ // Read Terraform configuration data into the model
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ // If applicable, this is a great opportunity to initialize any necessary
+ // provider client data and make a call using it.
+ // httpResp, err := d.client.Do(httpReq)
+ // if err != nil {
+ // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read cached image, got error: %s", err))
+ // return
+ // }
+
+ // TODO(mafredri): Implement the actual data source read logic.
+ data.ID = types.StringValue("cached-image-id")
+ data.Exists = types.BoolValue(false)
+ data.Image = data.BuilderImage
+
+ // Compute the env attribute from the config map.
+ // TODO(mafredri): Convert any other relevant attributes given via schema.
+ for key, elem := range data.ExtraEnv.Elements() {
+ data.Env = appendKnownEnvToList(data.Env, key, elem)
+ }
+
+ data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_CACHE_REPO", data.CacheRepo)
+ data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_CACHE_TTL_DAYS", data.CacheTTLDays)
+ data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_URL", data.GitURL)
+ data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_USERNAME", data.GitUsername)
+ data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_PASSWORD", data.GitPassword)
+
+ // Write logs using the tflog package
+ // Documentation: https://terraform.io/plugin/log
+ tflog.Trace(ctx, "read a data source")
+
+ // Save data into Terraform state
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+type stringable interface {
+ IsUnknown() bool
+ String() string
+}
+
+func appendKnownEnvToList(list types.List, key string, value stringable) types.List {
+ if value.IsUnknown() {
+ return list
+ }
+ elem := types.StringValue(fmt.Sprintf("%s=%s", key, value.String()))
+ list, _ = types.ListValue(types.StringType, append(list.Elements(), elem))
+ return list
+}
diff --git a/internal/provider/cached_image_data_source_test.go b/internal/provider/cached_image_data_source_test.go
new file mode 100644
index 0000000..8769eb0
--- /dev/null
+++ b/internal/provider/cached_image_data_source_test.go
@@ -0,0 +1,48 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccExampleDataSource(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccCachedImageDataSourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(
+ // Input
+ resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "extra_env.ENVBUILDER_VERBOSE", "true"),
+ resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "git_url", "https://github.com/coder/envbuilder-starter-devcontainer"),
+ resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_username"),
+ resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_password"),
+ resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "cache_repo", "localhost:5000/local/test-cache"),
+ resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "cache_ttl_days"),
+ // Computed
+ resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "id", "cached-image-id"),
+ resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "exists", "false"),
+ resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "image", "ghcr.io/coder/envbuilder:latest"),
+ resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "env.0", "ENVBUILDER_VERBOSE=\"true\""),
+ ),
+ },
+ },
+ })
+}
+
+const testAccCachedImageDataSourceConfig = `
+data "envbuilder_cached_image" "test" {
+ builder_image = "ghcr.io/coder/envbuilder:latest"
+ git_url = "https://github.com/coder/envbuilder-starter-devcontainer"
+ cache_repo = "localhost:5000/local/test-cache"
+ extra_env = {
+ "ENVBUILDER_VERBOSE" : "true"
+ }
+}
+`
diff --git a/internal/provider/example_data_source.go b/internal/provider/example_data_source.go
deleted file mode 100644
index 585b9d2..0000000
--- a/internal/provider/example_data_source.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package provider
-
-import (
- "context"
- "fmt"
- "net/http"
-
- "github.com/hashicorp/terraform-plugin-framework/datasource"
- "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
- "github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/hashicorp/terraform-plugin-log/tflog"
-)
-
-// Ensure provider defined types fully satisfy framework interfaces.
-var _ datasource.DataSource = &ExampleDataSource{}
-
-func NewExampleDataSource() datasource.DataSource {
- return &ExampleDataSource{}
-}
-
-// ExampleDataSource defines the data source implementation.
-type ExampleDataSource struct {
- client *http.Client
-}
-
-// ExampleDataSourceModel describes the data source data model.
-type ExampleDataSourceModel struct {
- ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
- Id types.String `tfsdk:"id"`
-}
-
-func (d *ExampleDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_example"
-}
-
-func (d *ExampleDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
- resp.Schema = schema.Schema{
- // This description is used by the documentation generator and the language server.
- MarkdownDescription: "Example data source",
-
- Attributes: map[string]schema.Attribute{
- "configurable_attribute": schema.StringAttribute{
- MarkdownDescription: "Example configurable attribute",
- Optional: true,
- },
- "id": schema.StringAttribute{
- MarkdownDescription: "Example identifier",
- Computed: true,
- },
- },
- }
-}
-
-func (d *ExampleDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
- // Prevent panic if the provider has not been configured.
- if req.ProviderData == nil {
- return
- }
-
- client, ok := req.ProviderData.(*http.Client)
-
- if !ok {
- resp.Diagnostics.AddError(
- "Unexpected Data Source Configure Type",
- fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
- )
-
- return
- }
-
- d.client = client
-}
-
-func (d *ExampleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
- var data ExampleDataSourceModel
-
- // Read Terraform configuration data into the model
- resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
-
- if resp.Diagnostics.HasError() {
- return
- }
-
- // If applicable, this is a great opportunity to initialize any necessary
- // provider client data and make a call using it.
- // httpResp, err := d.client.Do(httpReq)
- // if err != nil {
- // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read example, got error: %s", err))
- // return
- // }
-
- // For the purposes of this example code, hardcoding a response value to
- // save into the Terraform state.
- data.Id = types.StringValue("example-id")
-
- // Write logs using the tflog package
- // Documentation: https://terraform.io/plugin/log
- tflog.Trace(ctx, "read a data source")
-
- // Save data into Terraform state
- resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
-}
diff --git a/internal/provider/example_data_source_test.go b/internal/provider/example_data_source_test.go
deleted file mode 100644
index 6f9aa7d..0000000
--- a/internal/provider/example_data_source_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package provider
-
-import (
- "testing"
-
- "github.com/hashicorp/terraform-plugin-testing/helper/resource"
-)
-
-func TestAccExampleDataSource(t *testing.T) {
- resource.Test(t, resource.TestCase{
- PreCheck: func() { testAccPreCheck(t) },
- ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
- Steps: []resource.TestStep{
- // Read testing
- {
- Config: testAccExampleDataSourceConfig,
- Check: resource.ComposeAggregateTestCheckFunc(
- resource.TestCheckResourceAttr("data.scaffolding_example.test", "id", "example-id"),
- ),
- },
- },
- })
-}
-
-const testAccExampleDataSourceConfig = `
-data "scaffolding_example" "test" {
- configurable_attribute = "example"
-}
-`
diff --git a/internal/provider/example_function.go b/internal/provider/example_function.go
deleted file mode 100644
index 1106e7d..0000000
--- a/internal/provider/example_function.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package provider
-
-import (
- "context"
-
- "github.com/hashicorp/terraform-plugin-framework/function"
-)
-
-var (
- _ function.Function = ExampleFunction{}
-)
-
-func NewExampleFunction() function.Function {
- return ExampleFunction{}
-}
-
-type ExampleFunction struct{}
-
-func (r ExampleFunction) Metadata(_ context.Context, req function.MetadataRequest, resp *function.MetadataResponse) {
- resp.Name = "example"
-}
-
-func (r ExampleFunction) Definition(_ context.Context, _ function.DefinitionRequest, resp *function.DefinitionResponse) {
- resp.Definition = function.Definition{
- Summary: "Example function",
- MarkdownDescription: "Echoes given argument as result",
- Parameters: []function.Parameter{
- function.StringParameter{
- Name: "input",
- MarkdownDescription: "String to echo",
- },
- },
- Return: function.StringReturn{},
- }
-}
-
-func (r ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
- var data string
-
- resp.Error = function.ConcatFuncErrors(req.Arguments.Get(ctx, &data))
-
- if resp.Error != nil {
- return
- }
-
- resp.Error = function.ConcatFuncErrors(resp.Result.Set(ctx, data))
-}
diff --git a/internal/provider/example_function_test.go b/internal/provider/example_function_test.go
deleted file mode 100644
index f7b5bdd..0000000
--- a/internal/provider/example_function_test.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package provider
-
-import (
- "regexp"
- "testing"
-
- "github.com/hashicorp/terraform-plugin-testing/helper/resource"
- "github.com/hashicorp/terraform-plugin-testing/tfversion"
-)
-
-func TestExampleFunction_Known(t *testing.T) {
- resource.UnitTest(t, resource.TestCase{
- TerraformVersionChecks: []tfversion.TerraformVersionCheck{
- tfversion.SkipBelow(tfversion.Version1_8_0),
- },
- ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
- Steps: []resource.TestStep{
- {
- Config: `
- output "test" {
- value = provider::scaffolding::example("testvalue")
- }
- `,
- Check: resource.ComposeAggregateTestCheckFunc(
- resource.TestCheckOutput("test", "testvalue"),
- ),
- },
- },
- })
-}
-
-func TestExampleFunction_Null(t *testing.T) {
- resource.UnitTest(t, resource.TestCase{
- TerraformVersionChecks: []tfversion.TerraformVersionCheck{
- tfversion.SkipBelow(tfversion.Version1_8_0),
- },
- ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
- Steps: []resource.TestStep{
- {
- Config: `
- output "test" {
- value = provider::scaffolding::example(null)
- }
- `,
- // The parameter does not enable AllowNullValue
- ExpectError: regexp.MustCompile(`argument must not be null`),
- },
- },
- })
-}
-
-func TestExampleFunction_Unknown(t *testing.T) {
- resource.UnitTest(t, resource.TestCase{
- TerraformVersionChecks: []tfversion.TerraformVersionCheck{
- tfversion.SkipBelow(tfversion.Version1_8_0),
- },
- ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
- Steps: []resource.TestStep{
- {
- Config: `
- resource "terraform_data" "test" {
- input = "testvalue"
- }
-
- output "test" {
- value = provider::scaffolding::example(terraform_data.test.output)
- }
- `,
- Check: resource.ComposeAggregateTestCheckFunc(
- resource.TestCheckOutput("test", "testvalue"),
- ),
- },
- },
- })
-}
diff --git a/internal/provider/example_resource.go b/internal/provider/example_resource.go
deleted file mode 100644
index 70e961a..0000000
--- a/internal/provider/example_resource.go
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package provider
-
-import (
- "context"
- "fmt"
- "net/http"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/hashicorp/terraform-plugin-log/tflog"
-)
-
-// Ensure provider defined types fully satisfy framework interfaces.
-var _ resource.Resource = &ExampleResource{}
-var _ resource.ResourceWithImportState = &ExampleResource{}
-
-func NewExampleResource() resource.Resource {
- return &ExampleResource{}
-}
-
-// ExampleResource defines the resource implementation.
-type ExampleResource struct {
- client *http.Client
-}
-
-// ExampleResourceModel describes the resource data model.
-type ExampleResourceModel struct {
- ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
- Defaulted types.String `tfsdk:"defaulted"`
- Id types.String `tfsdk:"id"`
-}
-
-func (r *ExampleResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_example"
-}
-
-func (r *ExampleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- resp.Schema = schema.Schema{
- // This description is used by the documentation generator and the language server.
- MarkdownDescription: "Example resource",
-
- Attributes: map[string]schema.Attribute{
- "configurable_attribute": schema.StringAttribute{
- MarkdownDescription: "Example configurable attribute",
- Optional: true,
- },
- "defaulted": schema.StringAttribute{
- MarkdownDescription: "Example configurable attribute with default value",
- Optional: true,
- Computed: true,
- Default: stringdefault.StaticString("example value when not configured"),
- },
- "id": schema.StringAttribute{
- Computed: true,
- MarkdownDescription: "Example identifier",
- PlanModifiers: []planmodifier.String{
- stringplanmodifier.UseStateForUnknown(),
- },
- },
- },
- }
-}
-
-func (r *ExampleResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- // Prevent panic if the provider has not been configured.
- if req.ProviderData == nil {
- return
- }
-
- client, ok := req.ProviderData.(*http.Client)
-
- if !ok {
- resp.Diagnostics.AddError(
- "Unexpected Resource Configure Type",
- fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
- )
-
- return
- }
-
- r.client = client
-}
-
-func (r *ExampleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data ExampleResourceModel
-
- // Read Terraform plan data into the model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
-
- if resp.Diagnostics.HasError() {
- return
- }
-
- // If applicable, this is a great opportunity to initialize any necessary
- // provider client data and make a call using it.
- // httpResp, err := r.client.Do(httpReq)
- // if err != nil {
- // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create example, got error: %s", err))
- // return
- // }
-
- // For the purposes of this example code, hardcoding a response value to
- // save into the Terraform state.
- data.Id = types.StringValue("example-id")
-
- // Write logs using the tflog package
- // Documentation: https://terraform.io/plugin/log
- tflog.Trace(ctx, "created a resource")
-
- // Save data into Terraform state
- resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
-}
-
-func (r *ExampleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var data ExampleResourceModel
-
- // Read Terraform prior state data into the model
- resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
-
- if resp.Diagnostics.HasError() {
- return
- }
-
- // If applicable, this is a great opportunity to initialize any necessary
- // provider client data and make a call using it.
- // httpResp, err := r.client.Do(httpReq)
- // if err != nil {
- // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read example, got error: %s", err))
- // return
- // }
-
- // Save updated data into Terraform state
- resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
-}
-
-func (r *ExampleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var data ExampleResourceModel
-
- // Read Terraform plan data into the model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
-
- if resp.Diagnostics.HasError() {
- return
- }
-
- // If applicable, this is a great opportunity to initialize any necessary
- // provider client data and make a call using it.
- // httpResp, err := r.client.Do(httpReq)
- // if err != nil {
- // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update example, got error: %s", err))
- // return
- // }
-
- // Save updated data into Terraform state
- resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
-}
-
-func (r *ExampleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var data ExampleResourceModel
-
- // Read Terraform prior state data into the model
- resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
-
- if resp.Diagnostics.HasError() {
- return
- }
-
- // If applicable, this is a great opportunity to initialize any necessary
- // provider client data and make a call using it.
- // httpResp, err := r.client.Do(httpReq)
- // if err != nil {
- // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete example, got error: %s", err))
- // return
- // }
-}
-
-func (r *ExampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
diff --git a/internal/provider/example_resource_test.go b/internal/provider/example_resource_test.go
deleted file mode 100644
index c5464d0..0000000
--- a/internal/provider/example_resource_test.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package provider
-
-import (
- "fmt"
- "testing"
-
- "github.com/hashicorp/terraform-plugin-testing/helper/resource"
-)
-
-func TestAccExampleResource(t *testing.T) {
- resource.Test(t, resource.TestCase{
- PreCheck: func() { testAccPreCheck(t) },
- ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
- Steps: []resource.TestStep{
- // Create and Read testing
- {
- Config: testAccExampleResourceConfig("one"),
- Check: resource.ComposeAggregateTestCheckFunc(
- resource.TestCheckResourceAttr("scaffolding_example.test", "configurable_attribute", "one"),
- resource.TestCheckResourceAttr("scaffolding_example.test", "defaulted", "example value when not configured"),
- resource.TestCheckResourceAttr("scaffolding_example.test", "id", "example-id"),
- ),
- },
- // ImportState testing
- {
- ResourceName: "scaffolding_example.test",
- ImportState: true,
- ImportStateVerify: true,
- // This is not normally necessary, but is here because this
- // example code does not have an actual upstream service.
- // Once the Read method is able to refresh information from
- // the upstream service, this can be removed.
- ImportStateVerifyIgnore: []string{"configurable_attribute", "defaulted"},
- },
- // Update and Read testing
- {
- Config: testAccExampleResourceConfig("two"),
- Check: resource.ComposeAggregateTestCheckFunc(
- resource.TestCheckResourceAttr("scaffolding_example.test", "configurable_attribute", "two"),
- ),
- },
- // Delete testing automatically occurs in TestCase
- },
- })
-}
-
-func testAccExampleResourceConfig(configurableAttribute string) string {
- return fmt.Sprintf(`
-resource "scaffolding_example" "test" {
- configurable_attribute = %[1]q
-}
-`, configurableAttribute)
-}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 2471df6..f96858e 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -12,44 +12,38 @@ import (
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/types"
)
-// Ensure ScaffoldingProvider satisfies various provider interfaces.
-var _ provider.Provider = &ScaffoldingProvider{}
-var _ provider.ProviderWithFunctions = &ScaffoldingProvider{}
+// Ensure EnvbuilderProvider satisfies various provider interfaces.
+var (
+ _ provider.Provider = &EnvbuilderProvider{}
+ _ provider.ProviderWithFunctions = &EnvbuilderProvider{}
+)
-// ScaffoldingProvider defines the provider implementation.
-type ScaffoldingProvider struct {
+// EnvbuilderProvider defines the provider implementation.
+type EnvbuilderProvider struct {
// version is set to the provider version on release, "dev" when the
// provider is built and ran locally, and "test" when running acceptance
// testing.
version string
}
-// ScaffoldingProviderModel describes the provider data model.
-type ScaffoldingProviderModel struct {
- Endpoint types.String `tfsdk:"endpoint"`
-}
+// EnvbuilderProviderModel describes the provider data model.
+type EnvbuilderProviderModel struct{}
-func (p *ScaffoldingProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
- resp.TypeName = "scaffolding"
+func (p *EnvbuilderProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
+ resp.TypeName = "envbuilder"
resp.Version = p.version
}
-func (p *ScaffoldingProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
+func (p *EnvbuilderProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: map[string]schema.Attribute{
- "endpoint": schema.StringAttribute{
- MarkdownDescription: "Example provider attribute",
- Optional: true,
- },
- },
+ Attributes: map[string]schema.Attribute{},
}
}
-func (p *ScaffoldingProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
- var data ScaffoldingProviderModel
+func (p *EnvbuilderProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
+ var data EnvbuilderProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
@@ -66,27 +60,23 @@ func (p *ScaffoldingProvider) Configure(ctx context.Context, req provider.Config
resp.ResourceData = client
}
-func (p *ScaffoldingProvider) Resources(ctx context.Context) []func() resource.Resource {
- return []func() resource.Resource{
- NewExampleResource,
- }
+func (p *EnvbuilderProvider) Resources(ctx context.Context) []func() resource.Resource {
+ return []func() resource.Resource{}
}
-func (p *ScaffoldingProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
+func (p *EnvbuilderProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
- NewExampleDataSource,
+ NewCachedImageDataSource,
}
}
-func (p *ScaffoldingProvider) Functions(ctx context.Context) []func() function.Function {
- return []func() function.Function{
- NewExampleFunction,
- }
+func (p *EnvbuilderProvider) Functions(ctx context.Context) []func() function.Function {
+ return []func() function.Function{}
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
- return &ScaffoldingProvider{
+ return &EnvbuilderProvider{
version: version,
}
}
diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go
index ef6599b..b7991c3 100644
--- a/internal/provider/provider_test.go
+++ b/internal/provider/provider_test.go
@@ -15,7 +15,7 @@ import (
// CLI command executed to create a provider server to which the CLI can
// reattach.
var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
- "scaffolding": providerserver.NewProtocol6WithError(New("test")()),
+ "envbuilder": providerserver.NewProtocol6WithError(New("test")()),
}
func testAccPreCheck(t *testing.T) {
diff --git a/main.go b/main.go
index a95e85c..80a071e 100644
--- a/main.go
+++ b/main.go
@@ -9,7 +9,7 @@ import (
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
- "github.com/hashicorp/terraform-provider-scaffolding-framework/internal/provider"
+ "github.com/mafredri/terraform-provider-envbuilder/internal/provider"
)
// Run "go generate" to format example terraform files and generate the docs for the registry/website
@@ -20,16 +20,14 @@ import (
// Run the docs generation tool, check its repository for more information on how it works and how docs
// can be customized.
-//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate -provider-name scaffolding
+//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate -provider-name envbuilder
-var (
- // these will be set by the goreleaser configuration
- // to appropriate values for the compiled binary.
- version string = "dev"
+// these will be set by the goreleaser configuration
+// to appropriate values for the compiled binary.
+var version string = "dev"
- // goreleaser can pass other information to the main package, such as the specific commit
- // https://goreleaser.com/cookbooks/using-main.version/
-)
+// goreleaser can pass other information to the main package, such as the specific commit
+// https://goreleaser.com/cookbooks/using-main.version/
func main() {
var debug bool
@@ -41,12 +39,11 @@ func main() {
// TODO: Update this string with the published name of your provider.
// Also update the tfplugindocs generate command to either remove the
// -provider-name flag or set its value to the updated provider name.
- Address: "registry.terraform.io/hashicorp/scaffolding",
+ Address: "registry.terraform.io/hashicorp/envbuilder",
Debug: debug,
}
err := providerserver.Serve(context.Background(), provider.New(version), opts)
-
if err != nil {
log.Fatal(err.Error())
}