Index par titre

Gestion des accès

La gestion des accès dans authentic a deux objectifs:

L'idée est de partir du modèle RBAC et d'en garder l'essentiel pour couvrir ces deux besoins.

class Role
class User
class Objet

User - Role : < membre
Role -down-> Droit : a
Role -right-> Role : hérite
Droit -> Action : comment
Droit -down-> Objet : quoi
`Modèle RBAC avec héritage`

Nous n'avons pas besoin de la partie sur les permissions qui rend le modèle complexe à gérer; on confondra toujours un rôle avec une permission sur un objet, i.e. pour chaque paire permission, objet dont nous aurions besoin, il y aura un rôle équivalent qui pourra se combiner avec d'autres rôle en utilisant l'héritage permettant ainsi exactement les mêmes possibilités que le modèle RBAC complet.

class Role
class User


User - Role : < membre
Role -right-> Role : hérite de
`Modèle RBAC simplifié pour Authentic`

Notion d'héritage

L'héritage entre rôle n'a rien à voir avec l'héritage en programmation. Si un rôle R1 hérite d'un rôle R2, cela veut dire que le rôle R1 possède en plus des siennes toutes les permissions associées au rôle R2, soit directement soit via héritage. C'est une relation transitive, si R2 hérite de R3 alors R1 hérite indirectement aussi de R3.

Cela revient aussi à dire que tous les membres de R1 sont aussi indirectement des membres de R2.

Les rôles

Les rôles seront séparés en deux:

class Role
RoleTechnique -up-> AnyClass : "administre/donne accès"
Role -down-> User : membre
RoleTechnique -down-> User : membre

RoleTechnique -right-> RoleTechnique : hérite de
Role -up-> RoleTechnique : hérite de
Role -down-> Role : hérite de
`Modèle RBAC simplifié pour Authentic`

Rôles techniques d'administration

Pour permettre un découpage à gros grain de l'administration on ajoute le concept d'organisation, chaque objet (y compris les utilisateurs et les rôles) appartiennent à une organisation. Un rôle technique d'administration général est associé à chaque organisation, c'est l'équivalent du rôle super-utilisateur classique mais contraint à une organisation donnée. Les organisations sont structurées en arbre, une organisation peut contenir d'autres organisations et ses administrateurs ont tout pouvoir sur ces sous-unités administratives.

Pour chaque type d'objet on ajoute dans chaque organisation des rôles techniques d'administration de ces objets, le rôle technique d'administration général en hérite.

object "Rôle d'administration général de Orga" as AdminOrga
object Orga
object User1
object User2
object "Rôle d'administration des utilisateurs de Orga" as AdminUser

User1 -up-> Orga : appartient
User2 -up-> Orga : appartient
AdminOrga -> Orga : gère
AdminOrga -down-> AdminUser : hérite de
AdminUser -right-> User1 : gère
AdminUser -right-> User2 : gère
`Vue des rôles techniques d'administration avec une unique unité administrative`

object "Rôle d'administration générale de Orga" as AdminOrga
object "Rôle d'administration générale de Orga1" as AdminOrga1
object "Rôle d'administration générale de Orga2" as AdminOrga2
object Orga
object Orga1
object Orga2


Orga1 -up-> Orga : appartient
Orga2 -up-> Orga : appartient
AdminOrga -> Orga : gère
AdminOrga -down-> AdminOrga1 : hérite de
AdminOrga -down-> AdminOrga2 : hérite de
AdminOrga1 -right-> Orga1 : gère
AdminOrga2 -right-> Orga2 : gère
`Vue sur les rôles techniques d'administration avec plusieurs unités administratives hiérarchisées`

Rôle technique d'administration des rôles

Pour chaque rôle R (technique ou pas) un rôle technique d'administration Ra est crée. Il désigne les utilisateurs ayant le droit d'ajouter ou d'enlever des membres à ce rôle ainsi que de faire hériter un autre rôle de ce même rôle. Cette dernière opération revenant à affecter tous les membres de l'autre rôle au rôle administré, il est logique de le rendre possible.

Les rôles d'administration des rôles sont particuliers en ce qu'ils contrôlent leur propre administration, i.e. l'administrateur d'un rôle pourra toujours déléguer son pouvoir à un autre, i.e. il est aussi administrateur du rôle d'administration. Ceci pour éviter une récursion infinie au niveau des rôles d'administration des rôles qui aurait eu besoin d'un rôle d'administration à leur tour. On dit que ces rôles sont 'auto-administrés'.

Pour rendre n'importe quel rôle 'auto-administré' il suffit de lui faire hériter de son rôle d'administration.

object "Rôle technique d'administration de rôle" as Ra
object "Rôle" as R

Ra -down-> R : administre
Ra -right-> Ra : administre

Rôles techniques de gestion des accès

TODO Pour chaque object ayant besoin d'un accès on crée un rôle technique par exemple pour un service SAML w.c.s. on créera un rôle accès w.c.s, il donne accès ce service, sans lui l'IdP ne répondra pas.

À supposer que l'IdP propose de modéliser les rôles applicatifs, ils seront reproduits du coté d'authentic par des objets spécifiques, pour chacun de ces objets authentic créera un rôle d'accès du même nom. Ce rôle héritera du rôle d'accès de base.

object "W.C.S." as SAML
object "Rôle applicatif 1" as Cat1
object "Rôle applicatif 2" as Cat2
object "Rôle applicatif 3" as Cat3
object "Rôle d'accès à W.C.S" as R
object "Rôle mirroir 1" as R1
object "Rôle mirroir 2" as R2
object "Rôle mirroir 3" as R3

SAML <-down- Cat1 : service
SAML <-down- Cat2 : service
SAML <-down- Cat3 : service

R -> SAML : gère l'accès à
R1 -> Cat1 : gère le droit d'avoir
R2 -> Cat2 : gère le droit d'avoir
R3 -> Cat3 : gère le droit d'avoir

R1 -up-> R : hérite de
R2 -up-> R : hérite de
R3 -up-> R : hérite de

Visibilité

Il peut se poser la question de savoir si un administrateur d'un rôle dans organisation fille doit pouvoir voir les utilisateurs ou les rôles de l'organisation parente ou d'une organisation sœur quand il administre son rôle. Pour l'instant nous écartons ce problème et le déclarons hors-scope. Dans toutes les situations où un utilisateur est amené à choisir un utilisateur, ajouter un membre à un rôle, ou un rôle sans nécessité d'une permission particulière1 tous les utilisateurs ou rôles seront visibles.

1 par exemple pour hériter d'un rôle il faut être administrateur de celui-ci, il ne sera donc pas possible de voir dans la liste les rôles qu'on administre pas

IHM

Le graphes des rôles est un graphe dirigé complexe qu'on essayera pas de représenter. On aura comme actuellement avec les groupes une vue alphabétique de la liste de tous les rôles, et pour chaque rôle la liste de ses membres (directs et indirects via l'héritage). On y ajoutera deux nouveaux onglets: la liste des rôles dont il hérite et la liste des rôles qui héritent de lui. Tout au plus les services pourront indiquer des relations hiérarchiques de représentation pour certains rôles techniques, ceux-ci ayant généralement des relations d'héritage simples entre eux. Ainsi il sera intéressant dans l'exemple plus haut de présenter le rôle d'accès w.c.s. comme racine d'un arbre dont les catégories en sont les branches.

Chaque organisation disposera d'une vue d'accueil présentant l'accès aux 2 objets gérés principaux les utilisateurs et les rôles. Il y sera aussi présents un bouton d'accès pour chaque sous-organisation. Les [xxx] sont des liens. [-] est un bouton de suppression, [/] un bouton de suppression grisé.

 Agglo

   [Agglo           ]    [Ville1          ]   [Ville2] | [Ville3] | [Ville 4]
   | → utilisateurs |    | → utilisateurs |   ... 
   | → (à réfléchir)|
   |                |

Benj m'a dit qu'on laissait tomber cet affichage des utilisateurs par organisation (ville), c'est pas gérable quand il y a beaucoup de ville (+ de 1000 au CDG59 actuellement et beaucoup aussi dans l'AO en cours). Du coup on ne verra que les utilisateurs pour lesquels on a les droits nécessaires. Affichage sous forme de liste paginée avec une colonne indiquant l'organisation à laquelle appartient l'utilisateur.
Idem pour les rôles.

`Accueil du manager d'authentic`

 [Agglo] > Ville1

   [Utilisateurs] | [Rôles] | [Services SAML]

 -----

   [Service enfance] [Service état civil]


`Accueil du manager d'authentic pour la sous-organisation ville1`
 [Agglo] > [Ville1] > Utilisateurs

  Recherche: ________________ [Créer un nouvel utilisateur]

    Nom | Prénom | Email
 1 [xxx | xxx    | xxx@xxx ]
 2 [yyy | yyy    | yyy@yyy ]

   [1] [2] .. [5] [6]

Dans le cadre de Publik, on s'est mis d'accord sur le fait que l'accueil du /manage d'Authentic était superflu : il ne contient rien qui ne soit déjà exposé sur le portail agent (hobo/combo). Benj est ok en dépit de ce qu'il écrivait ici #7088

`Administration des utilisateurs de ville 1`

 [Agglo] > [Ville1] > [Utilisateurs] > Utilisateur 1

  Informations | [ Rôles ]

  Nom:     xxxx_____       [Renvoyer un mot de passe]
  Prénom:  xxxx_____       
  Email:   xx@xx____       [Forcer le changement du |
                           |au prochain login       ]
   [1] [2] .. [5] [6]

