diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 55e62561af..4aa968468e 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -1,6 +1,7 @@ package coderdtest import ( + "archive/tar" "bytes" "context" "crypto" @@ -52,6 +53,7 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" "cdr.dev/slog/sloggers/slogtest" + "github.com/coder/coder/v2/archive" "github.com/coder/coder/v2/coderd/files" "github.com/coder/quartz" @@ -886,14 +888,22 @@ func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationI return other, user } -// CreateTemplateVersion creates a template import provisioner job -// with the responses provided. It uses the "echo" provisioner for compatibility -// with testing. -func CreateTemplateVersion(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses, mutators ...func(*codersdk.CreateTemplateVersionRequest)) codersdk.TemplateVersion { +func CreateTemplateVersionMimeType(t testing.TB, client *codersdk.Client, mimeType string, organizationID uuid.UUID, res *echo.Responses, mutators ...func(*codersdk.CreateTemplateVersionRequest)) codersdk.TemplateVersion { t.Helper() data, err := echo.TarWithOptions(context.Background(), client.Logger(), res) require.NoError(t, err) - file, err := client.Upload(context.Background(), codersdk.ContentTypeTar, bytes.NewReader(data)) + + switch mimeType { + case codersdk.ContentTypeTar: + // do nothing + case codersdk.ContentTypeZip: + data, err = archive.CreateZipFromTar(tar.NewReader(bytes.NewBuffer(data)), int64(len(data))) + require.NoError(t, err, "creating zip") + default: + t.Fatal("unexpected mime type", mimeType) + } + + file, err := client.Upload(context.Background(), mimeType, bytes.NewReader(data)) require.NoError(t, err) req := codersdk.CreateTemplateVersionRequest{ @@ -910,6 +920,13 @@ func CreateTemplateVersion(t testing.TB, client *codersdk.Client, organizationID return templateVersion } +// CreateTemplateVersion creates a template import provisioner job +// with the responses provided. It uses the "echo" provisioner for compatibility +// with testing. +func CreateTemplateVersion(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses, mutators ...func(*codersdk.CreateTemplateVersionRequest)) codersdk.TemplateVersion { + return CreateTemplateVersionMimeType(t, client, codersdk.ContentTypeTar, organizationID, res, mutators...) +} + // CreateWorkspaceBuild creates a workspace build for the given workspace and transition. func CreateWorkspaceBuild( t *testing.T, diff --git a/coderd/coderdtest/dynamicparameters.go b/coderd/coderdtest/dynamicparameters.go index 5d03f9fde9..28e0188556 100644 --- a/coderd/coderdtest/dynamicparameters.go +++ b/coderd/coderdtest/dynamicparameters.go @@ -20,6 +20,9 @@ type DynamicParameterTemplateParams struct { Plan json.RawMessage ModulesArchive []byte + // Uses a zip archive instead of a tar + Zip bool + // StaticParams is used if the provisioner daemon version does not support dynamic parameters. StaticParams []*proto.RichParameter @@ -45,7 +48,11 @@ func DynamicParameterTemplate(t *testing.T, client *codersdk.Client, org uuid.UU }, }} - version := CreateTemplateVersion(t, client, org, files, func(request *codersdk.CreateTemplateVersionRequest) { + mime := codersdk.ContentTypeTar + if args.Zip { + mime = codersdk.ContentTypeZip + } + version := CreateTemplateVersionMimeType(t, client, mime, org, files, func(request *codersdk.CreateTemplateVersionRequest) { if args.TemplateID != uuid.Nil { request.TemplateID = args.TemplateID } diff --git a/coderd/files/cache.go b/coderd/files/cache.go index 159f1b8aee..d9e54a66e1 100644 --- a/coderd/files/cache.go +++ b/coderd/files/cache.go @@ -303,10 +303,21 @@ func fetch(store database.Store, fileID uuid.UUID) (CacheEntryValue, error) { return CacheEntryValue{}, xerrors.Errorf("failed to read file from database: %w", err) } - content := bytes.NewBuffer(file.Data) + var files fs.FS + switch file.Mimetype { + case "application/zip", "application/x-zip-compressed": + files, err = archivefs.FromZipReader(bytes.NewReader(file.Data), int64(len(file.Data))) + if err != nil { + return CacheEntryValue{}, xerrors.Errorf("failed to read zip file: %w", err) + } + default: + // Assume '"application/x-tar"' as the default mimetype. + files = archivefs.FromTarReader(bytes.NewBuffer(file.Data)) + } + return CacheEntryValue{ Object: file.RBACObject(), - FS: archivefs.FromTarReader(content), + FS: files, Size: int64(len(file.Data)), }, nil } diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index 5d417f0dfb..1030536f21 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -294,7 +294,9 @@ func TestCreateUserWorkspace(t *testing.T) { OrganizationID: first.OrganizationID, }) - template, _ := coderdtest.DynamicParameterTemplate(t, admin, first.OrganizationID, coderdtest.DynamicParameterTemplateParams{}) + template, _ := coderdtest.DynamicParameterTemplate(t, admin, first.OrganizationID, coderdtest.DynamicParameterTemplateParams{ + Zip: true, + }) ctx = testutil.Context(t, testutil.WaitLong)