From 6cfe72cd90ba16090170ca0cc0383e74129f7fc0 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 18 Jul 2024 16:01:33 +0200 Subject: [PATCH 1/3] Add read-only mode for extension aware workspace filer By default, construct a read/write instance. If constructed in read-only mode, the underlying filer is wrapped in a readahead cache. --- .../workspace_files_extensions_client.go | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/libs/filer/workspace_files_extensions_client.go b/libs/filer/workspace_files_extensions_client.go index d5d0ce554e..a60ffe3698 100644 --- a/libs/filer/workspace_files_extensions_client.go +++ b/libs/filer/workspace_files_extensions_client.go @@ -18,8 +18,9 @@ import ( type workspaceFilesExtensionsClient struct { workspaceClient *databricks.WorkspaceClient - wsfs Filer - root string + wsfs Filer + root string + readonly bool } var extensionsToLanguages = map[string]workspace.Language{ @@ -143,6 +144,14 @@ func (e DuplicatePathError) Error() string { return fmt.Sprintf("failed to read files from the workspace file system. Duplicate paths encountered. Both %s at %s and %s at %s resolve to the same name %s. Changing the name of one of these objects will resolve this issue", e.oi1.ObjectType, e.oi1.Path, e.oi2.ObjectType, e.oi2.Path, e.commonName) } +type ReadonlyError struct { + op string +} + +func (e ReadonlyError) Error() string { + return fmt.Sprintf("failed to %s: filer is in read-only mode", e.op) +} + // This is a filer for the workspace file system that allows you to pretend the // workspace file system is a traditional file system. It allows you to list, read, write, // delete, and stat notebooks (and files in general) in the workspace, using their paths @@ -157,17 +166,30 @@ func (e DuplicatePathError) Error() string { // errors for namespace clashes (e.g. a file and a notebook or a directory and a notebook). // Thus users of these methods should be careful to avoid such clashes. func NewWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string) (Filer, error) { + return newWorkspaceFilesExtensionsClient(w, root, false) +} + +func NewReadOnlyWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string) (Filer, error) { + return newWorkspaceFilesExtensionsClient(w, root, true) +} + +func newWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string, readonly bool) (Filer, error) { filer, err := NewWorkspaceFilesClient(w, root) if err != nil { return nil, err } - cache := newWorkspaceFilesReadaheadCache(filer) + if readonly { + // Wrap in a readahead cache to avoid making unnecessary calls to the workspace. + filer = newWorkspaceFilesReadaheadCache(filer) + } + return &workspaceFilesExtensionsClient{ workspaceClient: w, - wsfs: cache, - root: root, + wsfs: filer, + root: root, + readonly: readonly, }, nil } @@ -214,6 +236,10 @@ func (w *workspaceFilesExtensionsClient) ReadDir(ctx context.Context, name strin // (e.g. a file and a notebook or a directory and a notebook). Thus users of this // method should be careful to avoid such clashes. func (w *workspaceFilesExtensionsClient) Write(ctx context.Context, name string, reader io.Reader, mode ...WriteMode) error { + if w.readonly { + return ReadonlyError{"write"} + } + return w.wsfs.Write(ctx, name, reader, mode...) } @@ -247,6 +273,10 @@ func (w *workspaceFilesExtensionsClient) Read(ctx context.Context, name string) // Try to delete the file as a regular file. If the file is not found, try to delete it as a notebook. func (w *workspaceFilesExtensionsClient) Delete(ctx context.Context, name string, mode ...DeleteMode) error { + if w.readonly { + return ReadonlyError{"delete"} + } + err := w.wsfs.Delete(ctx, name, mode...) // If the file is not found, it might be a notebook. @@ -293,5 +323,9 @@ func (w *workspaceFilesExtensionsClient) Stat(ctx context.Context, name string) // (e.g. a file and a notebook or a directory and a notebook). Thus users of this // method should be careful to avoid such clashes. func (w *workspaceFilesExtensionsClient) Mkdir(ctx context.Context, name string) error { + if w.readonly { + return ReadonlyError{"mkdir"} + } + return w.wsfs.Mkdir(ctx, name) } From 4dce342f22ac6d5b3d3ccefa6462aa574cfd47f8 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 18 Jul 2024 16:05:12 +0200 Subject: [PATCH 2/3] Construct read-only filer on WSFS --- bundle/config/mutator/configure_wsfs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundle/config/mutator/configure_wsfs.go b/bundle/config/mutator/configure_wsfs.go index 17af4828fc..c7b764f000 100644 --- a/bundle/config/mutator/configure_wsfs.go +++ b/bundle/config/mutator/configure_wsfs.go @@ -39,7 +39,7 @@ func (m *configureWSFS) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagno // If so, swap out vfs.Path instance of the sync root with one that // makes all Workspace File System interactions extension aware. p, err := vfs.NewFilerPath(ctx, root, func(path string) (filer.Filer, error) { - return filer.NewWorkspaceFilesExtensionsClient(b.WorkspaceClient(), path) + return filer.NewReadOnlyWorkspaceFilesExtensionsClient(b.WorkspaceClient(), path) }) if err != nil { return diag.FromErr(err) From d959e00071c59dedf140b7e339596507e8abb95f Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 18 Jul 2024 16:06:40 +0200 Subject: [PATCH 3/3] Capitalize --- libs/filer/workspace_files_extensions_client.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/filer/workspace_files_extensions_client.go b/libs/filer/workspace_files_extensions_client.go index a60ffe3698..844e736b58 100644 --- a/libs/filer/workspace_files_extensions_client.go +++ b/libs/filer/workspace_files_extensions_client.go @@ -144,11 +144,11 @@ func (e DuplicatePathError) Error() string { return fmt.Sprintf("failed to read files from the workspace file system. Duplicate paths encountered. Both %s at %s and %s at %s resolve to the same name %s. Changing the name of one of these objects will resolve this issue", e.oi1.ObjectType, e.oi1.Path, e.oi2.ObjectType, e.oi2.Path, e.commonName) } -type ReadonlyError struct { +type ReadOnlyError struct { op string } -func (e ReadonlyError) Error() string { +func (e ReadOnlyError) Error() string { return fmt.Sprintf("failed to %s: filer is in read-only mode", e.op) } @@ -237,7 +237,7 @@ func (w *workspaceFilesExtensionsClient) ReadDir(ctx context.Context, name strin // method should be careful to avoid such clashes. func (w *workspaceFilesExtensionsClient) Write(ctx context.Context, name string, reader io.Reader, mode ...WriteMode) error { if w.readonly { - return ReadonlyError{"write"} + return ReadOnlyError{"write"} } return w.wsfs.Write(ctx, name, reader, mode...) @@ -274,7 +274,7 @@ func (w *workspaceFilesExtensionsClient) Read(ctx context.Context, name string) // Try to delete the file as a regular file. If the file is not found, try to delete it as a notebook. func (w *workspaceFilesExtensionsClient) Delete(ctx context.Context, name string, mode ...DeleteMode) error { if w.readonly { - return ReadonlyError{"delete"} + return ReadOnlyError{"delete"} } err := w.wsfs.Delete(ctx, name, mode...) @@ -324,7 +324,7 @@ func (w *workspaceFilesExtensionsClient) Stat(ctx context.Context, name string) // method should be careful to avoid such clashes. func (w *workspaceFilesExtensionsClient) Mkdir(ctx context.Context, name string) error { if w.readonly { - return ReadonlyError{"mkdir"} + return ReadOnlyError{"mkdir"} } return w.wsfs.Mkdir(ctx, name)