From 44e8ee2b7acb352c69c69d056101b46b5b13af31 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 4 Feb 2022 21:12:19 +0000 Subject: [PATCH] feat: Add echo provisioner This replaces the cdr-basic provisioner type with "echo". It reads binary data from the directory and returns the responses in order. This is used to test project and workspace job logic. --- coderd/coderdtest/coderdtest.go | 20 ++- coderd/projecthistory_test.go | 25 ++-- coderd/projects.go | 2 +- coderd/projects_test.go | 42 +++---- coderd/provisionerdaemons.go | 2 +- coderd/workspacehistory_test.go | 51 +++----- coderd/workspacehistorylogs_test.go | 40 +++--- coderd/workspaces_test.go | 8 +- codersdk/projects_test.go | 12 +- codersdk/workspaces_test.go | 24 ++-- database/dump.sql | 4 +- database/migrations/000002_projects.up.sql | 2 +- database/models.go | 2 +- provisioner/echo/serve.go | 138 +++++++++++++++++++++ provisioner/echo/serve_test.go | 123 ++++++++++++++++++ 15 files changed, 366 insertions(+), 129 deletions(-) create mode 100644 provisioner/echo/serve.go create mode 100644 provisioner/echo/serve_test.go diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index d064c82dcfb61..86a50fabd0d28 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -20,7 +20,7 @@ import ( "github.com/coder/coder/database" "github.com/coder/coder/database/databasefake" "github.com/coder/coder/database/postgres" - "github.com/coder/coder/provisioner/terraform" + "github.com/coder/coder/provisioner/echo" "github.com/coder/coder/provisionerd" "github.com/coder/coder/provisionersdk" "github.com/coder/coder/provisionersdk/proto" @@ -64,21 +64,19 @@ func (s *Server) RandomInitialUser(t *testing.T) coderd.CreateInitialUserRequest return req } -// AddProvisionerd launches a new provisionerd instance! +// AddProvisionerd launches a new provisionerd instance with the +// test provisioner registered. func (s *Server) AddProvisionerd(t *testing.T) io.Closer { - tfClient, tfServer := provisionersdk.TransportPipe() + echoClient, echoServer := provisionersdk.TransportPipe() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(func() { - _ = tfClient.Close() - _ = tfServer.Close() + _ = echoClient.Close() + _ = echoServer.Close() cancelFunc() }) go func() { - err := terraform.Serve(ctx, &terraform.ServeOptions{ - ServeOptions: &provisionersdk.ServeOptions{ - Listener: tfServer, - }, - Logger: slogtest.Make(t, nil).Named("terraform-provisioner").Leveled(slog.LevelDebug), + err := echo.Serve(ctx, &provisionersdk.ServeOptions{ + Listener: echoServer, }) require.NoError(t, err) }() @@ -88,7 +86,7 @@ func (s *Server) AddProvisionerd(t *testing.T) io.Closer { PollInterval: 50 * time.Millisecond, UpdateInterval: 50 * time.Millisecond, Provisioners: provisionerd.Provisioners{ - string(database.ProvisionerTypeTerraform): proto.NewDRPCProvisionerClient(provisionersdk.Conn(tfClient)), + string(database.ProvisionerTypeEcho): proto.NewDRPCProvisionerClient(provisionersdk.Conn(echoClient)), }, WorkDirectory: t.TempDir(), }) diff --git a/coderd/projecthistory_test.go b/coderd/projecthistory_test.go index f3a1922b0ea4c..a0cf932886835 100644 --- a/coderd/projecthistory_test.go +++ b/coderd/projecthistory_test.go @@ -11,6 +11,8 @@ import ( "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/database" + "github.com/coder/coder/provisioner/echo" + "github.com/coder/coder/provisionersdk/proto" ) func TestProjectHistory(t *testing.T) { @@ -22,7 +24,7 @@ func TestProjectHistory(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) versions, err := server.Client.ListProjectHistory(context.Background(), user.Organization, project.Name) @@ -36,21 +38,18 @@ func TestProjectHistory(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - var buffer bytes.Buffer - writer := tar.NewWriter(&buffer) - err = writer.WriteHeader(&tar.Header{ - Name: "file", - Size: 1 << 10, - }) - require.NoError(t, err) - _, err = writer.Write(make([]byte, 1<<10)) + data, err := echo.Tar([]*proto.Parse_Response{{ + Type: &proto.Parse_Response_Complete{ + Complete: &proto.Parse_Complete{}, + }, + }}, nil) require.NoError(t, err) history, err := server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: buffer.Bytes(), + StorageSource: data, }) require.NoError(t, err) versions, err := server.Client.ListProjectHistory(context.Background(), user.Organization, project.Name) @@ -67,7 +66,7 @@ func TestProjectHistory(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) var buffer bytes.Buffer @@ -92,7 +91,7 @@ func TestProjectHistory(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ diff --git a/coderd/projects.go b/coderd/projects.go index e0ed677fa6315..991d20f0e79cf 100644 --- a/coderd/projects.go +++ b/coderd/projects.go @@ -22,7 +22,7 @@ type Project database.Project // CreateProjectRequest enables callers to create a new Project. type CreateProjectRequest struct { Name string `json:"name" validate:"username,required"` - Provisioner database.ProvisionerType `json:"provisioner" validate:"oneof=terraform cdr-basic,required"` + Provisioner database.ProvisionerType `json:"provisioner" validate:"oneof=terraform echo,required"` } // Lists all projects the authenticated user has access to. diff --git a/coderd/projects_test.go b/coderd/projects_test.go index 5e96b78aadd71..14ed1af4f03b1 100644 --- a/coderd/projects_test.go +++ b/coderd/projects_test.go @@ -1,8 +1,6 @@ package coderd_test import ( - "archive/tar" - "bytes" "context" "testing" "time" @@ -12,6 +10,8 @@ import ( "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/database" + "github.com/coder/coder/provisioner/echo" + "github.com/coder/coder/provisionersdk/proto" ) func TestProjects(t *testing.T) { @@ -23,7 +23,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) }) @@ -34,12 +34,12 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.Error(t, err) }) @@ -59,7 +59,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) // Ensure global query works. @@ -89,7 +89,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.Project(context.Background(), user.Organization, project.Name) @@ -102,7 +102,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.ProjectParameters(context.Background(), user.Organization, project.Name) @@ -115,7 +115,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ @@ -135,24 +135,22 @@ func TestProjects(t *testing.T) { _ = server.AddProvisionerd(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - var buffer bytes.Buffer - writer := tar.NewWriter(&buffer) - content := `variable "example" { - default = "hi" -}` - err = writer.WriteHeader(&tar.Header{ - Name: "main.tf", - Size: int64(len(content)), - }) - require.NoError(t, err) - _, err = writer.Write([]byte(content)) + data, err := echo.Tar([]*proto.Parse_Response{{ + Type: &proto.Parse_Response_Complete{ + Complete: &proto.Parse_Complete{ + ParameterSchemas: []*proto.ParameterSchema{{ + Name: "example", + }}, + }, + }, + }}, nil) require.NoError(t, err) history, err := server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: buffer.Bytes(), + StorageSource: data, }) require.NoError(t, err) require.Eventually(t, func() bool { diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index ac9cb7f3cb422..445f9ed1710ac 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -65,7 +65,7 @@ func (api *api) provisionerDaemonsServe(rw http.ResponseWriter, r *http.Request) ID: uuid.New(), CreatedAt: database.Now(), Name: namesgenerator.GetRandomName(1), - Provisioners: []database.ProvisionerType{database.ProvisionerTypeCdrBasic, database.ProvisionerTypeTerraform}, + Provisioners: []database.ProvisionerType{database.ProvisionerTypeEcho, database.ProvisionerTypeTerraform}, }) if err != nil { _ = conn.Close(websocket.StatusInternalError, fmt.Sprintf("insert provisioner daemon:% s", err)) diff --git a/coderd/workspacehistory_test.go b/coderd/workspacehistory_test.go index 49a41a4d25e0e..d65e82fd10ecb 100644 --- a/coderd/workspacehistory_test.go +++ b/coderd/workspacehistory_test.go @@ -1,8 +1,6 @@ package coderd_test import ( - "archive/tar" - "bytes" "context" "testing" "time" @@ -14,6 +12,7 @@ import ( "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/codersdk" "github.com/coder/coder/database" + "github.com/coder/coder/provisioner/echo" ) func TestWorkspaceHistory(t *testing.T) { @@ -22,7 +21,7 @@ func TestWorkspaceHistory(t *testing.T) { setupProjectAndWorkspace := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest) (coderd.Project, coderd.Workspace) { project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ @@ -33,24 +32,10 @@ func TestWorkspaceHistory(t *testing.T) { return project, workspace } - setupProjectHistory := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, files map[string]string) coderd.ProjectHistory { - var buffer bytes.Buffer - writer := tar.NewWriter(&buffer) - for path, content := range files { - err := writer.WriteHeader(&tar.Header{ - Name: path, - Size: int64(len(content)), - }) - require.NoError(t, err) - _, err = writer.Write([]byte(content)) - require.NoError(t, err) - } - err := writer.Flush() - require.NoError(t, err) - + setupProjectHistory := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectHistory { projectHistory, err := client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: buffer.Bytes(), + StorageSource: data, }) require.NoError(t, err) require.Eventually(t, func() bool { @@ -71,9 +56,9 @@ func TestWorkspaceHistory(t *testing.T) { history, err := server.Client.ListWorkspaceHistory(context.Background(), "", workspace.Name) require.NoError(t, err) require.Len(t, history, 0) - projectVersion := setupProjectHistory(t, server.Client, user, project, map[string]string{ - "example": "file", - }) + data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + require.NoError(t, err) + projectVersion := setupProjectHistory(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectHistoryID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, @@ -92,9 +77,9 @@ func TestWorkspaceHistory(t *testing.T) { project, workspace := setupProjectAndWorkspace(t, server.Client, user) _, err := server.Client.WorkspaceHistory(context.Background(), "", workspace.Name, "") require.Error(t, err) - projectHistory := setupProjectHistory(t, server.Client, user, project, map[string]string{ - "some": "file", - }) + data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + require.NoError(t, err) + projectHistory := setupProjectHistory(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectHistoryID: projectHistory.ID, Transition: database.WorkspaceTransitionCreate, @@ -110,10 +95,10 @@ func TestWorkspaceHistory(t *testing.T) { user := server.RandomInitialUser(t) _ = server.AddProvisionerd(t) project, workspace := setupProjectAndWorkspace(t, server.Client, user) - projectHistory := setupProjectHistory(t, server.Client, user, project, map[string]string{ - "main.tf": `resource "null_resource" "example" {}`, - }) - _, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + require.NoError(t, err) + projectHistory := setupProjectHistory(t, server.Client, user, project, data) + _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectHistoryID: projectHistory.ID, Transition: database.WorkspaceTransitionCreate, }) @@ -135,11 +120,11 @@ func TestWorkspaceHistory(t *testing.T) { user := server.RandomInitialUser(t) _ = server.AddProvisionerd(t) project, workspace := setupProjectAndWorkspace(t, server.Client, user) - projectHistory := setupProjectHistory(t, server.Client, user, project, map[string]string{ - "some": "content", - }) + data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + require.NoError(t, err) + projectHistory := setupProjectHistory(t, server.Client, user, project, data) - _, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectHistoryID: projectHistory.ID, Transition: database.WorkspaceTransitionCreate, }) diff --git a/coderd/workspacehistorylogs_test.go b/coderd/workspacehistorylogs_test.go index bbaa1e6be6e9d..310cd6215307b 100644 --- a/coderd/workspacehistorylogs_test.go +++ b/coderd/workspacehistorylogs_test.go @@ -1,8 +1,6 @@ package coderd_test import ( - "archive/tar" - "bytes" "context" "testing" "time" @@ -13,6 +11,8 @@ import ( "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/codersdk" "github.com/coder/coder/database" + "github.com/coder/coder/provisioner/echo" + "github.com/coder/coder/provisionersdk/proto" ) func TestWorkspaceHistoryLogs(t *testing.T) { @@ -21,7 +21,7 @@ func TestWorkspaceHistoryLogs(t *testing.T) { setupProjectAndWorkspace := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest) (coderd.Project, coderd.Workspace) { project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ @@ -32,24 +32,10 @@ func TestWorkspaceHistoryLogs(t *testing.T) { return project, workspace } - setupProjectHistory := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, files map[string]string) coderd.ProjectHistory { - var buffer bytes.Buffer - writer := tar.NewWriter(&buffer) - for path, content := range files { - err := writer.WriteHeader(&tar.Header{ - Name: path, - Size: int64(len(content)), - }) - require.NoError(t, err) - _, err = writer.Write([]byte(content)) - require.NoError(t, err) - } - err := writer.Flush() - require.NoError(t, err) - + setupProjectHistory := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectHistory { projectHistory, err := client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: buffer.Bytes(), + StorageSource: data, }) require.NoError(t, err) require.Eventually(t, func() bool { @@ -64,9 +50,19 @@ func TestWorkspaceHistoryLogs(t *testing.T) { user := server.RandomInitialUser(t) _ = server.AddProvisionerd(t) project, workspace := setupProjectAndWorkspace(t, server.Client, user) - projectHistory := setupProjectHistory(t, server.Client, user, project, map[string]string{ - "main.tf": `resource "null_resource" "test" {}`, - }) + data, err := echo.Tar(echo.ParseComplete, []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Log{ + Log: &proto.Log{ + Output: "test", + }, + }, + }, { + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}) + require.NoError(t, err) + projectHistory := setupProjectHistory(t, server.Client, user, project, data) workspaceHistory, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectHistoryID: projectHistory.ID, diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 2ff351813694a..2ee817899ca64 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -28,7 +28,7 @@ func TestWorkspaces(t *testing.T) { setupProjectAndWorkspace := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest) (coderd.Project, coderd.Workspace) { project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ @@ -55,7 +55,7 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspaces, err := server.Client.WorkspacesByProject(context.Background(), user.Organization, project.Name) @@ -79,7 +79,7 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ @@ -106,7 +106,7 @@ func TestWorkspaces(t *testing.T) { initial := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), initial.Organization, coderd.CreateProjectRequest{ Name: "banana", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ diff --git a/codersdk/projects_test.go b/codersdk/projects_test.go index 9ccc211e2d425..0645438c249f9 100644 --- a/codersdk/projects_test.go +++ b/codersdk/projects_test.go @@ -46,7 +46,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) }) @@ -64,7 +64,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.Project(context.Background(), user.Organization, "bananas") @@ -84,7 +84,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.ListProjectHistory(context.Background(), user.Organization, project.Name) @@ -107,7 +107,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) var buffer bytes.Buffer @@ -135,7 +135,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) params, err := server.Client.ProjectParameters(context.Background(), user.Organization, project.Name) @@ -150,7 +150,7 @@ func TestProjects(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) param, err := server.Client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ diff --git a/codersdk/workspaces_test.go b/codersdk/workspaces_test.go index 4b5e64d346d25..b030b3741450f 100644 --- a/codersdk/workspaces_test.go +++ b/codersdk/workspaces_test.go @@ -34,11 +34,11 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wooow", + Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) @@ -52,11 +52,11 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) _, err = server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wooow", + Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) @@ -84,11 +84,11 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wooow", + Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) @@ -109,11 +109,11 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wooow", + Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) @@ -134,11 +134,11 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wooow", + Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) @@ -152,11 +152,11 @@ func TestWorkspaces(t *testing.T) { user := server.RandomInitialUser(t) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", - Provisioner: database.ProvisionerTypeTerraform, + Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wooow", + Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) diff --git a/database/dump.sql b/database/dump.sql index 2aa3ae2792ace..7f174528af7b2 100644 --- a/database/dump.sql +++ b/database/dump.sql @@ -52,8 +52,8 @@ CREATE TYPE provisioner_job_type AS ENUM ( ); CREATE TYPE provisioner_type AS ENUM ( - 'terraform', - 'cdr-basic' + 'echo', + 'terraform' ); CREATE TYPE userstatus AS ENUM ( diff --git a/database/migrations/000002_projects.up.sql b/database/migrations/000002_projects.up.sql index 62b7468558bb3..0149ec8033f39 100644 --- a/database/migrations/000002_projects.up.sql +++ b/database/migrations/000002_projects.up.sql @@ -1,4 +1,4 @@ -CREATE TYPE provisioner_type AS ENUM ('terraform', 'cdr-basic'); +CREATE TYPE provisioner_type AS ENUM ('echo', 'terraform'); -- Project defines infrastructure that your software project -- requires for development. diff --git a/database/models.go b/database/models.go index dd7005a6c1dfa..f0c0458e5cd58 100644 --- a/database/models.go +++ b/database/models.go @@ -191,8 +191,8 @@ func (e *ProvisionerJobType) Scan(src interface{}) error { type ProvisionerType string const ( + ProvisionerTypeEcho ProvisionerType = "echo" ProvisionerTypeTerraform ProvisionerType = "terraform" - ProvisionerTypeCdrBasic ProvisionerType = "cdr-basic" ) func (e *ProvisionerType) Scan(src interface{}) error { diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go new file mode 100644 index 0000000000000..12172b6c5864e --- /dev/null +++ b/provisioner/echo/serve.go @@ -0,0 +1,138 @@ +package echo + +import ( + "archive/tar" + "bytes" + "context" + "fmt" + "os" + "path/filepath" + + "golang.org/x/xerrors" + + protobuf "google.golang.org/protobuf/proto" + + "github.com/coder/coder/provisionersdk" + "github.com/coder/coder/provisionersdk/proto" +) + +var ( + // ParseComplete is a helper to indicate an empty parse completion. + ParseComplete = []*proto.Parse_Response{{ + Type: &proto.Parse_Response_Complete{ + Complete: &proto.Parse_Complete{}, + }, + }} + // ProvisionComplete is a helper to indicate an empty provision completion. + ProvisionComplete = []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }} +) + +// Serve starts the echo provisioner. +func Serve(ctx context.Context, options *provisionersdk.ServeOptions) error { + return provisionersdk.Serve(ctx, &echo{}, options) +} + +// The echo provisioner serves as a dummy provisioner primarily +// used for testing. It echos responses from JSON files in the +// format %d.protobuf. It's used for testing. +type echo struct { +} + +// Parse reads requests from the provided directory to stream responses. +func (*echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error { + for index := 0; ; index++ { + path := filepath.Join(request.Directory, fmt.Sprintf("%d.parse.protobuf", index)) + _, err := os.Stat(path) + if err != nil { + break + } + data, err := os.ReadFile(path) + if err != nil { + return xerrors.Errorf("read file %q: %w", path, err) + } + var response proto.Parse_Response + err = protobuf.Unmarshal(data, &response) + if err != nil { + return xerrors.Errorf("unmarshal: %w", err) + } + err = stream.Send(&response) + if err != nil { + return err + } + } + return nil +} + +// Provision reads requests from the provided directory to stream responses. +func (*echo) Provision(request *proto.Provision_Request, stream proto.DRPCProvisioner_ProvisionStream) error { + for index := 0; ; index++ { + path := filepath.Join(request.Directory, fmt.Sprintf("%d.provision.protobuf", index)) + _, err := os.Stat(path) + if err != nil { + break + } + data, err := os.ReadFile(path) + if err != nil { + return xerrors.Errorf("read file %q: %w", path, err) + } + var response proto.Provision_Response + err = protobuf.Unmarshal(data, &response) + if err != nil { + return xerrors.Errorf("unmarshal: %w", err) + } + err = stream.Send(&response) + if err != nil { + return err + } + } + return nil +} + +// Tar returns a tar archive of responses to provisioner operations. +func Tar(parseResponses []*proto.Parse_Response, provisionResponses []*proto.Provision_Response) ([]byte, error) { + var buffer bytes.Buffer + writer := tar.NewWriter(&buffer) + for index, response := range parseResponses { + data, err := protobuf.Marshal(response) + if err != nil { + return nil, err + } + err = writer.WriteHeader(&tar.Header{ + Name: fmt.Sprintf("%d.parse.protobuf", index), + Size: int64(len(data)), + }) + if err != nil { + return nil, err + } + _, err = writer.Write(data) + if err != nil { + return nil, err + } + } + for index, response := range provisionResponses { + data, err := protobuf.Marshal(response) + if err != nil { + return nil, err + } + err = writer.WriteHeader(&tar.Header{ + Name: fmt.Sprintf("%d.provision.protobuf", index), + Size: int64(len(data)), + }) + if err != nil { + return nil, err + } + _, err = writer.Write(data) + if err != nil { + return nil, err + } + } + err := writer.Flush() + if err != nil { + return nil, err + } + return buffer.Bytes(), nil +} diff --git a/provisioner/echo/serve_test.go b/provisioner/echo/serve_test.go new file mode 100644 index 0000000000000..ce8a1e078bad1 --- /dev/null +++ b/provisioner/echo/serve_test.go @@ -0,0 +1,123 @@ +package echo_test + +import ( + "archive/tar" + "bytes" + "context" + "io" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/provisioner/echo" + "github.com/coder/coder/provisionersdk" + "github.com/coder/coder/provisionersdk/proto" +) + +func TestEcho(t *testing.T) { + t.Parallel() + + // Create an in-memory provisioner to communicate with. + client, server := provisionersdk.TransportPipe() + ctx, cancelFunc := context.WithCancel(context.Background()) + t.Cleanup(func() { + _ = client.Close() + _ = server.Close() + cancelFunc() + }) + go func() { + err := echo.Serve(ctx, &provisionersdk.ServeOptions{ + Listener: server, + }) + require.NoError(t, err) + }() + api := proto.NewDRPCProvisionerClient(provisionersdk.Conn(client)) + + t.Run("Parse", func(t *testing.T) { + t.Parallel() + + responses := []*proto.Parse_Response{{ + Type: &proto.Parse_Response_Log{ + Log: &proto.Log{ + Output: "log-output", + }, + }, + }, { + Type: &proto.Parse_Response_Complete{ + Complete: &proto.Parse_Complete{ + ParameterSchemas: []*proto.ParameterSchema{{ + Name: "parameter-schema", + }}, + }, + }, + }} + data, err := echo.Tar(responses, nil) + require.NoError(t, err) + client, err := api.Parse(ctx, &proto.Parse_Request{ + Directory: unpackTar(t, data), + }) + require.NoError(t, err) + log, err := client.Recv() + require.NoError(t, err) + require.Equal(t, responses[0].GetLog().Output, log.GetLog().Output) + complete, err := client.Recv() + require.NoError(t, err) + require.Equal(t, responses[1].GetComplete().ParameterSchemas[0].Name, + complete.GetComplete().ParameterSchemas[0].Name) + }) + + t.Run("Provision", func(t *testing.T) { + t.Parallel() + + responses := []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Log{ + Log: &proto.Log{ + Output: "log-output", + }, + }, + }, { + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "resource", + }}, + }, + }, + }} + data, err := echo.Tar(nil, responses) + require.NoError(t, err) + client, err := api.Provision(ctx, &proto.Provision_Request{ + Directory: unpackTar(t, data), + }) + require.NoError(t, err) + log, err := client.Recv() + require.NoError(t, err) + require.Equal(t, responses[0].GetLog().Output, log.GetLog().Output) + complete, err := client.Recv() + require.NoError(t, err) + require.Equal(t, responses[1].GetComplete().Resources[0].Name, + complete.GetComplete().Resources[0].Name) + }) +} + +func unpackTar(t *testing.T, data []byte) string { + directory := t.TempDir() + reader := tar.NewReader(bytes.NewReader(data)) + for { + header, err := reader.Next() + if err != nil { + break + } + // #nosec + path := filepath.Join(directory, header.Name) + file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0600) + require.NoError(t, err) + _, err = io.CopyN(file, reader, 1<<20) + require.ErrorIs(t, err, io.EOF) + err = file.Close() + require.NoError(t, err) + } + return directory +} 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