Skip to content

Commit 1cd68e3

Browse files
committed
create a prebuilds group in every org that needs it
1 parent af7c7cd commit 1cd68e3

File tree

4 files changed

+233
-96
lines changed

4 files changed

+233
-96
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,14 @@ var (
467467
rbac.ResourceFile.Type: {
468468
policy.ActionRead,
469469
},
470+
rbac.ResourceGroup.Type: {
471+
policy.ActionRead,
472+
policy.ActionCreate,
473+
policy.ActionUpdate,
474+
},
475+
rbac.ResourceGroupMember.Type: {
476+
policy.ActionRead,
477+
},
470478
}),
471479
},
472480
}),

docs/admin/templates/extending-templates/prebuilt-workspaces.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,18 @@ The system always maintains the desired number of prebuilt workspaces for the ac
235235

236236
### Managing resource quotas
237237

238-
Prebuilt workspaces can be used in conjunction with [resource quotas](../../users/quotas.md).
238+
To help prevent unexpected infrastructure costs, prebuilt workspaces can be used in conjunction with [resource quotas](../../users/quotas.md).
239239
Because unclaimed prebuilt workspaces are owned by the `prebuilds` user, you can:
240240

241241
1. Configure quotas for any group that includes this user.
242242
1. Set appropriate limits to balance prebuilt workspace availability with resource constraints.
243243

244+
When prebuilt workspaces are configured for an organization, Coder creates a "prebuilds" group in that organization and adds the prebuilds user to it. This group has a default quota allowance of 0, which you should adjust based on your needs:
245+
246+
- **Set a quota allowance** on the "prebuilds" group to control how many prebuilt workspaces can be provisioned
247+
- **Monitor usage** to ensure the quota is appropriate for your desired number of prebuilt instances
248+
- **Adjust as needed** based on your template costs and desired prebuilt workspace pool size
249+
244250
If a quota is exceeded, the prebuilt workspace will fail provisioning the same way other workspaces do.
245251

246252
### Template configuration best practices

enterprise/coderd/prebuilds/membership.go

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,37 +44,74 @@ func (s StoreMembershipReconciler) ReconcileAll(ctx context.Context, userID uuid
4444
return xerrors.Errorf("determine prebuild organization membership: %w", err)
4545
}
4646

47-
systemUserMemberships := make(map[uuid.UUID]struct{}, 0)
47+
orgMemberShips := make(map[uuid.UUID]struct{}, 0)
4848
defaultOrg, err := s.store.GetDefaultOrganization(ctx)
4949
if err != nil {
5050
return xerrors.Errorf("get default organization: %w", err)
5151
}
52-
systemUserMemberships[defaultOrg.ID] = struct{}{}
52+
orgMemberShips[defaultOrg.ID] = struct{}{}
5353
for _, o := range organizationMemberships {
54-
systemUserMemberships[o.ID] = struct{}{}
54+
orgMemberShips[o.ID] = struct{}{}
5555
}
5656

5757
var membershipInsertionErrors error
5858
for _, preset := range presets {
59-
_, alreadyMember := systemUserMemberships[preset.OrganizationID]
60-
if alreadyMember {
61-
continue
59+
_, alreadyOrgMember := orgMemberShips[preset.OrganizationID]
60+
if !alreadyOrgMember {
61+
// Add the organization to our list of memberships regardless of potential failure below
62+
// to avoid a retry that will probably be doomed anyway.
63+
orgMemberShips[preset.OrganizationID] = struct{}{}
64+
65+
// Insert the missing membership
66+
_, err = s.store.InsertOrganizationMember(ctx, database.InsertOrganizationMemberParams{
67+
OrganizationID: preset.OrganizationID,
68+
UserID: userID,
69+
CreatedAt: s.clock.Now(),
70+
UpdatedAt: s.clock.Now(),
71+
Roles: []string{},
72+
})
73+
if err != nil {
74+
membershipInsertionErrors = errors.Join(membershipInsertionErrors, xerrors.Errorf("insert membership for prebuilt workspaces: %w", err))
75+
continue
76+
}
6277
}
63-
// Add the organization to our list of memberships regardless of potential failure below
64-
// to avoid a retry that will probably be doomed anyway.
65-
systemUserMemberships[preset.OrganizationID] = struct{}{}
6678

67-
// Insert the missing membership
68-
_, err = s.store.InsertOrganizationMember(ctx, database.InsertOrganizationMemberParams{
79+
// Create a "prebuilds" group in the organization and add the system user to it
80+
// This group will have a quota of 0 by default, which users can adjust based on their needs
81+
prebuildsGroup, err := s.store.InsertGroup(ctx, database.InsertGroupParams{
82+
ID: uuid.New(),
83+
Name: "prebuilds",
84+
DisplayName: "Prebuilds",
6985
OrganizationID: preset.OrganizationID,
70-
UserID: userID,
71-
CreatedAt: s.clock.Now(),
72-
UpdatedAt: s.clock.Now(),
73-
Roles: []string{},
86+
AvatarURL: "",
87+
QuotaAllowance: 0, // Default quota of 0, users should set this based on their needs
88+
})
89+
if err != nil {
90+
// If the group already exists, try to get it
91+
if !database.IsUniqueViolation(err) {
92+
membershipInsertionErrors = errors.Join(membershipInsertionErrors, xerrors.Errorf("create prebuilds group: %w", err))
93+
continue
94+
}
95+
prebuildsGroup, err = s.store.GetGroupByOrgAndName(ctx, database.GetGroupByOrgAndNameParams{
96+
OrganizationID: preset.OrganizationID,
97+
Name: "prebuilds",
98+
})
99+
if err != nil {
100+
membershipInsertionErrors = errors.Join(membershipInsertionErrors, xerrors.Errorf("get existing prebuilds group: %w", err))
101+
continue
102+
}
103+
}
104+
105+
// Add the system user to the prebuilds group
106+
err = s.store.InsertGroupMember(ctx, database.InsertGroupMemberParams{
107+
GroupID: prebuildsGroup.ID,
108+
UserID: userID,
74109
})
75110
if err != nil {
76-
membershipInsertionErrors = errors.Join(membershipInsertionErrors, xerrors.Errorf("insert membership for prebuilt workspaces: %w", err))
77-
continue
111+
// Ignore unique violation errors as the user might already be in the group
112+
if !database.IsUniqueViolation(err) {
113+
membershipInsertionErrors = errors.Join(membershipInsertionErrors, xerrors.Errorf("add system user to prebuilds group: %w", err))
114+
}
78115
}
79116
}
80117
return membershipInsertionErrors

0 commit comments

Comments
 (0)