`Administration des informations personnelles de l'utilisateur 1 de ville 1`

 [Agglo] > [Ville1] > [Utilisateurs] > Utilisateur 1

  [Informations] | Rôles

  |   | Nom
  --------------------------
  | 1 | Administrateur Ville 1 [-]
  | 2 | Administrateur de service enfance de ville 1 (rôle hérité) [/]
  | 3 | W.C.S (rôle hérité) [/]
  | 4 | W.C.S :: Service enfance [-]
  |

  Ajouter un rôle: __________________ [Ok]
  `Vous devez être administrateur d'un rôle pour pouvoir l'ajouter`

(possibilité de clic sur "rôle hérité" pour avoir des infos du comment)

`Administration des rôles de l'utilisateur 1 de ville 1`

 [Agglo] > [Ville1] > Rôles

  Recherche: ________________ [Créer un nouveau rôle]

 |   | Nom                                      | Technique
 ----------------------------------------------------
 | 1 | Administrateur de ville 1                |   Oui
 | 2 | +-- Gestion des utilisateurs             |   Oui
 | 3 | +-- Gestion des rôles                    |   Oui
 | 4 | +-- Gestion des services SAML            |   Oui
 | 5 | +-- Administration du service enfance    |   Oui <- à voir si on fait aussi apparaître les rôles d'administration du niveau n au niveau n+1
 | 6 | +-- Administration du service état civil |   Oui
 | A | +-- Administration "élu"                 |   Oui
 | 7 | Accès à W.C.S.                           |   Oui
 | 8 | +--- Service Enfance                     |   Oui
 | 9 | +--- Service état civil                  |   Oui
 | B | +--- Élu                                 |   Oui
 |10 | Élus                                     |   Non

