mirror of
https://github.com/coder/coder.git
synced 2025-07-13 21:36:50 +00:00
feat: Refactor API routes to use UUIDs instead of friendly names (#401)
* Add client for agent * Cleanup code * Fix linting error * Rename routes to be simpler * Rename workspace history to workspace build * Refactor HTTP middlewares to use UUIDs * Cleanup routes * Compiles! * Fix files and organizations * Fix querying * Fix agent lock * Cleanup database abstraction * Add parameters * Fix linting errors * Fix log race * Lock on close wait * Fix log cleanup * Fix e2e tests * Fix upstream version of opencensus-go * Update coderdtest.go * Fix coverpkg * Fix codecov ignore
This commit is contained in:
@ -59,7 +59,7 @@ func login() *cobra.Command {
|
||||
}
|
||||
|
||||
client := codersdk.New(serverURL)
|
||||
hasInitialUser, err := client.HasInitialUser(cmd.Context())
|
||||
hasInitialUser, err := client.HasFirstUser(cmd.Context())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("has initial user: %w", err)
|
||||
}
|
||||
@ -119,7 +119,7 @@ func login() *cobra.Command {
|
||||
return xerrors.Errorf("specify password prompt: %w", err)
|
||||
}
|
||||
|
||||
_, err = client.CreateInitialUser(cmd.Context(), coderd.CreateInitialUserRequest{
|
||||
_, err = client.CreateFirstUser(cmd.Context(), coderd.CreateFirstUserRequest{
|
||||
Email: email,
|
||||
Username: username,
|
||||
Password: password,
|
||||
|
@ -1,13 +1,11 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/cli/clitest"
|
||||
"github.com/coder/coder/coderd"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/pty/ptytest"
|
||||
)
|
||||
@ -56,18 +54,7 @@ func TestLogin(t *testing.T) {
|
||||
t.Run("ExistingUserValidTokenTTY", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{
|
||||
Username: "test-user",
|
||||
Email: "test-user@coder.com",
|
||||
Organization: "acme-corp",
|
||||
Password: "password",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
token, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{
|
||||
Email: "test-user@coder.com",
|
||||
Password: "password",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
root, _ := clitest.New(t, "login", client.URL.String(), "--force-tty", "--no-open")
|
||||
pty := ptytest.New(t)
|
||||
@ -79,20 +66,14 @@ func TestLogin(t *testing.T) {
|
||||
}()
|
||||
|
||||
pty.ExpectMatch("Paste your token here:")
|
||||
pty.WriteLine(token.SessionToken)
|
||||
pty.WriteLine(client.SessionToken)
|
||||
pty.ExpectMatch("Welcome to Coder")
|
||||
})
|
||||
|
||||
t.Run("ExistingUserInvalidTokenTTY", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{
|
||||
Username: "test-user",
|
||||
Email: "test-user@coder.com",
|
||||
Organization: "acme-corp",
|
||||
Password: "password",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
root, _ := clitest.New(t, "login", client.URL.String(), "--force-tty", "--no-open")
|
||||
pty := ptytest.New(t)
|
||||
|
@ -56,7 +56,7 @@ func projectCreate() *cobra.Command {
|
||||
Default: filepath.Base(directory),
|
||||
Label: "What's your project's name?",
|
||||
Validate: func(s string) error {
|
||||
project, _ := client.Project(cmd.Context(), organization.Name, s)
|
||||
project, _ := client.ProjectByName(cmd.Context(), organization.ID, s)
|
||||
if project.ID.String() != uuid.Nil.String() {
|
||||
return xerrors.New("A project already exists with that name!")
|
||||
}
|
||||
@ -71,9 +71,9 @@ func projectCreate() *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
|
||||
Name: name,
|
||||
VersionImportJobID: job.ID,
|
||||
project, err := client.CreateProject(cmd.Context(), organization.ID, coderd.CreateProjectRequest{
|
||||
Name: name,
|
||||
VersionID: job.ID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -118,7 +118,7 @@ func projectCreate() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, organization coderd.Organization, provisioner database.ProvisionerType, directory string, parameters ...coderd.CreateParameterValueRequest) (*coderd.ProvisionerJob, error) {
|
||||
func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, organization coderd.Organization, provisioner database.ProvisionerType, directory string, parameters ...coderd.CreateParameterRequest) (*coderd.ProjectVersion, error) {
|
||||
spin := spinner.New(spinner.CharSets[5], 100*time.Millisecond)
|
||||
spin.Writer = cmd.OutOrStdout()
|
||||
spin.Suffix = " Uploading current directory..."
|
||||
@ -133,13 +133,13 @@ func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, o
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := client.UploadFile(cmd.Context(), codersdk.ContentTypeTar, tarData)
|
||||
resp, err := client.Upload(cmd.Context(), codersdk.ContentTypeTar, tarData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
before := time.Now()
|
||||
job, err := client.CreateProjectImportJob(cmd.Context(), organization.Name, coderd.CreateProjectImportJobRequest{
|
||||
version, err := client.CreateProjectVersion(cmd.Context(), organization.ID, coderd.CreateProjectVersionRequest{
|
||||
StorageMethod: database.ProvisionerStorageMethodFile,
|
||||
StorageSource: resp.Hash,
|
||||
Provisioner: provisioner,
|
||||
@ -149,7 +149,7 @@ func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, o
|
||||
return nil, err
|
||||
}
|
||||
spin.Suffix = " Waiting for the import to complete..."
|
||||
logs, err := client.ProjectImportJobLogsAfter(cmd.Context(), organization.Name, job.ID, before)
|
||||
logs, err := client.ProjectVersionLogsAfter(cmd.Context(), version.ID, before)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -162,22 +162,22 @@ func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, o
|
||||
logBuffer = append(logBuffer, log)
|
||||
}
|
||||
|
||||
job, err = client.ProjectImportJob(cmd.Context(), organization.Name, job.ID)
|
||||
version, err = client.ProjectVersion(cmd.Context(), version.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parameterSchemas, err := client.ProjectImportJobSchemas(cmd.Context(), organization.Name, job.ID)
|
||||
parameterSchemas, err := client.ProjectVersionSchema(cmd.Context(), version.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parameterValues, err := client.ProjectImportJobParameters(cmd.Context(), organization.Name, job.ID)
|
||||
parameterValues, err := client.ProjectVersionParameters(cmd.Context(), version.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spin.Stop()
|
||||
|
||||
if provisionerd.IsMissingParameterError(job.Error) {
|
||||
valuesBySchemaID := map[string]coderd.ComputedParameterValue{}
|
||||
if provisionerd.IsMissingParameterError(version.Job.Error) {
|
||||
valuesBySchemaID := map[string]coderd.ProjectVersionParameter{}
|
||||
for _, parameterValue := range parameterValues {
|
||||
valuesBySchemaID[parameterValue.SchemaID.String()] = parameterValue
|
||||
}
|
||||
@ -192,7 +192,7 @@ func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, o
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parameters = append(parameters, coderd.CreateParameterValueRequest{
|
||||
parameters = append(parameters, coderd.CreateParameterRequest{
|
||||
Name: parameterSchema.Name,
|
||||
SourceValue: value,
|
||||
SourceScheme: database.ParameterSourceSchemeData,
|
||||
@ -202,21 +202,20 @@ func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, o
|
||||
return validateProjectVersionSource(cmd, client, organization, provisioner, directory, parameters...)
|
||||
}
|
||||
|
||||
if job.Status != coderd.ProvisionerJobStatusSucceeded {
|
||||
if version.Job.Status != coderd.ProvisionerJobSucceeded {
|
||||
for _, log := range logBuffer {
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s %s\n", color.HiGreenString("[tf]"), log.Output)
|
||||
}
|
||||
|
||||
return nil, xerrors.New(job.Error)
|
||||
return nil, xerrors.New(version.Job.Error)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s Successfully imported project source!\n", color.HiGreenString("✓"))
|
||||
|
||||
resources, err := client.ProjectImportJobResources(cmd.Context(), organization.Name, job.ID)
|
||||
resources, err := client.ProjectVersionResources(cmd.Context(), version.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &job, displayProjectImportInfo(cmd, parameterSchemas, parameterValues, resources)
|
||||
return &version, displayProjectImportInfo(cmd, parameterSchemas, parameterValues, resources)
|
||||
}
|
||||
|
||||
func tarDirectory(directory string) ([]byte, error) {
|
||||
|
@ -18,7 +18,7 @@ func TestProjectCreate(t *testing.T) {
|
||||
t.Run("NoParameters", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
coderdtest.CreateInitialUser(t, client)
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
source := clitest.CreateProjectVersionSource(t, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
Provision: echo.ProvisionComplete,
|
||||
@ -54,7 +54,7 @@ func TestProjectCreate(t *testing.T) {
|
||||
t.Run("Parameter", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
coderdtest.CreateInitialUser(t, client)
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
source := clitest.CreateProjectVersionSource(t, &echo.Responses{
|
||||
Parse: []*proto.Parse_Response{{
|
||||
Type: &proto.Parse_Response_Complete{
|
||||
|
@ -23,7 +23,7 @@ func projectList() *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projects, err := client.Projects(cmd.Context(), organization.Name)
|
||||
projects, err := client.ProjectsByOrganization(cmd.Context(), organization.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ func TestProjectList(t *testing.T) {
|
||||
t.Run("None", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
coderdtest.CreateInitialUser(t, client)
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
cmd, root := clitest.New(t, "projects", "list")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
pty := ptytest.New(t)
|
||||
@ -33,12 +33,12 @@ func TestProjectList(t *testing.T) {
|
||||
t.Run("List", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateInitialUser(t, client)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
daemon := coderdtest.NewProvisionerDaemon(t, client)
|
||||
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
|
||||
coderdtest.AwaitProjectImportJob(t, client, user.Organization, job.ID)
|
||||
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
|
||||
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
|
||||
_ = daemon.Close()
|
||||
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
|
||||
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
|
||||
cmd, root := clitest.New(t, "projects", "list")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
pty := ptytest.New(t)
|
||||
|
@ -40,8 +40,8 @@ func projects() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProvisionerJobResource) error {
|
||||
schemaByID := map[string]coderd.ParameterSchema{}
|
||||
func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ProjectVersionParameterSchema, parameterValues []coderd.ProjectVersionParameter, resources []coderd.WorkspaceResource) error {
|
||||
schemaByID := map[string]coderd.ProjectVersionParameterSchema{}
|
||||
for _, schema := range parameterSchemas {
|
||||
schemaByID[schema.ID.String()] = schema
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ func createClient(cmd *cobra.Command) (*codersdk.Client, error) {
|
||||
|
||||
// currentOrganization returns the currently active organization for the authenticated user.
|
||||
func currentOrganization(cmd *cobra.Command, client *codersdk.Client) (coderd.Organization, error) {
|
||||
orgs, err := client.UserOrganizations(cmd.Context(), "me")
|
||||
orgs, err := client.OrganizationsByUser(cmd.Context(), "me")
|
||||
if err != nil {
|
||||
return coderd.Organization{}, nil
|
||||
}
|
||||
|
57
cli/workspaceagent.go
Normal file
57
cli/workspaceagent.go
Normal file
@ -0,0 +1,57 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/powersj/whatsthis/pkg/cloud"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/agent"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
func workspaceAgent() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "agent",
|
||||
// This command isn't useful for users, and seems
|
||||
// more likely to confuse.
|
||||
Hidden: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
coderURLRaw, exists := os.LookupEnv("CODER_URL")
|
||||
if !exists {
|
||||
return xerrors.New("CODER_URL must be set")
|
||||
}
|
||||
coderURL, err := url.Parse(coderURLRaw)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse %q: %w", coderURLRaw, err)
|
||||
}
|
||||
client := codersdk.New(coderURL)
|
||||
sessionToken, exists := os.LookupEnv("CODER_TOKEN")
|
||||
if !exists {
|
||||
probe, err := cloud.New()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("probe cloud: %w", err)
|
||||
}
|
||||
if !probe.Detected {
|
||||
return xerrors.Errorf("no valid authentication method found; set \"CODER_TOKEN\"")
|
||||
}
|
||||
switch {
|
||||
case probe.GCP():
|
||||
response, err := client.AuthWorkspaceGoogleInstanceIdentity(cmd.Context(), "", nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("authenticate workspace with gcp: %w", err)
|
||||
}
|
||||
sessionToken = response.SessionToken
|
||||
default:
|
||||
return xerrors.Errorf("%q authentication not supported; set \"CODER_TOKEN\" instead", probe.Name)
|
||||
}
|
||||
}
|
||||
client.SessionToken = sessionToken
|
||||
closer := agent.New(client.ListenWorkspaceAgent, nil)
|
||||
<-cmd.Context().Done()
|
||||
return closer.Close()
|
||||
},
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ func workspaceCreate() *cobra.Command {
|
||||
if s == "" {
|
||||
return xerrors.Errorf("You must provide a name!")
|
||||
}
|
||||
workspace, _ := client.Workspace(cmd.Context(), "", s)
|
||||
workspace, _ := client.WorkspaceByName(cmd.Context(), "", s)
|
||||
if workspace.ID.String() != uuid.Nil.String() {
|
||||
return xerrors.New("A workspace already exists with that name!")
|
||||
}
|
||||
@ -56,23 +56,23 @@ func workspaceCreate() *cobra.Command {
|
||||
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s Previewing project create...\n", caret)
|
||||
|
||||
project, err := client.Project(cmd.Context(), organization.Name, args[0])
|
||||
project, err := client.ProjectByName(cmd.Context(), organization.ID, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectVersion, err := client.ProjectVersion(cmd.Context(), organization.Name, project.Name, project.ActiveVersionID.String())
|
||||
projectVersion, err := client.ProjectVersion(cmd.Context(), project.ActiveVersionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parameterSchemas, err := client.ProjectImportJobSchemas(cmd.Context(), organization.Name, projectVersion.ImportJobID)
|
||||
parameterSchemas, err := client.ProjectVersionSchema(cmd.Context(), projectVersion.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parameterValues, err := client.ProjectImportJobParameters(cmd.Context(), organization.Name, projectVersion.ImportJobID)
|
||||
parameterValues, err := client.ProjectVersionParameters(cmd.Context(), projectVersion.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resources, err := client.ProjectImportJobResources(cmd.Context(), organization.Name, projectVersion.ImportJobID)
|
||||
resources, err := client.ProjectVersionResources(cmd.Context(), projectVersion.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -100,7 +100,7 @@ func workspaceCreate() *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
history, err := client.CreateWorkspaceHistory(cmd.Context(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{
|
||||
version, err := client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, coderd.CreateWorkspaceBuildRequest{
|
||||
ProjectVersionID: projectVersion.ID,
|
||||
Transition: database.WorkspaceTransitionStart,
|
||||
})
|
||||
@ -108,7 +108,7 @@ func workspaceCreate() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
logs, err := client.WorkspaceProvisionJobLogsAfter(cmd.Context(), organization.Name, history.ProvisionJobID, time.Time{})
|
||||
logs, err := client.WorkspaceBuildLogsAfter(cmd.Context(), version.ID, time.Time{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ func TestWorkspaceCreate(t *testing.T) {
|
||||
t.Run("Create", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateInitialUser(t, client)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
_ = coderdtest.NewProvisionerDaemon(t, client)
|
||||
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, &echo.Responses{
|
||||
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
Provision: []*proto.Provision_Response{{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
@ -32,8 +32,8 @@ func TestWorkspaceCreate(t *testing.T) {
|
||||
},
|
||||
}},
|
||||
})
|
||||
coderdtest.AwaitProjectImportJob(t, client, user.Organization, job.ID)
|
||||
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
|
||||
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
|
||||
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
|
||||
cmd, root := clitest.New(t, "workspaces", "create", project.Name)
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
|
@ -6,6 +6,7 @@ func workspaces() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "workspaces",
|
||||
}
|
||||
cmd.AddCommand(workspaceAgent())
|
||||
cmd.AddCommand(workspaceCreate())
|
||||
|
||||
return cmd
|
||||
|
Reference in New Issue
Block a user