From b9615bf2db3ce3d0d288924f27efe90874b804a4 Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Sat, 23 Sep 2023 12:54:17 +0200 Subject: [PATCH] fix defaults not handled by yaml configuration --- .github/workflows/e2e.yml | 2 + internal/app/job.go | 2 +- internal/config/config_test.go | 8 +- internal/config/fixtures/config.test.yml | 4 + internal/model/watch.go | 7 +- internal/model/watch_imagedefaults.go | 31 +++ internal/provider/common.go | 38 ++- internal/provider/common_test.go | 285 ++++----------------- internal/provider/docker/container.go | 2 +- internal/provider/docker/docker.go | 4 +- internal/provider/dockerfile/dockerfile.go | 4 +- internal/provider/dockerfile/image.go | 2 +- internal/provider/file/file.go | 4 +- internal/provider/file/file_test.go | 6 +- internal/provider/kubernetes/kubernetes.go | 4 +- internal/provider/kubernetes/pod.go | 2 +- internal/provider/nomad/nomad.go | 4 +- internal/provider/nomad/task.go | 2 +- internal/provider/swarm/service.go | 2 +- internal/provider/swarm/swarm.go | 4 +- test/docker5/diun.yml | 11 + 21 files changed, 146 insertions(+), 282 deletions(-) create mode 100644 internal/model/watch_imagedefaults.go create mode 100644 test/docker5/diun.yml diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index b5263574..871dd817 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -45,6 +45,8 @@ jobs: loglevel: info - folder: docker4 loglevel: info + - folder: docker5 + loglevel: info - folder: dockerfile1 loglevel: debug - folder: dockerfile2 diff --git a/internal/app/job.go b/internal/app/job.go index f186b17d..0b13efd0 100644 --- a/internal/app/job.go +++ b/internal/app/job.go @@ -118,7 +118,7 @@ func (di *Diun) createJob(job model.Job) { sublog.Error().Err(err).Msgf("Invoking job") } - if job.Image.WatchRepo == nil || !*job.Image.WatchRepo || len(job.RegImage.Domain) == 0 { + if !*job.Image.WatchRepo || len(job.RegImage.Domain) == 0 { return } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 1986071e..b21ef57d 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -58,9 +58,11 @@ func TestLoadFile(t *testing.T) { BaseURL: "https://hc-ping.com/", UUID: "5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278", }, - ImageDefaults: &model.Image{ - NotifyOn: model.NotifyOnDefaults, - SortTags: registry.SortTagReverse, + ImageDefaults: &model.ImageDefaults{ + WatchRepo: utl.NewFalse(), + NotifyOn: []model.NotifyOn{model.NotifyOnNew}, + MaxTags: 5, + SortTags: registry.SortTagReverse, }, }, Notif: &model.Notif{ diff --git a/internal/config/fixtures/config.test.yml b/internal/config/fixtures/config.test.yml index 39055cdf..f8f53843 100644 --- a/internal/config/fixtures/config.test.yml +++ b/internal/config/fixtures/config.test.yml @@ -11,6 +11,10 @@ watch: healthchecks: baseURL: https://hc-ping.com/ uuid: 5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278 + imageDefaults: + notifyOn: + - new + maxTags: 5 notif: amqp: diff --git a/internal/model/watch.go b/internal/model/watch.go index 13f192be..a5719b50 100644 --- a/internal/model/watch.go +++ b/internal/model/watch.go @@ -3,7 +3,6 @@ package model import ( "time" - "github.com/crazy-max/diun/v4/pkg/registry" "github.com/crazy-max/diun/v4/pkg/utl" ) @@ -16,7 +15,7 @@ type Watch struct { RunOnStartup *bool `yaml:"runOnStartup,omitempty" json:"runOnStartup,omitempty" validate:"required"` CompareDigest *bool `yaml:"compareDigest,omitempty" json:"compareDigest,omitempty" validate:"required"` Healthchecks *Healthchecks `yaml:"healthchecks,omitempty" json:"healthchecks,omitempty"` - ImageDefaults *Image `yaml:"defaults,omitempty" json:"defaults,omitempty"` + ImageDefaults *ImageDefaults `yaml:"imageDefaults,omitempty" json:"imageDefaults,omitempty"` } // GetDefaults gets the default values @@ -33,8 +32,4 @@ func (s *Watch) SetDefaults() { s.FirstCheckNotif = utl.NewFalse() s.RunOnStartup = utl.NewTrue() s.CompareDigest = utl.NewTrue() - s.ImageDefaults = &Image{ - NotifyOn: NotifyOnDefaults, - SortTags: registry.SortTagReverse, - } } diff --git a/internal/model/watch_imagedefaults.go b/internal/model/watch_imagedefaults.go new file mode 100644 index 00000000..64dbdbbc --- /dev/null +++ b/internal/model/watch_imagedefaults.go @@ -0,0 +1,31 @@ +package model + +import ( + "github.com/crazy-max/diun/v4/pkg/registry" + "github.com/crazy-max/diun/v4/pkg/utl" +) + +// ImageDefaults holds data necessary for image defaults configuration +type ImageDefaults struct { + WatchRepo *bool `yaml:"watchRepo,omitempty" json:"watchRepo,omitempty"` + NotifyOn []NotifyOn `yaml:"notifyOn,omitempty" json:"notifyOn,omitempty"` + MaxTags int `yaml:"maxTags,omitempty" json:"maxTags,omitempty"` + SortTags registry.SortTag `yaml:"sortTags,omitempty" json:"sortTags,omitempty"` + IncludeTags []string `yaml:"includeTags,omitempty" json:"includeTags,omitempty"` + ExcludeTags []string `yaml:"excludeTags,omitempty" json:"excludeTags,omitempty"` + Metadata map[string]string `yaml:"metadata,omitempty" json:"metadata,omitempty"` +} + +// GetDefaults gets the default values +func (s *ImageDefaults) GetDefaults() *Watch { + n := &Watch{} + n.SetDefaults() + return n +} + +// SetDefaults sets the default values +func (s *ImageDefaults) SetDefaults() { + s.WatchRepo = utl.NewFalse() + s.NotifyOn = NotifyOnDefaults + s.SortTags = registry.SortTagReverse +} diff --git a/internal/provider/common.go b/internal/provider/common.go index 27830b4d..cbefc7d4 100644 --- a/internal/provider/common.go +++ b/internal/provider/common.go @@ -18,19 +18,25 @@ var ( ) // ValidateImage returns a standard image through Docker labels -func ValidateImage(image string, metadata, labels map[string]string, watchByDef bool, imageDefaults model.Image) (img model.Image, err error) { +func ValidateImage(image string, metadata, labels map[string]string, watchByDef bool, imageDefaults *model.ImageDefaults) (img model.Image, err error) { img = model.Image{ Name: image, } - if err := mergo.Merge(&img, imageDefaults); err != nil { - return img, &invalidLabelError{errors.Wrapf(err, "failed to merge image defaults for image %s", image)} + if imageDefaults != nil { + img.WatchRepo = imageDefaults.WatchRepo + img.NotifyOn = imageDefaults.NotifyOn + img.MaxTags = imageDefaults.MaxTags + img.SortTags = imageDefaults.SortTags + img.IncludeTags = imageDefaults.IncludeTags + img.ExcludeTags = imageDefaults.ExcludeTags + img.Metadata = imageDefaults.Metadata } if enableStr, ok := labels["diun.enable"]; ok { enable, err := strconv.ParseBool(enableStr) if err != nil { - return img, &invalidLabelError{errors.Wrapf(err, "cannot parse %q value of label diun.enable", enableStr)} + return img, errors.Wrapf(err, "cannot parse %q value of label diun.enable", enableStr) } if !enable { return model.Image{}, nil @@ -47,7 +53,7 @@ func ValidateImage(image string, metadata, labels map[string]string, watchByDef if watchRepo, err := strconv.ParseBool(value); err == nil { img.WatchRepo = &watchRepo } else { - return img, &invalidLabelError{errors.Wrapf(err, "cannot parse %q value of label %s", value, key)} + return img, errors.Wrapf(err, "cannot parse %q value of label %s", value, key) } case key == "diun.notify_on": if len(value) == 0 { @@ -57,7 +63,7 @@ func ValidateImage(image string, metadata, labels map[string]string, watchByDef for _, no := range strings.Split(value, ";") { notifyOn := model.NotifyOn(no) if !notifyOn.Valid() { - return img, &invalidLabelError{errors.Errorf("unknown notify status %q", value)} + return img, errors.Errorf("unknown notify status %q", value) } img.NotifyOn = append(img.NotifyOn, notifyOn) } @@ -67,12 +73,12 @@ func ValidateImage(image string, metadata, labels map[string]string, watchByDef } sortTags := registry.SortTag(value) if !sortTags.Valid() { - return img, &invalidLabelError{errors.Errorf("unknown sort tags type %q", value)} + return img, errors.Errorf("unknown sort tags type %q", value) } img.SortTags = sortTags case key == "diun.max_tags": if img.MaxTags, err = strconv.Atoi(value); err != nil { - return img, &invalidLabelError{errors.Wrapf(err, "cannot parse %q value of label %s", value, key)} + return img, errors.Wrapf(err, "cannot parse %q value of label %s", value, key) } case key == "diun.include_tags": img.IncludeTags = strings.Split(value, ";") @@ -85,7 +91,7 @@ func ValidateImage(image string, metadata, labels map[string]string, watchByDef case key == "diun.platform": platform, err := platforms.Parse(value) if err != nil { - return img, &invalidLabelError{errors.Wrapf(err, "cannot parse %q platform of label %s", value, key)} + return img, errors.Wrapf(err, "cannot parse %q platform of label %s", value, key) } img.Platform = model.ImagePlatform{ OS: platform.OS, @@ -98,7 +104,7 @@ func ValidateImage(image string, metadata, labels map[string]string, watchByDef break } if err := validateMetadataKey(mkey); err != nil { - return img, &invalidLabelError{errors.Wrapf(err, "invalid metadata key %q", mkey)} + return img, errors.Wrapf(err, "invalid metadata key %q", mkey) } if img.Metadata == nil { img.Metadata = map[string]string{} @@ -121,15 +127,3 @@ func validateMetadataKey(key string) error { } return nil } - -type invalidLabelError struct { - error -} - -func (e *invalidLabelError) Error() string { - return e.Error() -} - -func (e *invalidLabelError) Unwrap() error { - return e -} diff --git a/internal/provider/common_test.go b/internal/provider/common_test.go index abaf59f7..00c5c7b3 100644 --- a/internal/provider/common_test.go +++ b/internal/provider/common_test.go @@ -6,6 +6,7 @@ import ( "github.com/crazy-max/diun/v4/internal/model" "github.com/crazy-max/diun/v4/pkg/registry" "github.com/crazy-max/diun/v4/pkg/utl" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -16,9 +17,9 @@ func TestValidateImage(t *testing.T) { metadata map[string]string labels map[string]string watchByDef bool - imageDefaults model.Image + imageDefaults *model.ImageDefaults expectedImage model.Image - expectedErr interface{} + expectedErr error }{ { name: "Test with digest", @@ -76,9 +77,8 @@ func TestValidateImage(t *testing.T) { expectedImage: model.Image{ Name: "myimg", }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.Errorf(`cannot parse "chickens" value of label diun.enable`), }, - // Test diun.regopt { name: "Set regopt", image: "myimg", @@ -86,7 +86,7 @@ func TestValidateImage(t *testing.T) { "diun.regopt": "foo", }, watchByDef: true, - imageDefaults: model.Image{}, + imageDefaults: &model.ImageDefaults{}, expectedImage: model.Image{ Name: "myimg", RegOpt: "foo", @@ -99,50 +99,18 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.regopt": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", RegOpt: "", }, expectedErr: nil, }, - { - name: "Default regopt", - image: "myimg", - watchByDef: true, - labels: map[string]string{}, - imageDefaults: model.Image{ - RegOpt: "foo", - }, - expectedImage: model.Image{ - Name: "myimg", - RegOpt: "foo", - }, - expectedErr: nil, - }, - { - name: "Override default regopt", - image: "myimg", - watchByDef: true, - labels: map[string]string{ - "diun.regopt": "bar", - }, - imageDefaults: model.Image{ - RegOpt: "foo", - }, - expectedImage: model.Image{ - Name: "myimg", - RegOpt: "bar", - }, - expectedErr: nil, - }, - // Test watch_repo { name: "Include using global settings", image: "myimg", watchByDef: true, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ WatchRepo: utl.NewTrue(), }, expectedImage: model.Image{ @@ -158,11 +126,11 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.watch_repo": "chickens", }, - imageDefaults: model.Image{}, + imageDefaults: &model.ImageDefaults{}, expectedImage: model.Image{ Name: "myimg", }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`cannot parse "chickens" value of label diun.watch_repo`), }, { name: "Override default image values with labels (true > false)", @@ -171,7 +139,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.watch_repo": "false", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ WatchRepo: utl.NewTrue(), }, expectedImage: model.Image{ @@ -187,7 +155,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.watch_repo": "true", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ WatchRepo: utl.NewFalse(), }, expectedImage: model.Image{ @@ -196,15 +164,13 @@ func TestValidateImage(t *testing.T) { }, expectedErr: nil, }, - // Test diun.notify_on { name: "Set valid notify_on", image: "myimg", labels: map[string]string{ "diun.notify_on": "new", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", NotifyOn: []model.NotifyOn{model.NotifyOnNew}, @@ -218,12 +184,11 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.notify_on": "chickens", }, - imageDefaults: model.Image{}, expectedImage: model.Image{ Name: "myimg", NotifyOn: []model.NotifyOn{}, }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`unknown notify status "chickens"`), }, { name: "Set empty notify_on", @@ -232,7 +197,6 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.notify_on": "", }, - imageDefaults: model.Image{}, expectedImage: model.Image{ Name: "myimg", }, @@ -243,7 +207,7 @@ func TestValidateImage(t *testing.T) { image: "myimg", watchByDef: true, labels: map[string]string{}, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ NotifyOn: []model.NotifyOn{model.NotifyOnNew}, }, expectedImage: model.Image{ @@ -259,7 +223,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.notify_on": "update", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ NotifyOn: []model.NotifyOn{model.NotifyOnNew}, }, expectedImage: model.Image{ @@ -268,15 +232,13 @@ func TestValidateImage(t *testing.T) { }, expectedErr: nil, }, - // Test diun.sort_tags { name: "Set valid sort_tags", image: "myimg", labels: map[string]string{ "diun.sort_tags": "semver", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", SortTags: registry.SortTagSemver, @@ -289,12 +251,11 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.sort_tags": "chickens", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`unknown sort tags type "chickens"`), }, { name: "Set empty sort_tags", @@ -302,8 +263,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.sort_tags": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, @@ -314,7 +274,7 @@ func TestValidateImage(t *testing.T) { image: "myimg", watchByDef: true, labels: map[string]string{}, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ SortTags: registry.SortTagSemver, }, expectedImage: model.Image{ @@ -330,7 +290,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.sort_tags": "reverse", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ SortTags: registry.SortTagSemver, }, expectedImage: model.Image{ @@ -339,15 +299,13 @@ func TestValidateImage(t *testing.T) { }, expectedErr: nil, }, - // Test diun.max_tags { name: "Set valid max_tags", image: "myimg", labels: map[string]string{ "diun.max_tags": "10", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", MaxTags: 10, @@ -360,12 +318,11 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.max_tags": "chickens", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`cannot parse "chickens" value of label diun.max_tags`), }, { name: "Set empty max_tags", @@ -373,19 +330,18 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.max_tags": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`cannot parse "" value of label diun.max_tags`), }, { name: "Default max_tags", image: "myimg", watchByDef: true, labels: map[string]string{}, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ MaxTags: 10, }, expectedImage: model.Image{ @@ -401,7 +357,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.max_tags": "11", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ MaxTags: 10, }, expectedImage: model.Image{ @@ -410,15 +366,13 @@ func TestValidateImage(t *testing.T) { }, expectedErr: nil, }, - // Test diun.include_tags { name: "Set include_tags", image: "myimg", labels: map[string]string{ "diun.include_tags": "alpine;ubuntu", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", IncludeTags: []string{"alpine", "ubuntu"}, @@ -431,8 +385,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.include_tags": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", IncludeTags: []string{""}, @@ -444,7 +397,7 @@ func TestValidateImage(t *testing.T) { image: "myimg", watchByDef: true, labels: map[string]string{}, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ IncludeTags: []string{"alpine"}, }, expectedImage: model.Image{ @@ -460,7 +413,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.include_tags": "ubuntu", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ IncludeTags: []string{"alpine"}, }, expectedImage: model.Image{ @@ -469,15 +422,13 @@ func TestValidateImage(t *testing.T) { }, expectedErr: nil, }, - // Test diun.exclude_tags { name: "Set exclude_tags", image: "myimg", labels: map[string]string{ "diun.exclude_tags": "alpine;ubuntu", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", ExcludeTags: []string{"alpine", "ubuntu"}, @@ -490,8 +441,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.exclude_tags": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", ExcludeTags: []string{""}, @@ -503,7 +453,7 @@ func TestValidateImage(t *testing.T) { image: "myimg", watchByDef: true, labels: map[string]string{}, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ ExcludeTags: []string{"alpine"}, }, expectedImage: model.Image{ @@ -519,7 +469,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.exclude_tags": "ubuntu", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ ExcludeTags: []string{"alpine"}, }, expectedImage: model.Image{ @@ -528,15 +478,13 @@ func TestValidateImage(t *testing.T) { }, expectedErr: nil, }, - // Test diun.hub_tpl { name: "Set hub_tpl", image: "myimg", labels: map[string]string{ "diun.hub_tpl": "foo", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", HubTpl: "foo", @@ -549,53 +497,20 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.hub_tpl": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", HubTpl: "", }, expectedErr: nil, }, - { - name: "Default hub_tpl", - image: "myimg", - watchByDef: true, - labels: map[string]string{}, - imageDefaults: model.Image{ - HubTpl: "foo", - }, - expectedImage: model.Image{ - Name: "myimg", - HubTpl: "foo", - }, - expectedErr: nil, - }, - { - name: "Override default hub_tpl", - image: "myimg", - watchByDef: true, - labels: map[string]string{ - "diun.hub_tpl": "bar", - }, - imageDefaults: model.Image{ - HubTpl: "foo", - }, - expectedImage: model.Image{ - Name: "myimg", - HubTpl: "bar", - }, - expectedErr: nil, - }, - // Test diun.hub_link { name: "Set hub_link", image: "myimg", labels: map[string]string{ "diun.hub_link": "foo", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", HubLink: "foo", @@ -608,53 +523,20 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.hub_link": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", HubLink: "", }, expectedErr: nil, }, - { - name: "Default hub_link", - image: "myimg", - watchByDef: true, - labels: map[string]string{}, - imageDefaults: model.Image{ - HubLink: "foo", - }, - expectedImage: model.Image{ - Name: "myimg", - HubLink: "foo", - }, - expectedErr: nil, - }, - { - name: "Override default hub_link", - image: "myimg", - watchByDef: true, - labels: map[string]string{ - "diun.hub_link": "bar", - }, - imageDefaults: model.Image{ - HubLink: "foo", - }, - expectedImage: model.Image{ - Name: "myimg", - HubLink: "bar", - }, - expectedErr: nil, - }, - // Test diun.platform { name: "Set valid platform", image: "myimg", labels: map[string]string{ "diun.platform": "linux/arm/v7", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", Platform: model.ImagePlatform{ @@ -671,12 +553,11 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.platform": "chickens", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`cannot parse "chickens" platform of label diun.platform`), }, { name: "Set empty platform", @@ -684,69 +565,20 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.platform": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", Platform: model.ImagePlatform{}, }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`cannot parse "" platform of label diun.platform`), }, - { - name: "Default platform", - image: "myimg", - watchByDef: true, - labels: map[string]string{}, - imageDefaults: model.Image{ - Platform: model.ImagePlatform{ - OS: "linux", - Arch: "arm", - Variant: "v7", - }, - }, - expectedImage: model.Image{ - Name: "myimg", - Platform: model.ImagePlatform{ - OS: "linux", - Arch: "arm", - Variant: "v7", - }, - }, - expectedErr: nil, - }, - { - name: "Override default platform", - image: "myimg", - watchByDef: true, - labels: map[string]string{ - "diun.platform": "linux/arm/v6", - }, - imageDefaults: model.Image{ - Platform: model.ImagePlatform{ - OS: "linux", - Arch: "arm", - Variant: "v7", - }, - }, - expectedImage: model.Image{ - Name: "myimg", - Platform: model.ImagePlatform{ - OS: "linux", - Arch: "arm", - Variant: "v6", - }, - }, - expectedErr: nil, - }, - // Test diun.metadata { name: "Set valid metadata", image: "myimg", labels: map[string]string{ "diun.metadata.foo123": "bar", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", Metadata: map[string]string{ @@ -761,12 +593,11 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.metadata.lots of chickens": "bar", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, - expectedErr: &invalidLabelError{}, + expectedErr: errors.New(`invalid metadata key "lots of chickens"`), }, { name: "Set empty metadata key", @@ -774,8 +605,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.metadata.": "bar", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, @@ -786,8 +616,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.metadata.foo123": "", }, - watchByDef: true, - imageDefaults: model.Image{}, + watchByDef: true, expectedImage: model.Image{ Name: "myimg", }, @@ -797,7 +626,7 @@ func TestValidateImage(t *testing.T) { image: "myimg", watchByDef: true, labels: map[string]string{}, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ Metadata: map[string]string{ "foo123": "bar", }, @@ -817,7 +646,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.metadata.biz123": "baz", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ Metadata: map[string]string{ "foo123": "bar", }, @@ -838,7 +667,7 @@ func TestValidateImage(t *testing.T) { labels: map[string]string{ "diun.metadata.foo123": "baz", }, - imageDefaults: model.Image{ + imageDefaults: &model.ImageDefaults{ Metadata: map[string]string{ "foo123": "bar", }, @@ -856,7 +685,6 @@ func TestValidateImage(t *testing.T) { for _, tt := range cases { tt := tt t.Run(tt.name, func(t *testing.T) { - t.Parallel() img, err := ValidateImage( tt.image, tt.metadata, @@ -868,12 +696,7 @@ func TestValidateImage(t *testing.T) { assert.NoError(t, err) assert.Equal(t, tt.expectedImage, img) } else { - switch err.(type) { - case *invalidLabelError: - assert.Error(t, err) - default: - assert.Error(t, err) - } + assert.ErrorContains(t, err, tt.expectedErr.Error()) } }) } diff --git a/internal/provider/docker/container.go b/internal/provider/docker/container.go index 8f264847..e5a829d6 100644 --- a/internal/provider/docker/container.go +++ b/internal/provider/docker/container.go @@ -91,7 +91,7 @@ func (c *Client) listContainerImage() []model.Image { Str("ctn_image", imageName). Interface("ctn_labels", ctn.Labels). Msg("Validate image") - image, err := provider.ValidateImage(imageName, metadata(ctn), ctn.Labels, *c.config.WatchByDefault, *c.imageDefaults) + image, err := provider.ValidateImage(imageName, metadata(ctn), ctn.Labels, *c.config.WatchByDefault, c.imageDefaults) if err != nil { c.logger.Error().Err(err). diff --git a/internal/provider/docker/docker.go b/internal/provider/docker/docker.go index 26a7521c..7753cddb 100644 --- a/internal/provider/docker/docker.go +++ b/internal/provider/docker/docker.go @@ -12,11 +12,11 @@ type Client struct { *provider.Client config *model.PrdDocker logger zerolog.Logger - imageDefaults *model.Image + imageDefaults *model.ImageDefaults } // New creates new docker provider instance -func New(config *model.PrdDocker, imageDefaults *model.Image) *provider.Client { +func New(config *model.PrdDocker, imageDefaults *model.ImageDefaults) *provider.Client { return &provider.Client{ Handler: &Client{ config: config, diff --git a/internal/provider/dockerfile/dockerfile.go b/internal/provider/dockerfile/dockerfile.go index cf009b83..8ba6d9d1 100644 --- a/internal/provider/dockerfile/dockerfile.go +++ b/internal/provider/dockerfile/dockerfile.go @@ -12,11 +12,11 @@ type Client struct { *provider.Client config *model.PrdDockerfile logger zerolog.Logger - imageDefaults *model.Image + imageDefaults *model.ImageDefaults } // New creates new dockerfile provider instance -func New(config *model.PrdDockerfile, imageDefaults *model.Image) *provider.Client { +func New(config *model.PrdDockerfile, imageDefaults *model.ImageDefaults) *provider.Client { return &provider.Client{ Handler: &Client{ config: config, diff --git a/internal/provider/dockerfile/image.go b/internal/provider/dockerfile/image.go index c941fd10..78030a57 100644 --- a/internal/provider/dockerfile/image.go +++ b/internal/provider/dockerfile/image.go @@ -32,7 +32,7 @@ func (c *Client) listExtImage() (list []model.Image) { Interface("dfile_comments", fromImage.Comments). Int("dfile_line", fromImage.Line). Msg("Validate image") - image, err := provider.ValidateImage(fromImage.Name, nil, c.extractLabels(fromImage.Comments), true, *c.imageDefaults) + image, err := provider.ValidateImage(fromImage.Name, nil, c.extractLabels(fromImage.Comments), true, c.imageDefaults) if err != nil { c.logger.Error().Err(err). Str("dfile_image", fromImage.Name). diff --git a/internal/provider/file/file.go b/internal/provider/file/file.go index 0f8468b7..77405bbf 100644 --- a/internal/provider/file/file.go +++ b/internal/provider/file/file.go @@ -12,11 +12,11 @@ type Client struct { *provider.Client config *model.PrdFile logger zerolog.Logger - imageDefaults *model.Image + imageDefaults *model.ImageDefaults } // New creates new file provider instance -func New(config *model.PrdFile, imageDefaults *model.Image) *provider.Client { +func New(config *model.PrdFile, imageDefaults *model.ImageDefaults) *provider.Client { return &provider.Client{ Handler: &Client{ config: config, diff --git a/internal/provider/file/file_test.go b/internal/provider/file/file_test.go index c1b3a019..dce29a9d 100644 --- a/internal/provider/file/file_test.go +++ b/internal/provider/file/file_test.go @@ -10,7 +10,7 @@ import ( ) var ( - defaultImageDefaults = model.Image{ + defaultImageDefaults = model.ImageDefaults{ NotifyOn: model.NotifyOnDefaults, SortTags: registry.SortTagReverse, } @@ -173,7 +173,9 @@ func TestListJobDirectory(t *testing.T) { func TestDefaultImageOptions(t *testing.T) { fc := New(&model.PrdFile{ Filename: "./fixtures/dockerhub.yml", - }, &model.Image{WatchRepo: utl.NewTrue()}) + }, &model.ImageDefaults{ + WatchRepo: utl.NewTrue(), + }) for _, job := range fc.ListJob() { assert.True(t, *job.Image.WatchRepo) diff --git a/internal/provider/kubernetes/kubernetes.go b/internal/provider/kubernetes/kubernetes.go index b1c91e36..40469686 100644 --- a/internal/provider/kubernetes/kubernetes.go +++ b/internal/provider/kubernetes/kubernetes.go @@ -12,11 +12,11 @@ type Client struct { *provider.Client config *model.PrdKubernetes logger zerolog.Logger - imageDefaults *model.Image + imageDefaults *model.ImageDefaults } // New creates new kubernetes provider instance -func New(config *model.PrdKubernetes, imageDefaults *model.Image) *provider.Client { +func New(config *model.PrdKubernetes, imageDefaults *model.ImageDefaults) *provider.Client { return &provider.Client{ Handler: &Client{ config: config, diff --git a/internal/provider/kubernetes/pod.go b/internal/provider/kubernetes/pod.go index dd478d15..672c0585 100644 --- a/internal/provider/kubernetes/pod.go +++ b/internal/provider/kubernetes/pod.go @@ -41,7 +41,7 @@ func (c *Client) listPodImage() []model.Image { Str("ctn_image", ctn.Image). Msg("Validate image") - image, err := provider.ValidateImage(ctn.Image, metadata(pod, ctn), pod.Annotations, *c.config.WatchByDefault, *c.imageDefaults) + image, err := provider.ValidateImage(ctn.Image, metadata(pod, ctn), pod.Annotations, *c.config.WatchByDefault, c.imageDefaults) if err != nil { c.logger.Error().Err(err). Str("pod_name", pod.Name). diff --git a/internal/provider/nomad/nomad.go b/internal/provider/nomad/nomad.go index 26d4f21e..a10d0017 100644 --- a/internal/provider/nomad/nomad.go +++ b/internal/provider/nomad/nomad.go @@ -12,11 +12,11 @@ type Client struct { *provider.Client config *model.PrdNomad logger zerolog.Logger - imageDefaults *model.Image + imageDefaults *model.ImageDefaults } // New creates new nomad provider instance -func New(config *model.PrdNomad, imageDefaults *model.Image) *provider.Client { +func New(config *model.PrdNomad, imageDefaults *model.ImageDefaults) *provider.Client { return &provider.Client{ Handler: &Client{ config: config, diff --git a/internal/provider/nomad/task.go b/internal/provider/nomad/task.go index 7a1bec0b..43f34a06 100644 --- a/internal/provider/nomad/task.go +++ b/internal/provider/nomad/task.go @@ -101,7 +101,7 @@ func (c *Client) listTaskImages() []model.Image { c.logger.Error().Err(err).Msg("Cannot merge task metadata") } - image, err := provider.ValidateImage(imageName, metadata(job, taskGroup, task), labels, *c.config.WatchByDefault, *c.imageDefaults) + image, err := provider.ValidateImage(imageName, metadata(job, taskGroup, task), labels, *c.config.WatchByDefault, c.imageDefaults) if err != nil { c.logger.Error(). Err(err). diff --git a/internal/provider/swarm/service.go b/internal/provider/swarm/service.go index d32c9019..be94090a 100644 --- a/internal/provider/swarm/service.go +++ b/internal/provider/swarm/service.go @@ -37,7 +37,7 @@ func (c *Client) listServiceImage() []model.Image { Str("ctn_image", svc.Spec.TaskTemplate.ContainerSpec.Image). Msg("Validate image") - image, err := provider.ValidateImage(svc.Spec.TaskTemplate.ContainerSpec.Image, metadata(svc), svc.Spec.Labels, *c.config.WatchByDefault, *c.imageDefaults) + image, err := provider.ValidateImage(svc.Spec.TaskTemplate.ContainerSpec.Image, metadata(svc), svc.Spec.Labels, *c.config.WatchByDefault, c.imageDefaults) if err != nil { c.logger.Error().Err(err). Str("svc_name", svc.Spec.Name). diff --git a/internal/provider/swarm/swarm.go b/internal/provider/swarm/swarm.go index 56a8ce40..ff227498 100644 --- a/internal/provider/swarm/swarm.go +++ b/internal/provider/swarm/swarm.go @@ -12,11 +12,11 @@ type Client struct { *provider.Client config *model.PrdSwarm logger zerolog.Logger - imageDefaults *model.Image + imageDefaults *model.ImageDefaults } // New creates new swarm provider instance -func New(config *model.PrdSwarm, imageDefaults *model.Image) *provider.Client { +func New(config *model.PrdSwarm, imageDefaults *model.ImageDefaults) *provider.Client { return &provider.Client{ Handler: &Client{ config: config, diff --git a/test/docker5/diun.yml b/test/docker5/diun.yml new file mode 100644 index 00000000..8ac5fef8 --- /dev/null +++ b/test/docker5/diun.yml @@ -0,0 +1,11 @@ +watch: + workers: 20 + schedule: "0 */6 * * *" + imageDefaults: + watchRepo: true + notifyOn: + - new + maxTags: 5 + +providers: + docker: {}