mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-23 02:20:12 +01:00
Added dashboard
This commit is contained in:
parent
d744c34886
commit
130429b10a
22 changed files with 2986 additions and 14 deletions
|
|
@ -23,6 +23,22 @@ func New(token string) *API {
|
|||
}
|
||||
}
|
||||
|
||||
func (api *API) EnableCors(fn http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Access-Control-Allow-Origin", "http://localhost:8001") // todo: configurable port
|
||||
w.Header().Add("Access-Control-Allow-Credentials", "true")
|
||||
w.Header().Add("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
||||
|
||||
if r.Method == http.MethodOptions {
|
||||
http.Error(w, "No Content", http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
fn(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// RequireToken is wrapper around http.HandleFunc that checks token validity
|
||||
func (api *API) RequireToken(fn http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -40,7 +56,7 @@ func (api *API) RequireToken(fn http.HandlerFunc) http.HandlerFunc {
|
|||
// RegisterFunc is a wrapper around http.HandleFunc that also sets the flag used to determine whether to launch the API
|
||||
func (api *API) RegisterFunc(path string, fn http.HandlerFunc) {
|
||||
api.hasHandlers = true
|
||||
http.HandleFunc(path, api.RequireToken(fn))
|
||||
http.HandleFunc(path, api.EnableCors(api.RequireToken(fn)))
|
||||
}
|
||||
|
||||
// RegisterHandler is a wrapper around http.Handler that also sets the flag used to determine whether to launch the API
|
||||
|
|
|
|||
93
pkg/api/check/check.go
Normal file
93
pkg/api/check/check.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package check
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/containrrr/watchtower/pkg/container"
|
||||
"github.com/containrrr/watchtower/pkg/types"
|
||||
)
|
||||
|
||||
// Handler is an HTTP handle for serving list data
|
||||
type Handler struct {
|
||||
Path string
|
||||
Client container.Client
|
||||
}
|
||||
|
||||
type CheckRequest struct {
|
||||
ContainerId string
|
||||
}
|
||||
|
||||
type CheckResponse struct {
|
||||
ContainerId string
|
||||
HasUpdate bool
|
||||
NewVersion string
|
||||
NewVersionCreated string
|
||||
}
|
||||
|
||||
// New is a factory function creating a new List instance
|
||||
func New(client container.Client) *Handler {
|
||||
return &Handler{
|
||||
Path: "/v1/check",
|
||||
Client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// HandlePost is the actual http.HandlePost function doing all the heavy lifting
|
||||
func (handle *Handler) HandlePost(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
log.Info("Calling Check API with unsupported method")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info("Check for update triggered by HTTP API request.")
|
||||
|
||||
var request CheckRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&request)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
client := handle.Client
|
||||
container, err := client.GetContainer(types.ContainerID(request.ContainerId))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
stale, newestImage, created, err := client.IsContainerStale(container)
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
data := CheckResponse{
|
||||
ContainerId: request.ContainerId,
|
||||
HasUpdate: stale,
|
||||
NewVersion: newestImage.ShortID(),
|
||||
NewVersionCreated: created,
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Fatalf("Error happened in JSON marshal. Err: %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(jsonData)
|
||||
}
|
||||
80
pkg/api/list/list.go
Normal file
80
pkg/api/list/list.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package list
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/containrrr/watchtower/pkg/container"
|
||||
filters "github.com/containrrr/watchtower/pkg/filters"
|
||||
)
|
||||
|
||||
// Handler is an HTTP handle for serving list data
|
||||
type Handler struct {
|
||||
Path string
|
||||
Client container.Client
|
||||
}
|
||||
|
||||
type ContainerListEntry struct {
|
||||
ContainerId string
|
||||
ContainerName string
|
||||
ImageName string
|
||||
ImageNameShort string
|
||||
ImageVersion string
|
||||
ImageCreatedDate string
|
||||
}
|
||||
type ListResponse struct {
|
||||
Containers []ContainerListEntry
|
||||
}
|
||||
|
||||
// New is a factory function creating a new List instance
|
||||
func New(client container.Client) *Handler {
|
||||
return &Handler{
|
||||
Path: "/v1/list",
|
||||
Client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleGet is the actual http.HandleGet function doing all the heavy lifting
|
||||
func (handle *Handler) HandleGet(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
log.Info("Calling List API with unsupported method")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info("List containers triggered by HTTP API request.")
|
||||
|
||||
client := handle.Client
|
||||
filter := filters.NoFilter
|
||||
containers, err := client.ListContainers(filter)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
}
|
||||
|
||||
data := ListResponse{Containers: []ContainerListEntry{}}
|
||||
|
||||
for _, c := range containers {
|
||||
data.Containers = append(data.Containers, ContainerListEntry{
|
||||
ContainerId: c.ID().ShortID(),
|
||||
ContainerName: c.Name()[1:],
|
||||
ImageName: c.ImageName(),
|
||||
ImageNameShort: strings.Split(c.ImageName(), ":")[0],
|
||||
ImageCreatedDate: c.ImageInfo().Created,
|
||||
ImageVersion: c.ImageID().ShortID(),
|
||||
})
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Fatalf("Error happened in JSON marshal. Err: %s", err)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(jsonData)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue