diff --git a/cmd/fluxd/main.go b/cmd/fluxd/main.go index 5d558767fe..6fefd9bd5f 100644 --- a/cmd/fluxd/main.go +++ b/cmd/fluxd/main.go @@ -146,6 +146,7 @@ func main() { registryTrace = fs.Bool("registry-trace", false, "output trace of image registry requests to log") registryInsecure = fs.StringSlice("registry-insecure-host", []string{}, "let these registry hosts skip TLS host verification and fall back to using HTTP instead of HTTPS; this allows man-in-the-middle attacks, so use with extreme caution") registryExcludeImage = fs.StringSlice("registry-exclude-image", []string{"k8s.gcr.io/*"}, "do not scan images that match these glob expressions; the default is to exclude the 'k8s.gcr.io/*' images") + registryUseLabels = fs.StringSlice("registry-use-labels", []string{"index.docker.io/weaveworks/*"}, "use the timestamp (RFC3339) from labels for (canonical) image refs that match these glob expression") // AWS authentication registryAWSRegions = fs.StringSlice("registry-ecr-region", nil, "include just these AWS regions when scanning images in ECR; when not supplied, the cluster's region will included if it can be detected through the AWS API") @@ -498,6 +499,9 @@ func main() { cacheRegistry = &cache.Cache{ Reader: cacheClient, + Decorators: []cache.Decorator{ + cache.TimestampLabelWhitelist(*registryUseLabels), + }, } cacheRegistry = registry.NewInstrumentedRegistry(cacheRegistry) diff --git a/registry/cache/registry.go b/registry/cache/registry.go index 967bae3ecf..07d61b3416 100644 --- a/registry/cache/registry.go +++ b/registry/cache/registry.go @@ -5,6 +5,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/ryanuber/go-glob" fluxerr "github.com/weaveworks/flux/errors" "github.com/weaveworks/flux/image" @@ -28,7 +29,41 @@ repository. // Cache is a local cache of image metadata. type Cache struct { - Reader Reader + Reader Reader + Decorators []Decorator +} + +// Decorator is for decorating an ImageRepository before it is returned. +type Decorator interface { + apply(*ImageRepository) +} + +// TimestampLabelWhitelist contains a string slice of glob patterns. Any +// canonical image reference that matches one of the glob patterns will +// prefer creation timestamps from labels over the one it received from +// the registry. +type TimestampLabelWhitelist []string + +// apply checks if any of the canonical image references from the +// repository matches a glob pattern from the list. If it does, and the +// image record has a valid timestamp label, it will replace the Created +// field with the value from the label. +func (l TimestampLabelWhitelist) apply(r *ImageRepository) { + for k, i := range r.Images { + for _, exp := range l { + if !glob.Glob(exp, i.ID.CanonicalName().String()) { + continue + } + + switch { + case !i.Labels.Created.IsZero(): + i.CreatedAt = i.Labels.Created + case !i.Labels.BuildDate.IsZero(): + i.CreatedAt = i.Labels.BuildDate + } + r.Images[k] = i + } + } } // GetImageRepositoryMetadata returns the metadata from an image @@ -53,6 +88,11 @@ func (c *Cache) GetImageRepositoryMetadata(id image.Name) (image.RepositoryMetad return image.RepositoryMetadata{}, ErrNotCached } + // (Maybe) decorate the image repository. + for _, d := range c.Decorators { + d.apply(&repo) + } + return repo.RepositoryMetadata, nil }