mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
This PR adds a package lifecycle and an Executor implementation that attempts to schedule a build of workspaces with autostart configured. - lifecycle.Executor takes a chan time.Time in its constructor (e.g. time.Tick(time.Minute)) - Whenever a value is received from this channel, it executes one iteration of looping through the workspaces and triggering lifecycle operations. - When the context passed to the executor is Done, it exits. - Only workspaces that meet the following criteria will have a lifecycle operation applied to them: - Workspace has a valid and non-empty autostart or autostop schedule (either) - Workspace's last build was successful - The following transitions will be applied depending on the current workspace state: - If the workspace is currently running, it will be stopped. - If the workspace is currently stopped, it will be started. - Otherwise, nothing will be done. - Workspace builds will be created with the same parameters and template version as the last successful build (for example, template version)
1759 lines
48 KiB
Go
1759 lines
48 KiB
Go
package databasefake
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/exp/slices"
|
|
|
|
"github.com/coder/coder/coderd/database"
|
|
)
|
|
|
|
// New returns an in-memory fake of the database.
|
|
func New() database.Store {
|
|
return &fakeQuerier{
|
|
apiKeys: make([]database.APIKey, 0),
|
|
organizationMembers: make([]database.OrganizationMember, 0),
|
|
organizations: make([]database.Organization, 0),
|
|
users: make([]database.User, 0),
|
|
|
|
auditLogs: make([]database.AuditLog, 0),
|
|
files: make([]database.File, 0),
|
|
gitSSHKey: make([]database.GitSSHKey, 0),
|
|
parameterSchemas: make([]database.ParameterSchema, 0),
|
|
parameterValues: make([]database.ParameterValue, 0),
|
|
provisionerDaemons: make([]database.ProvisionerDaemon, 0),
|
|
provisionerJobAgents: make([]database.WorkspaceAgent, 0),
|
|
provisionerJobLogs: make([]database.ProvisionerJobLog, 0),
|
|
provisionerJobResources: make([]database.WorkspaceResource, 0),
|
|
provisionerJobs: make([]database.ProvisionerJob, 0),
|
|
templateVersions: make([]database.TemplateVersion, 0),
|
|
templates: make([]database.Template, 0),
|
|
workspaceBuilds: make([]database.WorkspaceBuild, 0),
|
|
workspaces: make([]database.Workspace, 0),
|
|
}
|
|
}
|
|
|
|
// fakeQuerier replicates database functionality to enable quick testing.
|
|
type fakeQuerier struct {
|
|
mutex sync.RWMutex
|
|
|
|
// Legacy tables
|
|
apiKeys []database.APIKey
|
|
organizations []database.Organization
|
|
organizationMembers []database.OrganizationMember
|
|
users []database.User
|
|
|
|
// New tables
|
|
auditLogs []database.AuditLog
|
|
files []database.File
|
|
gitSSHKey []database.GitSSHKey
|
|
parameterSchemas []database.ParameterSchema
|
|
parameterValues []database.ParameterValue
|
|
provisionerDaemons []database.ProvisionerDaemon
|
|
provisionerJobAgents []database.WorkspaceAgent
|
|
provisionerJobLogs []database.ProvisionerJobLog
|
|
provisionerJobResources []database.WorkspaceResource
|
|
provisionerJobs []database.ProvisionerJob
|
|
templateVersions []database.TemplateVersion
|
|
templates []database.Template
|
|
workspaceBuilds []database.WorkspaceBuild
|
|
workspaces []database.Workspace
|
|
}
|
|
|
|
// InTx doesn't rollback data properly for in-memory yet.
|
|
func (q *fakeQuerier) InTx(fn func(database.Store) error) error {
|
|
return fn(q)
|
|
}
|
|
|
|
func (q *fakeQuerier) AcquireProvisionerJob(_ context.Context, arg database.AcquireProvisionerJobParams) (database.ProvisionerJob, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, provisionerJob := range q.provisionerJobs {
|
|
if provisionerJob.StartedAt.Valid {
|
|
continue
|
|
}
|
|
found := false
|
|
for _, provisionerType := range arg.Types {
|
|
if provisionerJob.Provisioner != provisionerType {
|
|
continue
|
|
}
|
|
found = true
|
|
break
|
|
}
|
|
if !found {
|
|
continue
|
|
}
|
|
provisionerJob.StartedAt = arg.StartedAt
|
|
provisionerJob.UpdatedAt = arg.StartedAt.Time
|
|
provisionerJob.WorkerID = arg.WorkerID
|
|
q.provisionerJobs[index] = provisionerJob
|
|
return provisionerJob, nil
|
|
}
|
|
return database.ProvisionerJob{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) DeleteParameterValueByID(_ context.Context, id uuid.UUID) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, parameterValue := range q.parameterValues {
|
|
if parameterValue.ID.String() != id.String() {
|
|
continue
|
|
}
|
|
q.parameterValues[index] = q.parameterValues[len(q.parameterValues)-1]
|
|
q.parameterValues = q.parameterValues[:len(q.parameterValues)-1]
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetAPIKeyByID(_ context.Context, id string) (database.APIKey, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, apiKey := range q.apiKeys {
|
|
if apiKey.ID == id {
|
|
return apiKey, nil
|
|
}
|
|
}
|
|
return database.APIKey{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetFileByHash(_ context.Context, hash string) (database.File, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, file := range q.files {
|
|
if file.Hash == hash {
|
|
return file, nil
|
|
}
|
|
}
|
|
return database.File{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetUserByEmailOrUsername(_ context.Context, arg database.GetUserByEmailOrUsernameParams) (database.User, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, user := range q.users {
|
|
if user.Email == arg.Email || user.Username == arg.Username {
|
|
return user, nil
|
|
}
|
|
}
|
|
return database.User{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetUserByID(_ context.Context, id uuid.UUID) (database.User, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, user := range q.users {
|
|
if user.ID == id {
|
|
return user, nil
|
|
}
|
|
}
|
|
return database.User{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetUserCount(_ context.Context) (int64, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
return int64(len(q.users)), nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams) ([]database.User, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
// Avoid side-effect of sorting.
|
|
users := make([]database.User, len(q.users))
|
|
copy(users, q.users)
|
|
|
|
// Database orders by created_at
|
|
slices.SortFunc(users, func(a, b database.User) bool {
|
|
if a.CreatedAt.Equal(b.CreatedAt) {
|
|
// Technically the postgres database also orders by uuid. So match
|
|
// that behavior
|
|
return a.ID.String() < b.ID.String()
|
|
}
|
|
return a.CreatedAt.Before(b.CreatedAt)
|
|
})
|
|
|
|
if params.AfterID != uuid.Nil {
|
|
found := false
|
|
for i, v := range users {
|
|
if v.ID == params.AfterID {
|
|
// We want to return all users after index i.
|
|
users = users[i+1:]
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// If no users after the time, then we return an empty list.
|
|
if !found {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
}
|
|
|
|
if params.Search != "" {
|
|
tmp := make([]database.User, 0, len(users))
|
|
for i, user := range users {
|
|
if strings.Contains(user.Email, params.Search) {
|
|
tmp = append(tmp, users[i])
|
|
} else if strings.Contains(user.Username, params.Search) {
|
|
tmp = append(tmp, users[i])
|
|
}
|
|
}
|
|
users = tmp
|
|
}
|
|
|
|
if params.Status != "" {
|
|
usersFilteredByStatus := make([]database.User, 0, len(users))
|
|
for i, user := range users {
|
|
if params.Status == string(user.Status) {
|
|
usersFilteredByStatus = append(usersFilteredByStatus, users[i])
|
|
}
|
|
}
|
|
users = usersFilteredByStatus
|
|
}
|
|
|
|
if params.OffsetOpt > 0 {
|
|
if int(params.OffsetOpt) > len(users)-1 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
users = users[params.OffsetOpt:]
|
|
}
|
|
|
|
if params.LimitOpt > 0 {
|
|
if int(params.LimitOpt) > len(users) {
|
|
params.LimitOpt = int32(len(users))
|
|
}
|
|
users = users[:params.LimitOpt]
|
|
}
|
|
|
|
return users, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetAllUserRoles(_ context.Context, userID uuid.UUID) (database.GetAllUserRolesRow, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
var user *database.User
|
|
roles := make([]string, 0)
|
|
for _, u := range q.users {
|
|
if u.ID == userID {
|
|
u := u
|
|
roles = append(roles, u.RBACRoles...)
|
|
user = &u
|
|
break
|
|
}
|
|
}
|
|
|
|
for _, mem := range q.organizationMembers {
|
|
if mem.UserID == userID {
|
|
roles = append(roles, mem.Roles...)
|
|
}
|
|
}
|
|
|
|
if user == nil {
|
|
return database.GetAllUserRolesRow{}, sql.ErrNoRows
|
|
}
|
|
|
|
return database.GetAllUserRolesRow{
|
|
ID: userID,
|
|
Username: user.Username,
|
|
Roles: roles,
|
|
}, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspacesByTemplateID(_ context.Context, arg database.GetWorkspacesByTemplateIDParams) ([]database.Workspace, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
workspaces := make([]database.Workspace, 0)
|
|
for _, workspace := range q.workspaces {
|
|
if workspace.TemplateID.String() != arg.TemplateID.String() {
|
|
continue
|
|
}
|
|
if workspace.Deleted != arg.Deleted {
|
|
continue
|
|
}
|
|
workspaces = append(workspaces, workspace)
|
|
}
|
|
if len(workspaces) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return workspaces, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceByID(_ context.Context, id uuid.UUID) (database.Workspace, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, workspace := range q.workspaces {
|
|
if workspace.ID.String() == id.String() {
|
|
return workspace, nil
|
|
}
|
|
}
|
|
return database.Workspace{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg database.GetWorkspaceByOwnerIDAndNameParams) (database.Workspace, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, workspace := range q.workspaces {
|
|
if workspace.OwnerID != arg.OwnerID {
|
|
continue
|
|
}
|
|
if !strings.EqualFold(workspace.Name, arg.Name) {
|
|
continue
|
|
}
|
|
if workspace.Deleted != arg.Deleted {
|
|
continue
|
|
}
|
|
return workspace, nil
|
|
}
|
|
return database.Workspace{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspacesAutostartAutostop(_ context.Context) ([]database.Workspace, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
workspaces := make([]database.Workspace, 0)
|
|
for _, ws := range q.workspaces {
|
|
if ws.AutostartSchedule.String != "" {
|
|
workspaces = append(workspaces, ws)
|
|
} else if ws.AutostopSchedule.String != "" {
|
|
workspaces = append(workspaces, ws)
|
|
}
|
|
}
|
|
return workspaces, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceOwnerCountsByTemplateIDs(_ context.Context, templateIDs []uuid.UUID) ([]database.GetWorkspaceOwnerCountsByTemplateIDsRow, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
counts := map[uuid.UUID]map[uuid.UUID]struct{}{}
|
|
for _, templateID := range templateIDs {
|
|
found := false
|
|
for _, workspace := range q.workspaces {
|
|
if workspace.TemplateID != templateID {
|
|
continue
|
|
}
|
|
if workspace.Deleted {
|
|
continue
|
|
}
|
|
countByOwnerID, ok := counts[templateID]
|
|
if !ok {
|
|
countByOwnerID = map[uuid.UUID]struct{}{}
|
|
}
|
|
countByOwnerID[workspace.OwnerID] = struct{}{}
|
|
counts[templateID] = countByOwnerID
|
|
found = true
|
|
break
|
|
}
|
|
if !found {
|
|
counts[templateID] = map[uuid.UUID]struct{}{}
|
|
}
|
|
}
|
|
res := make([]database.GetWorkspaceOwnerCountsByTemplateIDsRow, 0)
|
|
for key, value := range counts {
|
|
res = append(res, database.GetWorkspaceOwnerCountsByTemplateIDsRow{
|
|
TemplateID: key,
|
|
Count: int64(len(value)),
|
|
})
|
|
}
|
|
if len(res) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceBuildByID(_ context.Context, id uuid.UUID) (database.WorkspaceBuild, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, history := range q.workspaceBuilds {
|
|
if history.ID.String() == id.String() {
|
|
return history, nil
|
|
}
|
|
}
|
|
return database.WorkspaceBuild{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, build := range q.workspaceBuilds {
|
|
if build.JobID.String() == jobID.String() {
|
|
return build, nil
|
|
}
|
|
}
|
|
return database.WorkspaceBuild{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDWithoutAfter(_ context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, workspaceBuild := range q.workspaceBuilds {
|
|
if workspaceBuild.WorkspaceID.String() != workspaceID.String() {
|
|
continue
|
|
}
|
|
if !workspaceBuild.AfterID.Valid {
|
|
return workspaceBuild, nil
|
|
}
|
|
}
|
|
return database.WorkspaceBuild{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceBuildsByWorkspaceIDsWithoutAfter(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceBuild, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
builds := make([]database.WorkspaceBuild, 0)
|
|
for _, workspaceBuild := range q.workspaceBuilds {
|
|
for _, id := range ids {
|
|
if id.String() != workspaceBuild.WorkspaceID.String() {
|
|
continue
|
|
}
|
|
builds = append(builds, workspaceBuild)
|
|
}
|
|
}
|
|
if len(builds) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return builds, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceID(_ context.Context, workspaceID uuid.UUID) ([]database.WorkspaceBuild, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
history := make([]database.WorkspaceBuild, 0)
|
|
for _, workspaceBuild := range q.workspaceBuilds {
|
|
if workspaceBuild.WorkspaceID.String() == workspaceID.String() {
|
|
history = append(history, workspaceBuild)
|
|
}
|
|
}
|
|
if len(history) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return history, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndNameParams) (database.WorkspaceBuild, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, workspaceBuild := range q.workspaceBuilds {
|
|
if workspaceBuild.WorkspaceID.String() != arg.WorkspaceID.String() {
|
|
continue
|
|
}
|
|
if !strings.EqualFold(workspaceBuild.Name, arg.Name) {
|
|
continue
|
|
}
|
|
return workspaceBuild, nil
|
|
}
|
|
return database.WorkspaceBuild{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspacesByOrganizationID(_ context.Context, req database.GetWorkspacesByOrganizationIDParams) ([]database.Workspace, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
workspaces := make([]database.Workspace, 0)
|
|
for _, workspace := range q.workspaces {
|
|
if workspace.OrganizationID != req.OrganizationID {
|
|
continue
|
|
}
|
|
if workspace.Deleted != req.Deleted {
|
|
continue
|
|
}
|
|
workspaces = append(workspaces, workspace)
|
|
}
|
|
if len(workspaces) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return workspaces, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspacesByOrganizationIDs(_ context.Context, req database.GetWorkspacesByOrganizationIDsParams) ([]database.Workspace, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
workspaces := make([]database.Workspace, 0)
|
|
for _, workspace := range q.workspaces {
|
|
for _, id := range req.Ids {
|
|
if workspace.OrganizationID != id {
|
|
continue
|
|
}
|
|
if workspace.Deleted != req.Deleted {
|
|
continue
|
|
}
|
|
workspaces = append(workspaces, workspace)
|
|
}
|
|
}
|
|
return workspaces, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspacesByOwnerID(_ context.Context, req database.GetWorkspacesByOwnerIDParams) ([]database.Workspace, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
workspaces := make([]database.Workspace, 0)
|
|
for _, workspace := range q.workspaces {
|
|
if workspace.OwnerID != req.OwnerID {
|
|
continue
|
|
}
|
|
if workspace.Deleted != req.Deleted {
|
|
continue
|
|
}
|
|
workspaces = append(workspaces, workspace)
|
|
}
|
|
return workspaces, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetOrganizations(_ context.Context) ([]database.Organization, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
if len(q.organizations) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return q.organizations, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetOrganizationByID(_ context.Context, id uuid.UUID) (database.Organization, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, organization := range q.organizations {
|
|
if organization.ID == id {
|
|
return organization, nil
|
|
}
|
|
}
|
|
return database.Organization{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetOrganizationByName(_ context.Context, name string) (database.Organization, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, organization := range q.organizations {
|
|
if organization.Name == name {
|
|
return organization, nil
|
|
}
|
|
}
|
|
return database.Organization{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetOrganizationsByUserID(_ context.Context, userID uuid.UUID) ([]database.Organization, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
organizations := make([]database.Organization, 0)
|
|
for _, organizationMember := range q.organizationMembers {
|
|
if organizationMember.UserID != userID {
|
|
continue
|
|
}
|
|
for _, organization := range q.organizations {
|
|
if organization.ID != organizationMember.OrganizationID {
|
|
continue
|
|
}
|
|
organizations = append(organizations, organization)
|
|
}
|
|
}
|
|
if len(organizations) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return organizations, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetParameterValuesByScope(_ context.Context, arg database.GetParameterValuesByScopeParams) ([]database.ParameterValue, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
parameterValues := make([]database.ParameterValue, 0)
|
|
for _, parameterValue := range q.parameterValues {
|
|
if parameterValue.Scope != arg.Scope {
|
|
continue
|
|
}
|
|
if parameterValue.ScopeID != arg.ScopeID {
|
|
continue
|
|
}
|
|
parameterValues = append(parameterValues, parameterValue)
|
|
}
|
|
if len(parameterValues) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return parameterValues, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplateByID(_ context.Context, id uuid.UUID) (database.Template, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, template := range q.templates {
|
|
if template.ID.String() == id.String() {
|
|
return template, nil
|
|
}
|
|
}
|
|
return database.Template{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplateByOrganizationAndName(_ context.Context, arg database.GetTemplateByOrganizationAndNameParams) (database.Template, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, template := range q.templates {
|
|
if template.OrganizationID != arg.OrganizationID {
|
|
continue
|
|
}
|
|
if !strings.EqualFold(template.Name, arg.Name) {
|
|
continue
|
|
}
|
|
if template.Deleted != arg.Deleted {
|
|
continue
|
|
}
|
|
return template, nil
|
|
}
|
|
return database.Template{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, arg database.GetTemplateVersionsByTemplateIDParams) (version []database.TemplateVersion, err error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, templateVersion := range q.templateVersions {
|
|
if templateVersion.TemplateID.UUID.String() != arg.TemplateID.String() {
|
|
continue
|
|
}
|
|
version = append(version, templateVersion)
|
|
}
|
|
|
|
// Database orders by created_at
|
|
slices.SortFunc(version, func(a, b database.TemplateVersion) bool {
|
|
if a.CreatedAt.Equal(b.CreatedAt) {
|
|
// Technically the postgres database also orders by uuid. So match
|
|
// that behavior
|
|
return a.ID.String() < b.ID.String()
|
|
}
|
|
return a.CreatedAt.Before(b.CreatedAt)
|
|
})
|
|
|
|
if arg.AfterID != uuid.Nil {
|
|
found := false
|
|
for i, v := range version {
|
|
if v.ID == arg.AfterID {
|
|
// We want to return all users after index i.
|
|
version = version[i+1:]
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// If no users after the time, then we return an empty list.
|
|
if !found {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
}
|
|
|
|
if arg.OffsetOpt > 0 {
|
|
if int(arg.OffsetOpt) > len(version)-1 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
version = version[arg.OffsetOpt:]
|
|
}
|
|
|
|
if arg.LimitOpt > 0 {
|
|
if int(arg.LimitOpt) > len(version) {
|
|
arg.LimitOpt = int32(len(version))
|
|
}
|
|
version = version[:arg.LimitOpt]
|
|
}
|
|
|
|
if len(version) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
|
|
return version, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplateVersionByTemplateIDAndName(_ context.Context, arg database.GetTemplateVersionByTemplateIDAndNameParams) (database.TemplateVersion, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, templateVersion := range q.templateVersions {
|
|
if templateVersion.TemplateID != arg.TemplateID {
|
|
continue
|
|
}
|
|
if !strings.EqualFold(templateVersion.Name, arg.Name) {
|
|
continue
|
|
}
|
|
return templateVersion, nil
|
|
}
|
|
return database.TemplateVersion{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplateVersionByID(_ context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, templateVersion := range q.templateVersions {
|
|
if templateVersion.ID.String() != templateVersionID.String() {
|
|
continue
|
|
}
|
|
return templateVersion, nil
|
|
}
|
|
return database.TemplateVersion{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplateVersionByJobID(_ context.Context, jobID uuid.UUID) (database.TemplateVersion, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, templateVersion := range q.templateVersions {
|
|
if templateVersion.JobID.String() != jobID.String() {
|
|
continue
|
|
}
|
|
return templateVersion, nil
|
|
}
|
|
return database.TemplateVersion{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.UUID) ([]database.ParameterSchema, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
parameters := make([]database.ParameterSchema, 0)
|
|
for _, parameterSchema := range q.parameterSchemas {
|
|
if parameterSchema.JobID.String() != jobID.String() {
|
|
continue
|
|
}
|
|
parameters = append(parameters, parameterSchema)
|
|
}
|
|
if len(parameters) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return parameters, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetParameterValueByScopeAndName(_ context.Context, arg database.GetParameterValueByScopeAndNameParams) (database.ParameterValue, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, parameterValue := range q.parameterValues {
|
|
if parameterValue.Scope != arg.Scope {
|
|
continue
|
|
}
|
|
if parameterValue.ScopeID != arg.ScopeID {
|
|
continue
|
|
}
|
|
if parameterValue.Name != arg.Name {
|
|
continue
|
|
}
|
|
return parameterValue, nil
|
|
}
|
|
return database.ParameterValue{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplatesByOrganization(_ context.Context, arg database.GetTemplatesByOrganizationParams) ([]database.Template, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
templates := make([]database.Template, 0)
|
|
for _, template := range q.templates {
|
|
if template.Deleted != arg.Deleted {
|
|
continue
|
|
}
|
|
if template.OrganizationID != arg.OrganizationID {
|
|
continue
|
|
}
|
|
templates = append(templates, template)
|
|
}
|
|
if len(templates) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return templates, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetTemplatesByIDs(_ context.Context, ids []uuid.UUID) ([]database.Template, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
templates := make([]database.Template, 0)
|
|
for _, template := range q.templates {
|
|
for _, id := range ids {
|
|
if template.ID.String() != id.String() {
|
|
continue
|
|
}
|
|
templates = append(templates, template)
|
|
}
|
|
}
|
|
if len(templates) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return templates, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetOrganizationMemberByUserID(_ context.Context, arg database.GetOrganizationMemberByUserIDParams) (database.OrganizationMember, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, organizationMember := range q.organizationMembers {
|
|
if organizationMember.OrganizationID != arg.OrganizationID {
|
|
continue
|
|
}
|
|
if organizationMember.UserID != arg.UserID {
|
|
continue
|
|
}
|
|
return organizationMember, nil
|
|
}
|
|
return database.OrganizationMember{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetOrganizationIDsByMemberIDs(_ context.Context, ids []uuid.UUID) ([]database.GetOrganizationIDsByMemberIDsRow, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
getOrganizationIDsByMemberIDRows := make([]database.GetOrganizationIDsByMemberIDsRow, 0, len(ids))
|
|
for _, userID := range ids {
|
|
userOrganizationIDs := make([]uuid.UUID, 0)
|
|
for _, membership := range q.organizationMembers {
|
|
if membership.UserID == userID {
|
|
userOrganizationIDs = append(userOrganizationIDs, membership.OrganizationID)
|
|
}
|
|
}
|
|
getOrganizationIDsByMemberIDRows = append(getOrganizationIDsByMemberIDRows, database.GetOrganizationIDsByMemberIDsRow{
|
|
UserID: userID,
|
|
OrganizationIDs: userOrganizationIDs,
|
|
})
|
|
}
|
|
if len(getOrganizationIDsByMemberIDRows) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return getOrganizationIDsByMemberIDRows, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetOrganizationMembershipsByUserID(_ context.Context, userID uuid.UUID) ([]database.OrganizationMember, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
var memberships []database.OrganizationMember
|
|
for _, organizationMember := range q.organizationMembers {
|
|
mem := organizationMember
|
|
if mem.UserID != userID {
|
|
continue
|
|
}
|
|
memberships = append(memberships, mem)
|
|
}
|
|
return memberships, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateMemberRoles(_ context.Context, arg database.UpdateMemberRolesParams) (database.OrganizationMember, error) {
|
|
for i, mem := range q.organizationMembers {
|
|
if mem.UserID == arg.UserID && mem.OrganizationID == arg.OrgID {
|
|
uniqueRoles := make([]string, 0, len(arg.GrantedRoles))
|
|
exist := make(map[string]struct{})
|
|
for _, r := range arg.GrantedRoles {
|
|
if _, ok := exist[r]; ok {
|
|
continue
|
|
}
|
|
exist[r] = struct{}{}
|
|
uniqueRoles = append(uniqueRoles, r)
|
|
}
|
|
sort.Strings(uniqueRoles)
|
|
|
|
mem.Roles = uniqueRoles
|
|
q.organizationMembers[i] = mem
|
|
return mem, nil
|
|
}
|
|
}
|
|
return database.OrganizationMember{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetProvisionerDaemons(_ context.Context) ([]database.ProvisionerDaemon, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
if len(q.provisionerDaemons) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return q.provisionerDaemons, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceAgentByAuthToken(_ context.Context, authToken uuid.UUID) (database.WorkspaceAgent, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
// The schema sorts this by created at, so we iterate the array backwards.
|
|
for i := len(q.provisionerJobAgents) - 1; i >= 0; i-- {
|
|
agent := q.provisionerJobAgents[i]
|
|
if agent.AuthToken.String() == authToken.String() {
|
|
return agent, nil
|
|
}
|
|
}
|
|
return database.WorkspaceAgent{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceAgentByID(_ context.Context, id uuid.UUID) (database.WorkspaceAgent, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
// The schema sorts this by created at, so we iterate the array backwards.
|
|
for i := len(q.provisionerJobAgents) - 1; i >= 0; i-- {
|
|
agent := q.provisionerJobAgents[i]
|
|
if agent.ID.String() == id.String() {
|
|
return agent, nil
|
|
}
|
|
}
|
|
return database.WorkspaceAgent{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceAgentByInstanceID(_ context.Context, instanceID string) (database.WorkspaceAgent, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
// The schema sorts this by created at, so we iterate the array backwards.
|
|
for i := len(q.provisionerJobAgents) - 1; i >= 0; i-- {
|
|
agent := q.provisionerJobAgents[i]
|
|
if agent.AuthInstanceID.Valid && agent.AuthInstanceID.String == instanceID {
|
|
return agent, nil
|
|
}
|
|
}
|
|
return database.WorkspaceAgent{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceAgentsByResourceIDs(_ context.Context, resourceIDs []uuid.UUID) ([]database.WorkspaceAgent, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
workspaceAgents := make([]database.WorkspaceAgent, 0)
|
|
for _, agent := range q.provisionerJobAgents {
|
|
for _, resourceID := range resourceIDs {
|
|
if agent.ResourceID.String() != resourceID.String() {
|
|
continue
|
|
}
|
|
workspaceAgents = append(workspaceAgents, agent)
|
|
}
|
|
}
|
|
if len(workspaceAgents) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return workspaceAgents, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetProvisionerDaemonByID(_ context.Context, id uuid.UUID) (database.ProvisionerDaemon, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, provisionerDaemon := range q.provisionerDaemons {
|
|
if provisionerDaemon.ID.String() != id.String() {
|
|
continue
|
|
}
|
|
return provisionerDaemon, nil
|
|
}
|
|
return database.ProvisionerDaemon{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetProvisionerJobByID(_ context.Context, id uuid.UUID) (database.ProvisionerJob, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, provisionerJob := range q.provisionerJobs {
|
|
if provisionerJob.ID.String() != id.String() {
|
|
continue
|
|
}
|
|
return provisionerJob, nil
|
|
}
|
|
return database.ProvisionerJob{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceResourceByID(_ context.Context, id uuid.UUID) (database.WorkspaceResource, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, resource := range q.provisionerJobResources {
|
|
if resource.ID.String() == id.String() {
|
|
return resource, nil
|
|
}
|
|
}
|
|
return database.WorkspaceResource{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetWorkspaceResourcesByJobID(_ context.Context, jobID uuid.UUID) ([]database.WorkspaceResource, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
resources := make([]database.WorkspaceResource, 0)
|
|
for _, resource := range q.provisionerJobResources {
|
|
if resource.JobID.String() != jobID.String() {
|
|
continue
|
|
}
|
|
resources = append(resources, resource)
|
|
}
|
|
if len(resources) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return resources, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetProvisionerJobsByIDs(_ context.Context, ids []uuid.UUID) ([]database.ProvisionerJob, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
jobs := make([]database.ProvisionerJob, 0)
|
|
for _, job := range q.provisionerJobs {
|
|
for _, id := range ids {
|
|
if id.String() == job.ID.String() {
|
|
jobs = append(jobs, job)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if len(jobs) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
|
|
return jobs, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetProvisionerLogsByIDBetween(_ context.Context, arg database.GetProvisionerLogsByIDBetweenParams) ([]database.ProvisionerJobLog, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
logs := make([]database.ProvisionerJobLog, 0)
|
|
for _, jobLog := range q.provisionerJobLogs {
|
|
if jobLog.JobID.String() != arg.JobID.String() {
|
|
continue
|
|
}
|
|
if jobLog.CreatedAt.After(arg.CreatedBefore) {
|
|
continue
|
|
}
|
|
if jobLog.CreatedAt.Before(arg.CreatedAfter) {
|
|
continue
|
|
}
|
|
logs = append(logs, jobLog)
|
|
}
|
|
if len(logs) == 0 {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return logs, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertAPIKey(_ context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
key := database.APIKey{
|
|
ID: arg.ID,
|
|
HashedSecret: arg.HashedSecret,
|
|
UserID: arg.UserID,
|
|
ExpiresAt: arg.ExpiresAt,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
LastUsed: arg.LastUsed,
|
|
LoginType: arg.LoginType,
|
|
OAuthAccessToken: arg.OAuthAccessToken,
|
|
OAuthRefreshToken: arg.OAuthRefreshToken,
|
|
OAuthIDToken: arg.OAuthIDToken,
|
|
OAuthExpiry: arg.OAuthExpiry,
|
|
}
|
|
q.apiKeys = append(q.apiKeys, key)
|
|
return key, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertFile(_ context.Context, arg database.InsertFileParams) (database.File, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
file := database.File{
|
|
Hash: arg.Hash,
|
|
CreatedAt: arg.CreatedAt,
|
|
CreatedBy: arg.CreatedBy,
|
|
Mimetype: arg.Mimetype,
|
|
Data: arg.Data,
|
|
}
|
|
q.files = append(q.files, file)
|
|
return file, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertOrganization(_ context.Context, arg database.InsertOrganizationParams) (database.Organization, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
organization := database.Organization{
|
|
ID: arg.ID,
|
|
Name: arg.Name,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
}
|
|
q.organizations = append(q.organizations, organization)
|
|
return organization, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertOrganizationMember(_ context.Context, arg database.InsertOrganizationMemberParams) (database.OrganizationMember, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
organizationMember := database.OrganizationMember{
|
|
OrganizationID: arg.OrganizationID,
|
|
UserID: arg.UserID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
Roles: arg.Roles,
|
|
}
|
|
q.organizationMembers = append(q.organizationMembers, organizationMember)
|
|
return organizationMember, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertParameterValue(_ context.Context, arg database.InsertParameterValueParams) (database.ParameterValue, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
parameterValue := database.ParameterValue{
|
|
ID: arg.ID,
|
|
Name: arg.Name,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
Scope: arg.Scope,
|
|
ScopeID: arg.ScopeID,
|
|
SourceScheme: arg.SourceScheme,
|
|
SourceValue: arg.SourceValue,
|
|
DestinationScheme: arg.DestinationScheme,
|
|
}
|
|
q.parameterValues = append(q.parameterValues, parameterValue)
|
|
return parameterValue, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTemplateParams) (database.Template, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
template := database.Template{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
OrganizationID: arg.OrganizationID,
|
|
Name: arg.Name,
|
|
Provisioner: arg.Provisioner,
|
|
ActiveVersionID: arg.ActiveVersionID,
|
|
}
|
|
q.templates = append(q.templates, template)
|
|
return template, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertTemplateVersion(_ context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
version := database.TemplateVersion{
|
|
ID: arg.ID,
|
|
TemplateID: arg.TemplateID,
|
|
OrganizationID: arg.OrganizationID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
Name: arg.Name,
|
|
Description: arg.Description,
|
|
JobID: arg.JobID,
|
|
}
|
|
q.templateVersions = append(q.templateVersions, version)
|
|
return version, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertProvisionerJobLogs(_ context.Context, arg database.InsertProvisionerJobLogsParams) ([]database.ProvisionerJobLog, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
logs := make([]database.ProvisionerJobLog, 0)
|
|
for index, output := range arg.Output {
|
|
logs = append(logs, database.ProvisionerJobLog{
|
|
JobID: arg.JobID,
|
|
ID: arg.ID[index],
|
|
CreatedAt: arg.CreatedAt[index],
|
|
Source: arg.Source[index],
|
|
Level: arg.Level[index],
|
|
Stage: arg.Stage[index],
|
|
Output: output,
|
|
})
|
|
}
|
|
q.provisionerJobLogs = append(q.provisionerJobLogs, logs...)
|
|
return logs, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertParameterSchema(_ context.Context, arg database.InsertParameterSchemaParams) (database.ParameterSchema, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
param := database.ParameterSchema{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
JobID: arg.JobID,
|
|
Name: arg.Name,
|
|
Description: arg.Description,
|
|
DefaultSourceScheme: arg.DefaultSourceScheme,
|
|
DefaultSourceValue: arg.DefaultSourceValue,
|
|
AllowOverrideSource: arg.AllowOverrideSource,
|
|
DefaultDestinationScheme: arg.DefaultDestinationScheme,
|
|
AllowOverrideDestination: arg.AllowOverrideDestination,
|
|
DefaultRefresh: arg.DefaultRefresh,
|
|
RedisplayValue: arg.RedisplayValue,
|
|
ValidationError: arg.ValidationError,
|
|
ValidationCondition: arg.ValidationCondition,
|
|
ValidationTypeSystem: arg.ValidationTypeSystem,
|
|
ValidationValueType: arg.ValidationValueType,
|
|
}
|
|
q.parameterSchemas = append(q.parameterSchemas, param)
|
|
return param, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertProvisionerDaemon(_ context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
daemon := database.ProvisionerDaemon{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
OrganizationID: arg.OrganizationID,
|
|
Name: arg.Name,
|
|
Provisioners: arg.Provisioners,
|
|
}
|
|
q.provisionerDaemons = append(q.provisionerDaemons, daemon)
|
|
return daemon, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertProvisionerJob(_ context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
job := database.ProvisionerJob{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
OrganizationID: arg.OrganizationID,
|
|
InitiatorID: arg.InitiatorID,
|
|
Provisioner: arg.Provisioner,
|
|
StorageMethod: arg.StorageMethod,
|
|
StorageSource: arg.StorageSource,
|
|
Type: arg.Type,
|
|
Input: arg.Input,
|
|
}
|
|
q.provisionerJobs = append(q.provisionerJobs, job)
|
|
return job, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertWorkspaceAgent(_ context.Context, arg database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
agent := database.WorkspaceAgent{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
ResourceID: arg.ResourceID,
|
|
AuthToken: arg.AuthToken,
|
|
AuthInstanceID: arg.AuthInstanceID,
|
|
EnvironmentVariables: arg.EnvironmentVariables,
|
|
Name: arg.Name,
|
|
Architecture: arg.Architecture,
|
|
OperatingSystem: arg.OperatingSystem,
|
|
Directory: arg.Directory,
|
|
StartupScript: arg.StartupScript,
|
|
InstanceMetadata: arg.InstanceMetadata,
|
|
ResourceMetadata: arg.ResourceMetadata,
|
|
}
|
|
q.provisionerJobAgents = append(q.provisionerJobAgents, agent)
|
|
return agent, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertWorkspaceResource(_ context.Context, arg database.InsertWorkspaceResourceParams) (database.WorkspaceResource, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
resource := database.WorkspaceResource{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
JobID: arg.JobID,
|
|
Transition: arg.Transition,
|
|
Type: arg.Type,
|
|
Name: arg.Name,
|
|
}
|
|
q.provisionerJobResources = append(q.provisionerJobResources, resource)
|
|
return resource, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParams) (database.User, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
user := database.User{
|
|
ID: arg.ID,
|
|
Email: arg.Email,
|
|
HashedPassword: arg.HashedPassword,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
Username: arg.Username,
|
|
Status: database.UserStatusActive,
|
|
RBACRoles: arg.RBACRoles,
|
|
}
|
|
q.users = append(q.users, user)
|
|
return user, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateUserRoles(_ context.Context, arg database.UpdateUserRolesParams) (database.User, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, user := range q.users {
|
|
if user.ID != arg.ID {
|
|
continue
|
|
}
|
|
|
|
// Set new roles
|
|
user.RBACRoles = arg.GrantedRoles
|
|
// Remove duplicates and sort
|
|
uniqueRoles := make([]string, 0, len(user.RBACRoles))
|
|
exist := make(map[string]struct{})
|
|
for _, r := range user.RBACRoles {
|
|
if _, ok := exist[r]; ok {
|
|
continue
|
|
}
|
|
exist[r] = struct{}{}
|
|
uniqueRoles = append(uniqueRoles, r)
|
|
}
|
|
sort.Strings(uniqueRoles)
|
|
user.RBACRoles = uniqueRoles
|
|
|
|
q.users[index] = user
|
|
return user, nil
|
|
}
|
|
return database.User{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateUserProfile(_ context.Context, arg database.UpdateUserProfileParams) (database.User, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, user := range q.users {
|
|
if user.ID != arg.ID {
|
|
continue
|
|
}
|
|
user.Email = arg.Email
|
|
user.Username = arg.Username
|
|
q.users[index] = user
|
|
return user, nil
|
|
}
|
|
return database.User{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateUserStatus(_ context.Context, arg database.UpdateUserStatusParams) (database.User, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, user := range q.users {
|
|
if user.ID != arg.ID {
|
|
continue
|
|
}
|
|
user.Status = arg.Status
|
|
user.UpdatedAt = arg.UpdatedAt
|
|
q.users[index] = user
|
|
return user, nil
|
|
}
|
|
return database.User{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateUserHashedPassword(_ context.Context, arg database.UpdateUserHashedPasswordParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for i, user := range q.users {
|
|
if user.ID != arg.ID {
|
|
continue
|
|
}
|
|
user.HashedPassword = arg.HashedPassword
|
|
q.users[i] = user
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertWorkspace(_ context.Context, arg database.InsertWorkspaceParams) (database.Workspace, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
workspace := database.Workspace{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
OwnerID: arg.OwnerID,
|
|
OrganizationID: arg.OrganizationID,
|
|
TemplateID: arg.TemplateID,
|
|
Name: arg.Name,
|
|
}
|
|
q.workspaces = append(q.workspaces, workspace)
|
|
return workspace, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
workspaceBuild := database.WorkspaceBuild{
|
|
ID: arg.ID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
WorkspaceID: arg.WorkspaceID,
|
|
Name: arg.Name,
|
|
TemplateVersionID: arg.TemplateVersionID,
|
|
BeforeID: arg.BeforeID,
|
|
Transition: arg.Transition,
|
|
InitiatorID: arg.InitiatorID,
|
|
JobID: arg.JobID,
|
|
ProvisionerState: arg.ProvisionerState,
|
|
}
|
|
q.workspaceBuilds = append(q.workspaceBuilds, workspaceBuild)
|
|
return workspaceBuild, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPIKeyByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, apiKey := range q.apiKeys {
|
|
if apiKey.ID != arg.ID {
|
|
continue
|
|
}
|
|
apiKey.LastUsed = arg.LastUsed
|
|
apiKey.ExpiresAt = arg.ExpiresAt
|
|
apiKey.OAuthAccessToken = arg.OAuthAccessToken
|
|
apiKey.OAuthRefreshToken = arg.OAuthRefreshToken
|
|
apiKey.OAuthExpiry = arg.OAuthExpiry
|
|
q.apiKeys[index] = apiKey
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateTemplateActiveVersionByID(_ context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, template := range q.templates {
|
|
if template.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
template.ActiveVersionID = arg.ActiveVersionID
|
|
q.templates[index] = template
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateTemplateDeletedByID(_ context.Context, arg database.UpdateTemplateDeletedByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, template := range q.templates {
|
|
if template.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
template.Deleted = arg.Deleted
|
|
q.templates[index] = template
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, templateVersion := range q.templateVersions {
|
|
if templateVersion.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
templateVersion.TemplateID = arg.TemplateID
|
|
templateVersion.UpdatedAt = arg.UpdatedAt
|
|
q.templateVersions[index] = templateVersion
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateProvisionerDaemonByID(_ context.Context, arg database.UpdateProvisionerDaemonByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, daemon := range q.provisionerDaemons {
|
|
if arg.ID.String() != daemon.ID.String() {
|
|
continue
|
|
}
|
|
daemon.UpdatedAt = arg.UpdatedAt
|
|
daemon.Provisioners = arg.Provisioners
|
|
q.provisionerDaemons[index] = daemon
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateWorkspaceAgentConnectionByID(_ context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, agent := range q.provisionerJobAgents {
|
|
if agent.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
agent.FirstConnectedAt = arg.FirstConnectedAt
|
|
agent.LastConnectedAt = arg.LastConnectedAt
|
|
agent.DisconnectedAt = arg.DisconnectedAt
|
|
q.provisionerJobAgents[index] = agent
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateProvisionerJobByID(_ context.Context, arg database.UpdateProvisionerJobByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, job := range q.provisionerJobs {
|
|
if arg.ID.String() != job.ID.String() {
|
|
continue
|
|
}
|
|
job.UpdatedAt = arg.UpdatedAt
|
|
q.provisionerJobs[index] = job
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateProvisionerJobWithCancelByID(_ context.Context, arg database.UpdateProvisionerJobWithCancelByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, job := range q.provisionerJobs {
|
|
if arg.ID.String() != job.ID.String() {
|
|
continue
|
|
}
|
|
job.CanceledAt = arg.CanceledAt
|
|
q.provisionerJobs[index] = job
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateProvisionerJobWithCompleteByID(_ context.Context, arg database.UpdateProvisionerJobWithCompleteByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, job := range q.provisionerJobs {
|
|
if arg.ID.String() != job.ID.String() {
|
|
continue
|
|
}
|
|
job.UpdatedAt = arg.UpdatedAt
|
|
job.CompletedAt = arg.CompletedAt
|
|
job.Error = arg.Error
|
|
q.provisionerJobs[index] = job
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.UpdateWorkspaceAutostartParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, workspace := range q.workspaces {
|
|
if workspace.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
workspace.AutostartSchedule = arg.AutostartSchedule
|
|
q.workspaces[index] = workspace
|
|
return nil
|
|
}
|
|
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateWorkspaceAutostop(_ context.Context, arg database.UpdateWorkspaceAutostopParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, workspace := range q.workspaces {
|
|
if workspace.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
workspace.AutostopSchedule = arg.AutostopSchedule
|
|
q.workspaces[index] = workspace
|
|
return nil
|
|
}
|
|
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateWorkspaceBuildByID(_ context.Context, arg database.UpdateWorkspaceBuildByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, workspaceBuild := range q.workspaceBuilds {
|
|
if workspaceBuild.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
workspaceBuild.UpdatedAt = arg.UpdatedAt
|
|
workspaceBuild.AfterID = arg.AfterID
|
|
workspaceBuild.ProvisionerState = arg.ProvisionerState
|
|
q.workspaceBuilds[index] = workspaceBuild
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateWorkspaceDeletedByID(_ context.Context, arg database.UpdateWorkspaceDeletedByIDParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, workspace := range q.workspaces {
|
|
if workspace.ID.String() != arg.ID.String() {
|
|
continue
|
|
}
|
|
workspace.Deleted = arg.Deleted
|
|
q.workspaces[index] = workspace
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertGitSSHKey(_ context.Context, arg database.InsertGitSSHKeyParams) (database.GitSSHKey, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
//nolint:gosimple
|
|
gitSSHKey := database.GitSSHKey{
|
|
UserID: arg.UserID,
|
|
CreatedAt: arg.CreatedAt,
|
|
UpdatedAt: arg.UpdatedAt,
|
|
PrivateKey: arg.PrivateKey,
|
|
PublicKey: arg.PublicKey,
|
|
}
|
|
q.gitSSHKey = append(q.gitSSHKey, gitSSHKey)
|
|
return gitSSHKey, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) GetGitSSHKey(_ context.Context, userID uuid.UUID) (database.GitSSHKey, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
for _, key := range q.gitSSHKey {
|
|
if key.UserID == userID {
|
|
return key, nil
|
|
}
|
|
}
|
|
return database.GitSSHKey{}, sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) UpdateGitSSHKey(_ context.Context, arg database.UpdateGitSSHKeyParams) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, key := range q.gitSSHKey {
|
|
if key.UserID.String() != arg.UserID.String() {
|
|
continue
|
|
}
|
|
key.UpdatedAt = arg.UpdatedAt
|
|
key.PrivateKey = arg.PrivateKey
|
|
key.PublicKey = arg.PublicKey
|
|
q.gitSSHKey[index] = key
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) DeleteGitSSHKey(_ context.Context, userID uuid.UUID) error {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
for index, key := range q.gitSSHKey {
|
|
if key.UserID.String() != userID.String() {
|
|
continue
|
|
}
|
|
q.gitSSHKey[index] = q.gitSSHKey[len(q.gitSSHKey)-1]
|
|
q.gitSSHKey = q.gitSSHKey[:len(q.gitSSHKey)-1]
|
|
return nil
|
|
}
|
|
return sql.ErrNoRows
|
|
}
|
|
|
|
func (q *fakeQuerier) GetAuditLogsBefore(_ context.Context, arg database.GetAuditLogsBeforeParams) ([]database.AuditLog, error) {
|
|
q.mutex.RLock()
|
|
defer q.mutex.RUnlock()
|
|
|
|
logs := make([]database.AuditLog, 0)
|
|
start := database.AuditLog{}
|
|
|
|
if arg.ID != uuid.Nil {
|
|
for _, alog := range q.auditLogs {
|
|
if alog.ID == arg.ID {
|
|
start = alog
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
start.ID = uuid.New()
|
|
start.Time = arg.StartTime
|
|
}
|
|
|
|
if start.ID == uuid.Nil {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
|
|
// q.auditLogs are already sorted by time DESC, so no need to sort after the fact.
|
|
for _, alog := range q.auditLogs {
|
|
if alog.Time.Before(start.Time) {
|
|
logs = append(logs, alog)
|
|
}
|
|
|
|
if len(logs) >= int(arg.RowLimit) {
|
|
break
|
|
}
|
|
}
|
|
|
|
return logs, nil
|
|
}
|
|
|
|
func (q *fakeQuerier) InsertAuditLog(_ context.Context, arg database.InsertAuditLogParams) (database.AuditLog, error) {
|
|
q.mutex.Lock()
|
|
defer q.mutex.Unlock()
|
|
|
|
alog := database.AuditLog(arg)
|
|
|
|
q.auditLogs = append(q.auditLogs, alog)
|
|
slices.SortFunc(q.auditLogs, func(a, b database.AuditLog) bool {
|
|
return a.Time.Before(b.Time)
|
|
})
|
|
|
|
return alog, nil
|
|
}
|