statamic / cms

The core Laravel CMS Composer package
https://statamic.com
Other
3.7k stars 508 forks source link

Cloudflare R2 disk setup with S3 resulting in "unable to copy file from source to cache" error #7193

Closed el-schneider closed 9 months ago

el-schneider commented 1 year ago

Bug description

Assets are not being shown in filebrowser, but files can be uploaded and show in the respective Cloudflare R2 Bucket

Issue might be related to https://github.com/statamic/cms/pull/5996

grafik

How to reproduce

Here is a demo repo: https://github.com/el-schneider/statamic-r2

Logs

[2022-12-10 12:17:11] local.ERROR: Unable to copy file from source://aaf123d29f3f6403ee9ab5a5d21fe733-3.jpg to cache://aaf123d29f3f6403ee9ab5a5d21fe733-3.jpg {"userId":"bd612549-77ed-486b-86cf-579d1990ef4c","exception":"[object] (League\\Flysystem\\UnableToCopyFile(code: 0): Unable to copy file from source://aaf123d29f3f6403ee9ab5a5d21fe733-3.jpg to cache://aaf123d29f3f6403ee9ab5a5d21fe733-3.jpg at /Users/jonas/dev/playground/statamic-r2/vendor/league/flysystem/src/UnableToCopyFile.php:37)
[stacktrace]
#0 /Users/jonas/dev/playground/statamic-r2/vendor/league/flysystem/src/MountManager.php(371): League\\Flysystem\\UnableToCopyFile::fromLocationTo('source://aaf123...', 'cache://aaf123d...', Object(League\\Flysystem\\UnableToRetrieveMetadata))
#1 /Users/jonas/dev/playground/statamic-r2/vendor/league/flysystem/src/MountManager.php(245): League\\Flysystem\\MountManager->copyAcrossFilesystem(NULL, Object(League\\Flysystem\\Filesystem), 'aaf123d29f3f640...', Object(League\\Flysystem\\Filesystem), 'aaf123d29f3f640...', 'source://aaf123...', 'cache://aaf123d...')
#2 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Imaging/Attributes.php(20): League\\Flysystem\\MountManager->copy('source://aaf123...', 'cache://aaf123d...')
#3 /Users/jonas/dev/playground/statamic-r2/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(338): Statamic\\Imaging\\Attributes->from(Object(League\\Flysystem\\Filesystem), 'aaf123d29f3f640...')
#4 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Attributes.php(78): Illuminate\\Support\\Facades\\Facade::__callStatic('from', Array)
#5 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Attributes.php(43): Statamic\\Assets\\Attributes->getImageAttributes()
#6 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Asset.php(264): Statamic\\Assets\\Attributes->get()
#7 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Asset.php(238): Statamic\\Assets\\Asset->generateMeta()
#8 /Users/jonas/dev/playground/statamic-r2/vendor/laravel/framework/src/Illuminate/Cache/Repository.php(426): Statamic\\Assets\\Asset->Statamic\\Assets\\{closure}()
#9 /Users/jonas/dev/playground/statamic-r2/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php(418): Illuminate\\Cache\\Repository->rememberForever('asset-meta-asse...', Object(Closure))
#10 /Users/jonas/dev/playground/statamic-r2/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(338): Illuminate\\Cache\\CacheManager->__call('rememberForever', Array)
#11 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Asset.php(241): Illuminate\\Support\\Facades\\Facade::__callStatic('rememberForever', Array)
#12 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Asset.php(246): Statamic\\Assets\\Asset->meta()
#13 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Asset.php(215): Statamic\\Assets\\Asset->metaValue('size')
#14 /Users/jonas/dev/playground/statamic-r2/vendor/statamic/cms/src/Assets/Asset.php(823): Statamic\\Assets\\Asset->meta('size')

Environment

Environment
Application Name: Statamic
Laravel Version: 9.43.0
PHP Version: 8.1.13
Composer Version: 2.4.4
Environment: local
Debug Mode: ENABLED
URL: statamic-r2.test
Maintenance Mode: OFF

Cache
Config: CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: statamic
Database: mysql
Logs: stack / single
Mail: smtp
Queue: sync
Session: file

Statamic
Addons: 0
Antlers: regex
Version: 3.3.60 Solo

Installation

Fresh statamic/statamic site via CLI

Antlers Parser

None

Additional details

No response

el-schneider commented 1 year ago

For what it's worth I'm getting the same error when trying to configure https://bunny.net/ storage through league/flysystem-ftp. Uploads are also working.

duncanmcclean commented 1 year ago

What does your config/filesystems.php file look like? Also, is your Stache watcher enabled/disabled?

el-schneider commented 1 year ago

Like in the demo repo above. And I tried both stache watcher on and off. In the meantime I tested it also with DO Spaces (working) and KeyCDN (through FTP), also working.

stuartcusackie commented 1 year ago

I get errors like these using DO Spaces, but only on some images. I have quite a few in my error logs. If I enable the glide cache then these errors break the front-end.

