mirror of
https://github.com/coder/coder.git
synced 2026-09-21 20:51:01 +08:00
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:
@@ -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(),
|
||||
})
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Generated
+2
-2
@@ -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,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
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user