mirror of
https://github.com/crazy-max/diun.git
synced 2025-12-21 13:23:09 +01:00
Move static to file provider (#71)
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
* Internal cron implementation through go routines
|
* Internal cron implementation through go routines
|
||||||
* Worker pool to parallelize analyses
|
* Worker pool to parallelize analyses
|
||||||
* Allow overriding image os and architecture
|
* Allow overriding image os and architecture
|
||||||
* Multi providers available like [Docker](doc/providers/docker.md), [Swarm](doc/providers/swarm.md), [Static](doc/providers/static.md)...
|
* Multi providers available like [Docker](doc/providers/docker.md), [Swarm](doc/providers/swarm.md), [File](doc/providers/file.md)...
|
||||||
* Get notified through Slack, Mail, Telegram and [more](doc/notifications.md)
|
* Get notified through Slack, Mail, Telegram and [more](doc/notifications.md)
|
||||||
* Enhanced logging
|
* Enhanced logging
|
||||||
* Timezone can be changed
|
* Timezone can be changed
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
* Providers
|
* Providers
|
||||||
* [Docker](doc/providers/docker.md)
|
* [Docker](doc/providers/docker.md)
|
||||||
* [Swarm](doc/providers/swarm.md)
|
* [Swarm](doc/providers/swarm.md)
|
||||||
* [Static](doc/providers/static.md)
|
* [File](doc/providers/file.md)
|
||||||
* [Notifications](doc/notifications.md)
|
* [Notifications](doc/notifications.md)
|
||||||
* [FAQ](doc/faq.md)
|
* [FAQ](doc/faq.md)
|
||||||
|
|
||||||
|
|||||||
@@ -58,12 +58,12 @@ func main() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Load and check configuration
|
// Load configuration
|
||||||
cfg, err := config.Load(cli, version)
|
cfg, err := config.Load(cli, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("Cannot load configuration")
|
log.Fatal().Err(err).Msg("Cannot load configuration")
|
||||||
}
|
}
|
||||||
cfg.Display()
|
log.Debug().Msg(cfg.Display())
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
if diun, err = app.New(cfg, location); err != nil {
|
if diun, err = app.New(cfg, location); err != nil {
|
||||||
|
|||||||
@@ -86,36 +86,11 @@ providers:
|
|||||||
# Watch all services on local Swarm cluster
|
# Watch all services on local Swarm cluster
|
||||||
myswarm:
|
myswarm:
|
||||||
watch_by_default: true
|
watch_by_default: true
|
||||||
static:
|
file:
|
||||||
# Watch latest tag of crazymax/nextcloud image on docker.io (DockerHub) with registry ID 'someregistryoptions'.
|
# Watch images from filename ./myimages.yml
|
||||||
- name: docker.io/crazymax/nextcloud:latest
|
filename: ./myimages.yml
|
||||||
regopts_id: someregistryoptions
|
# Watch images from directory ./imagesdir
|
||||||
# Watch 4.0.0 tag of jfrog/artifactory-oss image on frog-docker-reg2.bintray.io (Bintray) with registry ID 'onemore'.
|
directory: ./imagesdir
|
||||||
- name: jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0
|
|
||||||
regopts_id: onemore
|
|
||||||
# Watch coreos/hyperkube image on quay.io (Quay) and assume latest tag.
|
|
||||||
- name: quay.io/coreos/hyperkube
|
|
||||||
# Watch crazymax/swarm-cronjob image and assume docker.io registry and latest tag.
|
|
||||||
# Only include tags matching regexp ^1\.2\..*
|
|
||||||
- name: crazymax/swarm-cronjob
|
|
||||||
watch_repo: true
|
|
||||||
include_tags:
|
|
||||||
- ^1\.2\..*
|
|
||||||
# Watch portainer/portainer image on docker.io (DockerHub) and assume latest tag
|
|
||||||
# Only watch latest 10 tags and include tags matching regexp ^(0|[1-9]\d*)\..*
|
|
||||||
- name: docker.io/portainer/portainer
|
|
||||||
watch_repo: true
|
|
||||||
max_tags: 10
|
|
||||||
include_tags:
|
|
||||||
- ^(0|[1-9]\d*)\..*
|
|
||||||
# Watch alpine image (library) and assume docker.io registry and latest tag.
|
|
||||||
# Force linux/arm64/v8 platform for this image
|
|
||||||
- name: alpine
|
|
||||||
watch_repo: true
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: arm64
|
|
||||||
variant: v8
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
@@ -187,31 +162,6 @@ providers:
|
|||||||
|
|
||||||
### providers
|
### providers
|
||||||
|
|
||||||
* `docker`: Map of Docker standalone engines to watch
|
* [docker](providers/docker.md)
|
||||||
* `<key>`: An unique identifier for this provider.
|
* [swarm](providers/swarm.md)
|
||||||
* `endpoint`: Server address to connect to. Local if empty.
|
* [file](providers/file.md)
|
||||||
* `api_version`: Overrides the client version with the specified one.
|
|
||||||
* `tls_certs_path`: Path to load the TLS certificates from.
|
|
||||||
* `tls_verify`: Controls whether client verifies the server's certificate chain and hostname (default: `true`).
|
|
||||||
* `watch_by_default`: Enable watch by default. If false, containers that don't have `diun.enable=true` label will be ignored (default: `false`).
|
|
||||||
* `watch_stopped`: Include created and exited containers too (default: `false`).
|
|
||||||
|
|
||||||
* `swarm`: Map of Docker Swarm to watch
|
|
||||||
* `<key>`: An unique identifier for this provider.
|
|
||||||
* `endpoint`: Server address to connect to. Local if empty.
|
|
||||||
* `api_version`: Overrides the client version with the specified one.
|
|
||||||
* `tls_certs_path`: Path to load the TLS certificates from.
|
|
||||||
* `tls_verify`: Controls whether client verifies the server's certificate chain and hostname (default: `true`).
|
|
||||||
* `watch_by_default`: Enable watch by default. If false, services that don't have `diun.enable=true` label will be ignored (default: `false`).
|
|
||||||
|
|
||||||
* `static`: Slice of static image to watch
|
|
||||||
* `name`: Docker image name to watch using `registry/path:tag` format. If registry is omitted, `docker.io` will be used and if tag is omitted, `latest` will be used. **required**
|
|
||||||
* `regopts_id`: Registry options ID from `regopts` to use.
|
|
||||||
* `watch_repo`: Watch all tags of this `image` repository (default: `false`).
|
|
||||||
* `max_tags`: Maximum number of tags to watch if `watch_repo` enabled. 0 means all of them (default: `0`).
|
|
||||||
* `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`.
|
|
||||||
* `platform`: Check a custom platform. (default is retrieved dynamically based on your operating system).
|
|
||||||
* `os`: Operating system to use.
|
|
||||||
* `arch`: CPU architecture to use.
|
|
||||||
* `variant`: Variant of the CPU to use.
|
|
||||||
|
|||||||
28
doc/faq.md
28
doc/faq.md
@@ -4,21 +4,11 @@
|
|||||||
|
|
||||||
## No image found in manifest list for architecture [], variant [], OS []
|
## No image found in manifest list for architecture [], variant [], OS []
|
||||||
|
|
||||||
If you encounter this kind of error, you are probably using the [static provider](providers/static.md) containing an image with an erroneous or empty platform. If the platform is not filled in, it will be deduced automatically from the information of your operating system on which Diun is running.
|
If you encounter this kind of error, you are probably using the [file provider](providers/file.md) containing an image with an erroneous or empty platform. If the platform is not filled in, it will be deduced automatically from the information of your operating system on which Diun is running.
|
||||||
|
|
||||||
In the example below, Diun is running (`diun_x.x.x_windows_i386.zip`) on Windows 10 and tries to analyze the `crazymax/cloudflared` image with the detected platform (`windows/386)`:
|
In the example below, Diun is running (`diun_x.x.x_windows_i386.zip`) on Windows 10 and tries to analyze the `crazymax/cloudflared` image with the detected platform (`windows/386)`:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
db:
|
|
||||||
path: diun.db
|
|
||||||
|
|
||||||
watch:
|
|
||||||
workers: 20
|
|
||||||
schedule: "* * * * *"
|
|
||||||
first_check_notif: true
|
|
||||||
|
|
||||||
providers:
|
|
||||||
static:
|
|
||||||
- name: crazymax/cloudflared:2020.2.1
|
- name: crazymax/cloudflared:2020.2.1
|
||||||
watch_repo: true
|
watch_repo: true
|
||||||
```
|
```
|
||||||
@@ -26,23 +16,13 @@ providers:
|
|||||||
But this platform is not supported by this image as you can see [on DockerHub](https://hub.docker.com/layers/crazymax/cloudflared/2020.2.1/images/sha256-137eea4e84ec4c6cb5ceb2017b9788dcd7b04f135d756e1f37e3e6673c0dd9d2?context=explore):
|
But this platform is not supported by this image as you can see [on DockerHub](https://hub.docker.com/layers/crazymax/cloudflared/2020.2.1/images/sha256-137eea4e84ec4c6cb5ceb2017b9788dcd7b04f135d756e1f37e3e6673c0dd9d2?context=explore):
|
||||||
|
|
||||||
```
|
```
|
||||||
Fri, 27 Mar 2020 01:20:03 UTC ERR Cannot run job error="Error choosing image instance: no image found in manifest list for architecture 386, variant , OS windows" provider=static-0
|
Fri, 27 Mar 2020 01:20:03 UTC ERR Cannot run job error="Error choosing image instance: no image found in manifest list for architecture 386, variant , OS windows" provider=file
|
||||||
Fri, 27 Mar 2020 01:20:03 UTC ERR Cannot list tags from registry error="Error choosing image instance: no image found in manifest list for architecture 386, variant , OS windows" image=crazymax/cloudflared:2020.2.1 provider=static-0
|
Fri, 27 Mar 2020 01:20:03 UTC ERR Cannot list tags from registry error="Error choosing image instance: no image found in manifest list for architecture 386, variant , OS windows" image=crazymax/cloudflared:2020.2.1 provider=file
|
||||||
```
|
```
|
||||||
|
|
||||||
You have to force the platform for this image if you are not on a supported platform. For example:
|
You have to force the platform for this image if you are not on a supported platform. For example:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
db:
|
|
||||||
path: diun.db
|
|
||||||
|
|
||||||
watch:
|
|
||||||
workers: 20
|
|
||||||
schedule: "* * * * *"
|
|
||||||
first_check_notif: true
|
|
||||||
|
|
||||||
providers:
|
|
||||||
static:
|
|
||||||
- name: crazymax/cloudflared:2020.2.1
|
- name: crazymax/cloudflared:2020.2.1
|
||||||
watch_repo: true
|
watch_repo: true
|
||||||
platform:
|
platform:
|
||||||
@@ -51,5 +31,5 @@ providers:
|
|||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
Fri, 27 Mar 2020 01:24:33 UTC INF New image found image=docker.io/crazymax/cloudflared:2020.2.1 provider=static-0
|
Fri, 27 Mar 2020 01:24:33 UTC INF New image found image=docker.io/crazymax/cloudflared:2020.2.1 provider=file
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -50,12 +50,11 @@ If you choose `webhook` notification, a HTTP request is sent with a JSON format
|
|||||||
{
|
{
|
||||||
"diun_version": "0.3.0",
|
"diun_version": "0.3.0",
|
||||||
"status": "new",
|
"status": "new",
|
||||||
"provider": "static-0",
|
"provider": "file",
|
||||||
"image": "docker.io/crazymax/swarm-cronjob:0.2.1",
|
"image": "docker.io/crazymax/swarm-cronjob:0.2.1",
|
||||||
"mime_type": "application/vnd.docker.distribution.manifest.v2+json",
|
"mime_type": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
"digest": "sha256:5913d4b5e8dc15430c2f47f40e43ab2ca7f2b8df5eee5db4d5c42311e08dfb79",
|
"digest": "sha256:5913d4b5e8dc15430c2f47f40e43ab2ca7f2b8df5eee5db4d5c42311e08dfb79",
|
||||||
"created": "2019-01-24T10:26:49.152006005Z",
|
"created": "2019-01-24T10:26:49.152006005Z",
|
||||||
"architecture": "amd64",
|
"platform": "linux/amd64"
|
||||||
"os": "linux"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
* [About](#about)
|
* [About](#about)
|
||||||
* [Quick start](#quick-start)
|
* [Quick start](#quick-start)
|
||||||
* [Configuration](#configuration)
|
* [Provider configuration](#provider-configuration)
|
||||||
|
* [Docker labels](#docker-labels)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
The Docker provider allows you to analyze the containers of your standalone Docker instance defined in the [Diun configuration](../configuration.md#providers) to extract the images found and check for updates on the registry.
|
The Docker provider allows you to analyze the containers of your standalone Docker instance to extract the images found and check for updates on the registry.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
@@ -88,9 +89,20 @@ diun_1 | Sat, 14 Dec 2019 15:30:13 CET INF Cron initialized with schedul
|
|||||||
diun_1 | Sat, 14 Dec 2019 15:30:13 CET INF Next run in 29 minutes (2019-12-14 16:00:00 +0100 CET)
|
diun_1 | Sat, 14 Dec 2019 15:30:13 CET INF Next run in 29 minutes (2019-12-14 16:00:00 +0100 CET)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Provider configuration
|
||||||
|
|
||||||
In the same spirit as the [static provider](static.md), you can configure more finely the way to analyze the image of your container. But unlike the static provider, this is done via Docker labels:
|
The Docker provider configuration is map of Docker standalone engines to watch with the following options available:
|
||||||
|
|
||||||
|
* `endpoint`: Server address to connect to. Local if empty.
|
||||||
|
* `api_version`: Overrides the client version with the specified one.
|
||||||
|
* `tls_certs_path`: Path to load the TLS certificates from.
|
||||||
|
* `tls_verify`: Controls whether client verifies the server's certificate chain and hostname (default: `true`).
|
||||||
|
* `watch_by_default`: Enable watch by default. If false, containers that don't have `diun.enable=true` label will be ignored (default: `false`).
|
||||||
|
* `watch_stopped`: Include created and exited containers too (default: `false`).
|
||||||
|
|
||||||
|
## Docker labels
|
||||||
|
|
||||||
|
You can configure more finely the way to analyze the image of your container through Docker labels:
|
||||||
|
|
||||||
* `diun.enable`: Set to true to enable image analysis of this container. Required if `watch_by_default` is disabled for this provider.
|
* `diun.enable`: Set to true to enable image analysis of this container. Required if `watch_by_default` is disabled for this provider.
|
||||||
* `diun.regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
|
* `diun.regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
|
||||||
|
|||||||
171
doc/providers/file.md
Normal file
171
doc/providers/file.md
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
# File provider
|
||||||
|
|
||||||
|
* [About](#about)
|
||||||
|
* [Example](#example)
|
||||||
|
* [Quick start](#quick-start)
|
||||||
|
* [Provider configuration](#provider-configuration)
|
||||||
|
* [filename](#filename)
|
||||||
|
* [directory](#directory)
|
||||||
|
* [YAML configuration file](#yaml-configuration-file)
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
The file provider lets you define Docker images to analyze through a YAML file or a directory.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Register the file provider:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
db:
|
||||||
|
path: diun.db
|
||||||
|
|
||||||
|
watch:
|
||||||
|
workers: 20
|
||||||
|
schedule: "* * * * *"
|
||||||
|
|
||||||
|
regopts:
|
||||||
|
someregistryoptions:
|
||||||
|
username: foo
|
||||||
|
password: bar
|
||||||
|
timeout: 20
|
||||||
|
onemore:
|
||||||
|
username: foo2
|
||||||
|
password: bar2
|
||||||
|
insecure_tls: true
|
||||||
|
|
||||||
|
providers:
|
||||||
|
file:
|
||||||
|
filename: /path/to/config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
```yml
|
||||||
|
### /path/to/config.yml
|
||||||
|
|
||||||
|
# Watch latest tag of crazymax/nextcloud image on docker.io (DockerHub) with registry ID 'someregistryoptions'.
|
||||||
|
- name: docker.io/crazymax/nextcloud:latest
|
||||||
|
regopts_id: someregistryoptions
|
||||||
|
|
||||||
|
# Watch 4.0.0 tag of jfrog/artifactory-oss image on frog-docker-reg2.bintray.io (Bintray) with registry ID 'onemore'.
|
||||||
|
- name: jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0
|
||||||
|
regopts_id: onemore
|
||||||
|
|
||||||
|
# Watch coreos/hyperkube image on quay.io (Quay) and assume latest tag.
|
||||||
|
- name: quay.io/coreos/hyperkube
|
||||||
|
|
||||||
|
# Watch crazymax/swarm-cronjob image and assume docker.io registry and latest tag.
|
||||||
|
# Only include tags matching regexp ^1\.2\..*
|
||||||
|
- name: crazymax/swarm-cronjob
|
||||||
|
watch_repo: true
|
||||||
|
include_tags:
|
||||||
|
- ^1\.2\..*
|
||||||
|
|
||||||
|
# Watch portainer/portainer image on docker.io (DockerHub) and assume latest tag
|
||||||
|
# Only watch latest 10 tags and include tags matching regexp ^(0|[1-9]\d*)\..*
|
||||||
|
- name: docker.io/portainer/portainer
|
||||||
|
watch_repo: true
|
||||||
|
max_tags: 10
|
||||||
|
include_tags:
|
||||||
|
- ^(0|[1-9]\d*)\..*
|
||||||
|
|
||||||
|
# Watch alpine image (library) and assume docker.io registry and latest tag.
|
||||||
|
# Force linux/arm64/v8 platform for this image
|
||||||
|
- name: alpine
|
||||||
|
watch_repo: true
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: arm64
|
||||||
|
variant: v8
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
Let's take a look with a simple example:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
db:
|
||||||
|
path: diun.db
|
||||||
|
|
||||||
|
watch:
|
||||||
|
workers: 20
|
||||||
|
schedule: "* * * * *"
|
||||||
|
|
||||||
|
regopts:
|
||||||
|
jfrog:
|
||||||
|
username: foo
|
||||||
|
password: bar
|
||||||
|
|
||||||
|
providers:
|
||||||
|
file:
|
||||||
|
filename: /path/to/config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
```yml
|
||||||
|
# /path/to/config.yml
|
||||||
|
- name: crazymax/cloudflared
|
||||||
|
watch_repo: true
|
||||||
|
- name: docker.bintray.io/jfrog/xray-mongo:3.2.6
|
||||||
|
regopts_id: jfrog
|
||||||
|
```
|
||||||
|
|
||||||
|
Here we want to analyze all tags of `crazymax/cloudflared` and `docker.bintray.io/jfrog/xray-mongo:3.2.6` tag. Now let's start Diun:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ diun --config diun.yml
|
||||||
|
Sat, 14 Dec 2019 15:32:23 UTC INF Starting Diun 2.0.0
|
||||||
|
Sat, 14 Dec 2019 15:32:23 UTC INF Found 2 image(s) to analyze... provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:25 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:latest provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.11.3 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.11.0 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.10.1 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.9.0 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.9.2 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.10.2 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.11.2 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.9.1 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.10.4 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=docker.bintray.io/jfrog/xray-mongo:3.2.6 image=docker.bintray.io/jfrog/xray-mongo:3.2.6 provider=file
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF Cron initialized with schedule * * * * *
|
||||||
|
Sat, 14 Dec 2019 15:32:28 UTC INF Next run in 31 seconds (2019-12-14 15:33:00 +0000 UTC)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Provider configuration
|
||||||
|
|
||||||
|
### filename
|
||||||
|
|
||||||
|
Defines the path to the [configuration file](#yaml-configuration-file).
|
||||||
|
|
||||||
|
> :warning: `filename` and `directory` are mutually exclusive.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
providers:
|
||||||
|
file:
|
||||||
|
filename: /path/to/config/conf.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### directory
|
||||||
|
|
||||||
|
Defines the path to the directory that contains the [configuration files](#yaml-configuration-file) (`*.yml` or `*.yaml`).
|
||||||
|
|
||||||
|
> :warning: `filename` and `directory` are mutually exclusive.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
providers:
|
||||||
|
file:
|
||||||
|
directory: /path/to/config
|
||||||
|
```
|
||||||
|
|
||||||
|
## YAML configuration file
|
||||||
|
|
||||||
|
The configuration file(s) defines a slice of images to analyze with the following fields:
|
||||||
|
|
||||||
|
* `name`: 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. **required**
|
||||||
|
* `regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
|
||||||
|
* `watch_repo`: Watch all tags of this `image` repository (default: `false`).
|
||||||
|
* `max_tags`: Maximum number of tags to watch if `watch_repo` enabled. 0 means all of them (default: `0`).
|
||||||
|
* `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`.
|
||||||
|
* `platform`: Check a custom platform. (default will retrieve platform dynamically based on your operating system).
|
||||||
|
* `os`: Operating system to use.
|
||||||
|
* `arch`: CPU architecture to use.
|
||||||
|
* `variant`: Variant of the CPU to use.
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# Static provider
|
|
||||||
|
|
||||||
* [About](#about)
|
|
||||||
* [Quick start](#quick-start)
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
The static provider is the most basic way to analyse Docker images. Nothing special to see here as everything is configured through the [providers field](../configuration.md#providers).
|
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
But let's take a look with a simple example:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
db:
|
|
||||||
path: diun.db
|
|
||||||
|
|
||||||
watch:
|
|
||||||
workers: 20
|
|
||||||
schedule: "* * * * *"
|
|
||||||
|
|
||||||
regopts:
|
|
||||||
jfrog:
|
|
||||||
username: foo
|
|
||||||
password: bar
|
|
||||||
|
|
||||||
providers:
|
|
||||||
static:
|
|
||||||
- name: crazymax/cloudflared
|
|
||||||
watch_repo: true
|
|
||||||
- name: docker.bintray.io/jfrog/xray-mongo:3.2.6
|
|
||||||
regopts_id: jfrog
|
|
||||||
```
|
|
||||||
|
|
||||||
Here we want to analyze all tags of `crazymax/cloudflared` and `docker.bintray.io/jfrog/xray-mongo:3.2.6` tag. Now let's start Diun:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ diun --config diun.yml
|
|
||||||
Sat, 14 Dec 2019 15:32:23 UTC INF Starting Diun 2.0.0
|
|
||||||
Sat, 14 Dec 2019 15:32:23 UTC INF Found 2 static provider(s) to analyze...
|
|
||||||
Sat, 14 Dec 2019 15:32:25 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:latest provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.11.3 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.11.0 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.10.1 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.9.0 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.9.2 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.10.2 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.11.2 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.9.1 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=crazymax/cloudflared image=docker.io/crazymax/cloudflared:2019.10.4 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF New image found id=docker.bintray.io/jfrog/xray-mongo:3.2.6 image=docker.bintray.io/jfrog/xray-mongo:3.2.6 provider=static
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF Cron initialized with schedule * * * * *
|
|
||||||
Sat, 14 Dec 2019 15:32:28 UTC INF Next run in 31 seconds (2019-12-14 15:33:00 +0000 UTC)
|
|
||||||
```
|
|
||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
* [About](#about)
|
* [About](#about)
|
||||||
* [Quick start](#quick-start)
|
* [Quick start](#quick-start)
|
||||||
* [Configuration](#configuration)
|
* [Provider configuration](#provider-configuration)
|
||||||
|
* [Docker labels](#docker-labels)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
The Swarm provider is closely linked to the [Docker provider](docker.md) except that it allows you to analyze the services of your Swarm cluster defined in the [Diun configuration](../configuration.md#providers) to extract the images found and check for updates on the registry.
|
The Swarm provider is closely linked to the [Docker provider](docker.md) except that it allows you to analyze the services of your Swarm cluster to extract the images found and check for updates on the registry.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
@@ -103,9 +104,19 @@ diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:20:02 CET INF N
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Provider configuration
|
||||||
|
|
||||||
In the same spirit as the [static provider](static.md), you can configure more finely the way to analyze the image of your service. But unlike the static provider, this is done via Docker labels:
|
The Swarm provider configuration is a map of Docker Swarm clusters to watch with the following options available:
|
||||||
|
|
||||||
|
* `endpoint`: Server address to connect to. Local if empty.
|
||||||
|
* `api_version`: Overrides the client version with the specified one.
|
||||||
|
* `tls_certs_path`: Path to load the TLS certificates from.
|
||||||
|
* `tls_verify`: Controls whether client verifies the server's certificate chain and hostname (default: `true`).
|
||||||
|
* `watch_by_default`: Enable watch by default. If false, services that don't have `diun.enable=true` label will be ignored (default: `false`).
|
||||||
|
|
||||||
|
## Docker labels
|
||||||
|
|
||||||
|
You can configure more finely the way to analyze the image of your service through Docker labels:
|
||||||
|
|
||||||
* `diun.enable`: Set to true to enable image analysis of this container. Required if `watch_by_default` is disabled for this provider.
|
* `diun.enable`: Set to true to enable image analysis of this container. Required if `watch_by_default` is disabled for this provider.
|
||||||
* `diun.regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
|
* `diun.regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/crazy-max/diun/internal/model"
|
"github.com/crazy-max/diun/internal/model"
|
||||||
"github.com/crazy-max/diun/internal/notif"
|
"github.com/crazy-max/diun/internal/notif"
|
||||||
dockerPrd "github.com/crazy-max/diun/internal/provider/docker"
|
dockerPrd "github.com/crazy-max/diun/internal/provider/docker"
|
||||||
staticPrd "github.com/crazy-max/diun/internal/provider/static"
|
filePrd "github.com/crazy-max/diun/internal/provider/file"
|
||||||
swarmPrd "github.com/crazy-max/diun/internal/provider/swarm"
|
swarmPrd "github.com/crazy-max/diun/internal/provider/swarm"
|
||||||
"github.com/hako/durafmt"
|
"github.com/hako/durafmt"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
@@ -127,8 +127,8 @@ func (di *Diun) Run() {
|
|||||||
di.createJob(job)
|
di.createJob(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static provider
|
// File provider
|
||||||
for _, job := range staticPrd.New(di.cfg.Providers.Static).ListJob() {
|
for _, job := range filePrd.New(di.cfg.Providers.File).ListJob() {
|
||||||
di.createJob(job)
|
di.createJob(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
@@ -12,7 +11,7 @@ import (
|
|||||||
"github.com/crazy-max/diun/internal/model"
|
"github.com/crazy-max/diun/internal/model"
|
||||||
"github.com/crazy-max/diun/pkg/utl"
|
"github.com/crazy-max/diun/pkg/utl"
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -123,11 +122,9 @@ func (cfg *Config) validate() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, prdStatic := range cfg.Providers.Static {
|
if err := cfg.validateFileProvider(); err != nil {
|
||||||
if err := cfg.validateStaticProvider(key, prdStatic); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.Notif.Mail.Enable {
|
if cfg.Notif.Mail.Enable {
|
||||||
if _, err := mail.ParseAddress(cfg.Notif.Mail.From); err != nil {
|
if _, err := mail.ParseAddress(cfg.Notif.Mail.From); err != nil {
|
||||||
@@ -183,17 +180,22 @@ func (cfg *Config) validateSwarmProvider(id string, prdSwarm model.PrdSwarm) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) validateStaticProvider(key int, prdStatic model.PrdStatic) error {
|
func (cfg *Config) validateFileProvider() error {
|
||||||
if prdStatic.Name == "" {
|
switch {
|
||||||
return fmt.Errorf("name is required for static provider %d", key)
|
case len(cfg.Providers.File.Directory) > 0:
|
||||||
|
if _, err := os.Stat(cfg.Providers.File.Directory); os.IsNotExist(err) {
|
||||||
|
return errors.Wrap(err, "directory not found for file provider")
|
||||||
|
}
|
||||||
|
case len(cfg.Providers.File.Filename) > 0:
|
||||||
|
if _, err := os.Stat(cfg.Providers.File.Filename); os.IsNotExist(err) {
|
||||||
|
return errors.Wrap(err, "filename not found for file provider")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Providers.Static[key] = prdStatic
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display logs configuration in a pretty JSON format
|
// Display configuration in a pretty JSON format
|
||||||
func (cfg *Config) Display() {
|
func (cfg *Config) Display() string {
|
||||||
b, _ := json.MarshalIndent(cfg, "", " ")
|
b, _ := json.MarshalIndent(cfg, "", " ")
|
||||||
log.Debug().Msg(string(b))
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,35 +68,5 @@ providers:
|
|||||||
swarm:
|
swarm:
|
||||||
local_swarm:
|
local_swarm:
|
||||||
watch_by_default: true
|
watch_by_default: true
|
||||||
static:
|
file:
|
||||||
- name: docker.io/crazymax/nextcloud:latest
|
filename: ./dummy.yml
|
||||||
regopts_id: someregopts
|
|
||||||
- name: crazymax/swarm-cronjob
|
|
||||||
watch_repo: true
|
|
||||||
include_tags:
|
|
||||||
- ^1\.2\..*
|
|
||||||
- name: jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0
|
|
||||||
regopts_id: bintrayoptions
|
|
||||||
- name: docker.bintray.io/jfrog/xray-server:2.8.6
|
|
||||||
watch_repo: true
|
|
||||||
max_tags: 50
|
|
||||||
- name: quay.io/coreos/hyperkube
|
|
||||||
- name: docker.io/portainer/portainer
|
|
||||||
watch_repo: true
|
|
||||||
max_tags: 10
|
|
||||||
include_tags:
|
|
||||||
- ^(0|[1-9]\d*)\..*
|
|
||||||
- name: traefik
|
|
||||||
watch_repo: true
|
|
||||||
- name: alpine
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: arm64
|
|
||||||
variant: v8
|
|
||||||
- name: docker.io/graylog/graylog:3.2.0
|
|
||||||
- name: jacobalberty/unifi:5.9
|
|
||||||
- name: quay.io/coreos/hyperkube:v1.1.7-coreos.1
|
|
||||||
- name: crazymax/ddns-route53
|
|
||||||
watch_repo: true
|
|
||||||
include_tags:
|
|
||||||
- ^1\..*
|
|
||||||
|
|||||||
@@ -121,66 +121,8 @@ func TestLoad(t *testing.T) {
|
|||||||
WatchByDefault: true,
|
WatchByDefault: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Static: []model.PrdStatic{
|
File: model.PrdFile{
|
||||||
{
|
Filename: "./dummy.yml",
|
||||||
Name: "docker.io/crazymax/nextcloud:latest",
|
|
||||||
RegOptsID: "someregopts",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "crazymax/swarm-cronjob",
|
|
||||||
WatchRepo: true,
|
|
||||||
IncludeTags: []string{
|
|
||||||
`^1\.2\..*`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0",
|
|
||||||
RegOptsID: "bintrayoptions",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "docker.bintray.io/jfrog/xray-server:2.8.6",
|
|
||||||
WatchRepo: true,
|
|
||||||
MaxTags: 50,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "quay.io/coreos/hyperkube",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "docker.io/portainer/portainer",
|
|
||||||
WatchRepo: true,
|
|
||||||
MaxTags: 10,
|
|
||||||
IncludeTags: []string{
|
|
||||||
`^(0|[1-9]\d*)\..*`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "traefik",
|
|
||||||
WatchRepo: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "alpine",
|
|
||||||
Platform: model.ImagePlatform{
|
|
||||||
Os: "linux",
|
|
||||||
Arch: "arm64",
|
|
||||||
Variant: "v8",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "docker.io/graylog/graylog:3.2.0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "jacobalberty/unifi:5.9",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "quay.io/coreos/hyperkube:v1.1.7-coreos.1",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "crazymax/ddns-route53",
|
|
||||||
WatchRepo: true,
|
|
||||||
IncludeTags: []string{
|
|
||||||
`^1\..*`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -189,8 +131,13 @@ func TestLoad(t *testing.T) {
|
|||||||
for _, tt := range cases {
|
for _, tt := range cases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
cfg, err := config.Load(tt.cli, "test")
|
cfg, err := config.Load(tt.cli, "test")
|
||||||
|
if !tt.wantErr && err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
assert.Equal(t, tt.wantData, cfg)
|
assert.Equal(t, tt.wantData, cfg)
|
||||||
assert.Equal(t, tt.wantErr, err != nil)
|
if !tt.wantErr && cfg != nil {
|
||||||
|
assert.NotEmpty(t, cfg.Display())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
0
internal/config/dummy.yml
Normal file
0
internal/config/dummy.yml
Normal file
@@ -4,7 +4,7 @@ package model
|
|||||||
type Providers struct {
|
type Providers struct {
|
||||||
Docker map[string]PrdDocker `yaml:"docker,omitempty" json:",omitempty"`
|
Docker map[string]PrdDocker `yaml:"docker,omitempty" json:",omitempty"`
|
||||||
Swarm map[string]PrdSwarm `yaml:"swarm,omitempty" json:",omitempty"`
|
Swarm map[string]PrdSwarm `yaml:"swarm,omitempty" json:",omitempty"`
|
||||||
Static []PrdStatic `yaml:"static,omitempty" json:",omitempty"`
|
File PrdFile `yaml:"file,omitempty" json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrdDocker holds docker provider configuration
|
// PrdDocker holds docker provider configuration
|
||||||
@@ -26,5 +26,8 @@ type PrdSwarm struct {
|
|||||||
WatchByDefault bool `yaml:"watch_by_default,omitempty" json:",omitempty"`
|
WatchByDefault bool `yaml:"watch_by_default,omitempty" json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrdStatic holds static provider configuration
|
// PrdFile holds file provider configuration
|
||||||
type PrdStatic Image
|
type PrdFile struct {
|
||||||
|
Filename string `yaml:"filename,omitempty" json:",omitempty"`
|
||||||
|
Directory string `yaml:"directory,omitempty" json:",omitempty"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/crazy-max/diun/internal/model"
|
"github.com/crazy-max/diun/internal/model"
|
||||||
"github.com/crazy-max/diun/internal/provider"
|
"github.com/crazy-max/diun/internal/provider"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -12,13 +13,17 @@ import (
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
*provider.Client
|
*provider.Client
|
||||||
elts map[string]model.PrdDocker
|
elts map[string]model.PrdDocker
|
||||||
|
logger zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates new docker provider instance
|
// New creates new docker provider instance
|
||||||
func New(elts map[string]model.PrdDocker) *provider.Client {
|
func New(elts map[string]model.PrdDocker) *provider.Client {
|
||||||
return &provider.Client{Handler: &Client{
|
return &provider.Client{
|
||||||
|
Handler: &Client{
|
||||||
elts: elts,
|
elts: elts,
|
||||||
}}
|
logger: log.With().Str("provider", "docker").Logger(),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListJob returns job list to process
|
// ListJob returns job list to process
|
||||||
@@ -27,7 +32,7 @@ func (c *Client) ListJob() []model.Job {
|
|||||||
return []model.Job{}
|
return []model.Job{}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msgf("Found %d docker provider(s) to analyze...", len(c.elts))
|
c.logger.Info().Msgf("Found %d image(s) to analyze", len(c.elts))
|
||||||
var list []model.Job
|
var list []model.Job
|
||||||
for id, elt := range c.elts {
|
for id, elt := range c.elts {
|
||||||
for _, img := range c.listContainerImage(id, elt) {
|
for _, img := range c.listContainerImage(id, elt) {
|
||||||
|
|||||||
103
internal/provider/file/file.go
Normal file
103
internal/provider/file/file.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/crazy-max/diun/internal/model"
|
||||||
|
"github.com/crazy-max/diun/internal/provider"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client represents an active file provider object
|
||||||
|
type Client struct {
|
||||||
|
*provider.Client
|
||||||
|
item model.PrdFile
|
||||||
|
logger zerolog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates new file provider instance
|
||||||
|
func New(item model.PrdFile) *provider.Client {
|
||||||
|
return &provider.Client{
|
||||||
|
Handler: &Client{
|
||||||
|
item: item,
|
||||||
|
logger: log.With().Str("provider", "file").Logger(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListJob returns job list to process
|
||||||
|
func (c *Client) ListJob() []model.Job {
|
||||||
|
images := c.loadImages()
|
||||||
|
if len(images) == 0 {
|
||||||
|
return []model.Job{}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.logger.Info().Msgf("Found %d image(s) to analyze", len(images))
|
||||||
|
var list []model.Job
|
||||||
|
for _, elt := range images {
|
||||||
|
list = append(list, model.Job{
|
||||||
|
Provider: "file",
|
||||||
|
Image: elt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) loadImages() []model.Image {
|
||||||
|
var images []model.Image
|
||||||
|
|
||||||
|
files := c.getFiles()
|
||||||
|
if len(files) == 0 {
|
||||||
|
return []model.Image{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
var items []model.Image
|
||||||
|
bytes, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error().Err(err).Msgf("Unable to read config file %s", file)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := yaml.UnmarshalStrict(bytes, &items); err != nil {
|
||||||
|
c.logger.Error().Err(err).Msgf("Unable to decode into struct %s", file)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
images = append(images, items...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return images
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getFiles() []string {
|
||||||
|
var files []string
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(c.item.Directory) > 0:
|
||||||
|
fileList, err := ioutil.ReadDir(c.item.Directory)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error().Err(err).Msgf("Unable to read directory %s", c.item.Directory)
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
for _, file := range fileList {
|
||||||
|
if file.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch strings.ToLower(filepath.Ext(file.Name())) {
|
||||||
|
case ".yaml", ".yml":
|
||||||
|
// noop
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
files = append(files, filepath.Join(c.item.Directory, file.Name()))
|
||||||
|
}
|
||||||
|
case len(c.item.Filename) > 0:
|
||||||
|
files = append(files, c.item.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
return files
|
||||||
|
}
|
||||||
127
internal/provider/file/file_test.go
Normal file
127
internal/provider/file/file_test.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package file_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/crazy-max/diun/internal/model"
|
||||||
|
"github.com/crazy-max/diun/internal/provider/file"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bintrayFile = []model.Job{
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0",
|
||||||
|
RegOptsID: "bintrayoptions",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "docker.bintray.io/jfrog/xray-server:2.8.6",
|
||||||
|
WatchRepo: true,
|
||||||
|
MaxTags: 50,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
dockerhubFile = []model.Job{
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "docker.io/crazymax/nextcloud:latest",
|
||||||
|
RegOptsID: "someregopts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "crazymax/swarm-cronjob",
|
||||||
|
WatchRepo: true,
|
||||||
|
IncludeTags: []string{
|
||||||
|
`^1\.2\..*`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "docker.io/portainer/portainer",
|
||||||
|
WatchRepo: true,
|
||||||
|
MaxTags: 10,
|
||||||
|
IncludeTags: []string{
|
||||||
|
`^(0|[1-9]\d*)\..*`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "traefik",
|
||||||
|
WatchRepo: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "alpine",
|
||||||
|
Platform: model.ImagePlatform{
|
||||||
|
Os: "linux",
|
||||||
|
Arch: "arm64",
|
||||||
|
Variant: "v8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "docker.io/graylog/graylog:3.2.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "jacobalberty/unifi:5.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "crazymax/ddns-route53",
|
||||||
|
WatchRepo: true,
|
||||||
|
IncludeTags: []string{
|
||||||
|
`^1\..*`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
quayFile = []model.Job{
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "quay.io/coreos/hyperkube",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Provider: "file",
|
||||||
|
Image: model.Image{
|
||||||
|
Name: "quay.io/coreos/hyperkube:v1.1.7-coreos.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestListJobFilename(t *testing.T) {
|
||||||
|
fc := file.New(model.PrdFile{
|
||||||
|
Filename: "./test/dockerhub.yml",
|
||||||
|
})
|
||||||
|
assert.Equal(t, dockerhubFile, fc.ListJob())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListJobDirectory(t *testing.T) {
|
||||||
|
fc := file.New(model.PrdFile{
|
||||||
|
Directory: "./test",
|
||||||
|
})
|
||||||
|
assert.Equal(t, append(append(bintrayFile, dockerhubFile...), quayFile...), fc.ListJob())
|
||||||
|
}
|
||||||
5
internal/provider/file/test/bintray.yml
Normal file
5
internal/provider/file/test/bintray.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
- name: jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0
|
||||||
|
regopts_id: bintrayoptions
|
||||||
|
- name: docker.bintray.io/jfrog/xray-server:2.8.6
|
||||||
|
watch_repo: true
|
||||||
|
max_tags: 50
|
||||||
24
internal/provider/file/test/dockerhub.yml
Normal file
24
internal/provider/file/test/dockerhub.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
- name: docker.io/crazymax/nextcloud:latest
|
||||||
|
regopts_id: someregopts
|
||||||
|
- name: crazymax/swarm-cronjob
|
||||||
|
watch_repo: true
|
||||||
|
include_tags:
|
||||||
|
- ^1\.2\..*
|
||||||
|
- name: docker.io/portainer/portainer
|
||||||
|
watch_repo: true
|
||||||
|
max_tags: 10
|
||||||
|
include_tags:
|
||||||
|
- ^(0|[1-9]\d*)\..*
|
||||||
|
- name: traefik
|
||||||
|
watch_repo: true
|
||||||
|
- name: alpine
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: arm64
|
||||||
|
variant: v8
|
||||||
|
- name: docker.io/graylog/graylog:3.2.0
|
||||||
|
- name: jacobalberty/unifi:5.9
|
||||||
|
- name: crazymax/ddns-route53
|
||||||
|
watch_repo: true
|
||||||
|
include_tags:
|
||||||
|
- ^1\..*
|
||||||
2
internal/provider/file/test/quay.yml
Normal file
2
internal/provider/file/test/quay.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
- name: quay.io/coreos/hyperkube
|
||||||
|
- name: quay.io/coreos/hyperkube:v1.1.7-coreos.1
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package static
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/crazy-max/diun/internal/model"
|
|
||||||
"github.com/crazy-max/diun/internal/provider"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Client represents an active static provider object
|
|
||||||
type Client struct {
|
|
||||||
*provider.Client
|
|
||||||
elts []model.PrdStatic
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates new static provider instance
|
|
||||||
func New(elts []model.PrdStatic) *provider.Client {
|
|
||||||
return &provider.Client{Handler: &Client{
|
|
||||||
elts: elts,
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListJob returns job list to process
|
|
||||||
func (c *Client) ListJob() []model.Job {
|
|
||||||
if len(c.elts) == 0 {
|
|
||||||
return []model.Job{}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Msgf("Found %d static provider(s) to analyze...", len(c.elts))
|
|
||||||
var list []model.Job
|
|
||||||
for key, elt := range c.elts {
|
|
||||||
list = append(list, model.Job{
|
|
||||||
Provider: fmt.Sprintf("static-%d", key),
|
|
||||||
Image: model.Image(elt),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/crazy-max/diun/internal/model"
|
"github.com/crazy-max/diun/internal/model"
|
||||||
"github.com/crazy-max/diun/internal/provider"
|
"github.com/crazy-max/diun/internal/provider"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -12,13 +13,17 @@ import (
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
*provider.Client
|
*provider.Client
|
||||||
elts map[string]model.PrdSwarm
|
elts map[string]model.PrdSwarm
|
||||||
|
logger zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates new swarm provider instance
|
// New creates new swarm provider instance
|
||||||
func New(elts map[string]model.PrdSwarm) *provider.Client {
|
func New(elts map[string]model.PrdSwarm) *provider.Client {
|
||||||
return &provider.Client{Handler: &Client{
|
return &provider.Client{
|
||||||
|
Handler: &Client{
|
||||||
elts: elts,
|
elts: elts,
|
||||||
}}
|
logger: log.With().Str("provider", "swarm").Logger(),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListJob returns job list to process
|
// ListJob returns job list to process
|
||||||
@@ -27,7 +32,7 @@ func (c *Client) ListJob() []model.Job {
|
|||||||
return []model.Job{}
|
return []model.Job{}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msgf("Found %d swarm provider(s) to analyze...", len(c.elts))
|
c.logger.Info().Msgf("Found %d image(s) to analyze", len(c.elts))
|
||||||
var list []model.Job
|
var list []model.Job
|
||||||
for id, elt := range c.elts {
|
for id, elt := range c.elts {
|
||||||
for _, img := range c.listServiceImage(id, elt) {
|
for _, img := range c.listServiceImage(id, elt) {
|
||||||
|
|||||||
Reference in New Issue
Block a user