mirror of
https://github.com/coder/terraform-provider-envbuilder.git
synced 2025-08-26 11:27:14 +00:00
feat(internal/provider): add env_map to cached_image_resource (#37)
This PR adds `env_map` to `cached_image_resource.` This consists of the computed env in map format, which can be useful for other providers that do not expect `KEY=VALUE` format.
This commit is contained in:
parent
b55c3783a8
commit
6cf3d93444
3 changed files with 105 additions and 46 deletions
|
@ -48,7 +48,8 @@ The cached image resource can be used to retrieve a cached image produced by env
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
- `env` (List of String, Sensitive) Computed envbuilder configuration to be set for the container. May contain secrets.
|
- `env` (List of String, Sensitive) Computed envbuilder configuration to be set for the container in the form of a list of strings of `key=value`. May contain secrets.
|
||||||
|
- `env_map` (Map of String, Sensitive) Computed envbuilder configuration to be set for the container in the form of a key-value map. May contain secrets.
|
||||||
- `exists` (Boolean) Whether the cached image was exists or not for the given config.
|
- `exists` (Boolean) Whether the cached image was exists or not for the given config.
|
||||||
- `id` (String) Cached image identifier. This will generally be the image's SHA256 digest.
|
- `id` (String) Cached image identifier. This will generally be the image's SHA256 digest.
|
||||||
- `image` (String) Outputs the cached image repo@digest if it exists, and builder image otherwise.
|
- `image` (String) Outputs the cached image repo@digest if it exists, and builder image otherwise.
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
kconfig "github.com/GoogleContainerTools/kaniko/pkg/config"
|
kconfig "github.com/GoogleContainerTools/kaniko/pkg/config"
|
||||||
|
@ -23,6 +24,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
|
||||||
|
@ -31,6 +33,7 @@ import (
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,6 +80,7 @@ type CachedImageResourceModel struct {
|
||||||
WorkspaceFolder types.String `tfsdk:"workspace_folder"`
|
WorkspaceFolder types.String `tfsdk:"workspace_folder"`
|
||||||
// Computed "outputs".
|
// Computed "outputs".
|
||||||
Env types.List `tfsdk:"env"`
|
Env types.List `tfsdk:"env"`
|
||||||
|
EnvMap types.Map `tfsdk:"env_map"`
|
||||||
Exists types.Bool `tfsdk:"exists"`
|
Exists types.Bool `tfsdk:"exists"`
|
||||||
ID types.String `tfsdk:"id"`
|
ID types.String `tfsdk:"id"`
|
||||||
Image types.String `tfsdk:"image"`
|
Image types.String `tfsdk:"image"`
|
||||||
|
@ -226,9 +230,8 @@ func (r *CachedImageResource) Schema(ctx context.Context, req resource.SchemaReq
|
||||||
},
|
},
|
||||||
|
|
||||||
// Computed "outputs".
|
// Computed "outputs".
|
||||||
// TODO(mafredri): Map vs List? Support both?
|
|
||||||
"env": schema.ListAttribute{
|
"env": schema.ListAttribute{
|
||||||
MarkdownDescription: "Computed envbuilder configuration to be set for the container. May contain secrets.",
|
MarkdownDescription: "Computed envbuilder configuration to be set for the container in the form of a list of strings of `key=value`. May contain secrets.",
|
||||||
ElementType: types.StringType,
|
ElementType: types.StringType,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Sensitive: true,
|
Sensitive: true,
|
||||||
|
@ -236,6 +239,15 @@ func (r *CachedImageResource) Schema(ctx context.Context, req resource.SchemaReq
|
||||||
listplanmodifier.RequiresReplace(),
|
listplanmodifier.RequiresReplace(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"env_map": schema.MapAttribute{
|
||||||
|
MarkdownDescription: "Computed envbuilder configuration to be set for the container in the form of a key-value map. May contain secrets.",
|
||||||
|
ElementType: types.StringType,
|
||||||
|
Computed: true,
|
||||||
|
Sensitive: true,
|
||||||
|
PlanModifiers: []planmodifier.Map{
|
||||||
|
mapplanmodifier.RequiresReplace(),
|
||||||
|
},
|
||||||
|
},
|
||||||
"exists": schema.BoolAttribute{
|
"exists": schema.BoolAttribute{
|
||||||
MarkdownDescription: "Whether the cached image was exists or not for the given config.",
|
MarkdownDescription: "Whether the cached image was exists or not for the given config.",
|
||||||
Computed: true,
|
Computed: true,
|
||||||
|
@ -338,28 +350,36 @@ func (r *CachedImageResource) Read(ctx context.Context, req resource.ReadRequest
|
||||||
data.Exists = types.BoolValue(true)
|
data.Exists = types.BoolValue(true)
|
||||||
|
|
||||||
// Set the expected environment variables.
|
// Set the expected environment variables.
|
||||||
|
env := make(map[string]string)
|
||||||
for key, elem := range data.ExtraEnv.Elements() {
|
for key, elem := range data.ExtraEnv.Elements() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, key, elem)
|
env[key] = tfValueToString(elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_CACHE_REPO", data.CacheRepo)
|
env["ENVBUILDER_CACHE_REPO"] = tfValueToString(data.CacheRepo)
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_URL", data.GitURL)
|
env["ENVBUILDER_GIT_URL"] = tfValueToString(data.GitURL)
|
||||||
|
|
||||||
if !data.CacheTTLDays.IsNull() {
|
if !data.CacheTTLDays.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_CACHE_TTL_DAYS", data.CacheTTLDays)
|
env["ENVBUILDER_CACHE_TTL_DAYS"] = tfValueToString(data.CacheTTLDays)
|
||||||
}
|
}
|
||||||
if !data.GitUsername.IsNull() {
|
if !data.GitUsername.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_USERNAME", data.GitUsername)
|
env["ENVBUILDER_GIT_USERNAME"] = tfValueToString(data.GitUsername)
|
||||||
}
|
}
|
||||||
if !data.GitPassword.IsNull() {
|
if !data.GitPassword.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_PASSWORD", data.GitPassword)
|
env["ENVBUILDER_GIT_PASSWORD"] = tfValueToString(data.GitPassword)
|
||||||
}
|
}
|
||||||
// Default to remote build mode.
|
// Default to remote build mode.
|
||||||
if data.RemoteRepoBuildMode.IsNull() {
|
if data.RemoteRepoBuildMode.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_REMOTE_REPO_BUILD_MODE", types.BoolValue(true))
|
env["ENVBUILDER_REMOTE_REPO_BUILD_MODE"] = "true"
|
||||||
} else {
|
} else {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_REMOTE_REPO_BUILD_MODE", data.RemoteRepoBuildMode)
|
env["ENVBUILDER_REMOTE_REPO_BUILD_MODE"] = tfValueToString(data.RemoteRepoBuildMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var diag diag.Diagnostics
|
||||||
|
data.EnvMap, diag = basetypes.NewMapValueFrom(ctx, types.StringType, env)
|
||||||
|
resp.Diagnostics.Append(diag...)
|
||||||
|
data.Env, diag = basetypes.NewListValueFrom(ctx, types.StringType, sortedKeyValues(env))
|
||||||
|
resp.Diagnostics.Append(diag...)
|
||||||
|
|
||||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,29 +416,36 @@ func (r *CachedImageResource) Create(ctx context.Context, req resource.CreateReq
|
||||||
data.ID = types.StringValue(digest.String())
|
data.ID = types.StringValue(digest.String())
|
||||||
}
|
}
|
||||||
// Compute the env attribute from the config map.
|
// Compute the env attribute from the config map.
|
||||||
// TODO(mafredri): Convert any other relevant attributes given via schema.
|
env := make(map[string]string)
|
||||||
for key, elem := range data.ExtraEnv.Elements() {
|
for key, elem := range data.ExtraEnv.Elements() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, key, elem)
|
env[key] = tfValueToString(elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_CACHE_REPO", data.CacheRepo)
|
env["ENVBUILDER_CACHE_REPO"] = tfValueToString(data.CacheRepo)
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_URL", data.GitURL)
|
env["ENVBUILDER_GIT_URL"] = tfValueToString(data.GitURL)
|
||||||
|
|
||||||
if !data.CacheTTLDays.IsNull() {
|
if !data.CacheTTLDays.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_CACHE_TTL_DAYS", data.CacheTTLDays)
|
env["ENVBUILDER_CACHE_TTL_DAYS"] = tfValueToString(data.CacheTTLDays)
|
||||||
}
|
}
|
||||||
if !data.GitUsername.IsNull() {
|
if !data.GitUsername.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_USERNAME", data.GitUsername)
|
env["ENVBUILDER_GIT_USERNAME"] = tfValueToString(data.GitUsername)
|
||||||
}
|
}
|
||||||
if !data.GitPassword.IsNull() {
|
if !data.GitPassword.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_GIT_PASSWORD", data.GitPassword)
|
env["ENVBUILDER_GIT_PASSWORD"] = tfValueToString(data.GitPassword)
|
||||||
}
|
}
|
||||||
// Default to remote build mode.
|
// Default to remote build mode.
|
||||||
if data.RemoteRepoBuildMode.IsNull() {
|
if data.RemoteRepoBuildMode.IsNull() {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_REMOTE_REPO_BUILD_MODE", types.BoolValue(true))
|
env["ENVBUILDER_REMOTE_REPO_BUILD_MODE"] = "true"
|
||||||
} else {
|
} else {
|
||||||
data.Env = appendKnownEnvToList(data.Env, "ENVBUILDER_REMOTE_REPO_BUILD_MODE", data.RemoteRepoBuildMode)
|
env["ENVBUILDER_REMOTE_REPO_BUILD_MODE"] = tfValueToString(data.RemoteRepoBuildMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var diag diag.Diagnostics
|
||||||
|
data.EnvMap, diag = basetypes.NewMapValueFrom(ctx, types.StringType, env)
|
||||||
|
resp.Diagnostics.Append(diag...)
|
||||||
|
data.Env, diag = basetypes.NewListValueFrom(ctx, types.StringType, sortedKeyValues(env))
|
||||||
|
resp.Diagnostics.Append(diag...)
|
||||||
|
|
||||||
// Save data into Terraform state
|
// Save data into Terraform state
|
||||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||||
}
|
}
|
||||||
|
@ -652,19 +679,8 @@ func tfValueToString(val attr.Value) string {
|
||||||
panic(fmt.Errorf("tfValueToString: value %T is not a supported type", val))
|
panic(fmt.Errorf("tfValueToString: value %T is not a supported type", val))
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendKnownEnvToList(list types.List, key string, value attr.Value) types.List {
|
// tfListToStringSlice converts a types.List to a []string by calling
|
||||||
if value.IsUnknown() || value.IsNull() {
|
// tfValueToString on each element.
|
||||||
return list
|
|
||||||
}
|
|
||||||
var sb strings.Builder
|
|
||||||
_, _ = sb.WriteString(key)
|
|
||||||
_, _ = sb.WriteRune('=')
|
|
||||||
_, _ = sb.WriteString(tfValueToString(value))
|
|
||||||
elem := types.StringValue(sb.String())
|
|
||||||
list, _ = types.ListValue(types.StringType, append(list.Elements(), elem))
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
func tfListToStringSlice(l types.List) []string {
|
func tfListToStringSlice(l types.List) []string {
|
||||||
var ss []string
|
var ss []string
|
||||||
for _, el := range l.Elements() {
|
for _, el := range l.Elements() {
|
||||||
|
@ -692,3 +708,19 @@ func tfLogFunc(ctx context.Context) eblog.Func {
|
||||||
logFn(ctx, fmt.Sprintf(format, args...))
|
logFn(ctx, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sortedKeyValues returns the keys and values of the map in the form "key=value"
|
||||||
|
// sorted by key in lexicographical order.
|
||||||
|
func sortedKeyValues(m map[string]string) []string {
|
||||||
|
pairs := make([]string, 0, len(m))
|
||||||
|
var sb strings.Builder
|
||||||
|
for k := range m {
|
||||||
|
_, _ = sb.WriteString(k)
|
||||||
|
_, _ = sb.WriteRune('=')
|
||||||
|
_, _ = sb.WriteString(m[k])
|
||||||
|
pairs = append(pairs, sb.String())
|
||||||
|
sb.Reset()
|
||||||
|
}
|
||||||
|
sort.Strings(pairs)
|
||||||
|
return pairs
|
||||||
|
}
|
||||||
|
|
|
@ -24,12 +24,18 @@ func TestAccCachedImageResource(t *testing.T) {
|
||||||
files map[string]string
|
files map[string]string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
// This test case is the simplest possible case: a devcontainer.json.
|
||||||
|
// However, it also makes sure we are able to generate a Dockerfile
|
||||||
|
// from the devcontainer.json.
|
||||||
name: "devcontainer only",
|
name: "devcontainer only",
|
||||||
files: map[string]string{
|
files: map[string]string{
|
||||||
".devcontainer/devcontainer.json": `{"image": "localhost:5000/test-ubuntu:latest"}`,
|
".devcontainer/devcontainer.json": `{"image": "localhost:5000/test-ubuntu:latest"}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// This test case includes a Dockerfile in addition to the devcontainer.json.
|
||||||
|
// The Dockerfile writes the current date to a file. This is currently not checked but
|
||||||
|
// illustrates that a RUN instruction is cached.
|
||||||
name: "devcontainer and Dockerfile",
|
name: "devcontainer and Dockerfile",
|
||||||
files: map[string]string{
|
files: map[string]string{
|
||||||
".devcontainer/devcontainer.json": `{"build": { "dockerfile": "Dockerfile" }}`,
|
".devcontainer/devcontainer.json": `{"build": { "dockerfile": "Dockerfile" }}`,
|
||||||
|
@ -46,20 +52,19 @@ RUN date > /date.txt`,
|
||||||
resource.Test(t, resource.TestCase{
|
resource.Test(t, resource.TestCase{
|
||||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
// Initial state: cache has not been seeded.
|
// 1) Initial state: cache has not been seeded.
|
||||||
{
|
{
|
||||||
Config: deps.Config(t),
|
Config: deps.Config(t),
|
||||||
PlanOnly: true,
|
PlanOnly: true,
|
||||||
ExpectNonEmptyPlan: true,
|
ExpectNonEmptyPlan: true,
|
||||||
},
|
},
|
||||||
// Should detect that no cached image is present and plan to create the resource.
|
// 2) Should detect that no cached image is present and plan to create the resource.
|
||||||
{
|
{
|
||||||
Config: deps.Config(t),
|
Config: deps.Config(t),
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
// Computed values MUST be present.
|
// Computed values MUST be present.
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "id", uuid.Nil.String()),
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "id", uuid.Nil.String()),
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "exists", "false"),
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "exists", "false"),
|
||||||
resource.TestCheckResourceAttrSet("envbuilder_cached_image.test", "env.0"),
|
|
||||||
// Cached image should be set to the builder image.
|
// Cached image should be set to the builder image.
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "image", deps.BuilderImage),
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "image", deps.BuilderImage),
|
||||||
// Inputs should still be present.
|
// Inputs should still be present.
|
||||||
|
@ -70,17 +75,18 @@ RUN date > /date.txt`,
|
||||||
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_username"),
|
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_username"),
|
||||||
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_password"),
|
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_password"),
|
||||||
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "cache_ttl_days"),
|
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "cache_ttl_days"),
|
||||||
|
// Environment variables
|
||||||
|
assertEnv(t, deps),
|
||||||
),
|
),
|
||||||
ExpectNonEmptyPlan: true, // TODO: check the plan.
|
ExpectNonEmptyPlan: true, // TODO: check the plan.
|
||||||
},
|
},
|
||||||
// Re-running plan should have the same effect.
|
// 3) Re-running plan should have the same effect.
|
||||||
{
|
{
|
||||||
Config: deps.Config(t),
|
Config: deps.Config(t),
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
// Computed values MUST be present.
|
// Computed values MUST be present.
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "id", uuid.Nil.String()),
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "id", uuid.Nil.String()),
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "exists", "false"),
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "exists", "false"),
|
||||||
resource.TestCheckResourceAttrSet("envbuilder_cached_image.test", "env.0"),
|
|
||||||
// Cached image should be set to the builder image.
|
// Cached image should be set to the builder image.
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "image", deps.BuilderImage),
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "image", deps.BuilderImage),
|
||||||
// Inputs should still be present.
|
// Inputs should still be present.
|
||||||
|
@ -91,10 +97,12 @@ RUN date > /date.txt`,
|
||||||
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_username"),
|
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_username"),
|
||||||
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_password"),
|
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "git_password"),
|
||||||
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "cache_ttl_days"),
|
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "cache_ttl_days"),
|
||||||
|
// Environment variables
|
||||||
|
assertEnv(t, deps),
|
||||||
),
|
),
|
||||||
ExpectNonEmptyPlan: true, // TODO: check the plan.
|
ExpectNonEmptyPlan: true, // TODO: check the plan.
|
||||||
},
|
},
|
||||||
// Now, seed the cache and re-run. We should now successfully create the cached image resource.
|
// 4) Now, seed the cache and re-run. We should now successfully create the cached image resource.
|
||||||
{
|
{
|
||||||
PreConfig: func() {
|
PreConfig: func() {
|
||||||
seedCache(ctx, t, deps)
|
seedCache(ctx, t, deps)
|
||||||
|
@ -114,19 +122,16 @@ RUN date > /date.txt`,
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "exists", "true"),
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "exists", "true"),
|
||||||
resource.TestCheckResourceAttrSet("envbuilder_cached_image.test", "image"),
|
resource.TestCheckResourceAttrSet("envbuilder_cached_image.test", "image"),
|
||||||
resource.TestCheckResourceAttrWith("envbuilder_cached_image.test", "image", quotedPrefix(deps.CacheRepo)),
|
resource.TestCheckResourceAttrWith("envbuilder_cached_image.test", "image", quotedPrefix(deps.CacheRepo)),
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.0", "FOO=bar\nbaz"),
|
// Environment variables
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.1", fmt.Sprintf("ENVBUILDER_CACHE_REPO=%s", deps.CacheRepo)),
|
assertEnv(t, deps),
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.2", fmt.Sprintf("ENVBUILDER_GIT_URL=%s", deps.Repo.URL)),
|
|
||||||
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.3", "ENVBUILDER_REMOTE_REPO_BUILD_MODE=true"),
|
|
||||||
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "env.4"),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
// Should produce an empty plan after apply
|
// 5) Should produce an empty plan after apply
|
||||||
{
|
{
|
||||||
Config: deps.Config(t),
|
Config: deps.Config(t),
|
||||||
PlanOnly: true,
|
PlanOnly: true,
|
||||||
},
|
},
|
||||||
// Ensure idempotence in this state!
|
// 6) Ensure idempotence in this state!
|
||||||
{
|
{
|
||||||
Config: deps.Config(t),
|
Config: deps.Config(t),
|
||||||
PlanOnly: true,
|
PlanOnly: true,
|
||||||
|
@ -136,3 +141,24 @@ RUN date > /date.txt`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assertEnv is a test helper that checks the environment variables set on the
|
||||||
|
// cached image resource based on the provided test dependencies.
|
||||||
|
func assertEnv(t *testing.T, deps testDependencies) resource.TestCheckFunc {
|
||||||
|
t.Helper()
|
||||||
|
return resource.ComposeAggregateTestCheckFunc(
|
||||||
|
// Check that the environment variables are set correctly.
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.0", fmt.Sprintf("ENVBUILDER_CACHE_REPO=%s", deps.CacheRepo)),
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.1", fmt.Sprintf("ENVBUILDER_GIT_URL=%s", deps.Repo.URL)),
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.2", "ENVBUILDER_REMOTE_REPO_BUILD_MODE=true"),
|
||||||
|
// Check that the extra environment variables are set correctly.
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env.3", "FOO=bar\nbaz"),
|
||||||
|
// We should not have any other environment variables set.
|
||||||
|
resource.TestCheckNoResourceAttr("envbuilder_cached_image.test", "env.4"),
|
||||||
|
// Check that the same values are set in env_map.
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env_map.FOO", "bar\nbaz"),
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env_map.ENVBUILDER_CACHE_REPO", deps.CacheRepo),
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env_map.ENVBUILDER_GIT_URL", deps.Repo.URL),
|
||||||
|
resource.TestCheckResourceAttr("envbuilder_cached_image.test", "env_map.ENVBUILDER_REMOTE_REPO_BUILD_MODE", "true"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue