Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add system user with special uuid
  • Loading branch information
AbhineetJain committed Jun 16, 2022
commit f79a138d568e44e262cb1d761f66ef15222f5d5e
10 changes: 8 additions & 2 deletions coderd/autobuild/executor/lifecycle_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,17 @@ func build(ctx context.Context, store database.Store, workspace database.Workspa
}
provisionerJobID := uuid.New()
now := database.Now()

systemUser, err := store.GetUserByID(ctx, database.SystemUserID)
if err != nil {
return xerrors.Errorf("get system user: %w", err)
}

newProvisionerJob, err := store.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{
ID: provisionerJobID,
CreatedAt: now,
UpdatedAt: now,
InitiatorID: workspace.OwnerID,
InitiatorID: systemUser.ID,
OrganizationID: template.OrganizationID,
Provisioner: template.Provisioner,
Type: database.ProvisionerJobTypeWorkspaceBuild,
Expand All @@ -233,7 +239,7 @@ func build(ctx context.Context, store database.Store, workspace database.Workspa
BuildNumber: priorBuildNumber + 1,
Name: namesgenerator.GetRandomName(1),
ProvisionerState: priorHistory.ProvisionerState,
InitiatorID: workspace.OwnerID,
InitiatorID: systemUser.ID,
Transition: trans,
JobID: newProvisionerJob.ID,
})
Expand Down
3 changes: 1 addition & 2 deletions coderd/autobuild/executor/lifecycle_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package executor_test

import (
"context"
"os"
"testing"
"time"

Expand Down Expand Up @@ -483,7 +482,7 @@ func TestExecutorWorkspaceAutostopNoWaitChangedMyMind(t *testing.T) {
}

func TestExecutorAutostartMultipleOK(t *testing.T) {
if os.Getenv("DB") == "" {
if !coderdtest.UseSQL() {
t.Skip(`This test only really works when using a "real" database, similar to a HA setup`)
}

Expand Down
6 changes: 5 additions & 1 deletion coderd/coderdtest/coderdtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func New(t *testing.T, options *Options) *codersdk.Client {
return client
}

func UseSQL() bool {
return os.Getenv("DB") != ""
}

// NewWithAPI constructs a codersdk client connected to the returned in-memory API instance.
func NewWithAPI(t *testing.T, options *Options) (*codersdk.Client, *coderd.API) {
if options == nil {
Expand All @@ -105,7 +109,7 @@ func NewWithAPI(t *testing.T, options *Options) (*codersdk.Client, *coderd.API)
// This can be hotswapped for a live database instance.
db := databasefake.New()
pubsub := database.NewPubsubInMemory()
if os.Getenv("DB") != "" {
if UseSQL() {
connectionURL, closePg, err := postgres.Open()
require.NoError(t, err)
t.Cleanup(closePg)
Expand Down
32 changes: 29 additions & 3 deletions coderd/database/databasefake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@ import (

// New returns an in-memory fake of the database.
func New() database.Store {
systemUser := database.User{
ID: database.SystemUserID,
Email: "system@coder.com",
Username: "system",
HashedPassword: make([]byte, 0),
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
RBACRoles: make([]string, 0),
}
return &fakeQuerier{
apiKeys: make([]database.APIKey, 0),
organizationMembers: make([]database.OrganizationMember, 0),
organizations: make([]database.Organization, 0),
users: make([]database.User, 0),
users: []database.User{systemUser},

auditLogs: make([]database.AuditLog, 0),
files: make([]database.File, 0),
Expand Down Expand Up @@ -179,11 +188,18 @@ func (q *fakeQuerier) GetUserByID(_ context.Context, id uuid.UUID) (database.Use
return database.User{}, sql.ErrNoRows
}

func (q *fakeQuerier) GetUserCount(_ context.Context) (int64, error) {
func (q *fakeQuerier) GetActualUserCount(_ context.Context) (int64, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()

return int64(len(q.users)), nil
var count int64
for _, user := range q.users {
if user.ID != database.SystemUserID {
count++
}
}

return count, nil
}

func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams) ([]database.User, error) {
Expand Down Expand Up @@ -233,6 +249,16 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
users = tmp
}

if !params.IncludeSystemUser {
tmp := make([]database.User, 0, len(users))
for i, user := range users {
if user.ID != database.SystemUserID {
tmp = append(tmp, users[i])
}
}
users = tmp
}

if len(params.Status) == 0 {
params.Status = []database.UserStatus{database.UserStatusActive}
}
Expand Down
3 changes: 3 additions & 0 deletions coderd/database/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ import (
"database/sql"
"errors"

"github.com/google/uuid"
"golang.org/x/xerrors"
)

var SystemUserID uuid.UUID = uuid.MustParse("11111111-1111-1111-1111-111111111111")

// Store contains all queryable database functions.
// It extends the generated interface to add transaction support.
type Store interface {
Expand Down
6 changes: 6 additions & 0 deletions coderd/database/migrations/000024_add_system_user.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

DELETE FROM
users
WHERE
id = '11111111-1111-1111-1111-111111111111';
12 changes: 12 additions & 0 deletions coderd/database/migrations/000024_add_system_user.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
INSERT INTO
users (
id,
email,
username,
hashed_password,
created_at,
updated_at,
rbac_roles
)
VALUES
('11111111-1111-1111-1111-111111111111', 'system@coder.com', 'system', '{}', NOW(), NOW(), '{}');
2 changes: 1 addition & 1 deletion coderd/database/querier.go

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

57 changes: 34 additions & 23 deletions coderd/database/queries.sql.go

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

13 changes: 11 additions & 2 deletions coderd/database/queries/users.sql
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ WHERE
LIMIT
1;

-- name: GetUserCount :one
-- name: GetActualUserCount :one
SELECT
COUNT(*)
FROM
users;
users
WHERE
id != '11111111-1111-1111-1111-111111111111';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this is a valid uuid, it needs some certain bits set. See https://github.com/google/uuid/blob/master/version4.go#L53

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Updated it to c0de2b07-0000-4000-A000-000000000000.


-- name: InsertUser :one
INSERT INTO
Expand Down Expand Up @@ -104,6 +106,13 @@ WHERE
)
ELSE true
END
-- Filter out system user
AND CASE
WHEN @include_system_user :: boolean THEN true
ELSE (
id != '11111111-1111-1111-1111-111111111111'
)
END
-- Filter by status
AND CASE
-- @status needs to be a text because it can be empty, If it was
Expand Down
4 changes: 2 additions & 2 deletions coderd/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

// Returns whether the initial user has been created or not.
func (api *API) firstUser(rw http.ResponseWriter, r *http.Request) {
userCount, err := api.Database.GetUserCount(r.Context())
userCount, err := api.Database.GetActualUserCount(r.Context())
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user count.",
Expand Down Expand Up @@ -56,7 +56,7 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) {
}

// This should only function for the first user.
userCount, err := api.Database.GetUserCount(r.Context())
userCount, err := api.Database.GetActualUserCount(r.Context())
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user count.",
Expand Down
15 changes: 15 additions & 0 deletions coderd/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ import (
"github.com/coder/coder/codersdk"
)

func TestSystemUser(t *testing.T) {
if !coderdtest.UseSQL() {
t.Skip("There is no point in running this test.")
}

t.Parallel()

_, opts := coderdtest.NewWithAPI(t, nil)
fake := databasefake.New()

fakeUser, _ := fake.GetUserByID(context.Background(), database.SystemUserID)
sqlUser, _ := opts.Database.GetUserByID(context.Background(), database.SystemUserID)
require.Equal(t, fakeUser, sqlUser)
}

func TestFirstUser(t *testing.T) {
t.Parallel()
t.Run("BadRequest", func(t *testing.T) {
Expand Down