fix(agent): list all compose profiles and fail closed on unknown services (#7)
This commit is contained in:
@@ -279,7 +279,18 @@ func (c *Collector) markBuilt(ctx context.Context, byKey map[string]protocol.Ser
|
||||
if svc.Kind != protocol.KindCompose {
|
||||
continue
|
||||
}
|
||||
if c.builtServices(ctx, svc.ComposeProject, stacks[svc.ComposeProject])[svc.ComposeService] {
|
||||
built := c.builtServices(ctx, svc.ComposeProject, stacks[svc.ComposeProject])
|
||||
if built == nil {
|
||||
continue // check failed; already logged
|
||||
}
|
||||
isBuilt, known := built[svc.ComposeService]
|
||||
if !known {
|
||||
// Fail closed: a service compose does not list cannot be shown to
|
||||
// be free of build:, so it is not offered for update.
|
||||
c.warnOnce(svc.ComposeProject+"/"+svc.ComposeService, "compose_service_not_in_config",
|
||||
"project", svc.ComposeProject, "service", svc.ComposeService)
|
||||
}
|
||||
if isBuilt || !known {
|
||||
svc.Built = true
|
||||
byKey[key] = svc
|
||||
}
|
||||
@@ -289,6 +300,10 @@ func (c *Collector) markBuilt(ctx context.Context, byKey map[string]protocol.Ser
|
||||
// builtServices returns the project's built services, from the cache while
|
||||
// the project's files are unchanged.
|
||||
func (c *Collector) builtServices(ctx context.Context, project string, l stackLabels) map[string]bool {
|
||||
// The key covers the files named in the labels. Changes in files they
|
||||
// pull in (extends:, include:, the default .env) do not invalidate the
|
||||
// cache, so Built can be stale until another change or an agent restart.
|
||||
// The job-time check is always fresh, so jobs stay safe.
|
||||
key := l.workingDir + "|" + l.configFiles + "|" + l.envFile + "|" + fileStamps(l.configFiles+","+l.envFile)
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
@@ -297,18 +312,30 @@ func (c *Collector) builtServices(ctx context.Context, project string, l stackLa
|
||||
}
|
||||
built, err := c.check.BuiltServices(ctx, project, l.workingDir, l.configFiles, l.envFile)
|
||||
c.cache[project] = buildEntry{key: key, built: built, err: err, at: c.now()}
|
||||
switch {
|
||||
case err == nil:
|
||||
if err == nil {
|
||||
delete(c.warned, project)
|
||||
case !c.warned[project]:
|
||||
c.warned[project] = true
|
||||
if c.log != nil {
|
||||
c.log.Warn("compose_build_check_failed", "project", project, "error", err)
|
||||
}
|
||||
} else {
|
||||
c.warnOnceLocked(project, "compose_build_check_failed", "project", project, "error", err)
|
||||
}
|
||||
return built
|
||||
}
|
||||
|
||||
// warnOnce logs msg the first time it is called for key (until the next
|
||||
// successful check of the project resets it).
|
||||
func (c *Collector) warnOnce(key, msg string, args ...any) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.warnOnceLocked(key, msg, args...)
|
||||
}
|
||||
|
||||
func (c *Collector) warnOnceLocked(key, msg string, args ...any) {
|
||||
if c.warned[key] || c.log == nil {
|
||||
return
|
||||
}
|
||||
c.warned[key] = true
|
||||
c.log.Warn(msg, args...)
|
||||
}
|
||||
|
||||
// fileStamps summarises size and mtime of the comma-separated files, so a
|
||||
// changed file changes the string.
|
||||
func fileStamps(list string) string {
|
||||
|
||||
Reference in New Issue
Block a user