ajoute le proxy console Go et le relais WebSocket vers nova-serialproxy
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
30e14b1c54
commit
8742bde807
30 changed files with 1103 additions and 6 deletions
99
proxy-console/main.go
Normal file
99
proxy-console/main.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Proxy console (étape 9 du déploiement Syllabus).
|
||||
//
|
||||
// Laravel demande à Nova l'adresse de la console série d'une VM, la range
|
||||
// dans Redis sous un jeton aléatoire pour 5 minutes, et ne donne que ce
|
||||
// jeton au navigateur. Ce service lit le jeton, ouvre (ou réutilise) la
|
||||
// connexion WebSocket vers nova-serialproxy, et recopie les octets dans les
|
||||
// deux sens — en lecture seule pour les abonnés qui n'ont pas le droit
|
||||
// d'écrire (voir hub.go).
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// Doit correspondre exactement à ce que Laravel écrit dans Redis
|
||||
// (App\Services\OpenStack\JetonConsole).
|
||||
type jetonConsole struct {
|
||||
URL string `json:"url"`
|
||||
InstanceID string `json:"instance_id"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
var rdb *redis.Client
|
||||
|
||||
func main() {
|
||||
adresseEcoute := env("PROXY_CONSOLE_ECOUTE", "127.0.0.1:8081")
|
||||
adresseRedis := env("PROXY_CONSOLE_REDIS", "127.0.0.1:6380")
|
||||
motDePasseRedis := os.Getenv("PROXY_CONSOLE_REDIS_MOT_DE_PASSE")
|
||||
|
||||
rdb = redis.NewClient(&redis.Options{
|
||||
Addr: adresseRedis,
|
||||
Password: motDePasseRedis,
|
||||
})
|
||||
|
||||
http.HandleFunc("/console/", gererConsole)
|
||||
http.HandleFunc("/sante", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
log.Printf("proxy-console à l'écoute sur %s (Redis %s)", adresseEcoute, adresseRedis)
|
||||
log.Fatal(http.ListenAndServe(adresseEcoute, nil))
|
||||
}
|
||||
|
||||
func gererConsole(w http.ResponseWriter, r *http.Request) {
|
||||
jeton := r.URL.Path[len("/console/"):]
|
||||
if jeton == "" {
|
||||
http.Error(w, "jeton manquant", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
valeur, err := rdb.Get(context.Background(), "console:"+jeton).Result()
|
||||
if err == redis.Nil {
|
||||
http.Error(w, "jeton inconnu ou expiré", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("erreur Redis pour le jeton %s : %v", jeton, err)
|
||||
http.Error(w, "erreur serveur", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var jc jetonConsole
|
||||
if err := json.Unmarshal([]byte(valeur), &jc); err != nil {
|
||||
http.Error(w, "jeton corrompu", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Printf("échec de l'upgrade WebSocket : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
hub, err := obtenirHub(jc.InstanceID, jc.URL)
|
||||
if err != nil {
|
||||
log.Printf("échec de connexion à nova-serialproxy pour %s : %v", jc.InstanceID, err)
|
||||
_ = conn.WriteMessage(websocket.TextMessage, []byte("\r\nConsole indisponible.\r\n"))
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
client := &Client{conn: conn, role: jc.Role, hub: hub}
|
||||
hub.ajouter(client)
|
||||
client.pompeClient()
|
||||
}
|
||||
|
||||
func env(cle, defaut string) string {
|
||||
if v := os.Getenv(cle); v != "" {
|
||||
return v
|
||||
}
|
||||
return defaut
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue