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 22, 2024
1 parent 6ebd419 commit a306b70
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 10 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@ terraform-provider-coderd
integration/integration.tfrc

*.tfstate

# Local .terraform directories
**/.terraform/*


# Ignore transient lock info files created by terraform apply
.terraform.tfstate.lock.info
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. (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.
2 changes: 1 addition & 1 deletion docs/resources/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ resource "coderd_template" "ubuntu-main" {
- `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 with the provided message and users will be blocked from creating new workspaces from it.
- `deprecation_message` (String) If set, the template will be marked as deprecated with the provided message and users will be blocked from creating new workspaces from it. 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
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.",
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
4 changes: 2 additions & 2 deletions internal/provider/template_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ func (r *TemplateResource) Schema(ctx context.Context, req resource.SchemaReques
Default: booldefault.StaticBool(false),
},
"deprecation_message": schema.StringAttribute{
MarkdownDescription: "If set, the template will be marked as deprecated with the provided message and users will be blocked from creating new workspaces from it.",
MarkdownDescription: "If set, the template will be marked as deprecated with the provided message and users will be blocked from creating new workspaces from it. Does nothing if set when the resource is created.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
Expand Down Expand Up @@ -586,8 +586,8 @@ func (r *TemplateResource) Read(ctx context.Context, req resource.ReadRequest, r
}
tfACL := convertResponseToACL(acl)
aclObj, diag := types.ObjectValueFrom(ctx, aclTypeAttr, tfACL)
diag.Append(diag...)
if diag.HasError() {
resp.Diagnostics.Append(diag...)
return
}
data.ACL = aclObj
Expand Down

0 comments on commit a306b70

Please sign in to comment.