mirror of
https://github.com/crazy-max/diun.git
synced 2025-04-10 22:00:13 +00:00
Remove support of multi Docker and Swarm providers
This commit is contained in:
parent
6da156cd07
commit
a6a231ac06
14 changed files with 204 additions and 208 deletions
doc
internal
config
model
provider
pkg/utl
|
@ -10,8 +10,6 @@
|
|||
|
||||
## Overview
|
||||
|
||||
Here is a YAML structure example:
|
||||
|
||||
```yml
|
||||
db:
|
||||
path: diun.db
|
||||
|
@ -83,21 +81,10 @@ regopts:
|
|||
|
||||
providers:
|
||||
docker:
|
||||
# Watch only labeled containers on local Docker engine
|
||||
local:
|
||||
watch_stopped: true
|
||||
# Watch all containers on 10.0.0.1:2375
|
||||
remote:
|
||||
endpoint: tcp://10.0.0.1:2375
|
||||
watch_by_default: true
|
||||
watch_stopped: true
|
||||
swarm:
|
||||
# Watch all services on local Swarm cluster
|
||||
myswarm:
|
||||
watch_by_default: true
|
||||
watch_by_default: true
|
||||
file:
|
||||
# Watch images from filename ./myimages.yml
|
||||
filename: ./myimages.yml
|
||||
# Watch images from directory ./imagesdir
|
||||
directory: ./imagesdir
|
||||
```
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
## About
|
||||
|
||||
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.
|
||||
The Docker provider allows you to analyze the containers of your Docker instance to extract images found and check for updates on the registry.
|
||||
|
||||
## Quick start
|
||||
|
||||
|
@ -22,8 +22,7 @@ watch:
|
|||
|
||||
providers:
|
||||
docker:
|
||||
mydocker:
|
||||
watch_stopped: true
|
||||
watch_stopped: true
|
||||
```
|
||||
|
||||
Here we use a single Docker provider with a minimum configuration to analyze labeled containers (watch by default disabled), even stopped ones, of your local Docker instance.
|
||||
|
@ -64,7 +63,7 @@ services:
|
|||
restart: always
|
||||
```
|
||||
|
||||
As an example we use [crazymax/cloudflared:latest](https://github.com/crazy-max/docker-cloudflared) Docker image. A few [labels](#configuration) are added to configure the image analysis of this container for Diun. Now start this composition with `docker-composes up -d` and take a look at the logs:
|
||||
As an example we use [crazymax/cloudflared:latest](https://github.com/crazy-max/docker-cloudflared) Docker image. A few [labels](#docker-labels) are added to configure the image analysis of this container for Diun. Now start this composition with `docker-composes up -d` and take a look at the logs:
|
||||
|
||||
```
|
||||
$ docker-compose logs -f
|
||||
|
@ -74,7 +73,7 @@ cloudflared | time="2019-12-14T15:30:07+01:00" level=info msg="Adding DNS ups
|
|||
cloudflared | time="2019-12-14T15:30:07+01:00" level=info msg="Starting metrics server" addr="[::]:49312"
|
||||
cloudflared | time="2019-12-14T15:30:07+01:00" level=info msg="Starting DNS over HTTPS proxy server" addr="dns://0.0.0.0:5053"
|
||||
diun_1 | Sat, 14 Dec 2019 15:30:07 CET INF Starting Diun v2.0.0
|
||||
diun_1 | Sat, 14 Dec 2019 15:30:07 CET INF Found 1 docker provider(s) to analyze...
|
||||
diun_1 | Sat, 14 Dec 2019 15:30:07 CET INF Found 1 image(s) to analyze provider=docker
|
||||
diun_1 | Sat, 14 Dec 2019 15:30:10 CET INF New image found id=mydocker image=docker.io/crazymax/cloudflared:latest provider=docker
|
||||
diun_1 | Sat, 14 Dec 2019 15:30:12 CET INF New image found id=mydocker image=docker.io/crazymax/cloudflared:2019.9.0 provider=docker
|
||||
diun_1 | Sat, 14 Dec 2019 15:30:12 CET INF New image found id=mydocker image=docker.io/crazymax/cloudflared:2019.9.1 provider=docker
|
||||
|
@ -91,8 +90,6 @@ diun_1 | Sat, 14 Dec 2019 15:30:13 CET INF Next run in 29 minutes (2019-
|
|||
|
||||
## Provider configuration
|
||||
|
||||
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.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
## 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 to extract the images found and check for updates on the registry.
|
||||
The Swarm provider allows you to analyze the services of your Swarm cluster to extract images found and check for updates on the registry.
|
||||
|
||||
## Quick start
|
||||
|
||||
|
@ -22,10 +22,9 @@ watch:
|
|||
|
||||
providers:
|
||||
swarm:
|
||||
myswarm:
|
||||
```
|
||||
|
||||
Here we use a single Swarm provider with a minimum configuration to analyze labeled containers (watch by default disabled), of your local Swarm cluster.
|
||||
Here we use our local Swarm provider with a minimum configuration to analyze labeled containers (watch by default disabled).
|
||||
|
||||
Now let's create a simple stack for Diun:
|
||||
|
||||
|
@ -69,7 +68,7 @@ services:
|
|||
- "diun.watch_repo=true"
|
||||
```
|
||||
|
||||
As an example we use [nginx](https://hub.docker.com/_/nginx/) Docker image. A few [labels](#configuration) are added to configure the image analysis of this service for Diun. We can now start these 2 stacks:
|
||||
As an example we use [nginx](https://hub.docker.com/_/nginx/) Docker image. A few [labels](#docker-labels) are added to configure the image analysis of this service for Diun. We can now start these 2 stacks:
|
||||
|
||||
```
|
||||
docker stack deploy -c diun.yml diun
|
||||
|
@ -82,7 +81,7 @@ And watch logs of Diun service:
|
|||
$ docker service logs -f diun_diun
|
||||
diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:19:57 CET INF Starting Diun dev
|
||||
diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:19:57 CET INF Starting Diun...
|
||||
diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:19:57 CET INF Found 1 swarm provider(s) to analyze...
|
||||
diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:19:57 CET INF Found 1 image(s) to analyze provider=swarm
|
||||
diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:19:59 CET INF New image found id=myswarm image=docker.io/library/nginx:latest provider=swarm
|
||||
diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:20:01 CET INF New image found id=myswarm image=docker.io/library/nginx:1.9 provider=swarm
|
||||
diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:20:01 CET INF New image found id=myswarm image=docker.io/library/nginx:1.9.4 provider=swarm
|
||||
|
@ -106,8 +105,6 @@ diun_diun.1.i1l4yuiafq6y@docker-desktop | Sat, 14 Dec 2019 16:20:02 CET INF N
|
|||
|
||||
## Provider configuration
|
||||
|
||||
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.
|
||||
|
|
|
@ -23,7 +23,7 @@ type Config struct {
|
|||
Watch model.Watch `yaml:"watch,omitempty"`
|
||||
Notif model.Notif `yaml:"notif,omitempty"`
|
||||
RegOpts map[string]model.RegOpts `yaml:"regopts,omitempty"`
|
||||
Providers model.Providers `yaml:"providers,omitempty"`
|
||||
Providers *model.Providers `yaml:"providers,omitempty"`
|
||||
}
|
||||
|
||||
// Load returns Configuration struct
|
||||
|
@ -116,16 +116,12 @@ func (cfg *Config) validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
for id, prdDocker := range cfg.Providers.Docker {
|
||||
if err := cfg.validateDockerProvider(id, prdDocker); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.validateDockerProvider(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for id, prdSwarm := range cfg.Providers.Swarm {
|
||||
if err := cfg.validateSwarmProvider(id, prdSwarm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.validateSwarmProvider(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cfg.validateFileProvider(); err != nil {
|
||||
|
@ -161,32 +157,42 @@ func (cfg *Config) validateRegOpts(id string, regopts model.RegOpts) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config) validateDockerProvider(id string, prdDocker model.PrdDocker) error {
|
||||
if err := mergo.Merge(&prdDocker, model.PrdDocker{
|
||||
TLSVerify: true,
|
||||
WatchByDefault: false,
|
||||
WatchStopped: false,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("cannot set default values for docker %s provider: %v", id, err)
|
||||
func (cfg *Config) validateDockerProvider() error {
|
||||
if cfg.Providers.Docker == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := mergo.Merge(cfg.Providers.Docker, model.PrdDocker{
|
||||
TLSVerify: utl.NewTrue(),
|
||||
WatchByDefault: utl.NewFalse(),
|
||||
WatchStopped: utl.NewFalse(),
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "cannot set default values for docker provider")
|
||||
}
|
||||
|
||||
cfg.Providers.Docker[id] = prdDocker
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config) validateSwarmProvider(id string, prdSwarm model.PrdSwarm) error {
|
||||
if err := mergo.Merge(&prdSwarm, model.PrdSwarm{
|
||||
TLSVerify: true,
|
||||
WatchByDefault: false,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("cannot set default values for swarm %s provider: %v", id, err)
|
||||
func (cfg *Config) validateSwarmProvider() error {
|
||||
if cfg.Providers.Swarm == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := mergo.Merge(cfg.Providers.Swarm, model.PrdSwarm{
|
||||
TLSVerify: utl.NewTrue(),
|
||||
WatchByDefault: utl.NewFalse(),
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "cannot set default values for docker provider")
|
||||
}
|
||||
|
||||
cfg.Providers.Swarm[id] = prdSwarm
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config) validateFileProvider() error {
|
||||
if cfg.Providers.File == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(cfg.Providers.File.Directory) > 0:
|
||||
if _, err := os.Stat(cfg.Providers.File.Directory); os.IsNotExist(err) {
|
||||
|
@ -196,7 +202,10 @@ func (cfg *Config) validateFileProvider() error {
|
|||
if _, err := os.Stat(cfg.Providers.File.Filename); os.IsNotExist(err) {
|
||||
return errors.Wrap(err, "filename not found for file provider")
|
||||
}
|
||||
default:
|
||||
return errors.New("error using file provider, neither filename or directory defined")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -69,11 +69,9 @@ regopts:
|
|||
|
||||
providers:
|
||||
docker:
|
||||
standalone:
|
||||
watch_by_default: true
|
||||
watch_stopped: true
|
||||
watch_by_default: true
|
||||
watch_stopped: true
|
||||
swarm:
|
||||
local_swarm:
|
||||
watch_by_default: true
|
||||
watch_by_default: true
|
||||
file:
|
||||
filename: ./dummy.yml
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/crazy-max/diun/internal/config"
|
||||
"github.com/crazy-max/diun/internal/model"
|
||||
"github.com/crazy-max/diun/pkg/utl"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -115,21 +116,17 @@ func TestLoad(t *testing.T) {
|
|||
PasswordFile: "/run/secrets/password",
|
||||
},
|
||||
},
|
||||
Providers: model.Providers{
|
||||
Docker: map[string]model.PrdDocker{
|
||||
"standalone": {
|
||||
TLSVerify: true,
|
||||
WatchByDefault: true,
|
||||
WatchStopped: true,
|
||||
},
|
||||
Providers: &model.Providers{
|
||||
Docker: &model.PrdDocker{
|
||||
TLSVerify: utl.NewTrue(),
|
||||
WatchByDefault: utl.NewTrue(),
|
||||
WatchStopped: utl.NewTrue(),
|
||||
},
|
||||
Swarm: map[string]model.PrdSwarm{
|
||||
"local_swarm": {
|
||||
TLSVerify: true,
|
||||
WatchByDefault: true,
|
||||
},
|
||||
Swarm: &model.PrdSwarm{
|
||||
TLSVerify: utl.NewTrue(),
|
||||
WatchByDefault: utl.NewTrue(),
|
||||
},
|
||||
File: model.PrdFile{
|
||||
File: &model.PrdFile{
|
||||
Filename: "./dummy.yml",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -2,9 +2,9 @@ package model
|
|||
|
||||
// Providers represents a provider configuration
|
||||
type Providers struct {
|
||||
Docker map[string]PrdDocker `yaml:"docker,omitempty" json:",omitempty"`
|
||||
Swarm map[string]PrdSwarm `yaml:"swarm,omitempty" json:",omitempty"`
|
||||
File PrdFile `yaml:"file,omitempty" json:",omitempty"`
|
||||
Docker *PrdDocker `yaml:"docker,omitempty" json:",omitempty"`
|
||||
Swarm *PrdSwarm `yaml:"swarm,omitempty" json:",omitempty"`
|
||||
File *PrdFile `yaml:"file,omitempty" json:",omitempty"`
|
||||
}
|
||||
|
||||
// PrdDocker holds docker provider configuration
|
||||
|
@ -12,9 +12,9 @@ type PrdDocker struct {
|
|||
Endpoint string `yaml:"endpoint,omitempty" json:",omitempty"`
|
||||
APIVersion string `yaml:"api_version,omitempty" json:",omitempty"`
|
||||
TLSCertsPath string `yaml:"tls_certs_path,omitempty" json:",omitempty"`
|
||||
TLSVerify bool `yaml:"tls_verify,omitempty" json:",omitempty"`
|
||||
WatchByDefault bool `yaml:"watch_by_default,omitempty" json:",omitempty"`
|
||||
WatchStopped bool `yaml:"watch_stopped,omitempty" json:",omitempty"`
|
||||
TLSVerify *bool `yaml:"tls_verify,omitempty" json:",omitempty"`
|
||||
WatchByDefault *bool `yaml:"watch_by_default,omitempty" json:",omitempty"`
|
||||
WatchStopped *bool `yaml:"watch_stopped,omitempty" json:",omitempty"`
|
||||
}
|
||||
|
||||
// PrdSwarm holds swarm provider configuration
|
||||
|
@ -22,8 +22,8 @@ type PrdSwarm struct {
|
|||
Endpoint string `yaml:"endpoint,omitempty" json:",omitempty"`
|
||||
APIVersion string `yaml:"api_version,omitempty" json:",omitempty"`
|
||||
TLSCertsPath string `yaml:"tls_certs_path,omitempty" json:",omitempty"`
|
||||
TLSVerify bool `yaml:"tls_verify,omitempty" json:",omitempty"`
|
||||
WatchByDefault bool `yaml:"watch_by_default,omitempty" json:",omitempty"`
|
||||
TLSVerify *bool `yaml:"tls_verify,omitempty" json:",omitempty"`
|
||||
WatchByDefault *bool `yaml:"watch_by_default,omitempty" json:",omitempty"`
|
||||
}
|
||||
|
||||
// PrdFile holds file provider configuration
|
||||
|
|
|
@ -1,42 +1,36 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/crazy-max/diun/internal/model"
|
||||
"github.com/crazy-max/diun/internal/provider"
|
||||
"github.com/crazy-max/diun/pkg/docker"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (c *Client) listContainerImage(id string, elt model.PrdDocker) []model.Image {
|
||||
sublog := log.With().
|
||||
Str("provider", fmt.Sprintf("docker-%s", id)).
|
||||
Logger()
|
||||
|
||||
func (c *Client) listContainerImage() []model.Image {
|
||||
cli, err := docker.New(docker.Options{
|
||||
Endpoint: elt.Endpoint,
|
||||
APIVersion: elt.APIVersion,
|
||||
TLSCertPath: elt.TLSCertsPath,
|
||||
TLSVerify: elt.TLSVerify,
|
||||
Endpoint: c.config.Endpoint,
|
||||
APIVersion: c.config.APIVersion,
|
||||
TLSCertPath: c.config.TLSCertsPath,
|
||||
TLSVerify: *c.config.TLSVerify,
|
||||
})
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("Cannot create Docker client")
|
||||
c.logger.Error().Err(err).Msg("Cannot create Docker client")
|
||||
return []model.Image{}
|
||||
}
|
||||
|
||||
ctnFilter := filters.NewArgs()
|
||||
ctnFilter.Add("status", "running")
|
||||
if elt.WatchStopped {
|
||||
if *c.config.WatchStopped {
|
||||
ctnFilter.Add("status", "created")
|
||||
ctnFilter.Add("status", "exited")
|
||||
}
|
||||
|
||||
ctns, err := cli.ContainerList(ctnFilter)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("Cannot list Docker containers")
|
||||
c.logger.Error().Err(err).Msg("Cannot list Docker containers")
|
||||
return []model.Image{}
|
||||
}
|
||||
|
||||
|
@ -44,18 +38,18 @@ func (c *Client) listContainerImage(id string, elt model.PrdDocker) []model.Imag
|
|||
for _, ctn := range ctns {
|
||||
local, err := cli.IsLocalImage(ctn.Image)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msgf("Cannot inspect image from container %s", ctn.ID)
|
||||
c.logger.Error().Err(err).Msgf("Cannot inspect image from container %s", ctn.ID)
|
||||
continue
|
||||
} else if local {
|
||||
sublog.Debug().Msgf("Skip locally built image for container %s", ctn.ID)
|
||||
c.logger.Debug().Msgf("Skip locally built image for container %s", ctn.ID)
|
||||
continue
|
||||
}
|
||||
image, err := provider.ValidateContainerImage(ctn.Image, ctn.Labels, elt.WatchByDefault)
|
||||
image, err := provider.ValidateContainerImage(ctn.Image, ctn.Labels, *c.config.WatchByDefault)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msgf("Cannot get image from container %s", ctn.ID)
|
||||
c.logger.Error().Err(err).Msgf("Cannot get image from container %s", ctn.ID)
|
||||
continue
|
||||
} else if reflect.DeepEqual(image, model.Image{}) {
|
||||
sublog.Debug().Msgf("Watch disabled for container %s", ctn.ID)
|
||||
c.logger.Debug().Msgf("Watch disabled for container %s", ctn.ID)
|
||||
continue
|
||||
}
|
||||
list = append(list, image)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/crazy-max/diun/internal/model"
|
||||
"github.com/crazy-max/diun/internal/provider"
|
||||
"github.com/rs/zerolog"
|
||||
|
@ -12,15 +10,15 @@ import (
|
|||
// Client represents an active docker provider object
|
||||
type Client struct {
|
||||
*provider.Client
|
||||
elts map[string]model.PrdDocker
|
||||
config *model.PrdDocker
|
||||
logger zerolog.Logger
|
||||
}
|
||||
|
||||
// New creates new docker provider instance
|
||||
func New(elts map[string]model.PrdDocker) *provider.Client {
|
||||
func New(config *model.PrdDocker) *provider.Client {
|
||||
return &provider.Client{
|
||||
Handler: &Client{
|
||||
elts: elts,
|
||||
config: config,
|
||||
logger: log.With().Str("provider", "docker").Logger(),
|
||||
},
|
||||
}
|
||||
|
@ -28,19 +26,22 @@ func New(elts map[string]model.PrdDocker) *provider.Client {
|
|||
|
||||
// ListJob returns job list to process
|
||||
func (c *Client) ListJob() []model.Job {
|
||||
if len(c.elts) == 0 {
|
||||
if c.config == nil {
|
||||
return []model.Job{}
|
||||
}
|
||||
|
||||
c.logger.Info().Msgf("Found %d image(s) to analyze", len(c.elts))
|
||||
images := c.listContainerImage()
|
||||
if len(images) == 0 {
|
||||
return []model.Job{}
|
||||
}
|
||||
|
||||
c.logger.Info().Msgf("Found %d image(s) to analyze", len(images))
|
||||
var list []model.Job
|
||||
for id, elt := range c.elts {
|
||||
for _, img := range c.listContainerImage(id, elt) {
|
||||
list = append(list, model.Job{
|
||||
Provider: fmt.Sprintf("docker-%s", id),
|
||||
Image: img,
|
||||
})
|
||||
}
|
||||
for _, image := range images {
|
||||
list = append(list, model.Job{
|
||||
Provider: "docker",
|
||||
Image: image,
|
||||
})
|
||||
}
|
||||
|
||||
return list
|
||||
|
|
|
@ -1,29 +1,24 @@
|
|||
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
|
||||
config *model.PrdFile
|
||||
logger zerolog.Logger
|
||||
}
|
||||
|
||||
// New creates new file provider instance
|
||||
func New(item model.PrdFile) *provider.Client {
|
||||
func New(config *model.PrdFile) *provider.Client {
|
||||
return &provider.Client{
|
||||
Handler: &Client{
|
||||
item: item,
|
||||
config: config,
|
||||
logger: log.With().Str("provider", "file").Logger(),
|
||||
},
|
||||
}
|
||||
|
@ -31,73 +26,23 @@ func New(item model.PrdFile) *provider.Client {
|
|||
|
||||
// ListJob returns job list to process
|
||||
func (c *Client) ListJob() []model.Job {
|
||||
images := c.loadImages()
|
||||
if c.config == nil {
|
||||
return []model.Job{}
|
||||
}
|
||||
|
||||
images := c.listFileImage()
|
||||
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 {
|
||||
for _, image := range images {
|
||||
list = append(list, model.Job{
|
||||
Provider: "file",
|
||||
Image: elt,
|
||||
Image: image,
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
64
internal/provider/file/image.go
Normal file
64
internal/provider/file/image.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/crazy-max/diun/internal/model"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func (c *Client) listFileImage() []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.config.Directory) > 0:
|
||||
fileList, err := ioutil.ReadDir(c.config.Directory)
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msgf("Unable to read directory %s", c.config.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.config.Directory, file.Name()))
|
||||
}
|
||||
case len(c.config.Filename) > 0:
|
||||
files = append(files, c.config.Filename)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
|
@ -1,35 +1,29 @@
|
|||
package swarm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/crazy-max/diun/internal/model"
|
||||
"github.com/crazy-max/diun/internal/provider"
|
||||
"github.com/crazy-max/diun/pkg/docker"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (c *Client) listServiceImage(id string, elt model.PrdSwarm) []model.Image {
|
||||
sublog := log.With().
|
||||
Str("provider", fmt.Sprintf("swarm-%s", id)).
|
||||
Logger()
|
||||
|
||||
func (c *Client) listServiceImage() []model.Image {
|
||||
cli, err := docker.New(docker.Options{
|
||||
Endpoint: elt.Endpoint,
|
||||
APIVersion: elt.APIVersion,
|
||||
TLSCertPath: elt.TLSCertsPath,
|
||||
TLSVerify: elt.TLSVerify,
|
||||
Endpoint: c.config.Endpoint,
|
||||
APIVersion: c.config.APIVersion,
|
||||
TLSCertPath: c.config.TLSCertsPath,
|
||||
TLSVerify: *c.config.TLSVerify,
|
||||
})
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("Cannot create Docker client")
|
||||
c.logger.Error().Err(err).Msg("Cannot create Docker client")
|
||||
return []model.Image{}
|
||||
}
|
||||
|
||||
svcs, err := cli.ServiceList(filters.NewArgs())
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("Cannot list Swarm services")
|
||||
c.logger.Error().Err(err).Msg("Cannot list Swarm services")
|
||||
return []model.Image{}
|
||||
}
|
||||
|
||||
|
@ -37,15 +31,15 @@ func (c *Client) listServiceImage(id string, elt model.PrdSwarm) []model.Image {
|
|||
for _, svc := range svcs {
|
||||
local, _ := cli.IsLocalImage(svc.Spec.TaskTemplate.ContainerSpec.Image)
|
||||
if local {
|
||||
sublog.Debug().Msgf("Skip locally built image for service %s", svc.Spec.Name)
|
||||
c.logger.Debug().Msgf("Skip locally built image for service %s", svc.Spec.Name)
|
||||
continue
|
||||
}
|
||||
image, err := provider.ValidateContainerImage(svc.Spec.TaskTemplate.ContainerSpec.Image, svc.Spec.Labels, elt.WatchByDefault)
|
||||
image, err := provider.ValidateContainerImage(svc.Spec.TaskTemplate.ContainerSpec.Image, svc.Spec.Labels, *c.config.WatchByDefault)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msgf("Cannot get image from service %s", svc.Spec.Name)
|
||||
c.logger.Error().Err(err).Msgf("Cannot get image from service %s", svc.Spec.Name)
|
||||
continue
|
||||
} else if reflect.DeepEqual(image, model.Image{}) {
|
||||
sublog.Debug().Msgf("Watch disabled for service %s", svc.Spec.Name)
|
||||
c.logger.Debug().Msgf("Watch disabled for service %s", svc.Spec.Name)
|
||||
continue
|
||||
}
|
||||
list = append(list, image)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package swarm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/crazy-max/diun/internal/model"
|
||||
"github.com/crazy-max/diun/internal/provider"
|
||||
"github.com/rs/zerolog"
|
||||
|
@ -12,15 +10,15 @@ import (
|
|||
// Client represents an active swarm provider object
|
||||
type Client struct {
|
||||
*provider.Client
|
||||
elts map[string]model.PrdSwarm
|
||||
config *model.PrdSwarm
|
||||
logger zerolog.Logger
|
||||
}
|
||||
|
||||
// New creates new swarm provider instance
|
||||
func New(elts map[string]model.PrdSwarm) *provider.Client {
|
||||
func New(config *model.PrdSwarm) *provider.Client {
|
||||
return &provider.Client{
|
||||
Handler: &Client{
|
||||
elts: elts,
|
||||
config: config,
|
||||
logger: log.With().Str("provider", "swarm").Logger(),
|
||||
},
|
||||
}
|
||||
|
@ -28,19 +26,22 @@ func New(elts map[string]model.PrdSwarm) *provider.Client {
|
|||
|
||||
// ListJob returns job list to process
|
||||
func (c *Client) ListJob() []model.Job {
|
||||
if len(c.elts) == 0 {
|
||||
if c.config == nil {
|
||||
return []model.Job{}
|
||||
}
|
||||
|
||||
c.logger.Info().Msgf("Found %d image(s) to analyze", len(c.elts))
|
||||
images := c.listServiceImage()
|
||||
if len(images) == 0 {
|
||||
return []model.Job{}
|
||||
}
|
||||
|
||||
c.logger.Info().Msgf("Found %d image(s) to analyze", len(images))
|
||||
var list []model.Job
|
||||
for id, elt := range c.elts {
|
||||
for _, img := range c.listServiceImage(id, elt) {
|
||||
list = append(list, model.Job{
|
||||
Provider: fmt.Sprintf("swarm-%s", id),
|
||||
Image: img,
|
||||
})
|
||||
}
|
||||
for _, image := range images {
|
||||
list = append(list, model.Job{
|
||||
Provider: "swarm",
|
||||
Image: image,
|
||||
})
|
||||
}
|
||||
|
||||
return list
|
||||
|
|
|
@ -66,3 +66,15 @@ func GetSecret(plaintext, filename string) (string, error) {
|
|||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// NewFalse returns a false bool pointer
|
||||
func NewFalse() *bool {
|
||||
b := false
|
||||
return &b
|
||||
}
|
||||
|
||||
// NewTrue returns a true bool pointer
|
||||
func NewTrue() *bool {
|
||||
b := true
|
||||
return &b
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue