Jelajahi Sumber

Upgrade since last project

Pierre-Yves Barriat 2 tahun lalu
induk
melakukan
ec4a4f6268
100 mengubah file dengan 4286 tambahan dan 366 penghapusan
  1. 6 1
      .gitignore
  2. 0 2
      README.md
  3. 0 320
      Report/Projet_brevet.md
  4. TEMPAT SAMPAH
      Report/Projet_brevet.pdf
  5. TEMPAT SAMPAH
      Report/assets/dia_nc_improved.png
  6. 0 43
      Report/compile.sh
  7. 19 0
      dev/README.md
  8. 11 0
      dev/README.txt
  9. 159 0
      dev/Vagrantfile
  10. 14 0
      dev/provisioning/ansible/grafana.yml
  11. 18 0
      dev/provisioning/ansible/haproxy.yml
  12. 15 0
      dev/provisioning/ansible/mariadb.yml
  13. 19 0
      dev/provisioning/ansible/nextcloud.yml
  14. 14 0
      dev/provisioning/ansible/node_exporter.yml
  15. 14 0
      dev/provisioning/ansible/prometheus.yml
  16. 14 0
      dev/provisioning/ansible/redis.yml
  17. 5 0
      dev/provisioning/ansible/roles/grafana/defaults/main.yml
  18. 5 0
      dev/provisioning/ansible/roles/grafana/handlers/main.yml
  19. 21 0
      dev/provisioning/ansible/roles/grafana/tasks/main.yml
  20. 35 0
      dev/provisioning/ansible/roles/grafana/tasks/setup/CentOS.yml
  21. 3 0
      dev/provisioning/ansible/roles/grafana/tasks/setup/RedHat.yml
  22. 462 0
      dev/provisioning/ansible/roles/grafana/templates/grafana.conf.j2
  23. 18 0
      dev/provisioning/ansible/roles/haproxy/defaults/main.yml
  24. 3 0
      dev/provisioning/ansible/roles/haproxy/handlers/main.yml
  25. 67 0
      dev/provisioning/ansible/roles/haproxy/tasks/main.yml
  26. 41 0
      dev/provisioning/ansible/roles/haproxy/templates/haproxy.cfg.j2
  27. 42 0
      dev/provisioning/ansible/roles/mariadb/defaults/main.yml
  28. 6 0
      dev/provisioning/ansible/roles/mariadb/handlers/main.yml
  29. 67 0
      dev/provisioning/ansible/roles/mariadb/tasks/config/secure-installation.yml
  30. 31 0
      dev/provisioning/ansible/roles/mariadb/tasks/config/secure.yml
  31. 16 0
      dev/provisioning/ansible/roles/mariadb/tasks/config/template.yml
  32. 11 0
      dev/provisioning/ansible/roles/mariadb/tasks/database/databases.yml
  33. 15 0
      dev/provisioning/ansible/roles/mariadb/tasks/database/users.yml
  34. 20 0
      dev/provisioning/ansible/roles/mariadb/tasks/main.yml
  35. 17 0
      dev/provisioning/ansible/roles/mariadb/tasks/setup/RedHat.yml
  36. 13 0
      dev/provisioning/ansible/roles/mariadb/tasks/setup/Suse.yml
  37. 33 0
      dev/provisioning/ansible/roles/mariadb/templates/galera.j2
  38. 9 0
      dev/provisioning/ansible/roles/mariadb/templates/mariadb-server.repo.j2
  39. 5 0
      dev/provisioning/ansible/roles/mariadb/templates/root-my.cnf.j2
  40. 22 0
      dev/provisioning/ansible/roles/mariadb/templates/server.j2
  41. 5 0
      dev/provisioning/ansible/roles/mariadb/templates/user-my.cnf.j2
  42. 12 0
      dev/provisioning/ansible/roles/mariadb/vars/RedHat.yml
  43. 9 0
      dev/provisioning/ansible/roles/mariadb/vars/Suse.yml
  44. 83 0
      dev/provisioning/ansible/roles/nextcloud/defaults/main.yml
  45. 4 0
      dev/provisioning/ansible/roles/nextcloud/files/apcu.config.php
  46. 15 0
      dev/provisioning/ansible/roles/nextcloud/files/apps.config.php
  47. 12 0
      dev/provisioning/ansible/roles/nextcloud/files/mysql_nextcloud.cnf
  48. TEMPAT SAMPAH
      dev/provisioning/ansible/roles/nextcloud/files/nextcloud_choosing_version.png
  49. 182 0
      dev/provisioning/ansible/roles/nextcloud/files/nextcloud_custom_mimetypemapping.json
  50. 0 0
      dev/provisioning/ansible/roles/nextcloud/files/nextcloud_file_name.xml
  51. 41 0
      dev/provisioning/ansible/roles/nextcloud/handlers/main.yml
  52. 56 0
      dev/provisioning/ansible/roles/nextcloud/tasks/main.yml
  53. 65 0
      dev/provisioning/ansible/roles/nextcloud/tasks/nc_download.yml
  54. 35 0
      dev/provisioning/ansible/roles/nextcloud/tasks/nc_install.yml
  55. 184 0
      dev/provisioning/ansible/roles/nextcloud/tasks/nc_setup.yml
  56. 102 0
      dev/provisioning/ansible/roles/nextcloud/tasks/prep_os/CentOS.yml
  57. 3 0
      dev/provisioning/ansible/roles/nextcloud/tasks/prep_os/RedHat.yml
  58. 57 0
      dev/provisioning/ansible/roles/nextcloud/tasks/prep_os/Suse.yml
  59. 117 0
      dev/provisioning/ansible/roles/nextcloud/tasks/prep_php/CentOS.yml
  60. 5 0
      dev/provisioning/ansible/roles/nextcloud/tasks/prep_php/RedHat.yml
  61. 76 0
      dev/provisioning/ansible/roles/nextcloud/tasks/prep_php/Suse.yml
  62. 51 0
      dev/provisioning/ansible/roles/nextcloud/tasks/selinux.yml
  63. 19 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/CentOS.yml
  64. 116 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/db_mysql.yml
  65. 28 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/db_postgresql.yml
  66. 69 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/http_apache.yml
  67. 90 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/http_nginx.yml
  68. 67 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/nc_apps.yml
  69. 51 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/php_install.yml
  70. 52 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/setup_env.yml
  71. 23 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/tls_installed.yml
  72. 39 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/tls_selfsigned.yml
  73. 31 0
      dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/tls_signed.yml
  74. 103 0
      dev/provisioning/ansible/roles/nextcloud/templates/apache2_nc.j2
  75. 4 0
      dev/provisioning/ansible/roles/nextcloud/templates/apcu_nc_ini.j2
  76. 26 0
      dev/provisioning/ansible/roles/nextcloud/templates/nextcloud_apache2.j2
  77. 207 0
      dev/provisioning/ansible/roles/nextcloud/templates/nginx_nc.j2
  78. 9 0
      dev/provisioning/ansible/roles/nextcloud/templates/nginx_php_handler.j2
  79. 13 0
      dev/provisioning/ansible/roles/nextcloud/templates/opcache_nc_ini.j2
  80. 11 0
      dev/provisioning/ansible/roles/nextcloud/templates/php_nc_ini.j2
  81. 9 0
      dev/provisioning/ansible/roles/nextcloud/templates/redis.config.php.j2
  82. 5 0
      dev/provisioning/ansible/roles/nextcloud/templates/root-my.cnf.j2
  83. 17 0
      dev/provisioning/ansible/roles/nextcloud/vars/main.yml
  84. 5 0
      dev/provisioning/ansible/roles/node_exporter/defaults/main.yml
  85. 14 0
      dev/provisioning/ansible/roles/node_exporter/files/node_exporter.service
  86. 70 0
      dev/provisioning/ansible/roles/node_exporter/tasks/main.yml
  87. 228 0
      dev/provisioning/ansible/roles/prometheus/defaults/main.yml
  88. 16 0
      dev/provisioning/ansible/roles/prometheus/files/alertmanager.service
  89. 18 0
      dev/provisioning/ansible/roles/prometheus/files/alertmanager.yml
  90. 17 0
      dev/provisioning/ansible/roles/prometheus/handlers/main.yml
  91. 88 0
      dev/provisioning/ansible/roles/prometheus/tasks/alertmanager.yml
  92. 69 0
      dev/provisioning/ansible/roles/prometheus/tasks/configure.yml
  93. 88 0
      dev/provisioning/ansible/roles/prometheus/tasks/download.yml
  94. 97 0
      dev/provisioning/ansible/roles/prometheus/tasks/install.yml
  95. 17 0
      dev/provisioning/ansible/roles/prometheus/tasks/main.yml
  96. 6 0
      dev/provisioning/ansible/roles/prometheus/templates/alert.rules.j2
  97. 85 0
      dev/provisioning/ansible/roles/prometheus/templates/prometheus.service.j2
  98. 34 0
      dev/provisioning/ansible/roles/prometheus/templates/prometheus.yml.j2
  99. 50 0
      dev/provisioning/ansible/roles/redis/defaults/main.yml
  100. 11 0
      dev/provisioning/ansible/roles/redis/handlers/main.yml

+ 6 - 1
.gitignore

@@ -1 +1,6 @@
-SandBox/
+sandbox/
+./dev/README.txt
+./report/old/
+./report/compile_2.sh
+./report/Projet_brevet.pdf
+./report/Complement_technique_Brevet_PYB.pdf

+ 0 - 2
README.md

@@ -1,5 +1,3 @@
 # Brevet
 
 Informaticien Expert
-
-## Creation d'un projet Redmine

+ 0 - 320
Report/Projet_brevet.md

@@ -1,320 +0,0 @@
----
-title: "Projet de premier brevet"
-author: [Pierre-Yves Barriat]
-date: "15 avril 2022"
-subject: "Examen d'avancement au grade d'informaticien-expert"
-keywords: [brevet, informaticien]
-#lang: "en"
-subtitle: "Examen d'avancement au grade d'informaticien-expert"
-option1: "**FGS :** 01108821"
-option2: "**Institut ELI - pôle ELIC**"
-option3: "**Dénomination de la fonction :** informaticien de recherche"
-option4: "**Fonction exercée depuis le :** 5 novembre 2007"
-option5: "**Grade et barème actuels :** informaticien - 12/2"
-option6: "**Grade et barème sollicités :** informaticien-expert - 13/3"
-titlepage: true
-titlepage-text-color: "1e355b"
-titlepage-background: "assets/garde.pdf"
-page-background: "assets/background.pdf"
-page-background-opacity: "0.8"
-footer-right: " "
-caption-justification: centering
-...
-
-# Introduction
-
-## Contexte
-
-Les chercheurs sont de plus en plus confrontés à la gestion d'énormes quantités de données scientifiques. Ces dernières sont soit produites localement soit téléchargées depuis les machines d'autres centres de recherche ou depuis des dépôts centralisés. Elles sont ensuite utilisées, analysées, étudiées, modifiées, localement ou à distance sur d'autres machines de calculs.
-
-La gestion de cette masse de données constitue un réel défi pour de nombreux pôles de recherche de notre institution. En effet, chaque chercheur ou groupe de chercheurs est soumis à une phase de formation et d'adaptation afin de maîtriser les différentes méthodologies à appliquer pour pouvoir obtenir et travailler sur telles ou telles données, et afin de pouvoir les stocker et les partager, les diffuser ou les réutiliser.
-
-Le stockage et l'accessibilité des données constituent l'enjeu de ce brevet.
-
-## Solutions de stockage
-
-Il existe 3 principales solutions de stockage des données à l'UCLouvain, hormis les solutions d'archivage et de backup. L'utilisation de l'une ou l'autre de ces solutions dépend du type des données (volumes, finalité, etc) mais aussi de l'environnement de l'utilisateur (système d'exploitation, logiciels, etc) et de l'environnement pour les données elles-mêmes (origine, logiciels pour les exploiter, etc).
-
-Le système de fichiers OASIS[^1] est un espace de stockage centralisé qu'il est possible d'intégrer à n'importe quel environnement de travail (multiplateformes via différents protocoles) au sein du réseau institutionnel. Il est utilisé pour des données dont la taille reste de l'ordre du Mo jusqu'à plusieurs Go et offre un backup journalier.
-OASIS représente un système de fichier dans un réseau privé (réseau UCLouvain) en "modèle interne" (entièrement géré et hébergé localement).  
-C'est un système de stockage hiérarchique qui fournit un accès partagé aux données. Les utilisateurs peuvent créer, supprimer, modifier, lire et écrire des fichiers et peuvent les organiser logiquement dans des arborescences de répertoires (accès intuitif).
-
-[^1]: https://intranet.uclouvain.be/fr/myucl/services-informatiques/service-fichier-personnel-en-detail.html
-
-SharePoint est une solution de stockage dans un cloud publique en modèle SaaS (Software as a Service ou Logiciel en tant que Service) : entièrement géré et hébergé par Microsoft. Cette solution est parfaitement intégrée à la suite de logiciels bureautique MS Office 365. Il s'agit d'un espace de travail collaboratif partagé, mais exclusivement disponible pour les utilisateurs de l'UCLouvain. L'utilisation de Sharepoint se fait en ligne via un navigateur. Il est possible de l'intégrer davantage (synchronisation, édition locale, etc) à l'environnement de travail via un client OneDrive (mais pas pour un environnement GNU/Linux).  
-Pour une utilisation plus individuelle, OneDrive est plus approprié[^2]. OneDrive (via un compte UCLouvain) permet de stocker et sauvegarder de grande quantité de données en toute sécurité dans l'UE (respectant les recommandations GDPR). Mais les données ne sont pérennes que pour un utilisateur de l'UCLouvain: si ce dernier quitte l'institution, les données disparaissent.  
-
-Les solutions de stockage de Microsoft ne sont en revanche pas ou peu adaptées pour des données sous environnement GNU/Linux. En outre, collaborer (SharePoint) ou partager des données (SharePoint, OneDrive) avec des utilisateurs extérieurs n'est pas sytématique: il est nécessaire d'être authentifié avec un compte Microsoft (UClouvain, personnel ou d'une autre organisation).
-
-[^2]: https://intranet.uclouvain.be/fr/myucl/services-informatiques/applications-disponibles.html
-
-Pour une partie du parc de machines individuelles de l'UCLouvain utilisant un environnement de travail GNU/Linux (majoritaires par exemple dans les pôles de recherche ELIC, TFL, MODL, ELEN, INMA, etc) mais aussi pour les clusters HPC et les serveurs interactifs partagés, il n'est donc pas aisé de lier efficacement l'un de ces services de stockage au système de fichiers local (du poste de travail ou de la machine partagée). Pour cela, il existe le service du stockage de masse proposé par la plateforme technologique du CISM.
-Cet espace de stockage offre une très grande capacité aux utilisateurs et de hautes performances. En revanche, celui-ci est essentiellement adapté aux environnements Unix (MacOs ou GNU/Linux) car accessible uniquement via les protocoles SSH et FTP. Comme OASIS, le stockage de masse du CISM est un système de fichier dans un réseau privé (réseau CECI: Universités francophones) en "modèle interne" (entièrement géré et hébergé au CISM).
-
-# Description du projet
-
-Comment offrir une solution de stockage multiplateformes combinant grande capacité de stockage, gestion des grands groupes de données (datasets >10Go) et hébergée localement ?
-
-Nextcloud est un logiciel libre qui propose de combiner cela. Il s'agit d'un logiciel de site d'hébergement de fichiers mais aussi d'une plateforme de collaboration. C'est-à-dire qu'il peut s'utiliser comme un espace de stockage dans le nuage publique à la manière de OneDrive ou DropBox, mais en "modèle interne" (entièrement géré et hébergé localement).  
-Il propose en outre une panoplie de fonctionnalités afin d'offrir des services à la manière d'Office 365 ou des services de Google: gestion des agendas (CalDAV), des contacts (CardDAV), des tâches, des notes, espace de collaboration (suite bureautique en ligne basée sur LibreOffice), gestion de version des fichiers, partage multiple, etc.
-Il est également possible de lui ajouter des extensions afin de prendre en charge des espaces de stockage externes par protocoles (FTP, SSH, NFS, WebDAV ou SMB/CIFS comme OASIS) mais aussi par services (comme OneDrive ou DropBox). Il peut également prendre en charge le stockage objet (comme Amazon S3 ou OpenStack).  
-Enfin, Nextcloud propose un logiciel client multiplateformes pour une intégration totale avec tous les environnements (Windows, MacOs, GNU/Linux, Android, iOS), dispose d'un système d'authentification à deux facteurs, et respecte les recommandations GDPR.
-
-Dans le contexte de la gestion des grandes quantités de données scientifiques, je propose une collaboration avec le CISM afin de pérenniser un service Nextcloud, c'est-à-dire le rendre performant et disponible à long terme.  
-L'objectif premier est d'offrir aux chercheurs un accès efficace à leurs données non bureautiques, c'est-à-dire non exploitables par des logiciels comme ceux fournis par la suite MS Office et nécessitant un traitement spécifique. La mise en place de ce service offre également l'opportunité d'intégrer les solutions de stockage existantes de l'Institution au sein d'une plateforme commune.
-
-## Objectifs
-
-Dans le cadre de ce premier brevet, les objectifs poursuivis sont:
-
-- d'installer une instance de Nextcloud dans l'infrastructure OpenStack du CISM
-- d'optimiser le déploiement du service en termes de performances, de robustesse, d'accessibilité et de maintenance
-- de créer des liens efficaces entre Nextcloud et les différents espaces de stockage: stockage de masse, OneDrive, OASIS, stockage partagé CECI, etc.
-- d'offrir via le service Nextcloud une solution intégrée de gestion de données volumineuses à l'ensemble des chercheurs de l'institut ELI ainsi qu'à tous les pôles de recherche intéressés
-
-Une phase de test du service Nextcloud a déjà été réalisée en amont de ce brevet: j'ai en effet pu installer une instance locale à petite échelle : déploiement simple (LAMP : acronyme pour Linux, Apache, MySQL, PHP) dans un conteneur virtuel Docker, sur une machine interactive financée par ELIC et installée dans l'infrastructure du CISM depuis 2017. Cette machine arrive cependant en fin de vie en juillet 2022.  
-Cette phase de test est arrivée à son terme et le but du présent brevet est de pérenniser ce service.
-
-Ce projet se positionne au niveau d'un institut de recherche (ELI) en collaboration avec une plateforme technologique sectorielle (CISM). Les services de l'Institution en relation avec le projet ou impacté sont le CISM et le SGSI.
-
-## Produit du projet
-
-Les délivrables de ce projet prendront la forme d'une instance Nextcloud entièrement opérationnelle:
-
-- côté serveur, dans l'environnement CISM pour l'infrastructure backend (service et stockage cloud)
-- côté client, disponible pour les utilisateurs via une interface web ou via les applications clientes disponibles pour Windows, MacOS, GNU/Linux (de nombreuses distributions), iOS et Android.
-
-Les spécifications et fonctionnalités de cette instance seront les suivantes:
-
-- authentification via l'utilisation d'un compte CISM préalablement créé
-- gestion des versions de fichiers (la fréquence de sauvegarde et la fréquence de conservation sont définies par l'administrateur)
-- partage des fichiers au niveau utilisateurs (les fichiers ou dossiers individuels peuvent être partagés avec des personnes sélectionnées sur les comptes Nextcloud, ou avec n'importe qui via un simple lien URL, l'expéditeur ayant un grand contrôle sur le processus. Ils peuvent, par exemple, définir une date d'expiration pour le lien, exiger un mot de passe pour ouvrir le fichier envoyé, joindre une note, etc.)
-- collaboration (Collabora Online est une suite bureautique en ligne basée sur LibreOffice qui prend en charge tous les principaux formats de documents, de feuilles de calcul et de fichiers de présentation.)
-- montage de stockages externes par protocoles SSH ou CIFS
-- montage de stockages externes des services OneDrive, DropBox et GoogleDrive
-- authentification à deux facteurs (via des codes de sauvegarde ou une application d'authentification TOTP)
-- conforme au RGPD
-
-# Contraintes
-
-Les contraintes de ce projet s'expriment essentiellement en termes de délais et de ressources.
-
-## Délais
-
-Voici une proposition pour l'ensemble du calendrier:
-
-- **25 janvier 2022 :** soumission d'acte de candidature à l'examen
-- **15 avril 2022 :** soumission du présent projet pour le premier brevet
-- **28 avril 2022 :** analyse de l'acte de candidature à l'examen et du présent projet par la Commission paritaire
-- **mai 2022 :** actualisation et initialisation du projet
-- **fin février 2023 :** fin du premier brevet
-
-Durée du projet : **10 mois** à partir de la validation du 28 avril 2022
-
-Livraison estimée d'un produit minimum viable (MVP) : **décembre 2022**
-
-Les échéances intermédiaires sont détaillées dans la section de planification du projet.
-
-## Ressources
-
-Voici certaines ressources à prendre en compte:
-
-- accessibilité à une infrastructure de développement et de validation (test) puis de production. Prise en compte des points suivants :
-  - localisation et hébergement des serveurs : qualité des performances, possibilité d'accès, coût, sécurité, etc.
-  - réseau (type, vitesse et performance des liaisons, disponibilité, support)
-  - outils de sécurisation des transactions et des serveurs (certificats, authentification par clés, mots de passe, firewall, etc.)
-  - procédures, outils et ressources pour assurer la gestion et la maintenance: du réseau, du matériel, des logiciels, des accès, de l'usage, des coûts, du support utilisateur, de la performance, etc.
-- accessibilité aux données : démarches administratives, protocoles de connexion, coûts éventuels, confidentialité, etc.
-- localisation des applications et des bases de données (répartition des processus applicatifs entre serveurs, etc.)
-- outils utilisés issus de logiciels libres
-- environnement de travail
-- architecture et fonctionnalités de l'application:
-  - interface web (proxy, load balancing)
-  - middleware (serveur web, php-fpm)
-  - bases de données (stockage, réplication, performance)
-- outils de sécurisation des transactions et des serveurs (certificats, authentification par clés, mots de passe, firewall, etc.)
-- performances que le système doit supporter dans 90% des cas: temps de réponse utilisateur, outils de mesure des performances, disponibilité requise, etc.)
-- reproductibilité et persistance de l'application
-- évolutivité de la solution (possibilités)
-- maintenance du service
-
-## Autres contraintes
-
-- documentation requise
-- méthode d'analyse (performance, risques)
-- évolutivité de la solution (coût)
-- plan de formation des utilisateurs et des gestionnaires
-- support utilisateurs
-
-# Déroulement du projet
-
-## Planification
-
-Les grandes phases du projet seront les suivantes:
-
-### Phase 1 : Initialisation du projet
-
-Fin de rédaction du cahier des charges, choix techniques
-
-Calendrier : **mai 2022**
-
-### Phase 2 : Analyse et conception
-
-Conception globale de l'application : analyse fonctionnelle, modélisation
-
-Calendrier : **juin 2022**
-
-### Phase 3 : Développement
-
-Evaluation à l'aide du cahier des charges en cours
-
-Calendrier : fin **octobre 2022**
-
-### Phase 4 : Tests d'intégration
-
-Intégration de l'ensemble des développements dans l'environnement de test
-
-Calendrier : **novembre 2022**
-
-### Phase 5 : Documentation et présentation
-
-Documentation de l'application + présentation aux utilisateurs
-
-Calendrier : **février 2023**
-
-## Organisation et suivi
-
-La phase d'initialisation du projet est soumise à la validation de la Commission paritaire.  
-L'ensemble des activités introduites dans la planification des tâches sera discuté et suivi par Thomas Keutgen en tant que coach-évaluateur et par Hugues Goosse en tant que second évaluateur. RHUM sera régulièrement informé du suivi global du travail.  
-Le développement du projet nécessitera des interactions avec de nombreux groupes au sein de l'UCL comme détaillé dans les spécifications techniques.
-
-## Evaluation
-
-La méthode d'analyse et les critères d'évaluation du projet sont soumis au règlement des examens d'avancement au grade d'informaticien-expert (document du 30 janvier 2006).
-
-## Spécifications techniques
-
-Quelques pistes pour les points encore à définir :
-
-- connexion réseau GB, agrégation de liens, etc. (contact : CISM, SRI)
-- localisation serveurs (contacts: CISM pour DCIII)
-- serveur(s) de stockage (contacts : ELI, ELIC, CISM, SGSI)
-- serveur(s) d'application (contacts : ELI, ELIC, CISM)
-- environnement de travail sous distribution virtualisée (OpenStack)
-- infrastructure en tant que code (IaC) : reproductibilité aisée de la configuration (Ansible)
-- persistance via système de gestion de versions (Git): utilisation de la forge GitLab de l'UCLouvain pour le suivi
-- duplication middleware (serveur Web) pour charges élevées
-- couche accès aux données locales puis via DB distribuée
-- base de données SQL (MySQL, Postgresql ?) et réplication
-- base de données haute performance Redis pour la mise en cache des requêtes de base de données (via la RAM)
-- stockage Ceph pour des charges élevées, et possibilité d'utiliser le stockage d'objets compatible S3
-- échange de données inter-sites via protocole GridFTP (sans doute hors MVP)
-
-## Spécifications de réalisation
-
-Quelques points encore à détailler :
-
-- maquette ou démonstration fonctionnelle : objectifs, représentativité par rapport au projet complet, configuration, plan de travail, ressources, critères d'acceptation avant de poursuivre les travaux ;
-- détails du calendrier des prestations : début, fin, phases, check-points ;
-- planning de disponibilité des ressources mises à disposition (quantité, qualification, dates, lieux)
-- méthodologie, plan et outils requis pour effectuer les tests :
-  - fonctionnels, de performance et de qualité
-  - de montée en charge du réseau et des applications, d'ergonomie
-  - des fonctions de sauvegarde et de reprise
-
-# Analyse et conception du projet
-
-## Choix techniques
-
-L'objectif est la création d'une interface de gestion de données sous forme d'une application web service.
-
-![Simple Nextcloud achitecture](./assets/dia_nc_simple.png)
-
-### Framework
-
-Un framework est un cadre qui permet de structurer le travail de développement grâce à un ensemble d'outils, une structure et des modèles prêts-à-l'emploi.
-Étant donné l'étendue des développements à effectuer pour concevoir une application web moderne, un framework est indispensable.
-
-Django est un framework Backend Open Source développé en Python. Il a été spécialement créé pour réaliser des sites web puissants et de haut niveau. Il embarque tous les composants utiles, que ce soit la gestion de vues, l'authentification, le mapping objet-relationnel, une documentation détaillée, etc.
-Python est un avantage car c'est le langage le plus utilisé par les chercheurs en ELIC. En outre, les services IT de l'UCL utilisent également ce framework pour les nouveaux développements web.
-Une alternative solide serait Ruby on Rails (RoR). Il est le framework libre le plus populaire ces 5 dernières années, et a été conçu pour développer des applications web plus rapidement. Il permet aux développeurs de créer des fonctionnalités avec moins de code. Mais si RoR nécessite peu de configuration, il exige aussi plus de conventions. En outre, le niveau d'expertise pour se lancer est une barrière à l'entrée pour les débutants. Enfin Ruby nécessite des ressources serveur plus importantes que Django et sa technologie comme son utilisation sont en déclin.
-
-![Improved Nextcloud achitecture](./assets/dia_nc_pelican.png){width=80%}
-
-Python/Django sera préféré pour la conception du projet.
-C'est un framework Full-Stack - il est très facile de combiner Django et Angular par exemple - et tout clé en main : modèles, côté serveur, panneau d'administration pour configurer un site sans coder, etc. Il utilise, comme souhaité, le patron de conception modèle-vue-contrôleur (MVC), c'est à dire que la structure du framework sépare les données (models) qui sont séparées des traitements (controller) qui sont eux-mêmes séparés de la vue (view/template). C'est également un outil idéal pour un projet collaboratif.
-Django étant très populaire auprès des développeurs web, de nombreux projets sont apparus autour du framework. Par exemple dans notre cas, Ncdjango est un ensemble d'outils de gestion de données et de géotraitement écrits en Python qui fonctionnent sur des données NetCDF.
-
-### Environnement
-
-Cette application sera conteneurisée. La conteneurisation logicielle permet une gestion simplifiée des dépendances: une application et toutes ses dépendances sont placées dans une seule unité. Le système hôte ne doit pas se soucier de ces dépendances.
-L'application conteneurisée est donc indépendante de l'architecture ou des ressources de l'hôte. Elle est donc plus flexible et plus facilement distribuable.
-Si cette conteneurisation apporte son lot d'avantages en développement et pour les tests de validation, son utilisation reste plus discutable dans le contexte d'une mise en production. Nous en rediscuterons plus en avant dans ce projet.
-
-Docker est la solution de conteneurisation la plus utilisée aujourd’hui. C'est un logiciel libre qui utilise une interface de programmation « Libcontainer » pour démarrer, gérer et arrêter les conteneurs. Il est basée sur le fonctionnement de LXC et y ajoute des capacités de niveau supérieur. Les conteneurs Docker peuvent servir d’images à d'autres conteneurs et le partage de conteneurs en public est possible via un service en ligne appelé Docker Hub. Il contient des images de conteneurs, ce qui permet aux utilisateurs de faire des échanges. Cela rend l’installation d’un conteneur extrêmement facile. 
-
-### Outil de développement
-
-PyCharm est un environnement de développement intégré utilisé pour développer en Python ainsi qu'avec Django. Il propose la possibilité de débugger en direct dans un conteneur Docker.
-Vagrant est un logiciel libre et open-source pour la création et la configuration des environnements de développement virtuel. Il peut être considéré comme un wrapper autour de logiciels de virtualisation comme VirtualBox.
-
-## Méthodologie
-
-L'application sera donc standardisée MVC, c'est-à-dire selon une architecture classique à trois couches.
-La couche vue sera développée très simplement sur base de templates existants à l'UCL.
-Les couches traitement et modèle présenteront les cas de figure suivants:
-- données locales: traitement "on the fly" sur DB(s) locales 130.104
-- données distantes
-  - à posteriori (DB & protocoles connus)
-  - à priori (infos de structures à soumettre)
-- données distantes
-  - indexées: traitement "on the fly" (batch process possible sur DB distante)
-  - non-indexées: traitement différé (DB distante accessible en interactif uniquement)
-
-Scénarios pour les données à posteriori et non-indexées :
-- téléchargement tiers + demande d'intégration aux DB
-- téléchargement à travers l'appli + intégration automatique aux DB locales
-
-![Large and efficient Nextcloud achitecture](./assets/dia_nc_improved.png)
-
-![Database cluster](./assets/dia_db_cluster.png)
-
-Comme nous souhaitons mettre à disposition des données pour quelles soient utilisées sur d’autres plateformes et qu'elles puissent intéragir avec d’autres données, une architecture REST ("REpresentational State Transfer") semble appropriée ici.
-L'architecture REST est plus axée sur un modèle orienté ressources (les données, dans notre cas) que sur un modèle orienté fonctions. Elle imite la façon dont le web lui-même fonctionne dans les échanges entre un client et un serveur.
-REST constitue donc une méthode d'intégration efficace puisque le service à développer ici concerne surtout la récupération de données. Aussi, plutôt que de définir toute une API (interfaces de programmation d'application) personnalisée mieux vaut utiliser un standard de manipulation des données CRUD (Create, Read, Update, Delete : créer, lire, mettre à jour, supprimer), qui "correspond" aux opérations HTTP (HyperText Transfert Protocol) GET, PUT, POST et DELETE. Ce fonctionnement ne repose pas sur la seule utilisation de ces opérateurs, mais sur une combinaison avec des URI.
-
-Le "Django REST framework" va nous permettre de créer plus facilement une API REST sur notre application Django.
-
-Un interfacage avec Amazon S3 serait un atout supplémentaire.
-
-![caption KO](./assets/openstack.png){width=30%}\ ![test backslash](./assets/openstack.png){width=30%}
-
-::: twocolumns
-
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a ante in mi ornare volutpat sed sit amet diam. Nullam interdum erat a augue faucibus, nec tempus tortor sagittis. Aenean imperdiet imperdiet dignissim. Nam aliquam blandit ex, sed molestie nibh feugiat ac. Morbi feugiat convallis semper. Ut et consequat purus. Fusce convallis vehicula enim in vulputate. Curabitur a augue arcu. Mauris laoreet lectus arcu, sed elementum turpis scelerisque id. Etiam porta turpis quis ipsum dictum vulputate. In ut convallis urna, at imperdiet nunc. Cras laoreet, massa lobortis gravida egestas, lacus est pellentesque arcu, imperdiet efficitur nibh dolor vel sapien. Sed accumsan condimentum diam non pellentesque.
-
-Vestibulum cursus nisi risus, sit amet consectetur massa suscipit nec. Sed condimentum, est id iaculis ornare, purus risus finibus felis, posuere congue est nibh eget dui. Maecenas orci erat, commodo auctor justo quis, vestibulum mollis ex. Vivamus sed bibendum turpis.
-
-:::
-
-"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
-
-\Begin{multicols}{2}
-
-"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
-
-![caption y](./assets/openstack.png){#fig:y width=30%}
-
-\End{multicols}
-
-"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
-
-<!-- needs: --filter pandoc-crossref -->
-
-<div id="fig:coolFig">
-![caption a](./assets/openstack.png){#fig:cfa width=30%}
-![caption b](./assets/openstack.png){#fig:cfb width=30%}
-![caption c](./assets/openstack.png){#fig:cfc width=30%}
-
-Cool figure!
-</div>

TEMPAT SAMPAH
Report/Projet_brevet.pdf


TEMPAT SAMPAH
Report/assets/dia_nc_improved.png


+ 0 - 43
Report/compile.sh

@@ -1,43 +0,0 @@
-#!/bin/bash
-#
-# PY Barriat, May 2022
-#
-# Install pandoc & pandac-crossref
-# sudo apt install ghc-9.0.1
-# https://github.com/jgm/pandoc/releases/tag/2.17.1.1
-# https://github.com/lierdakil/pandoc-crossref/releases/tag/v0.3.12.2a
-# https://github.com/jgm/pandoc-types/releases/tag/1.22.1
-#
-# Download and install diagrams:
-# sudo apt install graphviz python3-pydotplus
-# pip install diagrams
-#
-# Install npm (needed for mermaid: nice extension to make diagramm)
-# npm i
-#
-
-# with diagrams
-
-python assets/dia_nc_simple.py
-python assets/dia_nc_pelican.py
-python assets/dia_nc_improved.py
-
-# without mermaid
-
-#pandoc -s Projet_brevet.md -o Projet_brevet.pdf \
-#    --from markdown \
-#    --template assets/eisvogel \
-#    --lua-filter assets/columns.lua \
-#    --listings
-
-pandoc -s Projet_brevet.md -o Projet_brevet.pdf \
-    --from markdown \
-    --template assets/eisvogel \
-    --filter pandoc-crossref \
-    --lua-filter assets/columns.lua \
-    --listings
-
-#/opt/quarto/bin/quarto render tufte.qmd --to pdf
-
-# with mermaid
-

+ 19 - 0
dev/README.md

@@ -0,0 +1,19 @@
+# Development
+
+## Ubuntu Host Requirements
+
+```bash
+sudo apt install vagrant ansible virtualbox
+
+ansible-galaxy collection install ansible.posix
+
+ansible-galaxy collection install community.crypto
+
+ansible-galaxy collection install community.general
+```
+
+## Deploy
+
+```bash
+vagrant up
+```

+ 11 - 0
dev/README.txt

@@ -0,0 +1,11 @@
+https://www.cspo.be/polycliniquelln
+https://economie.fgov.be/fr/nouveautes/cheque-mazout-comment-obtenir
+https://github.com/geerlingguy/ansible-role-haproxy
+https://github.com/ReinerNippes/nextcloud/tree/master/roles
+https://github.com/nextcloud/all-in-one/blob/main/Containers/mastercontainer/Caddyfile
+https://github.com/Wonderfall/docker-nextcloud/tree/main/rootfs
+https://www.auto5.be/fr/t/f/47597-pneu/brand=dunlop/diametre-pneumatiquebe=18/indice-de-chargebe=95/indice-de-vitessebe=y/largeur-pneumatiquebe=225/saisonbe=ete9/serie-pneumatiquebe=45/type-pneube=voiture.html
+
+https://www.c-rieger.de/nextcloud-haproxy-mit-und-ohne-ssl-terminierung/
+
+https://www.c-rieger.de/nextcloud-installationsanleitung-apache2-fast-track/

+ 159 - 0
dev/Vagrantfile

@@ -0,0 +1,159 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+VAGRANTFILE_API_VERSION = "2" 
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+
+  config.vm.boot_timeout = 360
+
+  config.vm.provider "virtualbox" do |vb|
+    vb.memory = "2048"
+    vb.cpus = "1"
+  end
+
+  #LoadBalancer
+  config.vm.define "loadbalancer" do |loadbalancer|
+    loadbalancer.vm.box = 'ubuntu/focal64'
+    loadbalancer.vm.hostname = "loadbalancer"
+    loadbalancer.vm.network :private_network, ip: "192.168.56.10"
+    loadbalancer.vm.provision "shell", inline: "apt-get install -y haproxy"
+
+    #Provision the loadbalancer with Ansible
+    loadbalancer.vm.provision "ansible" do |ansible|
+       ansible.compatibility_mode = "2.0"
+       ansible.playbook="provisioning/ansible/haproxy.yml"
+       ansible.become = true
+       ansible.extra_vars = {
+         ansible_python_interpreter: "/usr/bin/python3",
+         ssl_name: "nextcloud.test",
+         network_allowed: "192.168.56.0/24",
+         haproxy_backend_servers:
+           { name: 'web', ip: '192.168.56.14:8000' },
+       }
+    end
+  end
+
+  #Redis Server 
+  config.vm.define "redis" do |redis| 
+    redis.vm.hostname = "redis"
+    redis.vm.box = "centos/7"
+    redis.vm.network "private_network", ip: "192.168.56.12"
+    redis.vm.provision "shell", inline: "yum install -y python3 dnf epel-release"
+
+    #Provision the webserver with Ansible
+    redis.vm.provision "ansible" do |ansible|
+       ansible.compatibility_mode = "2.0"
+       ansible.playbook="provisioning/ansible/redis.yml"
+       ansible.become = true
+       ansible.extra_vars = { 
+         ansible_python_interpreter: "/usr/bin/python2",
+         #redis_bind_interface: "192.168.56.14", #bug Centos
+       }
+    end 
+  end
+
+  #Database Server 
+  config.vm.define "db" do |db| 
+    db.vm.hostname = "mariadb"
+    db.vm.box = "centos/7"
+    db.vm.network "private_network", ip: "192.168.56.13"
+    db.vm.provision "shell", inline: "yum install -y python3 dnf"
+
+    #Provision the webserver with Ansible
+    db.vm.provision "ansible" do |ansible|
+       ansible.compatibility_mode = "2.0"
+       ansible.playbook="provisioning/ansible/mariadb.yml"
+       ansible.become = true
+       ansible.extra_vars = { 
+         ansible_python_interpreter: "/usr/bin/python2",
+         app_bind_address: "192.168.56.14"
+       }
+    end
+  end
+
+  #Web Server 
+  config.vm.define "web" do |web|
+    web.vm.hostname = "nextcloud"
+    web.vm.box = "centos/7"
+    web.vm.network "private_network", ip: "192.168.56.14"
+
+    # Creating a Shared Directory between host and guest VM 
+    #web.vm.synced_folder "/apps/shared", "/shared"
+
+    #Provision the webserver for nextcloud role ansible
+    web.vm.provision "shell", path: "provisioning/install/Centos_7.sh"
+
+    #Provision the webserver with Ansible
+    web.vm.provision "ansible" do |ansible|
+       ansible.compatibility_mode = "2.0"
+       ansible.playbook = "provisioning/ansible/nextcloud.yml"
+       ansible.become = true
+       ansible.extra_vars = {
+         ansible_python_interpreter: "/usr/bin/python2",
+         db_host: "192.168.56.13",
+         use_redis_server: "true",
+         redis_host: "192.168.56.12",
+         debug_speed: "false",
+       }
+       #ansible.inventory_path = "provisioning/apache.inventory"
+       #ansible.verbose = "vvvv"
+    end
+  end
+
+  #Prometheus
+  config.vm.define "prometheus" do |prometheus|
+    prometheus.vm.box = 'centos/7'
+    prometheus.vm.hostname = "prometheus"
+    prometheus.vm.network :private_network, ip: "192.168.56.11"
+    prometheus.vm.provision "shell", path: "provisioning/install/Centos_7.sh"
+
+    #Provision prometheus-grafana with Ansible
+    prometheus.vm.provision "ansible" do |ansible|
+       ansible.compatibility_mode = "2.0"
+       ansible.playbook="provisioning/ansible/prometheus.yml"
+       ansible.become = true
+       ansible.extra_vars = {
+         ansible_python_interpreter: "/usr/bin/python2",
+       }
+    end
+  end
+
+  #Node Exporter
+  config.vm.define "node" do |node|
+    node.vm.box = 'centos/7'
+    node.vm.hostname = "nodexporter"
+    node.vm.network :private_network, ip: "192.168.56.15"
+    node.vm.provision "shell", path: "provisioning/install/Centos_7.sh"
+
+    #Provision prometheus-grafana with Ansible
+    node.vm.provision "ansible" do |ansible|
+       ansible.compatibility_mode = "2.0"
+       ansible.playbook="provisioning/ansible/node_exporter.yml"
+       ansible.become = true
+       ansible.extra_vars = { 
+         ansible_python_interpreter: "/usr/bin/python2",
+       }
+    end 
+  end
+
+  #Grafana
+  config.vm.define "grafana" do |grafana|
+    grafana.vm.box = 'centos/7'
+    grafana.vm.hostname = "grafana"
+    grafana.vm.network :private_network, ip: "192.168.56.16"
+    grafana.vm.provision "shell", path: "provisioning/install/Centos_7.sh"
+
+    #Provision prometheus-grafana with Ansible
+    grafana.vm.provision "ansible" do |ansible|
+       ansible.compatibility_mode = "2.0"
+       ansible.playbook="provisioning/ansible/grafana.yml"
+       ansible.become = true
+       ansible.extra_vars = { 
+         ansible_python_interpreter: "/usr/bin/python2",
+       }
+    end 
+  end 
+
+  config.vm.box_check_update = false 
+end

+ 14 - 0
dev/provisioning/ansible/grafana.yml

@@ -0,0 +1,14 @@
+---
+- name: apply grafana role
+  hosts: all
+  #  vars:
+  #    ansible_python_interpreter: /usr/bin/python3
+  #    ansible_user: vagrant
+  #    ansible_password: vagrant
+  #  pre_tasks:
+  #    - name: define ansible_python_interpreter group // linux distribution
+  #      set_fact:
+  #        ansible_python_interpreter: /usr/bin/python2
+  #      when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
+  roles:
+    - { role: grafana }

+ 18 - 0
dev/provisioning/ansible/haproxy.yml

@@ -0,0 +1,18 @@
+---
+- name: apply haproxy role
+  hosts: all
+  #  vars:
+  #    ansible_python_interpreter: /usr/bin/python3
+  #    ansible_user: vagrant
+  #    ansible_password: vagrant
+  #    ssl_name: "nextcloud.test"
+  #    network_allowed: "192.168.56.0/24"
+  #    haproxy_backend_servers:
+  #      { name: 'web', ip: '192.168.56.14:8000' }
+  #  pre_tasks:
+  #    - name: define ansible_python_interpreter group // linux distribution
+  #      set_fact:
+  #        ansible_python_interpreter: /usr/bin/python2
+  #      when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
+  roles:
+    - { role: haproxy }

+ 15 - 0
dev/provisioning/ansible/mariadb.yml

@@ -0,0 +1,15 @@
+---
+- name: apply mariadb configuration
+  hosts: all
+  #vars:
+  #  ansible_python_interpreter: /usr/bin/python3
+  #  ansible_user: vagrant
+  #  ansible_password: vagrant
+  #  app_bind_address: 192.168.56.14
+  #pre_tasks:
+  #  - name: define ansible_python_interpreter group // linux distribution
+  #    set_fact:
+  #      ansible_python_interpreter: /usr/bin/python2
+  #    when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
+  roles:
+    - { role: mariadb }

+ 19 - 0
dev/provisioning/ansible/nextcloud.yml

@@ -0,0 +1,19 @@
+---
+- name: apply nextcloud role
+  collections:
+    - community.general
+    - ansible.posix
+  hosts: all
+  #  vars:
+  #    ansible_python_interpreter: /usr/bin/python3
+  #    ansible_user: vagrant
+  #    ansible_password: vagrant
+  #    db_host: 192.168.56.13
+  #    debug_speed: false
+  #  pre_tasks:
+  #    - name: define ansible_python_interpreter group // linux distribution
+  #      set_fact:
+  #        ansible_python_interpreter: /usr/bin/python2
+  #      when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
+  roles:
+    - { role: nextcloud }

+ 14 - 0
dev/provisioning/ansible/node_exporter.yml

@@ -0,0 +1,14 @@
+---
+- name: apply node_exporter role
+  hosts: all
+  #  vars:
+  #    ansible_python_interpreter: /usr/bin/python3
+  #    ansible_user: vagrant
+  #    ansible_password: vagrant
+  #  pre_tasks:
+  #    - name: define ansible_python_interpreter group // linux distribution
+  #      set_fact:
+  #        ansible_python_interpreter: /usr/bin/python2
+  #      when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
+  roles:
+    - { role: node_exporter }

+ 14 - 0
dev/provisioning/ansible/prometheus.yml

@@ -0,0 +1,14 @@
+---
+- name: apply prometheus role
+  hosts: all
+  #  vars:
+  #    ansible_python_interpreter: /usr/bin/python3
+  #    ansible_user: vagrant
+  #    ansible_password: vagrant
+  #  pre_tasks:
+  #    - name: define ansible_python_interpreter group // linux distribution
+  #      set_fact:
+  #        ansible_python_interpreter: /usr/bin/python2
+  #      when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
+  roles:
+    - { role: prometheus }

+ 14 - 0
dev/provisioning/ansible/redis.yml

@@ -0,0 +1,14 @@
+---
+- name: apply redis role
+  hosts: all
+  #  vars:
+  #    ansible_python_interpreter: /usr/bin/python3
+  #    ansible_user: vagrant
+  #    ansible_password: vagrant
+  #  pre_tasks:
+  #    - name: define ansible_python_interpreter group // linux distribution
+  #      set_fact:
+  #        ansible_python_interpreter: /usr/bin/python2
+  #      when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
+  roles:
+    - { role: redis }

+ 5 - 0
dev/provisioning/ansible/roles/grafana/defaults/main.yml

@@ -0,0 +1,5 @@
+---
+grafana_version: "6.2.2-1"
+grafana_tarball: "grafana-{{ grafana_version }}.x86_64"
+grafana_url: "https://s3-us-west-2.amazonaws.com/grafana-releases/release"
+grafana_skip_install: false

+ 5 - 0
dev/provisioning/ansible/roles/grafana/handlers/main.yml

@@ -0,0 +1,5 @@
+- name: "Restart the Grafana service."
+  service:
+    name: grafana-server
+    state: restarted
+  listen: event_restart_grafana

+ 21 - 0
dev/provisioning/ansible/roles/grafana/tasks/main.yml

@@ -0,0 +1,21 @@
+---
+
+- include_tasks: "setup/{{ ansible_os_family }}.yml"
+
+- name: "Grafana configuration file copy"
+  template:
+    src: "grafana.conf.j2"
+    dest: /etc/grafana/grafana.ini
+  notify: event_restart_grafana
+
+- name: "Grafana server started"
+  service:
+    name: grafana-server
+    enabled: true
+    state: started
+
+- name: "Check if Grafana is accessible."
+  uri:
+    url: http://127.0.0.1:3000
+    method: GET
+    status_code: 200

+ 35 - 0
dev/provisioning/ansible/roles/grafana/tasks/setup/CentOS.yml

@@ -0,0 +1,35 @@
+---
+
+- name: Install grafana
+  yum:
+    name: "{{ grafana_url }}/{{ grafana_tarball }}.rpm"
+    state: latest
+
+#- name: Download grafana archive
+#  get_url:
+#    url:  "{{ grafana_url }}/{{ grafana_tarball }}.tar.gz"
+#    dest: /tmp/{{ grafana_tarball }}.tar.gz
+#    #checksum: "sha256:{{ grafana_url }}/{{ grafana_tarball }}.tar.gz.sha256"
+#  register: _download_archive
+#  until: _download_archive is succeeded
+#  retries: 5
+#  delay: 2
+#  when: not grafana_skip_install
+#
+#- name: unpack grafana binaries
+#  unarchive:
+#    src: "/tmp/{{ grafana_tarball }}.tar.gz"
+#    dest: "/tmp"
+#    creates: "/tmp/grafana-{{ grafana_version }}/bin/grafana-cli"
+#    remote_src: true
+#  when: not grafana_skip_install
+#
+#- name: Copy grafana files to bin
+#  copy:
+#    src: "/tmp/grafana-{{ grafana_version }}/"
+#    dest: "/etc/grafana"
+#    owner: root
+#    group: root
+#    remote_src: yes
+#    mode: 0750
+#  when: not grafana_skip_install

+ 3 - 0
dev/provisioning/ansible/roles/grafana/tasks/setup/RedHat.yml

@@ -0,0 +1,3 @@
+---
+
+- include_tasks: "{{ ansible_facts['distribution'] }}.yml"

+ 462 - 0
dev/provisioning/ansible/roles/grafana/templates/grafana.conf.j2

@@ -0,0 +1,462 @@
+##################### Grafana Configuration Example #####################
+#
+# Everything has defaults so you only need to uncomment things you want to
+# change
+
+# possible values : production, development
+;app_mode = production
+
+# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
+;instance_name = ${HOSTNAME}
+
+#################################### Paths ####################################
+[paths]
+# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
+;data = /var/lib/grafana
+
+# Temporary files in `data` directory older than given duration will be removed
+;temp_data_lifetime = 24h
+
+# Directory where grafana can store logs
+;logs = /var/log/grafana
+
+# Directory where grafana will automatically scan and look for plugins
+;plugins = /var/lib/grafana/plugins
+
+# folder that contains provisioning config files that grafana will apply on startup and while running.
+;provisioning = conf/provisioning
+
+#################################### Server ####################################
+[server]
+# Protocol (http, https, socket)
+;protocol = http
+
+# The ip address to bind to, empty will bind to all interfaces
+;http_addr =
+
+# The http port  to use
+;http_port = 3000
+
+# The public facing domain name used to access grafana from a browser
+;domain = localhost
+
+# Redirect to correct domain if host header does not match domain
+# Prevents DNS rebinding attacks
+;enforce_domain = false
+
+# The full public facing url you use in browser, used for redirects and emails
+# If you use reverse proxy and sub path specify full url (with sub path)
+;root_url = http://localhost:3000
+
+# Log web requests
+;router_logging = false
+
+# the path relative working path
+;static_root_path = public
+
+# enable gzip
+;enable_gzip = false
+
+# https certs & key file
+;cert_file =
+;cert_key =
+
+# Unix socket path
+;socket =
+
+#################################### Database ####################################
+[database]
+# You can configure the database connection by specifying type, host, name, user and password
+# as separate properties or as on string using the url properties.
+
+# Either "mysql", "postgres" or "sqlite3", it's your choice
+;type = sqlite3
+;host = 127.0.0.1:3306
+;name = grafana
+;user = root
+# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
+;password =
+
+# Use either URL or the previous fields to configure the database
+# Example: mysql://user:secret@host:port/database
+;url =
+
+# For "postgres" only, either "disable", "require" or "verify-full"
+;ssl_mode = disable
+
+# For "sqlite3" only, path relative to data_path setting
+;path = grafana.db
+
+# Max idle conn setting default is 2
+;max_idle_conn = 2
+
+# Max conn setting default is 0 (mean not set)
+;max_open_conn =
+
+# Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours)
+;conn_max_lifetime = 14400
+
+# Set to true to log the sql calls and execution times.
+log_queries =
+
+#################################### Session ####################################
+[session]
+# Either "memory", "file", "redis", "mysql", "postgres", default is "file"
+;provider = file
+
+# Provider config options
+# memory: not have any config yet
+# file: session dir path, is relative to grafana data_path
+# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=grafana`
+# mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name`
+# postgres: user=a password=b host=localhost port=5432 dbname=c sslmode=disable
+;provider_config = sessions
+
+# Session cookie name
+;cookie_name = grafana_sess
+
+# If you use session in https only, default is false
+;cookie_secure = false
+
+# Session life time, default is 86400
+;session_life_time = 86400
+
+#################################### Data proxy ###########################
+[dataproxy]
+
+# This enables data proxy logging, default is false
+;logging = false
+
+#################################### Analytics ####################################
+[analytics]
+# Server reporting, sends usage counters to stats.grafana.org every 24 hours.
+# No ip addresses are being tracked, only simple counters to track
+# running instances, dashboard and error counts. It is very helpful to us.
+# Change this option to false to disable reporting.
+;reporting_enabled = true
+
+# Set to false to disable all checks to https://grafana.net
+# for new vesions (grafana itself and plugins), check is used
+# in some UI views to notify that grafana or plugin update exists
+# This option does not cause any auto updates, nor send any information
+# only a GET request to http://grafana.com to get latest versions
+;check_for_updates = true
+
+# Google Analytics universal tracking code, only enabled if you specify an id here
+;google_analytics_ua_id =
+
+#################################### Security ####################################
+[security]
+# default admin user, created on startup
+;admin_user = admin
+
+# default admin password, can be changed before first start of grafana,  or in profile settings
+;admin_password = admin
+
+# used for signing
+;secret_key = SW2YcwTIb9zpOOhoPsMm
+
+# Auto-login remember days
+;login_remember_days = 7
+;cookie_username = grafana_user
+;cookie_remember_name = grafana_remember
+
+# disable gravatar profile images
+;disable_gravatar = false
+
+# data source proxy whitelist (ip_or_domain:port separated by spaces)
+;data_source_proxy_whitelist =
+
+# disable protection against brute force login attempts
+;disable_brute_force_login_protection = false
+
+#################################### Snapshots ###########################
+[snapshots]
+# snapshot sharing options
+;external_enabled = true
+;external_snapshot_url = https://snapshots-origin.raintank.io
+;external_snapshot_name = Publish to snapshot.raintank.io
+
+# remove expired snapshot
+;snapshot_remove_expired = true
+
+#################################### Dashboards History ##################
+[dashboards]
+# Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1
+;versions_to_keep = 20
+
+#################################### Users ###############################
+[users]
+# disable user signup / registration
+;allow_sign_up = true
+
+# Allow non admin users to create organizations
+;allow_org_create = true
+
+# Set to true to automatically assign new users to the default organization (id 1)
+;auto_assign_org = true
+
+# Default role new users will be automatically assigned (if disabled above is set to true)
+;auto_assign_org_role = Viewer
+
+# Background text for the user field on the login page
+;login_hint = email or username
+
+# Default UI theme ("dark" or "light")
+;default_theme = dark
+
+# External user management, these options affect the organization users view
+;external_manage_link_url =
+;external_manage_link_name =
+;external_manage_info =
+
+# Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard.
+;viewers_can_edit = false
+
+[auth]
+# Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false
+;disable_login_form = false
+
+# Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false
+;disable_signout_menu = false
+
+# URL to redirect the user to after sign out
+;signout_redirect_url =
+
+#################################### Anonymous Auth ##########################
+[auth.anonymous]
+# enable anonymous access
+;enabled = false
+
+# specify organization name that should be used for unauthenticated users
+;org_name = Main Org.
+
+# specify role for unauthenticated users
+;org_role = Viewer
+
+#################################### Github Auth ##########################
+[auth.github]
+;enabled = false
+;allow_sign_up = true
+;client_id = some_id
+;client_secret = some_secret
+;scopes = user:email,read:org
+;auth_url = https://github.com/login/oauth/authorize
+;token_url = https://github.com/login/oauth/access_token
+;api_url = https://api.github.com/user
+;team_ids =
+;allowed_organizations =
+
+#################################### Google Auth ##########################
+[auth.google]
+;enabled = false
+;allow_sign_up = true
+;client_id = some_client_id
+;client_secret = some_client_secret
+;scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
+;auth_url = https://accounts.google.com/o/oauth2/auth
+;token_url = https://accounts.google.com/o/oauth2/token
+;api_url = https://www.googleapis.com/oauth2/v1/userinfo
+;allowed_domains =
+
+#################################### Generic OAuth ##########################
+[auth.generic_oauth]
+;enabled = false
+;name = OAuth
+;allow_sign_up = true
+;client_id = some_id
+;client_secret = some_secret
+;scopes = user:email,read:org
+;auth_url = https://foo.bar/login/oauth/authorize
+;token_url = https://foo.bar/login/oauth/access_token
+;api_url = https://foo.bar/user
+;team_ids =
+;allowed_organizations =
+;tls_skip_verify_insecure = false
+;tls_client_cert =
+;tls_client_key =
+;tls_client_ca =
+
+#################################### Grafana.com Auth ####################
+[auth.grafana_com]
+;enabled = false
+;allow_sign_up = true
+;client_id = some_id
+;client_secret = some_secret
+;scopes = user:email
+;allowed_organizations =
+
+#################################### Auth Proxy ##########################
+[auth.proxy]
+;enabled = false
+;header_name = X-WEBAUTH-USER
+;header_property = username
+;auto_sign_up = true
+;ldap_sync_ttl = 60
+;whitelist = 192.168.1.1, 192.168.2.1
+
+#################################### Basic Auth ##########################
+[auth.basic]
+;enabled = true
+
+#################################### Auth LDAP ##########################
+[auth.ldap]
+;enabled = false
+;config_file = /etc/grafana/ldap.toml
+;allow_sign_up = true
+
+#################################### SMTP / Emailing ##########################
+[smtp]
+;enabled = false
+;host = localhost:25
+;user =
+# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;"""
+;password =
+;cert_file =
+;key_file =
+;skip_verify = false
+;from_address = admin@grafana.localhost
+;from_name = Grafana
+# EHLO identity in SMTP dialog (defaults to instance_name)
+;ehlo_identity = dashboard.example.com
+
+[emails]
+;welcome_email_on_sign_up = false
+
+#################################### Logging ##########################
+[log]
+# Either "console", "file", "syslog". Default is console and  file
+# Use space to separate multiple modes, e.g. "console file"
+;mode = console file
+
+# Either "debug", "info", "warn", "error", "critical", default is "info"
+;level = info
+
+# optional settings to set different levels for specific loggers. Ex filters = sqlstore:debug
+;filters =
+
+# For "console" mode only
+[log.console]
+;level =
+
+# log line format, valid options are text, console and json
+;format = console
+
+# For "file" mode only
+[log.file]
+;level =
+
+# log line format, valid options are text, console and json
+;format = text
+
+# This enables automated log rotate(switch of following options), default is true
+;log_rotate = true
+
+# Max line number of single file, default is 1000000
+;max_lines = 1000000
+
+# Max size shift of single file, default is 28 means 1 << 28, 256MB
+;max_size_shift = 28
+
+# Segment log daily, default is true
+;daily_rotate = true
+
+# Expired days of log file(delete after max days), default is 7
+;max_days = 7
+
+[log.syslog]
+;level =
+
+# log line format, valid options are text, console and json
+;format = text
+
+# Syslog network type and address. This can be udp, tcp, or unix. If left blank, the default unix endpoints will be used.
+;network =
+;address =
+
+# Syslog facility. user, daemon and local0 through local7 are valid.
+;facility =
+
+# Syslog tag. By default, the process' argv[0] is used.
+;tag =
+
+#################################### Alerting ############################
+[alerting]
+# Disable alerting engine & UI features
+;enabled = true
+# Makes it possible to turn off alert rule execution but alerting UI is visible
+;execute_alerts = true
+
+#################################### Explore #############################
+[explore]
+# Enable the Explore section
+;enabled = false
+
+#################################### Internal Grafana Metrics ##########################
+# Metrics available at HTTP API Url /metrics
+[metrics]
+# Disable / Enable internal metrics
+;enabled           = true
+
+# Publish interval
+;interval_seconds  = 10
+
+# Send internal metrics to Graphite
+[metrics.graphite]
+# Enable by setting the address setting (ex localhost:2003)
+;address =
+;prefix = prod.grafana.%(instance_name)s.
+
+#################################### Distributed tracing ############
+[tracing.jaeger]
+# Enable by setting the address sending traces to jaeger (ex localhost:6831)
+;address = localhost:6831
+# Tag that will always be included in when creating new spans. ex (tag1:value1,tag2:value2)
+;always_included_tag = tag1:value1
+# Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote
+;sampler_type = const
+# jaeger samplerconfig param
+# for "const" sampler, 0 or 1 for always false/true respectively
+# for "probabilistic" sampler, a probability between 0 and 1
+# for "rateLimiting" sampler, the number of spans per second
+# for "remote" sampler, param is the same as for "probabilistic"
+# and indicates the initial sampling rate before the actual one
+# is received from the mothership
+;sampler_param = 1
+
+#################################### Grafana.com integration  ##########################
+# Url used to to import dashboards directly from Grafana.com
+[grafana_com]
+;url = https://grafana.com
+
+#################################### External image storage ##########################
+[external_image_storage]
+# Used for uploading images to public servers so they can be included in slack/email messages.
+# you can choose between (s3, webdav, gcs, azure_blob, local)
+;provider =
+
+[external_image_storage.s3]
+;bucket =
+;region =
+;path =
+;access_key =
+;secret_key =
+
+[external_image_storage.webdav]
+;url =
+;public_url =
+;username =
+;password =
+
+[external_image_storage.gcs]
+;key_file =
+;bucket =
+;path =
+
+[external_image_storage.azure_blob]
+;account_name =
+;account_key =
+;container_name =
+
+[external_image_storage.local]
+# does not require any configuration

+ 18 - 0
dev/provisioning/ansible/roles/haproxy/defaults/main.yml

@@ -0,0 +1,18 @@
+---
+# Frontend settings.
+frontend_mode: 'http'
+ssl_name: 'nextcloud.test'
+ssl_crt_path: '/etc/ssl/private'
+ssl_self: true
+
+# Backend settings.
+backend_mode: 'http'
+backend_balance_method: 'roundrobin' # leastconn | roundrobin
+
+# Specific nextcloud settings.
+nc_settings: true
+network_allowed: '192.168.56.0/24'
+
+# List of backend servers.
+haproxy_backend_servers:
+  - { name: 'web', ip: '192.168.56.14:8000' }

+ 3 - 0
dev/provisioning/ansible/roles/haproxy/handlers/main.yml

@@ -0,0 +1,3 @@
+---
+- name: restart haproxy
+  service: name=haproxy state=restarted

+ 67 - 0
dev/provisioning/ansible/roles/haproxy/tasks/main.yml

@@ -0,0 +1,67 @@
+---
+- name: Get HAProxy version.
+  command: haproxy -v
+  register: haproxy_version_result
+  changed_when: false
+  check_mode: false
+
+- name: Set HAProxy version.
+  set_fact:
+    haproxy_version: '{{ haproxy_version_result.stdout_lines[0] | regex_replace("^HA-Proxy version ([0-9]\.[0-9]).*$", "\1") }}'
+
+- name: Ensure HAProxy is started and enabled on boot.
+  service: name=haproxy state=started enabled=yes
+
+- name: Create private key (RSA, 4096 bits)
+  community.crypto.openssl_privatekey:
+    path: "{{ ssl_crt_path }}/{{ ssl_name }}.key"
+  when: ssl_self
+
+- name: Create certificate signing request (CSR) for self-signed certificate
+  community.crypto.openssl_csr_pipe:
+    privatekey_path: "{{ ssl_crt_path }}/{{ ssl_name }}.key"
+    country_name: BE
+    locality_name: Louvain-la-Neuve
+    common_name: "{{ ssl_name }}"
+    organization_name: UCLouvain
+    organizational_unit_name: ELIC
+  register: csr
+  when: ssl_self
+
+- name: Generate a Self Signed OpenSSL certificate
+  community.crypto.x509_certificate:
+    path: "{{ ssl_crt_path }}/{{ ssl_name }}.crt"
+    csr_content: "{{ csr.csr }}"
+    privatekey_path: "{{ ssl_crt_path }}/{{ ssl_name }}.key"
+    provider: selfsigned
+  when: ssl_self
+
+- name: Merge KEY and CRT to generate PEM
+  shell: "cat {{ ssl_crt_path }}/{{ ssl_name }}.key {{ ssl_crt_path }}/{{ ssl_name }}.crt >> {{ ssl_crt_path }}/{{ ssl_name }}.pem"
+  when: ssl_self
+
+- name: Generate DH Parameters with a different size (2048 bits)
+  community.crypto.openssl_dhparam:
+    path: /etc/haproxy/dhparams.pem
+    size: 2048
+
+- name: Add ssl dhparam file
+  lineinfile:
+    path: /etc/haproxy/haproxy.cfg
+    insertafter: "^.*ssl-default-bind-options.*"
+    line: "\tssl-dh-param-file /etc/haproxy/dhparams.pem"
+    firstmatch: yes
+    state: present 
+
+- name: Copy HAProxy configuration in place
+  set_fact:
+    cfg_content: "{{ lookup('template', '{{ role_path }}/templates/haproxy.cfg.j2') }}"
+
+- name: Merge HAProxy config file
+  blockinfile:
+    dest: "/etc/haproxy/haproxy.cfg"
+    content: '{{ cfg_content }}'
+    state: present
+
+- name: HAProxy restart
+  service: name=haproxy state=restarted

+ 41 - 0
dev/provisioning/ansible/roles/haproxy/templates/haproxy.cfg.j2

@@ -0,0 +1,41 @@
+
+frontend http_frontend
+  mode {{ frontend_mode }}
+	bind *:80
+	bind *:443 ssl crt  {{ ssl_crt_path }}/{{ ssl_name }}.pem alpn h2,http/1.1
+
+{% if nc_settings is sameas true %}
+	maxconn 20000
+	acl url_discovery_dav path /.well-known/caldav /.well-known/carddav
+	acl url_discovery_inf path /.well-known/webfinger /.well-known/nodeinfo
+	http-request redirect location /remote.php/dav/ code 301 if url_discovery_dav
+	http-request redirect location /index.php%[capture.req.uri] code 301 if url_discovery_inf
+	http-response set-header Strict-Transport-Security max-age=63072000
+{% endif %}
+	option forwardfor
+	option http-server-close
+
+{% if network_allowed != '' %}
+	#Only allow some services to be available internally
+	acl network_allowed src {{ network_allowed }}
+
+{% endif %}
+	redirect scheme https code 301 if !{ ssl_fc }
+	default_backend http_servers
+
+backend http_servers
+	mode {{ backend_mode }}
+	balance {{ backend_balance_method }}
+{% if nc_settings is sameas true %}
+	option httpchk HEAD /
+	cookie SERVERID insert indirect nocache
+	http-check expect rstatus [2-3][0-9][0-9]
+	http-response set-header X-Frame-Options SAMEORIGIN
+	http-response set-header X-XSS-Protection 1;mode=block
+	http-response set-header X-Content-Type-Options nosniff
+	default-server check maxconn 5000
+{% endif %}
+
+{% if haproxy_backend_servers != '' %}
+	server {{ haproxy_backend_servers.name }} {{ haproxy_backend_servers.ip }}
+{% endif %}

+ 42 - 0
dev/provisioning/ansible/roles/mariadb/defaults/main.yml

@@ -0,0 +1,42 @@
+---
+# defaults file for mariadb
+mariadb_version: "10.4"
+
+mysql_user_name: admin
+mysql_user_password: pedro
+
+mysql_root_username: root
+mysql_root_password: pedro
+
+# Set this to `true` to forcibly update the root password.
+#mysql_root_password_update: false
+#mysql_user_password_update: false
+
+# Allow remote root login
+disable_remote_root_login: true
+
+# Specify address to listen
+mariadb_bind_address: '0.0.0.0'
+mariadb_port: 3306
+
+# Add mariabd databases
+# default create nothing
+mariadb_database: 
+  - name: nextcloudb
+    collation: utf8_general_ci
+    encoding: utf8
+    state: present
+    target: omit
+
+# Add mariabd users
+# default create nothing
+mariadb_user: 
+  - name: web
+    password: secret
+    #host: 10.90.90.14 (replaced with global vars when calling role)
+    priv: 'nextcloudb.*:ALL,GRANT'
+    encrypted: false
+
+# Specify slow query log
+mariadb_slow_query_log_enabled: false
+mariadb_slow_query_time: "2"

+ 6 - 0
dev/provisioning/ansible/roles/mariadb/handlers/main.yml

@@ -0,0 +1,6 @@
+---
+# handlers file for ansible-role-mariadb
+- name: Restart mariadb
+  service:
+    name: "{{ mariadb_service }}"
+    state: restarted

+ 67 - 0
dev/provisioning/ansible/roles/mariadb/tasks/config/secure-installation.yml

@@ -0,0 +1,67 @@
+---
+#- name: Ensure default user is present.
+#  mysql_user:
+#    name: "{{ mysql_user_name }}"
+#    host: 'localhost'
+#    password: "{{ mysql_user_password }}"
+#    priv: '*.*:ALL,GRANT'
+#    state: present
+#  when: mysql_user_name != mysql_root_username
+#
+## Has to be after the password assignment, for idempotency.
+#- name: Copy user-my.cnf file with password credentials.
+#  template:
+#    src: "user-my.cnf.j2"
+#    dest: "/root/.my.cnf"
+#    owner: "{{ mysql_user_name }}"
+#    mode: 0600
+#  when: mysql_user_name != mysql_root_username
+
+- name: Disallow root login remotely
+  command: 'mysql -NBe "{{ item }}"'
+  with_items:
+    - DELETE FROM mysql.user WHERE User='{{ mysql_root_username }}' AND Host NOT IN ('localhost', '127.0.0.1', '::1')
+  changed_when: false
+
+- name: Get list of hosts for the root user.
+  command: mysql -NBe
+    "SELECT Host
+    FROM mysql.user
+    WHERE User = '{{ mysql_root_username }}'
+    ORDER BY (Host='localhost') ASC"
+  register: mysql_root_hosts
+  changed_when: false
+  check_mode: false
+
+# Set root password for MySQL
+- name: Update MySQL root password for localhost root account
+  shell: >
+    mysql -NBe
+    'SET PASSWORD FOR "{{ mysql_root_username }}"@"{{ item }}" = PASSWORD("{{ mysql_root_password }}"); FLUSH PRIVILEGES;'
+  with_items: "{{ mysql_root_hosts.stdout_lines|default([]) }}"
+
+# Has to be after the root password assignment, for idempotency.
+- name: Copy .my.cnf file with root password credentials.
+  template:
+    src: "root-my.cnf.j2"
+    dest: "/root/.my.cnf"
+    owner: root
+    group: root
+    mode: 0600
+
+- name: Get list of hosts for the anonymous user.
+  command: mysql -NBe "SELECT Host FROM mysql.user WHERE User = ''"
+  register: mysql_anonymous_hosts
+  changed_when: false
+  check_mode: false
+
+- name: Remove anonymous MySQL users.
+  mysql_user:
+    name: ""
+    host: "{{ item }}"
+    state: absent
+  with_items: "{{ mysql_anonymous_hosts.stdout_lines|default([]) }}"
+  no_log: true
+
+- name: Remove MySQL test database.
+  mysql_db: "name='test' state=absent"

+ 31 - 0
dev/provisioning/ansible/roles/mariadb/tasks/config/secure.yml

@@ -0,0 +1,31 @@
+---
+- name: Update MySQL root password for localhost root account (5.7.x).
+  shell: >
+    mysql -u root -NBe
+    "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('{{ mysql_root_password }}'); FLUSH PRIVILEGES;"
+  register: result
+  ignore_errors: true
+
+- name: Disallow root login remotely
+  command: 'mysql -NBe "{{ item }}" -p"{{ mysql_root_password }}"'
+  with_items:
+    - DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')
+  changed_when: false
+  when: (disable_remote_root_login|bool) and (result is succeeded)
+
+- name: Remove anonymous MySQL users
+  mysql_user:
+    name: ''
+    host_all: yes
+    login_user: root
+    login_password: "{{ mysql_root_password }}"
+    state: absent
+    login_unix_socket: "{{ mariadb_socket }}"
+
+- name: Remove MySQL test database
+  mysql_db:
+    name: test
+    login_user: root
+    login_password: "{{ mysql_root_password }}"
+    state: absent
+    login_unix_socket: "{{ mariadb_socket }}"

+ 16 - 0
dev/provisioning/ansible/roles/mariadb/tasks/config/template.yml

@@ -0,0 +1,16 @@
+---
+- name: Get MySQL version.
+  command: 'mysql --version'
+  register: mysql_cli_version
+  changed_when: false
+  check_mode: false
+
+- name: setup Mariadb config file
+  template:
+    src: server.j2
+    dest: "{{ mariadb_config_file }}"
+    owner: "{{ mariadb_config_file_owner }}"
+    group: "{{ mariadb_config_file_group }}"
+    mode: 0644
+  notify: 
+  - Restart mariadb

+ 11 - 0
dev/provisioning/ansible/roles/mariadb/tasks/database/databases.yml

@@ -0,0 +1,11 @@
+---
+
+- name: Ensure Mariadb database are present
+  mysql_db:
+    name: "{{ item.name }}"
+    collation: "{{ item.collation | default('utf8_general_ci') }}"
+    encoding: "{{ item.encoding | default('utf8') }}"
+    state: "{{ item.state | default('present') }}"
+    target: "{{ item.target | default(omit) }}"
+    login_unix_socket: "{{ mariadb_socket }}"
+  with_items: "{{ mariadb_database }}"

+ 15 - 0
dev/provisioning/ansible/roles/mariadb/tasks/database/users.yml

@@ -0,0 +1,15 @@
+---
+
+- name: Ensure Mariadb users are present.
+  mysql_user:
+    name: "{{ item.name }}"
+    #host: "{{ item.host | default('localhost') }}"
+    host: "{{ app_bind_address | default('localhost') }}"
+    password: "{{ item.password }}"
+    priv: "{{ item.priv | default('*.*:USAGE') }}"
+    state: "{{ item.state | default('present') }}"
+    append_privs: "{{ item.append_privs | default('no') }}"
+    encrypted: "{{ item.encrypted | default('no') }}"
+    login_unix_socket: "{{ mariadb_socket }}"
+  with_items: "{{ mariadb_user }}"
+  no_log: true

+ 20 - 0
dev/provisioning/ansible/roles/mariadb/tasks/main.yml

@@ -0,0 +1,20 @@
+---
+# tasks file for ansible-role-mariadb
+
+- name: Include OS specific variables.
+  include_vars: "{{ ansible_os_family }}.yml"
+
+- name: Install Mariadb
+  include_tasks: "setup/{{ ansible_os_family }}.yml"
+
+- name: Ensure Mariadb configfile is present
+  include_tasks: "config/template.yml"
+
+- name: Ensure Mariadb is secure
+  include_tasks: "config/secure-installation.yml"
+
+- name: Ensure Mariadb databases are present
+  include_tasks: "database/databases.yml"
+
+- name: Ensure Mariadb users are present
+  include_tasks: "database/users.yml"

+ 17 - 0
dev/provisioning/ansible/roles/mariadb/tasks/setup/RedHat.yml

@@ -0,0 +1,17 @@
+---
+# Install mariadb
+- name: Add MariaDB Repository for {{ ansible_distribution }}
+  template:
+    src: mariadb-server.repo.j2
+    dest: /etc/yum.repos.d/mariadb-server.repo
+
+- name: Install all the {{ ansible_distribution }} mariadb packages
+  dnf:
+    name: "{{ mariadb_packages }}"
+    state: present
+
+- name: Mariadb service
+  service:
+    name: "{{ mariadb_service }}"
+    state: started
+    enabled: yes

+ 13 - 0
dev/provisioning/ansible/roles/mariadb/tasks/setup/Suse.yml

@@ -0,0 +1,13 @@
+---
+# Install mariadb
+
+- name: Install all the Suse mariadb packages
+  zypper:
+    name: "{{ mariadb_packages }}"
+    state: present
+
+- name: Mariadb service
+  service:
+    name: "{{ mariadb_service }}"
+    state: started
+    enabled: yes

+ 33 - 0
dev/provisioning/ansible/roles/mariadb/templates/galera.j2

@@ -0,0 +1,33 @@
+#
+# These groups are read by MariaDB server.
+# Use it for options that only the server (but not clients) should see
+
+# this is read by the standalone daemon and embedded servers
+[server]
+
+[mysqld]
+bind-address = {{ mariadb_bind_address }}
+port = {{ mariadb_port }}
+
+{% if mariadb_slow_query_log_enabled == true %}
+slow_query_log = 1
+long_query_time = {{ mariadb_slow_query_time }}
+{% endif %}
+
+default-storage-engine = innodb
+
+# Galera-related settings
+[galera]
+wsrep_provider = {{ galera_wsrep_provider }}
+wsrep_cluster_address = "gcomm://{% for host in groups['galera_cluster'] %}{{ hostvars[host]['ansible_default_ipv4']['address'] }},{% endfor %}"
+wsrep_node_name = {{ ansible_hostname }}
+wsrep_cluster_name = {{ galera_cluster_name }}
+wsrep_node_address = {{ ansible_default_ipv4.address }}
+binlog_format = row
+default_storage_engine = InnoDB
+innodb_autoinc_lock_mode = 2
+wsrep_on = ON
+
+[embedded]
+
+[mariadb]

+ 9 - 0
dev/provisioning/ansible/roles/mariadb/templates/mariadb-server.repo.j2

@@ -0,0 +1,9 @@
+
+[mariadb]
+name = MariaDB
+baseurl = "http://yum.mariadb.org/{{ mariadb_version}}/{{ ansible_distribution|lower|regex_replace('redhat', 'rhel')|regex_replace('oraclelinux', 'centos') }}{{ ansible_distribution_major_version }}-amd64"
+gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
+gpgcheck=1
+{% if ansible_distribution_file_variety == "RedHat" and ansible_distribution_major_version == "8" %}
+module_hotfixes=1
+{% endif %}

+ 5 - 0
dev/provisioning/ansible/roles/mariadb/templates/root-my.cnf.j2

@@ -0,0 +1,5 @@
+{{ ansible_managed | comment }}
+
+[client]
+user="{{ mysql_root_username }}"
+password="{{ mysql_root_password }}"

+ 22 - 0
dev/provisioning/ansible/roles/mariadb/templates/server.j2

@@ -0,0 +1,22 @@
+#
+# These groups are read by MariaDB server.
+# Use it for options that only the server (but not clients) should see
+#
+# See the examples of server my.cnf files in /usr/share/mysql/
+#
+
+# this is read by the standalone daemon and embedded servers
+[server]
+
+[mysqld]
+bind-address = {{ mariadb_bind_address }}
+port = {{ mariadb_port }}
+
+{% if mariadb_slow_query_log_enabled == true %}
+slow_query_log = 1
+long_query_time = {{ mariadb_slow_query_time }}
+{% endif %}
+
+[embedded]
+
+[mariadb]

+ 5 - 0
dev/provisioning/ansible/roles/mariadb/templates/user-my.cnf.j2

@@ -0,0 +1,5 @@
+{{ ansible_managed | comment }}
+
+[client]
+user="{{ mysql_user_name }}"
+password="{{ mysql_user_password }}"

+ 12 - 0
dev/provisioning/ansible/roles/mariadb/vars/RedHat.yml

@@ -0,0 +1,12 @@
+mariadb_packages:
+  - mariadb
+  - mariadb-server
+  - mariadb-libs
+  - MySQL-python
+  - perl-DBD-MySQL
+
+mariadb_service: mariadb
+mariadb_config_file: /etc/my.cnf.d/server.cnf
+mariadb_socket: /var/lib/mysql/mysql.sock
+mariadb_config_file_owner: root
+mariadb_config_file_group: root

+ 9 - 0
dev/provisioning/ansible/roles/mariadb/vars/Suse.yml

@@ -0,0 +1,9 @@
+mariadb_packages:
+  - mariadb
+  - python3-PyMySQL
+
+mariadb_service: mariadb
+mariadb_config_file: /etc/my.cnf.d/server.cnf
+mariadb_socket: /run/mysql/mysql.sock
+mariadb_config_file_owner: root
+mariadb_config_file_group: root

+ 83 - 0
dev/provisioning/ansible/roles/nextcloud/defaults/main.yml

@@ -0,0 +1,83 @@
+---
+# defaults file for nextcloud
+NEXTCLOUD_VERSION: 24.0.5 # overload from the role
+NEXTCLOUD_TARBALL: "nextcloud-{{ NEXTCLOUD_VERSION }}.tar.bz2"
+NEXTCLOUD_URL: "https://download.nextcloud.com/server/releases/{{ NEXTCLOUD_TARBALL }}"
+NEXTCLOUD_GPG: "https://nextcloud.com/nextcloud.asc"
+GPG_FINGERPRINT: "28806A878AE423A28372792ED75899B9A724937A"
+
+# [PHP CONFIG AND EXTENSIONS]
+php_version: 8.1
+PHP_POST_LIMIT: 50G
+PHP_UPLOAD_LIMIT: 25G
+PHP_MAX_FILE: 200
+PHP_MAX_TIME: 3600
+PHP_MEMORY_LIMIT: 512M
+
+APC_SHM_SIZE: 128M
+OPCACHE_MEM_SIZE: 128M
+
+add_php_fpm: true
+nc_pm: "ondemand"
+nc_pm_max_children: 80
+nc_pm_start_servers: 2
+nc_pm_min_spare_servers: 1
+nc_pm_max_spare_servers: 3
+
+# [REDIS CONFIG]
+use_redis_server: false    # overload from the role
+redis_host: "127.0.0.1"    # overload from the role
+
+# [NEXTCLOUD CONFIG]
+nextcloud_trusted_domain: "nextcloud.test"
+nextcloud_ipv6: false
+debug_speed: false       # overload from the role
+
+nextcloud_instance_name: "{{ nextcloud_trusted_domain }}"
+
+nextcloud_install_websrv: true
+nextcloud_websrv: "apache2"  # "apache2" | "nginx"
+nextcloud_disable_websrv_default_site: false
+nextcloud_websrv_template: "templates/{{ nextcloud_websrv }}_nc.j2"
+nc_data_dir: "/srv/data"
+nc_admin_name: "pedro"
+nc_admin_pwd: "pedro"
+
+nc_loglevel: 2
+nc_log_rotate_size: 10485760
+nc_background_cron: true
+nc_cron_period: 10 # every <nc_cron_period> min
+
+## Custom nextcloud settings
+## https://docs.nextcloud.com/server/12/admin_manual/configuration_server/config_sample_php_parameters.html
+nextcloud_config_settings:
+  - { name: 'default_phone_region', value: 'BE' }  # set a country code using ISO 3166-1
+  - { name: 'open_basedir', value: '/dev/urandom' }
+  - { name: 'mysql.utf8mb4', value: 'true' }
+  - { name: 'updater.release.channel', value: 'production' }  # production | stable | daily | beta
+  - { name: 'mail_smtpmode', value: 'smtp' }
+  - { name: 'mail_domain', value: 'uclouvain.be' }
+  - { name: 'mail_smtphost', value: 'smtp.sgsi.ucl.ac.be' }
+  - { name: 'mail_smtpauthtype', value: 'LOGIN' }
+  - { name: 'overwrite.cli.url', value: 'https://{{ nextcloud_trusted_domain }}' }
+  - { name: 'overwritehost', value: 'nextcloud.test' }
+  - { name: 'overwriteprotocol', value: 'https' }
+
+#php /var/www/html/occ config:system:set share_folder --value="/Shared"
+
+# [DATABASE]
+db_host: "127.0.0.1" # overload from the role
+nc_db_name: "nextcloudb"
+nc_db_user: "web"
+nc_db_password: "secret"
+
+# [APPS]
+nextcloud_apps:
+  - twofactor_totp
+  - deck
+  - tasks
+  - calendar
+  - contacts
+  - apporder
+
+nc_collabora: false

+ 4 - 0
dev/provisioning/ansible/roles/nextcloud/files/apcu.config.php

@@ -0,0 +1,4 @@
+<?php
+$CONFIG = array (
+  'memcache.local' => '\OC\Memcache\APCu',
+);

+ 15 - 0
dev/provisioning/ansible/roles/nextcloud/files/apps.config.php

@@ -0,0 +1,15 @@
+<?php
+$CONFIG = array (
+  'apps_paths' => array (
+      0 => array (
+              'path'     => OC::$SERVERROOT.'/apps',
+              'url'      => '/apps',
+              'writable' => false,
+      ),
+      1 => array (
+              'path'     => OC::$SERVERROOT.'/custom_apps',
+              'url'      => '/custom_apps',
+              'writable' => true,
+      ),
+  ),
+);

+ 12 - 0
dev/provisioning/ansible/roles/nextcloud/files/mysql_nextcloud.cnf

@@ -0,0 +1,12 @@
+################################################################################
+# This file was generated by Ansible
+# Do NOT modify this file by hand!
+################################################################################
+
+# Nextcloud mysql.cnf
+
+[mysqld]
+binlog_format = MIXED
+innodb_large_prefix=on
+innodb_file_format=barracuda
+innodb_file_per_table=true

TEMPAT SAMPAH
dev/provisioning/ansible/roles/nextcloud/files/nextcloud_choosing_version.png


+ 182 - 0
dev/provisioning/ansible/roles/nextcloud/files/nextcloud_custom_mimetypemapping.json

@@ -0,0 +1,182 @@
+{
+        "_comment" : "This file was generated by Ansible, Do NOT modify this file by hand!",
+
+        "3gp": ["video/3gpp"],
+        "7z": ["application/x-7z-compressed"],
+        "accdb": ["application/msaccess"],
+        "ai": ["application/illustrator"],
+        "apk": ["application/vnd.android.package-archive"],
+        "arw": ["image/x-dcraw"],
+        "avi": ["video/x-msvideo"],
+        "bash": ["text/x-shellscript"],
+        "blend": ["application/x-blender"],
+        "bin": ["application/x-bin"],
+        "bmp": ["image/bmp"],
+        "bpg": ["image/bpg"],
+        "bz2": ["application/x-bzip2"],
+        "cb7": ["application/x-cbr"],
+        "cba": ["application/x-cbr"],
+        "cbr": ["application/x-cbr"],
+        "cbt": ["application/x-cbr"],
+        "cbtc": ["application/x-cbr"],
+        "cbz": ["application/x-cbr"],
+        "cc": ["text/x-c"],
+        "cdr": ["application/coreldraw"],
+        "class": ["application/java"],
+        "cnf": ["text/plain"],
+        "conf": ["text/plain"],
+        "cpp": ["text/x-c++src"],
+        "cr2": ["image/x-dcraw"],
+        "css": ["text/css"],
+        "csv": ["text/csv"],
+        "cvbdl": ["application/x-cbr"],
+        "c": ["text/x-c"],
+        "c++": ["text/x-c++src"],
+        "dcr": ["image/x-dcraw"],
+        "deb": ["application/x-deb"],
+        "dng": ["image/x-dcraw"],
+        "doc": ["application/msword"],
+        "docm": ["application/vnd.ms-word.document.macroEnabled.12"],
+        "docx": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
+        "dot": ["application/msword"],
+        "dotx": ["application/vnd.openxmlformats-officedocument.wordprocessingml.template"],
+        "dv": ["video/dv"],
+        "eot": ["application/vnd.ms-fontobject"],
+        "epub": ["application/epub+zip"],
+        "eps": ["application/postscript"],
+        "erf": ["image/x-dcraw"],
+        "exe": ["application/x-ms-dos-executable"],
+        "fb2": ["application/x-fictionbook+xml", "text/plain"],
+        "flac": ["audio/flac"],
+        "flv": ["video/x-flv"],
+        "gif": ["image/gif"],
+        "gz": ["application/x-gzip"],
+        "gzip": ["application/x-gzip"],
+        "h": ["text/x-h"],
+        "hh": ["text/x-h"],
+        "hpp": ["text/x-h"],
+        "html": ["text/html", "text/plain"],
+        "htm": ["text/html", "text/plain"],
+        "ical": ["text/calendar"],
+        "ics": ["text/calendar"],
+        "iiq": ["image/x-dcraw"],
+        "impress": ["text/impress"],
+        "java": ["text/x-java-source"],
+        "jpeg": ["image/jpeg"],
+        "jpg": ["image/jpeg"],
+        "jps": ["image/jpeg"],
+        "js": ["application/javascript", "text/plain"],
+        "json": ["application/json", "text/plain"],
+        "k25": ["image/x-dcraw"],
+        "kdc": ["image/x-dcraw"],
+        "key": ["application/x-iwork-keynote-sffkey"],
+        "keynote": ["application/x-iwork-keynote-sffkey"],
+        "kra": ["application/x-krita"],
+        "lwp": ["application/vnd.lotus-wordpro"],
+        "m2t": ["video/mp2t"],
+        "m4a": ["audio/mp4"],
+        "m4b": ["audio/m4b"],
+        "m4v": ["video/mp4"],
+        "markdown": ["text/markdown"],
+        "mdown": ["text/markdown"],
+        "md": ["text/markdown"],
+        "mdb": ["application/msaccess"],
+        "mdwn": ["text/markdown"],
+        "mkd": ["text/markdown"],
+        "mef": ["image/x-dcraw"],
+        "mkv": ["video/x-matroska"],
+        "mobi": ["application/x-mobipocket-ebook"],
+        "mov": ["video/quicktime"],
+        "mp3": ["audio/mpeg"],
+        "mp4": ["video/mp4"],
+        "mpeg": ["video/mpeg"],
+        "mpg": ["video/mpeg"],
+        "mpo": ["image/jpeg"],
+        "msi": ["application/x-msi"],
+        "mts": ["video/MP2T"],
+        "mt2s": ["video/MP2T"],
+        "nef": ["image/x-dcraw"],
+        "numbers": ["application/x-iwork-numbers-sffnumbers"],
+        "odf": ["application/vnd.oasis.opendocument.formula"],
+        "odg": ["application/vnd.oasis.opendocument.graphics"],
+        "odp": ["application/vnd.oasis.opendocument.presentation"],
+        "ods": ["application/vnd.oasis.opendocument.spreadsheet"],
+        "odt": ["application/vnd.oasis.opendocument.text"],
+        "oga": ["audio/ogg"],
+        "ogg": ["audio/ogg"],
+        "ogv": ["video/ogg"],
+        "one": ["application/msonenote"],
+        "opus": ["audio/ogg"],
+        "orf": ["image/x-dcraw"],
+        "otf": ["application/font-sfnt"],
+        "pad": ["application/x-ownpad"],
+        "calc": ["application/x-ownpad"],
+        "pages": ["application/x-iwork-pages-sffpages"],
+        "pdf": ["application/pdf"],
+        "pfb": ["application/x-font"],
+        "pef": ["image/x-dcraw"],
+        "php": ["application/x-php"],
+        "pl": ["application/x-perl"],
+        "png": ["image/png"],
+        "pot": ["application/vnd.ms-powerpoint"],
+        "potm": ["application/vnd.ms-powerpoint.template.macroEnabled.12"],
+        "potx": ["application/vnd.openxmlformats-officedocument.presentationml.template"],
+        "ppa": ["application/vnd.ms-powerpoint"],
+        "ppam": ["application/vnd.ms-powerpoint.addin.macroEnabled.12"],
+        "pps": ["application/vnd.ms-powerpoint"],
+        "ppsm": ["application/vnd.ms-powerpoint.slideshow.macroEnabled.12"],
+        "ppsx": ["application/vnd.openxmlformats-officedocument.presentationml.slideshow"],
+        "ppt": ["application/vnd.ms-powerpoint"],
+        "pptm": ["application/vnd.ms-powerpoint.presentation.macroEnabled.12"],
+        "pptx": ["application/vnd.openxmlformats-officedocument.presentationml.presentation"],
+        "ps": ["application/postscript"],
+        "psd": ["application/x-photoshop"],
+        "py": ["text/x-python"],
+        "raf": ["image/x-dcraw"],
+        "rar": ["application/x-rar-compressed"],
+        "reveal": ["text/reveal"],
+        "rss": ["application/rss+xml"],
+        "rtf": ["text/rtf"],
+        "rw2": ["image/x-dcraw"],
+        "sgf": ["application/sgf"],
+        "sh-lib": ["text/x-shellscript"],
+        "sh": ["text/x-shellscript"],
+        "srf": ["image/x-dcraw"],
+        "sr2": ["image/x-dcraw"],
+        "svg": ["image/svg+xml", "text/plain"],
+        "swf": ["application/x-shockwave-flash", "application/octet-stream"],
+        "tar": ["application/x-tar"],
+        "tar.bz2": ["application/x-bzip2"],
+        "tar.gz": ["application/x-compressed"],
+        "tbz2": ["application/x-bzip2"],
+        "tex": ["application/x-tex"],
+        "tgz": ["application/x-compressed"],
+        "tiff": ["image/tiff"],
+        "tif": ["image/tiff"],
+        "ttf": ["application/font-sfnt"],
+        "txt": ["text/plain"],
+        "vcard": ["text/vcard"],
+        "vcf": ["text/vcard"],
+        "vob": ["video/dvd"],
+        "vsd": ["application/vnd.visio"],
+        "wav": ["audio/wav"],
+        "webm": ["video/webm"],
+        "woff": ["application/font-woff"],
+        "wpd": ["application/vnd.wordperfect"],
+        "wmv": ["video/x-ms-wmv"],
+        "xcf": ["application/x-gimp"],
+        "xla": ["application/vnd.ms-excel"],
+        "xlam": ["application/vnd.ms-excel.addin.macroEnabled.12"],
+        "xls": ["application/vnd.ms-excel"],
+        "xlsb": ["application/vnd.ms-excel.sheet.binary.macroEnabled.12"],
+        "xlsm": ["application/vnd.ms-excel.sheet.macroEnabled.12"],
+        "xlsx": ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
+        "xlt": ["application/vnd.ms-excel"],
+        "xltm": ["application/vnd.ms-excel.template.macroEnabled.12"],
+        "xltx": ["application/vnd.openxmlformats-officedocument.spreadsheetml.template"],
+        "xml": ["application/xml", "text/plain"],
+        "xrf": ["image/x-dcraw"],
+        "yaml": ["application/yaml", "text/plain"],
+        "yml": ["application/yaml", "text/plain"],
+        "zip": ["application/zip"]
+}

File diff ditekan karena terlalu besar
+ 0 - 0
dev/provisioning/ansible/roles/nextcloud/files/nextcloud_file_name.xml


+ 41 - 0
dev/provisioning/ansible/roles/nextcloud/handlers/main.yml

@@ -0,0 +1,41 @@
+---
+# handlers file for nextcloud
+- name: restart mysql
+  ansible.builtin.service:
+    name: "{{ mysql_daemon }}"
+    state: restarted
+
+- name: start http
+  ansible.builtin.service:
+    name: "{{ http_service_name }}"
+    state: started
+
+- name: restart http
+  ansible.builtin.service:
+    name: "{{ http_service_name }}"
+    state: restarted
+
+- name: reload http
+  ansible.builtin.service:
+    name: "{{ http_service_name }}"
+    state: reloaded
+
+- name: start php-fpm
+  ansible.builtin.service:
+    name: php{{ php_ver }}-fpm
+    state: started
+
+- name: reload php-fpm
+  ansible.builtin.service:
+    name: php{{ php_ver }}-fpm
+    state: reloaded
+
+- name: start redis
+  ansible.builtin.service:
+    name: redis-server
+    state: started
+
+- name: restart redis
+  ansible.builtin.service:
+    name: redis-server
+    state: restarted

+ 56 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/main.yml

@@ -0,0 +1,56 @@
+---
+# tasks file for nextcloud
+
+- name: Main... Check Nextcloud debug speed
+  set_fact:
+    debug_speed_check: "{{ debug_speed }}"
+
+# include os specific tasks
+- include_tasks: "prep_os/{{ ansible_os_family }}.yml"
+
+# install required packages
+- include_tasks: "prep_php/{{ ansible_os_family }}.yml"
+
+- name: Main... Check if a mysql/mariadb database is available
+  shell: mysql --host={{ db_host }} --user={{ nc_db_user }} --password={{ nc_db_password }} -e 'SHOW DATABASES;' | grep -cx {{ nc_db_name }}
+  register: dbstatus
+  failed_when: "dbstatus.stdout|int != 1"
+  no_log: true
+
+- name: Main... Check Nextcloud installed
+  stat:
+    path: "{{ http_webroot }}/nextcloud/index.php"
+  register: nc_nextcloud_installed
+
+- name: Main... Download and Install Nextcloud
+  include_tasks: "nc_download.yml"
+  when: (nc_nextcloud_installed.stat.isreg is undefined) or (not nc_nextcloud_installed.stat.isreg)
+
+- name: Main... Check Nextcloud is installed
+  shell: grep installed {{ http_webroot }}/nextcloud/config/config.php | grep true | wc -l
+  register: nc_installation_configured
+
+- name: Main... Install nextcloud
+  include_tasks: nc_install.yml
+  when: nc_installation_configured.stdout|int == 0
+
+- name: Main... Check Selinux
+  include_tasks: "selinux.yml"
+  when:
+    - (ansible_os_family == "RedHat")
+    - (ansible_selinux.status == "enabled")
+
+- name: Main... Setup nextcloud
+  include_tasks: nc_setup.yml
+
+- name: Main... Restart {{ http_service_name }} service
+  service:
+    name: "{{ http_service_name }}"
+    state: restarted
+
+- name: Main... First run Cron
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} -f cron.php"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"

+ 65 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/nc_download.yml

@@ -0,0 +1,65 @@
+---
+- name: Download... Download Nextcloud archive
+  get_url:
+    url:  "{{ NEXTCLOUD_URL }}"
+    dest: /tmp/{{ NEXTCLOUD_TARBALL }}
+    checksum: "sha256:{{ NEXTCLOUD_URL }}.sha256"
+
+- name: Download... Download generic GPG key
+  get_url:
+    url: "{{ NEXTCLOUD_GPG }}"
+    dest: /tmp/nextcloud.asc
+
+- name: Download... Download Nextcloud release GPG key
+  get_url:
+    url: "{{ NEXTCLOUD_URL }}.asc"
+    dest: /tmp/{{ NEXTCLOUD_TARBALL }}.asc
+
+- name: Download... Import Nextcloud GPG key
+  shell: gpg --import /tmp/nextcloud.asc
+
+- name: Download... See Nextcloud GPG stored
+  set_fact:
+   correct_gpg: "{{ GPG_FINGERPRINT }}"
+
+- name: Download... Verify Nextcloud GPG
+  shell: gpg --verify /tmp/{{ NEXTCLOUD_TARBALL }}.asc /tmp/{{ NEXTCLOUD_TARBALL }} 2>&1 | tail -n 1 | cut -d ':' -f2 | tr -d ' '
+  register: nc_fingerprint
+  failed_when: (nc_fingerprint.stdout|string not in correct_gpg)
+
+- name: Download... Extract Nextcloud
+  unarchive:
+    src: /tmp/{{ NEXTCLOUD_TARBALL }}
+    dest: "{{ http_webroot }}"
+    remote_src: true
+    creates: "{{ http_webroot }}/nextcloud/occ"
+
+- name: Download... Ensure Nextcloud files are 0640
+  shell: find {{ http_webroot }}/nextcloud -type f -exec chmod -c 0640 {} \;
+  register: nc_installation_chmod_result
+  changed_when: "nc_installation_chmod_result.stdout != \"\""
+
+- name: Download... Setting stronger directory ownership
+  file:
+    path: "{{ http_webroot }}/nextcloud/"
+    recurse: true
+    owner: "{{ nextcloud_websrv_user }}"
+    group: "{{ nextcloud_websrv_group }}"
+    state: directory
+
+- name: Download... Ensure Nextcloud .htaccess and .user.ini are 0644 
+  file:
+    path: "{{ item }}"
+    mode: u=rw,g=r,o=r
+  with_items:
+    - "{{ http_webroot }}/nextcloud/.htaccess"
+    - "{{ http_webroot }}/nextcloud/.user.ini"
+
+- name: Download... Remove Nextcloud tmp files
+  ansible.builtin.file:
+    path: "{{ item }}"
+    state: absent
+  with_items:
+    - "/tmp/{{ NEXTCLOUD_TARBALL }}.asc"
+    - "/tmp/{{ NEXTCLOUD_TARBALL }}"
+    - "/tmp/nextcloud.asc"

+ 35 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/nc_install.yml

@@ -0,0 +1,35 @@
+---
+#########
+# Run command line installation.
+# the web server must be running by now in order to launch the installation
+
+- name: Install... Removing possibly old or incomplete config.php
+  file:
+    path: "{{ http_webroot }}/nextcloud/config/config.php"
+    state: absent
+
+- name: Install... Create data directory
+  file:
+    path: "{{ item }}"
+    state: directory
+    owner: "{{ nextcloud_websrv_user }}"
+    group: "{{ nextcloud_websrv_group }}"
+    mode: 0770
+  with_items:
+    - "{{ nc_data_dir }}"
+    - "{{ http_webroot }}/nextcloud/custom_apps"
+      
+- name: Install... First setup Nextcloud
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ maintenance:install --database=mysql --database-host={{ db_host }} --database-name={{ nc_db_name }} --database-user={{ nc_db_user }} --database-pass={{ nc_db_password }} --admin-user={{ nc_admin_name }} --admin-pass={{ nc_admin_pwd }} --data-dir={{ nc_data_dir }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+    creates: "{{ http_webroot }}/nextcloud/config/config.php"
+  register: setup_nc
+
+- name: Install... Removing possibly sample config
+  file:
+    path: "{{ http_webroot }}/nextcloud/config/config.sample.php"
+    state: absent
+

+ 184 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/nc_setup.yml

@@ -0,0 +1,184 @@
+---
+
+- name: Setup... Set APCU config for Nextcloud
+  copy:
+    dest: "{{ http_webroot }}/nextcloud/config/apcu.config.php"
+    src: files/apcu.config.php
+    owner: "{{ nextcloud_websrv_user }}"
+    group: "{{ nextcloud_websrv_group }}"
+    mode: 0640
+
+- name: Setup... Set custom_apps config for Nextcloud
+  copy:
+    dest: "{{ http_webroot }}/nextcloud/config/apps.config.php"
+    src: files/apps.config.php
+    owner: "{{ nextcloud_websrv_user }}"
+    group: "{{ nextcloud_websrv_group }}"
+    mode: 0640
+
+- name: Setup... Set Trusted Domains
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ config:system:set trusted_domains 0 --value={{ nextcloud_trusted_domain }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+
+- name: Setup... Check disabled apps list
+  shell: "{{ php_bin }} occ app:list --no-warnings | grep -A30 'Disabled' | grep -v 'Disabled' | cut -d'-' -f2 | cut -d':' -f1 | grep -v 'encryption'"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  register: nc_apps_list
+  failed_when: nc_apps_list.rc >= 2
+
+- name: Setup... Enable all disabled apps
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ app:enable {{ item }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  with_items: "{{ nc_apps_list.stdout_lines }}"
+  when: nc_apps_list.rc == 0
+
+- name: Setup... Applying default settings
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ {{ item }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  loop:
+    - "config:system:set loglevel --value='{{ nc_loglevel }}'"
+    - "config:system:set log_type --value=file"
+    - "config:system:set logfile --value='{{ nc_data_dir }}/nextcloud.log'"
+    - "config:system:set log_rotate_size --value='{{ nc_log_rotate_size }}'"
+    - "config:app:set admin_audit logfile --value='{{ nc_data_dir }}/audit.log'"
+    - "config:system:set log.condition apps 0 --value='admin_audit'"
+  loop_control:
+    pause: 2
+
+- name: Setup... Applying preview settings
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ {{ item }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  loop:
+    - "config:system:set preview_max_x --value='2048'"
+    - "config:system:set preview_max_y --value='2048'"
+    - "config:app:set preview jpeg_quality --value='60'"
+    - "config:system:set jpeg_quality --value='60'"
+    - "config:system:delete enabledPreviewProviders"
+    - "config:system:set enabledPreviewProviders 1 --value='OC\\Preview\\Image'"
+    - "config:system:set enabledPreviewProviders 2 --value='OC\\Preview\\MarkDown'"
+    - "config:system:set enabledPreviewProviders 3 --value='OC\\Preview\\MP3'"
+    - "config:system:set enabledPreviewProviders 4 --value='OC\\Preview\\TXT'"
+    - "config:system:set enabledPreviewProviders 5 --value='OC\\Preview\\OpenDocument'"
+    - "config:system:set enabledPreviewProviders 6 --value='OC\\Preview\\Movie'"
+    - "config:system:set enable_previews --value=true --type=boolean"
+  loop_control:
+    pause: 2
+
+- name: Setup... Applying other settings
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ {{ item }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  loop:
+    - "config:system:set upgrade.disable-web --type=bool --value=true"
+    - "config:system:set trashbin_retention_obligation --value='auto, 30'"
+    - "config:system:set versions_retention_obligation --value='auto, 30'"
+    - "config:system:set activity_expire_days --value='30'"
+    - "config:system:set simpleSignUpLink.shown --type=bool --value=false"
+    #- "config:system:set share_folder --value='/Shared'"
+  loop_control:
+    pause: 2
+
+- name: Setup... Set Nextcloud system settings in config.php
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ config:system:set {{ item.name }} --value={{ item.value }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  with_items:
+    - "{{ nextcloud_config_settings }}"
+
+- name: Setup... Set Redis Server
+  template:
+    dest: "{{ http_webroot }}/nextcloud/config/redis.config.php" 
+    src: redis.config.php.j2
+    owner: "{{ nextcloud_websrv_user }}"
+    group: "{{ nextcloud_websrv_group }}"
+    mode: 0640
+  when: (use_redis_server | bool)
+
+- name: Setup... Install Nextcloud Apps
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ app:install {{ item }}"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  with_items: "{{ nextcloud_apps }}"
+  register: nc_apps_installed
+  failed_when: nc_apps_installed.rc >= 2
+
+- name: Setup... Configure Cron
+  cron:
+    name: "Nextcloud Cronjob"
+    minute: "*/{{ nc_cron_period }}"
+    user: "{{ nextcloud_websrv_user }}"
+    job: "{{ php_bin }} -f {{ http_webroot }}/nextcloud/cron.php"
+    cron_file: "nextcloud"
+  when: (nc_background_cron | bool)
+
+- name: Setup... Set Cron method to Crontab
+  become_user: "{{ nextcloud_websrv_user }}"
+  become: true
+  shell: "{{ php_bin }} occ background:cron"
+  args:
+    chdir: "{{ http_webroot }}/nextcloud"
+  when: (nc_background_cron | bool)
+
+      ###- name: Setup... "[NC] Set Custom Mimetype"
+      ###  ansible.builtin.copy:
+      ###    dest: "{{ nextcloud_webroot }}/config/mimetypemapping.json"
+      ###    src: files/nextcloud_custom_mimetypemapping.json
+      ###    mode: 0640
+      ###
+
+- name: Setup... Collabora settings ownership
+  file:
+    path: "{{ item }}"
+    recurse: true
+    owner: cool
+    group: cool
+  with_items:
+    - /opt/cool/systemplate/etc/hosts
+    - /opt/cool/systemplate/etc/resolv.conf
+    - /etc/coolwsd
+  when: nc_collabora
+
+- name: Setup... Ensure Nextcloud directories are 0750
+  shell: find {{ http_webroot }}/nextcloud -type d -exec chmod -c 0750 {} \;
+  register: nc_installation_chmod_result
+  changed_when: "nc_installation_chmod_result.stdout != \"\""
+
+- name: Setup... Ensure Nextcloud files are 0640
+  shell: find {{ http_webroot }}/nextcloud -type f -exec chmod -c 0640 {} \;
+  register: nc_installation_chmod_result
+  changed_when: "nc_installation_chmod_result.stdout != \"\""
+
+      ###- name: Setup... "[NC] Setting stronger directory ownership"
+      ###  ansible.builtin.file:
+      ###    path: "{{ nextcloud_webroot }}/{{ item }}/"
+      ###    recurse: true
+      ###    owner: "{{ nextcloud_websrv_user }}"
+      ###    group: "{{ nextcloud_websrv_group }}"
+      ###    state: directory
+      ###  with_items:
+      ###    - apps
+      ###    - custom_apps
+      ###    - config
+      ###    - themes
+      ###    - updater

+ 102 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/prep_os/CentOS.yml

@@ -0,0 +1,102 @@
+---
+# CentOS related tasks
+
+#- name: Prep OS... Create tmp directory
+#  file:
+#    path: "{{ item }}"
+#    state: directory
+#    owner: "{{ ansible_user }}"
+#    mode: 0770
+#  with_items:
+#    - "/tmp/ansible_{{ ansible_user }}"
+#
+#- name: Prep OS... Set remote tmp
+#  set_fact:
+#    ansible_remote_tmp: "/tmp/ansible_{{ ansible_user }}"
+
+- name: Prep OS... add rpmfusion-free-release centos{{ ansible_distribution_major_version|int }} repo
+  dnf:
+    name: https://download1.rpmfusion.org/free/el/rpmfusion-free-release-{{ ansible_distribution_major_version|int }}.noarch.rpm
+    disable_gpg_check: yes
+    validate_certs: no
+    state: latest
+  when: not debug_speed_check
+
+- name: Prep OS... import key from Collabora centos{{ ansible_distribution_major_version|int }} repo
+  ansible.builtin.rpm_key:
+    state: present
+    key: https://www.collaboraoffice.com/repos/CollaboraOnline/CODE-centos{{ ansible_distribution_major_version|int }}/repodata/repomd.xml.key
+  when: nc_collabora
+
+- name: Prep OS... add Collabora repos centos{{ ansible_distribution_major_version|int }} repo
+  ansible.builtin.yum_repository:
+    name: collabora
+    description: Collabora Online CODE repo
+    baseurl: https://www.collaboraoffice.com/repos/CollaboraOnline/CODE-centos{{ ansible_distribution_major_version|int }}
+  when: nc_collabora
+
+- name: Prep OS... install Collabora packages
+  dnf:
+    name:
+      - coolwsd
+      - CODE-brand
+      - inotify-tools 
+      - psmisc 
+      - perl
+    state: latest
+  when: nc_collabora
+
+- name: Prep OS... update os
+  dnf:
+    name: '*'
+    update_cache: true
+    state: latest
+  when: not debug_speed_check
+
+- name: Prep OS... install needed packages
+  dnf:
+    name:
+      - libreoffice
+      - ffmpeg
+      - mariadb
+    state: latest
+    enablerepo: epel
+  when: not debug_speed_check
+
+- name: Prep OS... Ensure Apache is installed on {{ ansible_facts['distribution'] }}
+  dnf:
+    name: httpd
+    state: present
+  when: nextcloud_websrv in ["apache", "apache2"]
+
+- name: Prep OS... Set http env on {{ ansible_facts['distribution'] }}
+  set_fact:
+    http_service_name: httpd
+    http_webroot: /var/www/html
+    nextcloud_websrv_user: apache
+    nextcloud_websrv_group: apache
+  when: nextcloud_websrv in ["apache", "apache2"]
+
+- name: Prep OS... Generate Nextcloud configuration for apache
+  template:
+    dest: /etc/httpd/conf.d/nextcloud.conf
+    src: nextcloud_apache2.j2
+    mode: 0640
+  when: nextcloud_websrv in ["apache", "apache2"]
+
+- name: Prep OS... Allow http to listen on tcp port 8000
+  seport:
+    ports: 8000
+    proto: tcp
+    setype: http_port_t
+    state: present
+
+    #- name: Prep OS... semanage port
+    #  command: semanage port -m -t http_port_t -p tcp {{ item }}
+    #  loop:
+    #    - "8000"
+
+- name: Prep OS... Start {{ http_service_name }} service
+  service:
+    name: "{{ http_service_name }}"
+    state: started

+ 3 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/prep_os/RedHat.yml

@@ -0,0 +1,3 @@
+---
+
+- include_tasks: "{{ ansible_facts['distribution'] }}.yml"

+ 57 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/prep_os/Suse.yml

@@ -0,0 +1,57 @@
+---
+# Suse related tasks
+
+- name: add rpmfusion-free-release {{ ansible_distribution_major_version|int }} repo
+  dnf:
+    name: https://download1.rpmfusion.org/free/el/rpmfusion-free-release-{{ ansible_distribution_major_version|int }}.noarch.rpm
+    disable_gpg_check: yes
+    validate_certs: no
+    state: latest
+  when: not {{ debug_speed_check }}
+
+- name: update os
+  dnf:
+    name: '*'
+    update_cache: true
+    state: latest
+  when: not {{ debug_speed_check }}
+
+- name: install needed packages
+  dnf:
+    name:
+      - epel-release
+      - yum-utils
+      - curl
+      - bash-completion
+      - mlocate
+      - bzip2
+      - wget
+      - libreoffice
+      - ffmpeg
+      - mariadb
+    state: latest
+    enablerepo: epel
+  when: not {{ debug_speed_check }}
+
+- name: Ensure Apache is installed on {{ ansible_facts['distribution'] }}
+  dnf:
+    name: httpd
+    state: present
+  when: nextcloud_websrv in ["apache", "apache2"]
+  notify: start http
+
+- name: Set http env on {{ ansible_facts['distribution'] }}
+  set_fact:
+    http_service_name: httpd
+    http_webroot: /var/www/html
+    nextcloud_websrv_user: apache
+    nextcloud_websrv_group: apache
+  when: nextcloud_websrv in ["apache", "apache2"]
+
+- name: Generate Nextcloud configuration for apache
+  template:
+    dest: /etc/httpd/conf.d/nextcloud.conf
+    src: nextcloud_apache2.j2
+    mode: 0640
+  when: nextcloud_websrv in ["apache", "apache2"]
+  notify: restart http

+ 117 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/prep_php/CentOS.yml

@@ -0,0 +1,117 @@
+---
+- name: Prep php... add php Remi repo
+  dnf:
+    name: https://rpms.remirepo.net/enterprise/remi-release-{{ ansible_distribution_major_version|int }}.rpm
+    state: latest
+    disable_gpg_check: yes
+    validate_certs: no
+  when: not debug_speed_check
+
+- name: Prep php... disable all the php repositories
+  shell: yum-config-manager --disable 'remi-php*'
+  when: not debug_speed_check
+
+- name: Prep php... enable the repo php{{ php_version | replace(".","") }}
+  shell: yum-config-manager --enable remi-php{{ php_version | replace(".","") }}
+  when: not debug_speed_check
+
+- name: Prep php... update os
+  dnf:
+    name: '*'
+    update_cache: true
+    state: latest
+  when: not debug_speed_check
+
+- name: Prep php... install needed packages
+  dnf:
+    name:
+      - php{{ php_version | replace(".","") }}-php 
+      - php{{ php_version | replace(".","") }}-php-pecl-apcu 
+      - php{{ php_version | replace(".","") }}-php-bcmath 
+      - php{{ php_version | replace(".","") }}-php-dom 
+      - php{{ php_version | replace(".","") }}-php-gmp 
+      - php{{ php_version | replace(".","") }}-php-pecl-imagick 
+      - php{{ php_version | replace(".","") }}-php-ldap 
+      - php{{ php_version | replace(".","") }}-php-openssl 
+      - php{{ php_version | replace(".","") }}-php-gd 
+      - php{{ php_version | replace(".","") }}-php-json 
+      - php{{ php_version | replace(".","") }}-php-mysql 
+      - php{{ php_version | replace(".","") }}-php-curl 
+      - php{{ php_version | replace(".","") }}-php-mbstring 
+      - php{{ php_version | replace(".","") }}-php-intl 
+      - php{{ php_version | replace(".","") }}-php-exif 
+      - php{{ php_version | replace(".","") }}-php-zip 
+      - php{{ php_version | replace(".","") }}-php-zlib 
+      - php{{ php_version | replace(".","") }}-php-fileinfo 
+      - php{{ php_version | replace(".","") }}-php-pcntl 
+      - php{{ php_version | replace(".","") }}-php-posix 
+      - php{{ php_version | replace(".","") }}-php-xmlreader 
+      - php{{ php_version | replace(".","") }}-php-xmlwriter 
+      - php{{ php_version | replace(".","") }}-php-ctype 
+      - php{{ php_version | replace(".","") }}-php-bz2 
+      - php{{ php_version | replace(".","") }}-php-ftp
+      - php{{ php_version | replace(".","") }}-php-smbclient 
+      - php{{ php_version | replace(".","") }}-php-memcached 
+      - php{{ php_version | replace(".","") }}-php-redis 
+      - php{{ php_version | replace(".","") }}-php-phar 
+      - php{{ php_version | replace(".","") }}-php-opcache
+    state: latest
+  when: not debug_speed_check
+
+- name: Prep php... Set php env for {{ ansible_facts['distribution'] }}
+  set_fact: 
+    php_bin: "php{{ php_version | replace('.','') }}"
+    php_dir: "/etc/opt/remi/php{{ php_version | replace('.','') }}/php.d"
+    #php_pkg_apcu: "{{ php_config_ref[php_ver|replace('.','_')].php_pkg_apcu | d(php_config_ref.defaults.php_pkg_apcu) }}"
+    #php_pkg_spe: "{{ php_config_ref[php_ver|replace('.','_')].php_pkg_spe | d(php_config_ref.defaults.php_pkg_spe) }}"
+    #php_socket: "{{ php_config_ref[php_ver|replace('.','_')].php_socket | d(php_config_ref.defaults.php_socket) }}"
+
+- name: Prep php... Read Nextcloud configuration for PHP
+  set_fact:
+    php_content: "{{ lookup('template', '{{ role_path }}/templates/php_nc_ini.j2') }}"
+
+- name: Prep php... Integration Nextcloud configuration for PHP
+  blockinfile:
+    dest: /etc/opt/remi/php{{ php_version | replace(".","") }}/php.ini
+    content: '{{ php_content }}'
+    state: present
+
+- name: Prep php... Read APCU configuration for PHP 
+  set_fact:
+    php_content: "{{ lookup('template', '{{ role_path }}/templates/apcu_nc_ini.j2') }}"
+
+- name: Prep php... Integration APCU configuration for PHP 
+  blockinfile:
+    dest: /etc/opt/remi/php{{ php_version | replace(".","") }}/php.d/40-apcu.ini
+    content: '{{ php_content }}'
+    state: present
+
+- name: Prep php... Read OPCACHE configuration for PHP 
+  set_fact:
+    php_content: "{{ lookup('template', '{{ role_path }}/templates/opcache_nc_ini.j2') }}"
+
+- name: Prep php... Integration OPCACHE configuration for PHP 
+  blockinfile:
+    dest: /etc/opt/remi/php{{ php_version | replace(".","") }}/php.d/10-opcache.ini
+    content: '{{ php_content }}'
+    state: present
+
+- name: Prep php... Install PHP-FPM
+  dnf:
+    name:
+      - php{{ php_version | replace(".","") }}-php-fpm
+    state: latest
+  when: add_php_fpm
+
+- name: Prep php... Configure PHP-FPM
+  lineinfile:
+    dest: /etc/opt/remi/php{{ php_version | replace(".","") }}/php-fpm.d/www.conf
+    regexp: "^{{ item.property | regex_escape() }}.*"
+    line: "{{ item.value }}"
+  with_items:
+    - { property: 'pm = dynamic', value: 'pm = {{ nc_pm }}' }
+    - { property: 'pm.max_children =', value: 'pm.max_children = {{ nc_pm_max_children }}' }
+    - { property: 'pm.start_servers =', value: 'pm.start_servers = {{ nc_pm_start_servers }}' }
+    - { property: 'pm.min_spare_servers =', value: 'pm.min_spare_servers = {{ nc_pm_min_spare_servers }}' }
+    - { property: 'pm.max_spare_servers =', value: 'pm.max_spare_servers = {{ nc_pm_max_spare_servers }}' }
+  when: add_php_fpm

+ 5 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/prep_php/RedHat.yml

@@ -0,0 +1,5 @@
+---
+
+# install required packages
+- include_tasks: "{{ ansible_facts['distribution'] }}.yml"
+

+ 76 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/prep_php/Suse.yml

@@ -0,0 +1,76 @@
+---
+- name: add php{{ php_version | replace(".","") }} repo
+  dnf:
+    name: https://rpms.remirepo.net/enterprise/remi-release-{{ ansible_distribution_major_version|int }}.rpm
+    state: latest
+
+- name: update os
+  dnf:
+    name: '*'
+    update_cache: true
+    state: latest
+
+- name: install needed packages
+  dnf:
+    name:
+      - php{{ php_version | replace(".","") }}-php 
+      - php{{ php_version | replace(".","") }}-php-pecl-apcu 
+      - php{{ php_version | replace(".","") }}-php-bcmath 
+      - php{{ php_version | replace(".","") }}-php-dom 
+      - php{{ php_version | replace(".","") }}-php-gmp 
+      - php{{ php_version | replace(".","") }}-php-pecl-imagick 
+      - php{{ php_version | replace(".","") }}-php-ldap 
+      - php{{ php_version | replace(".","") }}-php-openssl 
+      - php{{ php_version | replace(".","") }}-php-gd 
+      - php{{ php_version | replace(".","") }}-php-json 
+      - php{{ php_version | replace(".","") }}-php-mysql 
+      - php{{ php_version | replace(".","") }}-php-curl 
+      - php{{ php_version | replace(".","") }}-php-mbstring 
+      - php{{ php_version | replace(".","") }}-php-intl 
+      - php{{ php_version | replace(".","") }}-php-exif 
+      - php{{ php_version | replace(".","") }}-php-zip 
+      - php{{ php_version | replace(".","") }}-php-zlib 
+      - php{{ php_version | replace(".","") }}-php-fileinfo 
+      - php{{ php_version | replace(".","") }}-php-pcntl 
+      - php{{ php_version | replace(".","") }}-php-posix 
+      - php{{ php_version | replace(".","") }}-php-xmlreader 
+      - php{{ php_version | replace(".","") }}-php-xmlwriter 
+      - php{{ php_version | replace(".","") }}-php-ctype 
+      - php{{ php_version | replace(".","") }}-php-bz2 
+      - php{{ php_version | replace(".","") }}-php-ftp
+      - php{{ php_version | replace(".","") }}-php-smbclient 
+      - php{{ php_version | replace(".","") }}-php-memcached 
+      - php{{ php_version | replace(".","") }}-php-redis 
+      - php{{ php_version | replace(".","") }}-php-phar 
+      - php{{ php_version | replace(".","") }}-php-opcache
+    state: latest
+
+- name: Set php env for {{ ansible_facts['distribution'] }}
+  set_fact: 
+    php_bin: "php{{ php_version | replace('.','') }}"
+    php_dir: "/etc/opt/remi/php{{ php_version | replace('.','') }}/php.d/nextcloud.ini"
+    #php_pkg_apcu: "{{ php_config_ref[php_ver|replace('.','_')].php_pkg_apcu | d(php_config_ref.defaults.php_pkg_apcu) }}"
+    #php_pkg_spe: "{{ php_config_ref[php_ver|replace('.','_')].php_pkg_spe | d(php_config_ref.defaults.php_pkg_spe) }}"
+    #php_socket: "{{ php_config_ref[php_ver|replace('.','_')].php_socket | d(php_config_ref.defaults.php_socket) }}"
+
+- name: Add Nextcloud configuration for PHP
+  template:
+    dest: /etc/opt/remi/php{{ php_version | replace(".","") }}/php.d/nextcloud.ini
+    src: php_nc_ini.j2
+    mode: '0640'
+  notify: restart http
+
+- name: Generate Nextcloud configuration for APCU
+  lineinfile:
+    path: /etc/opt/remi/php{{ php_version | replace(".","") }}/php.d/40-apcu.ini
+    regexp: '^apc.shm_size(.*)'
+    line:   'apc.shm_size = {{ APC_SHM_SIZE }}'
+    backup: true
+  notify: restart http
+
+- name: Generate Nextcloud configuration for OPCACHE
+  ansible.builtin.template:
+    dest: /etc/opt/remi/php{{ php_version | replace(".","") }}/php.d/10-opcache.ini
+    src: opcache_nc_ini.j2
+    mode: 0640
+  notify: restart http

+ 51 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/selinux.yml

@@ -0,0 +1,51 @@
+---
+
+- name: Selinux... selinux targets
+  sefcontext:
+    target: "{{ item }}"
+    setype: httpd_sys_rw_content_t
+    state: present
+  register: filecontext
+  with_items:
+    - '{{ nc_data_dir }}(/.*)?'
+    - '{{ http_webroot }}/nextcloud/config(/.*)?'
+    - '{{ http_webroot }}/nextcloud/apps(/.*)?'
+    - '{{ http_webroot }}/nextcloud/custom_apps(/.*)?'
+    - '{{ http_webroot }}/nextcloud/assets(/.*)?'
+    - '{{ http_webroot }}/nextcloud/.htaccess'
+    - '{{ http_webroot }}/nextcloud/.user.ini'
+    - '{{ http_webroot }}/nextcloud/3rdparty/aws/aws-sdk-php/src/data/logs(/.*)?'
+
+- name: Selinux... enable seboolean settings
+  seboolean:
+    name: "{{ item }}"
+    state: yes
+    persistent: yes
+  with_items:
+    - httpd_can_sendmail
+    - httpd_unified
+    - httpd_graceful_shutdown
+    - httpd_can_network_relay
+    - httpd_can_network_connect
+    - httpd_can_network_connect_db
+    - daemons_enable_cluster_mode
+    #- httpd_execmem
+
+      ###- name: Selinux... enable seboolean settings
+      ###  command: semodule -i {{ role_path }}/files/{{ item }}
+      ###  loop:
+      ###    - httpd-to-php-fpm.pp
+      ###    - httpd-to-redis-socket.pp
+      ###    - httpd-to-upload-tmp.pp
+
+- name: Selinux... Run restore context to reload selinux
+  shell: restorecon -R -v {{ item.target }}
+  when: filecontext.results[item.index] is changed
+  with_items:
+    - { index: 0, target: '{{ nc_data_dir }}/' }
+    - { index: 1, target: '{{ http_webroot }}/nextcloud/' }
+
+- name: Selinux... Restart {{ http_service_name }} service
+  service:
+    name: "{{ http_service_name }}" 
+    state: restarted

+ 19 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/CentOS.yml

@@ -0,0 +1,19 @@
+---
+- name: Ensure Apache is installed on {{ ansible_facts['distribution'] }}
+  dnf:
+    name: httpd
+    state: present
+  when: nextcloud_websrv in ["apache", "apache2"]
+  notify: start http
+
+- name: Set nextcloud webroot on {{ ansible_facts['distribution'] }}
+  set_fact:
+    nextcloud_webroot: /var/www/html/nextcloud/
+
+- name: Generate Nextcloud configuration for apache
+  template:
+    dest: /etc/httpd/conf.d/nextcloud.conf
+    src: nextcloud_apache2.j2
+    mode: 0640
+  when: nextcloud_websrv in ["apache", "apache2"]
+  notify: restart http

+ 116 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/db_mysql.yml

@@ -0,0 +1,116 @@
+---
+- name: "[mySQL] - Service is installed."
+  ansible.builtin.package:
+    name: "{{ 'default-' if ((ansible_distribution|lower) == 'debian' and nextcloud_db_backend == 'mysql') else '' }}{{ nextcloud_db_backend }}-server"
+    state: present
+  register: nc_mysql_db_install
+
+- name: "[mySQL] - Check if MySQL packages were installed."
+  ansible.builtin.set_fact:
+    mysql_install_packages: "{{ nc_mysql_db_install is defined and nc_mysql_db_install.changed }}"
+
+- name: "[mySQL] - Get MySQL version."
+  ansible.builtin.command: 'mysql --version'
+  register: mysql_cli_version
+  changed_when: false
+  check_mode: false
+
+- name: "[mySQL] - Packages are installed."
+  ansible.builtin.package:
+    name: "{{ nc_mysql_deps }}"
+    state: present
+  vars:
+    nc_mysql_deps:
+      - "php{{ php_ver }}-mysql"
+      - "python3-pymysql"
+
+- name: "[mySQL] - Ensure MySQL is started and enabled on boot."
+  ansible.builtin.service:
+    name: "{{ mysql_daemon }}"
+    state: started
+    enabled: "{{ nextcloud_db_enabled_on_startup }}"
+  register: mysql_service_configuration
+
+- name: "[mySQL] - Get list of hosts for the root user."
+  ansible.builtin.command: mysql -NBe
+    "SELECT Host
+    FROM mysql.user
+    WHERE User = 'root'
+    ORDER BY (Host='localhost') ASC"
+  register: mysql_root_hosts
+  changed_when: false
+  check_mode: false
+  when: mysql_install_packages | bool or nextcloud_mysql_root_pwd_update
+
+# Note: We do not use mysql_user for this operation, as it doesn't always update
+# the root password correctly. See: https://goo.gl/MSOejW
+- name: "[mySQL] - Update MySQL root password for localhost root account (5.7.x)."
+  ansible.builtin.shell: >
+    mysql -u root -NBe
+    'ALTER USER "root"@"{{ item }}"
+    IDENTIFIED WITH mysql_native_password BY "{{ nextcloud_mysql_root_pwd }}"; FLUSH PRIVILEGES;'
+  with_items: "{{ mysql_root_hosts.stdout_lines|default([]) }}"
+  when: >
+    ((mysql_install_packages | bool) or nextcloud_mysql_root_pwd_update)
+    and ('5.7.' in mysql_cli_version.stdout or '8.0.' in mysql_cli_version.stdout)
+
+- name: "[mySQL] - Update MySQL root password for localhost root account (< 5.7.x)."
+  ansible.builtin.shell: >
+    mysql -NBe
+    'SET PASSWORD FOR "root"@"{{ item }}" = PASSWORD("{{ nextcloud_mysql_root_pwd }}"); FLUSH PRIVILEGES;'
+  with_items: "{{ mysql_root_hosts.stdout_lines|default([]) }}"
+  when: >
+    ((mysql_install_packages | bool) or nextcloud_mysql_root_pwd_update)
+    and ('5.7.' not in mysql_cli_version.stdout and '8.0.' not in mysql_cli_version.stdout)
+
+- name: "[mySQL] - Copy .my.cnf file with root password credentials."
+  ansible.builtin.template:
+    src: "root-my.cnf.j2"
+    dest: "/root/.my.cnf"
+    owner: root
+    group: root
+    mode: 0600
+  when: mysql_install_packages | bool or nextcloud_mysql_root_pwd_update
+
+- name: "[mySQL] - Get list of hosts for the anonymous user."
+  ansible.builtin.command: mysql -NBe 'SELECT Host FROM mysql.user WHERE User = ""'
+  register: mysql_anonymous_hosts
+  changed_when: false
+  check_mode: false
+
+- name: "[mySQL] - Remove anonymous MySQL users."
+  mysql_user:
+    name: ""
+    host: "{{ item }}"
+    state: absent
+  with_items: "{{ mysql_anonymous_hosts.stdout_lines|default([]) }}"
+
+- name: "[mySQL] - Remove MySQL test database."
+  mysql_db:
+    name: 'test'
+    state: absent
+
+- name: "[mySQL] - Set mysql config option for Nextcloud"
+  ansible.builtin.copy:
+    dest: /etc/mysql/conf.d/nextcloud.cnf
+    src: files/mysql_nextcloud.cnf
+    mode: 0600
+  notify: restart mysql
+
+- name: "[mySQL] - Add Database {{ nextcloud_db_name }}."
+  mysql_db:
+    name: "{{ nextcloud_db_name }}"
+    login_user: root
+    login_password: "{{ nextcloud_mysql_root_pwd }}"
+    config_file: "{{ mysql_credential_file[(ansible_os_family|lower)] | default(omit) }}"
+    state: present
+
+- name: "[mySQL] - Configure the database user."
+  mysql_user:
+    name: "{{ nextcloud_db_admin }}"
+    password: "{{ nextcloud_db_pwd }}"
+    priv: "{{ nextcloud_db_name }}.*:ALL"
+    login_user: root
+    login_password: "{{ nextcloud_mysql_root_pwd }}"
+    config_file: "{{ mysql_credential_file[(ansible_os_family|lower)] | default(omit) }}"
+    state: present

+ 28 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/db_postgresql.yml

@@ -0,0 +1,28 @@
+---
+- name: "[PostgreSQL] - PostgreSQL packages are installed"
+  ansible.builtin.package:
+    name: "{{ pg_deps }}"
+    state: "present"
+  vars:
+    pg_deps:
+      - "postgresql"
+      - "php{{ php_ver }}-pgsql"
+      - "python3-psycopg2"
+
+- name: "[PostgreSQL] - nextcloud role is created."
+  postgresql_user:
+    name: "{{ nextcloud_db_admin }}"
+    password: "{{ nextcloud_db_pwd }}"
+    encrypted: true
+    state: present
+    role_attr_flags: CREATEDB
+  become_user: postgres
+  become: true
+
+- name: "[PostgreSQL] - nextcloud database is created."
+  postgresql_db:
+    name: "{{ nextcloud_db_name }}"
+    state: present
+    owner: "{{ nextcloud_db_admin }}"
+  become_user: postgres
+  become: true

+ 69 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/http_apache.yml

@@ -0,0 +1,69 @@
+---
+- name: "[APACHE] -  enable APC for php CLI"
+  ansible.builtin.lineinfile:
+    dest: "{{ php_dir }}/cli/php.ini"
+    line: "apc.enable_cli = 1"
+    insertbefore: "^; End:$"
+    state: present
+    # validate: "/usr/sbin/{{ php_bin }} -t #%s"
+
+- name: "[APACHE] -  enable PHP OPcache for php.ini"
+  ansible.builtin.lineinfile:
+    dest: "{{ php_dir }}/apache2/php.ini"
+    state: present
+    regexp: "{{ item.regexp }}"
+    line: "{{ item.line }}"
+    backrefs: true
+  with_items:
+    - {regexp: 'opcache.enable=0', line: 'opcache.enable=1'}
+    - {regexp: 'opcache.enable_cli', line: 'opcache.enable_cli=1'}
+    - {regexp: 'opcache.interned_strings_buffer', line: 'opcache.interned_strings_buffer=8'}
+    - {regexp: 'opcache.max_accelerated_files', line: 'opcache.max_accelerated_files=10000'}
+    - {regexp: 'opcache.memory_consumption', line: 'opcache.memory_consumption=128'}
+    - {regexp: 'opcache.save_comments', line: 'opcache.save_comments=1'}
+    - {regexp: 'opcache.revalidate_freq', line: 'opcache.revalidate_freq=1'}
+    - {regexp: 'memory_limit', line: 'memory_limit={{ php_memory_limit }}'}
+    # validate: "/usr/sbin/{{ php_bin }} -t #%s"
+  notify: reload http
+
+- name: "[APACHE] -  Required Apache2 modules are enabled"
+  apache2_module:
+    name: "{{ item }}"
+    state: present
+  with_items:
+    - rewrite
+    - headers
+    - env
+    - dir
+    - mime
+  notify: restart http
+
+- name: "[APACHE] -  Ssl Apache2 module is enabled"
+  apache2_module:
+    state: present
+    name: "{{ item }}"
+  with_items:
+    - ssl
+  when: (nextcloud_install_tls | bool)
+  notify: restart http
+
+- name: "[APACHE] -  generate Nextcloud configuration for apache"
+  ansible.builtin.template:
+    dest: /etc/apache2/sites-available/nc_{{ nextcloud_instance_name }}.conf
+    src: "{{ nextcloud_websrv_template }}"
+    mode: 0640
+  notify: reload http
+
+- name: "[APACHE] -  Enable Nextcloud site in apache conf"
+  ansible.builtin.file:
+    path: /etc/apache2/sites-enabled/nc_{{ nextcloud_instance_name }}.conf
+    src: /etc/apache2/sites-available/nc_{{ nextcloud_instance_name }}.conf
+    state: link
+  notify: reload http
+
+- name: "[APACHE] -  Disable apache default site"
+  ansible.builtin.file:
+    path: /etc/apache2/sites-enabled/000-default.conf
+    state: absent
+  when: nextcloud_disable_websrv_default_site | bool
+  notify: reload http

+ 90 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/http_nginx.yml

@@ -0,0 +1,90 @@
+---
+- name: "[NGINX] -  remove some commented line in php-fpm conf"
+  ansible.builtin.lineinfile:
+    dest: "{{ php_dir }}/fpm/pool.d/www.conf"
+    regexp: '^\;env'
+    state: absent
+    # validate: "/usr/sbin/{{ php_bin }} -t #%s"
+  notify: reload php-fpm
+
+- name: "[NGINX] -  Add path variable to php-fpm"
+  ansible.builtin.blockinfile:
+    dest: "{{ php_dir }}/fpm/pool.d/www.conf"
+    insertafter: '^; Default Value: clean env$'
+    marker: "; {mark} ANSIBLE MANAGED BLOCK"
+    block: |
+      env[HOSTNAME] = $HOSTNAME
+      env[PATH] = $PATH
+      env[TMP] = /tmp
+      env[TMPDIR] = /tmp
+      env[TEMP] = /tmp
+  notify: reload php-fpm
+
+- name: "[NGINX] -  enable APC for php CLI"
+  ansible.builtin.lineinfile:
+    dest: "{{ php_dir }}/cli/php.ini"
+    line: "apc.enable_cli = 1"
+    insertbefore: "^; End:$"
+    state: present
+    # validate: "/usr/sbin/{{ php_bin }} -t #%s"
+  notify: reload php-fpm
+
+- name: "[NGINX] -  enable PHP OPcache for php.ini"
+  ansible.builtin.lineinfile:
+    dest: "{{ php_dir }}/fpm/php.ini"
+    state: present
+    regexp: "{{ item.regexp }}"
+    line: "{{ item.line }}"
+    backrefs: true
+  with_items:
+    - { regexp: 'opcache.enable=0', line: 'opcache.enable=1' }
+    - { regexp: 'opcache.enable_cli', line: 'opcache.enable_cli=1' }
+    - { regexp: 'opcache.interned_strings_buffer', line: 'opcache.interned_strings_buffer=8' }
+    - { regexp: 'opcache.max_accelerated_files', line: 'opcache.max_accelerated_files=10000' }
+    - { regexp: 'opcache.memory_consumption', line: 'opcache.memory_consumption=128' }
+    - { regexp: 'opcache.save_comments', line: 'opcache.save_comments=1' }
+    - { regexp: 'opcache.revalidate_freq', line: 'opcache.revalidate_freq=1' }
+    - { regexp: 'memory_limit', line: 'memory_limit={{ php_memory_limit }}'}
+    # validate: "/usr/sbin/{{ php_bin }} -t #%s"
+  notify: reload php-fpm
+
+
+- name: "[NGINX] -  Public Diffie-Hellman Parameter are generated. This might take a while."
+  ansible.builtin.command: "openssl dhparam -out {{ nextcloud_tls_dhparam }} 2048"
+  args:
+    creates: "{{ nextcloud_tls_dhparam }}"
+
+- name: "[NGINX] -  php handler configuration is present."
+  ansible.builtin.template:
+    dest: /etc/nginx/sites-available/php_handler.cnf
+    src: templates/nginx_php_handler.j2
+    mode: 0640
+  notify: reload http
+
+- name: "[NGINX] -  php handler is enabled"
+  ansible.builtin.file:
+    path: /etc/nginx/sites-enabled/php_handler
+    src: /etc/nginx/sites-available/php_handler.cnf
+    state: link
+  notify: reload http
+
+- name: "[NGINX] -  generate Nextcloud configuration for nginx"
+  ansible.builtin.template:
+    dest: /etc/nginx/sites-available/nc_{{ nextcloud_instance_name }}.cnf
+    src: "{{ nextcloud_websrv_template }}"
+    mode: 0640
+  notify: reload http
+
+- name: "[NGINX] -  Enable Nextcloud in nginx conf"
+  ansible.builtin.file:
+    path: /etc/nginx/sites-enabled/nc_{{ nextcloud_instance_name }}
+    src: /etc/nginx/sites-available/nc_{{ nextcloud_instance_name }}.cnf
+    state: link
+  notify: reload http
+
+- name: "[NGINX] -  Disable nginx default site"
+  ansible.builtin.file:
+    path: /etc/nginx/sites-enabled/default
+    state: absent
+  when: nextcloud_disable_websrv_default_site | bool
+  notify: reload http

+ 67 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/nc_apps.yml

@@ -0,0 +1,67 @@
+---
+- name: parse the item values
+  ansible.builtin.set_fact:
+    nc_app_name: "{{ item.key }}"
+    nc_app_cfg: "{{ item.value }}"
+
+- name: "Install and enable Nextcloud Apps"
+  block:
+    - name: "[ App {{ nc_app_name }} ] - Download Archive in apps folder."
+      ansible.builtin.unarchive:
+        copy: false
+        src: "{{ nc_app_cfg }}"
+        dest: "{{ nextcloud_webroot }}/apps/"
+        owner: "{{ nextcloud_websrv_user }}"
+        group: "{{ nextcloud_websrv_group }}"
+        creates: "{{ nextcloud_webroot }}/apps/{{ nc_app_name }}"
+      when: nc_app_cfg is not none
+
+    - name: "[ App {{ nc_app_name }} ] - enable the application."
+      become_user: "{{ nextcloud_websrv_user }}"
+      become_flags: "{{ ansible_become_flags | default(omit) }}"
+      become: true
+      ansible.builtin.command: php occ app:enable "{{ nc_app_name }}"
+      args:
+        chdir: "{{ nextcloud_webroot }}"
+      when: nc_app_cfg is not none
+  when: nc_app_cfg is string
+
+- name: "Install Apps"
+  block:
+    - name: verify the app's yaml declaration
+      ansible.builtin.assert:
+        that:
+          - (nc_app_cfg.source is defined) and (nc_app_cfg.source is string)
+        msg: "{{ nc_app_name }} is not well declared."
+
+    - name: "[ App {{ nc_app_name }} ] - Download Archive in apps folder."
+      ansible.builtin.unarchive:
+        copy: false
+        src: "{{ nc_app_cfg.source }}"
+        dest: "{{ nextcloud_webroot }}/apps/"
+        owner: "{{ nextcloud_websrv_user }}"
+        group: "{{ nextcloud_websrv_group }}"
+        creates: "{{ nextcloud_webroot }}/apps/{{ nc_app_name }}"
+      when: nc_app_cfg.source is not none
+
+    - name: "[ App {{ nc_app_name }} ] - enable the application."
+      become_user: "{{ nextcloud_websrv_user }}"
+      become_flags: "{{ ansible_become_flags | default(omit) }}"
+      become: true
+      ansible.builtin.command: php occ app:enable "{{ nc_app_name }}"
+      args:
+        chdir: "{{ nextcloud_webroot }}"
+      when: nc_app_cfg.source is not none
+
+    - name: "[ App {{ nc_app_name }} ] - Configure the application "
+      become_user: "{{ nextcloud_websrv_user }}"
+      become_flags: "{{ ansible_become_flags | default(omit) }}"
+      become: true
+      ansible.builtin.command: php occ config:app:set {{ nc_app_name }} {{ item_cfg.key }} --value="{{ item_cfg.value }}"
+      args:
+        chdir: "{{ nextcloud_webroot }}"
+      with_dict: "{{ nc_app_cfg.conf | default({}) }}"
+      loop_control:
+        loop_var: item_cfg
+      when: nc_app_cfg.conf is defined
+  when: (nc_app_cfg is mapping)

+ 51 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/php_install.yml

@@ -0,0 +1,51 @@
+---
+- name: "[INSTALL] -  Required and recommended packages are installed."
+  ansible.builtin.package:
+    name: "{{ item }}"
+    state: present
+  with_items:
+    - "{{ nextcloud_websrv }}"
+    - imagemagick
+    - smbclient
+    - "php{{ php_ver }}-gd"
+    - "php{{ php_ver }}-ldap"
+    - "php{{ php_ver }}-imap"
+    - "php{{ php_ver }}-curl"
+    - "php{{ php_ver }}-intl"
+  notify:
+    - start http
+
+- name: "[INSTALL] - php-json is installed (PHP < 8)"
+  ansible.builtin.package:
+    name: "php{{ php_ver }}-json"
+    state: present
+  when: php_ver is version("8", "<")
+
+- name: "[INSTALL] -  Apache Required package is installed."
+  ansible.builtin.package:
+    name: "libapache2-mod-php{{ php_ver }}"
+    state: present
+  when: nextcloud_websrv == "apache2"
+  notify:
+    - start http
+
+- name: "[INSTALL] -  NGINX Required package is installed."
+  ansible.builtin.package:
+    name: "php{{ php_ver }}-fpm"
+    state: present
+  when: nextcloud_websrv == "nginx"
+  notify:
+    - start http
+    - start php-fpm
+
+- name: "[INSTALL] -  PHP extra Packages are installed."
+  ansible.builtin.package:
+    name: "{{ item }}"
+    state: present
+  with_items:
+    - "{{ php_pkg_spe }}"
+
+- name: "[INSTALL] -  APCu is installed."
+  ansible.builtin.package:
+    name: "{{ php_pkg_apcu }}"
+    state: present

+ 52 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/setup_env.yml

@@ -0,0 +1,52 @@
+---
+# additional setup and fixes for OS dependent environment
+- name: "[ENV] controls nextcloud_trusted_domain type"
+  ansible.builtin.fail:
+    msg: "New versions require nextcloud_trusted_domain to be declared as a list."
+  when: nextcloud_trusted_domain is string
+
+- name: "[ENV] - ca-certificate are up to date"
+  # needed for downloading from download.nextcloud.com as the site use letsencrypt certificates
+  # letsencrypt may not be trusted on older OS
+  ansible.builtin.apt:
+    name: "{{ item }}"
+    state: present
+    update_cache: true
+    cache_valid_time: 86400
+  loop:
+    - acl
+    - ca-certificates
+  when: ansible_os_family in [ "Debian" ]
+
+  # fix for debian not using sudo :
+  # finding out if sudo is installed or not
+- name: "[ENV] - Debian only : checking sudo."
+  ansible.builtin.command: "dpkg -l sudo"
+  changed_when: false
+  register: nc_sudo_installed_result
+  failed_when: false
+  when: ansible_distribution == "Debian"
+
+- name: "[ENV] - Checking su"
+  block:
+    - name: "[ENV] - rolling back to su."
+      ansible.builtin.set_fact:
+        ansible_become_method: "su"
+    - name: "[ENV] - force su to use /bin/sh as shell"
+      ansible.builtin.set_fact:
+        ansible_become_flags: '-s /bin/sh'
+  when:
+    - nc_sudo_installed_result.rc is defined
+    - nc_sudo_installed_result.rc != 0
+
+- name: "[ENV] - Generate database user password."
+  ansible.builtin.set_fact:
+    nextcloud_db_pwd: "{{ lookup( 'ansible.builtin.password', 'nextcloud_instances/'+ nextcloud_instance_name +'/db_admin.pwd' ) }}"
+  when: nextcloud_db_pwd is not defined
+
+- name: "[ENV] - Generate database root password."
+  ansible.builtin.set_fact:
+    nextcloud_mysql_root_pwd: "{{ lookup( 'ansible.builtin.password', 'nextcloud_instances/'+ nextcloud_instance_name +'/db_root.pwd' ) }}"
+  when:
+    - nextcloud_db_backend in ["mysql", "mariadb"]
+    - nextcloud_mysql_root_pwd is not defined

+ 23 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/tls_installed.yml

@@ -0,0 +1,23 @@
+---
+- name: define certificate path
+  ansible.builtin.set_fact:
+    nextcloud_tls_cert_file: "{{ nextcloud_tls_cert }}"
+- name: define key path
+  ansible.builtin.set_fact:
+    nextcloud_tls_cert_key_file: "{{ nextcloud_tls_cert_key }}"
+- name: define certificate chain  path
+  ansible.builtin.set_fact:
+    nextcloud_tls_cert_chain_file: "{{ nextcloud_tls_cert_chain }}"
+  when: nextcloud_tls_cert_chain is defined
+
+# - name: "[INSTALLED TLS] - check TLS certificate permissions"
+#   ansible.builtin.file:
+#     path: "{{ nextcloud_tls_cert_file }}"
+#     mode: 0644
+#     group: "{{ nextcloud_websrv_group }}"
+
+# - name: "[INSTALLED TLS] - check TLS key permissions"
+#   ansible.builtin.file:
+#     path: "{{ nextcloud_tls_cert_key_file }}"
+#     mode: 0640
+#     group: "{{ nextcloud_websrv_group }}"

+ 39 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/tls_selfsigned.yml

@@ -0,0 +1,39 @@
+---
+- name: define private certificate path
+  ansible.builtin.set_fact:
+    nextcloud_tls_cert_file: "/etc/ssl/{{ nextcloud_instance_name }}.crt"
+- name: define private key path
+  ansible.builtin.set_fact:
+    nextcloud_tls_cert_key_file: "/etc/ssl/{{ nextcloud_instance_name }}.key"
+- name: "[selfsigned TLS] - create self-signed SSL cert"
+  ansible.builtin.command: >
+    openssl req -new -nodes -x509
+    -subj "/C=US/ST=Oregon/L=Portland/O=IT/CN=${hostname --fqdn}"
+    -days 365
+    -keyout {{ nextcloud_tls_cert_key_file }}
+    -out {{ nextcloud_tls_cert_file }}
+    -extensions v3_ca
+  args:
+    creates: "{{ nextcloud_tls_cert_key_file }}"
+
+- name: "[selfsigned TLS] - check TLS certificate permissions"
+  ansible.builtin.file:
+    path: "{{ nextcloud_tls_cert_file }}"
+    mode: 0644
+    group: "{{ nextcloud_websrv_group }}"
+
+- name: "[selfsigned TLS] - check TLS key permissions"
+  ansible.builtin.file:
+    path: "{{ nextcloud_tls_cert_key_file }}"
+    mode: 0640
+    group: "{{ nextcloud_websrv_group }}"
+
+#   cd /etc/haproxy
+#   mkdir nextcloud.test
+#   cd nextcloud.test/
+#   openssl genrsa -out nextcloud.test.key 2048
+#   openssl req -new -key nextcloud.test.key -out nextcloud.test.csr
+#   openssl x509 -req -days 365 -in nextcloud.test.csr -signkey nextcloud.test.key -out nextcloud.test.crt
+#   bash -c 'cat nextcloud.test.key nextcloud.test.crt >> nextcloud.test.pem'
+#   cd /etc/haproxy
+#   openssl dhparam -out /etc/haproxy/dhparams.pem 2048

+ 31 - 0
dev/provisioning/ansible/roles/nextcloud/tasks/to_remove/tls_signed.yml

@@ -0,0 +1,31 @@
+---
+- name: define signed certificate path
+  ansible.builtin.set_fact:
+    nextcloud_tls_cert_file: "{{ nextcloud_tls_cert | default(\"/etc/ssl/\" + nextcloud_instance_name + \".crt\") }}"
+- name: define signed certificate's key path
+  ansible.builtin.set_fact:
+    nextcloud_tls_cert_key_file: "{{ nextcloud_tls_cert_key | default(\"/etc/ssl/\" + nextcloud_instance_name + \".key\") }}"
+
+- name: "[SIGNED TLS] - Certificate is on the host"
+  ansible.builtin.copy:
+    dest: "{{ nextcloud_tls_cert_file }}"
+    src: "{{ nextcloud_tls_src_cert }}"
+    mode: 0640
+
+- name: "[SIGNED TLS] - Key is on the host"
+  ansible.builtin.copy:
+    dest: "{{ nextcloud_tls_cert_key_file }}"
+    src: "{{ nextcloud_tls_src_cert_key }}"
+    mode: 0640
+
+- name: "[SIGNED TLS] - check TLS certificate permissions"
+  ansible.builtin.file:
+    path: "{{ nextcloud_tls_cert_file }}"
+    mode: 0644
+    group: "{{ nextcloud_websrv_group }}"
+
+- name: "[SIGNED TLS] - check TLS key permissions"
+  ansible.builtin.file:
+    path: "{{ nextcloud_tls_cert_key_file }}"
+    mode: 0640
+    group: "{{ nextcloud_websrv_group }}"

+ 103 - 0
dev/provisioning/ansible/roles/nextcloud/templates/apache2_nc.j2

@@ -0,0 +1,103 @@
+################################################################################
+# This file was generated by Ansible for {{ansible_fqdn}}
+# Do NOT modify this file by hand!
+################################################################################
+
+{% if nextcloud_install_tls and nextcloud_tls_enforce %}
+{% for domain in nextcloud_trusted_domain %}
+<VirtualHost *:80>
+  ServerName {{ domain }}
+  Redirect permanent / https://{{ domain | ansible.utils.ipwrap }}/
+</VirtualHost>
+{% endfor %}
+{% else %}
+<VirtualHost *:80>
+  ServerName {{ nextcloud_trusted_domain[0] }}
+{% for index in range(1, nextcloud_trusted_domain|length) %}
+  ServerAlias {{ nextcloud_trusted_domain[index]}}
+{% endfor %}
+  DocumentRoot {{ nextcloud_webroot }}
+  {% if (nextcloud_max_upload_size_in_bytes|int) <= 2147483647-%}
+  LimitRequestBody {{ nextcloud_max_upload_size_in_bytes }}
+  {% endif -%}
+  <Directory {{ nextcloud_webroot }}>
+    Allow from all
+    Satisfy Any
+    Options +FollowSymlinks
+    AllowOverride All
+
+   <IfModule mod_dav.c>
+    Dav off
+   </IfModule>
+
+   SetEnv HOME {{ nextcloud_webroot }}
+   SetEnv HTTP_HOME {{ nextcloud_webroot }}
+
+  </Directory>
+</VirtualHost>
+{% endif %}
+
+{% if nextcloud_install_tls %}
+<VirtualHost *:443>
+  ServerName {{ nextcloud_trusted_domain[0] }}
+{% for index in range(1, nextcloud_trusted_domain|length) %}
+  ServerAlias {{ nextcloud_trusted_domain[index]}}
+{% endfor %}
+  DocumentRoot {{ nextcloud_webroot }}
+  {% if (nextcloud_max_upload_size_in_bytes|int) <= 2147483647-%}
+  LimitRequestBody {{ nextcloud_max_upload_size_in_bytes }}
+  {% endif -%}
+  SSLEngine on
+  SSLCertificateFile      {{ nextcloud_tls_cert_file }}
+  SSLCertificateKeyFile   {{ nextcloud_tls_cert_key_file }}
+{% if nextcloud_tls_cert_chain_file is defined %}
+  SSLCertificateChainFile {{ nextcloud_tls_cert_chain_file }}
+{% endif %}
+
+  # enable HTTP/2, if available
+  Protocols h2 http/1.1
+
+{% if nextcloud_hsts is string %}
+  <IfModule mod_headers.c>
+    Header always set Strict-Transport-Security "{{ nextcloud_hsts }}"
+  </IfModule>
+{% endif %}
+
+  <Directory {{ nextcloud_webroot }}>
+    Allow from all
+    Satisfy Any
+    Options +FollowSymlinks
+    AllowOverride All
+
+   <IfModule mod_dav.c>
+    Dav off
+   </IfModule>
+
+   SetEnv HOME {{ nextcloud_webroot }}
+   SetEnv HTTP_HOME {{ nextcloud_webroot }}
+
+  </Directory>
+</VirtualHost>
+{% endif %}
+
+{% if nextcloud_install_tls %}
+{% if nextcloud_mozilla_modern_ssl_profile %}
+# modern configuration, tweak to your needs
+SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1 -TLSv1.2
+{% else %}
+# intermediate configuration, tweak to your needs
+SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
+SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+{% endif %}
+
+SSLHonorCipherOrder     off
+# SSLSessionTickets       off
+
+SSLCompression          off
+
+# OCSP stapling
+SSLUseStapling          on
+SSLStaplingResponderTimeout 5
+SSLStaplingReturnResponderErrors off
+SSLStaplingCache        shmcb:/var/run/ocsp(128000)
+{% endif %}

+ 4 - 0
dev/provisioning/ansible/roles/nextcloud/templates/apcu_nc_ini.j2

@@ -0,0 +1,4 @@
+
+apc.enable_cli=1
+apc.shm_size={{ APC_SHM_SIZE }}
+

+ 26 - 0
dev/provisioning/ansible/roles/nextcloud/templates/nextcloud_apache2.j2

@@ -0,0 +1,26 @@
+Listen 8000
+<VirtualHost *:8000>
+    # Nextcloud dir
+    DocumentRoot {{ http_webroot }}/nextcloud/
+    <Directory {{ http_webroot }}>/nextcloud/>
+        Options Indexes FollowSymLinks
+        Require all granted
+        AllowOverride All
+        Options FollowSymLinks MultiViews
+        
+        <IfModule mod_dav.c>
+            Dav off
+        </IfModule>
+    </Directory>
+    # Deny access to .ht files
+    <Files ".ht*">
+        Require all denied
+    </Files>
+
+    # Fix zero file sizes 
+    # See https://github.com/nextcloud/server/issues/3056#issuecomment-954209565
+    SetEnv proxy-sendcl 1
+
+    # See https://httpd.apache.org/docs/current/en/mod/core.html#limitrequestbody
+    LimitRequestBody 0
+</VirtualHost>

+ 207 - 0
dev/provisioning/ansible/roles/nextcloud/templates/nginx_nc.j2

@@ -0,0 +1,207 @@
+################################################################################
+# This file was generated by Ansible for {{ansible_fqdn}}
+# Do NOT modify this file by hand!
+################################################################################
+
+{% if nextcloud_install_tls and nextcloud_tls_enforce %}
+server {
+    listen 80;
+{% if nextcloud_ipv6 %}
+    listen [::]:80;
+{% endif %}
+    server_name {{ nextcloud_trusted_domain | ansible.utils.ipwrap | join(' ') }};
+
+    # Prevent nginx HTTP Server Detection
+    server_tokens off;
+
+    # Enforce HTTPS
+    return 301 https://$server_name$request_uri;
+}
+{% endif %}
+
+server {
+    server_name {{ nextcloud_trusted_domain | ansible.utils.ipwrap | join(' ') }};
+
+{% if not nextcloud_install_tls or not nextcloud_tls_enforce %}
+    listen 80;
+{% if nextcloud_ipv6 %}
+    listen [::]:80;
+{% endif %}
+{% endif %}
+
+{% if nextcloud_install_tls %}
+    listen 443 ssl http2;
+{% if nextcloud_ipv6 %}
+    listen [::]:443 ssl http2;
+{% endif %}
+    ssl_certificate {{ nextcloud_tls_cert_file }};
+    ssl_certificate_key {{ nextcloud_tls_cert_key_file }};
+
+    # Prevent nginx HTTP Server Detection
+    server_tokens off;
+
+    ssl_session_timeout 1d;
+    ssl_session_cache shared:SSL:{{ nextcloud_tls_session_cache_size }};
+    # ssl_session_tickets off;
+
+    # OCSP stapling
+    ssl_stapling on;
+    ssl_stapling_verify on;
+
+    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
+    ssl_dhparam {{ nextcloud_tls_dhparam }};
+
+    # Use Mozilla's guidelines for SSL/TLS settings
+    # https://mozilla.github.io/server-side-tls/ssl-config-generator/
+{% if nextcloud_mozilla_modern_ssl_profile %}
+    # modern configuration. tweak to your needs.
+    ssl_protocols TLSv1.3;
+{% else %}
+    # intermediate configuration. tweak to your needs.
+    ssl_protocols TLSv1.2 TLSv1.3;
+    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
+{% endif %}
+    ssl_prefer_server_ciphers off;
+
+    # HSTS settings
+    # WARNING: Only add the preload option once you read about
+    # the consequences in https://hstspreload.org/. This option
+    # will add the domain to a hardcoded list that is shipped
+    # in all major browsers and getting removed from this list
+    # could take several months.
+{% if nextcloud_hsts is string %}
+    add_header Strict-Transport-Security "{{ nextcloud_hsts }}";
+{% endif %}
+{% endif %}
+
+    # set max upload size and increase upload timeout:
+    client_max_body_size {{ nextcloud_max_upload_size }};
+    client_body_timeout 300s;
+    fastcgi_buffers 64 4K;
+
+    # Enable gzip but do not remove ETag headers
+    gzip on;
+    gzip_vary on;
+    gzip_comp_level 4;
+    gzip_min_length 256;
+    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
+    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
+
+    # Pagespeed is not supported by Nextcloud, so if your server is built
+    # with the `ngx_pagespeed` module, uncomment this line to disable it.
+    # pagespeed off;
+
+    # HTTP response headers borrowed from Nextcloud `.htaccess`
+    add_header Referrer-Policy                      "no-referrer"   always;
+    add_header X-Content-Type-Options               "nosniff"       always;
+    add_header X-Download-Options                   "noopen"        always;
+    add_header X-Frame-Options                      "SAMEORIGIN"    always;
+    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
+    add_header X-Robots-Tag                         "none"          always;
+    add_header X-XSS-Protection                     "1; mode=block" always;
+
+    # Remove X-Powered-By, which is an information leak
+    fastcgi_hide_header X-Powered-By;
+
+    # Path to the root of your installation
+    root {{ nextcloud_webroot }};
+
+    # Specify how to handle directories -- specifying `/index.php$request_uri`
+    # here as the fallback means that Nginx always exhibits the desired behaviour
+    # when a client requests a path that corresponds to a directory that exists
+    # on the server. In particular, if that directory contains an index.php file,
+    # that file is correctly served; if it doesn't, then the request is passed to
+    # the front-end controller. This consistent behaviour means that we don't need
+    # to specify custom rules for certain paths (e.g. images and other assets,
+    # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
+    # `try_files $uri $uri/ /index.php$request_uri`
+    # always provides the desired behaviour.
+    index index.php index.html /index.php$request_uri;
+
+    # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
+    location = / {
+        if ( $http_user_agent ~ ^DavClnt ) {
+            return 302 /remote.php/webdav/$is_args$args;
+        }
+    }
+
+    location = /robots.txt {
+        allow all;
+        log_not_found off;
+        access_log off;
+    }
+
+    # Make a regex exception for `/.well-known` so that clients can still
+    # access it despite the existence of the regex rule
+    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
+    # for `/.well-known`.
+    location ^~ /.well-known {
+        # The rules in this block are an adaptation of the rules
+        # in `.htaccess` that concern `/.well-known`.
+
+        location = /.well-known/carddav { return 301 /remote.php/dav/; }
+        location = /.well-known/caldav  { return 301 /remote.php/dav/; }
+
+        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
+        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }
+
+        # Let Nextcloud's API for `/.well-known` URIs handle all other
+        # requests by passing them to the front-end controller.
+        return 301 /index.php$request_uri;
+    }
+
+    # Rules borrowed from `.htaccess` to hide certain paths from clients
+    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
+    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }
+
+    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
+    # which handle static assets (as seen below). If this block is not declared first,
+    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
+    # to the URI, resulting in a HTTP 500 error response.
+    location ~ \.php(?:$|/) {
+        # Required for legacy support
+        rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;
+
+        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+        set $path_info $fastcgi_path_info;
+
+        try_files $fastcgi_script_name =404;
+
+        include fastcgi_params;
+        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+        fastcgi_param PATH_INFO $path_info;
+        fastcgi_param HTTPS on;
+
+        fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
+        fastcgi_param front_controller_active true;     # Enable pretty urls
+        fastcgi_pass php-handler;
+
+        fastcgi_intercept_errors on;
+        fastcgi_request_buffering off;
+    }
+
+    location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite)$ {
+        try_files $uri /index.php$request_uri;
+        expires 6M;         # Cache-Control policy borrowed from `.htaccess`
+        access_log off;     # Optional: Don't log access to assets
+
+        location ~ \.wasm$ {
+            default_type application/wasm;
+        }
+    }
+
+    location ~ \.woff2?$ {
+        try_files $uri /index.php$request_uri;
+        expires 7d;         # Cache-Control policy borrowed from `.htaccess`
+        access_log off;     # Optional: Don't log access to assets
+    }
+
+    # Rule borrowed from `.htaccess`
+    location /remote {
+        return 301 /remote.php$request_uri;
+    }
+
+    location / {
+        try_files $uri $uri/ /index.php$request_uri;
+    }
+}

+ 9 - 0
dev/provisioning/ansible/roles/nextcloud/templates/nginx_php_handler.j2

@@ -0,0 +1,9 @@
+################################################################################
+# This file was generated by Ansible for {{ansible_fqdn}}
+# Do NOT modify this file by hand!
+################################################################################
+
+upstream php-handler {
+    # server 127.0.0.1:9000;
+    server unix:{{ php_socket }};
+}

+ 13 - 0
dev/provisioning/ansible/roles/nextcloud/templates/opcache_nc_ini.j2

@@ -0,0 +1,13 @@
+
+opcache.enable=1
+opcache.enable_cli=1
+opcache.memory_consumption={{ OPCACHE_MEM_SIZE }}
+opcache.interned_strings_buffer=32
+opcache.max_accelerated_files=10000
+opcache.save_comments=1
+opcache.revalidate_freq=60
+
+opcache.fast_shutdown=1
+opcache.jit=disable
+opcache.jit_buffer_size=0
+

+ 11 - 0
dev/provisioning/ansible/roles/nextcloud/templates/php_nc_ini.j2

@@ -0,0 +1,11 @@
+
+memory_limit = {{ PHP_MEMORY_LIMIT }}
+upload_max_filesize = {{ PHP_UPLOAD_LIMIT }}
+post_max_size = {{ PHP_POST_LIMIT }}
+max_file_uploads = {{ PHP_MAX_FILE }}
+max_execution_time = {{ PHP_MAX_TIME }}
+max_input_time = {{ PHP_MAX_TIME }}
+session.gc_maxlifetime = {{ PHP_MAX_TIME }}
+
+output_buffering = Off
+

+ 9 - 0
dev/provisioning/ansible/roles/nextcloud/templates/redis.config.php.j2

@@ -0,0 +1,9 @@
+<?php
+$CONFIG = array (
+  'memcache.distributed' => '\OC\Memcache\Redis',
+  'memcache.locking' => '\OC\Memcache\Redis',
+  'redis' => array (
+    'host' => '{{ redis_host }}',
+    'port' => 6379,
+  ),
+);

+ 5 - 0
dev/provisioning/ansible/roles/nextcloud/templates/root-my.cnf.j2

@@ -0,0 +1,5 @@
+{{ ansible_managed | comment }}
+
+[client]
+user="root"
+password="{{ nextcloud_mysql_root_pwd }}"

+ 17 - 0
dev/provisioning/ansible/roles/nextcloud/vars/main.yml

@@ -0,0 +1,17 @@
+---
+# vars file for nextcloud
+
+nextcloud_dl_file_name:
+  latest: "{{ ['latest', nextcloud_version_major]|reject('undefined')|join('-') }}"
+  releases: "{{ ['nextcloud', nextcloud_version_full]|reject('undefined')|join('-') }}"
+  prereleases: "nextcloud-{{ [nextcloud_version_full, nextcloud_version_special]|reject('undefined')|join() }}"
+  daily: "nextcloud-{{ nextcloud_version_major|d('') }}-daily-{{ nextcloud_version_special|d('') }}"
+
+mysql_credential_file:
+  debian: '/etc/mysql/debian.cnf'
+
+nextcloud_max_upload_size_in_bytes: "{{ nextcloud_max_upload_size | human_to_bytes }}"
+
+# load configurations references
+os_config_ref: "{{ lookup('ansible.builtin.template', [role_path,'defaults','os_config_ref.yml']|join('/')) | from_yaml }}"
+php_config_ref: "{{ lookup('ansible.builtin.template', [role_path,'defaults','php_config_ref.yml']|join('/')) | from_yaml }}"

+ 5 - 0
dev/provisioning/ansible/roles/node_exporter/defaults/main.yml

@@ -0,0 +1,5 @@
+---
+node_exporter_version: 1.3.1 
+node_exporter_url: "https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}"
+node_exporter_tarball: "node_exporter-{{ node_exporter_version }}.linux-amd64"
+node_exporter_skip_install: false

+ 14 - 0
dev/provisioning/ansible/roles/node_exporter/files/node_exporter.service

@@ -0,0 +1,14 @@
+[Unit]
+Description=node_exporter
+Wants=network-online.target
+After=network-online.target
+
+[Service]
+User=node_exporter
+Group=node_exporter
+Restart=on-failure
+Type=simple
+ExecStart=/usr/local/bin/node_exporter
+
+[Install]
+WantedBy=multi-user.target

+ 70 - 0
dev/provisioning/ansible/roles/node_exporter/tasks/main.yml

@@ -0,0 +1,70 @@
+---
+
+- name: Creating node_exporter user group
+  group: name="node_exporter"
+  become: true
+
+- name: Creating node_exporter user
+  user:
+    name: "node_exporter"
+    group: "node_exporter"
+    system: yes
+    shell: "/sbin/nologin"
+    comment: "node_exporter nologin User"
+    createhome: "no"
+    state: present
+
+- name: Node exporter... Download Prometheus archive
+  get_url:
+    url:  "{{ node_exporter_url }}/{{ node_exporter_tarball }}.tar.gz"
+    dest: /tmp/{{ node_exporter_tarball }}.tar.gz
+    checksum: "sha256:{{ node_exporter_url }}/sha256sums.txt"
+  register: _download_archive
+  until: _download_archive is succeeded
+  retries: 5
+  delay: 2
+  when: not node_exporter_skip_install
+
+- name: Node exporter... unpack prometheus binaries
+  unarchive:
+    src: "/tmp/{{ node_exporter_tarball }}.tar.gz"
+    dest: "/tmp"
+    creates: "/tmp/{{ node_exporter_tarball }}/node_exporter"
+    remote_src: true
+  when: not node_exporter_skip_install
+
+- name: Node exporter... Copy prometheus node exporter file to bin
+  copy:
+    src: "/tmp/{{ node_exporter_tarball }}/node_exporter"
+    dest: "/usr/local/bin/node_exporter"
+    owner: node_exporter
+    group: node_exporter
+    remote_src: yes
+    mode: 0755
+  when: not node_exporter_skip_install
+
+- name: Delete node exporter tmp folder
+  file:
+    path: "/tmp/{{ node_exporter_tarball }}.tar.gz"
+    state: absent
+  when: not node_exporter_skip_install
+
+- name: Node exporter... Copy systemd init file
+  copy:
+    dest: /etc/systemd/system/node_exporter.service
+    src: files/node_exporter.service
+    owner: root
+    group: root
+    mode: 0640
+
+- name: Start node_exporter service
+  service:
+    name: node_exporter
+    state: started
+    enabled: yes
+
+- name: Check if node exporter emits metrices
+  uri:
+    url: http://127.0.0.1:9100/metrics
+    method: GET
+    status_code: 200

+ 228 - 0
dev/provisioning/ansible/roles/prometheus/defaults/main.yml

@@ -0,0 +1,228 @@
+---
+alertmanager_version: "0.24.0"
+alertmanager_tarball: "alertmanager-{{ alertmanager_version }}.linux-amd64"
+alertmanager_url: "https://github.com/prometheus/alertmanager/releases/download/v{{ alertmanager_version }}"
+alertmanager_skip_install: false
+
+prometheus_version: 2.37.1
+prometheus_tarball: "prometheus-{{ prometheus_version }}.linux-amd64"
+prometheus_url: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheus_version }}"
+prometheus_skip_install: false
+
+prometheus_binary_local_dir: ''
+prometheus_binary_install_dir: '/usr/local/bin'
+
+prometheus_config_dir: /etc/prometheus
+prometheus_db_dir: /var/lib/prometheus
+prometheus_read_only_dirs: []
+
+prometheus_web_listen_address: "0.0.0.0:9090"
+prometheus_web_external_url: ''
+# See https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md
+prometheus_web_config:
+  tls_server_config: {}
+  http_server_config: {}
+  basic_auth_users: {}
+
+prometheus_storage_retention: "30d"
+# Available since Prometheus 2.7.0
+# [EXPERIMENTAL] Maximum number of bytes that can be stored for blocks. Units
+# supported: KB, MB, GB, TB, PB.
+prometheus_storage_retention_size: "0"
+
+prometheus_config_flags_extra: {}
+# prometheus_config_flags_extra:
+#   storage.tsdb.retention: 15d
+#   alertmanager.timeout: 10s
+
+prometheus_alertmanager_config: []
+# prometheus_alertmanager_config:
+#   - scheme: https
+#     path_prefix: alertmanager/
+#     basic_auth:
+#       username: user
+#       password: pass
+#     static_configs:
+#       - targets: ["127.0.0.1:9093"]
+#     proxy_url: "127.0.0.2"
+
+prometheus_alert_relabel_configs: []
+# prometheus_alert_relabel_configs:
+#   - action: labeldrop
+#     regex: replica
+
+prometheus_global:
+  scrape_interval: 15s
+  scrape_timeout: 10s
+  evaluation_interval: 15s
+
+prometheus_remote_write: []
+# prometheus_remote_write:
+#   - url: https://dev.kausal.co/prom/push
+#     basic_auth:
+#       password: FOO
+
+prometheus_remote_read: []
+# prometheus_remote_read:
+#   - url: https://demo.cloudalchemy.org:9201/read
+#     basic_auth:
+#       password: FOO
+
+prometheus_external_labels:
+  environment: "{{ ansible_fqdn | default(ansible_host) | default(inventory_hostname) }}"
+
+prometheus_targets: {}
+#  node:
+#    - targets:
+#        - localhost:9100
+#      labels:
+#        env: test
+
+prometheus_scrape_configs:
+  - job_name: "prometheus"
+    metrics_path: "{{ prometheus_metrics_path }}"
+    static_configs:
+      - targets:
+          - "{{ ansible_fqdn | default(ansible_host) | default('localhost') }}:9090"
+  - job_name: "node"
+    file_sd_configs:
+      - files:
+          - "{{ prometheus_config_dir }}/file_sd/node.yml"
+
+# Alternative config file name, searched in ansible templates path.
+prometheus_config_file: 'prometheus.yml.j2'
+
+prometheus_alert_rules_files:
+  - prometheus/rules/*.rules
+
+prometheus_static_targets_files:
+  - prometheus/targets/*.yml
+  - prometheus/targets/*.json
+
+prometheus_alert_rules:
+  - alert: Watchdog
+    expr: vector(1)
+    for: 10m
+    labels:
+      severity: warning
+    annotations:
+      description: "This is an alert meant to ensure that the entire alerting pipeline is functional.\nThis alert is always firing, therefore it should always be firing in Alertmanager\nand always fire against a receiver. There are integrations with various notification\nmechanisms that send a notification when this alert is not firing. For example the\n\"DeadMansSnitch\" integration in PagerDuty."
+      summary: 'Ensure entire alerting pipeline is functional'
+  - alert: InstanceDown
+    expr: 'up == 0'
+    for: 5m
+    labels:
+      severity: critical
+    annotations:
+      description: '{% raw %}{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes.{% endraw %}'
+      summary: '{% raw %}Instance {{ $labels.instance }} down{% endraw %}'
+  - alert: RebootRequired
+    expr: 'node_reboot_required > 0'
+    labels:
+      severity: warning
+    annotations:
+      description: '{% raw %}{{ $labels.instance }} requires a reboot.{% endraw %}'
+      summary: '{% raw %}Instance {{ $labels.instance }} - reboot required{% endraw %}'
+  - alert: NodeFilesystemSpaceFillingUp
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available space left and is filling up.{% endraw %}'
+      summary: 'Filesystem is predicted to run out of space within the next 24 hours.'
+    expr: "(\n  node_filesystem_avail_bytes{job=\"node\",fstype!=\"\"} / node_filesystem_size_bytes{job=\"node\",fstype!=\"\"} * 100 < 40\nand\n  predict_linear(node_filesystem_avail_bytes{job=\"node\",fstype!=\"\"}[6h], 24*60*60) < 0\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: warning
+  - alert: NodeFilesystemSpaceFillingUp
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available space left and is filling up fast.{% endraw %}'
+      summary: 'Filesystem is predicted to run out of space within the next 4 hours.'
+    expr: "(\n  node_filesystem_avail_bytes{job=\"node\",fstype!=\"\"} / node_filesystem_size_bytes{job=\"node\",fstype!=\"\"} * 100 < 20\nand\n  predict_linear(node_filesystem_avail_bytes{job=\"node\",fstype!=\"\"}[6h], 4*60*60) < 0\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: critical
+  - alert: NodeFilesystemAlmostOutOfSpace
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available space left.{% endraw %}'
+      summary: 'Filesystem has less than 5% space left.'
+    expr: "(\n  node_filesystem_avail_bytes{job=\"node\",fstype!=\"\"} / node_filesystem_size_bytes{job=\"node\",fstype!=\"\"} * 100 < 5\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: warning
+  - alert: NodeFilesystemAlmostOutOfSpace
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available space left.{% endraw %}'
+      summary: 'Filesystem has less than 3% space left.'
+    expr: "(\n  node_filesystem_avail_bytes{job=\"node\",fstype!=\"\"} / node_filesystem_size_bytes{job=\"node\",fstype!=\"\"} * 100 < 3\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: critical
+  - alert: NodeFilesystemFilesFillingUp
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available inodes left and is filling up.{% endraw %}'
+      summary: 'Filesystem is predicted to run out of inodes within the next 24 hours.'
+    expr: "(\n  node_filesystem_files_free{job=\"node\",fstype!=\"\"} / node_filesystem_files{job=\"node\",fstype!=\"\"} * 100 < 40\nand\n  predict_linear(node_filesystem_files_free{job=\"node\",fstype!=\"\"}[6h], 24*60*60) < 0\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: warning
+  - alert: NodeFilesystemFilesFillingUp
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available inodes left and is filling up fast.{% endraw %}'
+      summary: 'Filesystem is predicted to run out of inodes within the next 4 hours.'
+    expr: "(\n  node_filesystem_files_free{job=\"node\",fstype!=\"\"} / node_filesystem_files{job=\"node\",fstype!=\"\"} * 100 < 20\nand\n  predict_linear(node_filesystem_files_free{job=\"node\",fstype!=\"\"}[6h], 4*60*60) < 0\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: critical
+  - alert: NodeFilesystemAlmostOutOfFiles
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available inodes left.{% endraw %}'
+      summary: 'Filesystem has less than 5% inodes left.'
+    expr: "(\n  node_filesystem_files_free{job=\"node\",fstype!=\"\"} / node_filesystem_files{job=\"node\",fstype!=\"\"} * 100 < 5\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: warning
+  - alert: NodeFilesystemAlmostOutOfFiles
+    annotations:
+      description: '{% raw %}Filesystem on {{ $labels.device }} at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available inodes left.{% endraw %}'
+      summary: 'Filesystem has less than 3% inodes left.'
+    expr: "(\n  node_filesystem_files_free{job=\"node\",fstype!=\"\"} / node_filesystem_files{job=\"node\",fstype!=\"\"} * 100 < 3\nand\n  node_filesystem_readonly{job=\"node\",fstype!=\"\"} == 0\n)\n"
+    for: 1h
+    labels:
+      severity: critical
+  - alert: NodeNetworkReceiveErrs
+    annotations:
+      description: '{% raw %}{{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf "%.0f" $value }} receive errors in the last two minutes.{% endraw %}'
+      summary: 'Network interface is reporting many receive errors.'
+    expr: "increase(node_network_receive_errs_total[2m]) > 10\n"
+    for: 1h
+    labels:
+      severity: warning
+  - alert: NodeNetworkTransmitErrs
+    annotations:
+      description: '{% raw %}{{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf "%.0f" $value }} transmit errors in the last two minutes.{% endraw %}'
+      summary: 'Network interface is reporting many transmit errors.'
+    expr: "increase(node_network_transmit_errs_total[2m]) > 10\n"
+    for: 1h
+    labels:
+      severity: warning
+  - alert: NodeHighNumberConntrackEntriesUsed
+    annotations:
+      description: '{% raw %}{{ $value | humanizePercentage }} of conntrack entries are used{% endraw %}'
+      summary: 'Number of conntrack are getting close to the limit'
+    expr: "(node_nf_conntrack_entries / node_nf_conntrack_entries_limit) > 0.75\n"
+    labels:
+      severity: warning
+  - alert: NodeClockSkewDetected
+    annotations:
+      message: '{% raw %}Clock on {{ $labels.instance }} is out of sync by more than 300s. Ensure NTP is configured correctly on this host.{% endraw %}'
+      summary: 'Clock skew detected.'
+    expr: "(\n  node_timex_offset_seconds > 0.05\nand\n  deriv(node_timex_offset_seconds[5m]) >= 0\n)\nor\n(\n  node_timex_offset_seconds < -0.05\nand\n  deriv(node_timex_offset_seconds[5m]) <= 0\n)\n"
+    for: 10m
+    labels:
+      severity: warning
+  - alert: NodeClockNotSynchronising
+    annotations:
+      message: '{% raw %}Clock on {{ $labels.instance }} is not synchronising. Ensure NTP is configured on this host.{% endraw %}'
+      summary: 'Clock not synchronising.'
+    expr: "min_over_time(node_timex_sync_status[5m]) == 0\n"
+    for: 10m
+    labels:
+      severity: warning

+ 16 - 0
dev/provisioning/ansible/roles/prometheus/files/alertmanager.service

@@ -0,0 +1,16 @@
+[Unit]
+Description=alertmanager
+Wants=network-online.target
+After=network-online.target
+
+[Service]
+User=alertmanager
+Group=alertmanager
+Restart=always
+RestartSec=2
+StartLimitInterval=0
+Type=simple
+ExecStart=/usr/local/bin/alertmanager --config.file=/etc/alertmanager/alertmanager.yml --storage.path=/data/alertmanager
+
+[Install]
+WantedBy=multi-user.target

+ 18 - 0
dev/provisioning/ansible/roles/prometheus/files/alertmanager.yml

@@ -0,0 +1,18 @@
+global:
+  slack_api_url: "https://hooks.slack.com/services/SlackWebhookAPI"
+
+route:
+  group_by: ['instance', 'severity']
+  group_wait: 30s
+  group_interval: 5m
+  repeat_interval: 3h
+  routes:
+  - match:
+      alertname: InstanceDown
+  receiver: 'alert-team'
+
+receivers:
+- name: 'alert-team'
+  slack_configs:
+  - channel: "#webhook-test"
+    text: "summary: {{ .CommonAnnotations.summary }}\ndescription: {{ .CommonAnnotations.description }}"

+ 17 - 0
dev/provisioning/ansible/roles/prometheus/handlers/main.yml

@@ -0,0 +1,17 @@
+---
+- name: restart prometheus
+  become: true
+  systemd:
+    daemon_reload: true
+    name: prometheus
+    state: restarted
+
+- name: reload prometheus
+  become: true
+  systemd:
+    name: prometheus
+    state: reloaded
+
+- name: reload alertmanager
+  command: systemctl daemon-reload
+  listen: systemd_reload

+ 88 - 0
dev/provisioning/ansible/roles/prometheus/tasks/alertmanager.yml

@@ -0,0 +1,88 @@
+- name: Creating alertmanager user group
+  group: name="alertmanager"
+  become: true
+
+- name: Creating alertmanager user
+  user:
+    name: "alertmanager"
+    group: "alertmanager"
+    system: yes
+    shell: "/sbin/nologin"
+    comment: "alertmanager nologin User"
+    createhome: "no"
+    state: present
+
+- name: AlertManager... Download alertmanager archive
+  get_url:
+    url:  "{{ alertmanager_url }}/{{ alertmanager_tarball }}.tar.gz"
+    dest: /tmp/{{ alertmanager_tarball }}.tar.gz
+    checksum: "sha256:{{ alertmanager_url }}/sha256sums.txt"
+  register: _download_archive
+  until: _download_archive is succeeded
+  retries: 5
+  delay: 2
+  when: not alertmanager_skip_install
+
+- name: AlertManager... unpack alertmanager binaries
+  unarchive:
+    src: "/tmp/{{ alertmanager_tarball }}.tar.gz"
+    dest: "/tmp"
+    creates: "/tmp/{{ alertmanager_tarball }}/alertmanager"
+    remote_src: true
+  when: not alertmanager_skip_install
+
+- name: Copy alertmanager executable to bin
+  copy:
+    src: "/tmp/{{ alertmanager_tarball }}/alertmanager"
+    dest: "/usr/local/bin/alertmanager"
+    owner: alertmanager
+    group: alertmanager
+    remote_src: yes
+    mode: 0755
+
+- name: Delete alertmanager tmp folder
+  file:
+    path: '/tmp/{{ alertmanager_tarball }}'
+    state: absent
+
+- name: Creates data directory
+  file: 
+    path: "/data/alertmanager/"
+    state: directory
+    owner: alertmanager
+    group: alertmanager
+    mode: 0755
+
+- name: Creates config directory
+  file: 
+    path: "/etc/alertmanager/"
+    state: directory
+    owner: alertmanager
+    group: alertmanager
+    mode: 0755
+
+- name: Copy config file
+  copy:
+    src: "{{ role_path }}/files/alertmanager.yml"
+    dest: /etc/alertmanager/alertmanager.yml
+
+- name: AlertManager... Copy systemd init file
+  copy:
+    dest: /etc/systemd/system/alertmanager.service
+    src: files/alertmanager.service
+    owner: root
+    group: root
+    mode: 0640
+  notify: systemd_reload
+
+- name: Start alertmanager service
+  service:
+    name: alertmanager
+    state: started
+    enabled: yes
+
+- name: Check if alertmanager is accessible
+  uri:
+    url: http://localhost:9093
+    method: GET
+    status_code: 200

+ 69 - 0
dev/provisioning/ansible/roles/prometheus/tasks/configure.yml

@@ -0,0 +1,69 @@
+---
+- name: alerting rules file
+  template:
+    src: "alert.rules.j2"
+    dest: "{{ prometheus_config_dir }}/rules/ansible_managed.rules"
+    owner: root
+    group: prometheus
+    mode: 0640
+    validate: "{{ prometheus_binary_install_dir }}/promtool check rules %s"
+  when:
+    - prometheus_alert_rules != []
+  notify:
+    - reload prometheus
+
+- name: copy custom alerting rule files
+  copy:
+    src: "{{ item }}"
+    dest: "{{ prometheus_config_dir }}/rules/"
+    owner: root
+    group: prometheus
+    mode: 0640
+    validate: "{{ prometheus_binary_install_dir }}/promtool check rules %s"
+  with_fileglob: "{{ prometheus_alert_rules_files }}"
+  notify:
+    - reload prometheus
+
+- name: configure prometheus
+  template:
+    src: "{{ prometheus_config_file }}"
+    dest: "{{ prometheus_config_dir }}/prometheus.yml"
+    force: true
+    owner: root
+    group: prometheus
+    mode: 0640
+    validate: "{{ prometheus_binary_install_dir }}/promtool check config %s"
+  notify:
+    - reload prometheus
+
+- name: configure Prometheus web
+  copy:
+    content: "{{ prometheus_web_config | to_nice_yaml(indent=2,sort_keys=False) }}"
+    dest: "{{ prometheus_config_dir }}/web.yml"
+    force: true
+    owner: root
+    group: prometheus
+    mode: 0640
+
+- name: configure prometheus static targets
+  copy:
+    content: |
+      #jinja2: lstrip_blocks: True
+      {{ item.value | to_nice_yaml(indent=2,sort_keys=False) }}
+    dest: "{{ prometheus_config_dir }}/file_sd/{{ item.key }}.yml"
+    force: true
+    owner: root
+    group: prometheus
+    mode: 0640
+  with_dict: "{{ prometheus_targets }}"
+  when: prometheus_targets != {}
+
+- name: copy prometheus custom static targets
+  copy:
+    src: "{{ item }}"
+    dest: "{{ prometheus_config_dir }}/file_sd/"
+    force: true
+    owner: root
+    group: prometheus
+    mode: 0640
+  with_fileglob: "{{ prometheus_static_targets_files }}"

+ 88 - 0
dev/provisioning/ansible/roles/prometheus/tasks/download.yml

@@ -0,0 +1,88 @@
+---
+- name: Get systemd version
+  command: systemctl --version
+  changed_when: false
+  check_mode: false
+  register: __systemd_version
+  tags:
+    - skip_ansible_lint
+
+- name: Set systemd version fact
+  set_fact:
+    prometheus_systemd_version: "{{ __systemd_version.stdout_lines[0].split(' ')[-1] }}"
+
+- name: Assert no duplicate config flags
+  assert:
+    that:
+      - prometheus_config_flags_extra['config.file'] is not defined
+      - prometheus_config_flags_extra['storage.tsdb.path'] is not defined
+      - prometheus_config_flags_extra['storage.local.path'] is not defined
+      - prometheus_config_flags_extra['web.listen-address'] is not defined
+      - prometheus_config_flags_extra['web.external-url'] is not defined
+    msg: "Detected duplicate configuration entry. Please check your ansible variables and role README.md."
+
+- name: Assert external_labels aren't configured twice
+  assert:
+    that: prometheus_global.external_labels is not defined
+    msg: "Use prometheus_external_labels to define external labels"
+
+- name: Set prometheus external metrics path
+  set_fact:
+    prometheus_metrics_path: "/{{ ( prometheus_web_external_url + '/metrics' ) | regex_replace('^(.*://)?(.*?)/') }}"
+
+- name: Fail when prometheus_config_flags_extra duplicates parameters set by other variables
+  fail:
+    msg: >
+      Whooops. You are duplicating configuration. Please look at your prometheus_config_flags_extra
+      and check against other variables in defaults/main.yml
+  with_items:
+    - 'storage.tsdb.retention'
+    - 'storage.tsdb.path'
+    - 'storage.local.retention'
+    - 'storage.local.path'
+    - 'config.file'
+    - 'web.listen-address'
+    - 'web.external-url'
+  when: item in prometheus_config_flags_extra.keys()
+
+- name: Get all file_sd files from scrape_configs
+  set_fact:
+    file_sd_files: "{{ prometheus_scrape_configs | json_query('[*][].file_sd_configs[*][].files[]') }}"
+
+- name: Fail when file_sd targets are not defined in scrape_configs
+  fail:
+    msg: >
+      Oh, snap! `{{ item.key }}` couldn't be found in your scrape configs. Please ensure you provided
+      all targets from prometheus_targets in prometheus_scrape_configs
+  when: not prometheus_config_dir + "/file_sd/" + item.key + ".yml" in file_sd_files
+  #  when: not item | basename | splitext | difference(['.yml']) | join('') in prometheus_targets.keys()
+  with_dict: "{{ prometheus_targets }}"
+
+- name: Alert when prometheus_alertmanager_config is empty, but prometheus_alert_rules is specified
+  debug:
+    msg: >
+      No alertmanager configuration was specified. If you want your alerts to be sent make sure to
+      specify a prometheus_alertmanager_config in defaults/main.yml.
+  when:
+    - prometheus_alertmanager_config == []
+    - prometheus_alert_rules != []
+
+- name: Download... Download Prometheus archive
+  get_url:
+    url:  "{{ prometheus_url }}/{{ prometheus_tarball }}.tar.gz"
+    dest: /tmp/{{ prometheus_tarball }}.tar.gz
+    checksum: "sha256:{{ prometheus_url }}/sha256sums.txt"
+  register: _download_archive
+  until: _download_archive is succeeded
+  retries: 5
+  delay: 2
+  when: not prometheus_skip_install
+
+- name: unpack prometheus binaries
+  unarchive:
+    src: "/tmp/{{ prometheus_tarball }}.tar.gz"
+    dest: "/tmp"
+    creates: "/tmp/{{ prometheus_tarball }}/prometheus"
+    remote_src: true
+  when: not prometheus_skip_install
+

+ 97 - 0
dev/provisioning/ansible/roles/prometheus/tasks/install.yml

@@ -0,0 +1,97 @@
+---
+- name: create prometheus system group
+  group:
+    name: prometheus
+    system: true
+    state: present
+
+- name: create prometheus system user
+  user:
+    name: prometheus
+    system: true
+    shell: "/usr/sbin/nologin"
+    group: prometheus
+    createhome: false
+    home: "{{ prometheus_db_dir }}"
+
+- name: create prometheus data directory
+  file:
+    path: "{{ prometheus_db_dir }}"
+    state: directory
+    owner: prometheus
+    group: prometheus
+    mode: 0755
+
+- name: create prometheus configuration directories
+  file:
+    path: "{{ item }}"
+    state: directory
+    owner: root
+    group: prometheus
+    mode: 0770
+  with_items:
+    - "{{ prometheus_config_dir }}"
+    - "{{ prometheus_config_dir }}/rules"
+    - "{{ prometheus_config_dir }}/file_sd"
+
+- name: propagate official prometheus and promtool binaries
+  copy:
+    src: "/tmp/{{ prometheus_tarball }}/{{ item }}"
+    dest: "{{ prometheus_binary_install_dir }}/{{ item }}"
+    mode: 0755
+    owner: root
+    group: root
+    remote_src: true
+  with_items:
+    - prometheus
+    - promtool
+  notify:
+    - restart prometheus
+
+- name: propagate official console templates
+  copy:
+    src: "/tmp/{{ prometheus_tarball }}/{{ item }}/"
+    dest: "{{ prometheus_config_dir }}/{{ item }}"
+    mode: 0644
+    owner: root
+    group: root
+    remote_src: true
+  with_items:
+    - console_libraries
+    - consoles
+  notify:
+    - restart prometheus
+
+      #- name: propagate locally distributed prometheus and promtool binaries
+      #  copy:
+      #    src: "{{ prometheus_binary_local_dir }}/{{ item }}"
+      #    dest: "{{ prometheus_binary_install_dir }}/{{ item }}"
+      #    mode: 0755
+      #    owner: root
+      #    group: root
+      #    remote_src: true
+      #  with_items:
+      #    - prometheus
+      #    - promtool
+      #  notify:
+      #    - restart prometheus
+
+- name: create systemd service unit
+  template:
+    src: prometheus.service.j2
+    dest: /etc/systemd/system/prometheus.service
+    owner: root
+    group: root
+    mode: 0644
+  notify:
+    - restart prometheus
+
+- name: Allow prometheus to bind to port in SELinux
+  seport:
+    ports: "{{ prometheus_web_listen_address.split(':')[1] }}"
+    proto: tcp
+    setype: http_port_t
+    state: present
+  when:
+    - (ansible_os_family == "RedHat")
+    - (ansible_selinux.status == "enabled")

+ 17 - 0
dev/provisioning/ansible/roles/prometheus/tasks/main.yml

@@ -0,0 +1,17 @@
+---
+- include: download.yml
+
+- include: install.yml
+  when: not prometheus_skip_install
+  
+- include: configure.yml
+ 
+- name: ensure prometheus service is started and enabled
+  become: true
+  systemd:
+    daemon_reload: true
+    name: prometheus
+    state: started
+    enabled: true
+
+- include: alertmanager.yml

+ 6 - 0
dev/provisioning/ansible/roles/prometheus/templates/alert.rules.j2

@@ -0,0 +1,6 @@
+{{ ansible_managed | comment }}
+
+groups:
+- name: ansible managed alert rules
+  rules:
+  {{ prometheus_alert_rules | to_nice_yaml(indent=2,sort_keys=False) | indent(2,False) }}

+ 85 - 0
dev/provisioning/ansible/roles/prometheus/templates/prometheus.service.j2

@@ -0,0 +1,85 @@
+{{ ansible_managed | comment }}
+
+[Unit]
+Description=Prometheus
+After=network-online.target
+Requires=local-fs.target
+After=local-fs.target
+
+[Service]
+Type=simple
+Environment="GOMAXPROCS={{ ansible_processor_vcpus|default(ansible_processor_count) }}"
+User=prometheus
+Group=prometheus
+ExecReload=/bin/kill -HUP $MAINPID
+ExecStart={{ prometheus_binary_install_dir }}/prometheus \
+  --storage.tsdb.path={{ prometheus_db_dir }} \
+{% if prometheus_version is version('2.7.0', '>=') %}
+  --storage.tsdb.retention.time={{ prometheus_storage_retention }} \
+  --storage.tsdb.retention.size={{ prometheus_storage_retention_size }} \
+{% else %}
+  --storage.tsdb.retention={{ prometheus_storage_retention }} \
+{% endif %}
+{% if prometheus_version is version('2.24.0', '>=') %}
+  --web.config.file={{ prometheus_config_dir }}/web.yml \
+{% endif %}
+  --web.console.libraries={{ prometheus_config_dir }}/console_libraries \
+  --web.console.templates={{ prometheus_config_dir }}/consoles \
+  --web.listen-address={{ prometheus_web_listen_address }} \
+  --web.external-url={{ prometheus_web_external_url }} \
+{% for flag, flag_value in prometheus_config_flags_extra.items() %}
+{% if not flag_value %}
+  --{{ flag }} \
+{% elif flag_value is string %}
+  --{{ flag }}={{ flag_value }} \
+{% elif flag_value is sequence %}
+{% for flag_value_item in flag_value %}
+  --{{ flag }}={{ flag_value_item }} \
+{% endfor %}
+{% endif %}
+{% endfor %}
+  --config.file={{ prometheus_config_dir }}/prometheus.yml
+
+CapabilityBoundingSet=CAP_SET_UID
+LimitNOFILE=65000
+LockPersonality=true
+NoNewPrivileges=true
+MemoryDenyWriteExecute=true
+PrivateDevices=true
+PrivateTmp=true
+ProtectHome=true
+RemoveIPC=true
+RestrictSUIDSGID=true
+#SystemCallFilter=@signal @timer
+
+{% if prometheus_systemd_version | int >= 231 %}
+ReadWritePaths={{ prometheus_db_dir }}
+{% for path in prometheus_read_only_dirs %}
+ReadOnlyPaths={{ path }}
+{% endfor %}
+{% else %}
+ReadWriteDirectories={{ prometheus_db_dir }}
+{% for path in prometheus_read_only_dirs %}
+ReadOnlyDirectories={{ path }}
+{% endfor %}
+{% endif %}
+
+{% if prometheus_systemd_version | int >= 232 %}
+PrivateUsers=true
+ProtectControlGroups=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectSystem=strict
+{% else %}
+ProtectSystem=full
+{% endif %}
+
+{% if http_proxy is defined %}
+Environment="HTTP_PROXY={{ http_proxy }}"{% if https_proxy is defined %} "HTTPS_PROXY={{ https_proxy }}{% endif %}"
+{% endif %}
+
+SyslogIdentifier=prometheus
+Restart=always
+
+[Install]
+WantedBy=multi-user.target

+ 34 - 0
dev/provisioning/ansible/roles/prometheus/templates/prometheus.yml.j2

@@ -0,0 +1,34 @@
+#jinja2: trim_blocks: True, lstrip_blocks: True
+{{ ansible_managed | comment }}
+# http://prometheus.io/docs/operating/configuration/
+
+global:
+  {{ prometheus_global | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }}
+  external_labels:
+    {{ prometheus_external_labels | to_nice_yaml(indent=2,sort_keys=False) | indent(4, False) }}
+
+{% if prometheus_remote_write != [] %}
+remote_write:
+  {{ prometheus_remote_write | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }}
+{% endif %}
+
+{% if prometheus_remote_read != [] %}
+remote_read:
+  {{ prometheus_remote_read | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }}
+{% endif %}
+
+rule_files:
+  - {{ prometheus_config_dir }}/rules/*.rules
+
+{% if prometheus_alertmanager_config | length > 0 %}
+alerting:
+  alertmanagers:
+  {{ prometheus_alertmanager_config | to_nice_yaml(indent=2,sort_keys=False) | indent(2,False) }}
+  {% if prometheus_alert_relabel_configs | length > 0 %}
+  alert_relabel_configs:
+  {{ prometheus_alert_relabel_configs | to_nice_yaml(indent=2,sort_keys=False) | indent(2,False) }}
+  {% endif %}
+{% endif %}
+
+scrape_configs:
+  {{ prometheus_scrape_configs | to_nice_yaml(indent=2,sort_keys=False) | indent(2,False) }}

+ 50 - 0
dev/provisioning/ansible/roles/redis/defaults/main.yml

@@ -0,0 +1,50 @@
+---
+redis_port: 6379
+redis_bind_interface: "0.0.0.0" # overload from role
+redis_unixsocket: ''
+redis_timeout: 300
+
+redis_loglevel: "notice"
+redis_logfile: /var/log/redis/redis-server.log
+
+redis_databases: 16
+
+# Set to an empty set to disable persistence (saving the DB to disk).
+redis_save:
+  - 900 1
+  - 300 10
+  - 60 10000
+
+redis_rdbcompression: "yes"
+redis_dbfilename: dump.rdb
+redis_dbdir: /var/lib/redis
+
+redis_maxmemory: 0
+redis_maxmemory_policy: "noeviction"
+redis_maxmemory_samples: 5
+
+redis_appendonly: "no"
+redis_appendfsync: "everysec"
+
+# Add extra include files for local configuration/overrides.
+redis_includes: []
+
+# Require authentication to Redis with a password.
+redis_requirepass: ""
+
+# Disable certain Redis commands for security reasons.
+redis_disabled_commands: []
+#  - FLUSHDB
+#  - FLUSHALL
+#  - KEYS
+#  - PEXPIRE
+#  - DEL
+#  - CONFIG
+#  - SHUTDOWN
+#  - BGREWRITEAOF
+#  - BGSAVE
+#  - SAVE
+#  - SPOP
+#  - SREM
+#  - RENAME
+#  - DEBUG

+ 11 - 0
dev/provisioning/ansible/roles/redis/handlers/main.yml

@@ -0,0 +1,11 @@
+---
+
+- name: start redis
+  ansible.builtin.service:
+    name: "{{ redis_daemon }}"
+    state: started
+
+- name: restart redis
+  ansible.builtin.service:
+    name: "{{ redis_daemon }}"
+    state: restarted

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini