feat(master): check the registry now from the service page (#35)
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/shcizo/package-updater/internal/agenttoken"
|
||||
"github.com/shcizo/package-updater/internal/master/events"
|
||||
"github.com/shcizo/package-updater/internal/master/model"
|
||||
"github.com/shcizo/package-updater/internal/master/poller"
|
||||
"github.com/shcizo/package-updater/internal/master/web/icons"
|
||||
"github.com/shcizo/package-updater/internal/master/webauth"
|
||||
"github.com/shcizo/package-updater/internal/protocol"
|
||||
@@ -85,6 +86,13 @@ type Jobs interface {
|
||||
RestoreDesired(ctx context.Context, serviceID int64, requestedBy string) (model.Job, error)
|
||||
}
|
||||
|
||||
// Poller checks the registry for one service. *poller.Poller satisfies it.
|
||||
type Poller interface {
|
||||
// PollService returns *poller.NotPolledError when the service is not
|
||||
// polled and model.ErrNotFound for an unknown or removed one.
|
||||
PollService(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
// Broker delivers change signals to open streams and accepts signals from
|
||||
// UI actions. *events.Broker satisfies it.
|
||||
type Broker interface {
|
||||
@@ -108,6 +116,7 @@ type Server struct {
|
||||
hub Hub
|
||||
jobs Jobs
|
||||
broker Broker
|
||||
poller Poller
|
||||
cfg Config
|
||||
log *slog.Logger
|
||||
now func() time.Time
|
||||
@@ -116,7 +125,7 @@ type Server struct {
|
||||
|
||||
// New parses the templates. Each page is its own template set so every page
|
||||
// can define its own "content" block.
|
||||
func New(store Store, hub Hub, jobs Jobs, broker Broker, cfg Config, log *slog.Logger) (*Server, error) {
|
||||
func New(store Store, hub Hub, jobs Jobs, broker Broker, poller Poller, cfg Config, log *slog.Logger) (*Server, error) {
|
||||
funcs := template.FuncMap{"shortRef": shortRef, "duration": jobDuration, "followsNoTag": followsNoTag, "middle": middle}
|
||||
pages := map[string]*template.Template{}
|
||||
for _, page := range []string{"overview.html", "agents.html", "service.html", "jobs.html", "job.html"} {
|
||||
@@ -126,7 +135,7 @@ func New(store Store, hub Hub, jobs Jobs, broker Broker, cfg Config, log *slog.L
|
||||
}
|
||||
pages[page] = t
|
||||
}
|
||||
return &Server{store: store, hub: hub, jobs: jobs, broker: broker, cfg: cfg, log: log, now: time.Now, pages: pages}, nil
|
||||
return &Server{store: store, hub: hub, jobs: jobs, broker: broker, poller: poller, cfg: cfg, log: log, now: time.Now, pages: pages}, nil
|
||||
}
|
||||
|
||||
// Register adds the UI routes to mux. protect wraps every route except
|
||||
@@ -140,6 +149,7 @@ func (s *Server) Register(mux *http.ServeMux, protect func(http.Handler) http.Ha
|
||||
route("GET /fragments/services/{id}/jobs", s.serviceJobsFragment)
|
||||
route("POST /services/{id}/update", s.updateService)
|
||||
route("POST /services/{id}/mode", s.setMode)
|
||||
route("POST /services/{id}/poll", s.pollService)
|
||||
route("POST /services/{id}/restore", s.restoreDesired)
|
||||
route("POST /services/{id}/accept", s.acceptRunning)
|
||||
route("POST /services/{id}/merge", s.mergeService)
|
||||
@@ -204,6 +214,7 @@ type pageData struct {
|
||||
ConfigFiles []string
|
||||
Reason string // why Service cannot be updated; "" when it can
|
||||
AutoBlocked string // why Service cannot be set to auto; "" when it can
|
||||
PollBlocked string // why Service cannot be checked against the registry; "" when it can
|
||||
Versions []versionRow
|
||||
NewerTag string // Service's newer tag while it still holds; "" otherwise
|
||||
Polling string // what the service page says about registry polling
|
||||
@@ -380,6 +391,7 @@ func (s *Server) serviceDetail(r *http.Request, id int64) (pageData, error) {
|
||||
return data, err
|
||||
}
|
||||
data.AutoBlocked = s.autoBlocked(svc)
|
||||
data.PollBlocked = pollBlocked(svc)
|
||||
if err := s.jobs.Restorable(svc); errors.As(err, &nu) {
|
||||
data.RestoreBlocked = nu.Reason
|
||||
} else if err != nil {
|
||||
@@ -605,6 +617,32 @@ func (s *Server) renderServiceError(w http.ResponseWriter, r *http.Request, id i
|
||||
s.page(w, r, status, "service.html", data)
|
||||
}
|
||||
|
||||
// pollService checks the registry for one service now and waits for the
|
||||
// answer. A registry error is not a failure of the request: it shows on the
|
||||
// service page as the last check failing. The poller publishes the change
|
||||
// itself when it writes.
|
||||
func (s *Server) pollService(w http.ResponseWriter, r *http.Request) {
|
||||
id, ok := pathID(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
err := s.poller.PollService(r.Context(), id)
|
||||
var np *poller.NotPolledError
|
||||
switch {
|
||||
case errors.As(err, &np):
|
||||
s.renderServiceError(w, r, id, http.StatusConflict, "Cannot check: "+np.Reason+".")
|
||||
return
|
||||
case r.Context().Err() != nil:
|
||||
return // the client is gone
|
||||
case err != nil:
|
||||
s.failLookup(w, err)
|
||||
return
|
||||
}
|
||||
sess, _ := webauth.SessionFrom(r.Context())
|
||||
s.log.Info("poll_requested", "service_id", id, "subject", sess.Subject)
|
||||
http.Redirect(w, r, "/services/"+strconv.FormatInt(id, 10), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// setMode switches a service between manual and auto. Manual is always
|
||||
// allowed; auto only when jobs.AutoAllowed says so.
|
||||
func (s *Server) setMode(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user