feat: master/agent phase 4 — registry polling and version history (#9) #23
@@ -91,10 +91,10 @@ func NewComposeExecutor(cli ComposeDocker, resolve *Resolver, selfID string, run
|
|||||||
return &ComposeExecutor{cli: cli, resolve: resolve, selfID: selfID, run: run, build: NewBuildChecker(cli, selfID, runOut)}
|
return &ComposeExecutor{cli: cli, resolve: resolve, selfID: selfID, run: run, build: NewBuildChecker(cli, selfID, runOut)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute pins job.Ref to its current digest (a ref that has one is used as is), writes it to the stack's
|
// Execute pins job.Ref to its current digest (a ref that has one is used as
|
||||||
// override file and recreates the service. Working directory and config
|
// is), writes it to the stack's override file and recreates the service.
|
||||||
// files come from the service's container labels on this machine, never from
|
// Working directory and config files come from the service's container
|
||||||
// the job. It returns the pinned ref.
|
// labels on this machine, never from the job. It returns the pinned ref.
|
||||||
func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, out io.Writer) (string, error) {
|
func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, out io.Writer) (string, error) {
|
||||||
project, service := job.ComposeProject, job.ComposeService
|
project, service := job.ComposeProject, job.ComposeService
|
||||||
cts, err := e.cli.ContainerList(ctx, container.ListOptions{
|
cts, err := e.cli.ContainerList(ctx, container.ListOptions{
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ func NewSwarmExecutor(cli SwarmClient, resolve *Resolver, auth *RegistryAuth) *S
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute checks that the local daemon is a manager of the job's cluster,
|
// Execute checks that the local daemon is a manager of the job's cluster,
|
||||||
// pins job.Ref to its current digest (a ref that has one is used as is) and updates the service to it. The
|
// pins job.Ref to its current digest (a ref that has one is used as is) and
|
||||||
// update is addressed by the ID and version of the service that was
|
// updates the service to it. The update is addressed by the ID and version of
|
||||||
// inspected, so it changes exactly that object. Success means the daemon
|
// the service that was inspected, so it changes exactly that object. Success
|
||||||
// accepted the new spec, not that the tasks have converged. It returns the
|
// means the daemon accepted the new spec, not that the tasks have converged.
|
||||||
// pinned ref.
|
// It returns the pinned ref.
|
||||||
func (e *SwarmExecutor) Execute(ctx context.Context, job protocol.JobStart, out io.Writer) (string, error) {
|
func (e *SwarmExecutor) Execute(ctx context.Context, job protocol.JobStart, out io.Writer) (string, error) {
|
||||||
info, err := e.cli.Info(ctx)
|
info, err := e.cli.Info(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -201,9 +201,15 @@ func newTestServer(t *testing.T) (*httptest.Server, *fakeStore, *fakeHub, *event
|
|||||||
return srv, store, hub, broker
|
return srv, store, hub, broker
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTestEnv starts the UI on fake storage. pollInterval is what the service
|
// newTestEnv starts the UI on fake storage, with polling off.
|
||||||
// page shows as the polling interval; it defaults to zero.
|
func newTestEnv(t *testing.T) (*httptest.Server, *fakeStore, *fakeHub, *events.Broker, *fakeJobs) {
|
||||||
func newTestEnv(t *testing.T, pollInterval ...time.Duration) (*httptest.Server, *fakeStore, *fakeHub, *events.Broker, *fakeJobs) {
|
t.Helper()
|
||||||
|
return newTestEnvPolling(t, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newTestEnvPolling is newTestEnv with pollInterval as the polling interval
|
||||||
|
// the service page shows.
|
||||||
|
func newTestEnvPolling(t *testing.T, pollInterval time.Duration) (*httptest.Server, *fakeStore, *fakeHub, *events.Broker, *fakeJobs) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
agentID := int64(2)
|
agentID := int64(2)
|
||||||
store := &fakeStore{
|
store := &fakeStore{
|
||||||
@@ -227,7 +233,7 @@ func newTestEnv(t *testing.T, pollInterval ...time.Duration) (*httptest.Server,
|
|||||||
jobs := &fakeJobs{}
|
jobs := &fakeJobs{}
|
||||||
s, err := New(store, hub, jobs, broker, Config{
|
s, err := New(store, hub, jobs, broker, Config{
|
||||||
AgentURL: "wss://10.0.0.5:8090/agent", MasterKey: "sha256:abc", AgentImage: "gitea.shcizo.se/shcizo/package-updater:latest",
|
AgentURL: "wss://10.0.0.5:8090/agent", MasterKey: "sha256:abc", AgentImage: "gitea.shcizo.se/shcizo/package-updater:latest",
|
||||||
PollInterval: append(pollInterval, 0)[0],
|
PollInterval: pollInterval,
|
||||||
}, slog.New(slog.NewTextHandler(io.Discard, nil)))
|
}, slog.New(slog.NewTextHandler(io.Discard, nil)))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
<td><code title="{{.Ref}}">{{shortRef .Ref}}</code>{{if .Running}} <span class="badge">running</span>{{end}}{{if not .Tag}} <span class="muted">the service will follow no tag afterwards</span>{{end}}</td>
|
<td><code title="{{.Ref}}">{{shortRef .Ref}}</code>{{if .Running}} <span class="badge">running</span>{{end}}{{if not .Tag}} <span class="muted">the service will follow no tag afterwards</span>{{end}}</td>
|
||||||
<td>{{.Source}}</td>
|
<td>{{.Source}}</td>
|
||||||
<td>{{.FirstSeenAt.Format "2006-01-02 15:04"}}</td>
|
<td>{{.FirstSeenAt.Format "2006-01-02 15:04"}}</td>
|
||||||
|
{{/* AutoBlocked is the same check that decides whether the service can be updated with an explicit ref, which is what a pick is. */}}
|
||||||
<td>{{if not $.AutoBlocked}}
|
<td>{{if not $.AutoBlocked}}
|
||||||
<form method="post" action="/services/{{$.Service.ID}}/update">
|
<form method="post" action="/services/{{$.Service.ID}}/update">
|
||||||
<input type="hidden" name="csrf_token" value="{{$.CSRF}}">
|
<input type="hidden" name="csrf_token" value="{{$.CSRF}}">
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ func TestServicePage_PollingRow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
srv, store, _, _, _ := newTestEnv(t, 6*time.Hour)
|
srv, store, _, _, _ := newTestEnvPolling(t, 6*time.Hour)
|
||||||
tt.edit(&store.services[0])
|
tt.edit(&store.services[0])
|
||||||
|
|
||||||
_, body := get(t, srv, "/services/1")
|
_, body := get(t, srv, "/services/1")
|
||||||
|
|||||||
Reference in New Issue
Block a user