122 lines
3.2 KiB
Go
122 lines
3.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"docker-manager/docker"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
)
|
|
|
|
func ListContainersHandler(w http.ResponseWriter, r *http.Request, client *docker.Client) {
|
|
var containers []map[string]interface{}
|
|
if err := client.GetJSON("/containers/json?all=true", &containers); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if containers == nil {
|
|
w.Write([]byte("[]"))
|
|
} else {
|
|
json.NewEncoder(w).Encode(containers)
|
|
}
|
|
}
|
|
|
|
func StartContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) {
|
|
if resp, err := client.Do("POST", fmt.Sprintf("/containers/%s/start", id), nil); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
} else {
|
|
defer resp.Body.Close()
|
|
w.WriteHeader(resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func StopContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) {
|
|
if resp, err := client.Do("POST", fmt.Sprintf("/containers/%s/stop", id), nil); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
} else {
|
|
defer resp.Body.Close()
|
|
w.WriteHeader(resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func RestartContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) {
|
|
if resp, err := client.Do("POST", fmt.Sprintf("/containers/%s/restart", id), nil); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
} else {
|
|
defer resp.Body.Close()
|
|
w.WriteHeader(resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func RemoveContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) {
|
|
if resp, err := client.Do("DELETE", fmt.Sprintf("/containers/%s?force=true", id), nil); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
} else {
|
|
defer resp.Body.Close()
|
|
w.WriteHeader(resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func GetLogsHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) {
|
|
body, err := client.DoStream("GET", fmt.Sprintf("/containers/%s/logs?stdout=true&stderr=true&tail=200", id), nil)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer body.Close()
|
|
|
|
// Docker logs returns docker stream format, need to parse it
|
|
logs := parseLogs(body)
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]string{"logs": logs})
|
|
}
|
|
|
|
// Docker log stream format: [8 bytes header][payload]
|
|
// Header: [1 byte stream type][3 bytes padding][4 bytes payload length]
|
|
func parseLogs(body io.Reader) string {
|
|
var result string
|
|
buffer := make([]byte, 4096)
|
|
|
|
for {
|
|
n, err := body.Read(buffer)
|
|
if err != nil && err != io.EOF {
|
|
break
|
|
}
|
|
if n == 0 {
|
|
break
|
|
}
|
|
|
|
// Parse docker stream format
|
|
data := buffer[:n]
|
|
for i := 0; i < len(data); {
|
|
if i+8 > len(data) {
|
|
break
|
|
}
|
|
// Skip 8-byte header
|
|
i += 8
|
|
// Read until next header or end
|
|
start := i
|
|
for i < len(data) && i+8 <= len(data) {
|
|
i += 8
|
|
if i > len(data) {
|
|
i = len(data)
|
|
break
|
|
}
|
|
}
|
|
if start < len(data) {
|
|
result += string(data[start : len(data)])
|
|
i = len(data)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback: if stream format parsing fails, just return the raw data as text
|
|
if result == "" {
|
|
return string(buffer)
|
|
}
|
|
return result
|
|
}
|