treeofhands commented 1 year ago

Did you ever work this out? Having the same issue.

stuartcusackie commented 1 year ago

This makes no sense to me but it seems like the problem has nothing to do with remote storage. Here's what I think is happening: Image gets manipulated from remote source and placed in local storage. Then the glide cache attempts to copy the local storage file to the public folder. This is where the error occurs. COPY FROM: /storage/statamic/glide/containers/XXX.jpg COPY TO: /public/img/containers/XXX.jpg

I went to the 'storage' folder and manually copied the problematic image and its folder to the 'public' folder. The error went away as the file no longer needed to be copied. So why is the League\ Flysystem\ UnableToCopyFile error being thrown? I can't see any reason why it can't perform a simple copy of the folder and file.

This was all tested on my local Windows machine by the way. Also, it seemed to be the very last image on the page, all preceding images were fine.

treeofhands commented 1 year ago

just to add to the mystery, I don't have any issues uploading PDFs (with R2) and switching AWS S3 doesn't cause any issues with Glide it seems

jbrhel commented 1 year ago

@treeofhands I just had a similar problem with my S3 disk setup after upgrading from laravel 8 to 9. Updating policie on S3 helped to me. Specifically, adding the s3:GetObjectAcl action. My functional policy looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::my-bucket.foo"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:*Object",
                "s3:PutObjectAcl",
                "s3:GetObjectAcl"
            ],
            "Resource": "arn:aws:s3:::my-bucket.foo/*"
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::my-bucket.foo/*"
        }
    ]
}
JellyBool commented 1 year ago

I have this same issue when using Cloudflare R2 (or AWS s3) as a assets container. Any one got a fix for the problem?

asantibanez commented 1 year ago

Good afternoon everyone

Went down the rabbit hole on this one. Like @jbrhel describes, the GetObjectAcl permission needs to be present. To find out, I followed the path of calls until MountManager class copyAcrossFilesystem is called. I caught the raw error manually and this is the error message before the custom UnableToCopyFile exception is thrown.

image
rezaplus commented 1 year ago

I noticed that when I comment and uncomment this line in MountManager within the League\Flysystem package, the problem disappears, and everything works well. Does anyone know why this is happening?


throw UnableToCopyFile::fromLocationTo($source, $destination, $exception);
edalzell commented 11 months ago

I'm getting this on a DO Space now, as well.

Mine seems to be a missing file that's being requested (from where????):

image
tb-b commented 11 months ago

Can confirm this is now happening on R2 with the latest Statamic. Strangely enough it was working fine a few weeks ago. Unable to copy file from source://bg_img.jpg to cache://bg_img.jpg

tb-b commented 11 months ago

It seems the $visibility is causing this:

In copyAcrossFilesystem line $visibility = $visibility ?? $sourceFilesystem->visibility($sourcePath);

if I hardcode $visibility = 'public' or $visibility = 'private', the upload goes through I'm uploading via Statamic with "league/flysystem-aws-s3-v3": "^3.16"

My config in filesystems.php:

        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
            'visibility' => 'public', // https://statamic.dev/assets#visibility
            'throw' => false,
        ],
JellyBool commented 11 months ago

@tb-b Your filesystems.php config works? or you need to change the source code copyAcrossFilesystem?

tb-b commented 11 months ago

To avoid the error above I have to change the source code of copyAcrossFilesystems as the filesystem.php seems to be ignoring the 'visibility' when it reaches copyAcrossFilesystems

JellyBool commented 11 months ago

Thanks! @tb-b

edalzell commented 11 months ago

I'm getting this on a DO Space now, as well.

Mine seems to be a missing file that's being requested (from where????): image

I had a root set to / which doesn't work, apparently. Removing that key solved my problem.

wch-karol commented 10 months ago

I think that it should be fixed immediately, because docs allows use root key. https://statamic.dev/tips/digital-ocean-spaces-for-asset-container image


Edit: I've solved problem by using scoped disk. https://laravel.com/docs/10.x/filesystem#scoped-and-read-only-filesystems

mbale commented 10 months ago

Long time no php dev here.

I've had the same issue with R2. I had to patch vendor/statamic/cms/src/Imaging/Attributes.php to pass the config to the MountManager constructor, otherwise the config (from config/filesystems) will be empty and the copyAcrossFilesystem will call visibility method on AwsS3V3Adapter which is unsupported on R2.

This smells to be a Statamic bug. Given the missing conf passing to MountManager, s3 adapter will fall back to ACL mode which fails with other s3 providers. (I guess DO spaces as well)

CleanShot 2023-11-19 at 11 10 28

CleanShot 2023-11-19 at 11 00 04

CleanShot 2023-11-19 at 11 08 08

Now it's working.

CleanShot 2023-11-19 at 11 06 54

edalzell commented 10 months ago

Ya that should be a PR

mbale commented 10 months ago

Ya that should be a PR

Will do

jasonvarga commented 9 months ago

Thank you for all the debugging everyone has done in this issue. 🥰