Symfony 2 : en finir avec le nettoyage du cache via cache:clear !

Symfony, qu’est-ce que tu nous cache ?

Que vous soyez un utilisateur avancé ou débutant du célèbre framework MVC basé sur PHP, vous avez forcément tôt ou tard du affronter cet écueil : mettre à jour le cache fichier de Symfony !

Le scénario est le suivant : vous installez la dernière version de votre framework préféré, vous vous rendez sur la page Web de configuration http://monsite/app_dev.php comme on vous l’a dit et là, c’est le drame :

RuntimeException: Unable to create the cache directory (/var/www/Symfony/app/cache/dev)

Rien de choquant, j’ai décompressé l’archive en tant qu’utilisateur seb, c’est donc lui qui possède tous les droits sur l’arborescence, que j’ai simplifiée dans l’exemple pour ne garder que les répertoires :

ls -l Symfony
total 120
drwxr-xr-x 6 seb seb 4096 mai 15 10:23 app
drwxr-xr-x 2 seb seb 4096 mai 15 10:23 bin
drwxr-xr-x 3 seb seb 4096 mai 15 10:23 src
drwxr-xr-x 13 seb seb 4096 mai 15 10:23 vendor
drwxr-xr-x 3 seb seb 4096 avril 27 20:36 web

L’utilisateur par défaut de mon serveur HTTP Apache est www-data : lorsque le malheureux tente de créer le répertoire de cache, il échoue lamentablement, faute de droits suffisants ! Comment faire ?

Bougredane et Bougredandouille ne font qu’un, mes users aussi !

Et si nous mettions www-data et notre user seb dans le même panier ? Après tout, ils vont se partager l’accès aux différents répertoires, autant officialiser leur collaboration ! Nous n’aurions plus qu’à donner les droits au groupe et nos deux utilisateurs pourraient enfin se partager cette arborescence dans la joie et la bonne humeur (et accessoirement, l’efficacité !)

Je vais ajouter seb à mon groupe www-data, dont fait partie l’utilisateur www-data. Je répète : il existe un groupe www-data, dont l’utilisateur principal est lui-même nommé www-data, attention à ne pas confondre ! Rien ne vous interdit d’y rajouter d’autres utilisateurs ! C’est même ce que nous allons faire de suite, notre utilisateur seb va rejoindre le groupe www-data :

sudo usermod -aG www-data votre_utilisateur

N’oubliez pas l’option -a (append) ! Si vous l’omettez, vous écrasez l’ensemble des groupes auxquels vous appartenez avec le nouveau groupe ! Pour vous assurer que le changement a bien été pris en compte, tapez la commande groups :

seb@debian:/var/www$ groups
seb www-data lpadmin

Mission (presque) accomplie : il vous faut en effet vous déconnecter/reconnecter pour que ces changements soient pris en compte par le système d’exploitation.

Extrait d'un strip de Dicentim

Ah, les lectures de jeunesse…

Changer les droits d’accès à l’arborescence de Symfony

Nous avons deux utilisateurs qui font partie du même groupe mais à ce stade, une arborescence qui est toujours la propriété de l’utilisateur qui l’a créée. Il faut donc la changer ! Disons dans un premier temps qu’elle appartient dorénavant au groupe www-data :

chgrp -R www-data Symfony/

Puis, que tout utilisateur membre de ce groupe possède les droits en écriture dessus :

chmod -R g+w Symfony/

Regardons l’impact du changement :

drwxrwxr-x  6 seb www-data  4096 mai   15 10:23 app
drwxrwxr-x  2 seb www-data  4096 mai   15 10:23 bin
drwxrwxr-x  3 seb www-data  4096 mai   15 10:23 src
drwxrwxr-x 13 seb www-data  4096 mai   15 10:23 vendor
drwxrwxr-x  3 seb www-data  4096 avril 27 20:36 web

A ce stade là, la joie nous anime et nous retournons immédiatement sur l’URL de notre page de config’ pour contempler avec satisfaction les conséquences du changement : TOUT MARCHE, c’est magnifique ! Alors nous paramétrons la connexion à notre base de données ! Tout se déroule parfaitement, nous prenons un moment pour nous extasier sur la démo Hello World puis très vite, nous développons nos premiers contrôleurs d’action, nos premières entités, nos premiers templates Twig…Et un beau jour, nous décidons de nettoyer le cache en ligne de commande avec la célèbre commande app/console cache:clear – -env=dev (le env étant optionnel car valant dev par défaut). La sanction est immédiate :

[UnexpectedValueException]
The stream or file « /var/www/Symfony/app/logs/dev.log » could not be opened: failed to open stream: Permission denied

Image d'une personne pleurant

Un développeur qui vient de faire son premier cache:clear en CLI

Mais…attendez une seconde…je ne comprends pas, j’ai deux utilisateurs du même groupe maintenant, pourquoi tant de haine à mon égard ? Si vous regardez le fichier incriminé (qui se trouve dans le répertoire de logs et pas de cache), voici ce que vous y verrez :

-rw-r--r-- 1 www-data www-data 94637 mai   15 11:01 dev.log
-rw-r--r-- 1 www-data www-data  2626 mai   15 11:00 prod.log

SCANDALE ! Ce sagouin de www-data n’est pas partageur, il n’a pas donné les droits d’écriture au groupe ! Mon utilisateur seb qui utilise la ligne de commande ne peut donc pas écrire dans ce fichier ! Que faire ? M’accaparer de force les droits d’écriture sur le répertoire logs ? Allons-y !

Mon utilisateur seb n’a pas crée ces fichiers, il doit donc passer par sudo pour faire cette modification :

sudo chmod -R g+w app/logs/

A la bonne heure ! Si www-data ne prête pas, je lui arrache des mains !
Sûr de moi je relance un app/console cache:clear et je manque de m’étrangler !

[RuntimeException]
Unable to write in the « /var/www/Symfony/app/cache/dev » directory

Bulle de bédé avec des pictogrammes

Le réflexe primaire du développeur contrarié : la bordée d’injures !

Sans surprise, je constate les mêmes dégâts dans le répertoire cache :

drwxr-xr-x 7 www-data www-data 4096 mai   15 11:00 dev
drwxr-xr-x 5 www-data www-data 4096 mai   15 11:00 prod

Pourtant j’avais bien dit à chmod de donner les droits en écriture sur ce maudit répertoire ! On dirait qu’il ne les a pas propagés aux sous-répertoires…Bizarre.
Qu’à cela ne tienne, je continue dans ma logique Rambo, je les aurais tous à la force de la Ranger cirée !

sudo chmod -R g+w app/cache/

ENFIN JE TRIOMPHE ! *rire démoniaque*
Je viens de lancer le nettoyage du cache en dev et il s’est effectué comme il faut, la preuve !

seb@debian:/var/www/Symfony$ app/console cache:clear –env=dev
Clearing the cache for the dev environment with debug true

Passablement ragaillardi par cette victoire sur la machine, je retourne donc en découdre avec la programmation, puis je fais un F5 sur mon client HTTP favori. H-O-R-R-E-U-R !!!

RuntimeException: Failed to write cache file « /var/www/Symfony/app/cache/dev/classes.php ».

Ce coup-ci c’en est trop, des tas d’idées vous passent par la tête et notamment la reconversion professionnelle…C’est sûr et certain, la machine vous en veut !

Regardons le répertoire de cache :

seb@debian:/var/www/Symfony$ ls -l app/cache/
total 8
drwxrwxr-x 6 seb      seb      4096 mai   15 11:32 dev
drwxrwxr-x 5 www-data www-data 4096 mai   15 11:00 prod

Bon sang, l’utilisateur seb a osé imposer SON groupe en lieu et place de celui que j’avais défini !!! De deux choses l’une, soit je trouve une solution à ce problème et vite, soit je joue éternellement au ping-pong avec les droits de mes deux utilisateurs et je ne garantis aucunement de continuer de jouir de l’ensemble de mes facultés mentales à la fin de la journée. Pire : dégoûté de ce cirque, je pourrais me tourner vers Zend ! (je plaisante, ne tapez pas !)

Ouère iz zeu problème ?

Mes utilisateurs accèdent en concurrence aux mêmes répertoires : dès que je modifie les permissions de l’un, c’est l’autre qui se voit refuser l’écriture. Ça peut durer longtemps ! J’étais sur la bonne piste en décidant de créer un seul groupe, mais je ne suis pas allé au bout de la solution !

Victime de chmod, tel est ton nom de code !

Un de mes problèmes vient du fait qu’un utilisateur, www-data ou seb, ne respecte pas les droits du répertoire parent dans lequel il crée le sien. Pour cela, il me faut faire usage de l’option +s de chmod, voyez plutôt :

chmod g+s cache/ logs/

Cette option setgid (set group id), lorsqu’elle est appliquée sur un répertoire, permet de dire la chose suivante : « tout fichier/répertoire créé dans CE répertoire héritera des droits DE GROUPE du répertoire de base au lieu d’hériter des droits DU GROUPE de l’utilisateur qui l’a crée ». Ceci va résoudre une partie de mon problème car seb ne s’arrogera pas le droit d’écraser la valeur de groupe www-data par la sienne (seb) ! Cependant, il faut un moyen de dire que nous souhaitons que nos deux utilisateurs maintiennent les droits EN ECRITURE de leur groupe commun, qui rappelons le est www-data !

Umask to the rescue !

Nous voulons pouvoir dire :

  • Les utilisateurs seb et www-data doivent répliquer les droits de groupe du répertoire de base
  • Les utilisateurs seb et www-data doivent garantir que tout fichier ou tout répertoire créé sera writeable par quiconque appartient au groupe www-data

Nous avons déjà assuré la première partie, comment garantir que mes deux utilisateurs donneront le droit d’écriture à leur groupe en toutes circonstances ?