(suggestion : mettre dans un onglet différent les rôles d'administration des rôles (5, 6, A))

(injonction : retirer la colonne technique)

`Administration des rôles de ville 1`

 [Agglo] > [Ville1] > [Rôles] > Élus

  Membres | [Rôles hérités] | [Rôles héritants]  

  |   | Nom | Prénom | Email    | Membre direct
  ----------------------------------------------
  | 1 | xxx | xxx    | xxx@xxx  | Oui  [-]
  | 2 | yyy | yyy    | yyy@yyy  | Non  [/]
  | 3 | zzz | zzz    | zzz@zzz  | Oui  [-]
  ....

  [1] [2] .. [3] [4]

  Ajouter un membre: ___________ [Ok]

(rôles hérités → rôles dont on est membre) (rôles héritants → rôles "membres de")

`Administration des membres du rôle Élus`

 [Agglo] > [Ville1] > [Rôles] > Élus

  [Membres ] | _Rôles hérités_ | [Rôles héritants]  

  |   | Nom du rôle
  --------------------------------------------
  | 1 | W.C.S :: Élu

  Ajouter un rôle hérité: ___________ [Ok]
  `Pour pouvoir ajouter un rôle hérité vous devez être administrateur de ce rôle`

`Administration des rôles hérités du rôle Élus`

 [Agglo] > [Ville1] > [Rôles] > Élus

  [Membres ] | [Rôles hérités] | _Rôles héritants_

  |   | Nom du rôle                          |
  --------------------------------------------
  | Aucun rôle héritant                      |

  Ajouter un rôle héritant: ___________ [Ok]

`Administration des rôles hérités du rôle Élus`


HowDoWeCreateAVM

Depuis l'interface de proxmox

Create CT

(mesclun)
Id: incrément du dernier
10xx => 192.168.43.xx
20xx => 176.31.146.xx

dns:
5.135.221.23 5.135.221.14 176.31.123.109

/!\ Sur mesclun, reloader powerdns


HowDoWeDoAndroidDebug

Pour debugguer un environnement Publik local avec Chrome Android ("remote debugging").
Il ne s'agit pas ici de debugger des application Android, mais simplement d'afficher une URL sur son téléphone et de voir tout ce qui se passe dans le debugguer de son bureau.

Pré-requis

Installez Chrome (version google nécessaire pour "inspecter" un onglet sous android chrome)

google-chrome --remote-debugging-port=9222

TODO trouver comment inspecter une page android-chrome avec chromium sous debian

(note de Fred : simplement utiliser chromium également sur le téléphone)

La documentation complète est ici : https://developers.google.com/web/tools/chrome-devtools/remote-debugging/

Configurez votre serveur local

Pour développer localement sur un module de Publik, utilisez publik-devinst en suivant cette documentation

Vous aurez toutefois besoin d'adapter cette installation pour que les DNS de votre installation locale soient aussi accessibles depuis le monde extérieur.

Configurez le téléphone Android de développement.

sudo apt install android-tools-adb
adb push entrouvert-ca-der.crt /mnt/sdcard/Download/

Debugguez !


HowDoWeDoAPI

Bonnes pratiques


HowDoWeDoBackup

Entr'ouvert gère la sauvegarde de toutes ses installations, les sauvegardes sont quotidiennes (nocturnes) et conservées :

En plus des sauvegardes complètes à chaud des systèmes, un archivage des transactions des bases de données est réalisé, cela permet de rejouer les modifications de données et de récupérer des données à la minute. Les restaurations sont testées régulièrement. Entr'ouvert dispose d'une procédure de restauration simple, que ce soit une restauration partielle « sur site » ou totale sur une nouvelle instance.

Nous utilisons BorgBackup pour les sauvegardes fichiers et PGBackRest pour les sauvegardes des bases de données PostGreSQL.


HowDoWeDoCodeReviews

Parce que ça améliore la qualité du code produit, que ça permet un partage de la connaissance du code, on fait des relectures des patchs avant d'envoyer ceux-ci dans les dépôts. Pour citer "Code reviews: from nitpicking to cooperation" repris dans les ressources en bas de page :

Code review and peer review are great methods for cooperation aiming at:

- Ensuring that the code works as intended
- Ensuring that the task was fully accomplished and no detail left out
- Ensuring that no security issues have been introduced
- Making sure the code fits the practices of the team and is understandable and maintainable by others
- Sharing insights, transferring knowledge between code author and code reviewer
- Helping the code author to learn to write better code

Toutes les applications, tous les modules sont concernés, que ça soit mail2redmine ou w.c.s., et de la même manière, tout le monde est concerné. Comme à tout il peut y avoir des exceptions, elles sont listées en bas de cette page.

Timing et attentes

Un auteur n'a pas envie d'attendre des jours que quelqu'un jette un œil à son code; il est souvent utile de préférer une réponse rapide mais incomplète, concentrée sur les points majeurs relevés d'une première lecture, plutôt qu'attendre le moment permettant la relecture intégrale et exhaustive. À ce sujet ça peut sembler ridicule de pointer des problèmes de style dès le premier moment mais c'est surtout ridicule parce que de tels problèmes ne devraient pas arriver avec un environnement de développement adéquat, qui indente de manière uniforme par exemple. En pratique l'utilisation de black est mise en place dans Chrono, pourrait être généralisée une fois intégrée dans jenkins etc.

Comme les relectures un autre aspect important du développement concerne les tests, de manière graduée une règle peut être qu'un patch doit être couvert par des tests autant que le reste du code du module (cf jenkins pour prendre connaissance de la couverture de code). Avoir les commits poussés dans des branches "wip" permet à jenkins d'assurer l'exécution et la visibilité des tests.

À noter qu'on peut bien sûr également partager des patchs en amont, pour interroger sur une approche, on ne fait pas de test-driven development.

Esprit de relecture

L'esprit doit être positif etc. L'article "Code reviews: from nitpicking to cooperation" en ressource pointe bien les risques à exiger des commits "parfaits".

Méthodes particulières

Exceptions

Ressources


HowDoWeDoCSS

Conseils et recommandations dans la rédaction ou refactorisation de code CSS.

Commentaires

La compilation sass du code source n'effectue pas de compression du code CSS compilé. Il est donc déconseillé d'utiliser les blocs commentaires CSS /* commentaire */.
À la place, utiliser des commentaires Sass // commentaire.

Plusieurs fichiers

Évitez les fichiers CSS à rallonge.
Il est judicieux de scinder des fragments de code distincts dans leurs propres fichiers, qui sont concaténés lors d'une étape de construction.
Isoler chaque composant/bloc dans un fichier propre permet de les faire évoluer distinctement des autres sans craindre les conflits ou d'éventuelles régressions sur les autres.

Tous les styles d'un composant seront donc de préférence définis dans son fichier.
Il faut éviter de styler plusieurs éléments provenant de plusieurs composants / blocs au sein d'une même déclaration.

Ne pas faire :

.composant-1 h2,
.bloc-2 h2,
.composant-3 h3 {
    text-transform: uppercase
}

Sélecteurs CSS

Liste des bonnes pratiques pour sélectionner et nommer un élément en CSS.

Éviter les sélecteurs d'id

Les sélecteurs par `#id` ont une spécificité trop lourde dans le calcul de résolution de la cascade, empêchant ainsi l'écriture efficace d'un code modulaire.

Éviter les sélecteurs de tag

Utiliser le sélecteur de tag doit être considéré comme une très mauvaise pratique.
Cela revient à définir le style d'un bloc en rapport à sa sémantique et rend impossible la mise à jour de l'HTML.

Exemple et conséquence de cette mauvaise pratique. Ne pas faire :

div.composant {
    background-color: gray;
}

Quand, dans le fichier template du composant, il s’avérera judicieux de remplacer la balise `div` non sémantique par une balise `section`, le style ne s'appliquera plus. Ce sélecteur empêche la mise à jour du template.

No DOM

Cette règle suit logiquement les recommandations précédentes.
Évitez les sélecteurs descendants par tag ou #id, Ne pas faire :

div.composant > ul > li {
    padding-left: 1em;
}

Dans cet exemple, les modifications suivantes du template HTML généreront des régressions de styles :

• La modification des balises div, ul ou li par des choix sémantiques différents.
• L'ajout des balises intermédiaires, comme ajouter une balise `nav` entre `div` et `ul`.

Ne pas ajouter d'informations relatives au DOM dans vos sélecteurs.

First class

Il est donc préférable de cibler les éléments uniquement par leur class.
Pour permettre une sélection sécurisée d'un élément par une class unique, une convention de nommage excluant les conflits est nécessaire.

Convention `block--element`

Le modèle `.app-block--element` est préconisé pour l'écriture de tout nouveau composant ou bloc.

block

Règles à suivre pour la définition du nom de class du bloc.

element

Dictionnaire d'identifiants d’éléments

Élément ou sous-bloc ?

Lorsqu'un composant présente une arborescence profonde, comme c'est souvent le cas avec les listes, il est préférable d'imbriquer les blocs plutôt que de définir des éléments trop complexes.

.main-nav {}
.main-nav--list {}
.main-nav--item {}
.main-nav--link {}

.sub-main-nav {}
.sub-main-nav--list {}
.sub-main-nav--item {}
.sub-main-nav--link {}

Exemple

Exemple d'un fichier scss `wcs/_steps.scss` avec le composant 'étapes d'une demande'.

Il est composé de 2 blocs

.wcs-steps              { /* styles du bloc */ }
.wcs-steps--list        { /* styles pour la liste (ol) */ }

.wcs-step               { /* styles pour l'item (li) */ }
.wcs-step--marker       { /* styles pour le marker (abbr) */ }
.wcs-step--marker-nb    { /* styles pour le num du marker (span) */ }
.wcs-step--marker-total { /* styles pour le num total du marker (span) */ }
.wcs-step--label        { /* styles pour le label (p) */ }

Avec le nesting SASS, il est possible de ne pas répéter l'identifiant du bloc dans les class des éléments tout en représentant graphiquement l'arborescence DOM des balises du template.

.wcs-step {
    /* styles pour l'item (li) */
    &--marker {
        /* styles pour le marker (abbr) */
        &-nb { 
            /* styles pour le num du marker (span) */ 
        }
        &-total { 
            /* styles pour le num total du marker (span) */ 
        }
    }
    &--label {
        /* styles pour le label (p) */    
    }
}

HowDoWeDoDebianPackages

Pour un backport de paquet qui existe déjà dans Debian, on peut utiliser dgit :

 $ dgit clone django-haystack
 $ cd django-haystack
 $ # si debian/patches/series existe, le retirer, parce que eobuilder va recréer le .orig.tar.gz avec les patchs déjà appliqués
 $ git rm -f debian/patches/series && git commit debian/patches/series
 $ git remote add eo git@git.entrouvert.org:debian/django-haystack
 $ git push -u eo dgit/sid:main

Puis lancer https://jenkins.entrouvert.org/job/debs/.

curl -X POST --user user:token "https://jenkins.entrouvert.org/job/debs/buildWithParameters?GIT_PROJECT=debian/django-haystack&DEBIAN_VERSIONS=buster,bullseye" 

Paquets python

debian/rules


#!/usr/bin/make -f
# -*- makefile -*-

export PYBUILD_NAME=combo <-- ici nom de la distribution déclaré dans setup.py ou pyproject.ml, ou plutôt suffix qui suivra python(3)- dans le nom du paquet, j'ai un doute ici
export PYBUILD_DISABLE=test

%:
    dh $@ --with python3 --buildsystem=pybuild <-- rajouter python2 si besoin, systemd si brique

override_dh_install: <-- uniquement pour les briques
    dh_install
    mv $(CURDIR)/debian/python3-<project>/usr/bin/manage.py $(CURDIR)/debian/<project>/usr/lib/<project>/manage.py

debian/python(3)-x.install

Inutile.

debian/project.install pour les briques (applications Django)

On ne doit trouver que ces fichiers (.init, .service, .cron, etc.. installé automatiquement)

debian/combo-manage       /usr/bin
debian/settings.py        /etc/combo
debian/uwsgi.ini          /etc/combo
debian/debian_config.py   /usr/lib/combo

Le manage surchargé, le settings de base, le uwsgi de base et le debian_config.py de base.

Mettre à jour un paquet issu d'un projet externe

Exemple :

git clone ssh://git@git.entrouvert.org/debian/factur-x
git remote add github https://github.com/akretion/factur-x.git
... merge et mise à jour éventuelle de trucs dans debian/, etc.
git push

Notes eoday

ex de fichier changelog à générer :

wcs (1.12.12.5.g46a0062-1~eob70+1)

  * (46a0062) tests: check forgotten page where user can set password (#6506)
  * (edbd295) hobos: change command to only deploy one instance, given as arg (#6486)
  * (0a58b8f) hobos: rename command to hobo_deploy, to match others (#6486)
  * (d0e2120) hobos: read json from a file if a filename is given on the command line (#6486)
  * (377911a) email: do starttls if advertised by the server (#6453)

wcs (1.12.12-0) $dist; urgency=low

  * (8df6312) release 1.12.12
  * (c631b0a) ctl: fix display of list of commands
  * (b199f1d) update french translation

 -- eobuilder <eobuilder@entrouvert.com>   Date...

wcs (1.12.11-0) $dist; urgency=low

  * (a563be0) release 1.12.11
  * (e54d2eb) form: fix handling of date in iso format in French-configured sites (#6390)
  * (1505495) use new password entry widget for register page (#5805)
  * (4a91c26) form: turn file type check into a hard check (#6134)
  * ...

 -- eobuilder <eobuilder@entrouvert.com>   Date...

...

Comment modifier la configuration d'un paquet debian d'un de nos projets ?

Dans la dépôt git du projet, les fichiers qui sont "usuellement" édités sont à la racine du dépôt dans le dossier debian/

Package: publik-base-theme
Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends}, python-xstatic-abrilfatface
Conflicts: python-authentic2 (< 2.1.20.742.gb6ee096-0)
Breaks: combo (< 0.7.1)
Description: Publik Base Theme
/etc/combo/settings.d
debian/fonts.py        /etc/combo/settings.d

Comment tester localement l'empaquetage debian ?

Pour ne pas avoir à pousser sur master et attendre de voir la tâche jenkins de notre paquet (par ex. https://jenkins.entrouvert.org/job/publik-base-theme-deb/), on peut localement tester ça sur sa debian avec :

sudo apt install devscripts
cd monprojet
debuild -uc -us -b 

HowDoWeDoDjangoDebugToolbar

Préparation

Aussi appelé djdt.

Depuis la version 1.6 l'installation automatique a été retiré il faut explicitement ajouter le code suivant dans le urls.py principal de la brique où on souhaite utiliser djdt:

if settings.DEBUG and 'debug_toolbar' in settings.INSTALLED_APPS:
    import debug_toolbar
    urlpatterns = [
        url(r'^__debug__/', include(debug_toolbar.urls)),
    ] + urlpatterns

Ensuite poser le fichier 10djdt.py suivant dans le répertoire settings.d de la brique:

DEBUG = True

# placer le middleware djdt après le middleware qui gère ForwardedFor, sinon on ne verra pas la bonne IP
MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES[:1] + (
    'debug_toolbar.middleware.DebugToolbarMiddleware',) + MIDDLEWARE_CLASSES[1:]

INSTALLED_APPS += ('debug_toolbar',)

INTERNAL_IPS = ['176.31.123.109']  # IP du VPN

Debian jessie

Le paquet de jessie n'est pas compatible Django 1.8 mais le paquet de stretch l'est et s'installe sans problème sur jessie pourvu qu'on installe aussi le paquet python-sqlparse de stretch.

HowDoWeDoDjangoManage

On laisse le fichier manage.py.

Dans le packaging debian on le met dans /usr/lib/$project/manage.py.

On crée un script /usr/bin/package-manage qui pose la variable d'environnement pour les settings debian et appelle le script manage, on oublie les jeux avec sudo/su au mieux on émet un message d'erreur quand l'utilisateur n'est pas bon.


HowDoWeDoDjangoProject

Pour éviter de répéter tout le temps les mêmes erreurs c'est intéressant d'avoir un projet template qui rassemble les bonnes pratiques sous forme de code et pas juste d'un wiki:

https://dev.entrouvert.org/projects/eo-django-project-template

On y met les bonnes recette de packaging python et debian mono et multi tenant.
Les bons settings, les bonnes librairies tierces qu'on voudrait voir partout (django-compressor?). La bonne intégration dans jenkins (tox.ini ? jenkins.sh ?).


HowDoWeDoDjangoSettings

Application simple

Le fichier settings.py est celui créé par Django (lors du startproject), on y ajoute la possibilité de charger des paramètres supplémentaires en ajoutant ces lignes à la fin (avec FOOBAR remplacé par le nom du projet) :

local_settings_file = os.environ.get('FOOBAR_SETTINGS_FILE',
        os.path.join(os.path.dirname(__file__), 'local_settings.py'))
if os.path.exists(local_settings_file):
    execfile(local_settings_file)

Commentaires

Par rapport à la forme from local_settings import * précédemment pratiquée, ça a l'avantage de donner un accès aux différentes variables déjà définies, pour par exemple permettre au fichier donné d'altérer INSTALLED_APPS.

Un inconvénient est que le fichier n'est pas surveillé par django, les modifications qui y sont faites ne sont pas automatiquement prises en compte, un redémarrage (ou la modification d'un autre fichier) est nécessaire.

Application multitenant

Le multitenant s'obtient pour une application donnée en utilisant le package python-hobo (à ne pas confondre avec l'application hobo). Pour devenir multitenant, une application doit entre autres modifier ses settings. Les modifications requises sont encapsulées dans un fichier de configuration debian_config_common.py que l'installation du package python-hobo positionne dans /usr/lib/hobo/.
Considérons une des briques applicatives de Publik, appelons là 'foobar'. La succession de chargement des settings se produit commme suit:

L'essentiel de la configuration est chargé à ce moment là. Cependant, si ils sont présents, des fichiers additionnels de configuration seront encore chargés:

Et les éventuels


HowDoWeDoDjangoTenants

Individuellement les projets n'ont pas à se soucier de multitenant, c'est totalement pris en charge par de la configuration.

Voir http://git.entrouvert.org/hobo.git/tree/debian/debian_config_common.py?h=master (à partir de # multitenant adaptations, ligne 206)

Exemple de fichier /usr/lib/<project>/debian_config.py appelé à la fin du settings.py du projet :

# /usr/lib/<project>/debian_config.py
# appelé en execfile() en toute fin des settings.py de <project>

PROJECT_NAME = 'foobar'

# si nécessaire:
#INSTALLED_APPS += ('mellon',)   # SAML2 authentication

execfile('/usr/lib/hobo/django_config_common.py')   # cf http://git.entrouvert.org/hobo.git/tree/debian/debian_config_common.py?h=debian

# en cas de besoin supplémentaire au niveau de la gestion des settings.py
# par tenant pour <project>. Par exemple pour Authentic:
TENANT_SETTINGS_MIDDLEWARE_LOADERS = +(
        'hobo.multitenant.settings_loaders.Authentic',
        # 'hobo.multitenant.settings_loaders.SettingsPy',
)

execfile('/etc/%s/settings.py' % PROJECT_NAME)

Utilisation

Création d'une base de données (avec comme propriétaire l'utilisateur faisant tourner le code de l'appli)

# su - postgres
$ createdb -O user foobar

Création d'un tenant

$ ./manage.py create_tenant foobar.example.net
[...]
$ ls /var/tmp/foobar/tenants/foobar.example.net/
media  static  templates

Appel des commandes de management

$ manage.py tenant_command createsuperuser -d foobar.example.net
Username (leave blank...)

Visite avec postgresql

$ psql foobar
foobar=> set schema 'foobar_example_net';
SET
foobar=> select username from auth_user;
 username 
----------
 fred
(1 ligne)
...

Fonctionnement

tenant_schema, "schémas" dans postgresql, + de notre côté des fichiers dans le filesystem, /var/lib/xxx/tenants/yyy.

Lancer des commandes

Commande unique:

package-manage tenant_command command -d domain ...

Commande multiple (pour les cron):

package-manage tenant_command command --all-tenants domain ...

Renommage des tenants

Renommage d'un site wcs (note: rien à voir avec les tenants Django)

Migrations Django

Il faut utiliser une commande dédiée pour gérer les migrations sur les tenants.

Revenir à la migration d'avant

$ passerelle-manage migrate_schemas iparapheur 0005 -v2
$ passerelle-manage migrate_schemas iparapheur 0005 -v2 --fake  # uniquement en base

Ajouter une migration

$ passerelle-manage makemigrations
$ git add passerelle/contrib/iparapheur/migrations/0006_iparapheur_wsdl_endpoint_location.py
$ passerelle-manage migrate_schemas

HowDoWeDoDns

Pour les déploiements de Publik on a besoin d'une série de noms de domaine et il faut les demander au client; là on pourrait 1) leur pointer l'adresse IP du service pour faire un enregistrement de type A mais ça nous bloquerait ensuite si jamais on devait changer celle-ci (par exemple si on met de l'ip failover en amont, si on change de presta, etc.), 2) on pourrait leur demander de faire un CNAME vers le service, genre statis.example.net CNAME bi.entrouvert.org. mais si jamais on se trouve devoir ou décider de distribuer les clients différemments, ça va nous bloquer aussi.

La solution adoptée est simplement de faire du nom de domaine un CNAME vers "nom de domaine".entrouvert.org, ainsi on a client par client, service par service, la main.

Exemple :

statistiques.nancy.fr      CNAME statistiques.nancy.fr.entrouvert.org.

https://perso.entrouvert.org/~fred/dns.html existe pour ridiculement faire ça (ajouter .entrouvert.org).

Ensuite, dans la configuration de notre côté (sur leucas), on fait le CNAME approprié. (dans cet exemple de statistiques.nancy.fr.entrouvert.org vers bi.entrouvert.org)

Zone *.dev.entrouvert.org

Il y a powerdns et du code et ça marche sans intervention manuelle.


HowDoWeDoEmail

Le SPAM


HowDoWeDoGit

Travailler dans une branche dont le nom suit le convention de nommage wip/XXXXX-mini-description, où XXXXX est le numéro de ticket où le développement est suivi.

 git checkout -b wip/XXXXX-mini-description

Une fois les commit faits dans la branche, pousser pour permette à Jenkins d'exécuter les tests :

git push origin wip/XXXXX-mini-description

Une fois la PR créée pour la branche, les tests seront exécutés par Jenkins et un mail vous sera envoyé en cas d'erreur.

Describe your changes in imperative mood, e.g. "make xyzzy do frotz" 
instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
to do frotz", as if you are giving orders to the codebase to change
its behaviour.
 -- http://git.kernel.org/cgit/git/git.git/tree/Documentation/SubmittingPatches

Gitea

On utilise gitea, installé ici : https://git.entrouvert.org/

Bugs et limitations connues :

Conseils & astuces git

(?) http://blogs.gnome.org/bastian/2015/02/12/a-guide-to-git-in-gnome-for-the-simple-minded/

Porcelaine git pour notre workflow (avant gitea)

J'ai créé ça :

https://pypi.org/project/git-redmine/

C'est sympatoche:

HowDoWeDoHotFixes


HowDoWeDoJavascript

Alléger notre dépendance à jQuery

La majorité des méthodes jQuery sont disponibles en JS. Même si c'est peu plus verbeux.

Liens utiles

Selecteurs DOM

// jQuery
const $elements = $('selecteurCSS')
// JS
// Le premier element
const element = document.querySelector('selecteurCSS')
// Tous les éléments
const elements = document.querySelectorAll('selecteurCSS')

Il est toujours possible ensuite d'utiliser une methode jQuery

$(elements).hide()

each VS forEach

// jQuery
$elements.each(function( index ) {
  console.log( index + ": " + $( this ).text() )
});
// JS
elem.forEach(function (currentValue, currentIndex, listObj) {
  console.log(`${currentIndex} : ${currentValue.textContent}`)
})

addClass, removeClass VS classList

// jQuery
$element.addClass('class')
// JS
element.classList.add(('class')

// jQuery
$element.removeClass('class')
// JS
element.classList.remove(('class')

ajax (fetch)

// jQuery
$.ajax(request)
  .done(function( data ) {})
// JS
const data = await fetch(url, requestParams)

paramètres inutilisés

On utilise _ pour nommer les paramètres inutilisés d'une fonction.


Jobs pipeline

Deux jobs jenkins par projet : un job projectname et un job projectname-wip.
Les deux jobs utilisent le même Jenkinsfile, placé à la racine du dépôt git du projet projectname.

Le Jenkinsfile :

Une libraire est utilisé pour éviter la redondance entre les Jenkinsfile des différents projets (http://git.entrouvert.org/jenkins-lib.git/).

Documentation jenkins pipeline : https://jenkins.io/doc/book/pipeline/
Documentation jenkins shared library : https://jenkins.io/doc/book/pipeline/shared-libraries/

Job projectname

Job projectname-wip

Jobs classiques (déprécié)


HowDoWeDoLDAP

Configurer authentic pour le LDAP LE

BABA de la connexion à un LDAP

ldapsearch -H ldap[s]://hostname[:port]/ -b '' -s base -x +

On trouvera la liste des base DN dans l'attribut namingContexts .

Configuration


HowDoWeDoLogging

La configuration globale des logs se fera via des variables d'environnement positionnée au niveau de la configuration de systemd dans /etc/systemd/system.conf via la directive DefaultEnvironment. Sur un système en marche on fera ensuite systemctl daemon-reexec pour s'assurer du rechargement de la configuration, aussi on relancera les démons concernés.

Le niveau NOTICE n'existe pas en Python, on l'ajoutera et on lui donnera comme valeur 25.

DefaultEnvironment="SENTRY_DSN=https://a2009....ouvert.org/1" "GRAYLOG_URL=ufo.entrouvert.org:12203" 

mettre aussi dans /etc/environment pour que l'environnement utilisateur et système soit équivalent:

SENTRY_DSN=https://a20092f7b3da484abf8fc0a4ee2f7202:c9fab41dcde24b04a30ac01ffd3c2457@sentry.entrouvert.org/1

Sentry

Graylog

Dans les scripts

Configuration des loggers

Je commencerai avec quelques principes: Questions: Pour débugger:

HowDoWeDoPostgreSQL

Tuning

Utiliser http://pgtune.leopard.in.ua/

Entrer RAM et nombre max de connections parallèles (= (nombre de processus uwsgi + gunicorn qui pointent vers la base) * 1.5):

Attention ces valeurs ne concernent qu'une machine postgresql seule! Si d'autre processus tournent sur la même machine il faut diminuer la RAM allouée à postgresql pour en garder pour les autres processus

Autres ressources:

Et sinon, appeler Dalibo.

Pour les devs

$ psql
> \l               # liste les bases
> \c passerelle    # se connecter à cette base
> \dn              # liste des schémas
> set search_path="passerelle_dev_publik_love";
> \dt              # liste des tables (ayant ce shcéma)

HowDoWeDoProvisioning

L'application agent hobo d'authentic2 écoute les signaux pre_{save/delete} des utilisateurs, rôles, relations de parenté entre rôles et relation d'enrôlement entre utilisateurs et rôles. En fin de requête un thread est lancé qui génère des messages de type "notify" poussé en AMQP (via RabbitMQ) pour les autres services.

Les agents reçoivent et agissent en conséquence.

La clé unique de communication, c'est l'uuid pour les rôles et les utilisateurs, néanmoins pour des raisons de reprise si l'uuid n'est pas trouvé on essaie de retrouver via le slug ou le nom dans le cas des rôles.

Dans les applications utilisant django-mellon, le mapping entre utilisateur NameID est stocké via le modèle UserSAMLIdentifier, le username est aussi généré en tronquant le NameID à 31 caractères; et c'est mappé sur un champ uuid d'un nouveau modèle Role (class Role(Group)) pour les rôles.

Par ailleurs, lors du SSO, l'assertion contient un attribut role-slug qui contient la liste des uuid de rôles.


NE PAS UTILISER, preferez https://dev.entrouvert.org/projects/prod-eo/wiki/HowDoWeDoPublikDomainNameChangeSurLeSaas

HowDoWeDoPublikDomainNameChange (pas sur le SaaS)

DNS

S'assurer que les noms de domaine existent. Sur un hébérgement on-premise, si besoin, taper les noms dans /etc/hosts.

Certificats

Obtenir le certificat pour le nouveau domaine. Placer dans /etc/ssl/{private,certs} ou /etc/nginx/ssl/.

NGINX

Créer le fichier de conf déclarant le nouveau certificat et sa clé. Ex: /etc/nginx/includes/wildcard.demarches.grenoblealpesmetropole.fr.conf

  ssl_certificate   /etc/nginx/ssl/wildcard.demarches.grenoblealpesmetropole.fr.crt;
  ssl_certificate_key   /etc/nginx/ssl/wildcard.demarches.grenoblealpesmetropole.fr.key;

Page de maintenance

Configurer le mode maintenance de Nginx:

Créer un fichier de configuration du mode maintenance: /etc/nginx/includes/maintenance.conf

    if (-f $document_root/maintenance.html) {
        set $maintenance 1;
    }

    if ($maintenance = 1) {
         return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
         rewrite ^(.*)$ /maintenance.html break;
    }


Créer le fichier /usr/share/nginx/html/maintenance.html et y poser le message de maintenance en HTML.

Déclarer un vhost pour l'ancien nom de domaine, avec la conf SSL, et de la page de maintenance. Ex:

  server {
       listen 443 ssl;
       server_name accueil.demarches.lametro.fr;

       include includes/ssl.conf;
       include includes/wildcard.demarches.lametro.fr.conf;

       include includes/maintenance.conf;
  }

Test de la config:

sudo nginx -t

et reload si tout va bien.

Services

Tenants

Rénommer les répértoires des tenants:

  sudo -u authentic-multitenant mv /var/lib/authentic2-multitenant/tenants/connexion.demarches.lametro.fr{,.invalid.migration}
  sudo -u bijoe mv /var/lib/bijoe/tenants/statistiques.demarches.lametro.fr{,.invalid.migration}
  sudo -u chrono mv /var/lib/chrono/tenants/agendas.demarches.lametro.fr{,.invalid.migration}
  sudo -u combo mv /var/lib/combo/tenants/portail-agent.demarches.lametro.fr{,.invalid.migration}
  sudo -u combo mv /var/lib/combo/tenants/demarches.lametro.fr{,.invalid.migration}
  sudo -u hobo mv /var/lib/hobo/tenants/hobo.demarches.lametro.fr{,.invalid.migration}
  sudo -u fargo mv /var/lib/fargo/tenants/porte-documents.demarches.lametro.fr{,.invalid.migration}
  sudo -u passerelle mv /var/lib/passerelle/tenants/passerelle.demarches.lametro.fr{,.invalid.migration}
  sudo -u wcs mv /var/lib/wcs/services.demarches.lametro.fr{,.invalid.migration}
  sudo -u welco mv /var/lib/welco/tenants/accueil.demarches.lametro.fr{,.invalid.migration}

Schémas des bases des données

Exporter les schemas pour toutes les briques, sauf wcs, en remplaçant l'ancien nom de domaine par le nouveau:

cela permet d'automatiquement renommer les issues dans mellon.UserSAMLIdentifier, les métadonnées des SP dans la base d'Authentic.

Pour chaque service

Authentic

Combo, Welco, Passerelle, Chrono, Fargo, Bijoe

Hobo

Bijoe

WCS

Renommer les fichiers avec les métadonnées d'authentic

mv idp-https-connexion.demarches.lametro.fr-idp-saml2-metadata-metadata.xml idp-https-connexion.demarches.grenoblealpesmetropole.fr-idp-saml2-metadata-metadata.xml

et y remplacer l'ancien nom de domaine par le nouveau. Ex: lametro par grenoblealpesmetropole

Mettre à jour le fichier config.pck du tenant (en faisant une sauvegarde au préalable):

import pickle
data = pickle.load(file('config.pck'))

data['idp']['https-connexion.demarches.grenoblealpesmetropole.fr-idp-saml2-metadata'] = data['idp']['https-connexion.demarches.lametro.fr-idp-saml2-metadata']
data['idp']['https-connexion.demarches.grenoblealpesmetropole.fr-idp-saml2-metadata']['metadata'] = data['idp']['https-connexion.demarches.grenoblealpesmetropole.fr-idp-saml2-metadata']['metadata'].replace('lametro', 'grenoblealpesmetropole')
data['idp']['https-connexion.demarches.grenoblealpesmetropole.fr-idp-saml2-metadata']['metadata_url'] = data['idp']['https-connexion.demarches.grenoblealpesmetropole.fr-idp-saml2-metadata']['metadata_url'].replace('lametro', 'grenoblealpesmetropole')
data['idp'].pop('https-connexion.demarches.lametro.fr-idp-saml2-metadata')

data['saml_identities']['registration-url'] = data['saml_identities']['registration-url'].replace('lametro', 'grenoblealpesmetropole')

data['sp']['saml2_base_url'] = data['sp']['saml2_base_url'].replace('lametro', 'grenoblealpesmetropole')
data['sp']['saml2_providerid'] = data['sp']['saml2_providerid'].replace('lametro', 'grenoblealpesmetropole')

data['misc']['frontoffice-url'] = data['misc']['frontoffice-url'].replace('lametro', 'grenoblealpesmetropole')
data['misc']['homepage-redirect-url'] = data['misc']['homepage-redirect-url'].replace('lametro', 'grenoblealpesmetropole')

# optionnel
data['postgresql']['database'] = data['postgresql']['database'].replace('lametro', 'grenoblealpesmetropole')

with open('new_config.pck', 'w') as conf:
    pickle.dump(data, conf)

Vérifier les dans /formsdefs/, /workflows/, /mail-templates/ s'il y a des références en dur vers le nom de domaine et le remplacer.

Création des nouveaux schémas

Importer les dumps créés plus haut:

sudo -u hobo psql < hobo.sql
sudo -u combo psql < combo.sql
sudo -u passerelle psql < passerelle.sql
sudo -u welco psql < welco.sql
sudo -u authentic-multitenant psql authentic2_multitenant < authentic.sql
sudo -u fargo psql < fargo.sql
sudo -u chrono psql < chrono.sql
sudo -u bijoe psql < bijoe.sql

Renommer les répértoires des tenants

sudo -u authentic-multitenant mv /var/lib/authentic2-multitenant/tenants/connexion.demarches.lametro.fr.invalid.migration /var/lib/authentic2-multitenant/tenants/connexion.demarches.grenoblealpesmetropole.fr
sudo -u bijoe mv /var/lib/bijoe/tenants/statistiques.demarches.lametro.fr.invalid.migration /var/lib/bijoe/tenants/statistiques.demarches.grenoblealpesmetropole.fr
sudo -u chrono mv /var/lib/chrono/tenants/agendas.demarches.lametro.fr.invalid.migration /var/lib/chrono/tenants/agendas.demarches.grenoblealpesmetropole.fr
sudo -u combo mv /var/lib/combo/tenants/portail-agent.demarches.lametro.fr.invalid.migration /var/lib/combo/tenants/portail-agent.demarches.grenoblealpesmetropole.fr
sudo -u combo mv /var/lib/combo/tenants/demarches.lametro.fr.invalid.migration /var/lib/combo/tenants/demarches.grenoblealpesmetropole.fr
sudo -u hobo mv /var/lib/hobo/tenants/hobo.demarches.lametro.fr.invalid.migration /var/lib/hobo/tenants/hobo.demarches.grenoblealpesmetropole.fr
sudo -u fargo mv /var/lib/fargo/tenants/porte-documents.demarches.lametro.fr.invalid.migration /var/lib/fargo/tenants/porte-documents.demarches.grenoblealpesmetropole.fr
sudo -u passerelle mv /var/lib/passerelle/tenants/passerelle.demarches.lametro.fr.invalid.migration /var/lib/passerelle/tenants/passerelle.demarches.grenoblealpesmetropole.fr
sudo -u wcs mv /var/lib/wcs/services.demarches.lametro.fr.invalid.migration /var/lib/wcs/services.demarches.grenoblealpesmetropole.fr
sudo -u welco mv /var/lib/welco/tenants/accueil.demarches.lametro.fr.invalid.migration /var/lib/welco/tenants/accueil.demarches.grenoblealpesmetropole.fr

Démarrer les services et les crons:

sudo systemctl start authentic2-multitenant bijoe chrono combo fargo hobo passerelle wcs welco
sudo vi /etc/cron.d/wcs

Retrait de la page de maintenance et redirection vers le nouveau domaine:

  server {
       listen 443 ssl;
       server_name accueil.demarches.lametro.fr;

       include includes/ssl.conf;
       include includes/wildcard.demarches.lametro.fr.conf;

       # include includes/maintenance.conf;
       return 302 https://accueil.demarches.lametro.fr$request_uri;
  }

Test de la config:

sudo nginx -t

et reload si tout va bien.

Warnings

FranceConnect

Il suffit de déclarer les nouvelles URLs de retour (callback et redirection de déconnexion) en plus des anciennes, puis de retirer les anciennes un fois la migration faite. Il n'y a pas de validation faites sur ces URLs dans le back-office de FranceConnect donc pas de blocage possible.

wcs

Les demandes peuvent contenir des URLs avec l'ancien nom de domaine (typiquement les URLs vers les résas dans Chrono). Les appels webservice vers ces URLs vont échouer car ne seront pas signés.
Il faut identifier toutes les demandes ayant des URLs avec l'ancien nom de domaine dans data et workflow_data et mettre à jour.


Changement du nom de domaine de base d’une instance de Publik sur le SaaS

Prérequis

DNS / Certificats

Puppet etc.

haproxy

Puppet etc. pareil qu'un déploiement, i.e. modif publik.map, ex: modules/haproxy/files/prod.saas.entrouvert.org/publik.map

Migration des chemins des pièces jointes dans wcs

Uniquement pour les instances déployées avant le 11 novembre 2021 (#21731)


from wcs.carddef import CardDef
from wcs.formdef import FormDef

for formdef in FormDef.select(ignore_migration=True) + CardDef.select(ignore_migration=True):
    for formdata in formdef.data_class().select_iterator(ignore_errors=True, itersize=200):
        formdata.store()

sudo -u wcs wcs-manage runscript -d formulaires.demarches.maville.fr fichierdemigrationcidessus.py

FC : ajout des callback vers nouveau nom de domaine dans l'interface partenaire

En plus des callback déjà présent. Les anciens pourront être supprimés après la migration.

https://partenaires.franceconnect.gouv.fr/login

Une fois la modif faite, surveiller les mails envoyés à franceconnect@entrouvert.com (de support.partenaires@franceconnect.gouv.fr) : #69830

En cas de changement de nom de domaine uniquement sur certaines briques

Si on me migre pas l'ensemble des applications, il faut d'abord mettre en place un menu personnalisé : ("PUBLIK_EXPLICIT_MENU": true).
Sinon problèmes d'affichage du menu (#54359#note-85).
Ça reste scabreux
#66280

Opération de migration

Mettre la plateforme en mode maintenance

Via le menu maintenance dans hobo :

Attention il faut que les IP autorisées aient été configurés sur l'infra, ex: #66099 .

Mise en place des tenants avec les nouveaux noms

On commence par les services "lambda", commande la commande hobo rename_service :

hobo-manage tenant_command rename_service https://demarches.maville.fr/ https://nouvellesdemarches.maville.fr/ -d hobo.demarches.maville.fr
hobo-manage tenant_command rename_service https://formulaires.demarches.maville.fr/ https://formulaires.nouvellesdemarches.maville.fr/ -d hobo.demarches.maville.fr
...

On termine par hobo via la commande rename_hobo_service:

hobo-manage rename_hobo_service https://hobo.demarches.maville.fr/ https://hobo.nouvellesdemarches.maville.fr/

Sur les déploiements multi collectivités, pour les services lambda la commande rename_service doit être lancée sur le tenant hobo qui contrôle le service :

hobo-manage tenant_command rename_service https://demarches.ville1.fr/ https://nouvellesdemarches.ville1.fr/ -d hobo.demarches.ville1.fr
hobo-manage tenant_command rename_service https://demarches.ville2.fr/ https://nouvellesdemarches.ville2.fr/ -d hobo.demarches.ville2.fr

Les hobo secondaires se migrent comme des services lambda, en s'adressant au tenant du hobo primaire :

hobo-manage tenant_command rename_service https://hobo.demarches.ville1.fr/ https://hobo.nouvellesdemarches.ville1.fr/ -d hobo.demarches.metrolpole.fr
hobo-manage tenant_command rename_service https://hobo.demarches.ville2.fr/ https://hobo.nouvellesdemarches.ville2.fr/ -d hobo.demarches.metrolpole.fr

Modifications manuelles coté authentic si relié à un annuaire en SAML

- "MELLON_PRIVATE_KEY": "/var/lib/authentic2-multitenant/tenants/connexion.demarches.maville.fr/saml.key",
+ "MELLON_PRIVATE_KEY": "/var/lib/authentic2-multitenant/tenants/connexion.nouvellesdemarches.maville.fr/saml.key",
- "MELLON_PUBLIC_KEYS": [
    "/var/lib/authentic2-multitenant/tenants/connexion.demarches.maville.fr/saml.crt" 
  ],
+ "MELLON_PUBLIC_KEYS": [
    "/var/lib/authentic2-multitenant/tenants/connexion.nouvellesdemarches.maville.fr/saml.crt" 
  ],

Modifications manuelles coté bijoe (si wcs a changé de nom, sinon rien à faire)

Regarder wcs-olap.ini (dans le répertoire du tenant bijoe), une nouvelle section a du apparaître : https://formulaires.nouvellesdemarches.maville.fr/ (en plus de https://formulaires.demarches.maville.fr/)

Sur la base de donnée bijoe, il faut supprimer le schéma de la section https://formulaires.demarches.maville.fr/ :

DROP SCHEMA formulaires_demarches_maville_fr;

Dans wcs-olap.ini, supprimer la section https://formulaires.demarches.maville.fr/.

Dans le répertoire du tenant, supprimer l'ancien modèle de données : rm /var/lib/bijoe/tenants/xxx/schemas/formulaires_demarches_maville_fr.model

Éventuellement relancer une synchro : sudo -u bijoe /usr/bin/wcs-olap --all /var/lib/bijoe/tenants/xxx/wcs-olap.ini (ou attendre la nuit que ça se fasse tout seul)

Mettre en place des redirections des anciens nom vers les nouveaux noms

Via puppet, modification haproxy pour rediriger automatiquement tous les requêtes faites sur l'ancien nom vers le nouveau nom.

--- a/modules/haproxy/files/prod.saas.entrouvert.org/publik.map
+++ b/modules/haproxy/files/prod.saas.entrouvert.org/publik.map 
-demarches.maville.fr combo-balancer
-formulaires.demarches.maville.fr wcs-balancer
....
+demarches.maville.fr redirect-map
+formulaires.demarches.maville.fr redirect-map
.....

--- a/modules/haproxy/files/prod.saas.entrouvert.org/redirect.map
+++ b/modules/haproxy/files/prod.saas.entrouvert.org/redirect.map

+demarches.maville.fr https://nouvellesdemarches.maville.fr
+formulaires.demarches.maville.fr https://formulaires.nouvellesdemarches.maville.fr
....

Pour les impatients, sur node1/node2 forcer la mise à jour via puppet : sudo puppet agent -t.

Désactiver le mode maintenance

Postface

Dans HowDoWeDoPublikDomainNameChange il est écrit pour FranceConnect :

S'assurer que côté FranceConnect il y a juste changement d'URLs d'authentic et non la création d'un nouveau compte avec des nouveaux client_id et client_secret. Cela permet (en théorie) d'avoir les mêmes subs pour les comptes déjà fédérés.

Retour d'expérience effectué :

Ci-dessous les tickets où l'on a appliqué la procédure et les problèmes rencontrés lors de celle-ci :
#72194
#68266


HowDoWeDoPython3Migration

On essaie au maximum d'avoir un code commun entre Python 2 et Python 3; souvent c'est possible de manière native, le reste du temps via six (pour les applications django six est dispo de base dans django.utils.six).

Éléments usuels :

Pour la gestion des encodages, utiliser force_text/smart_text/smart_bytes de Django, plutôt que des appels à unicode() ou str().

Via six :

La bibliothèque standard a été un petit peu rangée et certains modules ne se trouvent plus là où ils étaient; six assure la transition.

Quand il faut nécessairement du code différent entre Python 2 et Python 3, plutôt que comparer les versions via sys.version_info il existe six.PY3 (vrai en Python 3) et six.PY2 (vrai en Python 2).


HowDoWeDoPythonPackaging

Pousser sur pypi

Mettre dans ~/.pypirc

[distutils]                                                       
username: entrouvert
password: voir sur https://dev.entrouvert.org/projects/sysadmin/wiki/Mots_de_passe#Pypi

Installer twine :

apt install twine

Ensuite il faut construire la distribution des sources et binaire, pour un paquet mixte Python2/3 :

python3 setup.py sdist bdist_wheel

Ensuite il faut uploader les archives :

twine upload dist/*

HowDoWeDoRelease

Dans l'ordre :

Traductions

whatever-manage makemessages --all

Puis faire les traductions, pousser sur main, attendre que Jenkins soit ok.

Tag

Un script est disponible dans le dépôt misc-fred, qui regarde le dernier tag posé, incrémente et envoie le nouveau tag,

~/..../misc-fred/bin/tag

Et aller dans jenkins pour demander un nouveau build du module (il est possible d'utiliser "Restart from stage" pour lancer uniquement l'étape de packaging).

Il y a un flag -b qui ouvre jenkins sur la bonne page (il faut que le navigateur par défaut de debian soit démarré avec déjà une session jenkins).

Ensuite, attendre que le build soit terminé, il aura envoyé la nouvelle version du module dans le dépôt "entrouvert-testing".

Déploiement

Le script eoptasks permet de lancer des commandes sur tous les serveurs, dans le cadre d'une mise à jour des serveurs de test, on pourra utiliser :

~/..../eoptasks/eoptasks.py -k test/publik apt.upgrade

Ça utilise tmux pour fournir un accès aux différentes sessions ssh, pour une navigation basique, ctrl-b w permet de lister les différentes sessions.


HowDoWeDoSubmitFormsToWebservices

Dates

Les valeurs _raw des champs de type date dans wcs sont automatiquement sérialisées lors de l'envoi au webservice.
De ce fait, le paramètre doit être configuré de la sorte:

Données à envoyer dans le corps de la requête
event_date =form_var_event_date_raw

HowDoWeDoSupportTechnique

Un binôme est asssigné au support technique pendant deux mois.

L'objectif est de "libérer" les devs du suivi quotidien des projets pour permettre de rester concentré·es sur les développements; cela en gardant pour les CPF l'assurance qu'une réponse sera fournie.

Missions

Historique des binômes

Décompte

nombre de participation, dernière participation,

2

3


HowDoWeDoTests

Ressources

Tests manuels

Pense bête py.test&Django

Une fois qu'on a tox de configuré pour lancer les tests py.test on peut faire pas mal de choses amusantes, je donne mes exemples dans le contexte du projet authentic2.

Utiliser un debugger alternatif

Par défaut, utiliser l'option --pdb ou taper import pdb; pdb.set_trace() dans le code ouvrira l'interpréteur pdb de base.
Il est possible d'utiliser un autre interpréteur, par exemple IPython.

L'environnement installé par tox n'inclut pas IPython. Il faut donc injecter globalement la dépendance via un plugin : pip install tox-ipdb-plugin.

Ensuite, il faut dire à pytest d'utiliser cet interpréteur pour pdb. Là encore un peu de gymnastique pour que la configuration soit globale, il faut ajouter deux variables d'environnement dans son .bashrc :

export PYTEST_ADDOPTS='--pdbcls=IPython.terminal.debugger:TerminalPdb'
export TOX_TESTENV_PASSENV='PYTEST_ADDOPTS'

Voilà, vive l'autocomplétion.


HowDoWeDoThemes

(work in progress)

Le dévéloppement d'une intégration graphique exige un environnement de développement local, cf https://doc-publik.entrouvert.com/dev/installation-developpeur/

publik-base-theme

Le module publik-base-theme malgré son nom est le dépôt de (presque) toutes nos intégrations graphiques.

La liste est établie (lors de l'appel à make) en parcourant les répertoires sous static/, en tirant les informations de fichiers config.json, ex static/publik/config.json :

{
  "label": "Publik",
  "variables": {
    "theme_color": "#E80E89" 
  }
}

Style CSS

Dans publik-base-theme/static, il y a donc un répertoire par intégration. Celui-ci doit contenir un fichier style.css. On utilise le préprocesseur sass pour le créer à partir d'un fichier style.scss, ce travail est assuré via des règles dans le Makefile, la cible pour la création des fichiers style.css s'appelle "css" → make css exécuté depuis le répertoire publik-base-theme créera les fichiers style.css des différentes intégrations. Il est bien sûr également possible de viser un seul fichier, ex: make static/publik/style.css.

Le fichier style.scss sert à importer différents fichiers, généralement :

@import 'vars';
@import '../includes/publik';
@import 'custom';

La définition des styles de Publik vient de ../includes/publik, les deux autres fichiers servent à définir les spécificités locales.

Le fichier _vars.scss peut définir une série de variables (liste complète publiée sur https://doc.entrouvert.org/publik-base-theme/dev/misc-scss.html) qui permettent de paramétrer le rendu général du site, généralement en y appliquant les valeurs tirées d'une maquette ou du site servant de modèle.

@charset "UTF-8";

$primary-color: #1DA1AE;

$font-color: #565656;
$font-size: 13px;
$font-family: sans-serif;
$nav-background: $primary-color;
$nav-color: white;
$nav-active-color: darken($primary-color, 20%);
$border-radius: 3px;
$button-background: $primary-color;
$title-background: $primary-color;
$title-color: white;
$footer-background: transparent;
$footer-color: $font-color;

Pour aller au-delà de ce que ce paramétrage permet; le fichier _custom.scss peut accueillir des règles CSS supplémentaires :

#header {
    background: url(images/bandeau.jpg) no-repeat scroll left bottom;
    height: 180px;
}

body {
    background: url(images/bg_header.png) repeat-x scroll 0 2px;
}
[...]

Si on se trouve à copier/coller ou répéter des trucs de _custom.scss en _custom.scss, on doit sans doute réfléchir et voir pour intégrer ça dans les fichiers scss partagés.

Documentation publique des classes css

Compilation dynamique et livereload

En développement, il peut être pratique de relancer la compilation des thèmes lorsque des fichiers sont modifiés et de rafrchair les pages correspondantes dans le navigateur automatiqument. Pour cela, vous pouvez utiliser le script ./compile-and-reload.sh. Pour que cela fonctionne, assurez vous que votre environnement de développement est à jour (https://doc-publik.entrouvert.com/dev/installation-developpeur/#Mettre-%C3%A0-jour-son-installation) et que
~/.config/publik/settings/combo/settings.d/local.py contiennent bien LIVERELOAD_ENABLED = True.

D'autres n'utilisant pas livereload sont présentées ci-dessous :

# La première fois, penser à lancer aussi:
#   sudo apt install iwatch
iwatch -r -t '.scss' -e modify -c "make css" .

Lorsque cette commande est active, chaque modification d'un fichier SCSS dans le projet déclenche une recompilation du ou des thèmes correspondants.

Alternativement le script https://git.entrouvert.org/misc-fred.git/tree/bin/sassw assure ce taf.

Pour rafraîchir automatiquement le CSS dans le navigateur, vous pouvez installer cette extension Firefox : https://addons.mozilla.org/en-US/firefox/addon/content-override-watch/

Pour la configurer, installez l'application hôte en python qui charge le contenu local :

pip install cow-web-ext
cow-web-ext install

Puis configurez les mappings vers les fichiers dans les paramètres de l'extension dans firefox (Settings => Extensions & Thèmes => Content Override & Watch). Pour par exemple charger le CSS depuis votre dossier publik-base-theme :

.*\/static\/([^\/]*)\/style.css  => ~/src/publik-base-theme/static/$1/style.css

Utilisez l'icone dans la barre d'outils pour activer / désactiver la synchronisation avec le CSS local. Ça fonctionne aussi sur les sites en recette & prod, et permet de tester les changements de CSS directement sur du contenu de production.

Templates

Les templates Django sont dans le répertoire templates/; ils surchargent une partie des templates natifs des différents modules, pour diverses raisons (spécificités à Publik, paresse, etc.).

À éviter, il y a la possibilité pour un thème, de redéfinir de manière spécifique un template donné, en le plaçant sous templates/variants/$theme/, par exemple templates/variants/nancy-2017/combo/wcs/forms_of_category.html.

Images

Elles sont normalement rangées dans le répertoire img/ (mais ce n'est pas encore systématique).

Pour des petites images, il peut être intéressant d'optimiser le chargement en incluant directement l'image dans le fichier CSS, en utilisant une URI data. Pour assurer ce travail il y a une cible data_uris dans le Makefile, qui appelle le script make_data_uris.py sur un répertoire donné, ex :

python make_data_uris.py static/grandlyon-gnm/

Cela crée un fichier _data_uris.scss qui peut être inclus dans le thème et les images peuvent alors être référencées ainsi : url($data_uri_cadre_de_vie) (data_uri_ + le nom de fichier sans l'extension).

Icônes du tableau de bord

Inclure ../includes/dashboard dans les scss et ajouter le nécessaire au Makefile pour générer les images dans les couleurs désirées, ex :

cd src/ && python render-imgs-dashboard.py ../static/chateauroux/img/ --normal 333333 --selected 0779B7 --title FFFFFF --title-width 80

Icônes des catégories

Inclure ../includes/categories dans les scss et ajouter au Makefile.

cd src/ && python render-imgs-categories.py ../static/orleans/img/ --primary f05923 --secondary 34697D

Polices de caractère

On évite la récupération de polices depuis les CDN de Google ou autre, on incorpore directement dans publik-base-theme les polices (pour lesquelles les licences autorisent cela, bien sûr). On se trouve ainsi dans static/includes/ avec une série de fichiers _font-*.scss, ex: _font-montserrat.scss.

Pour donner accès à une police, on ajoutera donc un import de la forme :

@import '../includes/font-montserrat';

On inclut uniquement les versions woff2 et woff car c'est désormais pris en charge "partout" (>IE8).


Détails de la mécanique bas niveau

(Cette section n'est pas nécessaire pour la réalisation de thèmes.)

On définit un thème pour Combo ; d'abord de manière classique, par exemple un "common.html" qui va de <html> à </html> et puis les différents modèles de page, "page_template.html" et "page_template_sidebar.html" etc. qui {% extends "common.html" %}.

On précise les URL vers des ressources (css, js, images…) de manière absolue, il y a pour ça un {{site_base}} qui est utile; ex :

<script src="{{site_base}}{% xstatic 'jquery' 'jquery.min.js' %}"></script>
<script src="{{site_base}}{% static 'js/combo.public.js' %}"></script>

Ensuite, les fichiers base.html des applications peuvent être ajoutés (idéalement les applications cherchent toutes d'abord un /$app/base.html, donc les templates ne se mangent pas l'espace du /base.html). Ces fichiers démarrent sur un modèle simple, d'une ligne, {% extends theme_base %}. Cela créera à la volée un template avec un squelette généré sur base de celui servi par combo.

Pour ce faire l'application (en fait un context processor d'hobo) se base sur un paramètre THEME_SKELETON_URL, qui pointe vers le combo, ex :

THEME_SKELETON_URL = 'http://combo-test-theme.127.0.0.1.xip.io:8000/__skeleton__/'

Le context processor ajoute l'url demandée (paramètre source) et avec ça Combo trouve la page correspondant à l'application (en matchant le mieux possible l'url donnée, ce qui permet par exemple d'avoir une page pointant vers http://wcs.example.net/etat-civil/ et une autre pointant vers http://wcs/sport/, et y avoir des différences de contenu). Combo fait le rendu de cette page en remplaçant les zones laissées vides (sans cellules) par des appels de bloc django (ex : {% block content }{ endblock %}), ceux-ci seront alors interprété quand le context processor créera un objet Template() à partir du contenu de la page ainsi récupérée.

C'est possible d'ajouter des zones qui donneront des blocs sans pour autant donner des zones présentées à la composition des pages dans combo, il faut utiliser le templatetag skeleton_extra_placeholder, ex : {% skeleton_extra_placeholder 'extra-head' } ou { skeleton_extra_placeholder 'extra-body-args' %}; c'est ainsi possible de créer une structure correspondant à celle attendue par l'application.

Elle pourrait être composée directement au niveau de combo mais ça peut alourdir mochement le code, par exemple si on a authentic qui attend body-args et une autre qui atend autre-body-args, et ainsi de suite :

<body {% block body-args %}{% endblock %} {% block autre-body-args %}{% endblock %} ...>

Pour éviter ça, on peut mettre un seul bloc, et dans le $app/base.html, prolonger le extends par un mapping des blocs :

{% extends theme_base %}
{% block extra-body-args %}
  {% block bodyargs %}
  {% endblock %}
{% endblock %}

Définition intégration "light"

Mise en recettes et release du paquet deb publik-base-theme

Ça se passe dans de dépot publik-base-theme

  1. un fois ses commits validés, on peut pousser sur la branche principale (main)
  2. Jenkins va faire construire à partir de cette branche, à intervalles réguliers, et créer un paquet deb dans le dépôt 'unstable' d'EO
    - vérifiez que tout se finit bien ici : https://jenkins.entrouvert.org/job/publik-base-theme-deb/
  3. si les autres développeurs sont d'accords, on peut taguer une nouvelle version du dépôt Git : git tag -a v2.22
  4. Jenkins va aussi construire à partir du tag et créer un paquet de dans le dépôt 'testing' d'EO
    - vérifiez aussi que tout se passe bien
  5. on peut alors mettre à jour les recettes sur toutes les machines, on peut exécuter apt-get update && apt-get upgrade publik-base-theme
    - liste de toutes les machines de recette https://dev.entrouvert.org/projects/sysadmin/wiki/Mises_%C3%A0_jour_Publik#Recettes
    - on peut utiliser l'outil eotasks pour exécuter les commandes en parallèle sur les serveurs: [[sysadmin:Exécution_de_taches_sur_les_serveurs]]

HowDoWeDoTicketsTechniques

Créer un ticket sur redmine

On développe

Une fois que le ticket est passé (automatiquement) en "solution déployée"


HowDoWeDoTraductions

On suit globalement ce qui a été défini dans l'équipe de tradution GNOME; documents utiles :


HowDoWeDoUpgrades

Dépôts

Nos paquets sont distribués via des dépôts signés : https://deb.entrouvert.org/

Vous pouvez accepter notre clé GPG avec l'empreinte 27FF12846574F8A0EFFF7A84DF69CC342CCFEC25 en exécutant la commande suivante :

wget -O - https://deb.entrouvert.org/entrouvert.gpg | sudo apt-key add -

Configuration de apt

Afin de configurer apt pour récupérer les versions adaptées des logiciels issus des dépôts officiels, nous installons le paquet entrouvert-repository :

sudo apt install entrouvert-repository
sudo apt update

Mises-à-jour standards

Tous les seconds et quatrièmes jeudi nous livrons des mises-à-jours de tous les composants logiciels de Publik.

Pour les installer il est nécessaire d'executer:

sudo apt update
sudo apt full-upgrade

Mises-à-jour majeures : passage de Debian 8 ("Jessie") à Debian 9 ("Stretch")

1. Nettoyer les fichiers de préférences apt qui concernent Debian Jessie.

2. Adapter manuellement la configuration des dépôts :

sed 's/jessie/stretch/' -i /etc/apt/sources.list
sed 's/jessie/stretch/' -i /etc/apt/sources.list.d/entrouvert.list
apt update

S'assurer que le depot stretch-backports est bien présent dans /etc/apt/sources.list. Il est obligatoire pour avoir la version 1.11 de Django.

Supprimer d'éventuelles références additionnelles à nos dépôts.

3. Configurer apt:

apt install entrouvert-repository
# pour un serveur de recette, installer également entrouvert-repository-testing
apt update

4. Installer les mises-à-jours :

Attention: lors de la mise à jour du serveur openssh ne pas écraser le fichier de conf avec celui du paquet, pour ne pas changer le port d'écoute.
(de manière générale, ne pas écraser les configs qui auraient été modifiées)

apt full-upgrade

5. Si le serveur tourne w.c.s. vérifier l'installation de libreoffice :

apt install libreoffice

6. Migrer de version PostgreSQL (vers 9.6)

En utilisant pg_upgradecluster, cf la documentation du paquet postgresql pour les détails d'utilisation.

7. Relancer les services :

systemctl restart authentic2-multitenant bijoe chrono combo corbo fargo hobo passerelle wcs

Mises-à-jour majeures : passage de Debian 9 ("Stretch") à Debian 10 ("Buster")

Préliminaire : la machine doit être parfaitement à jour. Lancer tout d'abord une mise à jour classique « apt update && apt full-upgrade »

1. Nettoyer les fichiers de préférences apt qui concernent Debian Buster et inférieurs.

2. Adapter manuellement la configuration des dépôts :

# sed 's/stretch/buster/' -i /etc/apt/sources.list

S'assurer que le depot buster-backports est bien présent dans /etc/apt/sources.list.d/.

3. Configurer apt:

# apt install entrouvert-archive-keyring entrouvert-repository entrouvert-repository-hotfix
## pour un serveur de recette : apt install entrouvert-repository-testing
# apt update

4. Commencer par mettre à jour postgresql et réindexer les bases, ensuite installer les autres mises-à-jours :

# apt update
# apt install postgresql
# sudo -u postgres reindexdb --all
# apt full-upgrade

5. Migrer le cluster PostgreSQL vers la version 11

En utilisant pg_upgradecluster, cf la documentation du paquet postgresql pour les détails d'utilisation.

Mise à jour majeure de Debian 10 ("Buster") vers Debian 11 ("Bullseye")

https://dev.entrouvert.org/projects/publik/wiki/Mont%C3%A9eVersionBullseye


HowDoWeKi (ah ah)

Quand on fait une modification on en écrit un résumé/description dans le champ "commentaire", comme ça c'est mentionné dans les emails de notification et dans l'historique.


DevGuides

AdminGuides

Études