Skip to content

Commit

Permalink
chore: add missing template data source fields
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanndickson committed Aug 21, 2024
1 parent ef286de commit ea6324f
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 22 deletions.
42 changes: 42 additions & 0 deletions docs/data-sources/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,15 @@ data "coderd_template" "example-template2" {

### Read-Only

- `acl` (Attributes) (Enterprise) Access control list for the template. If null, ACL policies will not be added, removed, or inspected by Terraform. (see [below for nested schema](#nestedatt--acl))
- `active_user_count` (Number) Number of active users using the template.
- `active_version_id` (String) ID of the active version of the template.
- `activity_bump_ms` (Number) Duration to bump the deadline of a workspace when it receives activity.
- `allow_user_autostart` (Boolean) Whether users can autostart workspaces created from the template.
- `allow_user_autostop` (Boolean) Whether users can customize autostop behavior for workspaces created from the template.
- `allow_user_cancel_workspace_jobs` (Boolean) Whether users can cancel jobs in workspaces created from the template.
- `auto_start_permitted_days_of_week` (Set of String) List of days of the week in which autostart is allowed to happen, for all workspaces created from this template. Defaults to all days. If no days are specified, autostart is not allowed.
- `auto_stop_requirement` (Attributes) The auto-stop requirement for all workspaces created from this template. (see [below for nested schema](#nestedatt--auto_stop_requirement))
- `created_at` (Number) Unix timestamp of when the template was created.
- `created_by_user_id` (String) ID of the user who created the template.
- `default_ttl_ms` (Number) Default time-to-live for workspaces created from the template.
Expand All @@ -50,7 +53,46 @@ data "coderd_template" "example-template2" {
- `display_name` (String) Display name of the template.
- `failure_ttl_ms` (Number) Automatic cleanup TTL for failed workspace builds.
- `icon` (String) URL of the template's icon.
- `max_port_share_level` (String) The maximum port share level for workspaces created from the template.
- `require_active_version` (Boolean) Whether workspaces created from the template must be up-to-date on the latest active version.
- `time_til_dormant_autodelete_ms` (Number) Duration of inactivity after the workspace becomes dormant before a workspace is automatically deleted.
- `time_til_dormant_ms` (Number) Duration of inactivity before a workspace is considered dormant.
- `updated_at` (Number) Unix timestamp of when the template was last updated.

<a id="nestedatt--acl"></a>
### Nested Schema for `acl`

Read-Only:

- `groups` (Attributes Set) (see [below for nested schema](#nestedatt--acl--groups))
- `users` (Attributes Set) (see [below for nested schema](#nestedatt--acl--users))

<a id="nestedatt--acl--groups"></a>
### Nested Schema for `acl.groups`

Read-Only:

- `id` (String)
- `role` (String)


<a id="nestedatt--acl--users"></a>
### Nested Schema for `acl.users`

Read-Only:

- `id` (String)
- `role` (String)



<a id="nestedatt--auto_stop_requirement"></a>
### Nested Schema for `auto_stop_requirement`

Optional:

- `weeks` (Number) Weeks is the number of weeks between required restarts. Weeks are synced across all workspaces (and Coder deployments) using modulo math on a hardcoded epoch week of January 2nd, 2023 (the first Monday of 2023). Values of 0 or 1 indicate weekly restarts. Values of 2 indicate fortnightly restarts, etc.

Read-Only:

- `days_of_week` (Set of String) List of days of the week on which restarts are required. Restarts happen within the user's quiet hours (in their configured timezone). If no days are specified, restarts are not required.
4 changes: 2 additions & 2 deletions docs/resources/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ resource "coderd_template" "ubuntu-main" {

### Optional

- `acl` (Attributes) (Enterprise) Access control list for the template. If null, ACL policies will not be added, removed, or inspected by Terraform. (see [below for nested schema](#nestedatt--acl))
- `acl` (Attributes) (Enterprise) Access control list for the template. (see [below for nested schema](#nestedatt--acl))
- `activity_bump_ms` (Number) The activity bump duration for all workspaces created from this template, in milliseconds. Defaults to one hour.
- `allow_user_auto_start` (Boolean) (Enterprise) Whether users can auto-start workspaces created from this template. Defaults to true.
- `allow_user_auto_stop` (Boolean) (Enterprise) Whether users can auto-start workspaces created from this template. Defaults to true.
- `allow_user_cancel_workspace_jobs` (Boolean) Whether users can cancel in-progress workspace jobs using this template. Defaults to true.
- `auto_start_permitted_days_of_week` (Set of String) (Enterprise) List of days of the week in which autostart is allowed to happen, for all workspaces created from this template. Defaults to all days. If no days are specified, autostart is not allowed.
- `auto_stop_requirement` (Attributes) (Enterprise) The auto-stop requirement for all workspaces created from this template. (see [below for nested schema](#nestedatt--auto_stop_requirement))
- `default_ttl_ms` (Number) The default time-to-live for all workspaces created from this template, in milliseconds.
- `deprecation_message` (String) If set, the template will be marked as deprecated and users will be blocked from creating new workspaces from it. The provided message will be displayed.
- `deprecation_message` (String) If set, the template will be marked as deprecated and users will be blocked from creating new workspaces from it. The provided message will be displayed. Does nothing if set when the resource is created.
- `description` (String) A description of the template.
- `display_name` (String) The display name of the template. Defaults to the template name.
- `failure_ttl_ms` (Number) (Enterprise) The max lifetime before Coder stops all resources for failed workspaces created from this template, in milliseconds.
Expand Down
24 changes: 24 additions & 0 deletions examples/provider/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 11 additions & 10 deletions integration/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ func StartCoder(ctx context.Context, t *testing.T, name string, useLicense bool)
coderVersion = "latest"
}

coderLicense := os.Getenv("CODER_ENTERPRISE_LICENSE")
if useLicense && coderLicense == "" {
t.Skip("Skipping tests that require a license.")
}
// coderLicense := os.Getenv("CODER_ENTERPRISE_LICENSE")
// if useLicense && coderLicense == "" {
// t.Skip("Skipping tests that require a license.")
// }

t.Logf("using coder image %s:%s", coderImg, coderVersion)

Expand Down Expand Up @@ -101,6 +101,7 @@ func StartCoder(ctx context.Context, t *testing.T, name string, useLicense bool)
Email: testEmail,
Username: testUsername,
Password: testPassword,
Trial: useLicense,
})
require.NoError(t, err, "create first user")
resp, err := client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
Expand All @@ -109,12 +110,12 @@ func StartCoder(ctx context.Context, t *testing.T, name string, useLicense bool)
})
require.NoError(t, err, "login to coder instance with password")
client.SetSessionToken(resp.SessionToken)
if useLicense {
_, err := client.AddLicense(ctx, codersdk.AddLicenseRequest{
License: coderLicense,
})
require.NoError(t, err, "add license")
}
// if useLicense {
// _, err := client.AddLicense(ctx, codersdk.AddLicenseRequest{
// License: coderLicense,
// })
// require.NoError(t, err, "add license")
// }
return client
}

Expand Down
91 changes: 84 additions & 7 deletions internal/provider/template_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/coder/coder/v2/codersdk"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
Expand Down Expand Up @@ -42,10 +43,10 @@ type TemplateDataSourceModel struct {
DeprecationMessage types.String `tfsdk:"deprecation_message"`
Icon types.String `tfsdk:"icon"`

DefaultTTLMillis types.Int64 `tfsdk:"default_ttl_ms"`
ActivityBumpMillis types.Int64 `tfsdk:"activity_bump_ms"`
// TODO: AutostopRequirement
// TODO: AutostartRequirement
DefaultTTLMillis types.Int64 `tfsdk:"default_ttl_ms"`
ActivityBumpMillis types.Int64 `tfsdk:"activity_bump_ms"`
AutostopRequirement types.Object `tfsdk:"auto_stop_requirement"`
AutostartPermittedDaysOfWeek types.Set `tfsdk:"auto_start_permitted_days_of_week"`

AllowUserAutostart types.Bool `tfsdk:"allow_user_autostart"`
AllowUserAutostop types.Bool `tfsdk:"allow_user_autostop"`
Expand All @@ -55,14 +56,14 @@ type TemplateDataSourceModel struct {
TimeTilDormantMillis types.Int64 `tfsdk:"time_til_dormant_ms"`
TimeTilDormantAutoDeleteMillis types.Int64 `tfsdk:"time_til_dormant_autodelete_ms"`

RequireActiveVersion types.Bool `tfsdk:"require_active_version"`
// TODO: MaxPortShareLevel
RequireActiveVersion types.Bool `tfsdk:"require_active_version"`
MaxPortShareLevel types.String `tfsdk:"max_port_share_level"`

CreatedByUserID UUID `tfsdk:"created_by_user_id"`
CreatedAt types.Int64 `tfsdk:"created_at"` // Unix timestamp
UpdatedAt types.Int64 `tfsdk:"updated_at"` // Unix timestamp

// TODO: ACL-related stuff
ACL types.Object `tfsdk:"acl"`
}

func (d *TemplateDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
Expand Down Expand Up @@ -134,6 +135,27 @@ func (d *TemplateDataSource) Schema(ctx context.Context, req datasource.SchemaRe
MarkdownDescription: "Duration to bump the deadline of a workspace when it receives activity.",
Computed: true,
},
"auto_stop_requirement": schema.SingleNestedAttribute{
MarkdownDescription: "The auto-stop requirement for all workspaces created from this template.",
Computed: true,
Attributes: map[string]schema.Attribute{
"days_of_week": schema.SetAttribute{
MarkdownDescription: "List of days of the week on which restarts are required. Restarts happen within the user's quiet hours (in their configured timezone). If no days are specified, restarts are not required.",
Computed: true,
ElementType: types.StringType,
},
"weeks": schema.Int64Attribute{
MarkdownDescription: "Weeks is the number of weeks between required restarts. Weeks are synced across all workspaces (and Coder deployments) using modulo math on a hardcoded epoch week of January 2nd, 2023 (the first Monday of 2023). Values of 0 or 1 indicate weekly restarts. Values of 2 indicate fortnightly restarts, etc.",
Optional: true,
Computed: true,
},
},
},
"auto_start_permitted_days_of_week": schema.SetAttribute{
MarkdownDescription: "List of days of the week in which autostart is allowed to happen, for all workspaces created from this template. Defaults to all days. If no days are specified, autostart is not allowed.",
Computed: true,
ElementType: types.StringType,
},
"allow_user_autostart": schema.BoolAttribute{
MarkdownDescription: "Whether users can autostart workspaces created from the template.",
Computed: true,
Expand Down Expand Up @@ -162,6 +184,10 @@ func (d *TemplateDataSource) Schema(ctx context.Context, req datasource.SchemaRe
MarkdownDescription: "Whether workspaces created from the template must be up-to-date on the latest active version.",
Computed: true,
},
"max_port_share_level": schema.StringAttribute{
MarkdownDescription: "The maximum port share level for workspaces created from the template.",
Computed: true,
},
"created_by_user_id": schema.StringAttribute{
MarkdownDescription: "ID of the user who created the template.",
CustomType: UUIDType,
Expand All @@ -175,6 +201,14 @@ func (d *TemplateDataSource) Schema(ctx context.Context, req datasource.SchemaRe
MarkdownDescription: "Unix timestamp of when the template was last updated.",
Computed: true,
},
"acl": schema.SingleNestedAttribute{
MarkdownDescription: "(Enterprise) Access control list for the template. If null, ACL policies will not be added, removed, or inspected by Terraform.",
Computed: true,
Attributes: map[string]schema.Attribute{
"users": computedPermissionAttribute,
"groups": computedPermissionAttribute,
},
},
},
}
}
Expand Down Expand Up @@ -244,6 +278,33 @@ func (d *TemplateDataSource) Read(ctx context.Context, req datasource.ReadReques
return
}

acl, err := client.TemplateACL(ctx, template.ID)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to get template ACL: %s", err))
return
}
tfACL := convertResponseToACL(acl)
aclObj, diag := types.ObjectValueFrom(ctx, aclTypeAttr, tfACL)
if diag.HasError() {
resp.Diagnostics.Append(diag...)
return
}

asrObj, diag := types.ObjectValueFrom(ctx, autostopRequirementTypeAttr, AutostopRequirement{
DaysOfWeek: template.AutostopRequirement.DaysOfWeek,
Weeks: template.AutostopRequirement.Weeks,
})
resp.Diagnostics.Append(diag...)
if resp.Diagnostics.HasError() {
return
}
autoStartDays := make([]attr.Value, 0, len(template.AutostartRequirement.DaysOfWeek))
for _, day := range template.AutostartRequirement.DaysOfWeek {
autoStartDays = append(autoStartDays, types.StringValue(day))
}
data.ACL = aclObj
data.AutostartPermittedDaysOfWeek = types.SetValueMust(types.StringType, autoStartDays)
data.AutostopRequirement = asrObj
data.OrganizationID = UUIDValue(template.OrganizationID)
data.ID = UUIDValue(template.ID)
data.Name = types.StringValue(template.Name)
Expand All @@ -263,10 +324,26 @@ func (d *TemplateDataSource) Read(ctx context.Context, req datasource.ReadReques
data.TimeTilDormantMillis = types.Int64Value(template.TimeTilDormantMillis)
data.TimeTilDormantAutoDeleteMillis = types.Int64Value(template.TimeTilDormantAutoDeleteMillis)
data.RequireActiveVersion = types.BoolValue(template.RequireActiveVersion)
data.MaxPortShareLevel = types.StringValue(string(template.MaxPortShareLevel))
data.CreatedByUserID = UUIDValue(template.CreatedByID)
data.CreatedAt = types.Int64Value(template.CreatedAt.Unix())
data.UpdatedAt = types.Int64Value(template.UpdatedAt.Unix())

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

// computedPermissionAttribute is the attribute schema for a computed instance of `[]Permission`.
var computedPermissionAttribute = schema.SetNestedAttribute{
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
"role": schema.StringAttribute{
Computed: true,
},
},
},
}
25 changes: 25 additions & 0 deletions internal/provider/template_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ func TestAccTemplateDataSource(t *testing.T) {
})
require.NoError(t, err)

err = client.UpdateTemplateACL(ctx, tpl.ID, codersdk.UpdateTemplateACL{
UserPerms: map[string]codersdk.TemplateRole{
firstUser.ID.String(): codersdk.TemplateRoleAdmin,
},
GroupPerms: map[string]codersdk.TemplateRole{
firstUser.OrganizationIDs[0].String(): codersdk.TemplateRoleUse,
},
})
require.NoError(t, err)

checkFn := resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.coderd_template.test", "organization_id", tpl.OrganizationID.String()),
resource.TestCheckResourceAttr("data.coderd_template.test", "id", tpl.ID.String()),
Expand All @@ -112,16 +122,31 @@ func TestAccTemplateDataSource(t *testing.T) {
resource.TestCheckResourceAttr("data.coderd_template.test", "icon", tpl.Icon),
resource.TestCheckResourceAttr("data.coderd_template.test", "default_ttl_ms", strconv.FormatInt(tpl.DefaultTTLMillis, 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "activity_bump_ms", strconv.FormatInt(tpl.ActivityBumpMillis, 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "auto_stop_requirement.days_of_week.#", strconv.FormatInt(int64(len(tpl.AutostopRequirement.DaysOfWeek)), 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "auto_stop_requirement.weeks", strconv.FormatInt(tpl.AutostopRequirement.Weeks, 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "auto_start_permitted_days_of_week.#", strconv.FormatInt(int64(len(tpl.AutostartRequirement.DaysOfWeek)), 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "allow_user_cancel_workspace_jobs", "true"),
resource.TestCheckResourceAttr("data.coderd_template.test", "allow_user_autostart", strconv.FormatBool(tpl.AllowUserAutostart)),
resource.TestCheckResourceAttr("data.coderd_template.test", "allow_user_autostop", strconv.FormatBool(tpl.AllowUserAutostop)),
resource.TestCheckResourceAttr("data.coderd_template.test", "allow_user_cancel_workspace_jobs", strconv.FormatBool(tpl.AllowUserCancelWorkspaceJobs)),
resource.TestCheckResourceAttr("data.coderd_template.test", "failure_ttl_ms", strconv.FormatInt(tpl.FailureTTLMillis, 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "time_til_dormant_ms", strconv.FormatInt(tpl.TimeTilDormantMillis, 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "time_til_dormant_autodelete_ms", strconv.FormatInt(tpl.TimeTilDormantAutoDeleteMillis, 10)),
resource.TestCheckResourceAttr("data.coderd_template.test", "require_active_version", strconv.FormatBool(tpl.RequireActiveVersion)),
resource.TestCheckResourceAttr("data.coderd_template.test", "max_port_share_level", string(tpl.MaxPortShareLevel)),
resource.TestCheckResourceAttr("data.coderd_template.test", "created_by_user_id", firstUser.ID.String()),
resource.TestCheckResourceAttr("data.coderd_template.test", "created_at", strconv.Itoa(int(tpl.CreatedAt.Unix()))),
resource.TestCheckResourceAttr("data.coderd_template.test", "updated_at", strconv.Itoa(int(tpl.UpdatedAt.Unix()))),
resource.TestCheckResourceAttr("data.coderd_template.test", "acl.groups.#", "1"),
resource.TestCheckResourceAttr("data.coderd_template.test", "acl.users.#", "1"),
resource.TestMatchTypeSetElemNestedAttrs("data.coderd_template.test", "acl.groups.*", map[string]*regexp.Regexp{
"id": regexp.MustCompile(firstUser.OrganizationIDs[0].String()),
"role": regexp.MustCompile("^use$"),
}),
resource.TestMatchTypeSetElemNestedAttrs("data.coderd_template.test", "acl.users.*", map[string]*regexp.Regexp{
"id": regexp.MustCompile(firstUser.ID.String()),
"role": regexp.MustCompile("^admin$"),
}),
)

t.Run("TemplateByOrgAndNameOK", func(t *testing.T) {
Expand Down
Loading

0 comments on commit ea6324f

Please sign in to comment.