Génération de configuration pour nginx, historique d'une demande de tirage

Salutations, camarades. Sur mes serveurs de combat, le magnifique nginx tourne depuis 2006 et au cours des années de son administration, j'ai accumulé beaucoup de configurations et de modèles. J'ai beaucoup fait l'éloge de nginx et, d'une manière ou d'une autre, il s'est avéré que même le hub nginx sur Habr m'a également lancé, Ponte \ m /

Des amis m'ont demandé de créer une ferme de développement pour eux, et au lieu de les faire glisser avec mes modèles spécifiques, je me suis souvenu d'un projet intéressant nginxconfig.io , qui disperse les configurations et prépare tout pour le cryptage, etc. J'ai pensé, pourquoi pas? Cependant, j'étais furieux du fait que nginxconfig me propose de télécharger l'archive zip dans le navigateur, ne me permettant pas de la fusionner directement sur le serveur en utilisant wget / fetch / curl. Quel genre de non-sens, pourquoi en ai-je besoin dans le navigateur, j'en ai besoin sur le serveur depuis la console. En colère, je suis monté sur github pour voir les entrailles du projet, ce qui a conduit à sa fourche et, par conséquent, à la demande de traction. A propos de laquelle je n'écrirais pas si ce n'était pas intéressant;)

image

Bien sûr, avant de choisir la source, j'ai regardé d'où le chrome tire l'archive zip générée avec les configurations, et là j'attendais l'adresse commençant par "blob:", oppa. Il est déjà devenu clair que dans le processus le service ne génère rien, en fait que js fait tout cela. En effet, l'archive zip est générée par le client lui-même, navigateur, javascript. C'est-à-dire le charme est que le projet nginxconfig.io peut simplement être enregistré en tant que page html, téléchargé sur un certain narod.ru et cela fonctionnera) C'est une solution très drôle et intéressante, cependant, elle est terriblement gênante pour la configuration de serveurs, en fait, pour de ce pour quoi ce projet a été créé. Téléchargez l'archive générée par le navigateur, puis transférez-la sur le serveur en utilisant nc ... en 2019? Je me suis fixé pour tâche de trouver un moyen de télécharger la configuration résultante directement sur le serveur.

Ayant bifurqué le projet, j'ai commencé à réfléchir aux options dont je disposais. La tâche était compliquée par le fait que je ne voulais pas déroger à la condition que le projet reste un front-end propre, sans back-end. Bien sûr, la solution la plus simple consisterait à extraire nodejs et à lui faire générer une archive avec des configurations via des liens directs.

En fait, il n'y avait pas beaucoup d'options. Plus précisément, un seul est venu à l'esprit. Nous devons configurer les configurations et obtenir un lien que nous pouvons copier sur la console du serveur pour obtenir une archive zip.

Plusieurs fichiers texte dans l'archive zip résultante pesaient un peu, littéralement quelques kilo-octets. La solution évidente était d'obtenir la chaîne base64 à partir de l'archive zip générée et de la jeter dans le tampon, tandis que sur le serveur avec la commande dans la console
echo 'base64string' | base64 --decode > config.zip 
nous pourrions créer ce fichier très zip.

nginxconfig.io a été écrit en AngularJS, je ne peux même pas imaginer quels kilomètres de code seraient nécessaires si l'auteur ne choisissait pas un framework js réactif. Mais j'imagine parfaitement combien il serait plus facile et plus beau d'implémenter tout cela sur VueJS, bien que ce soit déjà un sujet complètement différent.

Dans les ressources du projet, nous voyons une méthode pour générer une archive zip:

 $scope.downloadZip = function() { var zip = new JSZip(); var sourceCodes = $window.document.querySelectorAll('main .file .code.source'); for (var i = 0; i < sourceCodes.length; i++) { var sourceCode = sourceCodes[i]; var name = sourceCode.dataset.filename; var content = sourceCode.children[0].children[0].innerText; if (!$scope.isSymlink() && name.match(/^sites-available\//)) { name = name.replace(/^sites-available\//, 'sites-enabled/'); } zip.file(name, content); if (name.match(/^sites-available\//)) { zip.file(name.replace(/^sites-available\//, 'sites-enabled/'), '../' + name, { unixPermissions: parseInt('120755', 8), }); } } zip.generateAsync({ type: 'blob', platform: 'UNIX', }).then(function(content) { saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip'); }); gtag('event', $scope.getDomains().join(','), { event_category: 'download_zip', }); }; 

tout est assez simple, en utilisant la bibliothèque jszip , un zip est créé où les fichiers de configuration sont placés. Après avoir créé l'archive zip, js la transmet au navigateur à l'aide de la bibliothèque FileSaver.js :

 saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip'); 

où content est l'objet d'archive zip blob résultant.

Ok, tout ce que j'avais à faire était d'ajouter un autre bouton à côté, et quand je clique dessus, n'enregistrez pas l'archive zip résultante dans le navigateur, mais récupérez-y le code base64. Après un peu de chamanisme, j'ai eu 2 méthodes, au lieu d'un téléchargement

 $scope.downloadZip = function() { generateZip(function (content) { saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip'); }); gtag('event', $scope.getDomains().join(','), { event_category: 'download_zip', }); }; $scope.downloadBase64 = function() { generateZip(function (content) { var reader = new FileReader(); reader.readAsDataURL(content); reader.onloadend = function() { var base64 = reader.result.replace(/^data:.+;base64,/, ''); //   base64     zip    base64  } }); gtag('event', $scope.getDomains().join(','), { event_category: 'download_base64', }); }; 

Comme vous pouvez le voir, j'ai mis la génération de l'archive zip dans la méthode privée generateZip, car c'est AngularJS, et l'auteur lui-même adhère aux rappels, ne l'a pas mis en œuvre par des promesses. downloadZip a quand même enregistré saveAs dans la sortie, tandis que downloadBase64 a fait un peu différent. Nous créons un objet FileReader qui nous est parvenu en html5 et est déjà disponible pour utilisation. Qui, en temps voulu, sait comment faire une chaîne base64 à partir d'un blob, plus précisément, il crée une chaîne DataURL, mais ce n'est pas si important pour nous, car DataURL contient exactement ce dont nous avons besoin. Bingo, une petite prise m'attendait quand j'ai essayé de mettre tout ça dans un tampon. L'auteur a utilisé la bibliothèque clipboardjs dans le projet, ce qui permet de travailler avec le presse-papiers sans objets flash, en fonction du texte sélectionné. Au départ, j'ai décidé de mettre ma base64 dans un élément avec display: none;, mais dans ce cas je n'ai pas pu le mettre dans le presse-papier, car aucune sélection n'a lieu. Par conséquent, au lieu d'afficher: aucun; j'ai fait

 position: absolute; z-index: -1; opacity: 0; 

ce qui m'a permis de cacher l'élément à mes yeux et en fait de le laisser sur la page. Voila, la tâche est terminée, lorsque j'ai cliqué sur mon bouton, une ligne du formulaire a été placée dans le buffer:

 echo 'base64string' | base64 --decode > config.zip 

que j'ai simplement inséré dans la console sur le serveur et reçu immédiatement une archive zip avec toutes les configurations.

Eh bien, bien sûr, j'ai lancé la pull request à l'auteur, car le projet est actif et vivant, je veux voir les mises à jour de l'auteur et avoir mon propre bouton) Peu importe, voici ma fourchette du projet et la requête pull elle - même , où vous pouvez voir ce que j'ai corrigé / mis à jour.

Développement Peppy :-)

Source: https://habr.com/ru/post/fr448522/


All Articles