feat: Add echo provisioner (#162)

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.
This commit is contained in:
Kyle Carberry
2022-02-04 16:51:54 -06:00
committed by GitHub
parent 65de6eef9c
commit 682238d384
15 changed files with 366 additions and 129 deletions
+9 -11
View File
@@ -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(),
})
+12 -13
View File
@@ -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{
+1 -1
View File
@@ -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.
+20 -22
View File
@@ -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 {
+1 -1
View File
@@ -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))
+18 -33
View File
@@ -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,
})
+18 -22
View File
@@ -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,
+4 -4
View File
@@ -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{
+6 -6
View File
@@ -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{
+12 -12
View File
@@ -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)
+2 -2
View File
@@ -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 (
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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 {
+138
View File
@@ -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
}
+123
View File
@@ -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
}