0
0
Fork 0
mirror of https://github.com/crazy-max/diun.git synced 2025-04-11 06:01:21 +00:00

Allow to choose status to be notified ()

Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2021-08-30 14:15:59 +02:00 committed by GitHub
parent 697684f67a
commit fc13b8c22c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 143 additions and 28 deletions

View file

@ -132,7 +132,7 @@ jobs:
path: ./dist/*
if-no-files-found: error
-
name: Build
name: Build image
uses: docker/bake-action@v1
with:
files: |

3
codecov.yml Normal file
View file

@ -0,0 +1,3 @@
comment: false
github_checks:
annotations: false

View file

@ -177,7 +177,8 @@ You can configure more finely the way to analyze the image of your container thr
| `diun.enable` | | Set to true to enable image analysis of this container |
| `diun.regopt` | | [Registry options](../config/regopts.md) name to use |
| `diun.watch_repo` | `false` | Watch all tags of this container image ([be careful](../faq.md#docker-hub-rate-limits) with this setting) |
| `diun.notify_on` | `new;update` | Semicolon separated list of status to be notified: `new`, `update`. |
| `diun.max_tags` | `0` | Maximum number of tags to watch if `diun.watch_repo` enabled. `0` means all of them |
| `diun.include_tags` | | Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.include_tags` | | Semicolon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semicolon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.platform` | _automatic_ | Platform to use (e.g. `linux/amd64`) |

View file

@ -110,7 +110,8 @@ The following annotations can be added as comments before the target instruction
|-------------------------------|---------------|---------------|
| `diun.regopt` | | [Registry options](../config/regopts.md) name to use |
| `diun.watch_repo` | `false` | Watch all tags of this image |
| `diun.notify_on` | `new;update` | Semicolon separated list of status to be notified: `new`, `update`. |
| `diun.max_tags` | `0` | Maximum number of tags to watch if `watch_repo` enabled. `0` means all of them |
| `diun.include_tags` | | Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.include_tags` | | Semicolon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semicolon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.platform` | _automatic_ | Platform to use (e.g. `linux/amd64`) |

View file

@ -52,9 +52,11 @@ providers:
# Watch crazymax/swarm-cronjob image and assume docker.io registry and latest tag
# with registry options named 'docker.io/crazymax' (image selector).
# Only include tags matching regexp ^1\.2\..*
# Only include tags matching regexp ^1\.2\..* and only be notified on new tag.
- name: crazymax/swarm-cronjob
watch_repo: true
notify_on:
- new
include_tags:
- ^1\.2\..*
@ -175,6 +177,7 @@ The configuration file(s) defines a slice of images to analyze with the followin
| `name` | `latest` | Docker image name to watch using `registry/path:tag` format. If registry omitted, `docker.io` will be used and if tag omitted, `latest` will be used |
| `regopt` | | [Registry options](../config/regopts.md) name to use |
| `watch_repo` | `false` | Watch all tags of this image ([be careful](../faq.md#docker-hub-rate-limits) with this setting) |
| `notify_on` | `new;update` | Semicolon separated list of status to be notified: `new`, `update`. |
| `max_tags` | `0` | Maximum number of tags to watch if `watch_repo` enabled. `0` means all of them |
| `include_tags` | | List of regular expressions to include tags. Can be useful if you enable `watch_repo` |
| `exclude_tags` | | List of regular expressions to exclude tags. Can be useful if you enable `watch_repo` |

View file

@ -286,7 +286,8 @@ You can configure more finely the way to analyze the image of your pods through
| `diun.enable` | | Set to true to enable image analysis of this pod |
| `diun.regopt` | | [Registry options](../config/regopts.md) name to use |
| `diun.watch_repo` | `false` | Watch all tags of this pod image ([be careful](../faq.md#docker-hub-rate-limits) with this setting) |
| `diun.notify_on` | `new;update` | Semicolon separated list of status to be notified: `new`, `update`. |
| `diun.max_tags` | `0` | Maximum number of tags to watch if `diun.watch_repo` enabled. `0` means all of them |
| `diun.include_tags` | | Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.include_tags` | | Semicolon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semicolon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.platform` | _automatic_ | Platform to use (e.g. `linux/amd64`) |

View file

@ -180,7 +180,8 @@ You can configure more finely the way to analyze the image of your service throu
| `diun.enable` | | Set to true to enable image analysis of this service |
| `diun.regopt` | | [Registry options](../config/regopts.md) name to use |
| `diun.watch_repo` | `false` | Watch all tags of this service image ([be careful](../faq.md#docker-hub-rate-limits) with this setting) |
| `diun.notify_on` | `new;update` | Semicolon separated list of status to be notified: `new`, `update`. |
| `diun.max_tags` | `0` | Maximum number of tags to watch if `diun.watch_repo` enabled. `0` means all of them |
| `diun.include_tags` | | Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.include_tags` | | Semicolon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
| `diun.exclude_tags` | | Semicolon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
| `diun.platform` | _automatic_ | Platform to use (e.g. `linux/amd64`) |

View file

@ -14,7 +14,8 @@ FROM gomod AS test
RUN --mount=type=bind,target=. \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic -race ./...
go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic -race ./... && \
go tool cover -func=/tmp/coverage.txt
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage.txt /coverage.txt

View file

@ -102,7 +102,7 @@ func (di *Diun) createJob(job model.Job) {
InsecureTLS: *reg.InsecureTLS,
UserAgent: di.meta.UserAgent,
CompareDigest: *di.cfg.Watch.CompareDigest,
ImageOs: job.Image.Platform.Os,
ImageOs: job.Image.Platform.OS,
ImageArch: job.Image.Platform.Arch,
ImageVariant: job.Image.Platform.Variant,
})
@ -222,6 +222,12 @@ func (di *Diun) runJob(job model.Job) (entry model.NotifEntry) {
return
}
notifyOn := model.NotifyOn(entry.Status)
if !notifyOn.OneOf(job.Image.NotifyOn) {
sublog.Debug().Msgf("Skipping notification (%s not part of specified notify status)", entry.Status)
return
}
di.notif.Send(entry)
return
}

View file

@ -6,6 +6,7 @@ type Image struct {
Platform ImagePlatform `yaml:"platform,omitempty" json:",omitempty"`
RegOpt string `yaml:"regopt,omitempty" json:",omitempty"`
WatchRepo bool `yaml:"watch_repo,omitempty" json:",omitempty"`
NotifyOn []NotifyOn `yaml:"notify_on,omitempty" json:",omitempty"`
MaxTags int `yaml:"max_tags,omitempty" json:",omitempty"`
IncludeTags []string `yaml:"include_tags,omitempty" json:",omitempty"`
ExcludeTags []string `yaml:"exclude_tags,omitempty" json:",omitempty"`
@ -14,12 +15,12 @@ type Image struct {
// ImagePlatform holds image platform configuration
type ImagePlatform struct {
Os string `yaml:"os,omitempty" json:",omitempty"`
OS string `yaml:"os,omitempty" json:",omitempty"`
Arch string `yaml:"arch,omitempty" json:",omitempty"`
Variant string `yaml:"variant,omitempty" json:",omitempty"`
}
// Image status constants
// ImageStatus constants
const (
ImageStatusNew = ImageStatus("new")
ImageStatusUpdate = ImageStatus("update")
@ -30,3 +31,33 @@ const (
// ImageStatus holds Docker image status analysis
type ImageStatus string
// NotifyOn constants
const (
NotifyOnNew = NotifyOn(ImageStatusNew)
NotifyOnUpdate = NotifyOn(ImageStatusUpdate)
)
// NotifyOn holds notify status type
type NotifyOn string
// NotifyOnDefaults are the default notify status
var NotifyOnDefaults = []NotifyOn{
NotifyOnNew,
NotifyOnUpdate,
}
// Valid checks notify status is valid
func (ns *NotifyOn) Valid() bool {
return ns.OneOf(NotifyOnDefaults)
}
// OneOf checks if notify status is one of the values in the list
func (ns *NotifyOn) OneOf(nsl []NotifyOn) bool {
for _, n := range nsl {
if n == *ns {
return true
}
}
return false
}

View file

@ -15,7 +15,8 @@ func ValidateImage(image string, labels map[string]string, watchByDef bool) (img
image = image[:i]
}
img = model.Image{
Name: image,
Name: image,
NotifyOn: model.NotifyOnDefaults,
}
if enableStr, ok := labels["diun.enable"]; ok {
@ -38,6 +39,18 @@ func ValidateImage(image string, labels map[string]string, watchByDef bool) (img
if img.WatchRepo, err = strconv.ParseBool(value); err != nil {
return img, fmt.Errorf("cannot parse %s value of label %s", value, key)
}
case "diun.notify_on":
if len(value) == 0 {
break
}
img.NotifyOn = []model.NotifyOn{}
for _, no := range strings.Split(value, ";") {
notifyOn := model.NotifyOn(no)
if !notifyOn.Valid() {
return img, fmt.Errorf("unknown notify status %q", value)
}
img.NotifyOn = append(img.NotifyOn, notifyOn)
}
case "diun.max_tags":
if img.MaxTags, err = strconv.Atoi(value); err != nil {
return img, fmt.Errorf("cannot parse %s value of label %s", value, key)
@ -54,7 +67,7 @@ func ValidateImage(image string, labels map[string]string, watchByDef bool) (img
return img, fmt.Errorf("cannot parse %s platform of label %s", value, key)
}
img.Platform = model.ImagePlatform{
Os: platform.OS,
OS: platform.OS,
Arch: platform.Architecture,
Variant: platform.Variant,
}

View file

@ -13,8 +13,9 @@ var (
{
Provider: "file",
Image: model.Image{
Name: "jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0",
RegOpt: "bintrayoptions",
Name: "jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0",
RegOpt: "bintrayoptions",
NotifyOn: model.NotifyOnDefaults,
},
},
{
@ -22,7 +23,10 @@ var (
Image: model.Image{
Name: "docker.bintray.io/jfrog/xray-server:2.8.6",
WatchRepo: true,
MaxTags: 50,
NotifyOn: []model.NotifyOn{
model.NotifyOnNew,
},
MaxTags: 50,
},
},
}
@ -30,8 +34,9 @@ var (
{
Provider: "file",
Image: model.Image{
Name: "docker.io/crazymax/nextcloud:latest",
RegOpt: "myregistry",
Name: "docker.io/crazymax/nextcloud:latest",
RegOpt: "myregistry",
NotifyOn: model.NotifyOnDefaults,
},
},
{
@ -39,6 +44,7 @@ var (
Image: model.Image{
Name: "crazymax/swarm-cronjob",
WatchRepo: true,
NotifyOn: model.NotifyOnDefaults,
IncludeTags: []string{
`^1\.2\..*`,
},
@ -49,6 +55,7 @@ var (
Image: model.Image{
Name: "docker.io/portainer/portainer",
WatchRepo: true,
NotifyOn: model.NotifyOnDefaults,
MaxTags: 10,
IncludeTags: []string{
`^(0|[1-9]\d*)\..*`,
@ -60,14 +67,16 @@ var (
Image: model.Image{
Name: "traefik",
WatchRepo: true,
NotifyOn: model.NotifyOnDefaults,
},
},
{
Provider: "file",
Image: model.Image{
Name: "alpine",
Name: "alpine",
NotifyOn: model.NotifyOnDefaults,
Platform: model.ImagePlatform{
Os: "linux",
OS: "linux",
Arch: "arm64",
Variant: "v8",
},
@ -76,13 +85,15 @@ var (
{
Provider: "file",
Image: model.Image{
Name: "docker.io/graylog/graylog:3.2.0",
Name: "docker.io/graylog/graylog:3.2.0",
NotifyOn: model.NotifyOnDefaults,
},
},
{
Provider: "file",
Image: model.Image{
Name: "jacobalberty/unifi:5.9",
Name: "jacobalberty/unifi:5.9",
NotifyOn: model.NotifyOnDefaults,
},
},
{
@ -90,6 +101,7 @@ var (
Image: model.Image{
Name: "crazymax/ddns-route53",
WatchRepo: true,
NotifyOn: model.NotifyOnDefaults,
IncludeTags: []string{
`^1\..*`,
},
@ -100,13 +112,15 @@ var (
{
Provider: "file",
Image: model.Image{
Name: "quay.io/coreos/hyperkube",
Name: "quay.io/coreos/hyperkube",
NotifyOn: model.NotifyOnDefaults,
},
},
{
Provider: "file",
Image: model.Image{
Name: "quay.io/coreos/hyperkube:v1.1.7-coreos.1",
Name: "quay.io/coreos/hyperkube:v1.1.7-coreos.1",
NotifyOn: model.NotifyOnDefaults,
},
},
}

View file

@ -2,4 +2,6 @@
regopt: bintrayoptions
- name: docker.bintray.io/jfrog/xray-server:2.8.6
watch_repo: true
notify_on:
- new
max_tags: 50

View file

@ -5,7 +5,9 @@ import (
"path/filepath"
"strings"
"github.com/containerd/containerd/platforms"
"github.com/crazy-max/diun/v4/internal/model"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"gopkg.in/yaml.v2"
)
@ -28,7 +30,43 @@ func (c *Client) listFileImage() []model.Image {
c.logger.Error().Err(err).Msgf("Unable to decode into struct %s", file)
continue
}
images = append(images, items...)
for _, item := range items {
// Check NotifyOn
if len(item.NotifyOn) == 0 {
item.NotifyOn = model.NotifyOnDefaults
} else {
for _, no := range item.NotifyOn {
if !no.Valid() {
c.logger.Error().
Str("file", file).
Str("img_name", item.Name).
Msgf("unknown notify status %q", no)
}
}
}
// Check Platform
if item.Platform != (model.ImagePlatform{}) {
_, err = platforms.Parse(platforms.Format(ocispecs.Platform{
OS: item.Platform.OS,
Architecture: item.Platform.Arch,
Variant: item.Platform.Variant,
}))
if err != nil {
c.logger.Error().
Str("file", file).
Str("img_name", item.Name).
Msgf("cannot parse %s platform", platforms.Format(ocispecs.Platform{
OS: item.Platform.OS,
Architecture: item.Platform.Arch,
Variant: item.Platform.Variant,
}))
}
}
images = append(images, item)
}
}
return images