craftcms / nitro

Speedy local dev environment for @craftcms.
https://getnitro.sh
MIT License
178 stars 24 forks source link

[2.0.0-beta.7] WSL on Windows write permissions issue with ./craft migrate/create #264

Closed jamesmacwhite closed 3 years ago

jamesmacwhite commented 3 years ago

Description

I don't think this is specific to Nitro, more likely the Docker layer as I know this happens on Docker generally as well. WSL in particularly struggles with the permissions setup due to the Docker container using www-data. This makes commands that perform write actions like ./craft migrate/create fail.

/app $ ./craft migrate/create test
Yii Migration Tool (based on Yii v2.0.40)

Create new migration '/app/migrations/m210302_111825_test.php'? (yes|no) [no]:yes
PHP Warning 'yii\base\ErrorException' with message 'file_put_contents(/app/migrations/m210302_111825_test.php): failed to open stream: Permission denied'

in /app/vendor/craftcms/cms/src/helpers/FileHelper.php:377

Stack trace:
#0 {main}

This happens with nitro ssh or nitro craft. The only solution I know of related to Docker, is using docker exec with the user context.

docker exec --user 1000:1000 -it container_name /bin/sh

Then running ./craft migrate/create, which will work because of user context being different.

I'm not sure there is a easy solution to this, but just for info.

jasonmccallister commented 3 years ago

@jamesmacwhite can you try running php craft migrate/create test instead of using the ./ syntax?

jamesmacwhite commented 3 years ago

Same with using php command format, trying with nitro ssh. Ultimately this a docker level issue I believe. I'm not sure what the permissions situation is like on real unix i.e. macOS and Linux hosts, but it's mostly down the user context in the container I believe, having --user 1000:1000 when using docker exec works. However for most operations you don't need to set this.

jasonmccallister commented 3 years ago

Can you perform an ls -la on the WSL2 terminal and with the nitro ssh command and provide the output here?

jamesmacwhite commented 3 years ago
/app $ ls -la
total 1240
drwxr-xr-x   20 1000     1000          4096 Mar  1 15:12 .
drwxr-xr-x    1 root     root          4096 Mar  2 09:31 ..
-rw-r--r--    1 1000     1000           380 Jan 10 10:43 .babelrc
-rw-r--r--    1 1000     1000            55 Jan 10 10:43 .browserslistrc
drwxr-xr-x    7 1000     1000          4096 Mar  1 15:12 .docker-config
-rw-r--r--    1 1000     1000           657 Jan 10 10:43 .editorconfig
-rw-r--r--    1 1000     1000          1114 Feb 26 18:05 .env
-rw-r--r--    1 1000     1000          5099 Mar  1 15:12 .env.example
-rw-r--r--    1 1000     1000          2404 Mar  1 14:52 .env.production.example
-rw-r--r--    1 1000     1000            23 Jan 10 10:43 .eslintignore
-rw-r--r--    1 1000     1000           710 Jan 10 10:43 .eslintrc.js
drwxr-xr-x    8 1000     1000          4096 Mar  2 10:40 .git
-rwxr-xr-x    1 1000     1000          1263 Feb 22 14:24 .gitignore
drwxr-xr-x    3 1000     1000          4096 Mar  2 18:53 .idea
-rw-r--r--    1 1000     1000          2150 Jan 10 10:43 .snyk
-rw-r--r--    1 1000     1000          5213 Mar  1 15:12 README.md
-rwxr-xr-x    1 1000     1000             9 Jan 10 10:43 VERSION
drwxr-xr-x    9 1000     1000          4096 Jan 10 10:43 assets
drwxr-xr-x    4 1000     1000          4096 Feb 26 13:10 build
-rwxrwxrwx    1 1000     1000          4148 Feb 22 18:01 composer.json
-rwxr-xr-x    1 1000     1000        525655 Mar  1 14:52 composer.lock
drwxr-xr-x    7 1000     1000          4096 Mar  1 14:52 config
-rwxr-xr-x    1 1000     1000           623 Jan 11 11:37 craft
-rw-r--r--    1 1000     1000           330 Jan 10 10:43 craft.bat
drwxr-xr-x    2 1000     1000          4096 Feb 23 16:38 data
-rw-r--r--    1 1000     1000          1378 Mar  1 15:12 docker-compose.yml
-rw-r--r--    1 1000     1000          4023 Jan 10 10:43 fractal.config.js
drwxr-xr-x    2 1000     1000          4096 Mar  2 11:24 migrations
drwxr-xr-x   10 1000     1000          4096 Jan 10 10:43 modules
drwxr-xr-x 1280 1000     1000         36864 Jan 23 15:06 node_modules
-rw-r--r--    1 1000     1000          2802 Jan 23 15:06 package.json
drwxr-xr-x    5 1000     1000          4096 Jan 10 10:43 redirects
drwxr-xr-x    2 1000     1000          4096 Jan 10 10:43 scripts
-rw-r--r--    1 1000     1000          2554 Feb 19 17:03 secrets.json
-rw-r--r--    1 1000     1000          1162 Feb 20 14:22 secrets.json.example
drwxrwxrwx    9 1000     1000          4096 Feb 18 15:18 storage
drwxr-xr-x    7 1000     1000          4096 Feb  3 22:58 styleguide
drwxr-xr-x   23 1000     1000          4096 Mar  1 14:52 templates
drwxr-xr-x    3 1000     1000          4096 Jan 10 10:43 translations
drwxrwxrwx  105 1000     1000          4096 Mar  1 12:32 vendor
drwxr-xr-x    4 1000     1000          4096 Mar  2 10:12 web
-rw-r--r--    1 1000     1000        526787 Jan 23 15:06 yarn.lock
jasonmccallister commented 3 years ago

Does it show the same user and group when running the ls -la command in WSL2?

jamesmacwhite commented 3 years ago

No it will be under the WSL user so in my case jameswhite:jameswhite

User 1000 I believe is the UID of www-data within the Docker container.

jamesmacwhite commented 3 years ago

https://user-images.githubusercontent.com/8067792/109705960-48186f00-7b90-11eb-8e1d-87e377e1539d.mp4

Quick demo with a shell. I use Windows Terminal because of it's full Unicode support (so emojis show up!), rather than a plain WSL bash terminal. It doesn't matter for this, as the error is coming from the PHP process I believe.

jasonmccallister commented 3 years ago

Hmm ok, there might be an easier way to detect this going forward. We can set the user here: https://github.com/craftcms/nitro/blob/main/command/ssh/ssh.go#L169

It defaults to www-data or if you pass the --root flag it will use the root user. We might be able to detect is this is linux/WSL and switch it to the 1000 user/group (you are right that is the www-data user in the docker image).

jamesmacwhite commented 3 years ago

Could be an option, although, I'm not fully aware of the ramifications setting the user context for the overall container interaction i.e. nitro ssh. I assume this is specific to WSL2 because of the Docker WSL integration, so I wouldn't want to pollute Nitro with Windows hacks. I know this happens with vanilla Docker containers too through WSL.

This might need a bit more investigation, I'm not sure running the container under that user context works for everything and might not be the best idea, if it starts to modify permissions of other elements and cause issues.

Example, after running composer update under the --user 1000:1000

> @php craft clear-caches/all
Clearing cache: Asset caches
Clearing cache: Asset indexing data
Clearing cache: Asset transform index
Clearing cache: Compiled templates
Could not clear the directory Compiled templates: rmdir(/app/storage/runtime/compiled_templates/49): Directory not empty
Clearing cache: Control panel resources
Error clearing cache Control panel resources: rmdir(/app/web/cpresources/69cd9a2a): Directory not empty
Clearing cache: Data caches
Clearing cache: Imager image transform cache
Clearing cache: Imager remote images cache
Clearing cache: Retour redirect caches
Clearing cache: SEOmatic frontend template caches
Clearing cache: SEOmatic metadata caches
Clearing cache: SEOmatic sitemap caches
Clearing cache: Temp files
Clearing cache: Twitter caches
Could not clear the directory Twitter caches: rmdir(/app/storage/runtime/twitter/userimages/49967368/96): Permission denied
Clearing cache: Videos caches

For the most part the way it is now works for most actions, I think you hit this when a write is attempted within the /app path by PHP, or at least certainly with Yii2.

jasonmccallister commented 3 years ago

Just a quick update, I'm diving into Docker's bind mount documentation and trying to find an automated way around this, it might be as simple as detecting if the OS is Linux and providing the user with the group @jamesmacwhite mentioned.

jamesmacwhite commented 3 years ago

Thank you for your continued investigation. From what I know it's certainly at the Docker level. Same issue occurs if you just use the Craft CMS docker images standalone without Nitro, but this isn't specific to Craft CMS either. I assume it is related to the PHP-FPM process running under www-data in the container and then essentially writing to host filesystem with a UID that isn't able to write. I'd imagine if you were to chmod 777 the migrations folder and then retry the same test case as originally reported without running docker exec with the --user 1000:1000 it would likely work but obviously chmod 777 on everything isn't the fix. It's acceptable for certain paths that are ephemeral or able to be regenerated.

I think this mostly hits WSL, because of the Docker and WSL integration. I don't think you'd get the same issue on macOS or Linux, but could be wrong.

jasonmccallister commented 3 years ago

Just released 2.0.7 with better support on Linux and WSL2 machines.