diff options
| -rw-r--r-- | api/api.go | 29 | ||||
| -rw-r--r-- | api/docker.go | 58 | ||||
| -rw-r--r-- | go.mod | 29 | ||||
| -rw-r--r-- | nonsense-time.go | 1 |
4 files changed, 116 insertions, 1 deletions
@@ -3,9 +3,11 @@ package api import ( "context" "encoding/json" + "io" "log/slog" "net/http" "os" + "strconv" "time" ) @@ -40,7 +42,7 @@ func respondOnline(w http.ResponseWriter, status ServerStatus) { jsonData, err := json.Marshal(status) if err != nil { http.Error(w, "Error constructing response", http.StatusInternalServerError) - Logger.Error("Error marshalling site status data") + Logger.Error("Error marshalling site status data", slog.Any("err", err)) return } @@ -61,6 +63,31 @@ func VttRedirect(w http.ResponseWriter, req *http.Request) { http.Redirect(w, req, VTT_URL, http.StatusMovedPermanently) } +func VttLogs(w http.ResponseWriter, req *http.Request) { + var lines uint = 0 + + linesParam := req.URL.Query().Get("lines") + if linesParam != "" { + lines_64, err := strconv.ParseUint(linesParam, 10, 64) + if err != nil { + Logger.ErrorContext(req.Context(), "Invalid line count in vtt logs request", slog.Any("err", err)) + http.Error(w, "Invalid line count in request", http.StatusBadRequest) + return + } + + lines = uint(lines_64) + } + + logReader, err := vttLogs(req.Context(), lines) + if err != nil { + http.Error(w, "Error occured while getting logs", http.StatusInternalServerError) + return + } + defer logReader.Close() + + io.Copy(w, logReader) +} + func SiteOnline(w http.ResponseWriter, req *http.Request) { const URL string = "https://dnd.jpappel.xyz" diff --git a/api/docker.go b/api/docker.go new file mode 100644 index 0000000..21d5c26 --- /dev/null +++ b/api/docker.go @@ -0,0 +1,58 @@ +package api + +import ( + "context" + "fmt" + "io" + "log/slog" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/client" +) + +const vttContainerId string = "foundry-foundry-1" + +func stopVtt(ctx context.Context) error { + apiClient, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + Logger.ErrorContext(ctx, "Failed to get docker api client", slog.Any("err", err)) + return err + } + + Logger.InfoContext(ctx, "Stopping foundry container") + err = apiClient.ContainerStop(ctx, vttContainerId, container.StopOptions{}) + if err != nil { + Logger.ErrorContext(ctx, "Error occured while stopping foundry container", slog.Any("err", err)) + return err + } + + return nil +} + +// Get readcloser for logs +// If lines is zero, returns all logs. +func vttLogs(ctx context.Context, lines uint) (io.ReadCloser, error) { + apiClient, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + Logger.ErrorContext(ctx, "Failed to get docker api client", slog.Any("err", err)) + return nil, err + } + + opts := container.LogsOptions{ + ShowStdout: true, + ShowStderr: true, + Timestamps: true, + } + if lines != 0 { + opts.Tail = fmt.Sprint(lines) + } + + Logger.DebugContext(ctx, "Getting container logs") + r, err := apiClient.ContainerLogs(ctx, vttContainerId, opts) + if err != nil { + Logger.ErrorContext(ctx, "Failed to get foundry container's logs", slog.Any("err", err)) + return nil, err + } + + return r, nil +} @@ -1,3 +1,32 @@ module nonsense-time go 1.23.0 + +require github.com/docker/docker v27.3.1+incompatible + +require ( + github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect + go.opentelemetry.io/otel v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 // indirect + go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.30.0 // indirect + go.opentelemetry.io/otel/trace v1.30.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/time v0.7.0 // indirect + gotest.tools/v3 v3.5.1 // indirect +) diff --git a/nonsense-time.go b/nonsense-time.go index 94c0a30..3ffff11 100644 --- a/nonsense-time.go +++ b/nonsense-time.go @@ -70,6 +70,7 @@ func main() { mux.Handle("GET /site/status", site) mux.HandleFunc("GET /", dashboard.Index) mux.HandleFunc("GET /static/", dashboard.StaticHandler) + mux.HandleFunc("GET /vtt/logs", api.VttLogs) logger.Info(fmt.Sprint("Listening on ", addr)) logger.Info(http.ListenAndServe(addr, mux).Error()) |