En positionnant le umask de l’un et de l’autre à la même valeur : 0002.
Pourquoi ce 0002 ? Le premier 0 indique une notation octale, mais ce n’est pas très intéressant…Ce qui nous intéresse c’est 002 ! 0 correspond aux droits de l’utilisateur (U), le second 0 aux droits du groupe (G) et le 2 aux autres (O, pour others), un bon moyen mnémotechnique consiste à retenir le prénom Hugo pour se souvenir de la place de chacun (U-G-O).
Bref, ce masque nous dit en gros « voici ce que j’enlève lorsque tu crée un fichier ou un répertoire » et donc il nous dit dans notre cas « J’enlève le droit d’écriture aux autres ». Souvenez-vous que les droits sont les suivants : lecture = 4, écriture = 2, exécution = 1.
En positionnant mon umask à 0002, je dis en substance « enlève les droits d’écriture à others et laisse le reste intact », donc j’aurais finalement 775 comme droits sur tout ce que je m’apprête à créer !

Pour voir l’état de votre umask, et donc de voir s’il y a besoin de le modifier, tapez simplement umask en ligne de commande.

Il y a de fortes chances pour qu’il soit par défaut à 0022, dans ce cas là il faudra le changer en faisant simplement umask 0002 puis umask pour vérifier que le bon s’affiche dorénavant. Attention toutefois, ce changement ne dure que le temps de votre session, il faudra penser à reporter cette commande dans votre fichier .bashrc, par exemple.

Nous y sommes ! Enfin, presque !

Un seul utilisateur a basculé son umask, c’est l’utilisateur CLI ! Il faut faire la même chose côté utilisateur Web, www-data, donc ! Nous rajoutons cette ligne au début des fichiers app_dev.php et console.php : umask(0002);

Ainsi, que nous créions des objets dans le filesystem avec la commande Symfony console, avec l’utilisateur Web via l’appel au contrôleur frontal de dev ou encore directement avec l’utilisateur qui manipule la ligne de commande, nous aurons à terme les mêmes droits !

Que dit la doc ?

Il est dit qu’il faut privilégier les ACL au détriment du umask car umask n’est pas totalement fiable. Soyons francs, quand on débute, on n’a pas forcément envie de s’improviser sysadmin et de s’attaquer aux ACL (de plus on peut très bien ne pas y avoir accès, en entreprise par exemple). Pour débuter ou encore développer en environnement local, nul besoin de mettre la barre trop haut, une modification du umask suffira largement.

Je vous recommande dans tous les cas la lecture à l’URL suivant : http://symfony.com/doc/current/book/installation.html#configuration-and-setup

Résumé

La TODO list, pour finir :

  • Mettez votre utilisateur CLI et votre utilisateur Web dans le même groupe
  • Faites un chmod g+s sur les répertoires qui posent problème : cache et logs
  • Changez le umask de votre utilisateur CLI dans .bashrc et dans le fichier app/console, faites de même pour l’utilisateur Web dans app_dev.php et app.php

Bon développement à tous et à toutes !

Beau ciel bleu

Le cache n’est plus un soucis, l’horizon est dégagé, vous êtes calme et détendu(e)…

8 réflexions sur « Symfony 2 : en finir avec le nettoyage du cache via cache:clear ! »

  1. François

    merci pour les tips et l’humour utilisé dans cet article (surtout quand le cache nous fait nous arracher les cheveux :p).
    Dans la doc officielle il y a aussi de bonnes ressources sur ce point. Thx, a+ !

    Répondre
    1. admin Auteur de l’article

      Oui, c’est écrit dans la doc, mais le moins qu’on puisse dire c’est que c’est assez nébuleux, et incomplet à mon goût. Nulle trace en effet de chmod +s qui est pourtant plutôt utile 😉

      Répondre
      1. toverux

        Je n’ai plus ce problème depuis longtemps (ACLs) mais je suis tombé sur votre article par hasard. J’aime bien votre solution qui reste basée sur les modes de fichiers POSIX, c’est la seule vraie solution « old-unix-style » que j’aie vu sur Internet. Sinon, je recommanderais peut-être les ACL, pas besoin de modifier l’umask (ce qui est assez pénible : modification du code PHP et de la conf Bash). Les ACL sont plus puissantes qur les modes et deux lignes de commandes suffisent, une fois entrées, tout cela est persistant (les ACL sont gérées au niveau de la partition, comme les modes) et je n’ai JAMAIS eu un seul autre problème. Après, votre solution fait office de remplacement aux ACL si elles ne sont pas dispos (ce qui ne devrait plus trop être le cas de nos jours).

        Répondre
  2. Pogs

    Merci !

    Par contre,

    sudo usermod -aG votre_utilisateur www-data

    C’est pas plutôt ?

    sudo usermod -aG www-data votre_utilisateur

    Répondre
    1. admin Auteur de l’article

      Vous avez parfaitement raison ! C’est d’abord le groupe et ensuite l’utilisateur…j’ai mis à jour l’article, merci !

      Répondre

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.