2026-03-18 13:47:39 +01:00

2328 lines
62 KiB
HTML

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="prev" href="../stage/2026-03-09/">
<link rel="next" href="../2026-01-23/">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="zensical-0.0.21">
<title>Alternavive GLSI léger : Grabber - Les incroyables notes de devops</title>
<link rel="stylesheet" href="../../assets/stylesheets/modern/main.f28b7ce3.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/modern/palette.dfe2e883.min.css">
<style>:root{--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M384%20512H96c-53%200-96-43-96-96V96C0%2043%2043%200%2096%200h304c26.5%200%2048%2021.5%2048%2048v288c0%2020.9-13.4%2038.7-32%2045.3V448c17.7%200%2032%2014.3%2032%2032s-14.3%2032-32%2032zM96%20384c-17.7%200-32%2014.3-32%2032s14.3%2032%2032%2032h256v-64zm32-232c0%2013.3%2010.7%2024%2024%2024h176c13.3%200%2024-10.7%2024-24s-10.7-24-24-24H152c-13.3%200-24%2010.7-24%2024m24%2072c-13.3%200-24%2010.7-24%2024s10.7%2024%2024%2024h176c13.3%200%2024-10.7%2024-24s-10.7-24-24-24z%22/%3E%3C/svg%3E');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20640%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M352%200c0-17.7-14.3-32-32-32s-32%2014.3-32%2032v64h-96c-53%200-96%2043-96%2096v224c0%2053%2043%2096%2096%2096h256c53%200%2096-43%2096-96V160c0-53-43-96-96-96h-96zM160%20368c0-13.3%2010.7-24%2024-24h32c13.3%200%2024%2010.7%2024%2024s-10.7%2024-24%2024h-32c-13.3%200-24-10.7-24-24m120%200c0-13.3%2010.7-24%2024-24h32c13.3%200%2024%2010.7%2024%2024s-10.7%2024-24%2024h-32c-13.3%200-24-10.7-24-24m120%200c0-13.3%2010.7-24%2024-24h32c13.3%200%2024%2010.7%2024%2024s-10.7%2024-24%2024h-32c-13.3%200-24-10.7-24-24M224%20176a48%2048%200%201%201%200%2096%2048%2048%200%201%201%200-96m144%2048a48%2048%200%201%201%2096%200%2048%2048%200%201%201-96%200m-304%200c0-17.7-14.3-32-32-32S0%20206.3%200%20224v96c0%2017.7%2014.3%2032%2032%2032s32-14.3%2032-32zm544-32c-17.7%200-32%2014.3-32%2032v96c0%2017.7%2014.3%2032%2032%2032s32-14.3%2032-32v-96c0-17.7-14.3-32-32-32%22/%3E%3C/svg%3E');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M416%20427.4c58.5-44%2096-111.6%2096-187.4C512%20107.5%20397.4%200%20256%200S0%20107.5%200%20240c0%2075.8%2037.5%20143.4%2096%20187.4V464c0%2026.5%2021.5%2048%2048%2048h32v-40c0-13.3%2010.7-24%2024-24s24%2010.7%2024%2024v40h64v-40c0-13.3%2010.7-24%2024-24s24%2010.7%2024%2024v40h32c26.5%200%2048-21.5%2048-48zM96%20256a64%2064%200%201%201%20128%200%2064%2064%200%201%201-128%200m256-64a64%2064%200%201%201%200%20128%2064%2064%200%201%201%200-128%22/%3E%3C/svg%3E');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M288%200H128c-17.7%200-32%2014.3-32%2032s14.3%2032%2032%2032v151.5L7.5%20426.3C2.6%20435%200%20444.7%200%20454.7%200%20486.4%2025.6%20512%2057.3%20512h333.4c31.6%200%2057.3-25.6%2057.3-57.3%200-10-2.6-19.8-7.5-28.4L320%20215.5V64c17.7%200%2032-14.3%2032-32S337.7%200%20320%200zm-96%20215.5V64h64v151.5c0%2011.1%202.9%2022.1%208.4%2031.8L306%20320H142l41.6-72.7c5.5-9.7%208.4-20.6%208.4-31.8%22/%3E%3C/svg%3E');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20576%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M480-16c6.9%200%2013%204.4%2015.2%2010.9l13.5%2040.4%2040.4%2013.5C555.6%2051%20560%2057.1%20560%2064s-4.4%2013-10.9%2015.2l-40.4%2013.5-13.5%2040.4c-2.2%206.5-8.3%2010.9-15.2%2010.9s-13-4.4-15.2-10.9l-13.5-40.4-40.4-13.5C404.4%2077%20400%2070.9%20400%2064s4.4-13%2010.9-15.2l40.4-13.5%2013.5-40.4C467-11.6%20473.1-16%20480-16M321.4%2097.4c12.5-12.5%2032.8-12.5%2045.3%200l80%2080c12.5%2012.5%2012.5%2032.8%200%2045.3l-10.9%2010.9c7.9%2022%2012.2%2045.7%2012.2%2070.5%200%20114.9-93.1%20208-208%20208S32%20418.9%2032%20304%20125.1%2096%20240%2096c24.7%200%2048.5%204.3%2070.5%2012.3zM144%20304c0-53%2043-96%2096-96%2013.3%200%2024-10.7%2024-24s-10.7-24-24-24c-79.5%200-144%2064.5-144%20144%200%2013.3%2010.7%2024%2024%2024s24-10.7%2024-24%22/%3E%3C/svg%3E');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M256%20512a256%20256%200%201%200%200-512%20256%20256%200%201%200%200%20512m-32-352a32%2032%200%201%201%2064%200%2032%2032%200%201%201-64%200m-8%2064h48c13.3%200%2024%2010.7%2024%2024v88h8c13.3%200%2024%2010.7%2024%2024s-10.7%2024-24%2024h-80c-13.3%200-24-10.7-24-24s10.7-24%2024-24h24v-64h-24c-13.3%200-24-10.7-24-24s10.7-24%2024-24%22/%3E%3C/svg%3E');--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M64%20480c-35.3%200-64-28.7-64-64V96c0-35.3%2028.7-64%2064-64h320c35.3%200%2064%2028.7%2064%2064v213.5c0%2017-6.7%2033.3-18.7%2045.3L322.7%20461.3c-12%2012-28.3%2018.7-45.3%2018.7zm325.5-176H296c-13.3%200-24%2010.7-24%2024v93.5z%22/%3E%3C/svg%3E');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M256%20512a256%20256%200%201%200%200-512%20256%20256%200%201%200%200%20512m0-336c-17.7%200-32%2014.3-32%2032%200%2013.3-10.7%2024-24%2024s-24-10.7-24-24c0-44.2%2035.8-80%2080-80s80%2035.8%2080%2080c0%2047.2-36%2067.2-56%2074.5v3.8c0%2013.3-10.7%2024-24%2024s-24-10.7-24-24v-8.1c0-20.5%2014.8-35.2%2030.1-40.2%206.4-2.1%2013.2-5.5%2018.2-10.3%204.3-4.2%207.7-10%207.7-19.6%200-17.7-14.3-32-32-32zm-32%20192a32%2032%200%201%201%2064%200%2032%2032%200%201%201-64%200%22/%3E%3C/svg%3E');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M0%20216C0%20149.7%2053.7%2096%20120%2096h8c17.7%200%2032%2014.3%2032%2032s-14.3%2032-32%2032h-8c-30.9%200-56%2025.1-56%2056v8h64c35.3%200%2064%2028.7%2064%2064v64c0%2035.3-28.7%2064-64%2064H64c-35.3%200-64-28.7-64-64zm256%200c0-66.3%2053.7-120%20120-120h8c17.7%200%2032%2014.3%2032%2032s-14.3%2032-32%2032h-8c-30.9%200-56%2025.1-56%2056v8h64c35.3%200%2064%2028.7%2064%2064v64c0%2035.3-28.7%2064-64%2064h-64c-35.3%200-64-28.7-64-64z%22/%3E%3C/svg%3E');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M434.8%2070.1c14.3%2010.4%2017.5%2030.4%207.1%2044.7l-256%20352c-5.5%207.6-14%2012.3-23.4%2013.1s-18.5-2.7-25.1-9.3l-128-128c-12.5-12.5-12.5-32.8%200-45.3s32.8-12.5%2045.3%200l101.5%20101.5%20234-321.7c10.4-14.3%2030.4-17.5%2044.7-7.1z%22/%3E%3C/svg%3E');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M461.2%2018.9C472.7%2024%20480%2035.4%20480%2048v416c0%2012.6-7.3%2024-18.8%2029.1s-24.8%203.2-34.3-5.1l-46.6-40.7c-43.6-38.1-98.7-60.3-156.4-63V480c0%2017.7-14.3%2032-32%2032h-32c-17.7%200-32-14.3-32-32v-96C57.3%20384%200%20326.7%200%20256s57.3-128%20128-128h84.5c61.8-.2%20121.4-22.7%20167.9-63.3L427%2024c9.4-8.3%2022.9-10.2%2034.3-5.1zM224%20320v.2c70.3%202.7%20137.8%2028.5%20192%2073.4V118.3c-54.2%2044.9-121.7%2070.7-192%2073.4z%22/%3E%3C/svg%3E');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M256%200c14.7%200%2028.2%208.1%2035.2%2021l216%20400c6.7%2012.4%206.4%2027.4-.8%2039.5S486.1%20480%20472%20480H40c-14.1%200-27.2-7.4-34.4-19.5s-7.5-27.1-.8-39.5l216-400c7-12.9%2020.5-21%2035.2-21m0%20352a32%2032%200%201%200%200%2064%2032%2032%200%201%200%200-64m0-192c-18.2%200-32.7%2015.5-31.4%2033.7l7.4%20104c.9%2012.5%2011.4%2022.3%2023.9%2022.3%2012.6%200%2023-9.7%2023.9-22.3l7.4-104c1.3-18.2-13.1-33.7-31.4-33.7z%22/%3E%3C/svg%3E');}</style>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="../../stylesheets/index.css">
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,t)=>(e<<5)-e+t.charCodeAt(0)),0),__md_get=(e,t=localStorage,a=__md_scope)=>JSON.parse(t.getItem(a.pathname+"."+e)),__md_set=(e,t,a=localStorage,_=__md_scope)=>{try{a.setItem(_.pathname+"."+e,JSON.stringify(t))}catch(e){}},document.documentElement.setAttribute("data-platform",navigator.platform)</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#alternavive-glsi-leger-grabber" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="Les incroyables notes de devops" class="md-header__button md-logo" aria-label="Les incroyables notes de devops" data-md-component="logo">
<img src="../../assets/logo.svg" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-menu" viewBox="0 0 24 24"><path d="M4 5h16M4 12h16M4 19h16"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Les incroyables notes de devops
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Alternavive GLSI léger : Grabber
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme)" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-sun-moon" viewBox="0 0 24 24"><path d="M12 2v2M14.837 16.385a6 6 0 1 1-7.223-7.222c.624-.147.97.66.715 1.248a4 4 0 0 0 5.26 5.259c.589-.255 1.396.09 1.248.715M16 12a4 4 0 0 0-4-4M19 5l-1.256 1.256M20 12h2"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="pink" data-md-color-accent="deep-purple" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="pink" data-md-color-accent="purple" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_2">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-moon" viewBox="0 0 24 24"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-search" viewBox="0 0 24 24"><path d="m21 21-4.34-4.34"/><circle cx="11" cy="11" r="8"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog" aria-label="Search">
<button type="button" class="md-search__button">
Search
</button>
</div>
<div class="md-header__source">
<a href="https://github.com/buchtioof/notes" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path fill="currentColor" d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
buchtioof/notes
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="Les incroyables notes de devops" class="md-nav__button md-logo" aria-label="Les incroyables notes de devops" data-md-component="logo">
<img src="../../assets/logo.svg" alt="logo">
</a>
Les incroyables notes de devops
</label>
<div class="md-nav__source">
<a href="https://github.com/buchtioof/notes" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path fill="currentColor" d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
buchtioof/notes
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
<span class="md-ellipsis">
Accueil
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
<span class="md-ellipsis">
Notes
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Notes
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1" >
<label class="md-nav__link" for="__nav_2_1" id="__nav_2_1_label" tabindex="0">
<span class="md-ellipsis">
🧰 SysAdmin
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_1">
<span class="md-nav__icon md-icon"></span>
🧰 SysAdmin
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../learn/sysadmin/2026-03-04/" class="md-nav__link">
<span class="md-ellipsis">
C'est quoi un Administrateur Système ?
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1_2" >
<label class="md-nav__link" for="__nav_2_1_2" id="__nav_2_1_2_label" tabindex="0">
<span class="md-ellipsis">
🐧 Linux
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_1_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_1_2">
<span class="md-nav__icon md-icon"></span>
🐧 Linux
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../learn/sysadmin/linux/2025-10-30/" class="md-nav__link">
<span class="md-ellipsis">
C'est quoi Linux ?
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/sysadmin/linux/2025-10-31/" class="md-nav__link">
<span class="md-ellipsis">
Arborescence type sur UNIX
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1_3" >
<label class="md-nav__link" for="__nav_2_1_3" id="__nav_2_1_3_label" tabindex="0">
<span class="md-ellipsis">
📚 Bases du Bash
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_1_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_1_3">
<span class="md-nav__icon md-icon"></span>
📚 Bases du Bash
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../learn/sysadmin/bash/2025-11-27/" class="md-nav__link">
<span class="md-ellipsis">
Commandes *sh pour les idiots
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/sysadmin/bash/2025-11-28/" class="md-nav__link">
<span class="md-ellipsis">
Commandes *sh avancées
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../learn/sysadmin/2026-02-25/" class="md-nav__link">
<span class="md-ellipsis">
SSH et Configuration propre
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_2" >
<label class="md-nav__link" for="__nav_2_2" id="__nav_2_2_label" tabindex="0">
<span class="md-ellipsis">
🔌 DevOps
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_2">
<span class="md-nav__icon md-icon"></span>
🔌 DevOps
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../learn/devops/2026-03-04/" class="md-nav__link">
<span class="md-ellipsis">
C'est quoi DevOps ?
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/devops/2025-11-28/" class="md-nav__link">
<span class="md-ellipsis">
Automatisation via les associations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/devops/2025-12-12/" class="md-nav__link">
<span class="md-ellipsis">
Git pour les neuilles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/devops/2026-01-22/" class="md-nav__link">
<span class="md-ellipsis">
SQL pour les tung tung tung sahur
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/devops/2026-03-18/" class="md-nav__link">
<span class="md-ellipsis">
Automatiser avec Ansible
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_3" >
<label class="md-nav__link" for="__nav_2_3" id="__nav_2_3_label" tabindex="0">
<span class="md-ellipsis">
☕ Javascript
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_3">
<span class="md-nav__icon md-icon"></span>
☕ Javascript
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../learn/javascript/2026-01-30/" class="md-nav__link">
<span class="md-ellipsis">
Javascript (30/01/26)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/javascript/2026-02-06/" class="md-nav__link">
<span class="md-ellipsis">
Asynchrone et promesses (06/02/26)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/javascript/2026-02-09/" class="md-nav__link">
<span class="md-ellipsis">
fetch des APIs et serveur HTTP (09/02/26)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_4" >
<label class="md-nav__link" for="__nav_2_4" id="__nav_2_4_label" tabindex="0">
<span class="md-ellipsis">
🐍 Python
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_4">
<span class="md-nav__icon md-icon"></span>
🐍 Python
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../learn/python/2026-01-16/" class="md-nav__link">
<span class="md-ellipsis">
pip et environnements virtuels
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../learn/python/2026-02-16/" class="md-nav__link">
<span class="md-ellipsis">
Django en gros
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_5" >
<label class="md-nav__link" for="__nav_2_5" id="__nav_2_5_label" tabindex="0">
<span class="md-ellipsis">
🎨 Frontend
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_5">
<span class="md-nav__icon md-icon"></span>
🎨 Frontend
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../learn/frontend/2026-02-21/" class="md-nav__link">
<span class="md-ellipsis">
Cheat Sheet Tailwind
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" checked>
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
<span class="md-ellipsis">
Projets
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Projets
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_1" >
<label class="md-nav__link" for="__nav_3_1" id="__nav_3_1_label" tabindex="0">
<span class="md-ellipsis">
Stage
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_1">
<span class="md-nav__icon md-icon"></span>
Stage
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../stage/2026-03-03/" class="md-nav__link">
<span class="md-ellipsis">
Étape 1 - Planification et installation Hardware
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../stage/2026-03-09/" class="md-nav__link">
<span class="md-ellipsis">
Étape 2 : Configuration de l'Infrastructure Serveur
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Alternavive GLSI léger : Grabber
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Alternavive GLSI léger : Grabber
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#introduction-au-projet" class="md-nav__link">
<span class="md-ellipsis">
Introduction au projet
</span>
</a>
<nav class="md-nav" aria-label="Introduction au projet">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#besoin" class="md-nav__link">
<span class="md-ellipsis">
Besoin
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solution" class="md-nav__link">
<span class="md-ellipsis">
Solution
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#choix-de-la-stack-technologique" class="md-nav__link">
<span class="md-ellipsis">
Choix de la stack technologique
</span>
</a>
<nav class="md-nav" aria-label="Choix de la stack technologique">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#-bash" class="md-nav__link">
<span class="md-ellipsis">
-&gt; Bash
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#-python-django-gunicorn-whitenoise" class="md-nav__link">
<span class="md-ellipsis">
-&gt; Python (Django + Gunicorn + Whitenoise)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#-sqlite" class="md-nav__link">
<span class="md-ellipsis">
-&gt; SQLite
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#architecture-technique" class="md-nav__link">
<span class="md-ellipsis">
Architecture technique
</span>
</a>
<nav class="md-nav" aria-label="Architecture technique">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#chef-du-service-grabbersh" class="md-nav__link">
<span class="md-ellipsis">
Chef du service : grabber.sh
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#lagent-de-collecte-alfredrun" class="md-nav__link">
<span class="md-ellipsis">
L'agent de collecte : alfred.run
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#cerveau-serveur-api-via-django" class="md-nav__link">
<span class="md-ellipsis">
Cerveau serveur : API via Django
</span>
</a>
<nav class="md-nav" aria-label="Cerveau serveur : API via Django">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#deploiement-dalfred" class="md-nav__link">
<span class="md-ellipsis">
Déploiement d'Alfred
</span>
</a>
<nav class="md-nav" aria-label="Déploiement d&#x27;Alfred">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#requete-avec-paramiko" class="md-nav__link">
<span class="md-ellipsis">
Requête avec Paramiko
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#protection-de-lapi-avec-un-token-dauthentification-session_token" class="md-nav__link">
<span class="md-ellipsis">
Protection de l'API avec un Token d'Authentification (SESSION_TOKEN)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#panel-admin" class="md-nav__link">
<span class="md-ellipsis">
Panel Admin
</span>
</a>
<nav class="md-nav" aria-label="Panel Admin">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#gestion-des-employes" class="md-nav__link">
<span class="md-ellipsis">
Gestion des "employés"
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#gestion-des-sessions" class="md-nav__link">
<span class="md-ellipsis">
Gestion des sessions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#design" class="md-nav__link">
<span class="md-ellipsis">
Design
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#vue-densemble-du-projet-et-conclusions-projet-a-finir-avant" class="md-nav__link">
<span class="md-ellipsis">
Vue d'ensemble du projet et Conclusions (Projet à finir avant)
</span>
</a>
<nav class="md-nav" aria-label="Vue d&#x27;ensemble du projet et Conclusions (Projet à finir avant)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#difficultes-rencontrees-et-apprentissages" class="md-nav__link">
<span class="md-ellipsis">
Difficultés rencontrées et apprentissages
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#bilan" class="md-nav__link">
<span class="md-ellipsis">
Bilan
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#axes-damelioration" class="md-nav__link">
<span class="md-ellipsis">
Axes d'amélioration
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../2026-01-23/" class="md-nav__link">
<span class="md-ellipsis">
Docs et notes avec Zensical
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../2026-02-13/" class="md-nav__link">
<span class="md-ellipsis">
Faire un portfolio en JS moderne
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#introduction-au-projet" class="md-nav__link">
<span class="md-ellipsis">
Introduction au projet
</span>
</a>
<nav class="md-nav" aria-label="Introduction au projet">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#besoin" class="md-nav__link">
<span class="md-ellipsis">
Besoin
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solution" class="md-nav__link">
<span class="md-ellipsis">
Solution
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#choix-de-la-stack-technologique" class="md-nav__link">
<span class="md-ellipsis">
Choix de la stack technologique
</span>
</a>
<nav class="md-nav" aria-label="Choix de la stack technologique">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#-bash" class="md-nav__link">
<span class="md-ellipsis">
-&gt; Bash
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#-python-django-gunicorn-whitenoise" class="md-nav__link">
<span class="md-ellipsis">
-&gt; Python (Django + Gunicorn + Whitenoise)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#-sqlite" class="md-nav__link">
<span class="md-ellipsis">
-&gt; SQLite
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#architecture-technique" class="md-nav__link">
<span class="md-ellipsis">
Architecture technique
</span>
</a>
<nav class="md-nav" aria-label="Architecture technique">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#chef-du-service-grabbersh" class="md-nav__link">
<span class="md-ellipsis">
Chef du service : grabber.sh
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#lagent-de-collecte-alfredrun" class="md-nav__link">
<span class="md-ellipsis">
L'agent de collecte : alfred.run
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#cerveau-serveur-api-via-django" class="md-nav__link">
<span class="md-ellipsis">
Cerveau serveur : API via Django
</span>
</a>
<nav class="md-nav" aria-label="Cerveau serveur : API via Django">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#deploiement-dalfred" class="md-nav__link">
<span class="md-ellipsis">
Déploiement d'Alfred
</span>
</a>
<nav class="md-nav" aria-label="Déploiement d&#x27;Alfred">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#requete-avec-paramiko" class="md-nav__link">
<span class="md-ellipsis">
Requête avec Paramiko
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#protection-de-lapi-avec-un-token-dauthentification-session_token" class="md-nav__link">
<span class="md-ellipsis">
Protection de l'API avec un Token d'Authentification (SESSION_TOKEN)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#panel-admin" class="md-nav__link">
<span class="md-ellipsis">
Panel Admin
</span>
</a>
<nav class="md-nav" aria-label="Panel Admin">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#gestion-des-employes" class="md-nav__link">
<span class="md-ellipsis">
Gestion des "employés"
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#gestion-des-sessions" class="md-nav__link">
<span class="md-ellipsis">
Gestion des sessions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#design" class="md-nav__link">
<span class="md-ellipsis">
Design
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#vue-densemble-du-projet-et-conclusions-projet-a-finir-avant" class="md-nav__link">
<span class="md-ellipsis">
Vue d'ensemble du projet et Conclusions (Projet à finir avant)
</span>
</a>
<nav class="md-nav" aria-label="Vue d&#x27;ensemble du projet et Conclusions (Projet à finir avant)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#difficultes-rencontrees-et-apprentissages" class="md-nav__link">
<span class="md-ellipsis">
Difficultés rencontrées et apprentissages
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#bilan" class="md-nav__link">
<span class="md-ellipsis">
Bilan
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#axes-damelioration" class="md-nav__link">
<span class="md-ellipsis">
Axes d'amélioration
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<p><img src="https://github.com/buchtioof/portfolio/blob/main/public/img/assets/projects/grabber.png?raw=true"></p>
<h1 id="alternavive-glsi-leger-grabber">Alternavive GLSI léger : Grabber</h1>
<h2 id="introduction-au-projet">Introduction au projet</h2>
<h3 id="besoin">Besoin</h3>
<p>Grabber part d'un besoin de gérer un petit parc informatique (dizaines d'ordinateurs) dans un espace de travail (type entreprise). On peut déja noter certains besoins majeurs : <strong>gérer des ordinateurs à distance</strong>, <strong>connaitre d'un coup d'oeil leur état</strong> (updates, hardware, software) et <strong>établir une liste de liens entre ordinateurs et employés</strong>.</p>
<h3 id="solution">Solution</h3>
<p>Grabber donc serait dans l'idée capable de répondre à ces besoins, via une interface web administrateur consultable par la DSI d'une entreprise par exemple. Pour la gestion d'un parc informatique de petite taille/toute petite, on proposera un produit simple, léger et plug and play. Via une simple commande de terminal et une configuration au préalable des ordinateurs cibles capable de recevoir des requêtes SSH, Grabber sera capable de couvrir un maximum des besoins.</p>
<h2 id="choix-de-la-stack-technologique">Choix de la stack technologique</h2>
<p>Le projet en général se basera sur du Bash et du Python pour gérer l'API et le panel Admin.</p>
<h3 id="-bash">-&gt; <em>Bash</em></h3>
<p>Les scripts Bash se contenteront de "fetch" les données système <em>(via des commandes comme lscpu ou la librairie inxi)</em>. Ils auront aussi le rôle d'empaqueter ces données en format JSON <em>(via jq)</em> à un serveur qui les enregistrera dans une BDD. Et enfin, ils seront un peu l'agent qui contrôle la machine via des contrôles du systeme (vérif. admin, réglages du serveur, lanceur du serveur...)</p>
<h3 id="-python-django-gunicorn-whitenoise">-&gt; <em>Python (Django + Gunicorn + Whitenoise)</em></h3>
<p>Django s'occupera de traiter les données brutes du script Bash et les enregistrer dans une BDD. De plus, il s'occupera de la logique du panel Admin via ses outil préfabriqués. Pour servir notre app Django en production, on utilise la dépendance Gunicorn qui pourra gérer le multi-tâches via des "Workers" et tenir les standards d'une webapp classique. Gunicorn sera accompagné de Whitenoise, un outil en plus qui gèrera les fichiers statiques (CSS/JS) que ne gère pas nativement Gunicorn.</p>
<h3 id="-sqlite">-&gt; <em>SQLite</em></h3>
<p>Pour le moment, SQLite est le meilleur choix pour sa simplicité et sa taille minimale, elle est stockée en local, ne nécessite pas plus de préparations spécifiques car déjà prête à l'emploi avec Django.</p>
<h2 id="architecture-technique">Architecture technique</h2>
<h3 id="chef-du-service-grabbersh">Chef du service : <em>grabber.sh</em></h3>
<p>Ce script aura un rôle majeur dans le projet, il sera le chef d'orchestre du service et se chargera de gérer le panel admin et le serveur Django ainsi que l'environnement Python et d'être le centre des commandes en sécurisant le service avec un token dynamique</p>
<p><strong>Entre autre, il devra :</strong></p>
<p>-&gt; Initialiser l'environnement virtuel Python (nommé gbvenv)</p>
<p>-&gt; Gérer les dépendances requises (fonction requirements qui vérifie si l'hôte a bien les requis tels que jq, sqlite3 et python) </p>
<p>-&gt; Génère si besoin les clés SSH nécessaires pour sécuriser la connexion de l'API</p>
<p>-&gt; Vérifier la présence d'un compte super-user dans Django (important pour se logger au panel Admin, via le lancement d'un script Python "lib/check_admin.py")</p>
<p>-&gt; Collecte les fichiers statiques depuis un dossier "static" afin de préparer le CSS pour Whitenoise</p>
<p>-&gt; Automatiser le processus de "migrations" (python manage.py migrate)</p>
<p>-&gt; Créer un token de session qui sécurisera les communications entre Django &lt;-&gt; Grabber &lt;-&gt; Alfred</p>
<h3 id="lagent-de-collecte-alfredrun">L'agent de collecte : <em>alfred.run</em></h3>
<div class="admonition info">
<p class="admonition-title">Info</p>
<p><em>Au départ une fonction inclue dans grabber.sh, il a finalement été décidé de séparer les deux pour plus de lisibilité et de facilité sur la suite pour être executé en autonomie dans une machine cible.</em></p>
</div>
<p>Son rôle est de fetch les données de la cible dont on a besoin pour répondre au besoin, données Hardware et Software. Toujours en Bash pour sa facilité d'utilisation dans des tâches d'extraction de données de l'OS. </p>
<p><strong>En résumé, il devra donc :</strong></p>
<p>-&gt; Récupérer les données système (avec des outils natifs comme les netutils ou bien la librairie externe inxi)</p>
<p>-&gt; Empaqueter ces données en un objet JSON (avec jq)</p>
<p>-&gt; Envoyer les données via une requête à l'endpoint du serveur Django (avec une requête HTTP POST curl)</p>
<p>-&gt; Renvoyer le token de session pour sécuriser la communication</p>
<p>-&gt; Le tout est codé dans un paquet .run qui contient les librairies requises comme jq et inxi pour être utilisable sur un maximum d'ordinateurs Linux (compilé avec makeself)</p>
<h3 id="cerveau-serveur-api-via-django">Cerveau serveur : API via Django</h3>
<h4 id="deploiement-dalfred">Déploiement d'Alfred</h4>
<p>Pour déployer Alfred sur une machine, on utilisera SSH pour envoyer le script dans un PC cible. On veut que cette tâche soit lancée directement depuis le panel Admin.</p>
<p>Pour se faire, on délègue celle-ci à Python avec Django qui l'effectuera avec un formulaire qui contient l'IP sur laquelle aller, le username et le mot de passe du SSH cible.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Puisque l'IP envoyée à la machine cible est récupérée via <strong>request.get_host()</strong>, l'administrateur doit impérativement accéder au panel Admin de Grabber via l'adresse IP réseau de la machine (ex: 192.168.x.x:8000) et non via localhost:8000. Sinon, le PC cible tentera d'envoyer ses données à son propre localhost et la base de données restera vide. </p>
</div>
<h5 id="requete-avec-paramiko">Requête avec Paramiko</h5>
<p>C'est la solution trouvée pour gérer cette demande, Paramiko est une librairie Python installable avec pip qui peut établir la session SSH et le fera depuis le backend Django (dans actions.py -&gt; fonction deploy_ssh)</p>
<p>Le cycle de la requête est le suivant :</p>
<pre><code>-&gt; Connexion SSH à la cible.
(Via la clé SSH d'abord, puis si refus, via les identifiants donnés par l'utilisateur)
-&gt; Si l'authentification via la clé n'a pas fonctionné,
on envoie notre clé SSH hôte sur la machine distante
-&gt; Transfert SFTP de l'exécutable alfred.run vers le répertoire temporaire /tmp/.
-&gt; Exécution distante en injectant l'IP du serveur (request.get_host()) et
le Token de session.
-&gt; Nettoyage des traces (rm /tmp/alfred.run).
</code></pre>
<h4 id="protection-de-lapi-avec-un-token-dauthentification-session_token">Protection de l'API avec un Token d'Authentification (SESSION_TOKEN)</h4>
<div class="admonition info">
<p class="admonition-title">Info</p>
<p>Ne faut pas confondre ce token destiné aux communications inter-machines avec les sessions administrateurs du panel web, qui sont elles gérées directement par la base de données SQLite.</p>
</div>
<p>Comme dit plus tôt, <code>grabber.sh</code> génère un token unique (faisant office de clé d'API) avec la commande <code>openssl rand</code> à chaque lancement du serveur. Ce token est temporairement stocké dans <code>settings.json</code> et est automatiquement réinitialisé à la fermeture du script (via la commande <code>trap</code> qui lance la fonction <code>cleanup</code>).</p>
<p>Du côté serveur, lors du démarrage de l'application par Gunicorn, le fichier <code>config/settings.py</code> se charge de lire <code>settings.json</code> et de charger cette clé en mémoire dans la variable globale <code>SESSION_TOKEN</code>.</p>
<p>Enfin, lorsqu'une requête est émise par <strong>Alfred</strong>, Django intercepte et vérifie cette clé via la vue dédiée dans <code>web/api.py</code>. Il extrait la clé envoyée de manière sécurisée dans les en-têtes HTTP de la requête <code>curl</code> (précisément le header <code>HTTP_X_API_KEY</code>) et la compare avec celle en mémoire. Si les clés correspondent, les données matérielles sont traitées, sinon, la connexion est immédiatement rejetée avec une erreur 401 (Accès refusé).</p>
<h4 id="panel-admin">Panel Admin</h4>
<p>Il est une partie de l'app Django et présente dans une interface HTML/CSS/JS, une liste des ordinateurs enregistrés, la table SystemInfo avec l'adresse MAC comme clé principale pour chaque PC. Le tout est sécurisé avec le login admin de Django.</p>
<h5 id="gestion-des-employes">Gestion des "employés"</h5>
<p>Via un petit modal, il est possible d'administrer en plus des ordinateurs, une BDD d'employés (stockée dans la même BDD SQLite) et d'y effectuer des tâches basiques comme créer un employé, le supprimer, l'éditer et l'assigner à un ordinateur depuis la page d'un PC.</p>
<h5 id="gestion-des-sessions">Gestion des sessions</h5>
<p>Pour gérer les sessions sur le Panel et éviter que les administrateurs soient déconnectés en naviguant (problème lié à la séparation des mémoires des différents workers de Gunicorn), le système de session de Django a été configuré pour être stocké directement dans la base de données SQLite (SESSION_ENGINE = "django.contrib.sessions.backends.db").</p>
<h5 id="design">Design</h5>
<p>Le CSS et le design utilisent la librairie Tailwind en mode CLI. Concrètement, on télécharge la librairie en local pour travailler avec, on la lance via une commande qui surveille "watch" les modifications, puis lorsque l'on a fini, on empaquete notre CSS avec le strict necessaire "minify". <a href="https://tailwindcss.com/docs/installation/tailwind-cli">En savoir plus</a></p>
<h2 id="vue-densemble-du-projet-et-conclusions-projet-a-finir-avant">Vue d'ensemble du projet et Conclusions (Projet à finir avant)</h2>
<h3 id="difficultes-rencontrees-et-apprentissages">Difficultés rencontrées et apprentissages</h3>
<h3 id="bilan">Bilan</h3>
<h3 id="axes-damelioration">Axes d'amélioration</h3>
<nav class="md-tags" >
<span class="md-tag">Projets</span>
<span class="md-tag">Bash</span>
<span class="md-tag">Docs</span>
</nav>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://zensical.org/" target="_blank" rel="noopener">
Zensical
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate":null,"base":"../..","features":["navigation.instant"],"search":"../../assets/javascripts/workers/search.e2d2d235.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null}</script>
<script src="../../assets/javascripts/bundle.36a64b72.min.js"></script>
</body>
</html>