From 4c481aef6f7af95b0156d715a813ab1aa8b23989 Mon Sep 17 00:00:00 2001 From: kylecarbs Date: Thu, 26 May 2022 02:29:06 +0000 Subject: [PATCH] chore: Remove interface from coderd and lift API surface Abstracting coderd into an interface added misdirection because the interface was never intended to be fulfilled outside of a single implementation. This lifts the abstraction, and attaches all handlers to a root struct named `*coderd.API`. --- cli/server.go | 16 +- coderd/authorize.go | 4 +- coderd/coderd.go | 224 ++++++++++++--------------- coderd/coderd_test.go | 5 +- coderd/coderdtest/coderdtest.go | 26 ++-- coderd/coderdtest/coderdtest_test.go | 4 +- coderd/files.go | 4 +- coderd/gitsshkey.go | 6 +- coderd/gitsshkey_test.go | 4 +- coderd/members.go | 4 +- coderd/organizations.go | 2 +- coderd/parameters.go | 6 +- coderd/provisionerdaemons.go | 18 +-- coderd/provisionerjobs.go | 4 +- coderd/roles.go | 6 +- coderd/templates.go | 10 +- coderd/templateversions.go | 20 +-- coderd/userauth.go | 4 +- coderd/users.go | 40 ++--- coderd/workspaceagents.go | 16 +- coderd/workspaceagents_test.go | 16 +- coderd/workspacebuilds.go | 16 +- coderd/workspacebuilds_test.go | 4 +- coderd/workspaceresourceauth.go | 8 +- coderd/workspaceresources.go | 2 +- coderd/workspaces.go | 18 +-- coderd/workspaces_test.go | 8 +- 27 files changed, 233 insertions(+), 262 deletions(-) diff --git a/cli/server.go b/cli/server.go index c778e0a220235..ac6f49d5079a7 100644 --- a/cli/server.go +++ b/cli/server.go @@ -273,7 +273,7 @@ func server() *cobra.Command { } } - coderDaemon := coderd.New(options) + coderAPI := coderd.New(options) client := codersdk.New(localURL) if tlsEnable { // Secure transport isn't needed for locally communicating! @@ -299,7 +299,7 @@ func server() *cobra.Command { errCh := make(chan error, 1) provisionerDaemons := make([]*provisionerd.Server, 0) for i := 0; uint8(i) < provisionerDaemonCount; i++ { - daemonClose, err := newProvisionerDaemon(cmd.Context(), coderDaemon, logger, cacheDir, errCh, dev) + daemonClose, err := newProvisionerDaemon(cmd.Context(), coderAPI, logger, cacheDir, errCh, dev) if err != nil { return xerrors.Errorf("create provisioner daemon: %w", err) } @@ -319,7 +319,7 @@ func server() *cobra.Command { // These errors are typically noise like "TLS: EOF". Vault does similar: // https://github.com/hashicorp/vault/blob/e2490059d0711635e529a4efcbaa1b26998d6e1c/command/server.go#L2714 ErrorLog: log.New(io.Discard, "", 0), - Handler: coderDaemon.Handler(), + Handler: coderAPI.Handler, BaseContext: func(_ net.Listener) context.Context { return shutdownConnsCtx }, @@ -387,7 +387,7 @@ func server() *cobra.Command { signal.Notify(stopChan, os.Interrupt) select { case <-cmd.Context().Done(): - coderDaemon.CloseWait() + coderAPI.Close() return cmd.Context().Err() case err := <-tunnelErrChan: if err != nil { @@ -395,7 +395,7 @@ func server() *cobra.Command { } case err := <-errCh: shutdownConns() - coderDaemon.CloseWait() + coderAPI.Close() return err case <-stopChan: } @@ -459,7 +459,7 @@ func server() *cobra.Command { _, _ = fmt.Fprintf(cmd.OutOrStdout(), cliui.Styles.Prompt.String()+"Waiting for WebSocket connections to close...\n") shutdownConns() - coderDaemon.CloseWait() + coderAPI.Close() return nil }, } @@ -555,7 +555,7 @@ func createFirstUser(cmd *cobra.Command, client *codersdk.Client, cfg config.Roo } // nolint:revive -func newProvisionerDaemon(ctx context.Context, coderDaemon coderd.CoderD, +func newProvisionerDaemon(ctx context.Context, coderAPI *coderd.API, logger slog.Logger, cacheDir string, errChan chan error, dev bool) (*provisionerd.Server, error) { err := os.MkdirAll(cacheDir, 0700) if err != nil { @@ -595,7 +595,7 @@ func newProvisionerDaemon(ctx context.Context, coderDaemon coderd.CoderD, }() provisioners[string(database.ProvisionerTypeEcho)] = proto.NewDRPCProvisionerClient(provisionersdk.Conn(echoClient)) } - return provisionerd.New(coderDaemon.ListenProvisionerDaemon, &provisionerd.Options{ + return provisionerd.New(coderAPI.ListenProvisionerDaemon, &provisionerd.Options{ Logger: logger, PollInterval: 500 * time.Millisecond, UpdateInterval: 500 * time.Millisecond, diff --git a/coderd/authorize.go b/coderd/authorize.go index 13374344fae1f..b98ad5e20f83c 100644 --- a/coderd/authorize.go +++ b/coderd/authorize.go @@ -12,12 +12,12 @@ import ( "github.com/coder/coder/coderd/rbac" ) -func AuthorizeFilter[O rbac.Objecter](api *api, r *http.Request, action rbac.Action, objects []O) []O { +func AuthorizeFilter[O rbac.Objecter](api *API, r *http.Request, action rbac.Action, objects []O) []O { roles := httpmw.UserRoles(r) return rbac.Filter(r.Context(), api.Authorizer, roles.ID.String(), roles.Roles, action, objects) } -func (api *api) Authorize(rw http.ResponseWriter, r *http.Request, action rbac.Action, object rbac.Objecter) bool { +func (api *API) Authorize(rw http.ResponseWriter, r *http.Request, action rbac.Action, object rbac.Objecter) bool { roles := httpmw.UserRoles(r) err := api.Authorizer.ByRoleName(r.Context(), roles.ID.String(), roles.Roles, action, object.RBACObject()) if err != nil { diff --git a/coderd/coderd.go b/coderd/coderd.go index c474aeb785215..3a4de3436e1ad 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -28,7 +28,6 @@ import ( "github.com/coder/coder/coderd/tracing" "github.com/coder/coder/coderd/turnconn" "github.com/coder/coder/codersdk" - "github.com/coder/coder/provisionerd/proto" "github.com/coder/coder/site" ) @@ -56,22 +55,8 @@ type Options struct { TracerProvider *sdktrace.TracerProvider } -type CoderD interface { - Handler() http.Handler - CloseWait() - - // An in-process provisionerd connection. - ListenProvisionerDaemon(ctx context.Context) (proto.DRPCProvisionerDaemonClient, error) -} - -type coderD struct { - api *api - router chi.Router - options *Options -} - -// newRouter constructs the Chi Router for the given API. -func newRouter(options *Options, a *api) chi.Router { +// New constructs a Coder API handler. +func New(options *Options) *API { if options.AgentConnectionUpdateFrequency == 0 { options.AgentConnectionUpdateFrequency = 3 * time.Second } @@ -87,15 +72,19 @@ func newRouter(options *Options, a *api) chi.Router { panic(xerrors.Errorf("rego authorize panic: %w", err)) } } + + r := chi.NewRouter() + api := &API{ + Options: options, + Handler: r, + } + apiKeyMiddleware := httpmw.ExtractAPIKey(options.Database, &httpmw.OAuth2Configs{ Github: options.GithubOAuth2Config, }) - // TODO: @emyrk we should just move this into 'ExtractAPIKey'. authRolesMiddleware := httpmw.ExtractUserRoles(options.Database) - r := chi.NewRouter() - r.Use( func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -103,7 +92,7 @@ func newRouter(options *Options, a *api) chi.Router { }) }, httpmw.Prometheus, - tracing.HTTPMW(a.TracerProvider, "coderd.http"), + tracing.HTTPMW(api.TracerProvider, "coderd.http"), ) r.Route("/api/v2", func(r chi.Router) { @@ -116,7 +105,7 @@ func newRouter(options *Options, a *api) chi.Router { r.Use( // Specific routes can specify smaller limits. httpmw.RateLimitPerMinute(options.APIRateLimit), - debugLogRequest(a.Logger), + debugLogRequest(api.Logger), ) r.Get("/", func(w http.ResponseWriter, r *http.Request) { httpapi.Write(w, http.StatusOK, httpapi.Response{ @@ -139,8 +128,8 @@ func newRouter(options *Options, a *api) chi.Router { // file content is expensive so it should be small. httpmw.RateLimitPerMinute(12), ) - r.Get("/{hash}", a.fileByHash) - r.Post("/", a.postFile) + r.Get("/{hash}", api.fileByHash) + r.Post("/", api.postFile) }) r.Route("/organizations/{organization}", func(r chi.Router) { r.Use( @@ -148,40 +137,40 @@ func newRouter(options *Options, a *api) chi.Router { httpmw.ExtractOrganizationParam(options.Database), authRolesMiddleware, ) - r.Get("/", a.organization) - r.Get("/provisionerdaemons", a.provisionerDaemonsByOrganization) - r.Post("/templateversions", a.postTemplateVersionsByOrganization) + r.Get("/", api.organization) + r.Get("/provisionerdaemons", api.provisionerDaemonsByOrganization) + r.Post("/templateversions", api.postTemplateVersionsByOrganization) r.Route("/templates", func(r chi.Router) { - r.Post("/", a.postTemplateByOrganization) - r.Get("/", a.templatesByOrganization) - r.Get("/{templatename}", a.templateByOrganizationAndName) + r.Post("/", api.postTemplateByOrganization) + r.Get("/", api.templatesByOrganization) + r.Get("/{templatename}", api.templateByOrganizationAndName) }) r.Route("/workspaces", func(r chi.Router) { - r.Post("/", a.postWorkspacesByOrganization) - r.Get("/", a.workspacesByOrganization) + r.Post("/", api.postWorkspacesByOrganization) + r.Get("/", api.workspacesByOrganization) r.Route("/{user}", func(r chi.Router) { r.Use(httpmw.ExtractUserParam(options.Database)) - r.Get("/{workspacename}", a.workspaceByOwnerAndName) - r.Get("/", a.workspacesByOwner) + r.Get("/{workspacename}", api.workspaceByOwnerAndName) + r.Get("/", api.workspacesByOwner) }) }) r.Route("/members", func(r chi.Router) { - r.Get("/roles", a.assignableOrgRoles) + r.Get("/roles", api.assignableOrgRoles) r.Route("/{user}", func(r chi.Router) { r.Use( httpmw.ExtractUserParam(options.Database), httpmw.ExtractOrganizationMemberParam(options.Database), ) - r.Put("/roles", a.putMemberRoles) + r.Put("/roles", api.putMemberRoles) }) }) }) r.Route("/parameters/{scope}/{id}", func(r chi.Router) { r.Use(apiKeyMiddleware) - r.Post("/", a.postParameter) - r.Get("/", a.parameters) + r.Post("/", api.postParameter) + r.Get("/", api.parameters) r.Route("/{name}", func(r chi.Router) { - r.Delete("/", a.deleteParameter) + r.Delete("/", api.deleteParameter) }) }) r.Route("/templates/{template}", func(r chi.Router) { @@ -191,12 +180,12 @@ func newRouter(options *Options, a *api) chi.Router { httpmw.ExtractTemplateParam(options.Database), ) - r.Get("/", a.template) - r.Delete("/", a.deleteTemplate) + r.Get("/", api.template) + r.Delete("/", api.deleteTemplate) r.Route("/versions", func(r chi.Router) { - r.Get("/", a.templateVersionsByTemplate) - r.Patch("/", a.patchActiveTemplateVersion) - r.Get("/{templateversionname}", a.templateVersionByName) + r.Get("/", api.templateVersionsByTemplate) + r.Patch("/", api.patchActiveTemplateVersion) + r.Get("/{templateversionname}", api.templateVersionByName) }) }) r.Route("/templateversions/{templateversion}", func(r chi.Router) { @@ -206,23 +195,23 @@ func newRouter(options *Options, a *api) chi.Router { httpmw.ExtractTemplateVersionParam(options.Database), ) - r.Get("/", a.templateVersion) - r.Patch("/cancel", a.patchCancelTemplateVersion) - r.Get("/schema", a.templateVersionSchema) - r.Get("/parameters", a.templateVersionParameters) - r.Get("/resources", a.templateVersionResources) - r.Get("/logs", a.templateVersionLogs) + r.Get("/", api.templateVersion) + r.Patch("/cancel", api.patchCancelTemplateVersion) + r.Get("/schema", api.templateVersionSchema) + r.Get("/parameters", api.templateVersionParameters) + r.Get("/resources", api.templateVersionResources) + r.Get("/logs", api.templateVersionLogs) }) r.Route("/users", func(r chi.Router) { - r.Get("/first", a.firstUser) - r.Post("/first", a.postFirstUser) - r.Post("/login", a.postLogin) - r.Post("/logout", a.postLogout) - r.Get("/authmethods", a.userAuthMethods) + r.Get("/first", api.firstUser) + r.Post("/first", api.postFirstUser) + r.Post("/login", api.postLogin) + r.Post("/logout", api.postLogout) + r.Get("/authmethods", api.userAuthMethods) r.Route("/oauth2", func(r chi.Router) { r.Route("/github", func(r chi.Router) { r.Use(httpmw.ExtractOAuth2(options.GithubOAuth2Config)) - r.Get("/callback", a.userOAuth2Github) + r.Get("/callback", api.userOAuth2Github) }) }) r.Group(func(r chi.Router) { @@ -230,62 +219,62 @@ func newRouter(options *Options, a *api) chi.Router { apiKeyMiddleware, authRolesMiddleware, ) - r.Post("/", a.postUser) - r.Get("/", a.users) + r.Post("/", api.postUser) + r.Get("/", api.users) // These routes query information about site wide roles. r.Route("/roles", func(r chi.Router) { - r.Get("/", a.assignableSiteRoles) + r.Get("/", api.assignableSiteRoles) }) r.Route("/{user}", func(r chi.Router) { r.Use(httpmw.ExtractUserParam(options.Database)) - r.Get("/", a.userByName) - r.Put("/profile", a.putUserProfile) + r.Get("/", api.userByName) + r.Put("/profile", api.putUserProfile) r.Route("/status", func(r chi.Router) { - r.Put("/suspend", a.putUserStatus(database.UserStatusSuspended)) - r.Put("/active", a.putUserStatus(database.UserStatusActive)) + r.Put("/suspend", api.putUserStatus(database.UserStatusSuspended)) + r.Put("/active", api.putUserStatus(database.UserStatusActive)) }) r.Route("/password", func(r chi.Router) { - r.Put("/", a.putUserPassword) + r.Put("/", api.putUserPassword) }) // These roles apply to the site wide permissions. - r.Put("/roles", a.putUserRoles) - r.Get("/roles", a.userRoles) + r.Put("/roles", api.putUserRoles) + r.Get("/roles", api.userRoles) - r.Post("/authorization", a.checkPermissions) + r.Post("/authorization", api.checkPermissions) - r.Post("/keys", a.postAPIKey) + r.Post("/keys", api.postAPIKey) r.Route("/organizations", func(r chi.Router) { - r.Post("/", a.postOrganizationsByUser) - r.Get("/", a.organizationsByUser) - r.Get("/{organizationname}", a.organizationByUserAndName) + r.Post("/", api.postOrganizationsByUser) + r.Get("/", api.organizationsByUser) + r.Get("/{organizationname}", api.organizationByUserAndName) }) - r.Get("/gitsshkey", a.gitSSHKey) - r.Put("/gitsshkey", a.regenerateGitSSHKey) + r.Get("/gitsshkey", api.gitSSHKey) + r.Put("/gitsshkey", api.regenerateGitSSHKey) }) }) }) r.Route("/workspaceagents", func(r chi.Router) { - r.Post("/azure-instance-identity", a.postWorkspaceAuthAzureInstanceIdentity) - r.Post("/aws-instance-identity", a.postWorkspaceAuthAWSInstanceIdentity) - r.Post("/google-instance-identity", a.postWorkspaceAuthGoogleInstanceIdentity) + r.Post("/azure-instance-identity", api.postWorkspaceAuthAzureInstanceIdentity) + r.Post("/aws-instance-identity", api.postWorkspaceAuthAWSInstanceIdentity) + r.Post("/google-instance-identity", api.postWorkspaceAuthGoogleInstanceIdentity) r.Route("/me", func(r chi.Router) { r.Use(httpmw.ExtractWorkspaceAgent(options.Database)) - r.Get("/metadata", a.workspaceAgentMetadata) - r.Get("/listen", a.workspaceAgentListen) - r.Get("/gitsshkey", a.agentGitSSHKey) - r.Get("/turn", a.workspaceAgentTurn) - r.Get("/iceservers", a.workspaceAgentICEServers) + r.Get("/metadata", api.workspaceAgentMetadata) + r.Get("/listen", api.workspaceAgentListen) + r.Get("/gitsshkey", api.agentGitSSHKey) + r.Get("/turn", api.workspaceAgentTurn) + r.Get("/iceservers", api.workspaceAgentICEServers) }) r.Route("/{workspaceagent}", func(r chi.Router) { r.Use( apiKeyMiddleware, httpmw.ExtractWorkspaceAgentParam(options.Database), ) - r.Get("/", a.workspaceAgent) - r.Get("/dial", a.workspaceAgentDial) - r.Get("/turn", a.workspaceAgentTurn) - r.Get("/pty", a.workspaceAgentPTY) - r.Get("/iceservers", a.workspaceAgentICEServers) + r.Get("/", api.workspaceAgent) + r.Get("/dial", api.workspaceAgentDial) + r.Get("/turn", api.workspaceAgentTurn) + r.Get("/pty", api.workspaceAgentPTY) + r.Get("/iceservers", api.workspaceAgentICEServers) }) }) r.Route("/workspaceresources/{workspaceresource}", func(r chi.Router) { @@ -295,31 +284,31 @@ func newRouter(options *Options, a *api) chi.Router { httpmw.ExtractWorkspaceResourceParam(options.Database), httpmw.ExtractWorkspaceParam(options.Database), ) - r.Get("/", a.workspaceResource) + r.Get("/", api.workspaceResource) }) r.Route("/workspaces", func(r chi.Router) { r.Use( apiKeyMiddleware, authRolesMiddleware, ) - r.Get("/", a.workspaces) + r.Get("/", api.workspaces) r.Route("/{workspace}", func(r chi.Router) { r.Use( httpmw.ExtractWorkspaceParam(options.Database), ) - r.Get("/", a.workspace) + r.Get("/", api.workspace) r.Route("/builds", func(r chi.Router) { - r.Get("/", a.workspaceBuilds) - r.Post("/", a.postWorkspaceBuilds) - r.Get("/{workspacebuildname}", a.workspaceBuildByName) + r.Get("/", api.workspaceBuilds) + r.Post("/", api.postWorkspaceBuilds) + r.Get("/{workspacebuildname}", api.workspaceBuildByName) }) r.Route("/autostart", func(r chi.Router) { - r.Put("/", a.putWorkspaceAutostart) + r.Put("/", api.putWorkspaceAutostart) }) r.Route("/ttl", func(r chi.Router) { - r.Put("/", a.putWorkspaceTTL) + r.Put("/", api.putWorkspaceTTL) }) - r.Get("/watch", a.watchWorkspace) + r.Get("/watch", api.watchWorkspace) }) }) r.Route("/workspacebuilds/{workspacebuild}", func(r chi.Router) { @@ -329,48 +318,33 @@ func newRouter(options *Options, a *api) chi.Router { httpmw.ExtractWorkspaceBuildParam(options.Database), httpmw.ExtractWorkspaceParam(options.Database), ) - r.Get("/", a.workspaceBuild) - r.Patch("/cancel", a.patchCancelWorkspaceBuild) - r.Get("/logs", a.workspaceBuildLogs) - r.Get("/resources", a.workspaceBuildResources) - r.Get("/state", a.workspaceBuildState) + r.Get("/", api.workspaceBuild) + r.Patch("/cancel", api.patchCancelWorkspaceBuild) + r.Get("/logs", api.workspaceBuildLogs) + r.Get("/resources", api.workspaceBuildResources) + r.Get("/state", api.workspaceBuildState) }) }) - - var _ = xerrors.New("test") - r.NotFound(site.DefaultHandler().ServeHTTP) - return r -} -func New(options *Options) CoderD { - a := &api{Options: options} - return &coderD{ - api: a, - router: newRouter(options, a), - options: options, - } + return api } -func (c *coderD) CloseWait() { - c.api.websocketWaitMutex.Lock() - c.api.websocketWaitGroup.Wait() - c.api.websocketWaitMutex.Unlock() -} - -func (c *coderD) Handler() http.Handler { - return c.router -} - -// API contains all route handlers. Only HTTP handlers should -// be added to this struct for code clarity. -type api struct { +type API struct { *Options + Handler chi.Router websocketWaitMutex sync.Mutex websocketWaitGroup sync.WaitGroup } +// Close waits for all WebSocket connections to drain before returning. +func (api *API) Close() { + api.websocketWaitMutex.Lock() + api.websocketWaitGroup.Wait() + api.websocketWaitMutex.Unlock() +} + func debugLogRequest(log slog.Logger) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go index 1b1f7b45599a2..61236c14bd048 100644 --- a/coderd/coderd_test.go +++ b/coderd/coderd_test.go @@ -40,7 +40,7 @@ func TestAuthorizeAllEndpoints(t *testing.T) { ctx := context.Background() authorizer := &fakeAuthorizer{} - srv, client, _ := coderdtest.NewWithServer(t, &coderdtest.Options{ + client, api := coderdtest.NewWithAPI(t, &coderdtest.Options{ Authorizer: authorizer, IncludeProvisionerD: true, }) @@ -267,8 +267,7 @@ func TestAuthorizeAllEndpoints(t *testing.T) { assertRoute[noTrailSlash] = v } - c, _ := srv.Config.Handler.(*chi.Mux) - err = chi.Walk(c, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error { + err = chi.Walk(api.Handler, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error { name := method + ":" + route t.Run(name, func(t *testing.T) { authorizer.reset() diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 7ee5a2bc4dc9d..7d397e78c2758 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -69,16 +69,14 @@ type Options struct { IncludeProvisionerD bool } -// New constructs an in-memory coderd instance and returns -// the connected client. +// New constructs a codersdk client connected to an in-memory API instance. func New(t *testing.T, options *Options) *codersdk.Client { - _, cli, _ := NewWithServer(t, options) - return cli + client, _ := NewWithAPI(t, options) + return client } -// NewWithServer returns an in-memory coderd instance and -// the HTTP server it started with. -func NewWithServer(t *testing.T, options *Options) (*httptest.Server, *codersdk.Client, coderd.CoderD) { +// 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 { options = &Options{} } @@ -144,7 +142,7 @@ func NewWithServer(t *testing.T, options *Options) (*httptest.Server, *codersdk. require.NoError(t, err) // We set the handler after server creation for the access URL. - coderDaemon := coderd.New(&coderd.Options{ + coderAPI := coderd.New(&coderd.Options{ AgentConnectionUpdateFrequency: 150 * time.Millisecond, AccessURL: serverURL, Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), @@ -160,24 +158,24 @@ func NewWithServer(t *testing.T, options *Options) (*httptest.Server, *codersdk. APIRateLimit: options.APIRateLimit, Authorizer: options.Authorizer, }) - srv.Config.Handler = coderDaemon.Handler() + srv.Config.Handler = coderAPI.Handler if options.IncludeProvisionerD { - _ = NewProvisionerDaemon(t, coderDaemon) + _ = NewProvisionerDaemon(t, coderAPI) } t.Cleanup(func() { cancelFunc() _ = turnServer.Close() srv.Close() - coderDaemon.CloseWait() + coderAPI.Close() }) - return srv, codersdk.New(serverURL), coderDaemon + return codersdk.New(serverURL), coderAPI } // NewProvisionerDaemon launches a provisionerd instance configured to work // well with coderd testing. It registers the "echo" provisioner for // quick testing. -func NewProvisionerDaemon(t *testing.T, coderDaemon coderd.CoderD) io.Closer { +func NewProvisionerDaemon(t *testing.T, coderAPI *coderd.API) io.Closer { echoClient, echoServer := provisionersdk.TransportPipe() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(func() { @@ -192,7 +190,7 @@ func NewProvisionerDaemon(t *testing.T, coderDaemon coderd.CoderD) io.Closer { assert.NoError(t, err) }() - closer := provisionerd.New(coderDaemon.ListenProvisionerDaemon, &provisionerd.Options{ + closer := provisionerd.New(coderAPI.ListenProvisionerDaemon, &provisionerd.Options{ Logger: slogtest.Make(t, nil).Named("provisionerd").Leveled(slog.LevelDebug), PollInterval: 50 * time.Millisecond, UpdateInterval: 250 * time.Millisecond, diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index 10ee90d9d3435..633f3f906ba8e 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -14,9 +14,9 @@ func TestMain(m *testing.M) { func TestNew(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - closer := coderdtest.NewProvisionerDaemon(t, coderDaemon) + closer := coderdtest.NewProvisionerDaemon(t, coderAPI) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/coderd/files.go b/coderd/files.go index 74b4b56f26f02..5e63889496ae8 100644 --- a/coderd/files.go +++ b/coderd/files.go @@ -18,7 +18,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) postFile(rw http.ResponseWriter, r *http.Request) { +func (api *API) postFile(rw http.ResponseWriter, r *http.Request) { apiKey := httpmw.APIKey(r) // This requires the site wide action to create files. // Once created, a user can read their own files uploaded @@ -74,7 +74,7 @@ func (api *api) postFile(rw http.ResponseWriter, r *http.Request) { }) } -func (api *api) fileByHash(rw http.ResponseWriter, r *http.Request) { +func (api *API) fileByHash(rw http.ResponseWriter, r *http.Request) { hash := chi.URLParam(r, "hash") if hash == "" { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ diff --git a/coderd/gitsshkey.go b/coderd/gitsshkey.go index d5b2b049f892c..a80144fee2683 100644 --- a/coderd/gitsshkey.go +++ b/coderd/gitsshkey.go @@ -12,7 +12,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) { +func (api *API) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) if !api.Authorize(rw, r, rbac.ActionUpdate, rbac.ResourceUserData.WithOwner(user.ID.String())) { @@ -57,7 +57,7 @@ func (api *api) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) { }) } -func (api *api) gitSSHKey(rw http.ResponseWriter, r *http.Request) { +func (api *API) gitSSHKey(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceUserData.WithOwner(user.ID.String())) { @@ -81,7 +81,7 @@ func (api *api) gitSSHKey(rw http.ResponseWriter, r *http.Request) { }) } -func (api *api) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) { +func (api *API) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) { agent := httpmw.WorkspaceAgent(r) resource, err := api.Database.GetWorkspaceResourceByID(r.Context(), agent.ResourceID) if err != nil { diff --git a/coderd/gitsshkey_test.go b/coderd/gitsshkey_test.go index 97a8d28672edb..9f767c0d66e73 100644 --- a/coderd/gitsshkey_test.go +++ b/coderd/gitsshkey_test.go @@ -79,9 +79,9 @@ func TestGitSSHKey(t *testing.T) { func TestAgentGitSSHKey(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - daemonCloser := coderdtest.NewProvisionerDaemon(t, coderDaemon) + daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, diff --git a/coderd/members.go b/coderd/members.go index 4c716c537af50..78f44294ae87f 100644 --- a/coderd/members.go +++ b/coderd/members.go @@ -16,7 +16,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) putMemberRoles(rw http.ResponseWriter, r *http.Request) { +func (api *API) putMemberRoles(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) organization := httpmw.OrganizationParam(r) member := httpmw.OrganizationMemberParam(r) @@ -55,7 +55,7 @@ func (api *api) putMemberRoles(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertOrganizationMember(updatedUser)) } -func (api *api) updateOrganizationMemberRoles(ctx context.Context, args database.UpdateMemberRolesParams) (database.OrganizationMember, error) { +func (api *API) updateOrganizationMemberRoles(ctx context.Context, args database.UpdateMemberRolesParams) (database.OrganizationMember, error) { // Enforce only site wide roles for _, r := range args.GrantedRoles { // Must be an org role for the org in the args diff --git a/coderd/organizations.go b/coderd/organizations.go index b0b57f748ccd6..a5e3a958817dc 100644 --- a/coderd/organizations.go +++ b/coderd/organizations.go @@ -10,7 +10,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) organization(rw http.ResponseWriter, r *http.Request) { +func (api *API) organization(rw http.ResponseWriter, r *http.Request) { organization := httpmw.OrganizationParam(r) if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceOrganization. diff --git a/coderd/parameters.go b/coderd/parameters.go index 0f8afcbb2da60..9e719798083f2 100644 --- a/coderd/parameters.go +++ b/coderd/parameters.go @@ -16,7 +16,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) postParameter(rw http.ResponseWriter, r *http.Request) { +func (api *API) postParameter(rw http.ResponseWriter, r *http.Request) { var createRequest codersdk.CreateParameterRequest if !httpapi.Read(rw, r, &createRequest) { return @@ -63,7 +63,7 @@ func (api *api) postParameter(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusCreated, convertParameterValue(parameterValue)) } -func (api *api) parameters(rw http.ResponseWriter, r *http.Request) { +func (api *API) parameters(rw http.ResponseWriter, r *http.Request) { scope, scopeID, valid := readScopeAndID(rw, r) if !valid { return @@ -89,7 +89,7 @@ func (api *api) parameters(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, apiParameterValues) } -func (api *api) deleteParameter(rw http.ResponseWriter, r *http.Request) { +func (api *API) deleteParameter(rw http.ResponseWriter, r *http.Request) { scope, scopeID, valid := readScopeAndID(rw, r) if !valid { return diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index bb3fa21361bdd..590f3e56264f4 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -30,7 +30,7 @@ import ( sdkproto "github.com/coder/coder/provisionersdk/proto" ) -func (api *api) provisionerDaemonsByOrganization(rw http.ResponseWriter, r *http.Request) { +func (api *API) provisionerDaemonsByOrganization(rw http.ResponseWriter, r *http.Request) { daemons, err := api.Database.GetProvisionerDaemons(r.Context()) if errors.Is(err, sql.ErrNoRows) { err = nil @@ -49,7 +49,7 @@ func (api *api) provisionerDaemonsByOrganization(rw http.ResponseWriter, r *http // ListenProvisionerDaemon is an in-memory connection to a provisionerd. Useful when starting coderd and provisionerd // in the same process. -func (c *coderD) ListenProvisionerDaemon(ctx context.Context) (client proto.DRPCProvisionerDaemonClient, err error) { +func (api *API) ListenProvisionerDaemon(ctx context.Context) (client proto.DRPCProvisionerDaemonClient, err error) { clientSession, serverSession := provisionersdk.TransportPipe() defer func() { if err != nil { @@ -58,7 +58,7 @@ func (c *coderD) ListenProvisionerDaemon(ctx context.Context) (client proto.DRPC } }() - daemon, err := c.api.Database.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{ + daemon, err := api.Database.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{ ID: uuid.New(), CreatedAt: database.Now(), Name: namesgenerator.GetRandomName(1), @@ -70,12 +70,12 @@ func (c *coderD) ListenProvisionerDaemon(ctx context.Context) (client proto.DRPC mux := drpcmux.New() err = proto.DRPCRegisterProvisionerDaemon(mux, &provisionerdServer{ - AccessURL: c.options.AccessURL, + AccessURL: api.AccessURL, ID: daemon.ID, - Database: c.options.Database, - Pubsub: c.options.Pubsub, + Database: api.Database, + Pubsub: api.Pubsub, Provisioners: daemon.Provisioners, - Logger: c.options.Logger.Named(fmt.Sprintf("provisionerd-%s", daemon.Name)), + Logger: api.Logger.Named(fmt.Sprintf("provisionerd-%s", daemon.Name)), }) if err != nil { return nil, err @@ -85,13 +85,13 @@ func (c *coderD) ListenProvisionerDaemon(ctx context.Context) (client proto.DRPC if xerrors.Is(err, io.EOF) { return } - c.options.Logger.Debug(ctx, "drpc server error", slog.Error(err)) + api.Logger.Debug(ctx, "drpc server error", slog.Error(err)) }, }) go func() { err = server.Serve(ctx, serverSession) if err != nil && !xerrors.Is(err, io.EOF) { - c.options.Logger.Debug(ctx, "provisioner daemon disconnected", slog.Error(err)) + api.Logger.Debug(ctx, "provisioner daemon disconnected", slog.Error(err)) } // close the sessions so we don't leak goroutines serving them. _ = clientSession.Close() diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go index 8c8ded3620f2f..a47cc15541994 100644 --- a/coderd/provisionerjobs.go +++ b/coderd/provisionerjobs.go @@ -26,7 +26,7 @@ import ( // 2. GET /logs?after=&follow // The combination of these responses should provide all current logs // to the consumer, and future logs are streamed in the follow request. -func (api *api) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job database.ProvisionerJob) { +func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job database.ProvisionerJob) { follow := r.URL.Query().Has("follow") afterRaw := r.URL.Query().Get("after") beforeRaw := r.URL.Query().Get("before") @@ -178,7 +178,7 @@ func (api *api) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job } } -func (api *api) provisionerJobResources(rw http.ResponseWriter, r *http.Request, job database.ProvisionerJob) { +func (api *API) provisionerJobResources(rw http.ResponseWriter, r *http.Request, job database.ProvisionerJob) { if !job.CompletedAt.Valid { httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{ Message: "Job hasn't completed!", diff --git a/coderd/roles.go b/coderd/roles.go index 58d7ea96c6d14..3843124fbc45d 100644 --- a/coderd/roles.go +++ b/coderd/roles.go @@ -11,7 +11,7 @@ import ( ) // assignableSiteRoles returns all site wide roles that can be assigned. -func (api *api) assignableSiteRoles(rw http.ResponseWriter, r *http.Request) { +func (api *API) assignableSiteRoles(rw http.ResponseWriter, r *http.Request) { // TODO: @emyrk in the future, allow granular subsets of roles to be returned based on the // role of the user. @@ -24,7 +24,7 @@ func (api *api) assignableSiteRoles(rw http.ResponseWriter, r *http.Request) { } // assignableSiteRoles returns all site wide roles that can be assigned. -func (api *api) assignableOrgRoles(rw http.ResponseWriter, r *http.Request) { +func (api *API) assignableOrgRoles(rw http.ResponseWriter, r *http.Request) { // TODO: @emyrk in the future, allow granular subsets of roles to be returned based on the // role of the user. organization := httpmw.OrganizationParam(r) @@ -37,7 +37,7 @@ func (api *api) assignableOrgRoles(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertRoles(roles)) } -func (api *api) checkPermissions(rw http.ResponseWriter, r *http.Request) { +func (api *API) checkPermissions(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceUser.WithOwner(user.ID.String())) { diff --git a/coderd/templates.go b/coderd/templates.go index 44850f817f623..185836e293335 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -18,7 +18,7 @@ import ( ) // Returns a single template. -func (api *api) template(rw http.ResponseWriter, r *http.Request) { +func (api *API) template(rw http.ResponseWriter, r *http.Request) { template := httpmw.TemplateParam(r) workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByTemplateIDs(r.Context(), []uuid.UUID{template.ID}) @@ -44,7 +44,7 @@ func (api *api) template(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertTemplate(template, count)) } -func (api *api) deleteTemplate(rw http.ResponseWriter, r *http.Request) { +func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) { template := httpmw.TemplateParam(r) if !api.Authorize(rw, r, rbac.ActionDelete, template) { return @@ -84,7 +84,7 @@ func (api *api) deleteTemplate(rw http.ResponseWriter, r *http.Request) { } // Create a new template in an organization. -func (api *api) postTemplateByOrganization(rw http.ResponseWriter, r *http.Request) { +func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Request) { var createTemplate codersdk.CreateTemplateRequest organization := httpmw.OrganizationParam(r) if !api.Authorize(rw, r, rbac.ActionCreate, rbac.ResourceTemplate.InOrg(organization.ID)) { @@ -193,7 +193,7 @@ func (api *api) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque httpapi.Write(rw, http.StatusCreated, template) } -func (api *api) templatesByOrganization(rw http.ResponseWriter, r *http.Request) { +func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request) { organization := httpmw.OrganizationParam(r) templates, err := api.Database.GetTemplatesByOrganization(r.Context(), database.GetTemplatesByOrganizationParams{ OrganizationID: organization.ID, @@ -230,7 +230,7 @@ func (api *api) templatesByOrganization(rw http.ResponseWriter, r *http.Request) httpapi.Write(rw, http.StatusOK, convertTemplates(templates, workspaceCounts)) } -func (api *api) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { organization := httpmw.OrganizationParam(r) templateName := chi.URLParam(r, "templatename") template, err := api.Database.GetTemplateByOrganizationAndName(r.Context(), database.GetTemplateByOrganizationAndNameParams{ diff --git a/coderd/templateversions.go b/coderd/templateversions.go index bf8438d32238b..0c1c1d3f7de83 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -19,7 +19,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) templateVersion(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) { templateVersion := httpmw.TemplateVersionParam(r) if !api.Authorize(rw, r, rbac.ActionRead, templateVersion) { return @@ -36,7 +36,7 @@ func (api *api) templateVersion(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job))) } -func (api *api) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Request) { +func (api *API) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Request) { templateVersion := httpmw.TemplateVersionParam(r) if !api.Authorize(rw, r, rbac.ActionUpdate, templateVersion) { return @@ -79,7 +79,7 @@ func (api *api) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Reque }) } -func (api *api) templateVersionSchema(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateVersionSchema(rw http.ResponseWriter, r *http.Request) { templateVersion := httpmw.TemplateVersionParam(r) if !api.Authorize(rw, r, rbac.ActionRead, templateVersion) { return @@ -122,7 +122,7 @@ func (api *api) templateVersionSchema(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, apiSchemas) } -func (api *api) templateVersionParameters(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateVersionParameters(rw http.ResponseWriter, r *http.Request) { apiKey := httpmw.APIKey(r) templateVersion := httpmw.TemplateVersionParam(r) if !api.Authorize(rw, r, rbac.ActionRead, templateVersion) { @@ -163,7 +163,7 @@ func (api *api) templateVersionParameters(rw http.ResponseWriter, r *http.Reques httpapi.Write(rw, http.StatusOK, values) } -func (api *api) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Request) { template := httpmw.TemplateParam(r) if !api.Authorize(rw, r, rbac.ActionRead, template) { return @@ -221,7 +221,7 @@ func (api *api) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque httpapi.Write(rw, http.StatusOK, apiVersion) } -func (api *api) templateVersionByName(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) { template := httpmw.TemplateParam(r) if !api.Authorize(rw, r, rbac.ActionRead, template) { return @@ -258,7 +258,7 @@ func (api *api) templateVersionByName(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job))) } -func (api *api) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Request) { +func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Request) { template := httpmw.TemplateParam(r) if !api.Authorize(rw, r, rbac.ActionUpdate, template) { return @@ -303,7 +303,7 @@ func (api *api) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Reque } // Creates a new version of a template. An import job is queued to parse the storage method provided. -func (api *api) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *http.Request) { +func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *http.Request) { apiKey := httpmw.APIKey(r) organization := httpmw.OrganizationParam(r) var req codersdk.CreateTemplateVersionRequest @@ -415,7 +415,7 @@ func (api *api) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht // provisioned, each resource can have an agent that dials back to coderd. // The agents returned are informative of the template version, and do not // return agents associated with any particular workspace. -func (api *api) templateVersionResources(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateVersionResources(rw http.ResponseWriter, r *http.Request) { templateVersion := httpmw.TemplateVersionParam(r) if !api.Authorize(rw, r, rbac.ActionRead, templateVersion) { return @@ -435,7 +435,7 @@ func (api *api) templateVersionResources(rw http.ResponseWriter, r *http.Request // template version. These logs are only associated with the template version, // and not any build logs for a workspace. // Eg: Logs returned from 'terraform plan' when uploading a new terraform file. -func (api *api) templateVersionLogs(rw http.ResponseWriter, r *http.Request) { +func (api *API) templateVersionLogs(rw http.ResponseWriter, r *http.Request) { templateVersion := httpmw.TemplateVersionParam(r) if !api.Authorize(rw, r, rbac.ActionRead, templateVersion) { return diff --git a/coderd/userauth.go b/coderd/userauth.go index e2b52329b37a7..5838f933e2571 100644 --- a/coderd/userauth.go +++ b/coderd/userauth.go @@ -28,14 +28,14 @@ type GithubOAuth2Config struct { AllowOrganizations []string } -func (api *api) userAuthMethods(rw http.ResponseWriter, _ *http.Request) { +func (api *API) userAuthMethods(rw http.ResponseWriter, _ *http.Request) { httpapi.Write(rw, http.StatusOK, codersdk.AuthMethods{ Password: true, Github: api.GithubOAuth2Config != nil, }) } -func (api *api) userOAuth2Github(rw http.ResponseWriter, r *http.Request) { +func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) { state := httpmw.OAuth2(r) oauthClient := oauth2.NewClient(r.Context(), oauth2.StaticTokenSource(state.Token)) diff --git a/coderd/users.go b/coderd/users.go index 0e0ce9bda22b8..8e927a9466d7b 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -25,7 +25,7 @@ import ( ) // Returns whether the initial user has been created or not. -func (api *api) firstUser(rw http.ResponseWriter, r *http.Request) { +func (api *API) firstUser(rw http.ResponseWriter, r *http.Request) { userCount, err := api.Database.GetUserCount(r.Context()) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ @@ -47,7 +47,7 @@ func (api *api) firstUser(rw http.ResponseWriter, r *http.Request) { } // Creates the initial user for a Coder deployment. -func (api *api) postFirstUser(rw http.ResponseWriter, r *http.Request) { +func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) { var createUser codersdk.CreateFirstUserRequest if !httpapi.Read(rw, r, &createUser) { return @@ -103,7 +103,7 @@ func (api *api) postFirstUser(rw http.ResponseWriter, r *http.Request) { }) } -func (api *api) users(rw http.ResponseWriter, r *http.Request) { +func (api *API) users(rw http.ResponseWriter, r *http.Request) { var ( searchName = r.URL.Query().Get("search") statusFilter = r.URL.Query().Get("status") @@ -161,7 +161,7 @@ func (api *api) users(rw http.ResponseWriter, r *http.Request) { } // Creates a new user. -func (api *api) postUser(rw http.ResponseWriter, r *http.Request) { +func (api *API) postUser(rw http.ResponseWriter, r *http.Request) { // Create the user on the site if !api.Authorize(rw, r, rbac.ActionCreate, rbac.ResourceUser) { return @@ -224,7 +224,7 @@ func (api *api) postUser(rw http.ResponseWriter, r *http.Request) { // Returns the parameterized user requested. All validation // is completed in the middleware for this route. -func (api *api) userByName(rw http.ResponseWriter, r *http.Request) { +func (api *API) userByName(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) organizationIDs, err := userOrganizationIDs(r.Context(), api, user) @@ -242,7 +242,7 @@ func (api *api) userByName(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertUser(user, organizationIDs)) } -func (api *api) putUserProfile(rw http.ResponseWriter, r *http.Request) { +func (api *API) putUserProfile(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) if !api.Authorize(rw, r, rbac.ActionUpdate, rbac.ResourceUser.WithID(user.ID.String())) { @@ -311,7 +311,7 @@ func (api *api) putUserProfile(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertUser(updatedUserProfile, organizationIDs)) } -func (api *api) putUserStatus(status database.UserStatus) func(rw http.ResponseWriter, r *http.Request) { +func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseWriter, r *http.Request) { return func(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) apiKey := httpmw.APIKey(r) @@ -352,7 +352,7 @@ func (api *api) putUserStatus(status database.UserStatus) func(rw http.ResponseW } } -func (api *api) putUserPassword(rw http.ResponseWriter, r *http.Request) { +func (api *API) putUserPassword(rw http.ResponseWriter, r *http.Request) { var ( user = httpmw.UserParam(r) params codersdk.UpdateUserPasswordRequest @@ -387,7 +387,7 @@ func (api *api) putUserPassword(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusNoContent, nil) } -func (api *api) userRoles(rw http.ResponseWriter, r *http.Request) { +func (api *API) userRoles(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceUserData. @@ -421,7 +421,7 @@ func (api *api) userRoles(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, resp) } -func (api *api) putUserRoles(rw http.ResponseWriter, r *http.Request) { +func (api *API) putUserRoles(rw http.ResponseWriter, r *http.Request) { // User is the user to modify user := httpmw.UserParam(r) roles := httpmw.UserRoles(r) @@ -469,7 +469,7 @@ func (api *api) putUserRoles(rw http.ResponseWriter, r *http.Request) { // updateSiteUserRoles will ensure only site wide roles are passed in as arguments. // If an organization role is included, an error is returned. -func (api *api) updateSiteUserRoles(ctx context.Context, args database.UpdateUserRolesParams) (database.User, error) { +func (api *API) updateSiteUserRoles(ctx context.Context, args database.UpdateUserRolesParams) (database.User, error) { // Enforce only site wide roles for _, r := range args.GrantedRoles { if _, ok := rbac.IsOrgRole(r); ok { @@ -489,7 +489,7 @@ func (api *api) updateSiteUserRoles(ctx context.Context, args database.UpdateUse } // Returns organizations the parameterized user has access to. -func (api *api) organizationsByUser(rw http.ResponseWriter, r *http.Request) { +func (api *API) organizationsByUser(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) organizations, err := api.Database.GetOrganizationsByUserID(r.Context(), user.ID) @@ -515,7 +515,7 @@ func (api *api) organizationsByUser(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, publicOrganizations) } -func (api *api) organizationByUserAndName(rw http.ResponseWriter, r *http.Request) { +func (api *API) organizationByUserAndName(rw http.ResponseWriter, r *http.Request) { organizationName := chi.URLParam(r, "organizationname") organization, err := api.Database.GetOrganizationByName(r.Context(), organizationName) if errors.Is(err, sql.ErrNoRows) { @@ -539,7 +539,7 @@ func (api *api) organizationByUserAndName(rw http.ResponseWriter, r *http.Reques httpapi.Write(rw, http.StatusOK, convertOrganization(organization)) } -func (api *api) postOrganizationsByUser(rw http.ResponseWriter, r *http.Request) { +func (api *API) postOrganizationsByUser(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) var req codersdk.CreateOrganizationRequest if !httpapi.Read(rw, r, &req) { @@ -605,7 +605,7 @@ func (api *api) postOrganizationsByUser(rw http.ResponseWriter, r *http.Request) } // Authenticates the user with an email and password. -func (api *api) postLogin(rw http.ResponseWriter, r *http.Request) { +func (api *API) postLogin(rw http.ResponseWriter, r *http.Request) { var loginWithPassword codersdk.LoginWithPasswordRequest if !httpapi.Read(rw, r, &loginWithPassword) { return @@ -651,7 +651,7 @@ func (api *api) postLogin(rw http.ResponseWriter, r *http.Request) { } // Creates a new session key, used for logging in via the CLI -func (api *api) postAPIKey(rw http.ResponseWriter, r *http.Request) { +func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) if !api.Authorize(rw, r, rbac.ActionCreate, rbac.ResourceAPIKey.WithOwner(user.ID.String())) { @@ -670,7 +670,7 @@ func (api *api) postAPIKey(rw http.ResponseWriter, r *http.Request) { } // Clear the user's session cookie -func (*api) postLogout(rw http.ResponseWriter, _ *http.Request) { +func (*API) postLogout(rw http.ResponseWriter, _ *http.Request) { // Get a blank token cookie cookie := &http.Cookie{ // MaxAge < 0 means to delete the cookie now @@ -700,7 +700,7 @@ func generateAPIKeyIDSecret() (id string, secret string, err error) { return id, secret, nil } -func (api *api) createAPIKey(rw http.ResponseWriter, r *http.Request, params database.InsertAPIKeyParams) (string, bool) { +func (api *API) createAPIKey(rw http.ResponseWriter, r *http.Request, params database.InsertAPIKeyParams) (string, bool) { keyID, keySecret, err := generateAPIKeyIDSecret() if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ @@ -743,7 +743,7 @@ func (api *api) createAPIKey(rw http.ResponseWriter, r *http.Request, params dat return sessionToken, true } -func (api *api) createUser(ctx context.Context, req codersdk.CreateUserRequest) (database.User, uuid.UUID, error) { +func (api *API) createUser(ctx context.Context, req codersdk.CreateUserRequest) (database.User, uuid.UUID, error) { var user database.User return user, req.OrganizationID, api.Database.InTx(func(db database.Store) error { var orgRoles []string @@ -845,7 +845,7 @@ func convertUsers(users []database.User, organizationIDsByUserID map[uuid.UUID][ return converted } -func userOrganizationIDs(ctx context.Context, api *api, user database.User) ([]uuid.UUID, error) { +func userOrganizationIDs(ctx context.Context, api *API, user database.User) ([]uuid.UUID, error) { organizationIDsByMemberIDsRows, err := api.Database.GetOrganizationIDsByMemberIDs(ctx, []uuid.UUID{user.ID}) if errors.Is(err, sql.ErrNoRows) || len(organizationIDsByMemberIDsRows) == 0 { return []uuid.UUID{}, nil diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index ec26001b99ff1..bbda257eb01d5 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -28,7 +28,7 @@ import ( "github.com/coder/coder/provisionersdk" ) -func (api *api) workspaceAgent(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceAgent(rw http.ResponseWriter, r *http.Request) { workspaceAgent := httpmw.WorkspaceAgentParam(r) apiAgent, err := convertWorkspaceAgent(workspaceAgent, api.AgentConnectionUpdateFrequency) if err != nil { @@ -41,7 +41,7 @@ func (api *api) workspaceAgent(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, apiAgent) } -func (api *api) workspaceAgentDial(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceAgentDial(rw http.ResponseWriter, r *http.Request) { api.websocketWaitMutex.Lock() api.websocketWaitGroup.Add(1) api.websocketWaitMutex.Unlock() @@ -90,7 +90,7 @@ func (api *api) workspaceAgentDial(rw http.ResponseWriter, r *http.Request) { } } -func (api *api) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request) { workspaceAgent := httpmw.WorkspaceAgent(r) apiAgent, err := convertWorkspaceAgent(workspaceAgent, api.AgentConnectionUpdateFrequency) if err != nil { @@ -136,7 +136,7 @@ func (api *api) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request) }) } -func (api *api) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) { api.websocketWaitMutex.Lock() api.websocketWaitGroup.Add(1) api.websocketWaitMutex.Unlock() @@ -269,12 +269,12 @@ func (api *api) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) { } } -func (api *api) workspaceAgentICEServers(rw http.ResponseWriter, _ *http.Request) { +func (api *API) workspaceAgentICEServers(rw http.ResponseWriter, _ *http.Request) { httpapi.Write(rw, http.StatusOK, api.ICEServers) } // workspaceAgentTurn proxies a WebSocket connection to the TURN server. -func (api *api) workspaceAgentTurn(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceAgentTurn(rw http.ResponseWriter, r *http.Request) { api.websocketWaitMutex.Lock() api.websocketWaitGroup.Add(1) api.websocketWaitMutex.Unlock() @@ -324,7 +324,7 @@ func (api *api) workspaceAgentTurn(rw http.ResponseWriter, r *http.Request) { // workspaceAgentPTY spawns a PTY and pipes it over a WebSocket. // This is used for the web terminal. -func (api *api) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) { api.websocketWaitMutex.Lock() api.websocketWaitGroup.Add(1) api.websocketWaitMutex.Unlock() @@ -395,7 +395,7 @@ func (api *api) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) { } // dialWorkspaceAgent connects to a workspace agent by ID. -func (api *api) dialWorkspaceAgent(r *http.Request, agentID uuid.UUID) (*agent.Conn, error) { +func (api *API) dialWorkspaceAgent(r *http.Request, agentID uuid.UUID) (*agent.Conn, error) { client, server := provisionersdk.TransportPipe() go func() { _ = peerbroker.ProxyListen(r.Context(), server, peerbroker.ProxyOptions{ diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 9a8b9c4ee9b61..b14ac43bac4ce 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -27,9 +27,9 @@ func TestWorkspaceAgent(t *testing.T) { t.Parallel() t.Run("Connect", func(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - daemonCloser := coderdtest.NewProvisionerDaemon(t, coderDaemon) + daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, @@ -68,9 +68,9 @@ func TestWorkspaceAgent(t *testing.T) { func TestWorkspaceAgentListen(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - daemonCloser := coderdtest.NewProvisionerDaemon(t, coderDaemon) + daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, @@ -118,9 +118,9 @@ func TestWorkspaceAgentListen(t *testing.T) { func TestWorkspaceAgentTURN(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - daemonCloser := coderdtest.NewProvisionerDaemon(t, coderDaemon) + daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, @@ -179,9 +179,9 @@ func TestWorkspaceAgentPTY(t *testing.T) { // it seems like it could be either. t.Skip("ConPTY appears to be inconsistent on Windows.") } - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - daemonCloser := coderdtest.NewProvisionerDaemon(t, coderDaemon) + daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index d142ea4221c8c..b07f38b7f068e 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -19,7 +19,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) workspaceBuild(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) { workspaceBuild := httpmw.WorkspaceBuildParam(r) workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID) if err != nil { @@ -45,7 +45,7 @@ func (api *api) workspaceBuild(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(job))) } -func (api *api) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceWorkspace. @@ -107,7 +107,7 @@ func (api *api) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, apiBuilds) } -func (api *api) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceWorkspace. InOrg(workspace.OrganizationID).WithOwner(workspace.OwnerID.String()).WithID(workspace.ID.String())) { @@ -142,7 +142,7 @@ func (api *api) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(job))) } -func (api *api) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { +func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { apiKey := httpmw.APIKey(r) workspace := httpmw.WorkspaceParam(r) var createBuild codersdk.CreateWorkspaceBuildRequest @@ -310,7 +310,7 @@ func (api *api) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusCreated, convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(provisionerJob))) } -func (api *api) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Request) { +func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Request) { workspaceBuild := httpmw.WorkspaceBuildParam(r) workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID) if err != nil { @@ -362,7 +362,7 @@ func (api *api) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques }) } -func (api *api) workspaceBuildResources(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request) { workspaceBuild := httpmw.WorkspaceBuildParam(r) workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID) if err != nil { @@ -387,7 +387,7 @@ func (api *api) workspaceBuildResources(rw http.ResponseWriter, r *http.Request) api.provisionerJobResources(rw, r, job) } -func (api *api) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) { workspaceBuild := httpmw.WorkspaceBuildParam(r) workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID) if err != nil { @@ -412,7 +412,7 @@ func (api *api) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) { api.provisionerJobLogs(rw, r, job) } -func (api *api) workspaceBuildState(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) { workspaceBuild := httpmw.WorkspaceBuildParam(r) workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID) if err != nil { diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 8b5b9478601bf..70f61657e2a87 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -119,9 +119,9 @@ func TestWorkspaceBuildResources(t *testing.T) { t.Parallel() t.Run("ListRunning", func(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - closeDaemon := coderdtest.NewProvisionerDaemon(t, coderDaemon) + closeDaemon := coderdtest.NewProvisionerDaemon(t, coderAPI) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) closeDaemon.Close() diff --git a/coderd/workspaceresourceauth.go b/coderd/workspaceresourceauth.go index 17a713b651be5..e403271e01645 100644 --- a/coderd/workspaceresourceauth.go +++ b/coderd/workspaceresourceauth.go @@ -18,7 +18,7 @@ import ( // Azure supports instance identity verification: // https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#tabgroup_14 -func (api *api) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r *http.Request) { +func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r *http.Request) { var req codersdk.AzureInstanceIdentityToken if !httpapi.Read(rw, r, &req) { return @@ -36,7 +36,7 @@ func (api *api) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r // AWS supports instance identity verification: // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html // Using this, we can exchange a signed instance payload for an agent token. -func (api *api) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r *http.Request) { +func (api *API) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r *http.Request) { var req codersdk.AWSInstanceIdentityToken if !httpapi.Read(rw, r, &req) { return @@ -54,7 +54,7 @@ func (api *api) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r * // Google Compute Engine supports instance identity verification: // https://cloud.google.com/compute/docs/instances/verifying-instance-identity // Using this, we can exchange a signed instance payload for an agent token. -func (api *api) postWorkspaceAuthGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) { +func (api *API) postWorkspaceAuthGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) { var req codersdk.GoogleInstanceIdentityToken if !httpapi.Read(rw, r, &req) { return @@ -85,7 +85,7 @@ func (api *api) postWorkspaceAuthGoogleInstanceIdentity(rw http.ResponseWriter, api.handleAuthInstanceID(rw, r, claims.Google.ComputeEngine.InstanceID) } -func (api *api) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, instanceID string) { +func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, instanceID string) { agent, err := api.Database.GetWorkspaceAgentByInstanceID(r.Context(), instanceID) if errors.Is(err, sql.ErrNoRows) { httpapi.Write(rw, http.StatusNotFound, httpapi.Response{ diff --git a/coderd/workspaceresources.go b/coderd/workspaceresources.go index 1bdf1f83e94b9..a08861971e60e 100644 --- a/coderd/workspaceresources.go +++ b/coderd/workspaceresources.go @@ -14,7 +14,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) workspaceResource(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceResource(rw http.ResponseWriter, r *http.Request) { workspaceBuild := httpmw.WorkspaceBuildParam(r) workspaceResource := httpmw.WorkspaceResourceParam(r) workspace := httpmw.WorkspaceParam(r) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index a30534a03e24d..340697a436baa 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -28,7 +28,7 @@ import ( "github.com/coder/coder/codersdk" ) -func (api *api) workspace(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspace(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) if !api.Authorize(rw, r, rbac.ActionRead, workspace) { return @@ -100,7 +100,7 @@ func (api *api) workspace(rw http.ResponseWriter, r *http.Request) { convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), template, owner)) } -func (api *api) workspacesByOrganization(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspacesByOrganization(rw http.ResponseWriter, r *http.Request) { organization := httpmw.OrganizationParam(r) workspaces, err := api.Database.GetWorkspacesWithFilter(r.Context(), database.GetWorkspacesWithFilterParams{ OrganizationID: organization.ID, @@ -131,7 +131,7 @@ func (api *api) workspacesByOrganization(rw http.ResponseWriter, r *http.Request // workspaces returns all workspaces a user can read. // Optional filters with query params -func (api *api) workspaces(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) { apiKey := httpmw.APIKey(r) // Empty strings mean no filter @@ -192,7 +192,7 @@ func (api *api) workspaces(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, apiWorkspaces) } -func (api *api) workspacesByOwner(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspacesByOwner(rw http.ResponseWriter, r *http.Request) { owner := httpmw.UserParam(r) workspaces, err := api.Database.GetWorkspacesWithFilter(r.Context(), database.GetWorkspacesWithFilterParams{ OwnerID: owner.ID, @@ -221,7 +221,7 @@ func (api *api) workspacesByOwner(rw http.ResponseWriter, r *http.Request) { httpapi.Write(rw, http.StatusOK, apiWorkspaces) } -func (api *api) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) { +func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) { owner := httpmw.UserParam(r) organization := httpmw.OrganizationParam(r) workspaceName := chi.URLParam(r, "workspacename") @@ -280,7 +280,7 @@ func (api *api) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) } // Create a new workspace for the currently authenticated user. -func (api *api) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) { +func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) { var createWorkspace codersdk.CreateWorkspaceRequest if !httpapi.Read(rw, r, &createWorkspace) { return @@ -502,7 +502,7 @@ func (api *api) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(templateVersionJob)), template, user)) } -func (api *api) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { +func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) if !api.Authorize(rw, r, rbac.ActionUpdate, rbac.ResourceWorkspace. InOrg(workspace.OrganizationID).WithOwner(workspace.OwnerID.String()).WithID(workspace.ID.String())) { @@ -539,7 +539,7 @@ func (api *api) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { } } -func (api *api) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { +func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) if !api.Authorize(rw, r, rbac.ActionUpdate, rbac.ResourceWorkspace. InOrg(workspace.OrganizationID).WithOwner(workspace.OwnerID.String()).WithID(workspace.ID.String())) { @@ -570,7 +570,7 @@ func (api *api) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { } } -func (api *api) watchWorkspace(rw http.ResponseWriter, r *http.Request) { +func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) c, err := websocket.Accept(rw, r, &websocket.AcceptOptions{ diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index ed15bf82c1434..97191ec95f0ac 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -290,9 +290,9 @@ func TestPostWorkspaceBuild(t *testing.T) { t.Run("AlreadyActive", func(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - closeDaemon := coderdtest.NewProvisionerDaemon(t, coderDaemon) + closeDaemon := coderdtest.NewProvisionerDaemon(t, coderAPI) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) @@ -328,9 +328,9 @@ func TestPostWorkspaceBuild(t *testing.T) { t.Run("WithState", func(t *testing.T) { t.Parallel() - _, client, coderDaemon := coderdtest.NewWithServer(t, nil) + client, coderAPI := coderdtest.NewWithAPI(t, nil) user := coderdtest.CreateFirstUser(t, client) - closeDaemon := coderdtest.NewProvisionerDaemon(t, coderDaemon) + closeDaemon := coderdtest.NewProvisionerDaemon(t, coderAPI) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID)