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 (#475)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
parent
697684f67a
commit
fc13b8c22c
14 changed files with 143 additions and 28 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -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
3
codecov.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
comment: false
|
||||
github_checks:
|
||||
annotations: false
|
|
@ -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`) |
|
||||
|
|
|
@ -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`) |
|
||||
|
|
|
@ -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` |
|
||||
|
|
|
@ -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`) |
|
||||
|
|
|
@ -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`) |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue