-
Notifications
You must be signed in to change notification settings - Fork 957
feat(enterprise/coderd): allow system users to be added to groups #18341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6b3a731
4b63826
90b9078
af7c7cd
1cd68e3
4c0c4d4
93c46e9
b3728d3
efdfe9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,13 @@ | ||
-- name: GetGroupMembers :many | ||
SELECT * FROM group_members_expanded | ||
WHERE CASE | ||
WHEN @include_system::bool THEN TRUE | ||
ELSE | ||
user_is_system = false | ||
END; | ||
WHERE (@include_system::bool OR NOT user_is_system); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
https://www.postgresql.org/docs/17/sql-expressions.html#SYNTAX-EXPRESS-EVAL There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was the one who suggested this change #18341 (comment) Sorry about that @SasSwart 🙇♀️ |
||
|
||
-- name: GetGroupMembersByGroupID :many | ||
SELECT * | ||
FROM group_members_expanded | ||
WHERE group_id = @group_id | ||
-- Filter by system type | ||
AND CASE | ||
WHEN @include_system::bool THEN TRUE | ||
ELSE | ||
user_is_system = false | ||
END; | ||
AND (@include_system::bool OR NOT user_is_system); | ||
|
||
-- name: GetGroupMembersCountByGroupID :one | ||
-- Returns the total count of members in a group. Shows the total | ||
|
@@ -25,11 +17,7 @@ SELECT COUNT(*) | |
FROM group_members_expanded | ||
WHERE group_id = @group_id | ||
-- Filter by system type | ||
AND CASE | ||
WHEN @include_system::bool THEN TRUE | ||
ELSE | ||
user_is_system = false | ||
END; | ||
AND (@include_system::bool OR NOT user_is_system); | ||
|
||
-- InsertUserGroupsByName adds a user to all provided groups, if they exist. | ||
-- name: InsertUserGroupsByName :exec | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,11 +24,7 @@ WHERE | |
ELSE true | ||
END | ||
-- Filter by system type | ||
AND CASE | ||
WHEN @include_system::bool THEN TRUE | ||
ELSE | ||
is_system = false | ||
END; | ||
AND (@include_system::bool OR NOT is_system); | ||
|
||
-- name: InsertOrganizationMember :one | ||
INSERT INTO | ||
|
@@ -89,6 +85,8 @@ WHERE | |
organization_id = @organization_id | ||
ELSE true | ||
END | ||
-- Filter by system type | ||
AND (@include_system::bool OR NOT is_system) | ||
Comment on lines
+88
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we adding this filter here? |
||
ORDER BY | ||
-- Deterministic and consistent ordering of all users. This is to ensure consistent pagination. | ||
LOWER(username) ASC OFFSET @offset_opt | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -235,12 +235,18 @@ The system always maintains the desired number of prebuilt workspaces for the ac | |
|
||
### Managing resource quotas | ||
|
||
Prebuilt workspaces can be used in conjunction with [resource quotas](../../users/quotas.md). | ||
To help prevent unexpected infrastructure costs, prebuilt workspaces can be used in conjunction with [resource quotas](../../users/quotas.md). | ||
Because unclaimed prebuilt workspaces are owned by the `prebuilds` user, you can: | ||
|
||
1. Configure quotas for any group that includes this user. | ||
1. Set appropriate limits to balance prebuilt workspace availability with resource constraints. | ||
|
||
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: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you update the PR description to match? |
||
|
||
- **Set a quota allowance** on the "prebuilds" group to control how many prebuilt workspaces can be provisioned | ||
- **Monitor usage** to ensure the quota is appropriate for your desired number of prebuilt instances | ||
- **Adjust as needed** based on your template costs and desired prebuilt workspace pool size | ||
|
||
If a quota is exceeded, the prebuilt workspace will fail provisioning the same way other workspaces do. | ||
|
||
### Template configuration best practices | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -156,7 +156,7 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) { | |
|
||
currentMembers, err := api.Database.GetGroupMembersByGroupID(ctx, database.GetGroupMembersByGroupIDParams{ | ||
GroupID: group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we still need all these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think so, because I maintain that the prebuilds user should be visible. If we decide that we should hide the prebuilds user, then we can revert this back to false. |
||
}) | ||
if err != nil { | ||
httpapi.InternalServerError(rw, err) | ||
|
@@ -180,7 +180,7 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) { | |
_, err := database.ExpectOne(api.Database.OrganizationMembers(ctx, database.OrganizationMembersParams{ | ||
OrganizationID: group.OrganizationID, | ||
UserID: uuid.MustParse(id), | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
})) | ||
if errors.Is(err, sql.ErrNoRows) { | ||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ | ||
|
@@ -296,7 +296,7 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) { | |
|
||
patchedMembers, err := api.Database.GetGroupMembersByGroupID(ctx, database.GetGroupMembersByGroupIDParams{ | ||
GroupID: group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
}) | ||
if err != nil { | ||
httpapi.InternalServerError(rw, err) | ||
|
@@ -307,7 +307,7 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) { | |
|
||
memberCount, err := api.Database.GetGroupMembersCountByGroupID(ctx, database.GetGroupMembersCountByGroupIDParams{ | ||
GroupID: group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
}) | ||
if err != nil { | ||
httpapi.InternalServerError(rw, err) | ||
|
@@ -353,7 +353,7 @@ func (api *API) deleteGroup(rw http.ResponseWriter, r *http.Request) { | |
|
||
groupMembers, getMembersErr := api.Database.GetGroupMembersByGroupID(ctx, database.GetGroupMembersByGroupIDParams{ | ||
GroupID: group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
}) | ||
if getMembersErr != nil { | ||
httpapi.InternalServerError(rw, getMembersErr) | ||
|
@@ -407,7 +407,7 @@ func (api *API) group(rw http.ResponseWriter, r *http.Request) { | |
|
||
users, err := api.Database.GetGroupMembersByGroupID(ctx, database.GetGroupMembersByGroupIDParams{ | ||
GroupID: group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
}) | ||
if err != nil && !errors.Is(err, sql.ErrNoRows) { | ||
httpapi.InternalServerError(rw, err) | ||
|
@@ -416,7 +416,7 @@ func (api *API) group(rw http.ResponseWriter, r *http.Request) { | |
|
||
memberCount, err := api.Database.GetGroupMembersCountByGroupID(ctx, database.GetGroupMembersCountByGroupIDParams{ | ||
GroupID: group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
}) | ||
if err != nil { | ||
httpapi.InternalServerError(rw, err) | ||
|
@@ -512,15 +512,15 @@ func (api *API) groups(rw http.ResponseWriter, r *http.Request) { | |
for _, group := range groups { | ||
members, err := api.Database.GetGroupMembersByGroupID(ctx, database.GetGroupMembersByGroupIDParams{ | ||
GroupID: group.Group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
}) | ||
if err != nil { | ||
httpapi.InternalServerError(rw, err) | ||
return | ||
} | ||
memberCount, err := api.Database.GetGroupMembersCountByGroupID(ctx, database.GetGroupMembersCountByGroupIDParams{ | ||
GroupID: group.Group.ID, | ||
IncludeSystem: false, | ||
IncludeSystem: true, | ||
}) | ||
if err != nil { | ||
httpapi.InternalServerError(rw, err) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -862,12 +862,12 @@ func TestGroup(t *testing.T) { | |
// The 'Everyone' group always has an ID that matches the organization ID. | ||
group, err := userAdminClient.Group(ctx, user.OrganizationID) | ||
require.NoError(t, err) | ||
require.Len(t, group.Members, 4) | ||
require.Len(t, group.Members, 5) | ||
require.Equal(t, "Everyone", group.Name) | ||
require.Equal(t, user.OrganizationID, group.OrganizationID) | ||
require.Contains(t, group.Members, user1.ReducedUser) | ||
require.Contains(t, group.Members, user2.ReducedUser) | ||
require.NotContains(t, group.Members, prebuildsUser.ReducedUser) | ||
require.Contains(t, group.Members, prebuildsUser.ReducedUser) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we include system users in the |
||
}) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add comments explaining why the prebuilds user needs this privilege?