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) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy